summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorRainer Schuetze <r.sagitario@gmx.de>2015-05-08 21:00:52 (GMT)
committerRainer Schuetze <r.sagitario@gmx.de>2015-05-08 21:00:52 (GMT)
commit7014d4546d7113aa21ec21b1a19293cacebc948a (patch)
tree8ab39f331250e0979de15fea4eb77866f62b6072 /src
parent0f4103c3f5768945c8a207746d1cb52524303110 (diff)
downloadcv2pdb-7014d4546d7113aa21ec21b1a19293cacebc948a.zip
cv2pdb-7014d4546d7113aa21ec21b1a19293cacebc948a.tar.gz
cv2pdb-7014d4546d7113aa21ec21b1a19293cacebc948a.tar.bz2
- new tool dumplines to display the debug line number info
Diffstat (limited to 'src')
-rw-r--r--src/PEImage.cpp359
-rw-r--r--src/PEImage.h23
-rw-r--r--src/cv2pdb.h2
-rw-r--r--src/cv2pdb.vcxproj1
-rw-r--r--src/cv2pdb.vcxproj.filters3
-rw-r--r--src/cv2pdb_vs12.sln14
-rw-r--r--src/dumplines.cpp139
-rw-r--r--src/dumplines.vcxproj115
-rw-r--r--src/dumplines.vcxproj.user8
-rw-r--r--src/dwarf2pdb.cpp311
-rw-r--r--src/dwarflines.cpp316
-rw-r--r--src/main.cpp6
-rw-r--r--src/readDwarf.h8
13 files changed, 970 insertions, 335 deletions
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 <direct.h>
#include <share.h>
#include <sys/stat.h>
+#include <vector>
#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<char>(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<char>(IMGHDR(FileHeader.PointerToSymbolTable) + IMGHDR(FileHeader.NumberOfSymbols) * IMAGE_SIZEOF_SYMBOL);
+ symtable = DPV<char>(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<IMAGE_FILE_HEADER> (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<ANON_OBJECT_HEADER_BIGOBJ> (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<char>(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<char>(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<char>(sec[s].PointerToRawData, sec[s].SizeOfRawData);
if(strcmp(name, ".debug_info") == 0)
- debug_info = DPV<char>(sec[s].PointerToRawData, debug_info_length = sec[s].Misc.VirtualSize);
+ debug_info = DPV<char>(sec[s].PointerToRawData, debug_info_length = sec[s].SizeOfRawData);
if(strcmp(name, ".debug_abbrev") == 0)
- debug_abbrev = DPV<char>(sec[s].PointerToRawData, debug_abbrev_length = sec[s].Misc.VirtualSize);
+ debug_abbrev = DPV<char>(sec[s].PointerToRawData, debug_abbrev_length = sec[s].SizeOfRawData);
if(strcmp(name, ".debug_line") == 0)
- debug_line = DPV<char>(sec[s].PointerToRawData, debug_line_length = sec[s].Misc.VirtualSize);
+ debug_line = DPV<char>(sec[linesSegment = s].PointerToRawData, debug_line_length = sec[s].SizeOfRawData);
if(strcmp(name, ".debug_frame") == 0)
debug_frame = DPV<char>(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<char>(sec[s].PointerToRawData, sec[s].SizeOfRawData);
if(strcmp(name, ".debug_ranges") == 0)
- debug_ranges = DPV<char>(sec[s].PointerToRawData, debug_ranges_length = sec[s].Misc.VirtualSize);
+ debug_ranges = DPV<char>(sec[s].PointerToRawData, debug_ranges_length = sec[s].SizeOfRawData);
if(strcmp(name, ".reloc") == 0)
- reloc = DPV<char>(sec[s].PointerToRawData, reloc_length = sec[s].Misc.VirtualSize);
+ reloc = DPV<char>(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<char> (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<IMAGE_RELOCATION>(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<DWORD>(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 : "<none>");
+ 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<const unsigned char*> lnames;
+ std::vector<const unsigned char*> 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<typename SYM>
+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<IMAGE_SYMBOL_EX> (s);
+ else
+ return t_findSectionSymbolName<IMAGE_SYMBOL> (s);
+}
+
int PEImage::findSymbol(const char* name, unsigned long& off) const
{
- IMAGE_SYMBOL* symtable = DPV<IMAGE_SYMBOL>(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<typename SYM> 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<byte*, int> 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 @@
<ClCompile Include="cvutil.cpp" />
<ClCompile Include="demangle.cpp" />
<ClCompile Include="dwarf2pdb.cpp" />
+ <ClCompile Include="dwarflines.cpp" />
<ClCompile Include="main.cpp" />
<ClCompile Include="mspdb.cpp" />
<ClCompile Include="PEImage.cpp" />
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 @@
<ClCompile Include="readDwarf.cpp">
<Filter>Source Files</Filter>
</ClCompile>
+ <ClCompile Include="dwarflines.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="cv2pdb.h">
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 <direct.h>
+
+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 " <obj-file>\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 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{6434537D-446A-4C99-9829-135F7C000D90}</ProjectGuid>
+ <RootNamespace>dumpLines</RootNamespace>
+ <Keyword>Win32Proj</Keyword>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <PlatformToolset>v120_xp</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <PlatformToolset>v120_xp</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup>
+ <_ProjectFileVersion>12.0.21005.1</_ProjectFileVersion>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <OutDir>..\bin\$(Configuration)\</OutDir>
+ <IntDir>..\bin\$(Configuration)\$(ProjectName)\</IntDir>
+ <LinkIncremental>true</LinkIncremental>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <OutDir>..\bin\$(Configuration)\</OutDir>
+ <IntDir>..\bin\$(Configuration)\$(ProjectName)\</IntDir>
+ <LinkIncremental>false</LinkIncremental>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <AdditionalOptions>/wd4996 %(AdditionalOptions)</AdditionalOptions>
+ <Optimization>Disabled</Optimization>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MinimalRebuild>true</MinimalRebuild>
+ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+ <TreatWChar_tAsBuiltInType>false</TreatWChar_tAsBuiltInType>
+ <PrecompiledHeader />
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>EditAndContinue</DebugInformationFormat>
+ </ClCompile>
+ <Link>
+ <AdditionalDependencies>dbghelp.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <OutputFile>$(OutDir)$(ProjectName).exe</OutputFile>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <SubSystem>Console</SubSystem>
+ <TargetMachine>MachineX86</TargetMachine>
+ <MinimumRequiredVersion>5.1</MinimumRequiredVersion>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <AdditionalOptions>/wd4996 %(AdditionalOptions)</AdditionalOptions>
+ <Optimization>MaxSpeed</Optimization>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <TreatWChar_tAsBuiltInType>false</TreatWChar_tAsBuiltInType>
+ <PrecompiledHeader />
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ </ClCompile>
+ <Link>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <SubSystem>Console</SubSystem>
+ <OptimizeReferences>true</OptimizeReferences>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <TargetMachine>MachineX86</TargetMachine>
+ <Profile>true</Profile>
+ <MinimumRequiredVersion>5.1</MinimumRequiredVersion>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="dumplines.cpp" />
+ <ClCompile Include="dwarflines.cpp" />
+ <ClCompile Include="PEImage.cpp" />
+ <ClCompile Include="readDwarf.cpp" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="dcvinfo.h" />
+ <ClInclude Include="dwarf.h" />
+ <ClInclude Include="LastError.h" />
+ <ClInclude Include="PEImage.h" />
+ <ClInclude Include="readDwarf.h" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ 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 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <LocalDebuggerCommandArguments>testgc3.obj</LocalDebuggerCommandArguments>
+ <LocalDebuggerWorkingDirectory>c:\tmp\d\objdump</LocalDebuggerWorkingDirectory>
+ <DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
+ </PropertyGroup>
+</Project> \ 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<unsigned int> 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<mspdb::LineInfoEntry> 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<char> (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 : "<none>");
+ 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<unsigned int> 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<mspdb::LineInfoEntry> 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