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.
This commit is contained in:
Rene Gollent 2018-08-07 22:15:02 -04:00
parent 8d1f13817f
commit 57893202f1
4 changed files with 210 additions and 151 deletions

View File

@ -409,6 +409,7 @@ DwarfImageDebugInfo::GetFunctions(const BObjectList<SymbolInfo>& 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<SymbolInfo>& symbols,
for (DebugInfoEntryList::ConstIterator it
= unitEntry->OtherChildren().GetIterator();
DebugInfoEntry* entry = it.Next();) {
if (entry->Tag() != DW_TAG_subprogram)
continue;
DIESubprogram* subprogramEntry = static_cast<DIESubprogram*>(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<DIESubprogram*>(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<DIENamespace*>(entry);
if (nsEntry != NULL) {
error = _RecursiveTraverseNamespaceForFunctions(nsEntry, unit,
functions);
if (error != B_OK)
return error;
}
BReference<TargetAddressRangeList> 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<LocatableFile> 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<FunctionDebugInfo>& 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<DIESubprogram*>(entry);
error = _AddFunction(subprogramEntry, unit, functions);
if (error != B_OK)
return error;
}
DIENamespace* nsEntry = dynamic_cast<DIENamespace*>(entry);
if (nsEntry != NULL) {
error = _RecursiveTraverseNamespaceForFunctions(nsEntry, unit,
functions);
if (error != B_OK)
return error;
continue;
}
DIEClassBaseType* classEntry = dynamic_cast<DIEClassBaseType*>(entry);
if (classEntry != NULL) {
for (DebugInfoEntryList::ConstIterator it
= classEntry->MemberFunctions().GetIterator();
DebugInfoEntry* memberEntry = it.Next();) {
error = _AddFunction(static_cast<DIESubprogram*>(memberEntry),
unit, functions);
if (error != B_OK)
return error;
}
}
}
return B_OK;
}
status_t
DwarfImageDebugInfo::_AddFunction(DIESubprogram* subprogramEntry,
CompilationUnit* unit, BObjectList<FunctionDebugInfo>& 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<TargetAddressRangeList> 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<LocatableFile> 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<DIENamespace*>(child);
if (namespaceEntry == NULL)
continue;
DIENamespace* namespaceEntry = dynamic_cast<DIENamespace*>(child);
if (_RecursiveTraverseNamespaceForTypes(namespaceEntry, unit)
!= B_OK) {
return B_NO_MEMORY;
@ -1455,7 +1499,9 @@ DwarfImageDebugInfo::_RecursiveAddTypeNames(DIEType* type, CompilationUnit* unit
}
DIEClassBaseType* classType = dynamic_cast<DIEClassBaseType*>(type);
if (classType != NULL) {
if (classType == NULL)
return B_OK;
for (DebugInfoEntryList::ConstIterator it
= classType->InnerTypes().GetIterator();
DIEType* innerType = dynamic_cast<DIEType*>(it.Next());) {
@ -1463,7 +1509,6 @@ DwarfImageDebugInfo::_RecursiveAddTypeNames(DIEType* type, CompilationUnit* 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<DIENamespace*>(child);
status_t error = _RecursiveTraverseNamespaceForTypes(entry, unit);
if (child->IsType()) {
DIEType* type = dynamic_cast<DIEType*>(child);
if (_RecursiveAddTypeNames(type, unit) != B_OK)
return B_NO_MEMORY;
} else {
DIENamespace* nameSpace = dynamic_cast<DIENamespace*>(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<DIEType*>(child);
if (_RecursiveAddTypeNames(type, unit) != B_OK)
return B_NO_MEMORY;
}
return B_OK;

View File

@ -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<FunctionDebugInfo>& functions);
status_t _AddFunction(DIESubprogram* subprogramEntry,
CompilationUnit* unit,
BObjectList<FunctionDebugInfo>& functions);
status_t _BuildTypeNameTable();
status_t _RecursiveAddTypeNames(DIEType* type,
CompilationUnit* unit);

View File

@ -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

View File

@ -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();