Add basic PDB symbol reading using radare2's PDB library functions
This commit is contained in:
parent
e234ce54cd
commit
817afcd046
|
@ -560,7 +560,8 @@ CONFIG_DEP_SUBDIR = $(addsuffix /$(DEPDIR),$(CONFIG_SRC_SUBDIR))
|
||||||
# should be according to Posix).
|
# should be according to Posix).
|
||||||
DEFS = @DEFS@
|
DEFS = @DEFS@
|
||||||
GDB_CFLAGS = -I. -I$(srcdir) -I$(srcdir)/config \
|
GDB_CFLAGS = -I. -I$(srcdir) -I$(srcdir)/config \
|
||||||
-DLOCALEDIR="\"$(localedir)\"" $(DEFS)
|
-DLOCALEDIR="\"$(localedir)\"" $(DEFS) \
|
||||||
|
-I/usr/include/libr
|
||||||
|
|
||||||
# MH_CFLAGS, if defined, has host-dependent CFLAGS from the config directory.
|
# MH_CFLAGS, if defined, has host-dependent CFLAGS from the config directory.
|
||||||
GLOBAL_CFLAGS = $(MH_CFLAGS)
|
GLOBAL_CFLAGS = $(MH_CFLAGS)
|
||||||
|
@ -613,7 +614,8 @@ CLIBS = $(SIM) $(READLINE) $(OPCODES) $(BFD) $(LIBCTF) $(ZLIB) \
|
||||||
$(LIBEXPAT) $(LIBLZMA) $(LIBBABELTRACE) $(LIBIPT) \
|
$(LIBEXPAT) $(LIBLZMA) $(LIBBABELTRACE) $(LIBIPT) \
|
||||||
$(LIBIBERTY) $(WIN32LIBS) $(LIBGNU) $(LIBICONV) $(LIBMPFR) \
|
$(LIBIBERTY) $(WIN32LIBS) $(LIBGNU) $(LIBICONV) $(LIBMPFR) \
|
||||||
$(SRCHIGH_LIBS) $(LIBXXHASH) $(PTHREAD_LIBS) \
|
$(SRCHIGH_LIBS) $(LIBXXHASH) $(PTHREAD_LIBS) \
|
||||||
-lLLVMDemangle
|
-lLLVMDemangle \
|
||||||
|
-lr_bin -lr_util
|
||||||
CDEPS = $(NAT_CDEPS) $(SIM) $(BFD) $(READLINE_DEPS) $(LIBCTF) \
|
CDEPS = $(NAT_CDEPS) $(SIM) $(BFD) $(READLINE_DEPS) $(LIBCTF) \
|
||||||
$(OPCODES) $(INTL_DEPS) $(LIBIBERTY) $(CONFIG_DEPS) $(LIBGNU)
|
$(OPCODES) $(INTL_DEPS) $(LIBIBERTY) $(CONFIG_DEPS) $(LIBGNU)
|
||||||
|
|
||||||
|
@ -1168,7 +1170,8 @@ COMMON_SFILES = \
|
||||||
varobj.c \
|
varobj.c \
|
||||||
xml-support.c \
|
xml-support.c \
|
||||||
xml-syscall.c \
|
xml-syscall.c \
|
||||||
xml-tdesc.c
|
xml-tdesc.c \
|
||||||
|
pdb.c
|
||||||
|
|
||||||
# Links made at configuration time should not be specified here, since
|
# Links made at configuration time should not be specified here, since
|
||||||
# SFILES is used in building the distribution archive.
|
# SFILES is used in building the distribution archive.
|
||||||
|
@ -1575,7 +1578,8 @@ HFILES_NO_SRCDIR = \
|
||||||
tui/tui-windata.h \
|
tui/tui-windata.h \
|
||||||
tui/tui-wingeneral.h \
|
tui/tui-wingeneral.h \
|
||||||
tui/tui-winsource.h \
|
tui/tui-winsource.h \
|
||||||
x86-tdep.h
|
x86-tdep.h \
|
||||||
|
pdb.h
|
||||||
|
|
||||||
# Header files that already have srcdir in them, or which are in objdir.
|
# Header files that already have srcdir in them, or which are in objdir.
|
||||||
|
|
||||||
|
|
|
@ -42,6 +42,8 @@
|
||||||
#include "psymtab.h"
|
#include "psymtab.h"
|
||||||
#include "build-id.h"
|
#include "build-id.h"
|
||||||
|
|
||||||
|
#include "pdb.h"
|
||||||
|
|
||||||
/* The objfile we are currently reading. */
|
/* The objfile we are currently reading. */
|
||||||
|
|
||||||
static struct objfile *coffread_objfile;
|
static struct objfile *coffread_objfile;
|
||||||
|
@ -631,6 +633,9 @@ coff_symfile_read (struct objfile *objfile, symfile_add_flags symfile_flags)
|
||||||
|
|
||||||
coff_symtab_read (reader, (long) symtab_offset, num_symbols, objfile);
|
coff_symtab_read (reader, (long) symtab_offset, num_symbols, objfile);
|
||||||
|
|
||||||
|
/* Try reading additional symbols from PDB. */
|
||||||
|
read_pdb(objfile, reader);
|
||||||
|
|
||||||
/* Install any minimal symbols that have been collected as the
|
/* Install any minimal symbols that have been collected as the
|
||||||
current minimal symbols for this objfile. */
|
current minimal symbols for this objfile. */
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,255 @@
|
||||||
|
/* Includes code from radare2:
|
||||||
|
radare - LGPL - Copyright 2014 - inisider
|
||||||
|
(https://github.com/radareorg/radare2) */
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
HACK: Honestly, this whole thing is a hack:
|
||||||
|
|
||||||
|
1. radare's PDB functions aren't great for external use,
|
||||||
|
2. few if any edge cases work,
|
||||||
|
3. we pretend our PDB symbols are minisyms, and
|
||||||
|
4. no tests.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "defs.h"
|
||||||
|
|
||||||
|
//BEGIN HACK (conflicting symbols)
|
||||||
|
#undef QUIT
|
||||||
|
|
||||||
|
#include <libr/r_pdb.h>
|
||||||
|
#include <libr/r_core.h>
|
||||||
|
|
||||||
|
#undef QUIT
|
||||||
|
#define QUIT maybe_quit ()
|
||||||
|
#undef B_SET
|
||||||
|
//END HACK (conflicting symbols)
|
||||||
|
|
||||||
|
#include "objfiles.h"
|
||||||
|
#include "gdb/fileio.h"
|
||||||
|
|
||||||
|
#include "gdbsupport/pathstuff.h"
|
||||||
|
#include <regex>
|
||||||
|
#include <fstream>
|
||||||
|
#include <cassert>
|
||||||
|
#include "psympriv.h"
|
||||||
|
|
||||||
|
//BEGIN radare2 imports
|
||||||
|
#include "pdb_types.h"
|
||||||
|
|
||||||
|
typedef void (*parse_stream_)(void *stream, R_STREAM_FILE *stream_file);
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
int indx;
|
||||||
|
parse_stream_ parse_stream;
|
||||||
|
void *stream;
|
||||||
|
EStream type;
|
||||||
|
free_func free;
|
||||||
|
} SStreamParseFunc;
|
||||||
|
//END radare2 imports
|
||||||
|
|
||||||
|
static std::unique_ptr<R_PDB>
|
||||||
|
get_r_pdb (std::string path)
|
||||||
|
{
|
||||||
|
R_PDB pdb = { 0 };
|
||||||
|
if (std::ifstream (path).good ())
|
||||||
|
{
|
||||||
|
if (init_pdb_parser (&pdb, path.c_str ()))
|
||||||
|
return std::make_unique<R_PDB> (pdb);
|
||||||
|
}
|
||||||
|
else if (path.rfind ("target:", 0) == 0)
|
||||||
|
{
|
||||||
|
auto target = find_target_at (process_stratum);
|
||||||
|
|
||||||
|
void* buffer;
|
||||||
|
size_t length;
|
||||||
|
|
||||||
|
{ //begin read PDB into buffer
|
||||||
|
int errno;
|
||||||
|
|
||||||
|
auto fd = target->fileio_open (nullptr,
|
||||||
|
path.c_str () + sizeof ("target:") - 1,
|
||||||
|
FILEIO_O_RDONLY, /* mode */ 0, /* warn_if_slow */ true, &errno);
|
||||||
|
|
||||||
|
if (fd == -1)
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct stat st;
|
||||||
|
if (target->fileio_fstat (fd, &st, &errno) == -1)
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
length = st.st_size;
|
||||||
|
buffer = xmalloc (length);
|
||||||
|
|
||||||
|
file_ptr pos = 0, bytes;
|
||||||
|
while (length > pos)
|
||||||
|
{
|
||||||
|
bytes = target->fileio_pread (fd,
|
||||||
|
(gdb_byte *) buffer + pos,
|
||||||
|
length - pos,
|
||||||
|
pos,
|
||||||
|
&errno);
|
||||||
|
if (bytes == 0)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (bytes == -1)
|
||||||
|
{
|
||||||
|
xfree (buffer);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pos += bytes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert (pos == length);
|
||||||
|
|
||||||
|
target->fileio_close (fd, &errno);
|
||||||
|
} //end read PDB into buffer
|
||||||
|
|
||||||
|
auto r_buffer = r_buf_new_with_bytes ((const ut8*) buffer, length);
|
||||||
|
if (init_pdb_parser_with_buf (&pdb, r_buffer))
|
||||||
|
{
|
||||||
|
xfree (buffer);
|
||||||
|
return std::make_unique<R_PDB> (pdb);
|
||||||
|
}
|
||||||
|
|
||||||
|
xfree (buffer);
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string
|
||||||
|
get_pdb_path (struct objfile *objfile)
|
||||||
|
{
|
||||||
|
/* HACK: Use _bfd_XXi_slurp_codeview_record to find the 'correct' PDB path.
|
||||||
|
|
||||||
|
We should use this as fallback, but we shouldn't try to find a PDB if
|
||||||
|
there is no codeview record at all. */
|
||||||
|
|
||||||
|
auto real_path = gdb_realpath (objfile->original_name);
|
||||||
|
auto pdb_path = std::regex_replace (std::string (real_path.get ()),
|
||||||
|
std::regex ("\\.[^.]*$"), ".pdb");
|
||||||
|
return pdb_path;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct find_section_by_name_args
|
||||||
|
{
|
||||||
|
const char *name;
|
||||||
|
asection **resultp;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
find_section_by_name_filter (bfd *abfd, asection *sect, void *obj)
|
||||||
|
{
|
||||||
|
struct find_section_by_name_args *args = (struct find_section_by_name_args *) obj;
|
||||||
|
|
||||||
|
if (strcmp (sect->name, args->name) == 0)
|
||||||
|
*args->resultp = sect;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct bfd_section*
|
||||||
|
section_by_name (const char* name, struct objfile *objfile)
|
||||||
|
{
|
||||||
|
asection *sect = NULL;
|
||||||
|
struct find_section_by_name_args args;
|
||||||
|
args.name = name;
|
||||||
|
args.resultp = §
|
||||||
|
bfd_map_over_sections (objfile->obfd, find_section_by_name_filter, &args);
|
||||||
|
return sect;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
read_pdb (struct objfile *objfile, minimal_symbol_reader &reader)
|
||||||
|
{
|
||||||
|
auto pdb_path = get_pdb_path (objfile);
|
||||||
|
|
||||||
|
auto pdb = get_r_pdb (pdb_path);
|
||||||
|
if (pdb)
|
||||||
|
{
|
||||||
|
if (pdb->pdb_parse (pdb.get ()))
|
||||||
|
{
|
||||||
|
SStreamParseFunc *omap = 0, *sctns = 0, *sctns_orig = 0, *gsym = 0, *tmp = 0;
|
||||||
|
SIMAGE_SECTION_HEADER *sctn_header = 0;
|
||||||
|
SGDATAStream *gsym_data_stream = 0;
|
||||||
|
SPEStream *pe_stream = 0;
|
||||||
|
SGlobal *gdata = 0;
|
||||||
|
RListIter *it = 0;
|
||||||
|
RList *l = 0;
|
||||||
|
|
||||||
|
l = pdb->pdb_streams2;
|
||||||
|
it = r_list_iterator (l);
|
||||||
|
while (r_list_iter_next (it))
|
||||||
|
{
|
||||||
|
tmp = (SStreamParseFunc *) r_list_iter_get (it);
|
||||||
|
switch (tmp->type)
|
||||||
|
{
|
||||||
|
case ePDB_STREAM_SECT__HDR_ORIG:
|
||||||
|
sctns_orig = tmp;
|
||||||
|
break;
|
||||||
|
case ePDB_STREAM_SECT_HDR:
|
||||||
|
sctns = tmp;
|
||||||
|
break;
|
||||||
|
case ePDB_STREAM_OMAP_FROM_SRC:
|
||||||
|
omap = tmp;
|
||||||
|
break;
|
||||||
|
case ePDB_STREAM_GSYM:
|
||||||
|
gsym = tmp;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!gsym)
|
||||||
|
{
|
||||||
|
eprintf ("There is no global symbols in current PDB.\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
gsym_data_stream = (SGDATAStream *) gsym->stream;
|
||||||
|
if ((omap != 0) && (sctns_orig != 0))
|
||||||
|
{
|
||||||
|
pe_stream = (SPEStream *) sctns_orig->stream;
|
||||||
|
}
|
||||||
|
else if (sctns)
|
||||||
|
{
|
||||||
|
pe_stream = (SPEStream *) sctns->stream;
|
||||||
|
}
|
||||||
|
if (!pe_stream)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf_filtered (_("Reading symbols from %s...\n"), pdb_path.c_str());
|
||||||
|
|
||||||
|
//TODO: Use this. For now, we allocate the symtab so we don't print we found no symbols.
|
||||||
|
auto psymtab = allocate_psymtab (objfile->original_name, objfile);
|
||||||
|
(void) psymtab;
|
||||||
|
|
||||||
|
it = r_list_iterator (gsym_data_stream->globals_list);
|
||||||
|
while (r_list_iter_next (it))
|
||||||
|
{
|
||||||
|
gdata = (SGlobal *) r_list_iter_get (it);
|
||||||
|
sctn_header = (SIMAGE_SECTION_HEADER*) r_list_get_n (pe_stream->sections_hdrs, (gdata->segment - 1));
|
||||||
|
if (sctn_header)
|
||||||
|
{
|
||||||
|
asection *sect = section_by_name(sctn_header->name, objfile);
|
||||||
|
|
||||||
|
auto section_address = sect ? bfd_section_vma(sect) : 0;
|
||||||
|
auto address = section_address + gdata->offset;
|
||||||
|
if (address == 0) continue; //we don't want to record unresolved symbols or something?
|
||||||
|
auto type = mst_unknown; //FIXME
|
||||||
|
reader.record_with_info(gdata->name.name, address, type, sect->index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pdb->finish_pdb_parse (pdb.get ());
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
#include "defs.h"
|
||||||
|
#include "symtab.h"
|
||||||
|
#include "minsyms.h"
|
||||||
|
|
||||||
|
extern void
|
||||||
|
read_pdb (struct objfile *objfile, minimal_symbol_reader &reader);
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue