summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRainer Schuetze <r.sagitario@gmx.de>2018-03-30 07:52:12 (GMT)
committerGitHub <noreply@github.com>2018-03-30 07:52:12 (GMT)
commit74615ceab4ac7577a8fdf1d2f93df7973ae1ff21 (patch)
treec4e4edb90e933146657174238d3bd49ecc843565
parenta76c08cdbecf7a20f7f486de724e720a8f012bdd (diff)
parentf505bf62ceaf051120609c019261f8908874af18 (diff)
downloadcv2pdb-74615ceab4ac7577a8fdf1d2f93df7973ae1ff21.zip
cv2pdb-74615ceab4ac7577a8fdf1d2f93df7973ae1ff21.tar.gz
cv2pdb-74615ceab4ac7577a8fdf1d2f93df7973ae1ff21.tar.bz2
Merge pull request #24 from pmderodat/master
Various improvements for Ada
-rw-r--r--src/cv2pdb.cpp21
-rw-r--r--src/cv2pdb.h21
-rw-r--r--src/dwarf2pdb.cpp469
-rw-r--r--src/readDwarf.cpp25
-rw-r--r--src/readDwarf.h26
-rw-r--r--src/symutil.cpp4
6 files changed, 462 insertions, 104 deletions
diff --git a/src/cv2pdb.cpp b/src/cv2pdb.cpp
index 1ac48bd..95749bc 100644
--- a/src/cv2pdb.cpp
+++ b/src/cv2pdb.cpp
@@ -49,6 +49,7 @@ CV2PDB::CV2PDB(PEImage& image)
thisIsNotRef = true;
v3 = true;
countEntries = img.countCVEntries();
+ build_cfi_index();
}
CV2PDB::~CV2PDB()
@@ -842,16 +843,20 @@ int CV2PDB::addFieldNestedType(codeview_fieldtype* dfieldtype, int type, const c
int CV2PDB::addFieldEnumerate(codeview_fieldtype* dfieldtype, const char* name, int val)
{
+ int len = 0;
+ BYTE *buffer = (BYTE*)dfieldtype;
+
dfieldtype->enumerate_v1.id = v3 ? LF_ENUMERATE_V3 : LF_ENUMERATE_V1;
dfieldtype->enumerate_v1.attribute = 0;
- //assert(val < LF_NUMERIC);
- dfieldtype->enumerate_v1.value = val;
- int len = cstrcpy_v(v3, (BYTE*)(&dfieldtype->enumerate_v1 + 1), name);
- len += sizeof (dfieldtype->enumerate_v1);
+ len += 4;
- unsigned char* p = (unsigned char*) dfieldtype;
+ // Append the enumerator value, and then its name
+ len += write_numeric_leaf(val, buffer + len);
+ len += cstrcpy_v(v3, buffer + len, name);
+
+ // Add padding so that the next record is properly aligned
for (; len & 3; len++)
- p[len] = 0xf4 - (len & 3);
+ buffer[len] = 0xf4 - (len & 3);
return len;
}
@@ -1855,8 +1860,8 @@ int CV2PDB::appendModifierType(int type, int attr)
dtype->modifier_v2.type = translateType(type);
dtype->modifier_v2.attribute = attr;
int len = sizeof(dtype->modifier_v2);
- //for (; len & 3; len++)
- // userTypes[cbUserTypes + len] = 0xf4 - (len & 3);
+ for (; len & 3; len++)
+ userTypes[cbUserTypes + len] = 0xf4 - (len & 3);
dtype->modifier_v2.len = len - 2;
cbUserTypes += len;
diff --git a/src/cv2pdb.h b/src/cv2pdb.h
index b1e84a1..558ce21 100644
--- a/src/cv2pdb.h
+++ b/src/cv2pdb.h
@@ -7,6 +7,8 @@
#ifndef __CV2PDB_H__
#define __CV2PDB_H__
+#include <stdint.h>
+
#include "LastError.h"
#include "mspdb.h"
#include "readDwarf.h"
@@ -23,6 +25,7 @@ extern "C" {
class PEImage;
struct DWARF_InfoData;
struct DWARF_CompilationUnit;
+class CFIIndex;
class CV2PDB : public LastError
{
@@ -173,10 +176,16 @@ public:
int addDWARFStructure(DWARF_InfoData& id, DWARF_CompilationUnit* cu, DIECursor cursor);
int addDWARFArray(DWARF_InfoData& arrayid, DWARF_CompilationUnit* cu, DIECursor cursor);
int addDWARFBasicType(const char*name, int encoding, int byte_size);
+ int addDWARFEnum(DWARF_InfoData& enumid, DWARF_CompilationUnit* cu, DIECursor cursor);
int getTypeByDWARFPtr(DWARF_CompilationUnit* cu, byte* ptr);
int getDWARFTypeSize(DWARF_CompilationUnit* cu, byte* ptr);
- int getDWARFArrayBounds(DWARF_InfoData& arrayid, DWARF_CompilationUnit* cu, DIECursor cursor, int& upperBound);
+ void getDWARFArrayBounds(DWARF_InfoData& arrayid, DWARF_CompilationUnit* cu, DIECursor cursor,
+ int& basetype, int& lowerBound, int& upperBound);
+ void getDWARFSubrangeInfo(DWARF_InfoData& subrangeid, DWARF_CompilationUnit* cu,
+ int& basetype, int& lowerBound, int& upperBound);
+ int getDWARFBasicType(int encoding, int byte_size);
+ void build_cfi_index();
bool mapTypes();
bool createTypes();
@@ -184,6 +193,7 @@ public:
BYTE* libraries;
PEImage& img;
+ CFIIndex* cfi_index;
mspdb::PDB* pdb;
mspdb::DBI *dbi;
@@ -264,6 +274,15 @@ public:
// DWARF
int codeSegOff;
std::unordered_map<byte*, int> mapOffsetToType;
+
+ // Default lower bound for the current compilation unit. This depends on
+ // the language of the current unit.
+ unsigned currentDefaultLowerBound;
+
+ // Value of the DW_AT_low_pc attribute for the current compilation unit.
+ // Specify the default base address for use in location lists and range
+ // lists.
+ uint32_t currentBaseAddress;
};
#endif //__CV2PDB_H__
diff --git a/src/dwarf2pdb.cpp b/src/dwarf2pdb.cpp
index 6388f8d..cb078e3 100644
--- a/src/dwarf2pdb.cpp
+++ b/src/dwarf2pdb.cpp
@@ -17,6 +17,7 @@
#include "dwarf.h"
+#include <algorithm>
#include <assert.h>
#include <string>
#include <vector>
@@ -155,6 +156,41 @@ CV_X86_REG dwarf_to_amd64_reg(unsigned dwarf_reg)
}
}
+// Index for efficient lookups in Call Frame Information entries
+class CFIIndex
+{
+public:
+ // Build the index, which will be tied to IMG.
+ CFIIndex(const PEImage& img);
+
+ // Look for a FDE whose PC range covers the PCLO/PCHI range and return a
+ // pointer to the FDE in the .debug_frame section. Return NULL if no such
+ // FDE exists.
+ byte *lookup(unsigned int pclo, unsigned pchi) const;
+
+private:
+ struct index_entry
+ {
+ // PC range for the FDE
+ unsigned int pclo, pchi;
+ // Pointer to the FDE in the .debug_frame section
+ byte *ptr;
+
+ // Sort entries by PCLO first and then by PCHI.
+ bool operator<(const index_entry& other) const {
+ if (pclo < other.pclo)
+ return true;
+ else if (pclo == other.pclo)
+ return pchi < other.pchi;
+ else
+ return false;
+ }
+
+ };
+
+ std::vector<index_entry> index;
+};
+
// Call Frame Information entry (CIE or FDE)
class CFIEntry
{
@@ -447,28 +483,27 @@ public:
Location cfa;
};
-Location findBestCFA(const PEImage& img, unsigned int pclo, unsigned int pchi)
+Location findBestCFA(const PEImage& img, const CFIIndex* index, unsigned int pclo, unsigned int pchi)
{
bool x64 = img.isX64();
Location ebp = { Location::RegRel, x64 ? 6 : 5, x64 ? 16 : 8 };
if (!img.debug_frame)
return ebp;
+ byte *fde_ptr = index->lookup(pclo, pchi);
+ if (fde_ptr == NULL)
+ return ebp;
+
CFIEntry entry;
CFICursor cursor(img);
- while(cursor.readNext(entry))
- {
- if (entry.type == CFIEntry::FDE &&
- entry.initial_location <= pclo && entry.initial_location + entry.address_range >= pchi)
- {
- CFACursor cfa(entry, pclo);
- while(cfa.processNext()) {}
- cfa.setInstructions(entry.instructions, entry.instructions_length);
- while(!cfa.beforeRestore() && cfa.processNext()) {}
- return cfa.cfa;
- }
- }
- return ebp;
+ cursor.ptr = fde_ptr;
+
+ assert(cursor.readNext(entry));
+ CFACursor cfa(entry, pclo);
+ while(cfa.processNext()) {}
+ cfa.setInstructions(entry.instructions, entry.instructions_length);
+ while(!cfa.beforeRestore() && cfa.processNext()) {}
+ return cfa.cfa;
}
// Location list entry
@@ -707,7 +742,7 @@ bool CV2PDB::addDWARFProc(DWARF_InfoData& procid, DWARF_CompilationUnit* cu, DIE
if (frameBase.is_abs()) // pointer into location list in .debug_loc? assume CFA
frameBase = findBestFBLoc(img, cu, frameBase.off);
- Location cfa = findBestCFA(img, procid.pclo, procid.pchi);
+ Location cfa = findBestCFA(img, cfi_index, procid.pclo, procid.pchi);
if (cu)
{
@@ -716,7 +751,7 @@ bool CV2PDB::addDWARFProc(DWARF_InfoData& procid, DWARF_CompilationUnit* cu, DIE
int off = 8;
DIECursor prev = cursor;
- while (cursor.readNext(id, true) && id.tag == DW_TAG_formal_parameter)
+ while (cursor.readNext(id, true))
{
if (id.tag == DW_TAG_formal_parameter)
{
@@ -727,7 +762,6 @@ bool CV2PDB::addDWARFProc(DWARF_InfoData& procid, DWARF_CompilationUnit* cu, DIE
appendStackVar(id.name, getTypeByDWARFPtr(cu, id.type), loc, cfa);
}
}
- prev = cursor;
}
appendEndArg();
@@ -743,7 +777,43 @@ bool CV2PDB::addDWARFProc(DWARF_InfoData& procid, DWARF_CompilationUnit* cu, DIE
{
if (id.tag == DW_TAG_lexical_block)
{
- if (id.hasChild && id.pchi != id.pclo)
+ // It seems it is not possible to describe blocks with
+ // non-contiguous address ranges in CodeView. Instead,
+ // just create a range that is large enough to cover
+ // all continuous ranges.
+ if (id.hasChild && id.ranges != -1u)
+ {
+ id.pclo = -1u;
+ id.pchi = 0;
+
+ // TODO: handle base address selection
+ byte *r = (byte *)img.debug_ranges + id.ranges;
+ byte *rend = (byte *)img.debug_ranges + img.debug_ranges_length;
+ bool is_= img.isX64() ? 8 : 4;
+ while (r < rend)
+ {
+ uint64_t pclo, pchi;
+
+ if (img.isX64())
+ {
+ pclo = RD8(r);
+ pchi = RD8(r);
+ }
+ else
+ {
+ pclo = RD4(r);
+ pchi = RD4(r);
+ }
+ if (pclo == 0 && pchi == 0)
+ break;
+ if (pclo >= pchi)
+ continue;
+ id.pclo = min(id.pclo, pclo + currentBaseAddress);
+ id.pchi = max(id.pchi, pchi + currentBaseAddress);
+ }
+ }
+
+ if (id.hasChild && id.pchi > id.pclo)
{
appendLexicalBlock(id, pclo + codeSegOff);
DIECursor next = cursor;
@@ -878,39 +948,121 @@ int CV2PDB::addDWARFStructure(DWARF_InfoData& structid, DWARF_CompilationUnit* c
return cvtype;
}
-int CV2PDB::getDWARFArrayBounds(DWARF_InfoData& arrayid, DWARF_CompilationUnit* cu,
- DIECursor cursor, int& upperBound)
+void CV2PDB::getDWARFArrayBounds(DWARF_InfoData& arrayid, DWARF_CompilationUnit* cu,
+ DIECursor cursor, int& basetype, int& lowerBound, int& upperBound)
{
- int lowerBound = 0;
+ DWARF_InfoData id;
+ // TODO: handle multi-dimensional arrays
if (cu)
{
- DWARF_InfoData id;
while (cursor.readNext(id, true))
{
- int cvid = -1;
if (id.tag == DW_TAG_subrange_type)
{
- lowerBound = id.lower_bound;
- upperBound = id.upper_bound;
+ getDWARFSubrangeInfo(id, cu, basetype, lowerBound, upperBound);
+ return;
}
cursor.gotoSibling();
}
}
- return lowerBound;
+
+ // In case of error, return plausible defaults
+ getDWARFSubrangeInfo(id, NULL, basetype, lowerBound, upperBound);
+}
+
+void CV2PDB::getDWARFSubrangeInfo(DWARF_InfoData& subrangeid, DWARF_CompilationUnit* cu,
+ int& basetype, int& lowerBound, int& upperBound)
+{
+ // In case of error, return plausible defaults. Assume the array
+ // contains one item: this is probably helpful to users.
+ basetype = T_INT4;
+ lowerBound = currentDefaultLowerBound;
+ upperBound = lowerBound;
+
+ if (!cu || subrangeid.tag != DW_TAG_subrange_type)
+ return;
+
+ basetype = getTypeByDWARFPtr(cu, subrangeid.type);
+ if (subrangeid.has_lower_bound)
+ lowerBound = subrangeid.lower_bound;
+ upperBound = subrangeid.upper_bound;
+}
+
+int CV2PDB::getDWARFBasicType(int encoding, int byte_size)
+{
+ int type = 0, mode = 0, size = 0;
+ switch (encoding)
+ {
+ case DW_ATE_boolean: type = 3; break;
+ case DW_ATE_complex_float: type = 5; byte_size /= 2; break;
+ case DW_ATE_float: type = 4; break;
+ case DW_ATE_signed: type = 1; break;
+ case DW_ATE_signed_char: type = 7; break;
+ case DW_ATE_unsigned: type = 2; break;
+ case DW_ATE_unsigned_char: type = 7; break;
+ case DW_ATE_imaginary_float:type = 4; break;
+ case DW_ATE_UTF: type = 7; break;
+ default:
+ setError("unknown basic type encoding");
+ }
+ switch (type)
+ {
+ case 1: // signed
+ case 2: // unsigned
+ case 3: // boolean
+ switch (byte_size)
+ {
+ case 1: size = 0; break;
+ case 2: size = 1; break;
+ case 4: size = 2; break;
+ case 8: size = 3; break;
+ case 16: size = 4; break; // __int128? experimental, type exists with GCC for Win64
+ default:
+ setError("unsupported integer type size");
+ }
+ break;
+ case 4:
+ case 5:
+ switch (byte_size)
+ {
+ case 4: size = 0; break;
+ case 8: size = 1; break;
+ case 10: size = 2; break;
+ case 12: size = 2; break; // with padding bytes
+ case 16: size = 3; break;
+ case 6: size = 4; break;
+ default:
+ setError("unsupported real type size");
+ }
+ break;
+ case 7:
+ switch (byte_size)
+ {
+ case 1: size = 0; break;
+ case 2: size = encoding == DW_ATE_signed_char ? 2 : 3; break;
+ case 4: size = encoding == DW_ATE_signed_char ? 4 : 5; break;
+ case 8: size = encoding == DW_ATE_signed_char ? 6 : 7; break;
+ default:
+ setError("unsupported real int type size");
+ }
+ }
+ int t = size | (type << 4);
+ return translateType(t);
}
int CV2PDB::addDWARFArray(DWARF_InfoData& arrayid, DWARF_CompilationUnit* cu,
DIECursor cursor)
{
- int upperBound, lowerBound = getDWARFArrayBounds(arrayid, cu, cursor, upperBound);
+ int basetype, upperBound, lowerBound;
+ getDWARFArrayBounds(arrayid, cu, cursor, basetype, lowerBound, upperBound);
checkUserTypeAlloc(kMaxNameLen + 100);
codeview_type* cvt = (codeview_type*) (userTypes + cbUserTypes);
cvt->array_v2.id = v3 ? LF_ARRAY_V3 : LF_ARRAY_V2;
cvt->array_v2.elemtype = getTypeByDWARFPtr(cu, arrayid.type);
- cvt->array_v2.idxtype = 0x74;
+ cvt->array_v2.idxtype = basetype;
int len = (BYTE*)&cvt->array_v2.arrlen - (BYTE*)cvt;
int size = (upperBound - lowerBound + 1) * getDWARFTypeSize(cu, arrayid.type);
len += write_numeric_leaf(size, &cvt->array_v2.arrlen);
@@ -989,70 +1141,132 @@ bool CV2PDB::addDWARFSectionContrib(mspdb::Mod* mod, unsigned long pclo, unsigne
int CV2PDB::addDWARFBasicType(const char*name, int encoding, int byte_size)
{
- int type = 0, mode = 0, size = 0;
- switch(encoding)
- {
- case DW_ATE_boolean: type = 3; break;
- case DW_ATE_complex_float: type = 5; byte_size /= 2; break;
- case DW_ATE_float: type = 4; break;
- case DW_ATE_signed: type = 1; break;
- case DW_ATE_signed_char: type = 7; break;
- case DW_ATE_unsigned: type = 2; break;
- case DW_ATE_unsigned_char: type = 7; break;
- case DW_ATE_imaginary_float:type = 4; break;
- case DW_ATE_UTF: type = 7; break;
- default:
- setError("unknown basic type encoding");
- }
- switch(type)
- {
- case 1: // signed
- case 2: // unsigned
- case 3: // boolean
- switch(byte_size)
- {
- case 1: size = 0; break;
- case 2: size = 1; break;
- case 4: size = 2; break;
- case 8: size = 3; break;
- case 16: size = 4; break; // __int128? experimental, type exists with GCC for Win64
- default:
- setError("unsupported integer type size");
- }
- break;
- case 4:
- case 5:
- switch(byte_size)
- {
- case 4: size = 0; break;
- case 8: size = 1; break;
- case 10: size = 2; break;
- case 12: size = 2; break; // with padding bytes
- case 16: size = 3; break;
- case 6: size = 4; break;
- default:
- setError("unsupported real type size");
- }
- break;
- case 7:
- switch(byte_size)
- {
- case 1: size = 0; break;
- case 2: size = encoding == DW_ATE_signed_char ? 2 : 3; break;
- case 4: size = encoding == DW_ATE_signed_char ? 4 : 5; break;
- case 8: size = encoding == DW_ATE_signed_char ? 6 : 7; break;
- default:
- setError("unsupported real int type size");
- }
- }
- int t = size | (type << 4);
- t = translateType(t);
+ int t = getDWARFBasicType(encoding, byte_size);
int cvtype = appendTypedef(t, name, false);
if(useTypedefEnum)
addUdtSymbol(cvtype, name);
return cvtype;
}
+int CV2PDB::addDWARFEnum(DWARF_InfoData& enumid, DWARF_CompilationUnit* cu, DIECursor cursor)
+{
+ /* Enumerated types are described in CodeView with two components:
+
+ 1. A LF_ENUM leaf, representing the type itself. We put this one in the
+ userTypes buffer.
+
+ 2. One or several LF_FIELDLIST records, to contain the list of
+ enumerators (name and value) associated to the enum type
+ (LF_ENUMERATE leaves). As type records cannot be larger 2**16 bytes,
+ we need to create multiple records when there are too many
+ enumerators. The first record contains the first LF_ENUMERATE leaves,
+ and then a LF_INDEX leaf that references a second LF_FIELDLIST
+ record, which contains the following LF_ENUMERATE leaves, and so
+ on. */
+
+ codeview_reftype* rdtype;
+ codeview_type* dtype;
+
+ /* Type index and offset/length in dwarfTypes for the last LF_FIELDLIST record
+ we produced. */
+ int fieldlistType = nextDwarfType++;
+ int fieldlistOffset = cbDwarfTypes;
+ int fieldlistLength = 0;
+
+ /* Type index for the first LF_FIELDLIST record we produce. This is the one
+ that LF_ENUM will refer to */
+ const int firstFieldlistType = fieldlistType;
+
+ /* Total number of DW_TAG_enumerator DIEs we translate into
+ LF_ENUMERATE. */
+ int count = 0;
+
+ /* Create the LF_FIELDLIST record to contain enumerators. We will fill in
+ its length once done. */
+ checkDWARFTypeAlloc(100);
+ rdtype = (codeview_reftype*)(dwarfTypes + fieldlistOffset);
+ rdtype->fieldlist.len = 0;
+ rdtype->fieldlist.id = LF_FIELDLIST_V2;
+ fieldlistLength += 4;
+
+ /* Now fill this field list with the enumerators we find in DWARF. */
+ DWARF_InfoData id;
+ while (cursor.readNext(id, true))
+ {
+ if (id.tag == DW_TAG_enumerator && id.has_const_value)
+ {
+ cbDwarfTypes = fieldlistOffset + fieldlistLength;
+ checkDWARFTypeAlloc(kMaxNameLen + 100);
+ codeview_fieldtype* dfieldtype
+ = (codeview_fieldtype*)(dwarfTypes + fieldlistOffset + fieldlistLength);
+ int len = addFieldEnumerate(dfieldtype, id.name, id.const_value);
+
+ /* If adding this enumerate leaves no room for a LF_INDEX leaf,
+ create a new LF_FIELDLIST record now. */
+ if (fieldlistLength + len + sizeof(dfieldtype->index_v2) > 0xffff)
+ {
+ /* Append the LF_INDEX leaf. */
+ codeview_fieldtype* indexLeaf
+ = (codeview_fieldtype*)(dwarfTypes + fieldlistOffset + fieldlistLength);
+ indexLeaf->index_v2.id = LF_INDEX_V2;
+ indexLeaf->index_v2.unk = 0;
+ fieldlistLength += sizeof(indexLeaf->index_v2);
+
+ /* Set the length of the previous LF_FIELDLIST record. */
+ rdtype = (codeview_reftype*)(dwarfTypes + fieldlistOffset);
+ rdtype->fieldlist.len += fieldlistLength - 2;
+
+ /* Create the new LF_FIELDLIST record. */
+ cbDwarfTypes = fieldlistOffset + fieldlistLength;
+ int newFieldlistType = nextDwarfType++;
+ int newFieldlistOffset = cbDwarfTypes;
+ int newFieldlistLength = 0;
+
+ rdtype = (codeview_reftype*)(dwarfTypes + newFieldlistOffset);
+ rdtype->fieldlist.len = 0;
+ rdtype->fieldlist.id = LF_FIELDLIST_V2;
+ newFieldlistLength += 4;
+
+ /* Reference this new record from the LF_INDEX leaf. */
+ indexLeaf->index_v2.ref = newFieldlistType;
+
+ /* Make next runs target the new LF_FIELDLIST record. */
+ fieldlistType = newFieldlistType;
+ fieldlistOffset = newFieldlistOffset;
+ fieldlistLength = newFieldlistLength;
+
+ /* Append the current enumerator to the new record. */
+ cbDwarfTypes = fieldlistOffset + fieldlistLength;
+ checkDWARFTypeAlloc(kMaxNameLen + 100);
+ dfieldtype = (codeview_fieldtype*)(dwarfTypes + fieldlistOffset + fieldlistLength);
+ len = addFieldEnumerate(dfieldtype, id.name, id.const_value);
+ }
+ fieldlistLength += len;
+ count++;
+ }
+ }
+ cbDwarfTypes = fieldlistOffset + fieldlistLength;
+
+ /* The field list is ready, so we can know fill in its length: it is the
+ number of bytes we stored in dwarfTypes since we created it, minus the
+ usual 2 bytes for type record size. */
+ rdtype = (codeview_reftype*)(dwarfTypes + fieldlistOffset);
+ rdtype->fieldlist.len += fieldlistLength - 2;
+
+ /* Now the LF_FIELDLIST is ready, create the LF_ENUM type record itself. */
+ checkUserTypeAlloc();
+ int basetype = (enumid.type != 0)
+ ? getTypeByDWARFPtr(cu, enumid.type)
+ : getDWARFBasicType(enumid.encoding, enumid.byte_size);
+ dtype = (codeview_type*)(userTypes + cbUserTypes);
+ const char* name = (enumid.name ? enumid.name : "__noname");
+ cbUserTypes += addEnum(dtype, count, firstFieldlistType, 0, basetype, name);
+ int enumType = nextUserType++;
+
+ addUdtSymbol(enumType, name);
+ return enumType;
+}
+
int CV2PDB::getTypeByDWARFPtr(DWARF_CompilationUnit* cu, byte* ptr)
{
std::unordered_map<byte*, int>::iterator it = mapOffsetToType.find(ptr);
@@ -1080,8 +1294,9 @@ int CV2PDB::getDWARFTypeSize(DWARF_CompilationUnit* cu, byte* typePtr)
return cu->address_size;
case DW_TAG_array_type:
{
- int upperBound, lowerBound = getDWARFArrayBounds(id, cu, cursor, upperBound);
- return (upperBound + lowerBound + 1) * getDWARFTypeSize(cu, id.type);
+ int basetype, upperBound, lowerBound;
+ getDWARFArrayBounds(id, cu, cursor, basetype, lowerBound, upperBound);
+ return (upperBound - lowerBound + 1) * getDWARFTypeSize(cu, id.type);
}
default:
if(id.type)
@@ -1193,6 +1408,12 @@ bool CV2PDB::createTypes()
cvtype = appendPointerType(getTypeByDWARFPtr(cu, id.type), pointerAttr | 0x20);
break;
+ case DW_TAG_subrange_type:
+ // It seems we cannot materialize bounds for scalar types in
+ // CodeView, so just redirect to a mere base type.
+ cvtype = appendModifierType(getTypeByDWARFPtr(cu, id.type), 0);
+ break;
+
case DW_TAG_class_type:
case DW_TAG_structure_type:
case DW_TAG_union_type:
@@ -1201,10 +1422,12 @@ bool CV2PDB::createTypes()
case DW_TAG_array_type:
cvtype = addDWARFArray(id, cu, cursor.getSubtreeCursor());
break;
- case DW_TAG_subroutine_type:
- case DW_TAG_subrange_type:
case DW_TAG_enumeration_type:
+ cvtype = addDWARFEnum(id, cu, cursor.getSubtreeCursor());
+ break;
+
+ case DW_TAG_subroutine_type:
case DW_TAG_string_type:
case DW_TAG_ptr_to_member_type:
case DW_TAG_set_type:
@@ -1230,6 +1453,25 @@ bool CV2PDB::createTypes()
break;
case DW_TAG_compile_unit:
+ currentBaseAddress = id.pclo;
+ switch (id.language)
+ {
+ case DW_LANG_Ada83:
+ case DW_LANG_Cobol74:
+ case DW_LANG_Cobol85:
+ case DW_LANG_Fortran77:
+ case DW_LANG_Fortran90:
+ case DW_LANG_Pascal83:
+ case DW_LANG_Modula2:
+ case DW_LANG_Ada95:
+ case DW_LANG_Fortran95:
+ case DW_LANG_PLI:
+ currentDefaultLowerBound = 1;
+ break;
+
+ default:
+ currentDefaultLowerBound = 0;
+ }
#if !FULL_CONTRIB
if (id.dir && id.name)
{
@@ -1423,3 +1665,50 @@ bool CV2PDB::writeDWARFImage(const TCHAR* opath)
return true;
}
+
+void CV2PDB::build_cfi_index()
+{
+ if (img.debug_frame == NULL)
+ return;
+ cfi_index = new CFIIndex(img);
+}
+
+CFIIndex::CFIIndex(const PEImage& img)
+{
+ CFIEntry entry;
+ CFICursor cursor(img);
+
+ // First register all FDE as index entries
+ while (cursor.readNext(entry))
+ {
+ if (entry.type != CFIEntry::FDE)
+ continue;
+
+ index_entry e = {
+ entry.initial_location,
+ entry.initial_location + entry.address_range,
+ entry.ptr
+ };
+ index.push_back(e);
+ }
+
+ // Then make them sorted so we can perform binary searches later on
+ std::sort(index.begin(), index.end());
+}
+
+byte *CFIIndex::lookup(unsigned int pclo, unsigned int pchi) const
+{
+ // TODO: here, we are just looking for the first entry whose range contains PCLO,
+ // assuming the found entry will have the same PCLO and PCHI as arguments. Maybe
+ // this is not always true.
+ index_entry e = { pclo, pclo, NULL };
+ std::vector<index_entry>::const_iterator it
+ = std::lower_bound(index.begin(), index.end(), e);
+ if (it == index.end())
+ return NULL;
+ e = *it;
+ if (e.pclo <= pclo && pchi <= e.pchi)
+ return e.ptr;
+ else
+ return NULL;
+} \ No newline at end of file
diff --git a/src/readDwarf.cpp b/src/readDwarf.cpp
index 690cb8e..c91776c 100644
--- a/src/readDwarf.cpp
+++ b/src/readDwarf.cpp
@@ -492,14 +492,37 @@ bool DIECursor::readNext(DWARF_InfoData& id, bool stopAtNull)
break;
case DW_AT_lower_bound:
assert(a.type == Const || a.type == Ref || a.type == ExprLoc);
- if (a.type == Const) // TODO: other types not supported yet
+ if (a.type == Const)
+ {
+ // TODO: other types not supported yet
id.lower_bound = a.cons;
+ id.has_lower_bound = true;
+ }
break;
case DW_AT_containing_type: assert(a.type == Ref); id.containing_type = a.ref; break;
case DW_AT_specification: assert(a.type == Ref); id.specification = a.ref; break;
case DW_AT_data_member_location: id.member_location = a; break;
case DW_AT_location: id.location = a; break;
case DW_AT_frame_base: id.frame_base = a; break;
+ case DW_AT_language: assert(a.type == Const); id.language = a.cons; break;
+ case DW_AT_const_value:
+ switch (a.type)
+ {
+ case Const:
+ id.const_value = a.cons;
+ id.has_const_value = true;
+ break;
+
+ // TODO: handle these
+ case String:
+ case Block:
+ break;
+
+ default:
+ assert(false);
+ break;
+ }
+ break;
}
}
diff --git a/src/readDwarf.h b/src/readDwarf.h
index bf56377..5fba790 100644
--- a/src/readDwarf.h
+++ b/src/readDwarf.h
@@ -152,7 +152,7 @@ struct DWARF_InfoData
unsigned long encoding;
unsigned long pclo;
unsigned long pchi;
- unsigned long ranges;
+ unsigned long ranges; // -1u when attribute is not present
byte* type;
byte* containing_type;
byte* specification;
@@ -163,6 +163,10 @@ struct DWARF_InfoData
DWARF_Attribute frame_base;
long upper_bound;
long lower_bound;
+ bool has_lower_bound;
+ unsigned language;
+ unsigned long const_value;
+ bool has_const_value;
void clear()
{
@@ -180,7 +184,7 @@ struct DWARF_InfoData
encoding = 0;
pclo = 0;
pchi = 0;
- ranges = 0;
+ ranges = -1u;
type = 0;
containing_type = 0;
specification = 0;
@@ -191,6 +195,10 @@ struct DWARF_InfoData
frame_base.type = Invalid;
upper_bound = 0;
lower_bound = 0;
+ has_lower_bound = false;
+ language = 0;
+ const_value = 0;
+ has_const_value = false;
}
void merge(const DWARF_InfoData& id)
@@ -203,6 +211,7 @@ struct DWARF_InfoData
if (id.encoding) encoding = id.encoding;
if (id.pclo) pclo = id.pclo;
if (id.pchi) pchi = id.pchi;
+ if (id.ranges != -1u) ranges = id.ranges;
if (id.type) type = id.type;
if (id.containing_type) containing_type = id.containing_type;
if (id.specification) specification = id.specification;
@@ -292,14 +301,23 @@ struct DWARF_LineState
void addLineInfo()
{
+ unsigned long addr = address;
+
+ // The DWARF standard says about end_sequence: "indicating that the current
+ // address is that of the first byte after the end of a sequence of target
+ // machine instructions". So if this is a end_sequence row, make it apply
+ // to the last byte of the current sequence.
+ if (end_sequence)
+ addr = last_addr - 1;
+
#if 0
const char* fname = (file == 0 ? file_ptr->file_name : files[file - 1].file_name);
printf("Adr:%08x Line: %5d File: %s\n", address, line, fname);
#endif
- if (address < seg_offset)
+ if (addr < seg_offset)
return;
mspdb::LineInfoEntry entry;
- entry.offset = address - seg_offset;
+ entry.offset = addr - seg_offset;
entry.line = line;
lineInfo.push_back(entry);
}
diff --git a/src/symutil.cpp b/src/symutil.cpp
index 225235d..d159f30 100644
--- a/src/symutil.cpp
+++ b/src/symutil.cpp
@@ -268,6 +268,10 @@ int pstrcpy_v(bool v3, BYTE* d, const BYTE* s)
int cstrcpy_v(bool v3, BYTE* d, const char* s)
{
+ // Process absent names as empty ones
+ if (s == NULL)
+ s = "";
+
int len = strlen(s);
if(!v3)
{