From: Rémi B. <rb...@co...> - 2020-11-30 09:01:27
|
Hi! I've been trying to fix Valgrind support for Wine that got pretty broken lately, as the recent refactoring there makes most code now be compiled as PE .dll files. There's already some support in Valgrind to notify it and load debug information from PDB files, but in general when compiling Wine using GCC the debug information is instead generated as DWARF info, so that doesn't work. I figured that it was just a matter of adding support for parsing PE files in Valgrind, and here it is. I've hooked that to the existing PDB notification, in the case no PDB file could be found, and it now works pretty nicely for all Wine code, whether it's within ELF .so files, or PE .dll, including backtraces with a hybrid mix of both. I'm not sure how contributions to Valgrind are supposed to go, so I'm sending these as patches here, but feel free to redirect me. Cheers, Rémi Bernon (3): Update Windows PE / PDB struct definitions using fixed-size types. Increase the number of supported CFI registers. Implement DWARF in PE parsing support, as PDB fallback. coregrind/m_debuginfo/debuginfo.c | 63 +- coregrind/m_debuginfo/priv_readelf.h | 23 + coregrind/m_debuginfo/priv_readpdb.h | 8 + coregrind/m_debuginfo/readdwarf.c | 2 +- coregrind/m_debuginfo/readelf.c | 42 +- coregrind/m_debuginfo/readpdb.c | 1598 ++++++++++++++++++++++---- 6 files changed, 1506 insertions(+), 230 deletions(-) -- 2.29.2 |
From: Rémi B. <rb...@co...> - 2020-11-30 09:01:36
|
MinGW may generate DWARF information with cie.ra_reg == 32, which makes Valgrind consider it invalid. Signed-off-by: Rémi Bernon <rb...@co...> --- coregrind/m_debuginfo/readdwarf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coregrind/m_debuginfo/readdwarf.c b/coregrind/m_debuginfo/readdwarf.c index 5701c504b..5f3006f77 100644 --- a/coregrind/m_debuginfo/readdwarf.c +++ b/coregrind/m_debuginfo/readdwarf.c @@ -1749,7 +1749,7 @@ void ML_(read_debuginfo_dwarf1) ( #elif defined(VGP_s390x_linux) # define N_CFI_REGS 66 #else -# define N_CFI_REGS 20 +# define N_CFI_REGS 33 #endif /* Instructions for the automaton */ -- 2.29.2 |
[Valgrind-developers] [PATCH 1/3] Update Windows PE / PDB struct
definitions using fixed-size types.
From: Rémi B. <rb...@co...> - 2020-11-30 09:01:37
|
Instead of unsigned long which may be 64bit. Signed-off-by: Rémi Bernon <rb...@co...> --- coregrind/m_debuginfo/readpdb.c | 587 +++++++++++++++++++++----------- 1 file changed, 382 insertions(+), 205 deletions(-) diff --git a/coregrind/m_debuginfo/readpdb.c b/coregrind/m_debuginfo/readpdb.c index 652238354..01e54dccd 100644 --- a/coregrind/m_debuginfo/readpdb.c +++ b/coregrind/m_debuginfo/readpdb.c @@ -91,6 +91,7 @@ /*--- ---*/ /*------------------------------------------------------------*/ +typedef ULong ULONGLONG; typedef UInt DWORD; typedef UShort WORD; typedef UChar BYTE; @@ -109,25 +110,25 @@ typedef UChar BYTE; #pragma pack(2) typedef struct _IMAGE_DOS_HEADER { - unsigned short e_magic; /* 00: MZ Header signature */ - unsigned short e_cblp; /* 02: Bytes on last page of file */ - unsigned short e_cp; /* 04: Pages in file */ - unsigned short e_crlc; /* 06: Relocations */ - unsigned short e_cparhdr; /* 08: Size of header in paragraphs */ - unsigned short e_minalloc; /* 0a: Minimum extra paragraphs needed */ - unsigned short e_maxalloc; /* 0c: Maximum extra paragraphs needed */ - unsigned short e_ss; /* 0e: Initial (relative) SS value */ - unsigned short e_sp; /* 10: Initial SP value */ - unsigned short e_csum; /* 12: Checksum */ - unsigned short e_ip; /* 14: Initial IP value */ - unsigned short e_cs; /* 16: Initial (relative) CS value */ - unsigned short e_lfarlc; /* 18: File address of relocation table */ - unsigned short e_ovno; /* 1a: Overlay number */ - unsigned short e_res[4]; /* 1c: Reserved words */ - unsigned short e_oemid; /* 24: OEM identifier (for e_oeminfo) */ - unsigned short e_oeminfo; /* 26: OEM information; e_oemid specific */ - unsigned short e_res2[10]; /* 28: Reserved words */ - unsigned long e_lfanew; /* 3c: Offset to extended header */ + WORD e_magic; /* 00: MZ Header signature */ + WORD e_cblp; /* 02: Bytes on last page of file */ + WORD e_cp; /* 04: Pages in file */ + WORD e_crlc; /* 06: Relocations */ + WORD e_cparhdr; /* 08: Size of header in paragraphs */ + WORD e_minalloc; /* 0a: Minimum extra paragraphs needed */ + WORD e_maxalloc; /* 0c: Maximum extra paragraphs needed */ + WORD e_ss; /* 0e: Initial (relative) SS value */ + WORD e_sp; /* 10: Initial SP value */ + WORD e_csum; /* 12: Checksum */ + WORD e_ip; /* 14: Initial IP value */ + WORD e_cs; /* 16: Initial (relative) CS value */ + WORD e_lfarlc; /* 18: File address of relocation table */ + WORD e_ovno; /* 1a: Overlay number */ + WORD e_res[4]; /* 1c: Reserved words */ + WORD e_oemid; /* 24: OEM identifier (for e_oeminfo) */ + WORD e_oeminfo; /* 26: OEM information; e_oemid specific */ + WORD e_res2[10]; /* 28: Reserved words */ + DWORD e_lfanew; /* 3c: Offset to extended header */ } IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER; #define IMAGE_DOS_SIGNATURE 0x5A4D /* MZ */ @@ -146,92 +147,255 @@ typedef struct _IMAGE_DOS_HEADER { #define IMAGE_SUBSYSTEM_OS2_CUI 5 #define IMAGE_SUBSYSTEM_POSIX_CUI 7 +typedef struct _IMAGE_SYMBOL { + union { + BYTE ShortName[8]; + struct { + DWORD Short; + DWORD Long; + } Name; + DWORD LongName[2]; + } N; + DWORD Value; + WORD SectionNumber; + WORD Type; + BYTE StorageClass; + BYTE NumberOfAuxSymbols; +} IMAGE_SYMBOL; +typedef IMAGE_SYMBOL *PIMAGE_SYMBOL; + +#define IMAGE_SIZEOF_SYMBOL 18 + +#define IMAGE_SYM_UNDEFINED (SHORT)0 +#define IMAGE_SYM_ABSOLUTE (SHORT)-1 +#define IMAGE_SYM_DEBUG (SHORT)-2 + +#define IMAGE_SYM_TYPE_NULL 0x0000 +#define IMAGE_SYM_TYPE_VOID 0x0001 +#define IMAGE_SYM_TYPE_CHAR 0x0002 +#define IMAGE_SYM_TYPE_SHORT 0x0003 +#define IMAGE_SYM_TYPE_INT 0x0004 +#define IMAGE_SYM_TYPE_LONG 0x0005 +#define IMAGE_SYM_TYPE_FLOAT 0x0006 +#define IMAGE_SYM_TYPE_DOUBLE 0x0007 +#define IMAGE_SYM_TYPE_STRUCT 0x0008 +#define IMAGE_SYM_TYPE_UNION 0x0009 +#define IMAGE_SYM_TYPE_ENUM 0x000A +#define IMAGE_SYM_TYPE_MOE 0x000B +#define IMAGE_SYM_TYPE_BYTE 0x000C +#define IMAGE_SYM_TYPE_WORD 0x000D +#define IMAGE_SYM_TYPE_UINT 0x000E +#define IMAGE_SYM_TYPE_DWORD 0x000F +#define IMAGE_SYM_TYPE_PCODE 0x8000 + +#define IMAGE_SYM_DTYPE_NULL 0 +#define IMAGE_SYM_DTYPE_POINTER 1 +#define IMAGE_SYM_DTYPE_FUNCTION 2 +#define IMAGE_SYM_DTYPE_ARRAY 3 + +#define IMAGE_SYM_CLASS_END_OF_FUNCTION (BYTE )-1 +#define IMAGE_SYM_CLASS_NULL 0x0000 +#define IMAGE_SYM_CLASS_AUTOMATIC 0x0001 +#define IMAGE_SYM_CLASS_EXTERNAL 0x0002 +#define IMAGE_SYM_CLASS_STATIC 0x0003 +#define IMAGE_SYM_CLASS_REGISTER 0x0004 +#define IMAGE_SYM_CLASS_EXTERNAL_DEF 0x0005 +#define IMAGE_SYM_CLASS_LABEL 0x0006 +#define IMAGE_SYM_CLASS_UNDEFINED_LABEL 0x0007 +#define IMAGE_SYM_CLASS_MEMBER_OF_STRUCT 0x0008 +#define IMAGE_SYM_CLASS_ARGUMENT 0x0009 +#define IMAGE_SYM_CLASS_STRUCT_TAG 0x000A +#define IMAGE_SYM_CLASS_MEMBER_OF_UNION 0x000B +#define IMAGE_SYM_CLASS_UNION_TAG 0x000C +#define IMAGE_SYM_CLASS_TYPE_DEFINITION 0x000D +#define IMAGE_SYM_CLASS_UNDEFINED_STATIC 0x000E +#define IMAGE_SYM_CLASS_ENUM_TAG 0x000F +#define IMAGE_SYM_CLASS_MEMBER_OF_ENUM 0x0010 +#define IMAGE_SYM_CLASS_REGISTER_PARAM 0x0011 +#define IMAGE_SYM_CLASS_BIT_FIELD 0x0012 + +#define IMAGE_SYM_CLASS_FAR_EXTERNAL 0x0044 +#define IMAGE_SYM_CLASS_BLOCK 0x0064 +#define IMAGE_SYM_CLASS_FUNCTION 0x0065 +#define IMAGE_SYM_CLASS_END_OF_STRUCT 0x0066 +#define IMAGE_SYM_CLASS_FILE 0x0067 +#define IMAGE_SYM_CLASS_SECTION 0x0068 +#define IMAGE_SYM_CLASS_WEAK_EXTERNAL 0x0069 + +#define N_BTMASK 0x000F +#define N_TMASK 0x0030 +#define N_TMASK1 0x00C0 +#define N_TMASK2 0x00F0 +#define N_BTSHFT 4 +#define N_TSHIFT 2 + +#define BTYPE(x) ((x) & N_BTMASK) + +#ifndef ISPTR +#define ISPTR(x) (((x) & N_TMASK) == (IMAGE_SYM_DTYPE_POINTER << N_BTSHFT)) +#endif + +#ifndef ISFCN +#define ISFCN(x) (((x) & N_TMASK) == (IMAGE_SYM_DTYPE_FUNCTION << N_BTSHFT)) +#endif + +#ifndef ISARY +#define ISARY(x) (((x) & N_TMASK) == (IMAGE_SYM_DTYPE_ARRAY << N_BTSHFT)) +#endif + +#ifndef ISTAG +#define ISTAG(x) ((x)==IMAGE_SYM_CLASS_STRUCT_TAG || (x)==IMAGE_SYM_CLASS_UNION_TAG || (x)==IMAGE_SYM_CLASS_ENUM_TAG) +#endif + +#ifndef INCREF +#define INCREF(x) ((((x)&~N_BTMASK)<<N_TSHIFT)|(IMAGE_SYM_DTYPE_POINTER<<N_BTSHFT)|((x)&N_BTMASK)) +#endif +#ifndef DECREF +#define DECREF(x) ((((x)>>N_TSHIFT)&~N_BTMASK)|((x)&N_BTMASK)) +#endif + typedef struct _IMAGE_FILE_HEADER { - unsigned short Machine; - unsigned short NumberOfSections; - unsigned long TimeDateStamp; - unsigned long PointerToSymbolTable; - unsigned long NumberOfSymbols; - unsigned short SizeOfOptionalHeader; - unsigned short Characteristics; + WORD Machine; + WORD NumberOfSections; + DWORD TimeDateStamp; + DWORD PointerToSymbolTable; + DWORD NumberOfSymbols; + WORD SizeOfOptionalHeader; + WORD Characteristics; } IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER; typedef struct _IMAGE_DATA_DIRECTORY { - unsigned long VirtualAddress; - unsigned long Size; + DWORD VirtualAddress; + DWORD Size; } IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY; #define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16 +typedef struct _IMAGE_OPTIONAL_HEADER64 { + WORD Magic; /* 0x20b */ + BYTE MajorLinkerVersion; + BYTE MinorLinkerVersion; + DWORD SizeOfCode; + DWORD SizeOfInitializedData; + DWORD SizeOfUninitializedData; + DWORD AddressOfEntryPoint; + DWORD BaseOfCode; + ULONGLONG ImageBase; + DWORD SectionAlignment; + DWORD FileAlignment; + WORD MajorOperatingSystemVersion; + WORD MinorOperatingSystemVersion; + WORD MajorImageVersion; + WORD MinorImageVersion; + WORD MajorSubsystemVersion; + WORD MinorSubsystemVersion; + DWORD Win32VersionValue; + DWORD SizeOfImage; + DWORD SizeOfHeaders; + DWORD CheckSum; + WORD Subsystem; + WORD DllCharacteristics; + ULONGLONG SizeOfStackReserve; + ULONGLONG SizeOfStackCommit; + ULONGLONG SizeOfHeapReserve; + ULONGLONG SizeOfHeapCommit; + DWORD LoaderFlags; + DWORD NumberOfRvaAndSizes; + IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; +} IMAGE_OPTIONAL_HEADER64, *PIMAGE_OPTIONAL_HEADER64; + typedef struct _IMAGE_OPTIONAL_HEADER { /* Standard fields */ - unsigned short Magic; /* 0x10b or 0x107 */ /* 0x00 */ - unsigned char MajorLinkerVersion; - unsigned char MinorLinkerVersion; - unsigned long SizeOfCode; - unsigned long SizeOfInitializedData; - unsigned long SizeOfUninitializedData; - unsigned long AddressOfEntryPoint; /* 0x10 */ - unsigned long BaseOfCode; - unsigned long BaseOfData; + WORD Magic; /* 0x10b or 0x107 */ /* 0x00 */ + BYTE MajorLinkerVersion; + BYTE MinorLinkerVersion; + DWORD SizeOfCode; + DWORD SizeOfInitializedData; + DWORD SizeOfUninitializedData; + DWORD AddressOfEntryPoint; /* 0x10 */ + DWORD BaseOfCode; + DWORD BaseOfData; /* NT additional fields */ - unsigned long ImageBase; - unsigned long SectionAlignment; /* 0x20 */ - unsigned long FileAlignment; - unsigned short MajorOperatingSystemVersion; - unsigned short MinorOperatingSystemVersion; - unsigned short MajorImageVersion; - unsigned short MinorImageVersion; - unsigned short MajorSubsystemVersion; /* 0x30 */ - unsigned short MinorSubsystemVersion; - unsigned long Win32VersionValue; - unsigned long SizeOfImage; - unsigned long SizeOfHeaders; - unsigned long CheckSum; /* 0x40 */ - unsigned short Subsystem; - unsigned short DllCharacteristics; - unsigned long SizeOfStackReserve; - unsigned long SizeOfStackCommit; - unsigned long SizeOfHeapReserve; /* 0x50 */ - unsigned long SizeOfHeapCommit; - unsigned long LoaderFlags; - unsigned long NumberOfRvaAndSizes; + DWORD ImageBase; + DWORD SectionAlignment; /* 0x20 */ + DWORD FileAlignment; + WORD MajorOperatingSystemVersion; + WORD MinorOperatingSystemVersion; + WORD MajorImageVersion; + WORD MinorImageVersion; + WORD MajorSubsystemVersion; /* 0x30 */ + WORD MinorSubsystemVersion; + DWORD Win32VersionValue; + DWORD SizeOfImage; + DWORD SizeOfHeaders; + DWORD CheckSum; /* 0x40 */ + WORD Subsystem; + WORD DllCharacteristics; + DWORD SizeOfStackReserve; + DWORD SizeOfStackCommit; + DWORD SizeOfHeapReserve; /* 0x50 */ + DWORD SizeOfHeapCommit; + DWORD LoaderFlags; + DWORD NumberOfRvaAndSizes; IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; /* 0x60 */ /* 0xE0 */ -} IMAGE_OPTIONAL_HEADER, *PIMAGE_OPTIONAL_HEADER; +} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32; + +/* Possible Magic values */ +#define IMAGE_NT_OPTIONAL_HDR32_MAGIC 0x10b +#define IMAGE_NT_OPTIONAL_HDR64_MAGIC 0x20b +#define IMAGE_ROM_OPTIONAL_HDR_MAGIC 0x107 + +typedef struct _IMAGE_NT_HEADERS64 { + DWORD Signature; + IMAGE_FILE_HEADER FileHeader; + IMAGE_OPTIONAL_HEADER64 OptionalHeader; +} IMAGE_NT_HEADERS64, *PIMAGE_NT_HEADERS64; typedef struct _IMAGE_NT_HEADERS { - unsigned long Signature; /* "PE"\0\0 */ /* 0x00 */ - IMAGE_FILE_HEADER FileHeader; /* 0x04 */ - IMAGE_OPTIONAL_HEADER OptionalHeader; /* 0x18 */ -} IMAGE_NT_HEADERS, *PIMAGE_NT_HEADERS; + DWORD Signature; /* "PE"\0\0 */ /* 0x00 */ + IMAGE_FILE_HEADER FileHeader; /* 0x04 */ + IMAGE_OPTIONAL_HEADER32 OptionalHeader; /* 0x18 */ +} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32; + +#if (VEX_HOST_WORDSIZE == 8) +typedef IMAGE_NT_HEADERS64 IMAGE_NT_HEADERS; +typedef PIMAGE_NT_HEADERS64 PIMAGE_NT_HEADERS; +typedef IMAGE_OPTIONAL_HEADER64 IMAGE_OPTIONAL_HEADER; +typedef PIMAGE_OPTIONAL_HEADER64 PIMAGE_OPTIONAL_HEADER; +#else +typedef IMAGE_NT_HEADERS32 IMAGE_NT_HEADERS; +typedef PIMAGE_NT_HEADERS32 PIMAGE_NT_HEADERS; +typedef IMAGE_OPTIONAL_HEADER32 IMAGE_OPTIONAL_HEADER; +typedef PIMAGE_OPTIONAL_HEADER32 PIMAGE_OPTIONAL_HEADER; +#endif #define IMAGE_SIZEOF_SHORT_NAME 8 typedef struct _IMAGE_SECTION_HEADER { - unsigned char Name[IMAGE_SIZEOF_SHORT_NAME]; + BYTE Name[IMAGE_SIZEOF_SHORT_NAME]; union { - unsigned long PhysicalAddress; - unsigned long VirtualSize; + DWORD PhysicalAddress; + DWORD VirtualSize; } Misc; - unsigned long VirtualAddress; - unsigned long SizeOfRawData; - unsigned long PointerToRawData; - unsigned long PointerToRelocations; - unsigned long PointerToLinenumbers; - unsigned short NumberOfRelocations; - unsigned short NumberOfLinenumbers; - unsigned long Characteristics; + DWORD VirtualAddress; + DWORD SizeOfRawData; + DWORD PointerToRawData; + DWORD PointerToRelocations; + DWORD PointerToLinenumbers; + WORD NumberOfRelocations; + WORD NumberOfLinenumbers; + DWORD Characteristics; } IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER; #define IMAGE_SIZEOF_SECTION_HEADER 40 #define IMAGE_FIRST_SECTION(ntheader) \ - ((PIMAGE_SECTION_HEADER)((LPunsigned char)&((PIMAGE_NT_HEADERS)(ntheader))->OptionalHeader + \ + ((PIMAGE_SECTION_HEADER)((BYTE *)&((PIMAGE_NT_HEADERS)(ntheader))->OptionalHeader + \ ((PIMAGE_NT_HEADERS)(ntheader))->FileHeader.SizeOfOptionalHeader)) /* These defines are for the Characteristics bitfield. */ @@ -242,7 +406,7 @@ typedef struct _IMAGE_SECTION_HEADER { /* #define IMAGE_SCN_TYPE_NO_PAD 0x00000008 - Reserved */ /* #define IMAGE_SCN_TYPE_COPY 0x00000010 - Reserved */ -#define IMAGE_SCN_CNT_CODE 0x00000020 +#define IMAGE_SCN_CNT_CODE 0x00000020 #define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040 #define IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080 @@ -254,13 +418,13 @@ typedef struct _IMAGE_SECTION_HEADER { /* 0x00002000 - Reserved */ /* #define IMAGE_SCN_MEM_PROTECTED 0x00004000 - Obsolete */ -#define IMAGE_SCN_MEM_FARDATA 0x00008000 +#define IMAGE_SCN_MEM_FARDATA 0x00008000 /* #define IMAGE_SCN_MEM_SYSHEAP 0x00010000 - Obsolete */ #define IMAGE_SCN_MEM_PURGEABLE 0x00020000 -#define IMAGE_SCN_MEM_16BIT 0x00020000 -#define IMAGE_SCN_MEM_LOCKED 0x00040000 -#define IMAGE_SCN_MEM_PRELOAD 0x00080000 +#define IMAGE_SCN_MEM_16BIT 0x00020000 +#define IMAGE_SCN_MEM_LOCKED 0x00040000 +#define IMAGE_SCN_MEM_PRELOAD 0x00080000 #define IMAGE_SCN_ALIGN_1BYTES 0x00100000 #define IMAGE_SCN_ALIGN_2BYTES 0x00200000 @@ -273,23 +437,36 @@ typedef struct _IMAGE_SECTION_HEADER { #define IMAGE_SCN_LNK_NRELOC_OVFL 0x01000000 - #define IMAGE_SCN_MEM_DISCARDABLE 0x02000000 #define IMAGE_SCN_MEM_NOT_CACHED 0x04000000 #define IMAGE_SCN_MEM_NOT_PAGED 0x08000000 -#define IMAGE_SCN_MEM_SHARED 0x10000000 -#define IMAGE_SCN_MEM_EXECUTE 0x20000000 -#define IMAGE_SCN_MEM_READ 0x40000000 -#define IMAGE_SCN_MEM_WRITE 0x80000000 +#define IMAGE_SCN_MEM_SHARED 0x10000000 +#define IMAGE_SCN_MEM_EXECUTE 0x20000000 +#define IMAGE_SCN_MEM_READ 0x40000000 +#define IMAGE_SCN_MEM_WRITE 0x80000000 #pragma pack() +typedef struct _IMAGE_EXPORT_DIRECTORY { + DWORD Characteristics; + DWORD TimeDateStamp; + WORD MajorVersion; + WORD MinorVersion; + DWORD Name; + DWORD Base; + DWORD NumberOfFunctions; + DWORD NumberOfNames; + DWORD AddressOfFunctions; + DWORD AddressOfNames; + DWORD AddressOfNameOrdinals; +} IMAGE_EXPORT_DIRECTORY,*PIMAGE_EXPORT_DIRECTORY; + typedef struct _GUID /* 16 bytes */ { - unsigned int Data1; - unsigned short Data2; - unsigned short Data3; - unsigned char Data4[ 8 ]; + DWORD Data1; + WORD Data2; + WORD Data3; + BYTE Data4[ 8 ]; } GUID; /*======================================================================== @@ -299,8 +476,8 @@ typedef struct _GUID /* 16 bytes */ #pragma pack(1) typedef struct _PDB_FILE { - unsigned long size; - unsigned long unknown; + DWORD size; + DWORD unknown; } PDB_FILE, *PPDB_FILE; @@ -311,190 +488,190 @@ typedef struct _PDB_FILE struct PDB_JG_HEADER { //char ident[40]; // "Microsoft C/C++ program database 2.00\r\n\032" - //unsigned long signature; // "JG\0\0" - unsigned int blocksize; // 0x400 typical; also 0x800, 0x1000 - unsigned short freelist; - unsigned short total_alloc; + //DWORD signature; // "JG\0\0" + DWORD blocksize; // 0x400 typical; also 0x800, 0x1000 + WORD freelist; + WORD total_alloc; PDB_FILE toc; - unsigned short toc_block[ 1 ]; + WORD toc_block[ 1 ]; }; struct PDB_DS_HEADER { //char signature[32]; // "Microsoft C/C++ MSF 7.00\r\n\032DS\0\0" - unsigned int block_size; - unsigned int unknown1; - unsigned int num_pages; - unsigned int toc_size; - unsigned int unknown2; - unsigned int toc_page; + DWORD block_size; + DWORD unknown1; + DWORD num_pages; + DWORD toc_size; + DWORD unknown2; + DWORD toc_page; }; struct PDB_JG_TOC { - unsigned int nFiles; + DWORD nFiles; PDB_FILE file[ 1 ]; }; struct PDB_DS_TOC { - unsigned int num_files; - unsigned int file_size[1]; + DWORD num_files; + DWORD file_size[1]; }; struct PDB_JG_ROOT { - unsigned int version; - unsigned int TimeDateStamp; - unsigned int age; - unsigned int cbNames; - char names[ 1 ]; + DWORD version; + DWORD TimeDateStamp; + DWORD age; + DWORD cbNames; + char names[ 1 ]; }; struct PDB_DS_ROOT { - unsigned int version; - unsigned int TimeDateStamp; - unsigned int age; - GUID guid; - unsigned int cbNames; - char names[1]; + DWORD version; + DWORD TimeDateStamp; + DWORD age; + GUID guid; + DWORD cbNames; + char names[1]; }; typedef struct _PDB_TYPES_OLD { - unsigned long version; - unsigned short first_index; - unsigned short last_index; - unsigned long type_size; - unsigned short file; - unsigned short pad; + DWORD version; + WORD first_index; + WORD last_index; + DWORD type_size; + WORD file; + WORD pad; } PDB_TYPES_OLD, *PPDB_TYPES_OLD; typedef struct _PDB_TYPES { - unsigned long version; - unsigned long type_offset; - unsigned long first_index; - unsigned long last_index; - unsigned long type_size; - unsigned short file; - unsigned short pad; - unsigned long hash_size; - unsigned long hash_base; - unsigned long hash_offset; - unsigned long hash_len; - unsigned long search_offset; - unsigned long search_len; - unsigned long unknown_offset; - unsigned long unknown_len; + DWORD version; + DWORD type_offset; + DWORD first_index; + DWORD last_index; + DWORD type_size; + WORD file; + WORD pad; + DWORD hash_size; + DWORD hash_base; + DWORD hash_offset; + DWORD hash_len; + DWORD search_offset; + DWORD search_len; + DWORD unknown_offset; + DWORD unknown_len; } PDB_TYPES, *PPDB_TYPES; typedef struct _PDB_SYMBOL_RANGE { - unsigned short segment; - unsigned short pad1; - unsigned long offset; - unsigned long size; - unsigned long characteristics; - unsigned short index; - unsigned short pad2; + WORD segment; + WORD pad1; + DWORD offset; + DWORD size; + DWORD characteristics; + WORD index; + WORD pad2; } PDB_SYMBOL_RANGE, *PPDB_SYMBOL_RANGE; typedef struct _PDB_SYMBOL_RANGE_EX { - unsigned short segment; - unsigned short pad1; - unsigned long offset; - unsigned long size; - unsigned long characteristics; - unsigned short index; - unsigned short pad2; - unsigned long timestamp; - unsigned long unknown; + WORD segment; + WORD pad1; + DWORD offset; + DWORD size; + DWORD characteristics; + WORD index; + WORD pad2; + DWORD timestamp; + DWORD unknown; } PDB_SYMBOL_RANGE_EX, *PPDB_SYMBOL_RANGE_EX; typedef struct _PDB_SYMBOL_FILE { - unsigned long unknown1; + DWORD unknown1; PDB_SYMBOL_RANGE range; - unsigned short flag; - unsigned short file; - unsigned long symbol_size; - unsigned long lineno_size; - unsigned long unknown2; - unsigned long nSrcFiles; - unsigned long attribute; + WORD flag; + WORD file; + DWORD symbol_size; + DWORD lineno_size; + DWORD unknown2; + DWORD nSrcFiles; + DWORD attribute; char filename[ 1 ]; } PDB_SYMBOL_FILE, *PPDB_SYMBOL_FILE; typedef struct _PDB_SYMBOL_FILE_EX { - unsigned long unknown1; + DWORD unknown1; PDB_SYMBOL_RANGE_EX range; - unsigned short flag; - unsigned short file; - unsigned long symbol_size; - unsigned long lineno_size; - unsigned long unknown2; - unsigned long nSrcFiles; - unsigned long attribute; - unsigned long reserved[ 2 ]; + WORD flag; + WORD file; + DWORD symbol_size; + DWORD lineno_size; + DWORD unknown2; + DWORD nSrcFiles; + DWORD attribute; + DWORD reserved[ 2 ]; char filename[ 1 ]; } PDB_SYMBOL_FILE_EX, *PPDB_SYMBOL_FILE_EX; typedef struct _PDB_SYMBOL_SOURCE { - unsigned short nModules; - unsigned short nSrcFiles; - unsigned short table[ 1 ]; + WORD nModules; + WORD nSrcFiles; + WORD table[ 1 ]; } PDB_SYMBOL_SOURCE, *PPDB_SYMBOL_SOURCE; typedef struct _PDB_SYMBOL_IMPORT { - unsigned long unknown1; - unsigned long unknown2; - unsigned long TimeDateStamp; - unsigned long nRequests; + DWORD unknown1; + DWORD unknown2; + DWORD TimeDateStamp; + DWORD nRequests; char filename[ 1 ]; } PDB_SYMBOL_IMPORT, *PPDB_SYMBOL_IMPORT; typedef struct _PDB_SYMBOLS_OLD { - unsigned short hash1_file; - unsigned short hash2_file; - unsigned short gsym_file; - unsigned short pad; - unsigned long module_size; - unsigned long offset_size; - unsigned long hash_size; - unsigned long srcmodule_size; + WORD hash1_file; + WORD hash2_file; + WORD gsym_file; + WORD pad; + DWORD module_size; + DWORD offset_size; + DWORD hash_size; + DWORD srcmodule_size; } PDB_SYMBOLS_OLD, *PPDB_SYMBOLS_OLD; typedef struct _PDB_SYMBOLS { - unsigned long signature; - unsigned long version; - unsigned long unknown; - unsigned long hash1_file; - unsigned long hash2_file; - unsigned long gsym_file; - unsigned long module_size; - unsigned long offset_size; - unsigned long hash_size; - unsigned long srcmodule_size; - unsigned long pdbimport_size; - unsigned long resvd[ 5 ]; + DWORD signature; + DWORD version; + DWORD unknown; + DWORD hash1_file; + DWORD hash2_file; + DWORD gsym_file; + DWORD module_size; + DWORD offset_size; + DWORD hash_size; + DWORD srcmodule_size; + DWORD pdbimport_size; + DWORD resvd[ 5 ]; } PDB_SYMBOLS, *PPDB_SYMBOLS; #pragma pack() @@ -507,8 +684,8 @@ typedef struct _PDB_SYMBOLS struct p_string /* "Pascal string": prefixed by byte containing length */ { - unsigned char namelen; - char name[1]; + BYTE namelen; + char name[1]; }; /* The other kind of "char name[1]" is a "C++ string" terminated by '\0'. * "Name mangling" to encode type information often exceeds 255 bytes. @@ -1156,7 +1333,7 @@ static void pdb_convert_types_header( PDB_TYPES *types, char* image ) VG_(memset)( types, 0, sizeof(PDB_TYPES) ); if ( !image ) return; - if ( *(unsigned long *)image < 19960000 ) { /* FIXME: correct version? */ + if ( *(DWORD *)image < 19960000 ) { /* FIXME: correct version? */ /* Old version of the types record header */ PDB_TYPES_OLD *old = (PDB_TYPES_OLD *)image; types->version = old->version; @@ -1178,7 +1355,7 @@ static void pdb_convert_symbols_header( PDB_SYMBOLS *symbols, VG_(memset)( symbols, 0, sizeof(PDB_SYMBOLS) ); if ( !image ) return; - if ( *(unsigned long *)image != 0xffffffff ) { + if ( *(DWORD *)image != 0xffffffff ) { /* Old version of the symbols record header */ PDB_SYMBOLS_OLD *old = (PDB_SYMBOLS_OLD *)image; symbols->version = 0; @@ -2110,7 +2287,7 @@ static void pdb_dump( const struct pdb_reader* pdb, default: if (VG_(clo_verbosity) > 1) VG_(umsg)("LOAD_PDB_DEBUGINFO: " - "Unknown .pdb type info version %lu\n", types.version ); + "Unknown .pdb type info version %u\n", types.version ); } header_size = 0; @@ -2124,7 +2301,7 @@ static void pdb_dump( const struct pdb_reader* pdb, default: if (VG_(clo_verbosity) > 1) VG_(umsg)("LOAD_PDB_DEBUGINFO: " - "Unknown .pdb symbol info version %lu\n", + "Unknown .pdb symbol info version %u\n", symbols.version ); } @@ -2181,7 +2358,7 @@ static void pdb_dump( const struct pdb_reader* pdb, file_name ); n_syms_read += DEBUG_SnarfCodeView( di, pe_avma, sectp_avma, modimage, - sizeof(unsigned long), + sizeof(DWORD), symbol_size ); } @@ -2319,7 +2496,7 @@ Bool ML_(read_pdb_debug_info)( VG_(memcpy)(name, pe_sechdr_avma->Name, 8); name[8] = '\0'; VG_(umsg)("LOAD_PDB_DEBUGINFO:" - " Scanning PE section %ps at avma %#lx svma %#lx\n", + " Scanning PE section %ps at avma %#lx svma %#x\n", name, obj_avma + pe_sechdr_avma->VirtualAddress, pe_sechdr_avma->VirtualAddress); } -- 2.29.2 |
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 |
From: Rémi B. <rb...@co...> - 2021-03-05 09:18:29
|
On 11/30/20 10:00 AM, Rémi Bernon wrote: > Hi! > > I've been trying to fix Valgrind support for Wine that got pretty broken > lately, as the recent refactoring there makes most code now be compiled > as PE .dll files. > > There's already some support in Valgrind to notify it and load debug > information from PDB files, but in general when compiling Wine using GCC > the debug information is instead generated as DWARF info, so that > doesn't work. > > I figured that it was just a matter of adding support for parsing PE > files in Valgrind, and here it is. I've hooked that to the existing PDB > notification, in the case no PDB file could be found, and it now works > pretty nicely for all Wine code, whether it's within ELF .so files, or > PE .dll, including backtraces with a hybrid mix of both. > > I'm not sure how contributions to Valgrind are supposed to go, so I'm > sending these as patches here, but feel free to redirect me. > > Cheers, > > Rémi Bernon (3): > Update Windows PE / PDB struct definitions using fixed-size types. > Increase the number of supported CFI registers. > Implement DWARF in PE parsing support, as PDB fallback. > > coregrind/m_debuginfo/debuginfo.c | 63 +- > coregrind/m_debuginfo/priv_readelf.h | 23 + > coregrind/m_debuginfo/priv_readpdb.h | 8 + > coregrind/m_debuginfo/readdwarf.c | 2 +- > coregrind/m_debuginfo/readelf.c | 42 +- > coregrind/m_debuginfo/readpdb.c | 1598 ++++++++++++++++++++++---- > 6 files changed, 1506 insertions(+), 230 deletions(-) > Hello! I sent these a while ago, but I didn't really get any feedback about it. There's a related bug entry, on which there's been a bit of discussion too, but I was wondering if that what the best way to contribute some code to Valgrind? Right now, because of changes in how Wine builds its modules, the code that is supposed to support this use-case in Valgrind is broken, and pretty much useless, I'd love to help making it work again. Cheers, -- Rémi Bernon <rb...@co...> |