-
Notifications
You must be signed in to change notification settings - Fork 15.3k
[lldb] Index static const members of classes, structs and unions as global variables in DWARF 4 and earlier #111859
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 4 commits
4c394ec
8f7c944
e34cd8f
86390ef
dd67524
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -219,6 +219,7 @@ void ManualDWARFIndex::IndexUnitImpl(DWARFUnit &unit, | |||||||||||||||||||||||||||||||||
| case DW_TAG_typedef: | ||||||||||||||||||||||||||||||||||
| case DW_TAG_union_type: | ||||||||||||||||||||||||||||||||||
| case DW_TAG_unspecified_type: | ||||||||||||||||||||||||||||||||||
| case DW_TAG_member: | ||||||||||||||||||||||||||||||||||
| case DW_TAG_variable: | ||||||||||||||||||||||||||||||||||
| break; | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
|
|
@@ -228,6 +229,7 @@ void ManualDWARFIndex::IndexUnitImpl(DWARFUnit &unit, | |||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| const char *name = nullptr; | ||||||||||||||||||||||||||||||||||
| const char *mangled_cstr = nullptr; | ||||||||||||||||||||||||||||||||||
| bool is_external = false; | ||||||||||||||||||||||||||||||||||
| bool is_declaration = false; | ||||||||||||||||||||||||||||||||||
| bool has_address = false; | ||||||||||||||||||||||||||||||||||
| bool has_location_or_const_value = false; | ||||||||||||||||||||||||||||||||||
|
|
@@ -246,6 +248,11 @@ void ManualDWARFIndex::IndexUnitImpl(DWARFUnit &unit, | |||||||||||||||||||||||||||||||||
| name = form_value.AsCString(); | ||||||||||||||||||||||||||||||||||
| break; | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| case DW_AT_external: | ||||||||||||||||||||||||||||||||||
| if (attributes.ExtractFormValueAtIndex(i, form_value)) | ||||||||||||||||||||||||||||||||||
| is_external = form_value.Unsigned() != 0; | ||||||||||||||||||||||||||||||||||
| break; | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| case DW_AT_declaration: | ||||||||||||||||||||||||||||||||||
| if (attributes.ExtractFormValueAtIndex(i, form_value)) | ||||||||||||||||||||||||||||||||||
| is_declaration = form_value.Unsigned() != 0; | ||||||||||||||||||||||||||||||||||
|
|
@@ -362,6 +369,23 @@ void ManualDWARFIndex::IndexUnitImpl(DWARFUnit &unit, | |||||||||||||||||||||||||||||||||
| set.namespaces.Insert(ConstString(name), ref); | ||||||||||||||||||||||||||||||||||
| break; | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| case DW_TAG_member: { | ||||||||||||||||||||||||||||||||||
| // In DWARF 4 and earlier `static const` members of a struct, a class or a | ||||||||||||||||||||||||||||||||||
| // union have an entry tag `DW_TAG_member`, and are also tagged as | ||||||||||||||||||||||||||||||||||
| // `DW_AT_external` and `DW_AT_declaration`, but otherwise follow the | ||||||||||||||||||||||||||||||||||
| // same rules as `DW_TAG_variable`. | ||||||||||||||||||||||||||||||||||
| if (unit.GetVersion() >= 5) | ||||||||||||||||||||||||||||||||||
| break; | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
| bool parent_is_class_type = false; | ||||||||||||||||||||||||||||||||||
| if (auto parent = die.GetParent()) { | ||||||||||||||||||||||||||||||||||
| parent_is_class_type = parent->Tag() == DW_TAG_structure_type || | ||||||||||||||||||||||||||||||||||
| parent->Tag() == DW_TAG_class_type || | ||||||||||||||||||||||||||||||||||
| parent->Tag() == DW_TAG_union_type; | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
| bool parent_is_class_type = false; | |
| if (auto parent = die.GetParent()) { | |
| parent_is_class_type = parent->Tag() == DW_TAG_structure_type || | |
| parent->Tag() == DW_TAG_class_type || | |
| parent->Tag() == DW_TAG_union_type; | |
| } | |
| bool parent_is_class_type = false; | |
| if (auto parent = die.GetParent()) | |
| parent_is_class_type = DWARFDIE(&unit, parent).IsStructUnionOrClass(); |
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wanted to note that we have this block here in DWARFASTParserClang.cpp:
llvm-project/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
Lines 2824 to 2839 in d2e7ee7
| // Handle static members, which are typically members without | |
| // locations. However, GCC doesn't emit DW_AT_data_member_location | |
| // for any union members (regardless of linkage). | |
| // Non-normative text pre-DWARFv5 recommends marking static | |
| // data members with an DW_AT_external flag. Clang emits this consistently | |
| // whereas GCC emits it only for static data members if not part of an | |
| // anonymous namespace. The flag that is consistently emitted for static | |
| // data members is DW_AT_declaration, so we check it instead. | |
| // The following block is only necessary to support DWARFv4 and earlier. | |
| // Starting with DWARFv5, static data members are marked DW_AT_variable so we | |
| // can consistently detect them on both GCC and Clang without below heuristic. | |
| if (attrs.member_byte_offset == UINT32_MAX && | |
| attrs.data_bit_offset == UINT64_MAX && attrs.is_declaration) { | |
| CreateStaticMemberVariable(die, attrs, class_clang_type); | |
| return; | |
| } |
Which describes an edge-case with how GCC emits static data members (i.e., it doesn't consistently emit the DW_AT_external flag). Not sure we want to account for that, but also, it would be nice if we had a single place where we did the "isPreDWARFv5StaticDataMember` check. But feel free to ignore
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good finding. I think it would be good to match whatever that code does. (making it a single function for it would be somewhat tricky, as the code here needs to be very fast, so we don't want to have the helper function do another lookup for the attributes and stuff).
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2402,8 +2402,10 @@ void SymbolFileDWARF::FindGlobalVariables( | |
| sc.module_sp = m_objfile_sp->GetModule(); | ||
| assert(sc.module_sp); | ||
|
|
||
| if (die.Tag() != DW_TAG_variable) | ||
| if (die.Tag() != DW_TAG_variable && die.Tag() != DW_TAG_member) | ||
| return true; | ||
| assert( | ||
| !die.GetAttributeValueAsOptionalUnsigned(DW_AT_data_member_location)); | ||
|
|
||
| auto *dwarf_cu = llvm::dyn_cast<DWARFCompileUnit>(die.GetCU()); | ||
| if (!dwarf_cu) | ||
|
|
@@ -3490,8 +3492,9 @@ VariableSP SymbolFileDWARF::ParseVariableDIE(const SymbolContext &sc, | |
| ModuleSP module = GetObjectFile()->GetModule(); | ||
|
|
||
| if (tag != DW_TAG_variable && tag != DW_TAG_constant && | ||
| (tag != DW_TAG_formal_parameter || !sc.function)) | ||
| tag != DW_TAG_member && (tag != DW_TAG_formal_parameter || !sc.function)) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we bail out (or at least assert) if we detect a
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added an assert, but maybe I should just add that as a condition for detecting a
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think that should be an assert unless some piece of code (where?) alredy makes sure that these kinds of DIEs don't make their way here. Debug info can come from all kinds of compilers (including those from the past and the future), so we shouldn't be crashing just because we've ran into debug info (aka "user input") that we don't understand. Logging something or reporting a warning might be more appropriate. Checking for this member when detecting a static const member might be okay, but it doesn't really count as the check I mention above, since it only works for the manual index. The other indexes come straight from the compiler (past, future, etc.) so they can't be relied upon in the same way. For this reason (and because we want to make the indexing step as fast as possible), I'd put the check into the indexing step only if it's necessary to properly detect static members. |
||
| return nullptr; | ||
| assert(!die.GetAttributeValueAsOptionalUnsigned(DW_AT_data_member_location)); | ||
|
|
||
| DWARFAttributes attributes = die.GetAttributes(); | ||
| const char *name = nullptr; | ||
|
|
@@ -3796,8 +3799,9 @@ void SymbolFileDWARF::ParseAndAppendGlobalVariable( | |
| return; | ||
|
|
||
| dw_tag_t tag = die.Tag(); | ||
| if (tag != DW_TAG_variable && tag != DW_TAG_constant) | ||
| if (tag != DW_TAG_variable && tag != DW_TAG_constant && tag != DW_TAG_member) | ||
| return; | ||
| assert(!die.GetAttributeValueAsOptionalUnsigned(DW_AT_data_member_location)); | ||
|
|
||
| // Check to see if we have already parsed this variable or constant? | ||
| VariableSP var_sp = GetDIEToVariable()[die.GetDIE()]; | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.