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:
parent
8d1f13817f
commit
57893202f1
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
||||
|
||||
|
@ -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();
|
||||
|
Loading…
Reference in New Issue
Block a user