diff options
author | Alex Budovski <alexbud@meta.com> | 2023-03-23 23:36:52 (GMT) |
---|---|---|
committer | Alex Budovski <alexbud@meta.com> | 2023-03-24 15:43:34 (GMT) |
commit | b36951d9b0c9a9b69784cde6342926ee4a7d0381 (patch) | |
tree | 6c163498379cfb6d157a0eca088bf8a6710b3e31 | |
parent | 186bfe29adc6875fd26107a18ab1bb257cbd9dec (diff) | |
download | cv2pdb-b36951d9b0c9a9b69784cde6342926ee4a7d0381.zip cv2pdb-b36951d9b0c9a9b69784cde6342926ee4a7d0381.tar.gz cv2pdb-b36951d9b0c9a9b69784cde6342926ee4a7d0381.tar.bz2 |
Support fully qualified names for enums
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.
-rw-r--r-- | src/dwarf2pdb.cpp | 51 |
1 files changed, 41 insertions, 10 deletions
diff --git a/src/dwarf2pdb.cpp b/src/dwarf2pdb.cpp index c88768e..b65d73d 100644 --- a/src/dwarf2pdb.cpp +++ b/src/dwarf2pdb.cpp @@ -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()?
@@ -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,
@@ -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. */
@@ -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;
}
|