From 57893202f1849d6e49e3ae88ca6202c18713b775 Mon Sep 17 00:00:00 2001 From: Rene Gollent Date: Tue, 7 Aug 2018 22:15:02 -0400 Subject: [PATCH] Debugger: Fix #14321. DIESubprogram: - Adjust to inherit from DIENamespace, as gcc can and will use it as a container in some circumstances. DIEClassBaseType: - Add accessor for member functions. DwarfImageDebugInfo: - Adjust recursive walking for types to take into account any DIENamespace, not just DW_TAG_namespace specifically. - Factor out adding function to list into a helper. - When retrieving the list of functions, perform a similar recursive walk as is done when building the types table, as some subprograms are apparently not always added to the root compilation unit entry. Curiously, this behavior seems to be relatively specific to a struct/class type declared inside a function in GCC's case, but based on the DWARF spec, there does not appear to be any specific restriction as far as where these can be nested, so be a bit more paranoid to ensure we don't encounter similar cases in the future. --- .../debug_info/DwarfImageDebugInfo.cpp | 241 +++++++++++------- .../debugger/debug_info/DwarfImageDebugInfo.h | 9 + src/kits/debugger/dwarf/DebugInfoEntries.cpp | 63 ++--- src/kits/debugger/dwarf/DebugInfoEntries.h | 48 ++-- 4 files changed, 210 insertions(+), 151 deletions(-) diff --git a/src/kits/debugger/debug_info/DwarfImageDebugInfo.cpp b/src/kits/debugger/debug_info/DwarfImageDebugInfo.cpp index 084cf2ac5c..46d515c070 100644 --- a/src/kits/debugger/debug_info/DwarfImageDebugInfo.cpp +++ b/src/kits/debugger/debug_info/DwarfImageDebugInfo.cpp @@ -409,6 +409,7 @@ DwarfImageDebugInfo::GetFunctions(const BObjectList& symbols, TRACE_IMAGES(" %" B_PRId32 " compilation units\n", fFile->CountCompilationUnits()); + status_t error = B_OK; for (int32 i = 0; CompilationUnit* unit = fFile->CompilationUnitAt(i); i++) { DIECompileUnitBase* unitEntry = unit->UnitEntry(); @@ -430,86 +431,21 @@ DwarfImageDebugInfo::GetFunctions(const BObjectList& symbols, for (DebugInfoEntryList::ConstIterator it = unitEntry->OtherChildren().GetIterator(); DebugInfoEntry* entry = it.Next();) { - if (entry->Tag() != DW_TAG_subprogram) - continue; - - DIESubprogram* subprogramEntry = static_cast(entry); - - // ignore declarations and inlined functions - if (subprogramEntry->IsDeclaration() - || subprogramEntry->Inline() == DW_INL_inlined - || subprogramEntry->Inline() == DW_INL_declared_inlined) { - continue; + if (entry->Tag() == DW_TAG_subprogram) { + DIESubprogram* subprogramEntry + = static_cast(entry); + error = _AddFunction(subprogramEntry, unit, functions); + if (error != B_OK) + return error; } - // get the name - BString name; - DwarfUtils::GetFullyQualifiedDIEName(subprogramEntry, name); - if (name.Length() == 0) - continue; - - // get the address ranges - TargetAddressRangeList* rangeList = fFile->ResolveRangeList(unit, - subprogramEntry->AddressRangesOffset()); - if (rangeList == NULL) { - target_addr_t lowPC = subprogramEntry->LowPC(); - target_addr_t highPC = subprogramEntry->HighPC(); - if (highPC <= lowPC) - continue; - - rangeList = new(std::nothrow) TargetAddressRangeList( - TargetAddressRange(lowPC, highPC - lowPC)); - if (rangeList == NULL) - return B_NO_MEMORY; - // TODO: Clean up already added functions! + DIENamespace* nsEntry = dynamic_cast(entry); + if (nsEntry != NULL) { + error = _RecursiveTraverseNamespaceForFunctions(nsEntry, unit, + functions); + if (error != B_OK) + return error; } - BReference rangeListReference(rangeList, - true); - - // get the source location - const char* directoryPath = NULL; - const char* fileName = NULL; - int32 line = -1; - int32 column = -1; - DwarfUtils::GetDeclarationLocation(fFile, subprogramEntry, - directoryPath, fileName, line, column); - - LocatableFile* file = NULL; - if (fileName != NULL) { - file = fFileManager->GetSourceFile(directoryPath, - fileName); - } - BReference fileReference(file, true); - - // create and add the functions - DwarfFunctionDebugInfo* function - = new(std::nothrow) DwarfFunctionDebugInfo(this, unit, - subprogramEntry, rangeList, name, file, - SourceLocation(line, std::max(column, (int32)0))); - if (function == NULL || !functions.AddItem(function)) { - delete function; - return B_NO_MEMORY; - // TODO: Clean up already added functions! - } - -// BString name; -// DwarfUtils::GetFullyQualifiedDIEName(subprogramEntry, name); -// printf(" subprogram entry: %p, name: %s, declaration: %d\n", -// subprogramEntry, name.String(), -// subprogramEntry->IsDeclaration()); -// -// rangeList = subprogramEntry->AddressRanges(); -// if (rangeList != NULL) { -// int32 count = rangeList->CountRanges(); -// for (int32 i = 0; i < count; i++) { -// TargetAddressRange range = rangeList->RangeAt(i); -// printf(" %#llx - %#llx\n", range.Start(), range.End()); -// } -// } else { -// printf(" %#llx - %#llx\n", -// (target_addr_t)subprogramEntry->LowPC(), -// (target_addr_t)subprogramEntry->HighPC()); -// } } } @@ -1383,6 +1319,114 @@ DwarfImageDebugInfo::_EvaluateBaseTypeConstraints(DIEType* type, } +status_t +DwarfImageDebugInfo::_RecursiveTraverseNamespaceForFunctions( + DIENamespace* nsEntry, CompilationUnit* unit, + BObjectList& functions) +{ + status_t error = B_OK; + for (DebugInfoEntryList::ConstIterator it + = nsEntry->Children().GetIterator(); + DebugInfoEntry* entry = it.Next();) { + if (entry->Tag() == DW_TAG_subprogram) { + DIESubprogram* subprogramEntry + = static_cast(entry); + error = _AddFunction(subprogramEntry, unit, functions); + if (error != B_OK) + return error; + } + + DIENamespace* nsEntry = dynamic_cast(entry); + if (nsEntry != NULL) { + error = _RecursiveTraverseNamespaceForFunctions(nsEntry, unit, + functions); + if (error != B_OK) + return error; + continue; + } + + DIEClassBaseType* classEntry = dynamic_cast(entry); + if (classEntry != NULL) { + for (DebugInfoEntryList::ConstIterator it + = classEntry->MemberFunctions().GetIterator(); + DebugInfoEntry* memberEntry = it.Next();) { + error = _AddFunction(static_cast(memberEntry), + unit, functions); + if (error != B_OK) + return error; + } + } + } + + return B_OK; +} + + +status_t +DwarfImageDebugInfo::_AddFunction(DIESubprogram* subprogramEntry, + CompilationUnit* unit, BObjectList& functions) +{ + // ignore declarations and inlined functions + if (subprogramEntry->IsDeclaration() + || subprogramEntry->Inline() == DW_INL_inlined + || subprogramEntry->Inline() == DW_INL_declared_inlined) { + return B_OK; + } + + // get the name + BString name; + DwarfUtils::GetFullyQualifiedDIEName(subprogramEntry, name); + if (name.Length() == 0) + return B_OK; + + // get the address ranges + TargetAddressRangeList* rangeList = fFile->ResolveRangeList(unit, + subprogramEntry->AddressRangesOffset()); + if (rangeList == NULL) { + target_addr_t lowPC = subprogramEntry->LowPC(); + target_addr_t highPC = subprogramEntry->HighPC(); + if (highPC <= lowPC) + return B_OK; + + rangeList = new(std::nothrow) TargetAddressRangeList( + TargetAddressRange(lowPC, highPC - lowPC)); + if (rangeList == NULL) + return B_NO_MEMORY; + // TODO: Clean up already added functions! + } + BReference rangeListReference(rangeList, + true); + + // get the source location + const char* directoryPath = NULL; + const char* fileName = NULL; + int32 line = -1; + int32 column = -1; + DwarfUtils::GetDeclarationLocation(fFile, subprogramEntry, + directoryPath, fileName, line, column); + + LocatableFile* file = NULL; + if (fileName != NULL) { + file = fFileManager->GetSourceFile(directoryPath, + fileName); + } + BReference fileReference(file, true); + + // create and add the functions + DwarfFunctionDebugInfo* function + = new(std::nothrow) DwarfFunctionDebugInfo(this, unit, + subprogramEntry, rangeList, name, file, + SourceLocation(line, std::max(column, (int32)0))); + if (function == NULL || !functions.AddItem(function)) { + delete function; + return B_NO_MEMORY; + // TODO: Clean up already added functions! + } + + return B_OK; +} + + status_t DwarfImageDebugInfo::_BuildTypeNameTable() { @@ -1409,10 +1453,10 @@ DwarfImageDebugInfo::_BuildTypeNameTable() for (DebugInfoEntryList::ConstIterator it = unit->UnitEntry()->OtherChildren().GetIterator(); DebugInfoEntry* child = it.Next();) { - if (child->Tag() != DW_TAG_namespace) + DIENamespace* namespaceEntry = dynamic_cast(child); + if (namespaceEntry == NULL) continue; - DIENamespace* namespaceEntry = dynamic_cast(child); if (_RecursiveTraverseNamespaceForTypes(namespaceEntry, unit) != B_OK) { return B_NO_MEMORY; @@ -1455,14 +1499,15 @@ DwarfImageDebugInfo::_RecursiveAddTypeNames(DIEType* type, CompilationUnit* unit } DIEClassBaseType* classType = dynamic_cast(type); - if (classType != NULL) { - for (DebugInfoEntryList::ConstIterator it - = classType->InnerTypes().GetIterator(); - DIEType* innerType = dynamic_cast(it.Next());) { - error = _RecursiveAddTypeNames(innerType, unit); - if (error != B_OK) - return error; - } + if (classType == NULL) + return B_OK; + + for (DebugInfoEntryList::ConstIterator it + = classType->InnerTypes().GetIterator(); + DIEType* innerType = dynamic_cast(it.Next());) { + error = _RecursiveAddTypeNames(innerType, unit); + if (error != B_OK) + return error; } return B_OK; @@ -1476,20 +1521,22 @@ DwarfImageDebugInfo::_RecursiveTraverseNamespaceForTypes(DIENamespace* nsEntry, for (DebugInfoEntryList::ConstIterator it = nsEntry->Children().GetIterator(); DebugInfoEntry* child = it.Next();) { - if (child->Tag() == DW_TAG_namespace) { - DIENamespace* entry = dynamic_cast(child); - status_t error = _RecursiveTraverseNamespaceForTypes(entry, unit); + + if (child->IsType()) { + DIEType* type = dynamic_cast(child); + if (_RecursiveAddTypeNames(type, unit) != B_OK) + return B_NO_MEMORY; + } else { + DIENamespace* nameSpace = dynamic_cast(child); + if (nameSpace == NULL) + continue; + + status_t error = _RecursiveTraverseNamespaceForTypes(nameSpace, + unit); if (error != B_OK) return error; continue; } - - if (!child->IsType()) - continue; - - DIEType* type = dynamic_cast(child); - if (_RecursiveAddTypeNames(type, unit) != B_OK) - return B_NO_MEMORY; } return B_OK; diff --git a/src/kits/debugger/debug_info/DwarfImageDebugInfo.h b/src/kits/debugger/debug_info/DwarfImageDebugInfo.h index 7e5c92ddba..66d481154f 100644 --- a/src/kits/debugger/debug_info/DwarfImageDebugInfo.h +++ b/src/kits/debugger/debug_info/DwarfImageDebugInfo.h @@ -21,6 +21,7 @@ class Architecture; class CompilationUnit; class DebuggerInterface; class DIENamespace; +class DIESubprogram; class DIEType; class DwarfFunctionDebugInfo; class DwarfStackFrameDebugInfo; @@ -131,6 +132,14 @@ private: const TypeLookupConstraints& constraints) const; + status_t _RecursiveTraverseNamespaceForFunctions( + DIENamespace* nsEntry, + CompilationUnit* unit, + BObjectList& functions); + status_t _AddFunction(DIESubprogram* subprogramEntry, + CompilationUnit* unit, + BObjectList& functions); + status_t _BuildTypeNameTable(); status_t _RecursiveAddTypeNames(DIEType* type, CompilationUnit* unit); diff --git a/src/kits/debugger/dwarf/DebugInfoEntries.cpp b/src/kits/debugger/dwarf/DebugInfoEntries.cpp index 64c8eadd96..9ddf148117 100644 --- a/src/kits/debugger/dwarf/DebugInfoEntries.cpp +++ b/src/kits/debugger/dwarf/DebugInfoEntries.cpp @@ -1865,6 +1865,36 @@ DIENameListItem::Tag() const } +// #pragma mark - DIENamespace + + +DIENamespace::DIENamespace() +{ +} + + +uint16 +DIENamespace::Tag() const +{ + return DW_TAG_namespace; +} + + +bool +DIENamespace::IsNamespace() const +{ + return true; +} + + +status_t +DIENamespace::AddChild(DebugInfoEntry* child) +{ + fChildren.Add(child); + return B_OK; +} + + // #pragma mark - DIEPackedType @@ -1952,11 +1982,12 @@ DIESubprogram::AddChild(DebugInfoEntry* child) fCallSites.Add(child); return B_OK; default: - return DIEDeclaredNamedBase::AddChild(child); + return DIENamespace::AddChild(child); } } + status_t DIESubprogram::AddAttribute_low_pc(uint16 attributeName, const AttributeValue& value) @@ -2410,36 +2441,6 @@ DIEInterfaceType::Tag() const } -// #pragma mark - DIENamespace - - -DIENamespace::DIENamespace() -{ -} - - -uint16 -DIENamespace::Tag() const -{ - return DW_TAG_namespace; -} - - -bool -DIENamespace::IsNamespace() const -{ - return true; -} - - -status_t -DIENamespace::AddChild(DebugInfoEntry* child) -{ - fChildren.Add(child); - return B_OK; -} - - // #pragma mark - DIEImportedModule diff --git a/src/kits/debugger/dwarf/DebugInfoEntries.h b/src/kits/debugger/dwarf/DebugInfoEntries.h index 4789eefe6a..fb078c85f2 100644 --- a/src/kits/debugger/dwarf/DebugInfoEntries.h +++ b/src/kits/debugger/dwarf/DebugInfoEntries.h @@ -366,6 +366,8 @@ public: const DebugInfoEntryList& BaseTypes() const { return fBaseTypes; } + const DebugInfoEntryList& MemberFunctions() const + { return fMemberFunctions; } const DebugInfoEntryList& InnerTypes() const { return fInnerTypes; } const DebugInfoEntryList& TemplateParameters() const @@ -1218,6 +1220,28 @@ public: }; +class DIENamespace : public DIEDeclaredNamedBase { +public: + DIENamespace(); + + virtual uint16 Tag() const; + + virtual bool IsNamespace() const; + + const DebugInfoEntryList& Children() const + { return fChildren; } + + virtual status_t AddChild(DebugInfoEntry* child); + +private: + DebugInfoEntryList fChildren; + +// TODO: +// DW_AT_extension +// DW_AT_start_scope +}; + + class DIEPackedType : public DIEModifiedType { public: DIEPackedType(); @@ -1226,7 +1250,7 @@ public: }; -class DIESubprogram : public DIEDeclaredNamedBase { +class DIESubprogram : public DIENamespace { public: DIESubprogram(); ~DIESubprogram(); @@ -1531,28 +1555,6 @@ public: }; -class DIENamespace : public DIEDeclaredNamedBase { -public: - DIENamespace(); - - virtual uint16 Tag() const; - - virtual bool IsNamespace() const; - - const DebugInfoEntryList& Children() const - { return fChildren; } - - virtual status_t AddChild(DebugInfoEntry* child); - -private: - DebugInfoEntryList fChildren; - -// TODO: -// DW_AT_extension -// DW_AT_start_scope -}; - - class DIEImportedModule : public DIEDeclaredBase { public: DIEImportedModule();