From 7014d4546d7113aa21ec21b1a19293cacebc948a Mon Sep 17 00:00:00 2001 From: Rainer Schuetze Date: Fri, 8 May 2015 23:00:52 +0200 Subject: - new tool dumplines to display the debug line number info --- CHANGES | 4 + VERSION | 2 +- src/PEImage.cpp | 359 ++++++++++++++++++++++++++++++++++++++++++--- src/PEImage.h | 23 ++- src/cv2pdb.h | 2 - src/cv2pdb.vcxproj | 1 + src/cv2pdb.vcxproj.filters | 3 + src/cv2pdb_vs12.sln | 14 ++ src/dumplines.cpp | 139 ++++++++++++++++++ src/dumplines.vcxproj | 115 +++++++++++++++ src/dumplines.vcxproj.user | 8 + src/dwarf2pdb.cpp | 311 +-------------------------------------- src/dwarflines.cpp | 316 +++++++++++++++++++++++++++++++++++++++ src/main.cpp | 6 +- src/readDwarf.h | 8 +- 15 files changed, 975 insertions(+), 336 deletions(-) create mode 100644 src/dumplines.cpp create mode 100644 src/dumplines.vcxproj create mode 100644 src/dumplines.vcxproj.user create mode 100644 src/dwarflines.cpp diff --git a/CHANGES b/CHANGES index 03bd8bc..4bf87b4 100644 --- a/CHANGES +++ b/CHANGES @@ -216,3 +216,7 @@ unreleased Version 0.22 * DWARF: translate __int128 to CV code 0x14, just a wild guesss * DWARF: add support for DW_ATE_UTF, remove bad assert + +2015-05-08 Version 0.35 + + * new tool dumplines to display the debug line number info diff --git a/VERSION b/VERSION index 41cf16f..ec5227f 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -VERSION = 0.34 +VERSION = 0.35 diff --git a/src/PEImage.cpp b/src/PEImage.cpp index 0f7608c..ad8b288 100644 --- a/src/PEImage.cpp +++ b/src/PEImage.cpp @@ -17,6 +17,7 @@ extern "C" { #include #include #include +#include #ifdef UNICODE #define T_sopen _wsopen @@ -45,11 +46,17 @@ PEImage::PEImage(const TCHAR* iname) , debug_loc(0) , debug_ranges(0) , codeSegment(0) +, linesSegment(-1) , reloc(0) , reloc_length(0) +, nsec(0) +, nsym(0) +, symtable(0) +, strtable(0) +, bigobj(false) { if(iname) - load(iname); + loadExe(iname); } PEImage::~PEImage() @@ -61,7 +68,7 @@ PEImage::~PEImage() } /////////////////////////////////////////////////////////////////////// -bool PEImage::load(const TCHAR* iname) +bool PEImage::readAll(const TCHAR* iname) { if (fd != -1) return setError("file already open"); @@ -81,10 +88,27 @@ bool PEImage::load(const TCHAR* iname) if (read(fd, dump_base, dump_total_len) != dump_total_len) return setError("Cannot read file"); - close(fd); fd = -1; - return initCVPtr(true) || initDWARFPtr(true); + return true; +} + +/////////////////////////////////////////////////////////////////////// +bool PEImage::loadExe(const TCHAR* iname) +{ + if (!readAll(iname)) + return false; + + return initCVPtr(true) || initDWARFPtr(true); +} + +/////////////////////////////////////////////////////////////////////// +bool PEImage::loadObj(const TCHAR* iname) +{ + if (!readAll(iname)) + return false; + + return initDWARFObject(); } /////////////////////////////////////////////////////////////////////// @@ -230,6 +254,11 @@ bool PEImage::initCVPtr(bool initDbgDir) return setError("optional header too small"); sec = hdr32 ? IMAGE_FIRST_SECTION(hdr32) : IMAGE_FIRST_SECTION(hdr64); + nsec = IMGHDR(FileHeader.NumberOfSections); + + symtable = DPV(IMGHDR(FileHeader.PointerToSymbolTable)); + nsym = IMGHDR(FileHeader.NumberOfSymbols); + strtable = symtable + nsym * IMAGE_SIZEOF_SYMBOL; if(IMGHDR(OptionalHeader.NumberOfRvaAndSizes) <= IMAGE_DIRECTORY_ENTRY_DEBUG) return setError("too few entries in data directory"); @@ -293,8 +322,57 @@ bool PEImage::initDWARFPtr(bool initDbgDir) dbgDir = 0; sec = hdr32 ? IMAGE_FIRST_SECTION(hdr32) : IMAGE_FIRST_SECTION(hdr64); - int nsec = IMGHDR(FileHeader.NumberOfSections); - const char* strtable = DPV(IMGHDR(FileHeader.PointerToSymbolTable) + IMGHDR(FileHeader.NumberOfSymbols) * IMAGE_SIZEOF_SYMBOL); + symtable = DPV(IMGHDR(FileHeader.PointerToSymbolTable)); + nsym = IMGHDR(FileHeader.NumberOfSymbols); + strtable = symtable + nsym * IMAGE_SIZEOF_SYMBOL; + initDWARFSegments(); + + setError(0); + return true; +} + +bool PEImage::initDWARFObject() +{ + IMAGE_FILE_HEADER* hdr = DPV (0); + if(!dos) + return setError("file too small for COFF header"); + + if (hdr->Machine == IMAGE_FILE_MACHINE_UNKNOWN && hdr->NumberOfSections == 0xFFFF) + { + static CLSID bigObjClSID = { 0xD1BAA1C7, 0xBAEE, 0x4ba9, { 0xAF, 0x20, 0xFA, 0xF6, 0x6A, 0xA4, 0xDC, 0xB8 } }; + ANON_OBJECT_HEADER_BIGOBJ* bighdr = DPV (0); + if (!bighdr || bighdr->Version < 2 || bighdr->ClassID != bigObjClSID) + return setError("invalid big object file COFF header"); + sec = (IMAGE_SECTION_HEADER*)((char*)(bighdr + 1) + bighdr->SizeOfData); + nsec = bighdr->NumberOfSections; + bigobj = true; + symtable = DPV(bighdr->PointerToSymbolTable); + nsym = bighdr->NumberOfSymbols; + strtable = symtable + nsym * sizeof(IMAGE_SYMBOL_EX); + } + else if (hdr->Machine != IMAGE_FILE_MACHINE_UNKNOWN) + { + sec = (IMAGE_SECTION_HEADER*)(hdr + 1); + nsec = hdr->NumberOfSections; + bigobj = false; + hdr32 = (IMAGE_NT_HEADERS32*)((char*)hdr - 4); // skip back over signature + symtable = DPV(IMGHDR(FileHeader.PointerToSymbolTable)); + nsym = IMGHDR(FileHeader.NumberOfSymbols); + strtable = symtable + nsym * IMAGE_SIZEOF_SYMBOL; + } + else + return setError("Unknown object file format"); + + if (!symtable || !strtable) + return setError("Unknown object file format"); + + initDWARFSegments(); + setError(0); + return true; +} + +void PEImage::initDWARFSegments() +{ for(int s = 0; s < nsec; s++) { const char* name = (const char*) sec[s].Name; @@ -310,11 +388,11 @@ bool PEImage::initDWARFPtr(bool initDbgDir) if(strcmp(name, ".debug_pubtypes") == 0) debug_pubtypes = DPV(sec[s].PointerToRawData, sec[s].SizeOfRawData); if(strcmp(name, ".debug_info") == 0) - debug_info = DPV(sec[s].PointerToRawData, debug_info_length = sec[s].Misc.VirtualSize); + debug_info = DPV(sec[s].PointerToRawData, debug_info_length = sec[s].SizeOfRawData); if(strcmp(name, ".debug_abbrev") == 0) - debug_abbrev = DPV(sec[s].PointerToRawData, debug_abbrev_length = sec[s].Misc.VirtualSize); + debug_abbrev = DPV(sec[s].PointerToRawData, debug_abbrev_length = sec[s].SizeOfRawData); if(strcmp(name, ".debug_line") == 0) - debug_line = DPV(sec[s].PointerToRawData, debug_line_length = sec[s].Misc.VirtualSize); + debug_line = DPV(sec[linesSegment = s].PointerToRawData, debug_line_length = sec[s].SizeOfRawData); if(strcmp(name, ".debug_frame") == 0) debug_frame = DPV(sec[s].PointerToRawData, sec[s].SizeOfRawData); if(strcmp(name, ".debug_str") == 0) @@ -322,41 +400,284 @@ bool PEImage::initDWARFPtr(bool initDbgDir) if(strcmp(name, ".debug_loc") == 0) debug_loc = DPV(sec[s].PointerToRawData, sec[s].SizeOfRawData); if(strcmp(name, ".debug_ranges") == 0) - debug_ranges = DPV(sec[s].PointerToRawData, debug_ranges_length = sec[s].Misc.VirtualSize); + debug_ranges = DPV(sec[s].PointerToRawData, debug_ranges_length = sec[s].SizeOfRawData); if(strcmp(name, ".reloc") == 0) - reloc = DPV(sec[s].PointerToRawData, reloc_length = sec[s].Misc.VirtualSize); + reloc = DPV(sec[s].PointerToRawData, reloc_length = sec[s].SizeOfRawData); if(strcmp(name, ".text") == 0) codeSegment = s; } +} - setError(0); +bool PEImage::relocateDebugLineInfo(unsigned int img_base) +{ + if(!reloc || !reloc_length) + return true; + + char* relocbase = reloc; + char* relocend = reloc + reloc_length; + while(relocbase < relocend) + { + unsigned int virtadr = *(unsigned int *) relocbase; + unsigned int chksize = *(unsigned int *) (relocbase + 4); + char* p = RVA (virtadr, 1); + if(p >= debug_line && p < debug_line + debug_line_length) + { + for (unsigned int w = 8; w < chksize; w += 2) + { + unsigned short entry = *(unsigned short*)(relocbase + w); + unsigned short type = (entry >> 12) & 0xf; + unsigned short off = entry & 0xfff; + + if(type == 3) // HIGHLOW + { + *(long*) (p + off) += img_base; + } + } + } + if(chksize == 0 || chksize >= reloc_length) + break; + relocbase += chksize; + } return true; } +int PEImage::getRelocationInLineSegment(unsigned int offset) const +{ + return getRelocationInSegment(linesSegment, offset); +} + +int PEImage::getRelocationInSegment(int segment, unsigned int offset) const +{ + if (segment < 0) + return -1; + + int cnt = sec[segment].NumberOfRelocations; + IMAGE_RELOCATION* rel = DPV(sec[segment].PointerToRelocations, cnt * sizeof(IMAGE_RELOCATION)); + if (!rel) + return -1; + + for (int i = 0; i < cnt; i++) + if (rel[i].VirtualAddress == offset) + { + if (bigobj) + { + IMAGE_SYMBOL_EX* sym = (IMAGE_SYMBOL_EX*)(symtable + rel[i].SymbolTableIndex * sizeof(IMAGE_SYMBOL_EX)); + if (!sym) + return -1; + return sym->SectionNumber; + } + else + { + IMAGE_SYMBOL* sym = (IMAGE_SYMBOL*)(symtable + rel[i].SymbolTableIndex * IMAGE_SIZEOF_SYMBOL); + if (!sym) + return -1; + return sym->SectionNumber; + } + } + + return -1; +} + +/////////////////////////////////////////////////////////////////////// +struct LineInfoData +{ + int funcoff; + int funcidx; + int funcsiz; + int srcfileoff; + int npairs; + int size; +}; + +struct LineInfoPair +{ + int offset; + int line; +}; + +int PEImage::dumpDebugLineInfoCOFF() +{ + char* f3section = 0; + char* f4section = 0; + for(int s = 0; s < nsec; s++) + { + if (strncmp((char*)sec[s].Name, ".debug$S", 8) == 0) + { + DWORD* base = DPV(sec[s].PointerToRawData, sec[s].SizeOfRawData); + if (!base || *base != 4) + continue; + DWORD* end = base + sec[s].SizeOfRawData / 4; + for (DWORD* p = base + 1; p < end; p += (p[1] + 3) / 4 + 2) + { + if (!f4section && p[0] == 0xf4) + f4section = (char*)p + 8; + if (!f3section && p[0] == 0xf3) + f3section = (char*)p + 8; + if (p[0] != 0xf2) + continue; + + LineInfoData* info = (LineInfoData*) (p + 2); + if (p[1] != info->size + 12) + continue; + + int* f3off = f4section ? (int*)(f4section + info->srcfileoff) : 0; + const char* fname = f3off ? f3section + *f3off : "unknown"; + int section = getRelocationInSegment(s, (char*)info - (char*)base); + const char* secname = findSectionSymbolName(section); + printf("Sym: %s\n", secname ? secname : ""); + printf("File: %s\n", fname); + LineInfoPair* pairs = (LineInfoPair*)(info + 1); + for (int i = 0; i < info->npairs; i++) + printf("\tOff 0x%x: Line %d\n", pairs[i].offset, pairs[i].line & 0x7fffffff); + } + } + } + return 0; +} + +int _pstrlen(const BYTE* &p) +{ + int len = *p++; + if(len == 0xff && *p == 0) + { + len = p[1] | (p[2] << 8); + p += 3; + } + return len; +} + +unsigned _getIndex(const BYTE* &p) +{ + if (*p & 0x80) + { + p += 2; + return *(unsigned short*)(p - 2) & 0x7fff; + } + return *p++; +} + +int PEImage::dumpDebugLineInfoOMF() +{ + std::vector lnames; + std::vector llnames; + const unsigned char* fname = 0; + unsigned char* base = (unsigned char*) dump_base; + if (*base != 0x80) // assume THEADR record + return -1; + unsigned char* end = base + dump_total_len; + for(unsigned char* p = base; p < end; p += *(unsigned short*)(p + 1) + 3) + { + switch(*p) + { + case 0x80: // THEADR + fname = p + 3; // pascal string + break; + case 0x96: // LNAMES + { + int len = *(unsigned short*)(p + 1); + for(const unsigned char* q = p + 3; q < p + len + 2; q += _pstrlen (q)) // defined behaviour? + lnames.push_back(q); + break; + } + case 0xCA: // LLNAMES + { + int len = *(unsigned short*)(p + 1); + for(const unsigned char* q = p + 3; q < p + len + 2; q += _pstrlen (q)) // defined behaviour? + llnames.push_back(q); + break; + } + case 0x95: // LINNUM + { + const unsigned char* q = p + 3; + int basegrp = _getIndex(q); + int baseseg = _getIndex(q); + unsigned num = (p + *(unsigned short*)(p + 1) + 2 - q) / 6; + const unsigned char* fn = fname; + int flen = fn ? _pstrlen(fn) : 0; + printf("File: %.*s, BaseSegment %d\n", flen, fn, baseseg); + for (int i = 0; i < num; i++) + printf("\tOff 0x%x: Line %d\n", *(int*)(q + 2 + 6 * i), *(unsigned short*)(p + 6 * i)); + break; + } + case 0xc5: // LINSYM + { + const unsigned char* q = p + 3; + unsigned flags = *q++; + unsigned pubname = _getIndex(q); + unsigned num = (p + *(unsigned short*)(p + 1) + 2 - q) / 6; + if (num == 0) + break; + const unsigned char* fn = fname; + int flen = fn ? _pstrlen(fn) : 0; + const unsigned char* sn = (pubname == 0 || pubname > lnames.size() ? 0 : lnames[pubname-1]); + int slen = sn ? _pstrlen(sn) : 0; + printf("Sym: %.*s\n", slen, sn); + printf("File: %.*s\n", flen, fn); + for (unsigned i = 0; i < num; i++) + printf("\tOff 0x%x: Line %d\n", *(int*)(q + 2 + 6 * i), *(unsigned short*)(q + 6 * i)); + break; + } + default: + break; + } + } + return 0; +} + +/////////////////////////////////////////////////////////////////////// int PEImage::findSection(unsigned int off) const { off -= IMGHDR(OptionalHeader.ImageBase); - int nsec = IMGHDR(FileHeader.NumberOfSections); for(int s = 0; s < nsec; s++) if(sec[s].VirtualAddress <= off && off < sec[s].VirtualAddress + sec[s].Misc.VirtualSize) return s; return -1; } +template +const char* PEImage::t_findSectionSymbolName(int s) const +{ + SYM* sym = 0; + for(int i = 0; i < nsym; i += 1 + sym->NumberOfAuxSymbols) + { + sym = (SYM*) symtable + i; + if (sym->SectionNumber == s && sym->StorageClass == IMAGE_SYM_CLASS_EXTERNAL) + { + static char sname[10] = { 0 }; + + if (sym->N.Name.Short == 0) + return strtable + sym->N.Name.Long; + return strncpy (sname, (char*)sym->N.ShortName, 8); + } + } + return 0; +} + +const char* PEImage::findSectionSymbolName(int s) const +{ + if (s < 0 || s >= nsec) + return 0; + if (!(sec[s].Characteristics & IMAGE_SCN_LNK_COMDAT)) + return 0; + + if (bigobj) + return t_findSectionSymbolName (s); + else + return t_findSectionSymbolName (s); +} + int PEImage::findSymbol(const char* name, unsigned long& off) const { - IMAGE_SYMBOL* symtable = DPV(IMGHDR(FileHeader.PointerToSymbolTable)); - int syms = IMGHDR(FileHeader.NumberOfSymbols); - const char* strtable = (const char*) (symtable + syms); - for(int i = 0; i < syms; i++) + int sizeof_sym = bigobj ? sizeof(IMAGE_SYMBOL_EX) : IMAGE_SIZEOF_SYMBOL; + for(int i = 0; i < nsym; i++) { - IMAGE_SYMBOL* sym = symtable + i; + IMAGE_SYMBOL* sym = (IMAGE_SYMBOL*) (symtable + i * sizeof_sym); const char* symname = sym->N.Name.Short == 0 ? strtable + sym->N.Name.Long : (char*)sym->N.ShortName; if(strcmp(symname, name) == 0 || (symname[0] == '_' && strcmp(symname + 1, name) == 0)) { off = sym->Value; - return sym->SectionNumber; + return bigobj ? ((IMAGE_SYMBOL_EX*)sym)->SectionNumber : sym->SectionNumber; } } return -1; diff --git a/src/PEImage.h b/src/PEImage.h index 45bc76b..350d59c 100644 --- a/src/PEImage.h +++ b/src/PEImage.h @@ -56,12 +56,17 @@ public: return 0; } - bool load(const TCHAR* iname); + bool readAll(const TCHAR* iname); + bool loadExe(const TCHAR* iname); + bool loadObj(const TCHAR* iname); bool save(const TCHAR* oname); bool replaceDebugSection (const void* data, int datalen, bool initCV); bool initCVPtr(bool initDbgDir); bool initDWARFPtr(bool initDbgDir); + bool initDWARFObject(); + void initDWARFSegments(); + bool relocateDebugLineInfo(unsigned int img_base); bool hasDWARF() const { return debug_line != 0; } bool isX64() const { return hdr64 != 0; } @@ -75,13 +80,21 @@ public: static void* alloc_aligned(unsigned int size, unsigned int align, unsigned int alignoff = 0); static void free_aligned(void* p); - int countSections() const { return IMGHDR(FileHeader.NumberOfSections); } + int countSections() const { return nsec; } int findSection(unsigned int off) const; int findSymbol(const char* name, unsigned long& off) const; + const char* findSectionSymbolName(int s) const; const IMAGE_SECTION_HEADER& getSection(int s) const { return sec[s]; } unsigned long long getImageBase() const { return IMGHDR(OptionalHeader.ImageBase); } + int getRelocationInLineSegment(unsigned int offset) const; + int getRelocationInSegment(int segment, unsigned int offset) const; + + int dumpDebugLineInfoCOFF(); + int dumpDebugLineInfoOMF(); private: + template const char* t_findSectionSymbolName(int s) const; + int fd; void* dump_base; int dump_total_len; @@ -94,6 +107,11 @@ private: IMAGE_DEBUG_DIRECTORY* dbgDir; OMFDirHeader* dirHeader; OMFDirEntry* dirEntry; + int nsec; + int nsym; + const char* symtable; + const char* strtable; + bool bigobj; public: //dwarf @@ -109,6 +127,7 @@ public: char* debug_ranges; unsigned long debug_ranges_length; char* reloc; unsigned long reloc_length; + int linesSegment; int codeSegment; int cv_base; }; diff --git a/src/cv2pdb.h b/src/cv2pdb.h index 6f88903..0e9b96e 100644 --- a/src/cv2pdb.h +++ b/src/cv2pdb.h @@ -164,7 +164,6 @@ public: bool addDWARFTypes(); bool addDWARFLines(); bool addDWARFPublics(); - bool relocateDebugLineInfo(); bool writeDWARFImage(const TCHAR* opath); bool addDWARFSectionContrib(mspdb::Mod* mod, unsigned long pclo, unsigned long pchi); @@ -260,5 +259,4 @@ public: std::unordered_map mapOffsetToType; }; - #endif //__CV2PDB_H__ \ No newline at end of file diff --git a/src/cv2pdb.vcxproj b/src/cv2pdb.vcxproj index d54b98b..7f4bf25 100644 --- a/src/cv2pdb.vcxproj +++ b/src/cv2pdb.vcxproj @@ -101,6 +101,7 @@ + diff --git a/src/cv2pdb.vcxproj.filters b/src/cv2pdb.vcxproj.filters index c374026..76247b2 100644 --- a/src/cv2pdb.vcxproj.filters +++ b/src/cv2pdb.vcxproj.filters @@ -34,6 +34,9 @@ Source Files + + Source Files + diff --git a/src/cv2pdb_vs12.sln b/src/cv2pdb_vs12.sln index 240fcee..7cdaa57 100644 --- a/src/cv2pdb_vs12.sln +++ b/src/cv2pdb_vs12.sln @@ -25,6 +25,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cvtest", "..\test\cvtest.vc EndProject Project("{002A2DE9-8BB6-484D-9802-7E4AD4084715}") = "test", "..\test\test.visualdproj", "{370E7494-D0CB-450F-B74A-4CEEDB19FBAE}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "dumplines", "dumplines.vcxproj", "{6434537D-446A-4C99-9829-135F7C000D90}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug GDC|Win32 = Debug GDC|Win32 @@ -89,6 +91,18 @@ Global {370E7494-D0CB-450F-B74A-4CEEDB19FBAE}.Win32 COFF|Win32.Build.0 = Win32 COFF|Win32 {370E7494-D0CB-450F-B74A-4CEEDB19FBAE}.Win32 COFF|x64.ActiveCfg = Win32 COFF|x64 {370E7494-D0CB-450F-B74A-4CEEDB19FBAE}.Win32 COFF|x64.Build.0 = Win32 COFF|x64 + {6434537D-446A-4C99-9829-135F7C000D90}.Debug GDC|Win32.ActiveCfg = Debug|Win32 + {6434537D-446A-4C99-9829-135F7C000D90}.Debug GDC|Win32.Build.0 = Debug|Win32 + {6434537D-446A-4C99-9829-135F7C000D90}.Debug GDC|x64.ActiveCfg = Debug|Win32 + {6434537D-446A-4C99-9829-135F7C000D90}.Debug|Win32.ActiveCfg = Debug|Win32 + {6434537D-446A-4C99-9829-135F7C000D90}.Debug|Win32.Build.0 = Debug|Win32 + {6434537D-446A-4C99-9829-135F7C000D90}.Debug|x64.ActiveCfg = Debug|Win32 + {6434537D-446A-4C99-9829-135F7C000D90}.Release|Win32.ActiveCfg = Release|Win32 + {6434537D-446A-4C99-9829-135F7C000D90}.Release|Win32.Build.0 = Release|Win32 + {6434537D-446A-4C99-9829-135F7C000D90}.Release|x64.ActiveCfg = Release|Win32 + {6434537D-446A-4C99-9829-135F7C000D90}.Win32 COFF|Win32.ActiveCfg = Release|Win32 + {6434537D-446A-4C99-9829-135F7C000D90}.Win32 COFF|Win32.Build.0 = Release|Win32 + {6434537D-446A-4C99-9829-135F7C000D90}.Win32 COFF|x64.ActiveCfg = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/dumplines.cpp b/src/dumplines.cpp new file mode 100644 index 0000000..1a33888 --- /dev/null +++ b/src/dumplines.cpp @@ -0,0 +1,139 @@ +// Convert DMD CodeView debug information to PDB files +// Copyright (c) 2009-2010 by Rainer Schuetze, All Rights Reserved +// +// License for redistribution is given by the Artistic License 2.0 +// see file LICENSE for further details + +#include "PEImage.h" +#include "cv2pdb.h" +#include "symutil.h" + +#include + +double +#include "../VERSION" +; + +#ifdef UNICODE +#define T_toupper towupper +#define T_getdcwd _wgetdcwd +#define T_strlen wcslen +#define T_strcpy wcscpy +#define T_strcat wcscat +#define T_strstr wcsstr +#define T_strtod wcstod +#define T_strrchr wcsrchr +#define T_unlink _wremove +#define T_main wmain +#define SARG "%S" +#else +#define T_toupper toupper +#define T_getdcwd _getdcwd +#define T_strlen strlen +#define T_strcpy strcpy +#define T_strcat strcat +#define T_strstr strstr +#define T_strtod strtod +#define T_strrchr strrchr +#define T_unlink unlink +#define T_main main +#define SARG "%s" +#endif + +void fatal(const char *message, ...) +{ + va_list argptr; + va_start(argptr, message); + vprintf(message, argptr); + va_end(argptr); + printf("\n"); + exit(1); +} + +void makefullpath(TCHAR* pdbname) +{ + TCHAR* pdbstart = pdbname; + TCHAR fullname[260]; + TCHAR* pfullname = fullname; + + int drive = 0; + if (pdbname[0] && pdbname[1] == ':') + { + if (pdbname[2] == '\\' || pdbname[2] == '/') + return; + drive = T_toupper (pdbname[0]); + pdbname += 2; + } + else + { + drive = _getdrive(); + } + + if (*pdbname != '\\' && *pdbname != '/') + { + T_getdcwd(drive, pfullname, sizeof(fullname)/sizeof(fullname[0]) - 2); + pfullname += T_strlen(pfullname); + if (pfullname[-1] != '\\') + *pfullname++ = '\\'; + } + else + { + *pfullname++ = 'a' - 1 + drive; + *pfullname++ = ':'; + } + T_strcpy(pfullname, pdbname); + T_strcpy(pdbstart, fullname); + + for(TCHAR*p = pdbstart; *p; p++) + if (*p == '/') + *p = '\\'; + + // remove relative parts "./" and "../" + while (TCHAR* p = T_strstr (pdbstart, TEXT("\\.\\"))) + T_strcpy(p, p + 2); + + while (TCHAR* p = T_strstr (pdbstart, TEXT("\\..\\"))) + { + for (TCHAR* q = p - 1; q >= pdbstart; q--) + if (*q == '\\') + { + T_strcpy(q, p + 3); + break; + } + } +} + +int dumpObjectFile(TCHAR* fname) +{ + PEImage img; + if (!img.readAll(fname)) + fatal(SARG ": %s", fname, img.getLastError()); + + img.initDWARFObject(); + if(img.debug_line) + { + if (!interpretDWARFLines(img, 0)) + fatal(SARG ": cannot dump line numbers", fname); + } + else if (img.dumpDebugLineInfoOMF() < 0) + img.dumpDebugLineInfoCOFF(); + + return 0; +} + +int T_main(int argc, TCHAR* argv[]) +{ + if (argc < 2) + { + printf("Dump line information for object files in OMF/CV4, COFF/CV8 or COFF/DWARF format, Version %g\n", VERSION); + printf("Copyright (c) 2015 by Rainer Schuetze, All Rights Reserved\n"); + printf("\n"); + printf("License for redistribution is given by the Artistic License 2.0\n"); + printf("see file LICENSE for further details\n"); + printf("\n"); + printf("usage: " SARG " \n", argv[0]); + return -1; + } + + return dumpObjectFile(argv[1]); +} diff --git a/src/dumplines.vcxproj b/src/dumplines.vcxproj new file mode 100644 index 0000000..b5dccdd --- /dev/null +++ b/src/dumplines.vcxproj @@ -0,0 +1,115 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {6434537D-446A-4C99-9829-135F7C000D90} + dumpLines + Win32Proj + + + + Application + v120_xp + Unicode + true + + + Application + v120_xp + Unicode + + + + + + + + + + + + + <_ProjectFileVersion>12.0.21005.1 + + + ..\bin\$(Configuration)\ + ..\bin\$(Configuration)\$(ProjectName)\ + true + + + ..\bin\$(Configuration)\ + ..\bin\$(Configuration)\$(ProjectName)\ + false + + + + /wd4996 %(AdditionalOptions) + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + false + + Level3 + EditAndContinue + + + dbghelp.lib;%(AdditionalDependencies) + $(OutDir)$(ProjectName).exe + true + Console + MachineX86 + 5.1 + + + + + /wd4996 %(AdditionalOptions) + MaxSpeed + true + Speed + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreaded + true + false + + Level3 + ProgramDatabase + + + true + Console + true + true + MachineX86 + true + 5.1 + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/dumplines.vcxproj.user b/src/dumplines.vcxproj.user new file mode 100644 index 0000000..b0ef588 --- /dev/null +++ b/src/dumplines.vcxproj.user @@ -0,0 +1,8 @@ + + + + testgc3.obj + c:\tmp\d\objdump + WindowsLocalDebugger + + \ No newline at end of file diff --git a/src/dwarf2pdb.cpp b/src/dwarf2pdb.cpp index 91a6293..450a533 100644 --- a/src/dwarf2pdb.cpp +++ b/src/dwarf2pdb.cpp @@ -915,320 +915,15 @@ bool CV2PDB::createDWARFModules() return true; } -bool isRelativePath(const std::string& s) -{ - if(s.length() < 1) - return true; - if(s[0] == '/' || s[0] == '\\') - return false; - if(s.length() < 2) - return true; - if(s[1] == ':') - return false; - return true; -} - -static int cmpAdr(const void* s1, const void* s2) -{ - const mspdb::LineInfoEntry* e1 = (const mspdb::LineInfoEntry*) s1; - const mspdb::LineInfoEntry* e2 = (const mspdb::LineInfoEntry*) s2; - return e1->offset - e2->offset; -} - -bool _flushDWARFLines(CV2PDB* cv2pdb, DWARF_LineState& state) -{ - if(state.lineInfo.size() == 0) - return true; - - unsigned int saddr = state.lineInfo[0].offset; - unsigned int eaddr = state.lineInfo.back().offset; - int segIndex = cv2pdb->img.findSection(saddr + state.seg_offset); - if(segIndex < 0) - { - // throw away invalid lines (mostly due to "set address to 0") - state.lineInfo.resize(0); - return true; - //return false; - } - -// if(saddr >= 0x4000) -// return true; - - const DWARF_FileName* dfn; - if(state.file == 0) - dfn = state.file_ptr; - else if(state.file > 0 && state.file <= state.files.size()) - dfn = &state.files[state.file - 1]; - else - return false; - std::string fname = dfn->file_name; - - if(isRelativePath(fname) && - dfn->dir_index > 0 && dfn->dir_index <= state.include_dirs.size()) - { - std::string dir = state.include_dirs[dfn->dir_index - 1]; - if(dir.length() > 0 && dir[dir.length() - 1] != '/' && dir[dir.length() - 1] != '\\') - dir.append("\\"); - fname = dir + fname; - } - for(size_t i = 0; i < fname.length(); i++) - if(fname[i] == '/') - fname[i] = '\\'; - - mspdb::Mod* mod = cv2pdb->globalMod(); -#if 1 - bool dump = false; // (fname == "cvtest.d"); - //qsort(&state.lineInfo[0], state.lineInfo.size(), sizeof(state.lineInfo[0]), cmpAdr); -#if 0 - printf("%s:\n", fname.c_str()); - for(size_t ln = 0; ln < state.lineInfo.size(); ln++) - printf(" %08x: %4d\n", state.lineInfo[ln].offset + 0x401000, state.lineInfo[ln].line); -#endif - - unsigned int firstLine = state.lineInfo[0].line; - unsigned int firstAddr = state.lineInfo[0].offset; - unsigned int firstEntry = 0; - unsigned int entry = 0; - for(size_t ln = firstEntry; ln < state.lineInfo.size(); ln++) - { - if(state.lineInfo[ln].line < firstLine || state.lineInfo[ln].offset < firstAddr) - { - if(ln > firstEntry) - { - unsigned int length = state.lineInfo[entry-1].offset + 1; // firstAddr has been subtracted before - if(dump) - printf("AddLines(%08x+%04x, Line=%4d+%3d, %s)\n", firstAddr, length, firstLine, entry - firstEntry, fname.c_str()); - int rc = mod->AddLines(fname.c_str(), segIndex + 1, firstAddr, length, firstAddr, firstLine, - (unsigned char*) &state.lineInfo[firstEntry], - (ln - firstEntry) * sizeof(state.lineInfo[0])); - firstLine = state.lineInfo[ln].line; - firstAddr = state.lineInfo[ln].offset; - firstEntry = entry; - } - } - else if(ln > firstEntry && state.lineInfo[ln].offset == state.lineInfo[ln-1].offset) - continue; // skip entries without offset change - state.lineInfo[entry].line = state.lineInfo[ln].line - firstLine; - state.lineInfo[entry].offset = state.lineInfo[ln].offset - firstAddr; - entry++; - } - unsigned int length = eaddr - firstAddr; - if(dump) - printf("AddLines(%08x+%04x, Line=%4d+%3d, %s)\n", firstAddr, length, firstLine, entry - firstEntry, fname.c_str()); - int rc = mod->AddLines(fname.c_str(), segIndex + 1, firstAddr, length, firstAddr, firstLine, - (unsigned char*) &state.lineInfo[firstEntry], - (entry - firstEntry) * sizeof(state.lineInfo[0])); -#else - unsigned int firstLine = 0; - unsigned int firstAddr = 0; - int rc = mod->AddLines(fname.c_str(), segIndex + 1, saddr, eaddr - saddr, firstAddr, firstLine, - (unsigned char*) &state.lineInfo[0], state.lineInfo.size() * sizeof(state.lineInfo[0])); -#endif - - state.lineInfo.resize(0); - return rc > 0; -} - bool CV2PDB::addDWARFLines() { if(!img.debug_line) return setError("no .debug_line section found"); - mspdb::Mod* mod = globalMod(); - for(unsigned long off = 0; off < img.debug_line_length; ) - { - DWARF_LineNumberProgramHeader* hdr = (DWARF_LineNumberProgramHeader*) (img.debug_line + off); - int length = hdr->unit_length; - if(length < 0) - break; - length += sizeof(length); - - unsigned char* p = (unsigned char*) (hdr + 1); - unsigned char* end = (unsigned char*) hdr + length; - - std::vector opcode_lengths; - opcode_lengths.resize(hdr->opcode_base); - opcode_lengths[0] = 0; - for(int o = 1; o < hdr->opcode_base && p < end; o++) - opcode_lengths[o] = LEB128(p); + if (!interpretDWARFLines(img, globalMod())) + return setError("cannot add line number info to module"); - DWARF_LineState state; - state.seg_offset = img.getImageBase() + img.getSection(img.codeSegment).VirtualAddress; - - // dirs - while(p < end) - { - if(*p == 0) - break; - state.include_dirs.push_back((const char*) p); - p += strlen((const char*) p) + 1; - } - p++; - - // files - DWARF_FileName fname; - while(p < end && *p) - { - fname.read(p); - state.files.push_back(fname); - } - p++; - - std::vector lineInfo; - - state.init(hdr); - while(p < end) - { - int opcode = *p++; - if(opcode >= hdr->opcode_base) - { - // special opcode - int adjusted_opcode = opcode - hdr->opcode_base; - int operation_advance = adjusted_opcode / hdr->line_range; - state.advance_addr(hdr, operation_advance); - int line_advance = hdr->line_base + (adjusted_opcode % hdr->line_range); - state.line += line_advance; - - state.addLineInfo(); - - state.basic_block = false; - state.prologue_end = false; - state.epilogue_end = false; - state.discriminator = 0; - } - else - { - switch(opcode) - { - case 0: // extended - { - int exlength = LEB128(p); - unsigned char* q = p + exlength; - int excode = *p++; - switch(excode) - { - case DW_LNE_end_sequence: - if((char*)p - img.debug_line >= 0xe4e0) - p = p; - state.end_sequence = true; - state.last_addr = state.address; - state.addLineInfo(); - if(!_flushDWARFLines(this, state)) - return setError("cannot add line number info to module"); - state.init(hdr); - break; - case DW_LNE_set_address: - if(unsigned long adr = RD4(p)) - state.address = adr; - else - state.address = state.last_addr; // strange adr 0 for templates? - state.op_index = 0; - break; - case DW_LNE_define_file: - fname.read(p); - state.file_ptr = &fname; - state.file = 0; - break; - case DW_LNE_set_discriminator: - state.discriminator = LEB128(p); - break; - } - p = q; - } - break; - case DW_LNS_copy: - state.addLineInfo(); - state.basic_block = false; - state.prologue_end = false; - state.epilogue_end = false; - state.discriminator = 0; - break; - case DW_LNS_advance_pc: - state.advance_addr(hdr, LEB128(p)); - break; - case DW_LNS_advance_line: - state.line += SLEB128(p); - break; - case DW_LNS_set_file: - if(!_flushDWARFLines(this, state)) - return setError("cannot add line number info to module"); - state.file = LEB128(p); - break; - case DW_LNS_set_column: - state.column = LEB128(p); - break; - case DW_LNS_negate_stmt: - state.is_stmt = !state.is_stmt; - break; - case DW_LNS_set_basic_block: - state.basic_block = true; - break; - case DW_LNS_const_add_pc: - state.advance_addr(hdr, (255 - hdr->opcode_base) / hdr->line_range); - break; - case DW_LNS_fixed_advance_pc: - state.address += RD2(p); - state.op_index = 0; - break; - case DW_LNS_set_prologue_end: - state.prologue_end = true; - break; - case DW_LNS_set_epilogue_begin: - state.epilogue_end = true; - break; - case DW_LNS_set_isa: - state.isa = LEB128(p); - break; - default: - // unknown standard opcode - for(unsigned int arg = 0; arg < opcode_lengths[opcode]; arg++) - LEB128(p); - break; - } - } - } - if(!_flushDWARFLines(this, state)) - return setError("cannot add line number info to module"); - - off += length; - } - - return true; -} - -bool CV2PDB::relocateDebugLineInfo() -{ - if(!img.reloc || !img.reloc_length) - return true; - - unsigned int img_base = 0x400000; - char* relocbase = img.reloc; - char* relocend = img.reloc + img.reloc_length; - while(relocbase < relocend) - { - unsigned int virtadr = *(unsigned int *) relocbase; - unsigned int chksize = *(unsigned int *) (relocbase + 4); - - char* p = img.RVA (virtadr, 1); - if(p >= img.debug_line && p < img.debug_line + img.debug_line_length) - { - for (unsigned int w = 8; w < chksize; w += 2) - { - unsigned short entry = *(unsigned short*)(relocbase + w); - unsigned short type = (entry >> 12) & 0xf; - unsigned short off = entry & 0xfff; - - if(type == 3) // HIGHLOW - { - *(long*) (p + off) += img_base; - } - } - } - if(chksize == 0 || chksize >= img.reloc_length) - break; - relocbase += chksize; - } - return true; + return true; } bool CV2PDB::addDWARFPublics() diff --git a/src/dwarflines.cpp b/src/dwarflines.cpp new file mode 100644 index 0000000..4a1b2d5 --- /dev/null +++ b/src/dwarflines.cpp @@ -0,0 +1,316 @@ +// Convert DMD CodeView/DWARF debug information to PDB files +// Copyright (c) 2009-2012 by Rainer Schuetze, All Rights Reserved +// +// License for redistribution is given by the Artistic License 2.0 +// see file LICENSE for further details +// + +#include "PEImage.h" +#include "mspdb.h" +#include "dwarf.h" +#include "readDwarf.h" + +bool isRelativePath(const std::string& s) +{ + if(s.length() < 1) + return true; + if(s[0] == '/' || s[0] == '\\') + return false; + if(s.length() < 2) + return true; + if(s[1] == ':') + return false; + return true; +} + +static int cmpAdr(const void* s1, const void* s2) +{ + const mspdb::LineInfoEntry* e1 = (const mspdb::LineInfoEntry*) s1; + const mspdb::LineInfoEntry* e2 = (const mspdb::LineInfoEntry*) s2; + return e1->offset - e2->offset; +} + + +bool printLines(char const *fname, unsigned short sec, char const *secname, + mspdb::LineInfoEntry* pLineInfo, long numLineInfo) +{ + printf("Sym: %s\n", secname ? secname : ""); + printf("File: %s\n", fname); + for (int i = 0; i < numLineInfo; i++) + printf("\tOff 0x%x: Line %d\n", pLineInfo[i].offset, pLineInfo[i].line); + return true; +} + + +bool _flushDWARFLines(const PEImage& img, mspdb::Mod* mod, DWARF_LineState& state) +{ + if(state.lineInfo.size() == 0) + return true; + + unsigned int saddr = state.lineInfo[0].offset; + unsigned int eaddr = state.lineInfo.back().offset; + int segIndex = state.section; + if (segIndex < 0) + segIndex = img.findSection(saddr + state.seg_offset); + if(segIndex < 0) + { + // throw away invalid lines (mostly due to "set address to 0") + state.lineInfo.resize(0); + return true; + //return false; + } + +// if(saddr >= 0x4000) +// return true; + + const DWARF_FileName* dfn; + if(state.file == 0) + dfn = state.file_ptr; + else if(state.file > 0 && state.file <= state.files.size()) + dfn = &state.files[state.file - 1]; + else + return false; + std::string fname = dfn->file_name; + + if(isRelativePath(fname) && + dfn->dir_index > 0 && dfn->dir_index <= state.include_dirs.size()) + { + std::string dir = state.include_dirs[dfn->dir_index - 1]; + if(dir.length() > 0 && dir[dir.length() - 1] != '/' && dir[dir.length() - 1] != '\\') + dir.append("\\"); + fname = dir + fname; + } + for(size_t i = 0; i < fname.length(); i++) + if(fname[i] == '/') + fname[i] = '\\'; + + if (!mod) + { + printLines(fname.c_str(), segIndex, img.findSectionSymbolName(segIndex), + state.lineInfo.data(), state.lineInfo.size()); + state.lineInfo.resize(0); + return true; + } +#if 1 + bool dump = false; // (fname == "cvtest.d"); + //qsort(&state.lineInfo[0], state.lineInfo.size(), sizeof(state.lineInfo[0]), cmpAdr); +#if 0 + printf("%s:\n", fname.c_str()); + for(size_t ln = 0; ln < state.lineInfo.size(); ln++) + printf(" %08x: %4d\n", state.lineInfo[ln].offset + 0x401000, state.lineInfo[ln].line); +#endif + + int rc = 1; + unsigned int firstLine = state.lineInfo[0].line; + unsigned int firstAddr = state.lineInfo[0].offset; + unsigned int firstEntry = 0; + unsigned int entry = 0; + for(size_t ln = firstEntry; ln < state.lineInfo.size(); ln++) + { + if(state.lineInfo[ln].line < firstLine || state.lineInfo[ln].offset < firstAddr) + { + if(ln > firstEntry) + { + unsigned int length = state.lineInfo[entry-1].offset + 1; // firstAddr has been subtracted before + if(dump) + printf("AddLines(%08x+%04x, Line=%4d+%3d, %s)\n", firstAddr, length, firstLine, entry - firstEntry, fname.c_str()); + rc = mod->AddLines(fname.c_str(), segIndex + 1, firstAddr, length, firstAddr, firstLine, + (unsigned char*) &state.lineInfo[firstEntry], + (ln - firstEntry) * sizeof(state.lineInfo[0])); + firstLine = state.lineInfo[ln].line; + firstAddr = state.lineInfo[ln].offset; + firstEntry = entry; + } + } + else if(ln > firstEntry && state.lineInfo[ln].offset == state.lineInfo[ln-1].offset) + continue; // skip entries without offset change + state.lineInfo[entry].line = state.lineInfo[ln].line - firstLine; + state.lineInfo[entry].offset = state.lineInfo[ln].offset - firstAddr; + entry++; + } + unsigned int length = eaddr - firstAddr; + if(dump) + printf("AddLines(%08x+%04x, Line=%4d+%3d, %s)\n", firstAddr, length, firstLine, entry - firstEntry, fname.c_str()); + rc = mod->AddLines(fname.c_str(), segIndex + 1, firstAddr, length, firstAddr, firstLine, + (unsigned char*) &state.lineInfo[firstEntry], + (entry - firstEntry) * sizeof(state.lineInfo[0])); + +#else + unsigned int firstLine = 0; + unsigned int firstAddr = 0; + int rc = mod->AddLines(fname.c_str(), segIndex + 1, saddr, eaddr - saddr, firstAddr, firstLine, + (unsigned char*) &state.lineInfo[0], state.lineInfo.size() * sizeof(state.lineInfo[0])); +#endif + + state.lineInfo.resize(0); + return rc > 0; +} + +bool interpretDWARFLines(const PEImage& img, mspdb::Mod* mod) +{ + for(unsigned long off = 0; off < img.debug_line_length; ) + { + DWARF_LineNumberProgramHeader* hdr = (DWARF_LineNumberProgramHeader*) (img.debug_line + off); + int length = hdr->unit_length; + if(length < 0) + break; + length += sizeof(length); + + unsigned char* p = (unsigned char*) (hdr + 1); + unsigned char* end = (unsigned char*) hdr + length; + + std::vector opcode_lengths; + opcode_lengths.resize(hdr->opcode_base); + if (hdr->opcode_base > 0) + { + opcode_lengths[0] = 0; + for(int o = 1; o < hdr->opcode_base && p < end; o++) + opcode_lengths[o] = LEB128(p); + } + + DWARF_LineState state; + state.seg_offset = img.getImageBase() + img.getSection(img.codeSegment).VirtualAddress; + + // dirs + while(p < end) + { + if(*p == 0) + break; + state.include_dirs.push_back((const char*) p); + p += strlen((const char*) p) + 1; + } + p++; + + // files + DWARF_FileName fname; + while(p < end && *p) + { + fname.read(p); + state.files.push_back(fname); + } + p++; + + state.init(hdr); + while(p < end) + { + int opcode = *p++; + if(opcode >= hdr->opcode_base) + { + // special opcode + int adjusted_opcode = opcode - hdr->opcode_base; + int operation_advance = adjusted_opcode / hdr->line_range; + state.advance_addr(hdr, operation_advance); + int line_advance = hdr->line_base + (adjusted_opcode % hdr->line_range); + state.line += line_advance; + + state.addLineInfo(); + + state.basic_block = false; + state.prologue_end = false; + state.epilogue_end = false; + state.discriminator = 0; + } + else + { + switch(opcode) + { + case 0: // extended + { + int exlength = LEB128(p); + unsigned char* q = p + exlength; + int excode = *p++; + switch(excode) + { + case DW_LNE_end_sequence: + if((char*)p - img.debug_line >= 0xe4e0) + p = p; + state.end_sequence = true; + state.last_addr = state.address; + state.addLineInfo(); + if(!_flushDWARFLines(img, mod, state)) + return false; + state.init(hdr); + break; + case DW_LNE_set_address: + if (!mod && state.section == -1) + state.section = img.getRelocationInLineSegment((char*)p - img.debug_line); + if(unsigned long adr = RD4(p)) + state.address = adr; + else if (!mod) + state.address = adr; + else + state.address = state.last_addr; // strange adr 0 for templates? + state.op_index = 0; + break; + case DW_LNE_define_file: + fname.read(p); + state.file_ptr = &fname; + state.file = 0; + break; + case DW_LNE_set_discriminator: + state.discriminator = LEB128(p); + break; + } + p = q; + break; + } + case DW_LNS_copy: + state.addLineInfo(); + state.basic_block = false; + state.prologue_end = false; + state.epilogue_end = false; + state.discriminator = 0; + break; + case DW_LNS_advance_pc: + state.advance_addr(hdr, LEB128(p)); + break; + case DW_LNS_advance_line: + state.line += SLEB128(p); + break; + case DW_LNS_set_file: + if(!_flushDWARFLines(img, mod, state)) + return false; + state.file = LEB128(p); + break; + case DW_LNS_set_column: + state.column = LEB128(p); + break; + case DW_LNS_negate_stmt: + state.is_stmt = !state.is_stmt; + break; + case DW_LNS_set_basic_block: + state.basic_block = true; + break; + case DW_LNS_const_add_pc: + state.advance_addr(hdr, (255 - hdr->opcode_base) / hdr->line_range); + break; + case DW_LNS_fixed_advance_pc: + state.address += RD2(p); + state.op_index = 0; + break; + case DW_LNS_set_prologue_end: + state.prologue_end = true; + break; + case DW_LNS_set_epilogue_begin: + state.epilogue_end = true; + break; + case DW_LNS_set_isa: + state.isa = LEB128(p); + break; + default: + // unknown standard opcode + for(unsigned int arg = 0; arg < opcode_lengths[opcode]; arg++) + LEB128(p); + break; + } + } + } + if(!_flushDWARFLines(img, mod, state)) + return false; + + off += length; + } + + return true; +} + diff --git a/src/main.cpp b/src/main.cpp index 8c23cf3..112e7b5 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -105,7 +105,6 @@ void makefullpath(TCHAR* pdbname) int T_main(int argc, TCHAR* argv[]) { - PEImage img; double Dversion = 2.043; const TCHAR* pdbref = 0; @@ -143,7 +142,8 @@ int T_main(int argc, TCHAR* argv[]) return -1; } - if (!img.load(argv[1])) + PEImage img; + if (!img.loadExe(argv[1])) fatal(SARG ": %s", argv[1], img.getLastError()); if (img.countCVEntries() == 0 && !img.hasDWARF()) fatal(SARG ": no codeview debug entries found", argv[1]); @@ -177,7 +177,7 @@ int T_main(int argc, TCHAR* argv[]) if(img.hasDWARF()) { - if(!cv2pdb.relocateDebugLineInfo()) + if(!img.relocateDebugLineInfo(0x400000)) fatal(SARG ": %s", argv[1], cv2pdb.getLastError()); if(!cv2pdb.createDWARFModules()) diff --git a/src/readDwarf.h b/src/readDwarf.h index 637a6ec..3c4ded5 100644 --- a/src/readDwarf.h +++ b/src/readDwarf.h @@ -255,6 +255,7 @@ struct DWARF_LineState // not part of the "documented" state DWARF_FileName* file_ptr; unsigned long seg_offset; + unsigned long section; unsigned long last_addr; std::vector lineInfo; @@ -266,6 +267,7 @@ struct DWARF_LineState void init(DWARF_LineNumberProgramHeader* hdr) { + section = -1; address = 0; op_index = 0; file = 1; @@ -366,4 +368,8 @@ public: bool readNext(DWARF_InfoData& id, bool stopAtNull = false); }; -#endif \ No newline at end of file +// iterate over DWARF debug_line information +// if mod is null, print them out, otherwise add to module +bool interpretDWARFLines(const PEImage& img, mspdb::Mod* mod); + +#endif -- cgit v0.12