Skip to content

Commit

Permalink
Merge pull request #86 from alexbudfb/dwarftree
Browse files Browse the repository at this point in the history
Vastly Improved DWARF to PDB Support
  • Loading branch information
rainers authored Jun 10, 2023
2 parents d9b51b7 + a21b415 commit e076c74
Show file tree
Hide file tree
Showing 12 changed files with 806 additions and 185 deletions.
26 changes: 26 additions & 0 deletions src/NatvisFile.natvis
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
<Type Name="DWARF_InfoData">
<DisplayString>tag={tag} code={code} {name,s}</DisplayString>
<Expand>
<Synthetic Name="children" Condition="children">
<Expand>
<LinkedListItems>
<HeadPointer>children</HeadPointer>
<NextPointer>next</NextPointer>
<ValueNode>this</ValueNode>
</LinkedListItems>
</Expand>
</Synthetic>
<Synthetic Name="siblings" Condition="next">
<Expand>
<LinkedListItems>
<HeadPointer>next</HeadPointer>
<NextPointer>next</NextPointer>
<ValueNode>this</ValueNode>
</LinkedListItems>
</Expand>
</Synthetic>
</Expand>
</Type>
</AutoVisualizer>
6 changes: 6 additions & 0 deletions src/PEImage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,7 @@ bool PEImage::_initFromCVDebugDir(IMAGE_DEBUG_DIRECTORY* ddir)
}

///////////////////////////////////////////////////////////////////////
// Used for PE (EXE/DLL) files.
bool PEImage::initDWARFPtr(bool initDbgDir)
{
dos = DPV<IMAGE_DOS_HEADER> (0);
Expand Down Expand Up @@ -410,6 +411,7 @@ bool PEImage::initDWARFPtr(bool initDbgDir)
return true;
}

// Used for COFF objects.
bool PEImage::initDWARFObject()
{
IMAGE_FILE_HEADER* hdr = DPV<IMAGE_FILE_HEADER> (0);
Expand Down Expand Up @@ -466,8 +468,11 @@ void PEImage::initSec(PESection& peSec, int secNo) const
peSec.secNo = secNo;
}

// Initialize all the DWARF sections present in this PE or COFF file.
// Common to both object and image modules.
void PEImage::initDWARFSegments()
{
// Scan all the PE sections in this image.
for(int s = 0; s < nsec; s++)
{
const char* name = (const char*) sec[s].Name;
Expand All @@ -477,6 +482,7 @@ void PEImage::initDWARFSegments()
name = strtable + off;
}

// Is 'name' one of the DWARF sections?
for (const SectionDescriptor *sec_desc : sec_descriptors) {
if (!strcmp(name, sec_desc->name)) {
PESection& peSec = this->*(sec_desc->pSec);
Expand Down
10 changes: 8 additions & 2 deletions src/PEImage.h
Original file line number Diff line number Diff line change
Expand Up @@ -178,11 +178,16 @@ class PEImage : public LastError

template<typename SYM> const char* t_findSectionSymbolName(int s) const;

// File handle to PE image.
int fd;

// Pointer to in-memory buffer containing loaded PE image.
void* dump_base;

// Size of `dump_base` in bytes.
int dump_total_len;

// codeview
// codeview fields
IMAGE_DOS_HEADER *dos;
IMAGE_NT_HEADERS32* hdr32;
IMAGE_NT_HEADERS64* hdr64;
Expand All @@ -200,7 +205,8 @@ class PEImage : public LastError
std::unordered_map<std::string, SymbolInfo> symbolCache;

public:
//dwarf
// dwarf fields
// List of DWARF section descriptors.
#define EXPANDSEC(name) PESection name;
SECTION_LIST()
#undef EXPANDSEC
Expand Down
64 changes: 36 additions & 28 deletions src/cv2pdb.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,6 @@ CV2PDB::CV2PDB(PEImage& image, DebugLevel debug_)
memset(typedefs, 0, sizeof(typedefs));
memset(translatedTypedefs, 0, sizeof(translatedTypedefs));
cntTypedefs = 0;
nextUserType = 0x1000;
nextDwarfType = 0x1000;

addClassTypeEnum = true;
addObjectViewHelper = true;
Expand Down Expand Up @@ -899,25 +897,28 @@ void CV2PDB::checkGlobalTypeAlloc(int size, int add)
}
}

// Get the CodeView type descriptor for the given type ID.
// CV-only. Returns NULL for DWARF-based images.
const codeview_type* CV2PDB::getTypeData(int type)
{
if (!globalTypeHeader)
if (!globalTypeHeader) // NULL for DWARF.
return 0;
if (type < 0x1000 || type >= (int) (0x1000 + globalTypeHeader->cTypes + nextUserType))
if (type < BASE_USER_TYPE || type >= (int) (BASE_USER_TYPE + globalTypeHeader->cTypes + nextUserType))
return 0;
if (type >= (int) (0x1000 + globalTypeHeader->cTypes))
if (type >= (int) (BASE_USER_TYPE + globalTypeHeader->cTypes))
return getUserTypeData(type);

DWORD* offset = (DWORD*)(globalTypeHeader + 1);
BYTE* typeData = (BYTE*)(offset + globalTypeHeader->cTypes);

return (codeview_type*)(typeData + offset[type - 0x1000]);
return (codeview_type*)(typeData + offset[type - BASE_USER_TYPE]);
}

// CV-only. Never called for DWARF.
const codeview_type* CV2PDB::getUserTypeData(int type)
{
type -= 0x1000 + globalTypeHeader->cTypes;
if (type < 0 || type >= nextUserType - 0x1000)
type -= BASE_USER_TYPE + globalTypeHeader->cTypes;
if (type < 0 || type >= nextUserType - BASE_USER_TYPE)
return 0;

int pos = 0;
Expand All @@ -933,8 +934,8 @@ const codeview_type* CV2PDB::getUserTypeData(int type)

const codeview_type* CV2PDB::getConvertedTypeData(int type)
{
type -= 0x1000;
if (type < 0 || type >= nextUserType - 0x1000)
type -= BASE_USER_TYPE;
if (type < 0 || type >= nextUserType - BASE_USER_TYPE)
return 0;

int pos = typePrefix;
Expand Down Expand Up @@ -1013,7 +1014,7 @@ int CV2PDB::findMemberFunctionType(codeview_symbol* lastGProcSym, int thisPtrTyp
type->mfunction_v1.call == proctype->procedure_v1.call &&
type->mfunction_v1.rvtype == proctype->procedure_v1.rvtype)
{
return t + 0x1000;
return t + BASE_USER_TYPE;
}
}
}
Expand Down Expand Up @@ -1123,7 +1124,7 @@ int CV2PDB::sizeofBasicType(int type)

int CV2PDB::sizeofType(int type)
{
if (type < 0x1000)
if (type < BASE_USER_TYPE)
return sizeofBasicType(type);

const codeview_type* cvtype = getTypeData(type);
Expand All @@ -1144,11 +1145,14 @@ int CV2PDB::sizeofType(int type)
// to be used when writing new type only to avoid double translation
int CV2PDB::translateType(int type)
{
if (type < 0x1000)
if (type < BASE_USER_TYPE)
{
// Check D lang typedefs.
for(int i = 0; i < cntTypedefs; i++)
if(type == typedefs[i])
return translatedTypedefs[i];

// Return original type.
return type;
}

Expand Down Expand Up @@ -1279,7 +1283,7 @@ bool CV2PDB::nameOfModifierType(int type, int mod, char* name, int maxlen)

bool CV2PDB::nameOfType(int type, char* name, int maxlen)
{
if(type < 0x1000)
if(type < BASE_USER_TYPE)
return nameOfBasicType(type, name, maxlen);

const codeview_type* ptype = getTypeData(type);
Expand Down Expand Up @@ -2032,7 +2036,7 @@ void CV2PDB::ensureUDT(int type, const codeview_type* cvtype)
if (getStructProperty(cvtype) & kPropIncomplete)
cvtype = findCompleteClassType(cvtype, &type);

if(findUdtSymbol(type + 0x1000))
if(findUdtSymbol(type + BASE_USER_TYPE))
return;

char name[kMaxNameLen];
Expand All @@ -2054,9 +2058,9 @@ void CV2PDB::ensureUDT(int type, const codeview_type* cvtype)
int viewHelperType = nextUserType++;
// addUdtSymbol(viewHelperType, "object_viewhelper");
addUdtSymbol(viewHelperType, name);
} else {
addUdtSymbol(type + BASE_USER_TYPE, name);
}
else
addUdtSymbol(type + 0x1000, name);
}

int CV2PDB::createEmptyFieldListType()
Expand Down Expand Up @@ -2114,6 +2118,7 @@ int CV2PDB::appendTypedef(int type, const char* name, bool saveTranslation)
return typedefType;
}

// CV-only.
void CV2PDB::appendTypedefs()
{
if(Dversion == 0)
Expand All @@ -2135,6 +2140,7 @@ void CV2PDB::appendTypedefs()
appendComplex(0x52, 0x42, 10, "creal");
}

// CV-only.
bool CV2PDB::initGlobalTypes()
{
int object_derived_type = 0;
Expand All @@ -2160,7 +2166,7 @@ bool CV2PDB::initGlobalTypes()
*(DWORD*) globalTypes = 4;
cbGlobalTypes = typePrefix;

nextUserType = globalTypeHeader->cTypes + 0x1000;
nextUserType = globalTypeHeader->cTypes + BASE_USER_TYPE;

appendTypedefs();
if(Dversion > 0)
Expand Down Expand Up @@ -2277,7 +2283,7 @@ bool CV2PDB::initGlobalTypes()
if(const codeview_type* td = getTypeData(type->struct_v1.fieldlist))
if(td->generic.id == LF_FIELDLIST_V1 || td->generic.id == LF_FIELDLIST_V2)
dtype->struct_v2.n_element = countFields((const codeview_reftype*)td);
dtype->struct_v2.property = fixProperty(t + 0x1000, type->struct_v1.property,
dtype->struct_v2.property = fixProperty(t + BASE_USER_TYPE, type->struct_v1.property,
type->struct_v1.fieldlist);
#if REMOVE_LF_DERIVED
dtype->struct_v2.derived = 0;
Expand Down Expand Up @@ -2308,7 +2314,7 @@ bool CV2PDB::initGlobalTypes()
dtype->union_v2.id = v3 ? LF_UNION_V3 : LF_UNION_V2;
dtype->union_v2.count = type->union_v1.count;
dtype->union_v2.fieldlist = type->struct_v1.fieldlist;
dtype->union_v2.property = fixProperty(t + 0x1000, type->struct_v1.property, type->struct_v1.fieldlist);
dtype->union_v2.property = fixProperty(t + BASE_USER_TYPE, type->struct_v1.property, type->struct_v1.fieldlist);
leaf_len = numeric_leaf(&value, &type->union_v1.un_len);
memcpy (&dtype->union_v2.un_len, &type->union_v1.un_len, leaf_len);
len = pstrcpy_v(v3, (BYTE*) &dtype->union_v2.un_len + leaf_len,
Expand Down Expand Up @@ -2349,10 +2355,10 @@ bool CV2PDB::initGlobalTypes()
dtype->mfunction_v2.rvtype = translateType(type->mfunction_v1.rvtype);
clsstype = type->mfunction_v1.class_type;
dtype->mfunction_v2.class_type = translateType(clsstype);
if (clsstype >= 0x1000 && clsstype < 0x1000 + globalTypeHeader->cTypes)
if (clsstype >= BASE_USER_TYPE && clsstype < BASE_USER_TYPE + globalTypeHeader->cTypes)
{
// fix class_type to point to class, not pointer to class
codeview_type* ctype = (codeview_type*)(typeData + offset[clsstype - 0x1000]);
codeview_type* ctype = (codeview_type*)(typeData + offset[clsstype - BASE_USER_TYPE]);
if (ctype->generic.id == LF_POINTER_V1)
dtype->mfunction_v2.class_type = translateType(ctype->pointer_v1.datatype);
}
Expand All @@ -2370,12 +2376,12 @@ bool CV2PDB::initGlobalTypes()
dtype->enumeration_v2.count = type->enumeration_v1.count;
dtype->enumeration_v2.type = translateType(type->enumeration_v1.type);
dtype->enumeration_v2.fieldlist = type->enumeration_v1.fieldlist;
dtype->enumeration_v2.property = fixProperty(t + 0x1000, type->enumeration_v1.property, type->enumeration_v1.fieldlist);
dtype->enumeration_v2.property = fixProperty(t + BASE_USER_TYPE, type->enumeration_v1.property, type->enumeration_v1.fieldlist);
len = pstrcpy_v (v3, (BYTE*) &dtype->enumeration_v2.p_name, (BYTE*) &type->enumeration_v1.p_name);
len += sizeof(dtype->enumeration_v2) - sizeof(dtype->enumeration_v2.p_name);
if(dtype->enumeration_v2.fieldlist && v3)
if(!findUdtSymbol(t + 0x1000))
addUdtSymbol(t + 0x1000, (char*) &dtype->enumeration_v2.p_name);
if(!findUdtSymbol(t + BASE_USER_TYPE))
addUdtSymbol(t + BASE_USER_TYPE, (char*) &dtype->enumeration_v2.p_name);
break;

case LF_FIELDLIST_V1:
Expand All @@ -2392,7 +2398,7 @@ bool CV2PDB::initGlobalTypes()
rdtype->derived_v2.id = LF_DERIVED_V2;
rdtype->derived_v2.num = rtype->derived_v1.num;
for (int i = 0; i < rtype->derived_v1.num; i++)
if (rtype->derived_v1.drvdcls[i] < 0x1000) // + globalTypeHeader->cTypes)
if (rtype->derived_v1.drvdcls[i] < BASE_USER_TYPE) // + globalTypeHeader->cTypes)
rdtype->derived_v2.drvdcls[i] = translateType(rtype->derived_v1.drvdcls[i] + 0xfff);
else
rdtype->derived_v2.drvdcls[i] = translateType(rtype->derived_v1.drvdcls[i]);
Expand Down Expand Up @@ -3166,8 +3172,8 @@ int CV2PDB::copySymbols(BYTE* srcSymbols, int srcSize, BYTE* destSymbols, int de
codeview_symbol* dsym = (codeview_symbol*)(destSymbols + destSize);
memcpy(dsym, sym, length);
#endif
if (type >= 0x1000 && pointerTypes[type - 0x1000])
type = pointerTypes[type - 0x1000];
if (type >= BASE_USER_TYPE && pointerTypes[type - BASE_USER_TYPE])
type = pointerTypes[type - BASE_USER_TYPE];
}
}
dsym->stack_v2.id = v3 ? S_BPREL_V3 : S_BPREL_V1;
Expand Down Expand Up @@ -3279,6 +3285,8 @@ bool isUDTid(int id)
return id == S_UDT_V1 || id == S_UDT_V2 || id == S_UDT_V3;
}

// Find a user-defined type CV symbol.
// CV-only.
codeview_symbol* CV2PDB::findUdtSymbol(int type)
{
type = translateType(type);
Expand Down
38 changes: 30 additions & 8 deletions src/cv2pdb.h
Original file line number Diff line number Diff line change
Expand Up @@ -169,17 +169,24 @@ class CV2PDB : public LastError
bool addDWARFLines();
bool addDWARFPublics();
bool writeDWARFImage(const TCHAR* opath);
DWARF_InfoData* findEntryByPtr(byte* entryPtr) const;

// Helper to just print the DWARF tree we've built for debugging purposes.
void dumpDwarfTree() const;

bool addDWARFSectionContrib(mspdb::Mod* mod, unsigned long pclo, unsigned long pchi);
bool addDWARFProc(DWARF_InfoData& id, const std::vector<RangeEntry> &ranges, DIECursor cursor);
void formatFullyQualifiedName(const DWARF_InfoData* node, char* buf, size_t cbBuf) const;

int addDWARFStructure(DWARF_InfoData& id, DIECursor cursor);
int addDWARFFields(DWARF_InfoData& structid, DIECursor cursor, int off, int flStart);
int addDWARFArray(DWARF_InfoData& arrayid, DIECursor cursor);
int addDWARFFields(DWARF_InfoData& structid, DIECursor& cursor, int off, int flStart);
int addDWARFArray(DWARF_InfoData& arrayid, const DIECursor& cursor);
int addDWARFBasicType(const char*name, int encoding, int byte_size);
int addDWARFEnum(DWARF_InfoData& enumid, DIECursor cursor);
int getTypeByDWARFPtr(byte* ptr);
int getTypeByDWARFPtr(byte* typePtr);
int findTypeIdByPtr(byte* typePtr) const;
int getDWARFTypeSize(const DIECursor& parent, byte* ptr);
void getDWARFArrayBounds(DWARF_InfoData& arrayid, DIECursor cursor,
void getDWARFArrayBounds(DIECursor cursor,
int& basetype, int& lowerBound, int& upperBound);
void getDWARFSubrangeInfo(DWARF_InfoData& subrangeid, const DIECursor& parent,
int& basetype, int& lowerBound, int& upperBound);
Expand Down Expand Up @@ -211,6 +218,7 @@ class CV2PDB : public LastError
OMFSegMapDesc* segMapDesc;
int* segFrame2Index;

// CV-only
OMFGlobalTypes* globalTypeHeader;

unsigned char* globalTypes;
Expand All @@ -236,8 +244,10 @@ class CV2PDB : public LastError
int cbDwarfTypes;
int allocDwarfTypes;

int nextUserType;
int nextDwarfType;
static constexpr int BASE_USER_TYPE = 0x1000;

int nextUserType = BASE_USER_TYPE;
int nextDwarfType = BASE_USER_TYPE;
int objectType;

int emptyFieldListType;
Expand Down Expand Up @@ -272,9 +282,21 @@ class CV2PDB : public LastError

double Dversion;

// DWARF
// DWARF fields.

int codeSegOff;
std::unordered_map<byte*, int> mapOffsetToType;

// Lookup table for type IDs based on the DWARF_InfoData::entryPtr
std::unordered_map<byte*, int> mapEntryPtrToTypeID;

// Lookup table for entries based on the DWARF_InfoData::entryPtr
std::unordered_map<byte*, DWARF_InfoData*> mapEntryPtrToEntry;

// A multimap keyed on entry name. Since this is not unique, we use a multimap.
std::multimap<std::string, DWARF_InfoData*> mapEntryNameToEntries;

// Head of list of DWARF DIE nodes.
DWARF_InfoData* dwarfHead = nullptr;

// Default lower bound for the current compilation unit. This depends on
// the language of the current unit.
Expand Down
Loading

0 comments on commit e076c74

Please sign in to comment.