Skip to content

Commit

Permalink
Support fully qualified names for enums
Browse files Browse the repository at this point in the history
This commit enables full support for enums in the following ways:

1) Enums now are also produced with fully-qualified names (such as those
   nested in classes, or namespaces). Thus two enums `Foo` in two
   classes can be uniquely examined in a debugger.
2) Fix the way in which we emit the underlying enum type in the PDB.
   Previously, we were emitting a "UDT reference" for almost all enum
   types, even "unsigned long", which it turns out Windows debuggers do
   not like. WinDbg crashes when encountering such a symbol in some
   cases, and Visual Studio Debugger fails to resolve the value.

   It turns out that the root cause here is that enums in a PDB must
   always use a "base type," never a UDT. To do this, I unwind the DIE
   type reference by walking its "type" chain until the last element,
   and produce a CV base type from the encoding and byte size of said
   record.

   E.g. for cases like enum Foo : size_t { ... }, we walk the size_t UDT
   reference and find, for example, an `unsigned long` UDT reference,
   and follow that, and ultimately find a base type with encoding
   `DW_ATE_unsigned` and byte size = 4, and generate a T_ULONG CV type
   for the enum.

Also, a minor improvement:

We now correctly indicate whether a structure is a class or struct,
instead of always emitting "struct" in the CV record.
  • Loading branch information
alexbudfb committed Mar 24, 2023
1 parent 186bfe2 commit b36951d
Showing 1 changed file with 41 additions and 10 deletions.
51 changes: 41 additions & 10 deletions src/dwarf2pdb.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1104,7 +1104,7 @@ int CV2PDB::addDWARFStructure(DWARF_InfoData& structid, DIECursor cursor)
char namebuf[kMaxNameLen] = {};
formatFullyQualifiedName(&structid, namebuf, sizeof namebuf);
int attr = fieldlistType ? 0 : kPropIncomplete;
int len = addAggregate(cvt, false, nfields, fieldlistType, attr, 0, 0, structid.byte_size, namebuf, nullptr);
int len = addAggregate(cvt, structid.tag == DW_TAG_class_type, nfields, fieldlistType, attr, 0, 0, structid.byte_size, namebuf, nullptr);
cbUserTypes += len;

//ensureUDT()?
Expand Down Expand Up @@ -1323,10 +1323,10 @@ int CV2PDB::addDWARFEnum(DWARF_InfoData& enumid, 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.
userTypes buffer.
2. One or several LF_FIELDLIST records, to contain the list of
enumerators (name and value) associated to the enum type
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,
Expand Down Expand Up @@ -1372,7 +1372,7 @@ int CV2PDB::addDWARFEnum(DWARF_InfoData& enumid, DIECursor cursor)
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. */
create a new LF_FIELDLIST record now. */
if (fieldlistLength + len + sizeof(dfieldtype->index_v2) > 0xffff)
{
/* Append the LF_INDEX leaf. */
Expand Down Expand Up @@ -1425,15 +1425,46 @@ int CV2PDB::addDWARFEnum(DWARF_InfoData& enumid, DIECursor cursor)

/* Now the LF_FIELDLIST is ready, create the LF_ENUM type record itself. */
checkUserTypeAlloc();
int basetype = (enumid.type != 0)
? getTypeByDWARFPtr(enumid.type)
: getDWARFBasicType(enumid.encoding, enumid.byte_size);
const DWARF_InfoData* entry = findEntryByPtr(enumid.entryPtr);
int prop = 0;
if (entry && entry->parent) {
int tag = entry->parent->tag;
if (tag == DW_TAG_class_type ||
tag == DW_TAG_structure_type ||
tag == DW_TAG_union_type)
{
prop |= kPropIsNested;
}
}

// NOTE: WinDbg/VS Dbg expects enum types to be base types, not indirect
// refs/UDTs.
//
// Compute the best base/underlying type to use.
int encoding = DW_ATE_signed; // default to int
const DWARF_InfoData* typeEntry = findEntryByPtr(enumid.type);
const DWARF_InfoData* t = typeEntry;

// Follow all the parent types to get to the base UDT.
while (t) {
t = findEntryByPtr(t->type);
if (t) typeEntry = t;
}

if (typeEntry) {
encoding = typeEntry->encoding;
assert(typeEntry->byte_size == enumid.byte_size);
}

const int basetype = getDWARFBasicType(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);
char namebuf[kMaxNameLen] = {};
formatFullyQualifiedName(&enumid, namebuf, sizeof namebuf);
cbUserTypes += addEnum(dtype, count, firstFieldlistType, prop, basetype, namebuf);
int enumType = nextUserType++;

addUdtSymbol(enumType, name);
addUdtSymbol(enumType, namebuf);
return enumType;
}

Expand Down

0 comments on commit b36951d

Please sign in to comment.