|
From: Rémi B. <rb...@co...> - 2020-11-30 09:01:42
|
To support Wine PE modules when built with DWARF debug info, eventually
in separate debug files referenced through .gnu_debuglink section.
Hooking it to the Wine specific LOAD_PDB_DEBUGINFO notification, for
simplicity. Most of the code here was adapted from read_elf_debug_info.
Signed-off-by: Rémi Bernon <rb...@co...>
---
coregrind/m_debuginfo/debuginfo.c | 63 +-
coregrind/m_debuginfo/priv_readelf.h | 23 +
coregrind/m_debuginfo/priv_readpdb.h | 8 +
coregrind/m_debuginfo/readelf.c | 42 +-
coregrind/m_debuginfo/readpdb.c | 1011 ++++++++++++++++++++++++++
5 files changed, 1123 insertions(+), 24 deletions(-)
diff --git a/coregrind/m_debuginfo/debuginfo.c b/coregrind/m_debuginfo/debuginfo.c
index 13e528e5d..0c43b2b89 100644
--- a/coregrind/m_debuginfo/debuginfo.c
+++ b/coregrind/m_debuginfo/debuginfo.c
@@ -1588,10 +1588,65 @@ void VG_(di_notify_pdb_debuginfo)( Int fd_obj, Addr avma_obj,
/* See if we can find it, and check it's in-dateness. */
sres = VG_(stat)(pdbname, &stat_buf);
if (sr_isError(sres)) {
- VG_(message)(Vg_UserMsg, "Warning: Missing or un-stat-able %s\n",
- pdbname);
- if (VG_(clo_verbosity) > 0)
- VG_(message)(Vg_UserMsg, "LOAD_PDB_DEBUGINFO: missing: %s\n", pdbname);
+ /* play safe; always invalidate the debug info caches. I don't know if
+ this is necessary, but anyway .. */
+ caches__invalidate();
+ /* dump old info for this range, if any */
+ discard_syms_in_range( avma_obj, total_size );
+ advance_current_DiEpoch("VG_(di_notify_pdb_debuginfo)");
+
+ DebugInfo* di = find_or_create_DebugInfo_for(exename);
+
+ /* this di must be new, since we just nuked any old stuff in the range */
+ vg_assert(di && !di->fsm.have_rx_map && !di->fsm.have_rw_map);
+ vg_assert(!di->have_dinfo);
+
+ Bool ok = ML_(read_pe_debug_info)( di, avma_obj, bias_obj );
+
+ if (ok) {
+ TRACE_SYMTAB("\n------ Canonicalising the "
+ "acquired info ------\n");
+ /* invalidate the debug info caches. */
+ caches__invalidate();
+ /* prepare read data for use */
+ ML_(canonicaliseTables)( di );
+ /* Check invariants listed in
+ Comment_on_IMPORTANT_REPRESENTATIONAL_INVARIANTS in
+ priv_storage.h. */
+ check_CFSI_related_invariants(di);
+ ML_(finish_CFSI_arrays)(di);
+
+ // Mark di's first epoch point as a valid epoch. Because its
+ // last_epoch value is still invalid, this changes di's state from
+ // "allocated" to "active".
+ vg_assert(is_DebugInfo_allocated(di));
+ di->first_epoch = VG_(current_DiEpoch)();
+ vg_assert(is_DebugInfo_active(di));
+ show_epochs("di_notify_ACHIEVE_ACCEPT_STATE success");
+
+ /* notify m_redir about it */
+ TRACE_SYMTAB("\n------ Notifying m_redir ------\n");
+ VG_(redir_notify_new_DebugInfo)( di );
+ /* Note that we succeeded */
+ di->have_dinfo = True;
+ vg_assert(di->handle > 0);
+
+ } else {
+ VG_(message)(Vg_UserMsg, "Warning: Missing or un-stat-able %s\n",
+ pdbname);
+ if (VG_(clo_verbosity) > 0)
+ VG_(message)(Vg_UserMsg, "LOAD_PDB_DEBUGINFO: missing: %s\n", pdbname);
+
+ /* We cannot make any sense of this pdb, so (force) discard it,
+ even if VG_(clo_keep_debuginfo) is True. */
+ const Bool save_clo_keep_debuginfo = VG_(clo_keep_debuginfo);
+ VG_(clo_keep_debuginfo) = False;
+ // The below will assert if di is not active. Not too sure what
+ // the state of di in this failed loading state.
+ discard_or_archive_DebugInfo (di);
+ VG_(clo_keep_debuginfo) = save_clo_keep_debuginfo;
+ }
+
goto out;
}
pdb_mtime = stat_buf.mtime;
diff --git a/coregrind/m_debuginfo/priv_readelf.h b/coregrind/m_debuginfo/priv_readelf.h
index 2bee615ab..c5368244d 100644
--- a/coregrind/m_debuginfo/priv_readelf.h
+++ b/coregrind/m_debuginfo/priv_readelf.h
@@ -52,6 +52,29 @@ extern Bool ML_(is_elf_object_file)( const void* image, SizeT n_image,
*/
extern Bool ML_(read_elf_debug_info) ( DebugInfo* di );
+/* Try and open a separate debug file, ignoring any where the CRC does
+ not match the value from the main object file. Returned DiImage
+ must be discarded by the caller.
+ */
+extern DiImage* ML_(open_debug_file)( const HChar* name,
+ const HChar* buildid,
+ UInt crc,
+ Bool rel_ok,
+ const HChar* serverAddr );
+
+/* Try to find a separate debug file for a given object file. If
+ found, return its DiImage, which should be freed by the caller. */
+extern DiImage* ML_(find_debug_file)( struct _DebugInfo* di,
+ const HChar* objpath,
+ const HChar* buildid,
+ const HChar* debugname,
+ UInt crc, Bool rel_ok );
+
+/* Try to find a separate debug file for a given object file, in a
+ hacky and dangerous way: check only the --extra-debuginfo-path and
+ the --debuginfo-server. And don't do a consistency check. */
+extern DiImage* ML_(find_debug_file_ad_hoc)( const DebugInfo* di,
+ const HChar* objpath );
#endif /* ndef __PRIV_READELF_H */
diff --git a/coregrind/m_debuginfo/priv_readpdb.h b/coregrind/m_debuginfo/priv_readpdb.h
index b8f595810..13fa09903 100644
--- a/coregrind/m_debuginfo/priv_readpdb.h
+++ b/coregrind/m_debuginfo/priv_readpdb.h
@@ -54,6 +54,14 @@ extern Bool ML_(read_pdb_debug_info)(
ML_(dinfo_free). */
HChar* ML_(find_name_of_pdb_file)( const HChar* pename );
+/* The central function for reading PE debug info. For the
+ object/exe specified by the SegInfo, find sections, then read
+ the symbols, line number info, file name info, CFA (stack-unwind
+ info) and anything else we want, into the tables within the
+ supplied SegInfo.
+*/
+extern Bool ML_(read_pe_debug_info) ( DebugInfo* di, Addr obj_avma,
+ PtrdiffT obj_bias );
#endif /* ndef __PRIV_READPDB_H */
diff --git a/coregrind/m_debuginfo/readelf.c b/coregrind/m_debuginfo/readelf.c
index bc5a732d7..65de8912a 100644
--- a/coregrind/m_debuginfo/readelf.c
+++ b/coregrind/m_debuginfo/readelf.c
@@ -1227,9 +1227,9 @@ HChar* find_buildid(DiImage* img, Bool rel_ok, Bool search_shdrs)
spec of the form "d.d.d.d:d" or "d.d.d.d", and |name| is expected
to be a plain filename (no path components at all).
*/
-static
-DiImage* open_debug_file( const HChar* name, const HChar* buildid, UInt crc,
- Bool rel_ok, const HChar* serverAddr )
+DiImage* ML_(open_debug_file)( const HChar* name, const HChar* buildid,
+ UInt crc, Bool rel_ok,
+ const HChar* serverAddr )
{
DiImage* dimg
= serverAddr ? ML_(img_from_di_server)(name, serverAddr)
@@ -1289,10 +1289,11 @@ DiImage* open_debug_file( const HChar* name, const HChar* buildid, UInt crc,
debug object, then we look in various places to find a file with
the specified CRC. And if that doesn't work out then we give
up. */
-static
-DiImage* find_debug_file( struct _DebugInfo* di,
- const HChar* objpath, const HChar* buildid,
- const HChar* debugname, UInt crc, Bool rel_ok )
+DiImage* ML_(find_debug_file)( struct _DebugInfo* di,
+ const HChar* objpath,
+ const HChar* buildid,
+ const HChar* debugname,
+ UInt crc, Bool rel_ok )
{
const HChar* extrapath = VG_(clo_extra_debuginfo_path);
const HChar* serverpath = VG_(clo_debuginfo_server);
@@ -1307,7 +1308,7 @@ DiImage* find_debug_file( struct _DebugInfo* di,
VG_(sprintf)(debugpath, "/usr/lib/debug/.build-id/%c%c/%s.debug",
buildid[0], buildid[1], buildid + 2);
- dimg = open_debug_file(debugpath, buildid, 0, rel_ok, NULL);
+ dimg = ML_(open_debug_file)(debugpath, buildid, 0, rel_ok, NULL);
if (!dimg) {
ML_(dinfo_free)(debugpath);
debugpath = NULL;
@@ -1336,7 +1337,8 @@ DiImage* find_debug_file( struct _DebugInfo* di,
# define TRY_OBJDIR(format, ...) \
do { \
VG_(sprintf)(debugpath, format, __VA_ARGS__); \
- dimg = open_debug_file(debugpath, buildid, crc, rel_ok, NULL); \
+ dimg = ML_(open_debug_file)(debugpath, buildid, \
+ crc, rel_ok, NULL); \
if (dimg != NULL) goto dimg_ok; \
} while (0);
@@ -1372,7 +1374,8 @@ DiImage* find_debug_file( struct _DebugInfo* di,
basename = VG_(strrchr)(basename, '/') + 1;
}
VG_(sprintf)(debugpath, "%s on %s", basename, serverpath);
- dimg = open_debug_file(basename, buildid, crc, rel_ok, serverpath);
+ dimg = ML_(open_debug_file)(basename, buildid,
+ crc, rel_ok, serverpath);
if (dimg) goto dimg_ok;
}
@@ -1401,9 +1404,8 @@ DiImage* find_debug_file( struct _DebugInfo* di,
/* Try to find a separate debug file for a given object file, in a
hacky and dangerous way: check only the --extra-debuginfo-path and
the --debuginfo-server. And don't do a consistency check. */
-static
-DiImage* find_debug_file_ad_hoc( const DebugInfo* di,
- const HChar* objpath )
+DiImage* ML_(find_debug_file_ad_hoc)( const DebugInfo* di,
+ const HChar* objpath )
{
const HChar* extrapath = VG_(clo_extra_debuginfo_path);
const HChar* serverpath = VG_(clo_debuginfo_server);
@@ -2749,14 +2751,14 @@ Bool ML_(read_elf_debug_info) ( struct _DebugInfo* di )
HChar* debuglink_str_m
= ML_(img_strdup)(debuglink_escn.img,
"di.redi_dlk.1", debuglink_escn.ioff);
- dimg = find_debug_file( di, di->fsm.filename, buildid,
- debuglink_str_m, crc, False );
+ dimg = ML_(find_debug_file)( di, di->fsm.filename, buildid,
+ debuglink_str_m, crc, False );
if (debuglink_str_m)
ML_(dinfo_free)(debuglink_str_m);
} else {
/* See if we can find a matching debug file */
- dimg = find_debug_file( di, di->fsm.filename, buildid,
- NULL, 0, False );
+ dimg = ML_(find_debug_file)( di, di->fsm.filename, buildid,
+ NULL, 0, False );
}
}
@@ -2779,7 +2781,7 @@ Bool ML_(read_elf_debug_info) ( struct _DebugInfo* di )
section here, and just looking for a file of the same name
either the extra-path or on the server. */
if (dimg == NULL && VG_(clo_allow_mismatched_debuginfo)) {
- dimg = find_debug_file_ad_hoc( di, di->fsm.filename );
+ dimg = ML_(find_debug_file_ad_hoc)( di, di->fsm.filename );
}
/* TOPLEVEL */
@@ -3049,8 +3051,8 @@ Bool ML_(read_elf_debug_info) ( struct _DebugInfo* di )
+ buildid_offset + j));
/* See if we can find a matching debug file */
- aimg = find_debug_file( di, rdbgname, altbuildid,
- altfile_str_m, 0, True );
+ aimg = ML_(find_debug_file)( di, rdbgname, altbuildid,
+ altfile_str_m, 0, True );
ML_(dinfo_free)(rdbgname);
diff --git a/coregrind/m_debuginfo/readpdb.c b/coregrind/m_debuginfo/readpdb.c
index 01e54dccd..98fc0f805 100644
--- a/coregrind/m_debuginfo/readpdb.c
+++ b/coregrind/m_debuginfo/readpdb.c
@@ -44,6 +44,7 @@
#include "pub_core_libcprint.h"
#include "pub_core_libcproc.h" // VG_(getpid), system
#include "pub_core_options.h" // VG_(clo_verbosity)
+#include "pub_core_oset.h"
#include "pub_core_xarray.h" // keeps priv_storage.h happy
#include "pub_core_redir.h"
@@ -52,6 +53,9 @@
#include "priv_d3basics.h"
#include "priv_storage.h"
#include "priv_readpdb.h" // self
+#include "priv_readelf.h" /* open/find_debug_file/_ad_hoc */
+#include "priv_readdwarf.h" /* 'cos ELF contains DWARF */
+#include "priv_readdwarf3.h"
/*------------------------------------------------------------*/
@@ -2781,6 +2785,1013 @@ HChar* ML_(find_name_of_pdb_file)( const HChar* pename )
return res;
}
+
+static
+Bool is_pe_object_file( const void* image, SizeT n_image, Bool rel_ok )
+{
+ const IMAGE_DOS_HEADER* dos_avma;
+ const IMAGE_NT_HEADERS* ntheaders_avma;
+
+ dos_avma = (const IMAGE_DOS_HEADER *)image;
+ if (dos_avma->e_magic != IMAGE_DOS_SIGNATURE)
+ return False;
+
+ ntheaders_avma
+ = (const IMAGE_NT_HEADERS *)(((const Char*)image) + dos_avma->e_lfanew);
+ if (ntheaders_avma->Signature != IMAGE_NT_SIGNATURE)
+ return False;
+
+ return True;
+}
+
+
+static
+Bool is_pe_object_file_by_DiImage( DiImage* img, Bool rel_ok )
+{
+ char buf[1024];
+
+ if (!ML_(img_valid)(img, 0, sizeof(buf)))
+ return False;
+
+ ML_(img_get)(buf, img, 0, sizeof(buf));
+ return is_pe_object_file( buf, sizeof(buf), rel_ok );
+}
+
+
+static
+int shdr_name_strcmp( DiImage *img, IMAGE_SECTION_HEADER *shdr,
+ DiOffT strtab_off, const char *name )
+{
+ if (*shdr->Name != '/') return VG_(strcmp)((char *)shdr->Name, name);
+ Long n = VG_(strtoll10)((const char*)shdr->Name + 1, NULL);
+ return ML_(img_strcmp_c)(img, strtab_off + n, name);
+}
+
+
+static
+Int cmp_IMAGE_SYMBOL_by_section_value( const void* v1, const void* v2 )
+{
+ const IMAGE_SYMBOL* s1 = v1, *s2 = v2;
+ if (s1->SectionNumber != s2->SectionNumber)
+ return s1->SectionNumber - s2->SectionNumber;
+ if (s1->Value != s2->Value)
+ return s1->Value - s2->Value;
+ return 0;
+}
+
+
+Bool ML_(read_pe_debug_info) ( struct _DebugInfo* di, Addr obj_avma,
+ PtrdiffT obj_bias )
+{
+ /* TOPLEVEL */
+ Bool res, ok;
+ Word i, n;
+
+ /* Image for the main PE file we're working with. */
+ DiImage* mimg = NULL;
+
+ /* Ditto for any PE debuginfo file that we might happen to load. */
+ DiImage* dimg = NULL;
+
+ /* Ditto for alternate PE debuginfo file that we might happen to load. */
+ DiImage* aimg = NULL;
+
+ /* Program header table image addr, # entries, entry size */
+ DiOffT phdr_mioff = 0;
+ UWord phdr_mnent = 0;
+ UWord phdr_ment_szB = 0;
+
+ /* Section header image addr, # entries, entry size. Also the
+ associated string table. */
+ DiOffT shdr_mioff = 0;
+ UWord shdr_mnent = 0;
+ UWord shdr_ment_szB = 0;
+
+ DiOffT strtab_mioff = 0;
+
+ vg_assert(di);
+ vg_assert(di->have_dinfo == False);
+ vg_assert(di->fsm.filename);
+ vg_assert(!di->symtab);
+ vg_assert(!di->loctab);
+ vg_assert(!di->inltab);
+ vg_assert(!di->cfsi_base);
+ vg_assert(!di->cfsi_m_ix);
+ vg_assert(!di->cfsi_rd);
+ vg_assert(!di->cfsi_exprs);
+ vg_assert(!di->strpool);
+ vg_assert(!di->fndnpool);
+ vg_assert(!di->soname);
+
+ res = False;
+
+ /* Connect to the primary object image, so that we can read symbols
+ and line number info out of it. It will be disconnected
+ immediately thereafter; it is only connected transiently. */
+ mimg = ML_(img_from_local_file)(di->fsm.filename);
+ if (mimg == NULL) {
+ VG_(message)(Vg_UserMsg, "warning: connection to image %s failed\n",
+ di->fsm.filename );
+ VG_(message)(Vg_UserMsg, " no symbols or debug info loaded\n" );
+ return False;
+ }
+
+ /* Ok, the object image is available. Now verify that it is a
+ valid PE. */
+ ok = is_pe_object_file_by_DiImage(mimg, False);
+ if (!ok)
+ goto out;
+
+ if (VG_(clo_verbosity) > 1 || VG_(clo_trace_redir))
+ VG_(message)(Vg_DebugMsg, "Reading syms from %s\n",
+ di->fsm.filename );
+
+ /* Find where the program and section header tables are, and give
+ up if either is missing or outside the image (bogus). */
+ IMAGE_DOS_HEADER dos_hdr;
+ ok = ML_(img_valid)(mimg, 0, sizeof(dos_hdr));
+ vg_assert(ok); // ML_(is_pe_object_file) should ensure this
+ ML_(img_get)(&dos_hdr, mimg, 0, sizeof(dos_hdr));
+
+ IMAGE_NT_HEADERS nt_hdr;
+ ok = ML_(img_valid)(mimg, dos_hdr.e_lfanew, sizeof(nt_hdr));
+ vg_assert(ok); // ML_(is_pe_object_file) should ensure this
+ ML_(img_get)(&nt_hdr, mimg, dos_hdr.e_lfanew, sizeof(nt_hdr));
+
+ phdr_mioff = dos_hdr.e_lfanew;
+ phdr_mnent = 1;
+ phdr_ment_szB = OFFSET_OF(IMAGE_NT_HEADERS, OptionalHeader)
+ + nt_hdr.FileHeader.SizeOfOptionalHeader;
+
+ shdr_mioff = phdr_mioff + phdr_ment_szB;
+ shdr_mnent = nt_hdr.FileHeader.NumberOfSections;
+ shdr_ment_szB = sizeof(IMAGE_SECTION_HEADER);
+
+ if (nt_hdr.FileHeader.PointerToSymbolTable
+ && nt_hdr.FileHeader.NumberOfSymbols)
+ {
+ strtab_mioff = nt_hdr.FileHeader.PointerToSymbolTable
+ + nt_hdr.FileHeader.NumberOfSymbols * sizeof(IMAGE_SYMBOL);
+ }
+
+ TRACE_SYMTAB("------ Basic facts about the object ------\n");
+ TRACE_SYMTAB("object: n_oimage %llu\n",
+ (ULong)ML_(img_size)(mimg));
+ TRACE_SYMTAB("phdr: ioff %llu nent %lu ent_szB %lu\n",
+ phdr_mioff, phdr_mnent, phdr_ment_szB);
+ TRACE_SYMTAB("shdr: ioff %llu nent %lu ent_szB %lu\n",
+ shdr_mioff, shdr_mnent, shdr_ment_szB);
+ for (i = 0; i < VG_(sizeXA)(di->fsm.maps); i++) {
+ const DebugInfoMapping* map = VG_(indexXA)(di->fsm.maps, i);
+ if (map->rx)
+ TRACE_SYMTAB("rx_map: avma %#lx size %lu foff %ld\n",
+ map->avma, map->size, map->foff);
+ }
+ for (i = 0; i < VG_(sizeXA)(di->fsm.maps); i++) {
+ const DebugInfoMapping* map = VG_(indexXA)(di->fsm.maps, i);
+ if (map->rw)
+ TRACE_SYMTAB("rw_map: avma %#lx size %lu foff %ld\n",
+ map->avma, map->size, map->foff);
+ }
+
+ if (phdr_mnent == 0
+ || !ML_(img_valid)(mimg, phdr_mioff, phdr_mnent * phdr_ment_szB)) {
+ ML_(symerr)(di, True, "Missing or invalid PE Program Header Table");
+ goto out;
+ }
+
+ if (shdr_mnent == 0
+ || !ML_(img_valid)(mimg, shdr_mioff, shdr_mnent * shdr_ment_szB)) {
+ ML_(symerr)(di, True, "Missing or invalid PE Section Header Table");
+ goto out;
+ }
+
+ TRACE_SYMTAB("shdr: string table at %llu\n", strtab_mioff);
+
+ /* TOPLEVEL */
+ /* Look through the program header table, and:
+ - find (or fake up) the .soname for this object.
+ */
+ TRACE_SYMTAB("\n");
+ TRACE_SYMTAB("------ Examining the program headers ------\n");
+ vg_assert(di->soname == NULL);
+
+ {
+ /* TOPLEVEL */
+ DWORD prev_svma = 0;
+
+ for (i = 0; i < shdr_mnent; i++) {
+ IMAGE_SECTION_HEADER a_shdr;
+ ML_(img_get)(&a_shdr, mimg, shdr_mioff + i * shdr_ment_szB, sizeof(a_shdr));
+
+ if (a_shdr.Characteristics & IMAGE_SCN_CNT_UNINITIALIZED_DATA) continue;
+
+ TRACE_SYMTAB("PT_LOAD[%ld]: p_vaddr %#lx (prev %#lx)\n",
+ i, (UWord)a_shdr.VirtualAddress, (UWord)prev_svma);
+ TRACE_SYMTAB("PT_LOAD[%ld]: p_offset %lu, p_filesz %lu,"
+ " perms %c%c%c\n",
+ i, (UWord)a_shdr.PointerToRawData, (UWord)a_shdr.SizeOfRawData,
+ a_shdr.Characteristics & IMAGE_SCN_MEM_READ ? 'r' : '-',
+ a_shdr.Characteristics & IMAGE_SCN_MEM_WRITE ? 'w' : '-',
+ a_shdr.Characteristics & IMAGE_SCN_MEM_EXECUTE ? 'x' : '-');
+ if (a_shdr.VirtualAddress < prev_svma) {
+ ML_(symerr)(di, True, "PE Sections are not in ascending order");
+ goto out;
+ }
+ prev_svma = a_shdr.VirtualAddress;
+
+ DebugInfoMapping map;
+ map.avma = (Addr)obj_avma + a_shdr.VirtualAddress;
+ map.size = a_shdr.Misc.VirtualSize;
+ map.foff = a_shdr.PointerToRawData;
+ map.ro = False;
+ map.rx = False;
+ map.rw = False;
+
+ if (a_shdr.Misc.VirtualSize == 0) continue;
+
+ DWORD rx_mask = (IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_EXECUTE);
+ DWORD rw_mask = (IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE);
+ DWORD mask = rx_mask | rw_mask;
+ if ((a_shdr.Characteristics & mask) == rw_mask) {
+ map.rw = True;
+ VG_(addToXA)(di->fsm.maps, &map);
+ di->fsm.have_rw_map = True;
+ TRACE_SYMTAB("PT_LOAD[%ld]: acquired as rw\n", i);
+ }
+ else if ((a_shdr.Characteristics & mask) == rx_mask) {
+ map.rx = True;
+ VG_(addToXA)(di->fsm.maps, &map);
+ di->fsm.have_rx_map = True;
+ TRACE_SYMTAB("PT_LOAD[%ld]: acquired as rx\n", i);
+ }
+ else if ((a_shdr.Characteristics & mask) == IMAGE_SCN_MEM_READ) {
+ map.ro = True;
+ VG_(addToXA)(di->fsm.maps, &map);
+ TRACE_SYMTAB("PT_LOAD[%ld]: acquired as ro\n", i);
+ } else {
+ VG_(addToXA)(di->fsm.maps, &map);
+ TRACE_SYMTAB("PT_LOAD[%ld]: acquired\n", i);
+ }
+ } /* for (i = 0; i < phdr_Mnent; i++) ... */
+
+ for (i = 0; i < shdr_mnent; i++) {
+ IMAGE_SECTION_HEADER a_shdr;
+ ML_(img_get)(&a_shdr, mimg, shdr_mioff + i * shdr_ment_szB, sizeof(a_shdr));
+
+ /* Try to get the soname. If there isn't one, use "NONE".
+ The seginfo needs to have some kind of soname in order to
+ facilitate writing redirect functions, since all redirect
+ specifications require a soname (pattern). */
+ if (0 == shdr_name_strcmp(mimg, &a_shdr, strtab_mioff, ".edata")
+ && di->soname == NULL) {
+ IMAGE_EXPORT_DIRECTORY a_edir;
+ ML_(img_get)(&a_edir, mimg, a_shdr.PointerToRawData, sizeof(a_edir));
+
+ if (a_edir.Name >= a_shdr.VirtualAddress
+ && a_edir.Name + sizeof(DWORD)
+ <= a_shdr.VirtualAddress + a_shdr.Misc.VirtualSize) {
+ di->soname = ML_(img_strdup)(mimg, "di.redi.1",
+ a_shdr.PointerToRawData
+ + a_edir.Name - a_shdr.VirtualAddress);
+ TRACE_SYMTAB("Found soname = %s\n", di->soname);
+ }
+ }
+ } /* for (i = 0; i < phdr_Mnent; i++) ... */
+ /* TOPLEVEL */
+
+ } /* examine the program headers (local scope) */
+
+ /* TOPLEVEL */
+
+ /* HACK: Force it even if we didn't find any */
+ di->fsm.have_rw_map = True;
+
+ /* If, after looking at all the program headers, we still didn't
+ find a soname, add a fake one. */
+ if (di->soname == NULL) {
+ TRACE_SYMTAB("No soname found; using (fake) \"NONE\"\n");
+ di->soname = ML_(dinfo_strdup)("di.redi.2", "NONE");
+ }
+
+ /* Now read the section table. */
+ TRACE_SYMTAB("\n");
+ TRACE_SYMTAB("------ Examining the section headers ------\n");
+ for (i = 0; i < VG_(sizeXA)(di->fsm.maps); i++) {
+ const DebugInfoMapping* map = VG_(indexXA)(di->fsm.maps, i);
+ if (map->rx)
+ TRACE_SYMTAB("rx: at %#lx are mapped foffsets %ld .. %lu\n",
+ map->avma, map->foff, map->foff + map->size - 1 );
+ }
+ for (i = 0; i < VG_(sizeXA)(di->fsm.maps); i++) {
+ const DebugInfoMapping* map = VG_(indexXA)(di->fsm.maps, i);
+ if (map->rw)
+ TRACE_SYMTAB("rw: at %#lx are mapped foffsets %ld .. %lu\n",
+ map->avma, map->foff, map->foff + map->size - 1 );
+ }
+
+ /* TOPLEVEL */
+ /* Iterate over section headers */
+ for (i = 0; i < shdr_mnent; i++) {
+ IMAGE_SECTION_HEADER a_shdr;
+ ML_(img_get)(&a_shdr, mimg, shdr_mioff + i * shdr_ment_szB, sizeof(a_shdr));
+
+ HChar* name = (HChar*)a_shdr.Name;
+ Addr svma = obj_avma + a_shdr.VirtualAddress;
+ OffT foff = a_shdr.PointerToRawData;
+ UWord size = a_shdr.Misc.VirtualSize;
+
+ TRACE_SYMTAB(" [sec %2ld] foff %6ld .. %6lu "
+ " svma %p name \"%s\"\n",
+ i, foff, (size == 0) ? foff : foff+size-1, (void *) svma, name);
+
+ /* Ignore zero sized sections. */
+ if (size == 0) {
+ TRACE_SYMTAB("zero sized section \"%s\", ignoring\n", name);
+ continue;
+ }
+
+# define BAD(_secname) \
+ do { ML_(symerr)(di, True, \
+ "Can't make sense of " _secname \
+ " section mapping"); \
+ /* make sure we don't assert if we find */ \
+ /* ourselves back in this routine later, */ \
+ /* with the same di */ \
+ di->soname = NULL; \
+ goto out; \
+ } while (0)
+
+ /* Find avma-s for: .text .data .rodata .bss and .eh_frame */
+
+ /* Accept .text where mapped as rx (code), even if zero-sized */
+ if (0 == shdr_name_strcmp(mimg, &a_shdr, strtab_mioff, ".text")) {
+ if (!di->text_present) {
+ di->text_present = True;
+ di->text_svma = svma;
+ di->text_avma = svma;
+ di->text_size = size;
+ di->text_bias = 0;
+ di->text_debug_svma = svma;
+ di->text_debug_bias = 0;
+ TRACE_SYMTAB("acquiring .text svma = %#lx .. %#lx\n",
+ di->text_svma,
+ di->text_svma + di->text_size - 1);
+ TRACE_SYMTAB("acquiring .text avma = %#lx .. %#lx\n",
+ di->text_avma,
+ di->text_avma + di->text_size - 1);
+ TRACE_SYMTAB("acquiring .text bias = %#lx debug %#lx\n",
+ (UWord)di->text_bias, (UWord)di->text_debug_bias);
+ } else {
+ BAD(".text");
+ }
+ }
+
+ /* Accept .data where mapped as rw (data), even if zero-sized */
+ if (0 == shdr_name_strcmp(mimg, &a_shdr, strtab_mioff, ".data")) {
+ if (!di->data_present) {
+ di->data_present = True;
+ di->data_svma = svma;
+ di->data_avma = svma;
+ di->data_size = size;
+ di->data_bias = 0;
+ di->data_debug_svma = svma;
+ di->data_debug_bias = 0;
+ TRACE_SYMTAB("acquiring .data svma = %#lx .. %#lx\n",
+ di->data_svma,
+ di->data_svma + di->data_size - 1);
+ TRACE_SYMTAB("acquiring .data avma = %#lx .. %#lx\n",
+ di->data_avma,
+ di->data_avma + di->data_size - 1);
+ TRACE_SYMTAB("acquiring .data bias = %#lx\n", (UWord)di->data_bias);
+ } else {
+ BAD(".data");
+ }
+ }
+
+ /* Accept .rodata where mapped as rx or rw (data), even if zero-sized */
+ if (0 == shdr_name_strcmp(mimg, &a_shdr, strtab_mioff, ".rodata")) {
+ if (!di->rodata_present) {
+ di->rodata_svma = svma;
+ di->rodata_avma = svma;
+ di->rodata_size = size;
+ di->rodata_debug_svma = svma;
+ di->rodata_bias = 0;
+ di->rodata_debug_bias = 0;
+ di->rodata_present = True;
+ TRACE_SYMTAB("acquiring .rodata svma = %#lx .. %#lx\n",
+ di->rodata_svma,
+ di->rodata_svma + di->rodata_size - 1);
+ TRACE_SYMTAB("acquiring .rodata avma = %#lx .. %#lx\n",
+ di->rodata_avma,
+ di->rodata_avma + di->rodata_size - 1);
+ TRACE_SYMTAB("acquiring .rodata bias = %#lx\n",
+ (UWord)di->rodata_bias);
+ } else {
+ BAD(".rodata");
+ }
+ }
+
+ /* Accept .bss where mapped as rw (data), even if zero-sized */
+ if (0 == shdr_name_strcmp(mimg, &a_shdr, strtab_mioff, ".bss")) {
+ if (!di->bss_present) {
+ di->bss_present = True;
+ di->bss_svma = svma;
+ di->bss_avma = svma;
+ di->bss_size = size;
+ di->bss_bias = 0;
+ di->bss_debug_svma = svma;
+ di->bss_debug_bias = 0;
+ TRACE_SYMTAB("acquiring .bss svma = %#lx .. %#lx\n",
+ di->bss_svma,
+ di->bss_svma + di->bss_size - 1);
+ TRACE_SYMTAB("acquiring .bss avma = %#lx .. %#lx\n",
+ di->bss_avma,
+ di->bss_avma + di->bss_size - 1);
+ TRACE_SYMTAB("acquiring .bss bias = %#lx\n",
+ (UWord)di->bss_bias);
+ } else {
+ BAD(".bss");
+ }
+ }
+
+ /* Accept .eh_frame where mapped as rx (code). This seems to be
+ the common case. However, if that doesn't pan out, try for
+ rw (data) instead. We can handle up to N_EHFRAME_SECTS per
+ PE object. */
+ if (0 == shdr_name_strcmp(mimg, &a_shdr, strtab_mioff, ".eh_frame")) {
+ if (di->n_ehframe < N_EHFRAME_SECTS) {
+ di->ehframe_avma[di->n_ehframe] = svma;
+ di->ehframe_size[di->n_ehframe] = size;
+ TRACE_SYMTAB("acquiring .eh_frame avma = %#lx\n",
+ di->ehframe_avma[di->n_ehframe]);
+ di->n_ehframe++;
+ } else {
+ BAD(".eh_frame");
+ }
+ }
+
+# undef BAD
+
+ } /* iterate over the section headers */
+
+ /* TOPLEVEL */
+ if (0) VG_(printf)("YYYY text_: avma %#lx size %lu bias %#lx\n",
+ di->text_avma, di->text_size, (UWord)di->text_bias);
+
+ if (VG_(clo_verbosity) > 2 || VG_(clo_trace_redir))
+ VG_(message)(Vg_DebugMsg, " svma %#010lx, avma %#010lx\n",
+ di->text_avma - di->text_bias,
+ di->text_avma );
+
+ TRACE_SYMTAB("\n");
+ TRACE_SYMTAB("------ Finding image addresses "
+ "for debug-info sections ------\n");
+
+ /* TOPLEVEL */
+ /* Find interesting sections, read the symbol table(s), read any
+ debug information. Each section is located either in the main,
+ debug or alt-debug files, but only in one. For each section,
+ |section_escn| records which of |mimg|, |dimg| or |aimg| we
+ found it in, along with the section's image offset and its size.
+ The triples (section_img, section_ioff, section_szB) are
+ consistent, in that they are always either (NULL,
+ DiOffT_INVALID, 0), or refer to the same image, and are all
+ assigned together. */
+ {
+ /* TOPLEVEL */
+ DiSlice debuglink_escn = DiSlice_INVALID; // .gnu_debuglink
+ DiSlice debug_line_escn = DiSlice_INVALID; // .debug_line (dwarf2)
+ DiSlice debug_info_escn = DiSlice_INVALID; // .debug_info (dwarf2)
+ DiSlice debug_types_escn = DiSlice_INVALID; // .debug_types (dwarf4)
+ DiSlice debug_abbv_escn = DiSlice_INVALID; // .debug_abbrev (dwarf2)
+ DiSlice debug_str_escn = DiSlice_INVALID; // .debug_str (dwarf2)
+ DiSlice debug_ranges_escn = DiSlice_INVALID; // .debug_ranges (dwarf2)
+ DiSlice debug_loc_escn = DiSlice_INVALID; // .debug_loc (dwarf2)
+ DiSlice debug_frame_escn = DiSlice_INVALID; // .debug_frame (dwarf2)
+ DiSlice debug_line_alt_escn = DiSlice_INVALID; // .debug_line (alt)
+ DiSlice debug_info_alt_escn = DiSlice_INVALID; // .debug_info (alt)
+ DiSlice debug_abbv_alt_escn = DiSlice_INVALID; // .debug_abbrev (alt)
+ DiSlice debug_str_alt_escn = DiSlice_INVALID; // .debug_str (alt)
+ DiSlice dwarf1d_escn = DiSlice_INVALID; // .debug (dwarf1)
+ DiSlice dwarf1l_escn = DiSlice_INVALID; // .line (dwarf1)
+ DiSlice ehframe_escn[N_EHFRAME_SECTS]; // .eh_frame (dwarf2)
+
+ for (i = 0; i < N_EHFRAME_SECTS; i++)
+ ehframe_escn[i] = DiSlice_INVALID;
+
+ /* Find all interesting sections */
+
+ UInt ehframe_mix = 0;
+
+ /* What FIND does: it finds the section called _SEC_NAME. The
+ size of it is assigned to _SEC_SIZE. The address of the
+ section in the transiently loaded oimage is assigned to
+ _SEC_IMG. If the section is found, _POST_FX is executed
+ after _SEC_NAME and _SEC_SIZE have been assigned to.
+
+ Even for sections which are marked loadable, the client's
+ ld.so may not have loaded them yet, so there is no guarantee
+ that we can safely prod around in any such area). Because
+ the entire object file is transiently mapped aboard for
+ inspection, it's always safe to inspect that area. */
+
+ /* TOPLEVEL */
+ /* Iterate over section headers (again) */
+ for (i = 0; i < shdr_mnent; i++) {
+
+# define FINDX(_sec_name, _sec_escn, _post_fx) \
+ do { \
+ IMAGE_SECTION_HEADER a_shdr; \
+ ML_(img_get)(&a_shdr, mimg, \
+ shdr_mioff + i * shdr_ment_szB, \
+ sizeof(a_shdr)); \
+ if (0 == shdr_name_strcmp(mimg, &a_shdr, strtab_mioff, _sec_name)) { \
+ _sec_escn.img = mimg; \
+ _sec_escn.ioff = (DiOffT)a_shdr.PointerToRawData; \
+ _sec_escn.szB = a_shdr.Misc.VirtualSize; \
+ vg_assert(_sec_escn.img != NULL); \
+ vg_assert(_sec_escn.ioff != DiOffT_INVALID); \
+ TRACE_SYMTAB( "%-18s: ioff %llu .. %llu\n", \
+ _sec_name, (ULong)a_shdr.PointerToRawData, \
+ ((ULong)a_shdr.PointerToRawData) + a_shdr.Misc.VirtualSize - 1); \
+ /* SHT_NOBITS sections have zero size in the file. */ \
+ if (a_shdr.PointerToRawData + \
+ a_shdr.Misc.VirtualSize > ML_(img_real_size)(mimg)) { \
+ ML_(symerr)(di, True, \
+ " section beyond image end?!"); \
+ goto out; \
+ } \
+ _post_fx; \
+ } \
+ } while (0);
+
+ /* Version with no post-effects */
+# define FIND(_sec_name, _sec_escn) \
+ FINDX(_sec_name, _sec_escn, /**/)
+
+ /* NAME ElfSec */
+ FIND( ".gnu_debuglink", debuglink_escn)
+
+ FIND( ".debug_line", debug_line_escn)
+ if (!ML_(sli_is_valid)(debug_line_escn))
+ FIND(".zdebug_line", debug_line_escn)
+
+ FIND( ".debug_info", debug_info_escn)
+ if (!ML_(sli_is_valid)(debug_info_escn))
+ FIND(".zdebug_info", debug_info_escn)
+
+ FIND( ".debug_types", debug_types_escn)
+ if (!ML_(sli_is_valid)(debug_types_escn))
+ FIND(".zdebug_types", debug_types_escn)
+
+ FIND( ".debug_abbrev", debug_abbv_escn)
+ if (!ML_(sli_is_valid)(debug_abbv_escn))
+ FIND(".zdebug_abbrev", debug_abbv_escn)
+
+ FIND( ".debug_str", debug_str_escn)
+ if (!ML_(sli_is_valid)(debug_str_escn))
+ FIND(".zdebug_str", debug_str_escn)
+
+ FIND( ".debug_ranges", debug_ranges_escn)
+ if (!ML_(sli_is_valid)(debug_ranges_escn))
+ FIND(".zdebug_ranges", debug_ranges_escn)
+
+ FIND( ".debug_loc", debug_loc_escn)
+ if (!ML_(sli_is_valid)(debug_loc_escn))
+ FIND(".zdebug_loc", debug_loc_escn)
+
+ FIND( ".debug_frame", debug_frame_escn)
+ if (!ML_(sli_is_valid)(debug_frame_escn))
+ FIND(".zdebug_frame", debug_frame_escn)
+
+ FIND( ".debug", dwarf1d_escn)
+ FIND( ".line", dwarf1l_escn)
+
+ FINDX( ".eh_frame", ehframe_escn[ehframe_mix],
+ do { ehframe_mix++; vg_assert(ehframe_mix <= N_EHFRAME_SECTS);
+ } while (0)
+ )
+ /* Comment_on_EH_FRAME_MULTIPLE_INSTANCES: w.r.t. .eh_frame
+ multi-instance kludgery, how are we assured that the order
+ in which we fill in ehframe_escn[] is consistent with the
+ order in which we previously filled in di->ehframe_avma[]
+ and di->ehframe_size[] ? By the fact that in both cases,
+ these arrays were filled in by iterating over the section
+ headers top-to-bottom. So both loops (this one and the
+ previous one) encounter the .eh_frame entries in the same
+ order and so fill in these arrays in a consistent order.
+ */
+
+# undef FINDX
+# undef FIND
+ } /* Iterate over section headers (again) */
+
+ /* TOPLEVEL */
+ /* Now, see if we can find a debuginfo object, and if so connect
+ |dimg| to it. */
+ vg_assert(dimg == NULL && aimg == NULL);
+
+ /* Look for a debug image that matches either the build-id or
+ the debuglink-CRC32 in the main image. If the main image
+ doesn't contain either of those then this won't even bother
+ to try looking. This looks in all known places, including
+ the --extra-debuginfo-path if specified and on the
+ --debuginfo-server if specified. */
+ if (debuglink_escn.img != NULL) {
+ UInt crc_offset
+ = VG_ROUNDUP(ML_(img_strlen)(debuglink_escn.img,
+ debuglink_escn.ioff)+1, 4);
+ vg_assert(crc_offset + sizeof(UInt) <= debuglink_escn.szB);
+
+ /* Extract the CRC from the debuglink section */
+ UInt crc = ML_(img_get_UInt)(debuglink_escn.img,
+ debuglink_escn.ioff + crc_offset);
+
+ /* See if we can find a matching debug file */
+ HChar* debuglink_str_m
+ = ML_(img_strdup)(debuglink_escn.img,
+ "di.redi_dlk.1", debuglink_escn.ioff);
+ dimg = ML_(find_debug_file)( di, di->fsm.filename, NULL,
+ debuglink_str_m, crc, False );
+ if (debuglink_str_m)
+ ML_(dinfo_free)(debuglink_str_m);
+ } else {
+ /* See if we can find a matching debug file */
+ dimg = ML_(find_debug_file)( di, di->fsm.filename, NULL,
+ NULL, 0, False );
+ }
+
+ /* As a last-ditch measure, try looking for in the
+ --extra-debuginfo-path and/or on the --debuginfo-server, but
+ only in the case where --allow-mismatched-debuginfo=yes.
+ This is dangerous in that (1) it gives no assurance that the
+ debuginfo object matches the main one, and hence (2) we will
+ very likely get an assertion in the code below, if indeed
+ there is a mismatch. Hence it is disabled by default
+ (--allow-mismatched-debuginfo=no). Nevertheless it's
+ sometimes a useful way of getting out of a tight spot.
+
+ Note that we're ignoring the name in the .gnu_debuglink
+ section here, and just looking for a file of the same name
+ either the extra-path or on the server. */
+ if (dimg == NULL && VG_(clo_allow_mismatched_debuginfo)) {
+ dimg = ML_(find_debug_file_ad_hoc)( di, di->fsm.filename );
+ }
+
+ /* TOPLEVEL */
+ /* If we were successful in finding a debug image, pull various
+ SVMA/bias/size and image addresses out of it. */
+ if (dimg != NULL && is_pe_object_file_by_DiImage(dimg, False)) {
+
+ /* Pull out and validate program header and section header info */
+ IMAGE_DOS_HEADER dos_hdr_dimg;
+ ML_(img_get)(&dos_hdr_dimg, dimg, 0, sizeof(dos_hdr_dimg));
+
+ IMAGE_NT_HEADERS nt_hdr_dimg;
+ ML_(img_get)(&nt_hdr_dimg, dimg, dos_hdr_dimg.e_lfanew, sizeof(nt_hdr_dimg));
+
+ DiOffT phdr_dioff = dos_hdr_dimg.e_lfanew;
+ UWord phdr_dnent = 1;
+ UWord phdr_dent_szB = OFFSET_OF(IMAGE_NT_HEADERS, OptionalHeader)
+ + nt_hdr_dimg.FileHeader.SizeOfOptionalHeader;
+
+ DiOffT shdr_dioff = phdr_dioff + phdr_dent_szB;
+ UWord shdr_dnent = nt_hdr_dimg.FileHeader.NumberOfSections;
+ UWord shdr_dent_szB = sizeof(IMAGE_SECTION_HEADER);
+
+ DiOffT strtab_dioff = 0;
+ if (nt_hdr_dimg.FileHeader.PointerToSymbolTable
+ && nt_hdr_dimg.FileHeader.NumberOfSymbols)
+ {
+ strtab_dioff = nt_hdr_dimg.FileHeader.PointerToSymbolTable
+ + nt_hdr_dimg.FileHeader.NumberOfSymbols * sizeof(IMAGE_SYMBOL);
+ }
+
+ PtrdiffT obj_dsmva;
+ if (nt_hdr_dimg.OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC)
+ obj_dsmva = ((IMAGE_OPTIONAL_HEADER64 *)&nt_hdr_dimg.OptionalHeader)->ImageBase;
+ else
+ obj_dsmva = ((IMAGE_OPTIONAL_HEADER32 *)&nt_hdr_dimg.OptionalHeader)->ImageBase;
+
+ Bool need_dwarf2, need_dwarf1;
+
+ if (phdr_dnent == 0
+ || !ML_(img_valid)(dimg, phdr_dioff,
+ phdr_dnent * phdr_dent_szB)) {
+ ML_(symerr)(di, True,
+ "Missing or invalid PE Program Header Table"
+ " (debuginfo file)");
+ goto out;
+ }
+
+ if (shdr_dnent == 0
+ || !ML_(img_valid)(dimg, shdr_dioff,
+ shdr_dnent * shdr_dent_szB)) {
+ ML_(symerr)(di, True,
+ "Missing or invalid PE Section Header Table"
+ " (debuginfo file)");
+ goto out;
+ }
+
+ need_dwarf2 = (debug_info_escn.img == NULL);
+ need_dwarf1 = (dwarf1d_escn.img == NULL);
+
+ /* Find all interesting sections in the debug image */
+ for (i = 0; i < shdr_dnent; i++) {
+
+ /* Find debug svma and bias information for sections
+ we found in the main file. */
+
+# define FIND(_sec, _seg) \
+ do { \
+ IMAGE_SECTION_HEADER a_shdr; \
+ ML_(img_get)(&a_shdr, dimg, shdr_dioff + i * shdr_dent_szB, \
+ sizeof(a_shdr)); \
+ if (di->_sec##_present \
+ && 0 == shdr_name_strcmp(dimg, &a_shdr, strtab_dioff, "." #_sec)) { \
+ vg_assert(di->_sec##_size == a_shdr.Misc.VirtualSize); \
+ /* Assume we have a correct value for the main */ \
+ /* object's bias. Use that to derive the debuginfo */ \
+ /* object's bias, by adding the difference in SVMAs */ \
+ /* for the corresponding sections in the two files. */ \
+ /* That should take care of all prelinking effects. */ \
+ di->_sec##_debug_svma = obj_dsmva + a_shdr.VirtualAddress; \
+ di->_sec##_debug_bias \
+ = di->_sec##_bias + \
+ di->_sec##_svma - di->_sec##_debug_svma; \
+ TRACE_SYMTAB("acquiring ." #_sec \
+ " debug svma = %#lx .. %#lx\n", \
+ di->_sec##_debug_svma, \
+ di->_sec##_debug_svma + di->_sec##_size - 1); \
+ TRACE_SYMTAB("acquiring ." #_sec " debug bias = %#lx\n", \
+ (UWord)di->_sec##_debug_bias); \
+ } \
+ } while (0);
+
+ /* SECTION SEGMENT */
+ FIND(text, rx)
+ FIND(data, rw)
+ FIND(sdata, rw)
+ FIND(rodata, rw)
+ FIND(bss, rw)
+ FIND(sbss, rw)
+
+# undef FIND
+
+ /* Same deal as previous FIND, except only do it for those
+ sections which we didn't find in the main file. */
+
+# define FIND(_condition, _sec_name, _sec_escn) \
+ do { \
+ IMAGE_SECTION_HEADER a_shdr; \
+ ML_(img_get)(&a_shdr, dimg, shdr_dioff + i * shdr_dent_szB, \
+ sizeof(a_shdr)); \
+ if (_condition \
+ && 0 == shdr_name_strcmp(dimg, &a_shdr, strtab_dioff, _sec_name)) { \
+ if (_sec_escn.img != NULL) { \
+ ML_(symerr)(di, True, \
+ " debuginfo section duplicates a" \
+ " section in the main ELF file"); \
+ goto out; \
+ } \
+ _sec_escn.img = dimg; \
+ _sec_escn.ioff = (DiOffT)a_shdr.PointerToRawData; \
+ _sec_escn.szB = a_shdr.Misc.VirtualSize; \
+ vg_assert(_sec_escn.img != NULL); \
+ vg_assert(_sec_escn.ioff != DiOffT_INVALID); \
+ TRACE_SYMTAB( "%-18s: dioff %llu .. %llu\n", \
+ _sec_name, \
+ (ULong)a_shdr.PointerToRawData, \
+ ((ULong)a_shdr.PointerToRawData) + a_shdr.Misc.VirtualSize - 1); \
+ if (a_shdr.PointerToRawData \
+ + a_shdr.Misc.VirtualSize > ML_(img_real_size)(_sec_escn.img)) { \
+ ML_(symerr)(di, True, \
+ " section beyond image end?!"); \
+ goto out; \
+ } \
+ } \
+ } while (0);
+
+ /* NEEDED? NAME ElfSec */
+ FIND( need_dwarf2, ".debug_line", debug_line_escn)
+ if (!ML_(sli_is_valid)(debug_line_escn))
+ FIND(need_dwarf2, ".zdebug_line", debug_line_escn)
+
+ FIND( need_dwarf2, ".debug_info", debug_info_escn)
+ if (!ML_(sli_is_valid)(debug_info_escn))
+ FIND(need_dwarf2, ".zdebug_info", debug_info_escn)
+
+ FIND( need_dwarf2, ".debug_types", debug_types_escn)
+ if (!ML_(sli_is_valid)(debug_types_escn))
+ FIND(need_dwarf2, ".zdebug_types", debug_types_escn)
+
+ FIND( need_dwarf2, ".debug_abbrev", debug_abbv_escn)
+ if (!ML_(sli_is_valid)(debug_abbv_escn))
+ FIND(need_dwarf2, ".zdebug_abbrev", debug_abbv_escn)
+
+ FIND( need_dwarf2, ".debug_str", debug_str_escn)
+ if (!ML_(sli_is_valid)(debug_str_escn))
+ FIND(need_dwarf2, ".zdebug_str", debug_str_escn)
+
+ FIND( need_dwarf2, ".debug_ranges", debug_ranges_escn)
+ if (!ML_(sli_is_valid)(debug_ranges_escn))
+ FIND(need_dwarf2, ".zdebug_ranges", debug_ranges_escn)
+
+ FIND( need_dwarf2, ".debug_loc", debug_loc_escn)
+ if (!ML_(sli_is_valid)(debug_loc_escn))
+ FIND(need_dwarf2, ".zdebug_loc", debug_loc_escn)
+
+ FIND( need_dwarf2, ".debug_frame", debug_frame_escn)
+ if (!ML_(sli_is_valid)(debug_frame_escn))
+ FIND(need_dwarf2, ".zdebug_frame", debug_frame_escn)
+
+ FIND( need_dwarf1, ".debug", dwarf1d_escn)
+ FIND( need_dwarf1, ".line", dwarf1l_escn)
+
+# undef FIND
+ } /* Find all interesting sections */
+ } /* do we have a debug image? */
+
+ /* TOPLEVEL */
+ /* Read symbols */
+ if (!nt_hdr.FileHeader.PointerToSymbolTable)
+ ML_(symerr)(di, False, " object doesn't have a symbol table");
+ else
+ TRACE_SYMTAB( "\n--- Reading (PE, standard) (%u entries) ---\n",
+ nt_hdr.FileHeader.NumberOfSymbols );
+
+ XArray *symbols = VG_(newXA)(ML_(dinfo_zalloc), "di.rpedi.1",
+ ML_(dinfo_free), sizeof(IMAGE_SYMBOL));
+
+ for (i = 0; i < nt_hdr.FileHeader.NumberOfSymbols; i++) {
+ IMAGE_SYMBOL sym;
+ ML_(img_get)(&sym, mimg, nt_hdr.FileHeader.PointerToSymbolTable
+ + i * sizeof(IMAGE_SYMBOL), sizeof(sym));
+
+ if (sym.SectionNumber && sym.SectionNumber <= nt_hdr.FileHeader.NumberOfSections
+ && (ISFCN(sym.Type) || sym.StorageClass == IMAGE_SYM_CLASS_EXTERNAL
+ || sym.StorageClass == IMAGE_SYM_CLASS_LABEL))
+ VG_(addToXA)(symbols, &sym);
+
+ i += sym.NumberOfAuxSymbols;
+ }
+
+ VG_(setCmpFnXA)(symbols, cmp_IMAGE_SYMBOL_by_section_value);
+ VG_(sortXA)(symbols);
+
+ for (i = 0, n = VG_(sizeXA)(symbols); i < n; i++) {
+ const IMAGE_SYMBOL* sym = VG_(indexXA)(symbols, i);
+ const IMAGE_SYMBOL* nsym = i + 1 < n ? VG_(indexXA)(symbols, i + 1) : NULL;
+
+ IMAGE_SECTION_HEADER a_shdr;
+ ML_(img_get)(&a_shdr, mimg,
+ shdr_mioff + (sym->SectionNumber - 1) * shdr_ment_szB,
+ sizeof(a_shdr));
+
+ SymAVMAs sym_avmas_really;
+ Int sym_size = 0;
+ Bool is_text = False, is_ifunc = ISFCN(sym->Type);
+ Bool is_global = sym->StorageClass == IMAGE_SYM_CLASS_LABEL ? False : True;
+ sym_avmas_really.main = obj_avma + a_shdr.VirtualAddress + sym->Value;
+ SET_TOCPTR_AVMA(sym_avmas_really, 0);
+ SET_LOCAL_EP_AVMA(sym_avmas_really, 0);
+
+ if (!VG_(strcmp)((char *)a_shdr.Name, ".text"))
+ {
+ sym_size = di->text_size - sym->Value;
+ is_text = True;
+ }
+ if (!VG_(strcmp)((char *)a_shdr.Name, ".data"))
+ sym_size = di->data_size - sym->Value;
+ if (!VG_(strcmp)((char *)a_shdr.Name, ".rodata"))
+ sym_size = di->rodata_size - sym->Value;
+ if (!VG_(strcmp)((char *)a_shdr.Name, ".bss"))
+ sym_size = di->bss_size - sym->Value;
+
+ if (nsym && nsym->SectionNumber == sym->SectionNumber)
+ sym_size = nsym->Value - sym->Value;
+
+ DiSym disym;
+ VG_(memset)(&disym, 0, sizeof(disym));
+ HChar* cstr;
+
+ if (sym->N.Name.Short)
+ {
+ char buffer[9];
+ VG_(memcpy)(buffer, sym->N.ShortName, 8);
+ buffer[8] = 0;
+ cstr = ML_(dinfo_strdup)("di.res__n.1", buffer);
+ }
+ else
+ cstr = ML_(img_strdup)(mimg, "di.res__n.1",
+ strtab_mioff + sym->N.Name.Long);
+
+ disym.avmas = sym_avmas_really;
+ disym.pri_name = ML_(addStr) ( di, cstr, -1 );
+ disym.sec_names = NULL;
+ disym.size = sym_size;
+ disym.isText = is_text;
+ disym.isIFunc = is_ifunc;
+ disym.isGlobal = is_global;
+ if (cstr) { ML_(dinfo_free)(cstr); cstr = NULL; }
+ vg_assert(disym.pri_name);
+ vg_assert(GET_TOCPTR_AVMA(disym.avmas) == 0);
+ /* has no role except on ppc64be-linux */
+ ML_(addSym) ( di, &disym );
+
+ if (TRACE_SYMTAB_ENABLED) {
+ TRACE_SYMTAB(" rec(%c) [%4ld]: "
+ " val %#010lx, sz %4d %s\n",
+ is_text ? 't' : 'd',
+ i,
+ disym.avmas.main,
+ (Int)disym.size,
+ disym.pri_name
+ );
+ if (GET_LOCAL_EP_AVMA(disym.avmas) != 0) {
+ TRACE_SYMTAB(" local entry point %#010lx\n",
+ GET_LOCAL_EP_AVMA(disym.avmas));
+ }
+ }
+ }
+
+ VG_(deleteXA)(symbols);
+
+ /* TOPLEVEL */
+ /* Read .eh_frame and .debug_frame (call-frame-info) if any. Do
+ the .eh_frame section(s) first. */
+ vg_assert(di->n_ehframe >= 0 && di->n_ehframe <= N_EHFRAME_SECTS);
+ for (i = 0; i < di->n_ehframe; i++) {
+ /* see Comment_on_EH_FRAME_MULTIPLE_INSTANCES above for why
+ this next assertion should hold. */
+ vg_assert(ML_(sli_is_valid)(ehframe_escn[i]));
+ vg_assert(ehframe_escn[i].szB == di->ehframe_size[i]);
+ ML_(read_callframe_info_dwarf3)( di,
+ ehframe_escn[i],
+ di->ehframe_avma[i],
+ True/*is_ehframe*/ );
+ }
+ if (ML_(sli_is_valid)(debug_frame_escn)) {
+ ML_(read_callframe_info_dwarf3)( di,
+ debug_frame_escn,
+ 0/*assume zero avma*/,
+ False/*!is_ehframe*/ );
+ }
+
+ /* TOPLEVEL */
+ /* jrs 2006-01-01: icc-8.1 has been observed to generate
+ binaries without debug_str sections. Don't preclude
+ debuginfo reading for that reason, but, in
+ read_unitinfo_dwarf2, do check that debugstr is non-NULL
+ before using it. */
+ if (ML_(sli_is_valid)(debug_info_escn)
+ && ML_(sli_is_valid)(debug_abbv_escn)
+ && ML_(sli_is_valid)(debug_line_escn)) {
+ /* The old reader: line numbers and unwind info only */
+ ML_(read_debuginfo_dwarf3) ( di,
+ debug_info_escn,
+ debug_types_escn,
+ debug_abbv_escn,
+ debug_line_escn,
+ debug_str_escn,
+ debug_str_alt_escn );
+ /* The new reader: read the DIEs in .debug_info to acquire
+ information on variable types and locations or inline info.
+ But only if the tool asks for it, or the user requests it on
+ the command line. */
+ if (VG_(clo_read_var_info) /* the user or tool asked for it */
+ || VG_(clo_read_inline_info)) {
+ ML_(new_dwarf3_reader)(
+ di, debug_info_escn, debug_types_escn,
+ debug_abbv_escn, debug_line_escn,
+ debug_str_escn, debug_ranges_escn,
+ debug_loc_escn, debug_info_alt_escn,
+ debug_abbv_alt_escn, debug_line_alt_escn,
+ debug_str_alt_escn
+ );
+ }
+ }
+
+ } /* "Find interesting sections, read the symbol table(s), read any debug
+ information" (a local scope) */
+
+ /* TOPLEVEL */
+ res = True;
+
+ out:
+ {
+ /* Last, but not least, detach from the image(s). */
+ if (mimg) ML_(img_done)(mimg);
+ if (dimg) ML_(img_done)(dimg);
+ if (aimg) ML_(img_done)(aimg);
+
+ return res;
+ } /* out: */
+
+ /* NOTREACHED */
+}
+
#endif // defined(VGO_linux) || defined(VGO_darwin) || defined(VGO_solaris)
/*--------------------------------------------------------------------*/
--
2.29.2
|