diff --git a/src/apps/debugger/debug_info/DwarfImageDebugInfo.cpp b/src/apps/debugger/debug_info/DwarfImageDebugInfo.cpp index d9638db7e2..e0fe825ea6 100644 --- a/src/apps/debugger/debug_info/DwarfImageDebugInfo.cpp +++ b/src/apps/debugger/debug_info/DwarfImageDebugInfo.cpp @@ -147,6 +147,22 @@ private: }; +// #pragma mark - EntryListWrapper + + +/*! Wraps a DebugInfoEntryList, which is a typedef and thus cannot appear in + the header, since our policy disallows us to include DWARF headers there. +*/ +struct DwarfImageDebugInfo::EntryListWrapper { + const DebugInfoEntryList& list; + + EntryListWrapper(const DebugInfoEntryList& list) + : + list(list) + { + } +}; + // #pragma mark - DwarfImageDebugInfo @@ -313,6 +329,7 @@ DwarfImageDebugInfo::CreateFrame(Image* image, functionInstance->GetFunctionDebugInfo()); if (function == NULL) return B_BAD_VALUE; +printf("DwarfImageDebugInfo::CreateFrame(): subprogram DIE: %p\n", function->SubprogramEntry()); int32 registerCount = fArchitecture->CountRegisters(); const Register* registers = fArchitecture->Registers(); @@ -344,9 +361,9 @@ DwarfImageDebugInfo::CreateFrame(Image* image, target_addr_t instructionPointer = cpuState->InstructionPointer() - fRelocationDelta; target_addr_t framePointer; - error = fFile->UnwindCallFrame(function->GetCompilationUnit(), - function->SubprogramEntry(), instructionPointer, &inputInterface, - &outputInterface, framePointer); + CompilationUnit* unit = function->GetCompilationUnit(); + error = fFile->UnwindCallFrame(unit, function->SubprogramEntry(), + instructionPointer, &inputInterface, &outputInterface, framePointer); if (error != B_OK) return B_UNSUPPORTED; @@ -382,9 +399,8 @@ if (previousCpuState->GetRegisterValue(reg, value)) { // create function parameter objects DIESubprogram* subprogramEntry = function->SubprogramEntry(); - DwarfInterfaceFactory factory(fFile, function->GetCompilationUnit(), - subprogramEntry, instructionPointer, framePointer, &inputInterface, - fromDwarfMap); + DwarfInterfaceFactory factory(fFile, unit, subprogramEntry, + instructionPointer, framePointer, &inputInterface, fromDwarfMap); error = factory.Init(); if (error != B_OK) return error; @@ -403,13 +419,17 @@ if (previousCpuState->GetRegisterValue(reg, value)) { != B_OK) { continue; } + Reference parameterReference(parameter, true); - if (!frame->AddParameter(parameter)) { - parameter->ReleaseReference(); + if (!frame->AddParameter(parameter)) return B_NO_MEMORY; - } } + // create objects for the local variables + _CreateLocalVariables(unit, frame, functionID, factory, instructionPointer, + functionInstance->Address() - fRelocationDelta, + subprogramEntry->Variables(), subprogramEntry->Blocks()); + _previousFrame = frameReference.Detach(); _previousCpuState = previousCpuStateReference.Detach(); @@ -723,3 +743,75 @@ DwarfImageDebugInfo::_GetSourceFileIndex(CompilationUnit* unit, return -1; } + + +status_t +DwarfImageDebugInfo::_CreateLocalVariables(CompilationUnit* unit, + StackFrame* frame, FunctionID* functionID, DwarfInterfaceFactory& factory, + target_addr_t instructionPointer, target_addr_t lowPC, + const EntryListWrapper& variableEntries, + const EntryListWrapper& blockEntries) +{ +printf("DwarfImageDebugInfo::_CreateLocalVariables(): ip: %#llx, low PC: %#llx\n", +instructionPointer, lowPC); + // iterate through the variables and add the ones in scope + for (DebugInfoEntryList::ConstIterator it + = variableEntries.list.GetIterator(); + DIEVariable* variableEntry = dynamic_cast(it.Next());) { +printf(" variableEntry %p, scope start: %llu\n", variableEntry, variableEntry->StartScope()); + // check the variable's scope + if (instructionPointer < lowPC + variableEntry->StartScope()) + continue; + + // add the variable + Variable* variable; + if (factory.CreateLocalVariable(functionID, variableEntry, variable) + != B_OK) { + continue; + } + Reference variableReference(variable, true); + + if (!frame->AddLocalVariable(variable)) + return B_NO_MEMORY; + } + + // iterate through the blocks and find the one we're currently in (if any) + for (DebugInfoEntryList::ConstIterator it = blockEntries.list.GetIterator(); + DIELexicalBlock* block = dynamic_cast(it.Next());) { +printf(" lexical block: %p\n", block); + + // check whether the block has low/high PC attributes + if (block->LowPC() != 0) { +printf(" has lowPC\n"); + // yep, compare with the instruction pointer + if (instructionPointer < block->LowPC() + || instructionPointer >= block->HighPC()) { + continue; + } + } else { +printf(" no lowPC\n"); + // check the address ranges instead + TargetAddressRangeList* rangeList = fFile->ResolveRangeList(unit, + block->AddressRangesOffset()); + if (rangeList == NULL) +{ +printf(" failed to get ranges\n"); + continue; +} + Reference rangeListReference(rangeList, + true); + + if (!rangeList->Contains(instructionPointer)) +{ +printf(" ranges don't contain IP\n"); + continue; +} + } + + // found a block -- recurse + return _CreateLocalVariables(unit, frame, functionID, factory, + instructionPointer, lowPC, block->Variables(), block->Blocks()); + } + + return B_OK; +} diff --git a/src/apps/debugger/debug_info/DwarfImageDebugInfo.h b/src/apps/debugger/debug_info/DwarfImageDebugInfo.h index e72727768c..ff26186144 100644 --- a/src/apps/debugger/debug_info/DwarfImageDebugInfo.h +++ b/src/apps/debugger/debug_info/DwarfImageDebugInfo.h @@ -17,10 +17,12 @@ class Architecture; class CompilationUnit; +class DwarfInterfaceFactory; class DwarfFile; class ElfSegment; class FileManager; class FileSourceCode; +class FunctionID; class LocatableFile; class SourceCode; class TeamMemory; @@ -65,6 +67,7 @@ public: private: struct UnwindTargetInterface; + struct EntryListWrapper; private: status_t _AddSourceCodeInfo(CompilationUnit* unit, @@ -73,6 +76,14 @@ private: int32 _GetSourceFileIndex(CompilationUnit* unit, LocatableFile* sourceFile) const; + status_t _CreateLocalVariables(CompilationUnit* unit, + StackFrame* frame, FunctionID* functionID, + DwarfInterfaceFactory& factory, + target_addr_t instructionPointer, + target_addr_t lowPC, + const EntryListWrapper& variableEntries, + const EntryListWrapper& blockEntries); + private: BLocker fLock; ImageInfo fImageInfo; diff --git a/src/apps/debugger/debug_info/DwarfInterfaceFactory.cpp b/src/apps/debugger/debug_info/DwarfInterfaceFactory.cpp index f9f4ae65fc..3d82a090aa 100644 --- a/src/apps/debugger/debug_info/DwarfInterfaceFactory.cpp +++ b/src/apps/debugger/debug_info/DwarfInterfaceFactory.cpp @@ -17,6 +17,7 @@ #include "DwarfUtils.h" #include "FunctionID.h" #include "FunctionParameterID.h" +#include "LocalVariableID.h" #include "RegisterMap.h" #include "StringUtils.h" #include "ValueLocation.h" @@ -63,6 +64,54 @@ private: }; +// #pragma mark - DwarfLocalVariableID + + +struct DwarfInterfaceFactory::DwarfLocalVariableID : public LocalVariableID { + + DwarfLocalVariableID(FunctionID* functionID, const BString& name, + int32 line, int32 column) + : + fFunctionID(functionID), + fName(name), + fLine(line), + fColumn(column) + { + fFunctionID->AcquireReference(); + } + + virtual ~DwarfLocalVariableID() + { + fFunctionID->ReleaseReference(); + } + + virtual bool operator==(const ObjectID& other) const + { + const DwarfLocalVariableID* otherID + = dynamic_cast(&other); + return otherID != NULL && *fFunctionID == *otherID->fFunctionID + && fName == otherID->fName && fLine == otherID->fLine + && fColumn == otherID->fColumn; + } + +protected: + virtual uint32 ComputeHashValue() const + { + uint32 hash = fFunctionID->HashValue(); + hash = hash * 19 + StringUtils::HashValue(fName); + hash = hash * 19 + fLine; + hash = hash * 19 + fColumn; + return hash; + } + +private: + FunctionID* fFunctionID; + const BString fName; + int32 fLine; + int32 fColumn; +}; + + // #pragma mark - DwarfType @@ -521,61 +570,43 @@ parameterEntry, name.String()); return B_NO_MEMORY; Reference idReference(id, true); - // get the type entry - DIEFormalParameter* typeOwnerEntry = parameterEntry; - DIEType* typeEntry = typeOwnerEntry->GetType(); - if (typeEntry == NULL) { - if (DIEFormalParameter* abstractOrigin - = dynamic_cast( - typeOwnerEntry->AbstractOrigin())) { - typeOwnerEntry = abstractOrigin; - typeEntry = typeOwnerEntry->GetType(); - } - } + // create the variable + return _CreateVariable(id, name, _GetDIEType(parameterEntry), + parameterEntry->GetLocationDescription(), _parameter); +} - if (typeEntry == NULL) { - if (DIEFormalParameter* specification - = dynamic_cast( - typeOwnerEntry->Specification())) { - typeOwnerEntry = specification; - typeEntry = typeOwnerEntry->GetType(); - } - } - if (typeEntry == NULL) - return B_BAD_VALUE; +status_t +DwarfInterfaceFactory::CreateLocalVariable(FunctionID* functionID, + DIEVariable* variableEntry, Variable*& _variable) +{ + // get the name + BString name; + DwarfUtils::GetDIEName(variableEntry, name); +printf("DwarfInterfaceFactory::CreateLocalVariable(DIE: %p): name: \"%s\"\n", +variableEntry, name.String()); - // get the location, if possible - ValueLocation* location = new(std::nothrow) ValueLocation; - if (location == NULL) + // get the declaration location + int32 line = -1; + int32 column = -1; + const char* file; + const char* directory; + DwarfUtils::GetDeclarationLocation(fFile, variableEntry, directory, file, + line, column); + // TODO: If the declaration location is unavailable, we should probably + // add a component to the ID to make it unique nonetheless (the name + // might not suffice). + + // create the ID + DwarfLocalVariableID* id = new(std::nothrow) DwarfLocalVariableID( + functionID, name, line, column); + if (id == NULL) return B_NO_MEMORY; - Reference locationReference(location, true); - - LocationDescription* locationDescription - = parameterEntry->GetLocationDescription(); - if (locationDescription->IsValid()) { - fFile->ResolveLocation(fCompilationUnit, - fSubprogramEntry, locationDescription, fTargetInterface, - fInstructionPointer, 0, fFramePointer, *location); -location->Dump(); - } - - // create the type - DwarfType* type; - status_t error = _CreateType(typeEntry, type); - if (error != B_OK) - return error; - Reference typeReference(type, true); - - _FixLocation(location, type); + Reference idReference(id, true); // create the variable - Variable* variable = new(std::nothrow) Variable(id, name, type, location); - if (variable == NULL) - return B_NO_MEMORY; - - _parameter = variable; - return B_OK; + return _CreateVariable(id, name, _GetDIEType(variableEntry), + variableEntry->GetLocationDescription(), _variable); } @@ -1049,6 +1080,46 @@ DwarfInterfaceFactory::_CreateArrayType(const BString& name, } +status_t +DwarfInterfaceFactory::_CreateVariable(ObjectID* id, const BString& name, + DIEType* typeEntry, LocationDescription* locationDescription, + Variable*& _variable) +{ + if (typeEntry == NULL) + return B_BAD_VALUE; + + // get the location, if possible + ValueLocation* location = new(std::nothrow) ValueLocation; + if (location == NULL) + return B_NO_MEMORY; + Reference locationReference(location, true); + + if (locationDescription->IsValid()) { + fFile->ResolveLocation(fCompilationUnit, + fSubprogramEntry, locationDescription, fTargetInterface, + fInstructionPointer, 0, fFramePointer, *location); +location->Dump(); + } + + // create the type + DwarfType* type; + status_t error = _CreateType(typeEntry, type); + if (error != B_OK) + return error; + Reference typeReference(type, true); + + _FixLocation(location, type); + + // create the variable + Variable* variable = new(std::nothrow) Variable(id, name, type, location); + if (variable == NULL) + return B_NO_MEMORY; + + _variable = variable; + return B_OK; +} + + status_t DwarfInterfaceFactory::_ResolveTypedef(DIETypedef* entry, DIEType*& _baseTypeEntry) @@ -1204,3 +1275,28 @@ printf(" set single piece size to %llu\n", type->ByteSize()); } } } + + +template +/*static*/ DIEType* +DwarfInterfaceFactory::_GetDIEType(EntryType* entry) +{ + if (DIEType* typeEntry = entry->GetType()) + return typeEntry; + + if (EntryType* abstractOrigin = dynamic_cast( + entry->AbstractOrigin())) { + entry = abstractOrigin; + if (DIEType* typeEntry = entry->GetType()) + return typeEntry; + } + + if (EntryType* specification = dynamic_cast( + entry->Specification())) { + entry = specification; + if (DIEType* typeEntry = entry->GetType()) + return typeEntry; + } + + return NULL; +} diff --git a/src/apps/debugger/debug_info/DwarfInterfaceFactory.h b/src/apps/debugger/debug_info/DwarfInterfaceFactory.h index 0825bdbaad..6e788a266b 100644 --- a/src/apps/debugger/debug_info/DwarfInterfaceFactory.h +++ b/src/apps/debugger/debug_info/DwarfInterfaceFactory.h @@ -23,9 +23,12 @@ class DIEModifiedType; class DIESubprogram; class DIEType; class DIETypedef; +class DIEVariable; class DwarfFile; class DwarfTargetInterface; class FunctionID; +class LocationDescription; +class ObjectID; class RegisterMap; class Type; class ValueLocation; @@ -51,9 +54,14 @@ public: DIEFormalParameter* parameterEntry, Variable*& _parameter); // returns reference + status_t CreateLocalVariable(FunctionID* functionID, + DIEVariable* variableEntry, + Variable*& _variable); + // returns reference private: struct DwarfFunctionParameterID; + struct DwarfLocalVariableID; struct DwarfType; struct DwarfDataMember; struct DwarfPrimitiveType; @@ -91,6 +99,11 @@ private: DIEArrayType* typeEntry, DwarfType*& _type); + status_t _CreateVariable(ObjectID* id, + const BString& name, DIEType* typeEntry, + LocationDescription* locationDescription, + Variable*& _variable); + status_t _ResolveTypedef(DIETypedef* entry, DIEType*& _baseTypeEntry); status_t _ResolveTypeByteSize(DIEType* typeEntry, @@ -99,6 +112,9 @@ private: void _FixLocation(ValueLocation* location, DwarfType* type); + template + static DIEType* _GetDIEType(EntryType* entry); + private: DwarfFile* fFile; CompilationUnit* fCompilationUnit;