From d315bfd510d1dba20fe05a39ac455fe354ca1a96 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Fri, 17 Jul 2009 01:54:43 +0000 Subject: [PATCH] * Added class ValueLocation to represent a location of a value on the target machine. * DWARF: - Various additions to the DIE classes. - DwarfExpressionEvaluationContext: - Added support for location expressions and thus the missing DW_OP_piece and DW_OP_bit_piece operations. - Fixed some deviations from the specs. - Added debug output. - DwarfFile: - Added missing evaluation of CFA expression rules. - Added service methods to evaluate expressions, location expressions, and constant and dynamic values. * Added model classes for representing types and variables. Particularly the types part is not finished yet. * StackFrame does now contain parameters and local variables. * Added DwarfInterfaceFactory, which creates implementation objects for the types, as well as variables objects. It's even less finished. * DwarfImageDebugInfo::CreateFrame(): Resolve function parameters and add them to the stack frame. No local variables yet. * Added the beginnings of a variables view. Only lists the names of parameters and local variables (of understood types) ATM. * Renamed RegisterView to RegistersView. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@31614 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/apps/debugger/Jamfile | 8 +- .../debug_info/DwarfFunctionDebugInfo.cpp | 1 + .../debug_info/DwarfFunctionDebugInfo.h | 3 + .../debug_info/DwarfImageDebugInfo.cpp | 39 +- .../debugger/debug_info/DwarfImageDebugInfo.h | 1 + .../debug_info/DwarfInterfaceFactory.cpp | 1013 +++++++++++++++++ .../debug_info/DwarfInterfaceFactory.h | 103 ++ src/apps/debugger/dwarf/AttributeValue.h | 15 +- src/apps/debugger/dwarf/DebugInfoEntries.cpp | 193 +++- src/apps/debugger/dwarf/DebugInfoEntries.h | 152 ++- src/apps/debugger/dwarf/DebugInfoEntry.cpp | 1 - .../dwarf/DwarfExpressionEvaluator.cpp | 257 ++++- .../debugger/dwarf/DwarfExpressionEvaluator.h | 20 +- src/apps/debugger/dwarf/DwarfFile.cpp | 396 ++++++- src/apps/debugger/dwarf/DwarfFile.h | 55 +- .../{RegisterView.cpp => RegistersView.cpp} | 25 +- .../{RegisterView.h => RegistersView.h} | 14 +- .../debugger/gui/team_window/TeamWindow.cpp | 14 +- .../debugger/gui/team_window/TeamWindow.h | 6 +- .../gui/team_window/VariablesView.cpp | 160 +++ .../debugger/gui/team_window/VariablesView.h | 41 + src/apps/debugger/model/StackFrame.cpp | 69 +- src/apps/debugger/model/StackFrame.h | 15 + src/apps/debugger/model/Type.cpp | 113 ++ src/apps/debugger/model/Type.h | 126 ++ src/apps/debugger/model/Variable.cpp | 28 + src/apps/debugger/model/Variable.h | 35 + src/apps/debugger/types/ValueLocation.cpp | 64 ++ src/apps/debugger/types/ValueLocation.h | 99 ++ 29 files changed, 2956 insertions(+), 110 deletions(-) create mode 100644 src/apps/debugger/debug_info/DwarfInterfaceFactory.cpp create mode 100644 src/apps/debugger/debug_info/DwarfInterfaceFactory.h rename src/apps/debugger/gui/team_window/{RegisterView.cpp => RegistersView.cpp} (89%) rename src/apps/debugger/gui/team_window/{RegisterView.h => RegistersView.h} (68%) create mode 100644 src/apps/debugger/gui/team_window/VariablesView.cpp create mode 100644 src/apps/debugger/gui/team_window/VariablesView.h create mode 100644 src/apps/debugger/model/Type.cpp create mode 100644 src/apps/debugger/model/Type.h create mode 100644 src/apps/debugger/model/Variable.cpp create mode 100644 src/apps/debugger/model/Variable.h create mode 100644 src/apps/debugger/types/ValueLocation.cpp create mode 100644 src/apps/debugger/types/ValueLocation.h diff --git a/src/apps/debugger/Jamfile b/src/apps/debugger/Jamfile index 72c68e71b9..591b6ab150 100644 --- a/src/apps/debugger/Jamfile +++ b/src/apps/debugger/Jamfile @@ -29,6 +29,7 @@ SourceHdrs DwarfFunctionDebugInfo.cpp DwarfImageDebugInfo.cpp DwarfTeamDebugInfo.cpp + DwarfInterfaceFactory.cpp : [ FDirName $(SUBDIR) dwarf ] ; @@ -58,6 +59,7 @@ Application Debugger : DwarfFunctionDebugInfo.cpp DwarfImageDebugInfo.cpp DwarfTeamDebugInfo.cpp + DwarfInterfaceFactory.cpp Function.cpp FunctionDebugInfo.cpp FunctionInstance.cpp @@ -84,11 +86,12 @@ Application Debugger : # gui/team_window ImageFunctionsView.cpp ImageListView.cpp - RegisterView.cpp + RegistersView.cpp SourceView.cpp StackTraceView.cpp TeamWindow.cpp ThreadListView.cpp + VariablesView.cpp # model Breakpoint.cpp @@ -107,6 +110,8 @@ Application Debugger : TeamMemory.cpp Thread.cpp ThreadInfo.cpp + Type.cpp + Variable.cpp # source_language CLanguage.cpp @@ -119,6 +124,7 @@ Application Debugger : # types TargetAddressRangeList.cpp + ValueLocation.cpp # util StringUtils.cpp diff --git a/src/apps/debugger/debug_info/DwarfFunctionDebugInfo.cpp b/src/apps/debugger/debug_info/DwarfFunctionDebugInfo.cpp index 93bd2fdab5..2aee31ef8b 100644 --- a/src/apps/debugger/debug_info/DwarfFunctionDebugInfo.cpp +++ b/src/apps/debugger/debug_info/DwarfFunctionDebugInfo.cpp @@ -19,6 +19,7 @@ DwarfFunctionDebugInfo::DwarfFunctionDebugInfo( : fImageDebugInfo(imageDebugInfo), fCompilationUnit(compilationUnit), + fSubprogramEntry(subprogramEntry), fAddressRanges(addressRanges), fName(name), fSourceFile(sourceFile), diff --git a/src/apps/debugger/debug_info/DwarfFunctionDebugInfo.h b/src/apps/debugger/debug_info/DwarfFunctionDebugInfo.h index 84340170ad..b9f1345c1a 100644 --- a/src/apps/debugger/debug_info/DwarfFunctionDebugInfo.h +++ b/src/apps/debugger/debug_info/DwarfFunctionDebugInfo.h @@ -41,10 +41,13 @@ public: CompilationUnit* GetCompilationUnit() const { return fCompilationUnit; } + DIESubprogram* SubprogramEntry() const + { return fSubprogramEntry; } private: DwarfImageDebugInfo* fImageDebugInfo; CompilationUnit* fCompilationUnit; + DIESubprogram* fSubprogramEntry; TargetAddressRangeList* fAddressRanges; BString fName; LocatableFile* fSourceFile; diff --git a/src/apps/debugger/debug_info/DwarfImageDebugInfo.cpp b/src/apps/debugger/debug_info/DwarfImageDebugInfo.cpp index b55ce1ac11..14fb0ba658 100644 --- a/src/apps/debugger/debug_info/DwarfImageDebugInfo.cpp +++ b/src/apps/debugger/debug_info/DwarfImageDebugInfo.cpp @@ -25,6 +25,7 @@ #include "Dwarf.h" #include "DwarfFile.h" #include "DwarfFunctionDebugInfo.h" +#include "DwarfInterfaceFactory.h" #include "DwarfTargetInterface.h" #include "DwarfUtils.h" #include "ElfFile.h" @@ -40,6 +41,8 @@ #include "TargetAddressRangeList.h" #include "TeamMemory.h" #include "UnsupportedLanguage.h" +#include "ValueLocation.h" +#include "Variable.h" // #pragma mark - UnwindTargetInterface @@ -336,10 +339,12 @@ DwarfImageDebugInfo::CreateFrame(Image* image, FunctionDebugInfo* _function, fromDwarfMap, toDwarfMap, previousCpuState, fArchitecture, fTeamMemory); // do the unwinding + target_addr_t instructionPointer + = cpuState->InstructionPointer() - fRelocationDelta; target_addr_t framePointer; error = fFile->UnwindCallFrame(function->GetCompilationUnit(), - cpuState->InstructionPointer() - fRelocationDelta, - &inputInterface, &outputInterface, framePointer); + function->SubprogramEntry(), instructionPointer, &inputInterface, + &outputInterface, framePointer); if (error != B_OK) return B_UNSUPPORTED; @@ -358,12 +363,40 @@ if (previousCpuState->GetRegisterValue(reg, value)) { cpuState, framePointer, cpuState->InstructionPointer()); if (frame == NULL) return B_NO_MEMORY; + Reference frameReference(frame, true); frame->SetReturnAddress(previousCpuState->InstructionPointer()); // Note, this is correct, since we actually retrieved the return // address. Our caller will fix the IP for us. - _previousFrame = frame; + // create function parameter objects + DIESubprogram* subprogramEntry = function->SubprogramEntry(); + DwarfInterfaceFactory factory(fFile, function->GetCompilationUnit(), + subprogramEntry, instructionPointer, framePointer, &inputInterface); + error = factory.Init(); + if (error != B_OK) + return error; + + for (DebugInfoEntryList::ConstIterator it = subprogramEntry->Parameters() + .GetIterator(); DebugInfoEntry* entry = it.Next();) { + BString parameterName; + DwarfUtils::GetDIEName(entry, parameterName); + if (entry->Tag() != DW_TAG_formal_parameter) + continue; + + DIEFormalParameter* parameterEntry + = dynamic_cast(entry); + Variable* parameter; + if (factory.CreateParameter(parameterEntry, parameter) != B_OK) + continue; + + if (!frame->AddParameter(parameter)) { + parameter->ReleaseReference(); + return B_NO_MEMORY; + } + } + + _previousFrame = frameReference.Detach(); _previousCpuState = previousCpuStateReference.Detach(); return B_OK; diff --git a/src/apps/debugger/debug_info/DwarfImageDebugInfo.h b/src/apps/debugger/debug_info/DwarfImageDebugInfo.h index 9667ff2604..76692c92e0 100644 --- a/src/apps/debugger/debug_info/DwarfImageDebugInfo.h +++ b/src/apps/debugger/debug_info/DwarfImageDebugInfo.h @@ -12,6 +12,7 @@ #include "ImageInfo.h" #include "SpecificImageDebugInfo.h" +#include "Type.h" class Architecture; diff --git a/src/apps/debugger/debug_info/DwarfInterfaceFactory.cpp b/src/apps/debugger/debug_info/DwarfInterfaceFactory.cpp new file mode 100644 index 0000000000..696ef018db --- /dev/null +++ b/src/apps/debugger/debug_info/DwarfInterfaceFactory.cpp @@ -0,0 +1,1013 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + + +#include "DwarfInterfaceFactory.h" + +#include + +#include + +#include "DebugInfoEntries.h" +#include "Dwarf.h" +#include "DwarfFile.h" +#include "DwarfUtils.h" +#include "ValueLocation.h" +#include "Variable.h" + + +// #pragma mark - DwarfType + + +struct DwarfInterfaceFactory::DwarfType : virtual Type, + HashTableLink { +public: + DwarfType(const BString& name) + : + fName(name) + { + } + + virtual const char* Name() const + { + return fName.Length() > 0 ? fName.String() : NULL; + } + + virtual DIEType* GetDIEType() const = 0; + +private: + BString fName; +}; + + +// #pragma mark - DwarfDataMember + + +struct DwarfInterfaceFactory::DwarfDataMember : DataMember { +public: + DwarfDataMember(DIEMember* entry, const BString& name, DwarfType* type) + : + fEntry(entry), + fName(name), + fType(type) + { + fType->AcquireReference(); + } + + ~DwarfDataMember() + { + fType->ReleaseReference(); + } + + virtual const char* Name() const + { + return fName.Length() > 0 ? fName.String() : NULL; + } + + virtual Type* GetType() const + { + return fType; + } + + DIEMember* Entry() const + { + return fEntry; + } + +private: + DIEMember* fEntry; + BString fName; + DwarfType* fType; + +}; + + +// #pragma mark - DwarfPrimitiveType + + +struct DwarfInterfaceFactory::DwarfPrimitiveType : PrimitiveType, DwarfType { +public: + DwarfPrimitiveType(const BString& name, DIEBaseType* entry, + uint32 typeConstant) + : + DwarfType(name), + fEntry(entry), + fTypeConstant(typeConstant) + { + } + + virtual DIEType* GetDIEType() const + { + return fEntry; + } + + DIEBaseType* Entry() const + { + return fEntry; + } + + virtual uint32 TypeConstant() const + { + return fTypeConstant; + } + +private: + DIEBaseType* fEntry; + uint32 fTypeConstant; +}; + + +// #pragma mark - DwarfCompoundType + + +struct DwarfInterfaceFactory::DwarfCompoundType : CompoundType, DwarfType { +public: + DwarfCompoundType(const BString& name, DIECompoundType* entry) + : + DwarfType(name), + fEntry(entry) + { + } + + ~DwarfCompoundType() + { + for (int32 i = 0; DwarfDataMember* member = fDataMembers.ItemAt(i); i++) + member->ReleaseReference(); + } + + virtual int32 CountDataMembers() const + { + return fDataMembers.CountItems(); + } + + virtual DataMember* DataMemberAt(int32 index) const + { + return fDataMembers.ItemAt(index); + } + + virtual DIEType* GetDIEType() const + { + return fEntry; + } + + DIECompoundType* Entry() const + { + return fEntry; + } + + bool AddDataMember(DwarfDataMember* member) + { + if (!fDataMembers.AddItem(member)) + return false; + + member->AcquireReference(); + return true; + } + +private: + typedef BObjectList DataMemberList; + +private: + DIECompoundType* fEntry; + DataMemberList fDataMembers; +}; + + +// #pragma mark - DwarfModifiedType + + +struct DwarfInterfaceFactory::DwarfModifiedType : ModifiedType, DwarfType { +public: + DwarfModifiedType(const BString& name, DIEModifiedType* entry, + uint32 modifiers, DwarfType* baseType) + : + DwarfType(name), + fEntry(entry), + fModifiers(modifiers), + fBaseType(baseType) + { + fBaseType->AcquireReference(); + } + + ~DwarfModifiedType() + { + fBaseType->ReleaseReference(); + } + + virtual uint32 Modifiers() const + { + return fModifiers; + } + + virtual Type* BaseType() const + { + return fBaseType; + } + + virtual DIEType* GetDIEType() const + { + return fEntry; + } + + DIEModifiedType* Entry() const + { + return fEntry; + } + +private: + DIEModifiedType* fEntry; + uint32 fModifiers; + DwarfType* fBaseType; +}; + + +// #pragma mark - DwarfTypedefType + + +struct DwarfInterfaceFactory::DwarfTypedefType : TypedefType, DwarfType { +public: + DwarfTypedefType(const BString& name, DIETypedef* entry, + DwarfType* baseType) + : + DwarfType(name), + fEntry(entry), + fBaseType(baseType) + { + fBaseType->AcquireReference(); + } + + ~DwarfTypedefType() + { + fBaseType->ReleaseReference(); + } + + virtual Type* BaseType() const + { + return fBaseType; + } + + virtual DIEType* GetDIEType() const + { + return fEntry; + } + + DIETypedef* Entry() const + { + return fEntry; + } + +private: + DIETypedef* fEntry; + DwarfType* fBaseType; +}; + + +// #pragma mark - DwarfAddressType + + +struct DwarfInterfaceFactory::DwarfAddressType : AddressType, DwarfType { +public: + DwarfAddressType(const BString& name, DIEAddressingType* entry, + address_type_kind addressKind, DwarfType* baseType) + : + DwarfType(name), + fEntry(entry), + fAddressKind(addressKind), + fBaseType(baseType) + { + fBaseType->AcquireReference(); + } + + ~DwarfAddressType() + { + fBaseType->ReleaseReference(); + } + + virtual address_type_kind AddressKind() const + { + return fAddressKind; + } + + virtual Type* BaseType() const + { + return fBaseType; + } + + virtual DIEType* GetDIEType() const + { + return fEntry; + } + + DIEAddressingType* Entry() const + { + return fEntry; + } + +private: + DIEAddressingType* fEntry; + address_type_kind fAddressKind; + DwarfType* fBaseType; +}; + + +// #pragma mark - DwarfArrayType + + +struct DwarfInterfaceFactory::DwarfArrayType : ArrayType, DwarfType { + DwarfArrayType(const BString& name, DIEArrayType* entry, + DwarfType* baseType, target_size_t elementCount) + : + DwarfType(name), + fEntry(entry), + fBaseType(baseType), + fElementCount(elementCount) + { + fBaseType->AcquireReference(); + } + + ~DwarfArrayType() + { + fBaseType->ReleaseReference(); + } + + virtual Type* BaseType() const + { + return fBaseType; + } + + virtual target_size_t CountElements() const + { + return fElementCount; + } + + virtual DIEType* GetDIEType() const + { + return fEntry; + } + + DIEArrayType* Entry() const + { + return fEntry; + } + +private: + DIEArrayType* fEntry; + DwarfType* fBaseType; + target_size_t fElementCount; +}; + + +// #pragma mark - DwarfTypeHashDefinition + + +struct DwarfInterfaceFactory::DwarfTypeHashDefinition { + typedef const DIEType* KeyType; + typedef DwarfType ValueType; + + size_t HashKey(const DIEType* key) const + { + return (addr_t)key; + } + + size_t Hash(const DwarfType* value) const + { + return HashKey(value->GetDIEType()); + } + + bool Compare(const DIEType* key, const DwarfType* value) const + { + return key == value->GetDIEType(); + } + + HashTableLink* GetLink(DwarfType* value) const + { + return value; + } +}; + + +// #pragma mark - DwarfInterfaceFactory + + +DwarfInterfaceFactory::DwarfInterfaceFactory(DwarfFile* file, + CompilationUnit* compilationUnit, DIESubprogram* subprogramEntry, + target_addr_t instructionPointer, target_addr_t framePointer, + DwarfTargetInterface* targetInterface) + : + fFile(file), + fCompilationUnit(compilationUnit), + fSubprogramEntry(subprogramEntry), + fInstructionPointer(instructionPointer), + fFramePointer(framePointer), + fTargetInterface(targetInterface), + fTypes(NULL) +{ +} + + +DwarfInterfaceFactory::~DwarfInterfaceFactory() +{ + if (fTypes != NULL) { + DwarfType* type = fTypes->Clear(true); + while (type != NULL) { + DwarfType* next = type->fNext; + type->ReleaseReference(); + type = next; + } + + delete fTypes; + } +} + + +status_t +DwarfInterfaceFactory::Init() +{ + fTypes = new(std::nothrow) TypeTable; + if (fTypes == NULL) + return B_NO_MEMORY; + + return fTypes->Init(); +} + + +status_t +DwarfInterfaceFactory::CreateType(DIEType* typeEntry, Type*& _type) +{ + DwarfType* type; + status_t error = _CreateType(typeEntry, type); + if (error != B_OK) + return error; + + _type = type; + return B_OK; +} + + +status_t +DwarfInterfaceFactory::CreateParameter(DIEFormalParameter* parameterEntry, + Variable*& _parameter) +{ + // get the name + BString name; + DwarfUtils::GetFullyQualifiedDIEName(parameterEntry, name); + + // 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(); + } + } + + if (typeEntry == NULL) { + if (DIEFormalParameter* specification + = dynamic_cast( + typeOwnerEntry->Specification())) { + typeOwnerEntry = specification; + typeEntry = typeOwnerEntry->GetType(); + } + } + + 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); + + LocationDescription* locationDescription + = parameterEntry->GetLocationDescription(); + if (locationDescription->IsValid()) { + fFile->ResolveLocation(fCompilationUnit, + fSubprogramEntry, locationDescription, fTargetInterface, + fInstructionPointer, 0, fFramePointer, *location); + } + + // create the type + DwarfType* type; + status_t error = _CreateType(typeEntry, type); + if (error != B_OK) + return error; + Reference typeReference(type, true); + + // create the variable + Variable* variable = new(std::nothrow) Variable(name, type, location); + if (variable == NULL) + return B_NO_MEMORY; + + _parameter = variable; + return B_OK; +} + + +status_t +DwarfInterfaceFactory::_CreateType(DIEType* typeEntry, DwarfType*& _type) +{ + // Try the type cache first. If we don't know the type yet, create it. + DwarfType* type = fTypes->Lookup(typeEntry); + + if (type == NULL) { + status_t error = _CreateTypeInternal(typeEntry, type); + if (error != B_OK) + return error; + + fTypes->Insert(type); + } + + type->AcquireReference(); + _type = type; + return B_OK; +} + + +status_t +DwarfInterfaceFactory::_CreateTypeInternal(DIEType* typeEntry, + DwarfType*& _type) +{ + BString name; + DwarfUtils::GetFullyQualifiedDIEName(typeEntry, name); + + switch (typeEntry->Tag()) { + case DW_TAG_class_type: + case DW_TAG_structure_type: + case DW_TAG_union_type: + case DW_TAG_interface_type: + return _CreateCompoundType(name, + dynamic_cast(typeEntry), _type); + + case DW_TAG_base_type: + return _CreatePrimitiveType(name, + dynamic_cast(typeEntry), _type); + + case DW_TAG_pointer_type: + return _CreateAddressType(name, + dynamic_cast(typeEntry), + DERIVED_TYPE_POINTER, _type); + case DW_TAG_reference_type: + return _CreateAddressType(name, + dynamic_cast(typeEntry), + DERIVED_TYPE_REFERENCE, _type); + + case DW_TAG_const_type: + return _CreateModifiedType(name, + dynamic_cast(typeEntry), + TYPE_MODIFIER_CONST, _type); + case DW_TAG_packed_type: + return _CreateModifiedType(name, + dynamic_cast(typeEntry), + TYPE_MODIFIER_PACKED, _type); + case DW_TAG_volatile_type: + return _CreateModifiedType(name, + dynamic_cast(typeEntry), + TYPE_MODIFIER_VOLATILE, _type); + case DW_TAG_restrict_type: + return _CreateModifiedType(name, + dynamic_cast(typeEntry), + TYPE_MODIFIER_RESTRICT, _type); + case DW_TAG_shared_type: + return _CreateModifiedType(name, + dynamic_cast(typeEntry), + TYPE_MODIFIER_SHARED, _type); + + case DW_TAG_typedef: + return _CreateTypedefType(name, + dynamic_cast(typeEntry), _type); + + case DW_TAG_array_type: + return _CreateArrayType(name, + dynamic_cast(typeEntry), _type); + + case DW_TAG_unspecified_type: + case DW_TAG_subroutine_type: + case DW_TAG_enumeration_type: + case DW_TAG_ptr_to_member_type: + case DW_TAG_subrange_type: + // TODO: Implement! + return B_UNSUPPORTED; + + case DW_TAG_string_type: + case DW_TAG_file_type: + case DW_TAG_set_type: + // TODO: Implement! + return B_UNSUPPORTED; + } + + return B_UNSUPPORTED; +} + + +status_t +DwarfInterfaceFactory::_CreateCompoundType(const BString& name, + DIECompoundType* typeEntry, DwarfType*& _type) +{ + // create the type + DwarfCompoundType* type = new(std::nothrow) DwarfCompoundType(name, + typeEntry); + if (type == NULL) + return B_NO_MEMORY; + Reference typeReference(type, true); + + // find the abstract origin or specification that defines the data members + if (typeEntry->DataMembers().IsEmpty()) { + if (DIECompoundType* abstractOrigin = dynamic_cast( + typeEntry->AbstractOrigin())) { + typeEntry = abstractOrigin; + } + } + + if (typeEntry->DataMembers().IsEmpty()) { + if (DIECompoundType* specification = dynamic_cast( + typeEntry->Specification())) { + typeEntry = specification; + } + } + + // create the data member objects + for (DebugInfoEntryList::ConstIterator it + = typeEntry->DataMembers().GetIterator(); + DebugInfoEntry* _memberEntry = it.Next();) { + DIEMember* memberEntry = dynamic_cast(_memberEntry); + + // get the type + DwarfType* memberType; + if (_CreateType(memberEntry->GetType(), memberType) != B_OK) + continue; + Reference memberTypeReference(memberType, true); + + // get the name + BString memberName; + DwarfUtils::GetDIEName(memberEntry, memberName); + + // create and add the member object + DwarfDataMember* member = new(std::nothrow) DwarfDataMember(memberEntry, + memberName, memberType); + Reference memberReference(member, true); + if (member == NULL || !type->AddDataMember(member)) + return B_NO_MEMORY; + } + + _type = typeReference.Detach(); + return B_OK;; +} + + +status_t +DwarfInterfaceFactory::_CreatePrimitiveType(const BString& name, + DIEBaseType* typeEntry, DwarfType*& _type) +{ + const DynamicAttributeValue* byteSizeValue = typeEntry->ByteSize(); +// const DynamicAttributeValue* bitOffsetValue = typeEntry->BitOffset(); + const DynamicAttributeValue* bitSizeValue = typeEntry->BitSize(); + + uint32 bitSize = 0; + if (byteSizeValue->IsValid()) { + BVariant value; + status_t error = fFile->EvaluateDynamicValue(fCompilationUnit, + fSubprogramEntry, byteSizeValue, fTargetInterface, + fInstructionPointer, fFramePointer, value); + if (error == B_OK && value.IsInteger()) + bitSize = value.ToUInt32() * 8; + } else if (bitSizeValue->IsValid()) { + BVariant value; + status_t error = fFile->EvaluateDynamicValue(fCompilationUnit, + fSubprogramEntry, bitSizeValue, fTargetInterface, + fInstructionPointer, fFramePointer, value); + if (error == B_OK && value.IsInteger()) + bitSize = value.ToUInt32(); + } + + // determine type constant + uint32 typeConstant = 0; + switch (typeEntry->Encoding()) { + case DW_ATE_boolean: + typeConstant = B_BOOL_TYPE; + break; + + case DW_ATE_float: + switch (bitSize) { + case 32: + typeConstant = B_FLOAT_TYPE; + break; + case 64: + typeConstant = B_DOUBLE_TYPE; + break; + } + break; + + case DW_ATE_signed: + case DW_ATE_signed_char: + switch (bitSize) { + case 8: + typeConstant = B_INT8_TYPE; + break; + case 16: + typeConstant = B_INT16_TYPE; + break; + case 32: + typeConstant = B_INT32_TYPE; + break; + case 64: + typeConstant = B_INT64_TYPE; + break; + } + break; + + case DW_ATE_address: + case DW_ATE_unsigned: + case DW_ATE_unsigned_char: + switch (bitSize) { + case 8: + typeConstant = B_UINT8_TYPE; + break; + case 16: + typeConstant = B_UINT16_TYPE; + break; + case 32: + typeConstant = B_UINT32_TYPE; + break; + case 64: + typeConstant = B_UINT64_TYPE; + break; + } + break; + + case DW_ATE_complex_float: + case DW_ATE_imaginary_float: + case DW_ATE_packed_decimal: + case DW_ATE_numeric_string: + case DW_ATE_edited: + case DW_ATE_signed_fixed: + case DW_ATE_unsigned_fixed: + case DW_ATE_decimal_float: + default: + break; + } + + // create the type + DwarfPrimitiveType* type = new(std::nothrow) DwarfPrimitiveType(name, + typeEntry, typeConstant); + if (type == NULL) + return B_NO_MEMORY; + + _type = type; + return B_OK; +} + + +status_t +DwarfInterfaceFactory::_CreateAddressType(const BString& name, + DIEAddressingType* typeEntry, address_type_kind addressKind, + DwarfType*& _type) +{ + // get the base type entry + DIEAddressingType* baseTypeOwnerEntry = typeEntry; + DIEType* baseTypeEntry = baseTypeOwnerEntry->GetType(); + if (baseTypeEntry == NULL) { + if (DIEAddressingType* abstractOrigin + = dynamic_cast( + baseTypeOwnerEntry->AbstractOrigin())) { + baseTypeOwnerEntry = abstractOrigin; + baseTypeEntry = baseTypeOwnerEntry->GetType(); + } + } + + if (baseTypeEntry == NULL) { + if (DIEAddressingType* specification = dynamic_cast( + baseTypeOwnerEntry->Specification())) { + baseTypeOwnerEntry = specification; + baseTypeEntry = baseTypeOwnerEntry->GetType(); + } + } + + if (baseTypeEntry == NULL) + return B_BAD_VALUE; + + // create the base type + DwarfType* baseType; + status_t error = _CreateType(baseTypeEntry, baseType); + if (error != B_OK) + return error; + Reference baseTypeReference(baseType, true); + + DwarfAddressType* type = new(std::nothrow) DwarfAddressType(name, typeEntry, + addressKind, baseType); + if (type == NULL) + return B_NO_MEMORY; + + _type = type; + return B_OK; +} + + +status_t +DwarfInterfaceFactory::_CreateModifiedType(const BString& name, + DIEModifiedType* typeEntry, uint32 modifiers, DwarfType*& _type) +{ + // Get the base type entry. If it is a modified type too or a typedef, + // collect all modifiers and iterate until hitting an actual base type. + DIEModifiedType* baseTypeOwnerEntry = typeEntry; + DIEType* baseTypeEntry; + while (true) { + baseTypeEntry = baseTypeOwnerEntry->GetType(); + if (baseTypeEntry == NULL) { + if (DIEModifiedType* abstractOrigin + = dynamic_cast( + baseTypeOwnerEntry->AbstractOrigin())) { + baseTypeOwnerEntry = abstractOrigin; + baseTypeEntry = baseTypeOwnerEntry->GetType(); + } + } + + if (baseTypeEntry == NULL) { + if (DIEModifiedType* specification = dynamic_cast( + baseTypeOwnerEntry->Specification())) { + baseTypeOwnerEntry = specification; + baseTypeEntry = baseTypeOwnerEntry->GetType(); + } + } + + // resolve a typedef + if (baseTypeEntry != NULL && baseTypeEntry->Tag() == DW_TAG_typedef) { + status_t error = _ResolveTypedef( + dynamic_cast(baseTypeEntry), baseTypeEntry); + if (error != B_OK) + return error; + } + + if (baseTypeEntry == NULL) + return B_BAD_VALUE; + + // If the base type is a modified type, too, resolve it. + switch (baseTypeEntry->Tag()) { + case DW_TAG_const_type: + modifiers |= TYPE_MODIFIER_CONST; + baseTypeOwnerEntry + = dynamic_cast(baseTypeEntry); + continue; + case DW_TAG_packed_type: + modifiers |= TYPE_MODIFIER_PACKED; + baseTypeOwnerEntry + = dynamic_cast(baseTypeEntry); + continue; + case DW_TAG_volatile_type: + modifiers |= TYPE_MODIFIER_VOLATILE; + baseTypeOwnerEntry + = dynamic_cast(baseTypeEntry); + continue; + case DW_TAG_restrict_type: + modifiers |= TYPE_MODIFIER_RESTRICT; + baseTypeOwnerEntry + = dynamic_cast(baseTypeEntry); + continue; + case DW_TAG_shared_type: + modifiers |= TYPE_MODIFIER_SHARED; + baseTypeOwnerEntry + = dynamic_cast(baseTypeEntry); + continue; + + default: + break; + } + + // If we get here, we've found an actual base type. + break; + } + + // create the base type + DwarfType* baseType; + status_t error = _CreateType(baseTypeEntry, baseType); + if (error != B_OK) + return error; + Reference baseTypeReference(baseType, true); + + DwarfModifiedType* type = new(std::nothrow) DwarfModifiedType(name, + typeEntry, modifiers, baseType); + if (type == NULL) + return B_NO_MEMORY; + + _type = type; + return B_OK; +} + + +status_t +DwarfInterfaceFactory::_CreateTypedefType(const BString& name, + DIETypedef* typeEntry, DwarfType*& _type) +{ + // resolve the base type + DIEType* baseTypeEntry; + status_t error = _ResolveTypedef(typeEntry, baseTypeEntry); + if (error != B_OK) + return error; + + // create the base type + DwarfType* baseType; + error = _CreateType(baseTypeEntry, baseType); + if (error != B_OK) + return error; + Reference baseTypeReference(baseType, true); + + DwarfTypedefType* type = new(std::nothrow) DwarfTypedefType(name, typeEntry, + baseType); + if (type == NULL) + return B_NO_MEMORY; + + _type = type; + return B_OK; +} + + +status_t +DwarfInterfaceFactory::_CreateArrayType(const BString& name, + DIEArrayType* typeEntry, DwarfType*& _type) +{ +#if 0 + // get the base type entry + DIEArrayType* baseTypeOwnerEntry = typeEntry; + DIEType* baseTypeEntry = baseTypeOwnerEntry->GetType(); + if (baseTypeEntry == NULL) { + if (DIEArrayType* abstractOrigin = dynamic_cast( + baseTypeOwnerEntry->AbstractOrigin())) { + baseTypeOwnerEntry = abstractOrigin; + baseTypeEntry = baseTypeOwnerEntry->GetType(); + } + } + + if (baseTypeEntry == NULL) { + if (DIEArrayType* specification = dynamic_cast( + baseTypeOwnerEntry->Specification())) { + baseTypeOwnerEntry = specification; + baseTypeEntry = baseTypeOwnerEntry->GetType(); + } + } + + if (baseTypeEntry == NULL) + return B_BAD_VALUE; + + // create the base type + DwarfType* baseType; + status_t error = _CreateType(baseTypeEntry, baseType); + if (error != B_OK) + return error; + Reference baseTypeReference(baseType, true); + + DwarfArrayType* type = new(std::nothrow) DwarfArrayType(name, typeEntry, + baseType, elementCount); + if (type == NULL) + return B_NO_MEMORY; + + _type = type; + return B_OK; +#endif + + // TODO:... + return B_UNSUPPORTED; +} + + +status_t +DwarfInterfaceFactory::_ResolveTypedef(DIETypedef* entry, + DIEType*& _baseTypeEntry) +{ + while (true) { + // resolve the base type, possibly following abstract origin or + // specification + DIEType* baseTypeEntry = entry->GetType(); + + if (baseTypeEntry == NULL) { + if (DIETypedef* abstractOrigin = dynamic_cast( + entry->AbstractOrigin())) { + entry = abstractOrigin; + baseTypeEntry = entry->GetType(); + } + } + + if (baseTypeEntry == NULL) { + if (DIETypedef* specification = dynamic_cast( + entry->Specification())) { + entry = specification; + baseTypeEntry = entry->GetType(); + } + } + + if (baseTypeEntry == NULL) + return B_BAD_VALUE; + + if (baseTypeEntry->Tag() != DW_TAG_typedef) { + _baseTypeEntry = baseTypeEntry; + return B_OK; + } + + entry = dynamic_cast(baseTypeEntry); + } +} + diff --git a/src/apps/debugger/debug_info/DwarfInterfaceFactory.h b/src/apps/debugger/debug_info/DwarfInterfaceFactory.h new file mode 100644 index 0000000000..b466e85413 --- /dev/null +++ b/src/apps/debugger/debug_info/DwarfInterfaceFactory.h @@ -0,0 +1,103 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef DWARF_INTERFACE_FACTORY_H +#define DWARF_INTERFACE_FACTORY_H + + +#include + +#include + +#include "Type.h" + + +class CompilationUnit; +class DIEAddressingType; +class DIEArrayType; +class DIEBaseType; +class DIECompoundType; +class DIEFormalParameter; +class DIEModifiedType; +class DIESubprogram; +class DIEType; +class DIETypedef; +class DwarfFile; +class DwarfTargetInterface; +class Type; +class Variable; + + +class DwarfInterfaceFactory { +public: + DwarfInterfaceFactory(DwarfFile* file, + CompilationUnit* compilationUnit, + DIESubprogram* subprogramEntry, + target_addr_t instructionPointer, + target_addr_t framePointer, + DwarfTargetInterface* targetInterface); + ~DwarfInterfaceFactory(); + + status_t Init(); + + status_t CreateType(DIEType* typeEntry, Type*& _type); + // returns reference + status_t CreateParameter( + DIEFormalParameter* parameterEntry, + Variable*& _parameter); + // returns reference + +private: + struct DwarfType; + struct DwarfDataMember; + struct DwarfPrimitiveType; + struct DwarfCompoundType; + struct DwarfModifiedType; + struct DwarfTypedefType; + struct DwarfAddressType; + struct DwarfArrayType; + struct DwarfTypeHashDefinition; + + typedef OpenHashTable TypeTable; + +private: + status_t _CreateType(DIEType* typeEntry, + DwarfType*& _type); + status_t _CreateTypeInternal(DIEType* typeEntry, + DwarfType*& _type); + + status_t _CreateCompoundType(const BString& name, + DIECompoundType* typeEntry, + DwarfType*& _type); + status_t _CreatePrimitiveType(const BString& name, + DIEBaseType* typeEntry, + DwarfType*& _type); + status_t _CreateAddressType(const BString& name, + DIEAddressingType* typeEntry, + address_type_kind addressKind, + DwarfType*& _type); + status_t _CreateModifiedType(const BString& name, + DIEModifiedType* typeEntry, + uint32 modifiers, DwarfType*& _type); + status_t _CreateTypedefType(const BString& name, + DIETypedef* typeEntry, DwarfType*& _type); + status_t _CreateArrayType(const BString& name, + DIEArrayType* typeEntry, + DwarfType*& _type); + + status_t _ResolveTypedef(DIETypedef* entry, + DIEType*& _baseTypeEntry); + +private: + DwarfFile* fFile; + CompilationUnit* fCompilationUnit; + DIESubprogram* fSubprogramEntry; + target_addr_t fInstructionPointer; + target_addr_t fFramePointer; + DwarfTargetInterface* fTargetInterface; + TypeTable* fTypes; +}; + + +#endif // DWARF_INTERFACE_FACTORY_H diff --git a/src/apps/debugger/dwarf/AttributeValue.h b/src/apps/debugger/dwarf/AttributeValue.h index 72c2b2d206..e5823d8258 100644 --- a/src/apps/debugger/dwarf/AttributeValue.h +++ b/src/apps/debugger/dwarf/AttributeValue.h @@ -135,11 +135,16 @@ struct DynamicAttributeValue { DynamicAttributeValue() : - attributeClass(ATTRIBUTE_CLASS_CONSTANT) + attributeClass(ATTRIBUTE_CLASS_UNKNOWN) { this->constant = 0; } + bool IsValid() const + { + return attributeClass != ATTRIBUTE_CLASS_UNKNOWN; + } + void SetTo(uint64 constant) { this->constant = constant; @@ -174,9 +179,13 @@ struct ConstantAttributeValue { ConstantAttributeValue() : - attributeClass(ATTRIBUTE_CLASS_CONSTANT) + attributeClass(ATTRIBUTE_CLASS_UNKNOWN) { - this->constant = 0; + } + + bool IsValid() const + { + return attributeClass != ATTRIBUTE_CLASS_UNKNOWN; } void SetTo(uint64 constant) diff --git a/src/apps/debugger/dwarf/DebugInfoEntries.cpp b/src/apps/debugger/dwarf/DebugInfoEntries.cpp index d41e9ab68f..9fcb8d3117 100644 --- a/src/apps/debugger/dwarf/DebugInfoEntries.cpp +++ b/src/apps/debugger/dwarf/DebugInfoEntries.cpp @@ -437,7 +437,7 @@ DIEClassBaseType::AddChild(DebugInfoEntry* child) { switch (child->Tag()) { case DW_TAG_inheritance: - fDataMembers.Add(child); + fBaseTypes.Add(child); return B_OK; case DW_TAG_friend: fFriends.Add(child); @@ -777,6 +777,9 @@ DIEEnumerationType::AddAttribute_specification(uint16 attributeName, DIEFormalParameter::DIEFormalParameter() + : + fAbstractOrigin(NULL), + fType(NULL) { } @@ -788,6 +791,13 @@ DIEFormalParameter::Tag() const } +DebugInfoEntry* +DIEFormalParameter::AbstractOrigin() const +{ + return fAbstractOrigin; +} + + LocationDescription* DIEFormalParameter::GetLocationDescription() { @@ -795,6 +805,32 @@ DIEFormalParameter::GetLocationDescription() } +status_t +DIEFormalParameter::AddAttribute_abstract_origin(uint16 attributeName, + const AttributeValue& value) +{ + fAbstractOrigin = value.reference; + return B_OK; +} + + +status_t +DIEFormalParameter::AddAttribute_const_value(uint16 attributeName, + const AttributeValue& value) +{ + return SetConstantAttributeValue(fValue, value); +} + + +status_t +DIEFormalParameter::AddAttribute_type(uint16 attributeName, + const AttributeValue& value) +{ + fType = dynamic_cast(value.reference); + return fType != NULL ? B_OK : B_BAD_DATA; +} + + // #pragma mark - DIEImportedDeclaration @@ -844,6 +880,8 @@ DIELexicalBlock::Tag() const DIEMember::DIEMember() + : + fType(NULL) { } @@ -855,6 +893,15 @@ DIEMember::Tag() const } +status_t +DIEMember::AddAttribute_type(uint16 attributeName, + const AttributeValue& value) +{ + fType = dynamic_cast(value.reference); + return fType != NULL ? B_OK : B_BAD_DATA; +} + + // #pragma mark - DIEPointerType @@ -1118,6 +1165,8 @@ DIECommonInclusion::Tag() const DIEInheritance::DIEInheritance() + : + fType(NULL) { } @@ -1129,6 +1178,15 @@ DIEInheritance::Tag() const } +status_t +DIEInheritance::AddAttribute_type(uint16 attributeName, + const AttributeValue& value) +{ + fType = dynamic_cast(value.reference); + return fType != NULL ? B_OK : B_BAD_DATA; +} + + // #pragma mark - DIEInlinedSubroutine @@ -1297,6 +1355,8 @@ DIESubrangeType::AddAttribute_threads_scaled(uint16 attributeName, DIEWithStatement::DIEWithStatement() + : + fType(NULL) { } @@ -1315,6 +1375,15 @@ DIEWithStatement::GetLocationDescription() } +status_t +DIEWithStatement::AddAttribute_type(uint16 attributeName, + const AttributeValue& value) +{ + fType = dynamic_cast(value.reference); + return fType != NULL ? B_OK : B_BAD_DATA; +} + + // #pragma mark - DIEAccessDeclaration @@ -1424,6 +1493,8 @@ DIEConstType::Tag() const DIEConstant::DIEConstant() + : + fType(NULL) { } @@ -1435,6 +1506,23 @@ DIEConstant::Tag() const } +status_t +DIEConstant::AddAttribute_const_value(uint16 attributeName, + const AttributeValue& value) +{ + return SetConstantAttributeValue(fValue, value); +} + + +status_t +DIEConstant::AddAttribute_type(uint16 attributeName, + const AttributeValue& value) +{ + fType = dynamic_cast(value.reference); + return fType != NULL ? B_OK : B_BAD_DATA; +} + + // #pragma mark - DIEEnumerator @@ -1586,6 +1674,20 @@ DIESubprogram::AbstractOrigin() const } +status_t +DIESubprogram::AddChild(DebugInfoEntry* child) +{ + switch (child->Tag()) { + case DW_TAG_formal_parameter: + case DW_TAG_unspecified_parameters: + fParameters.Add(child); + return B_OK; + default: + return DIEDeclaredNamedBase::AddChild(child); + } +} + + status_t DIESubprogram::AddAttribute_low_pc(uint16 attributeName, const AttributeValue& value) @@ -1669,10 +1771,30 @@ DIESubprogram::AddAttribute_abstract_origin(uint16 attributeName, } +status_t +DIESubprogram::AddAttribute_frame_base(uint16 attributeName, + const AttributeValue& value) +{ + if (value.attributeClass == ATTRIBUTE_CLASS_LOCLISTPTR) { + fFrameBase.SetToLocationList(value.pointer); + return B_OK; + } + + if (value.attributeClass == ATTRIBUTE_CLASS_BLOCK) { + fFrameBase.SetToExpression(value.block.data, value.block.length); + return B_OK; + } + + return B_BAD_DATA; +} + + // #pragma mark - DIETemplateTypeParameter DIETemplateTypeParameter::DIETemplateTypeParameter() + : + fType(NULL) { } @@ -1684,10 +1806,21 @@ DIETemplateTypeParameter::Tag() const } +status_t +DIETemplateTypeParameter::AddAttribute_type(uint16 attributeName, + const AttributeValue& value) +{ + fType = dynamic_cast(value.reference); + return fType != NULL ? B_OK : B_BAD_DATA; +} + + // #pragma mark - DIETemplateValueParameter DIETemplateValueParameter::DIETemplateValueParameter() + : + fType(NULL) { } @@ -1699,10 +1832,29 @@ DIETemplateValueParameter::Tag() const } +status_t +DIETemplateValueParameter::AddAttribute_const_value(uint16 attributeName, + const AttributeValue& value) +{ + return SetConstantAttributeValue(fValue, value); +} + + +status_t +DIETemplateValueParameter::AddAttribute_type(uint16 attributeName, + const AttributeValue& value) +{ + fType = dynamic_cast(value.reference); + return fType != NULL ? B_OK : B_BAD_DATA; +} + + // #pragma mark - DIEThrownType DIEThrownType::DIEThrownType() + : + fType(NULL) { } @@ -1714,6 +1866,15 @@ DIEThrownType::Tag() const } +status_t +DIEThrownType::AddAttribute_type(uint16 attributeName, + const AttributeValue& value) +{ + fType = dynamic_cast(value.reference); + return fType != NULL ? B_OK : B_BAD_DATA; +} + + // #pragma mark - DIETryBlock @@ -1733,6 +1894,8 @@ DIETryBlock::Tag() const DIEVariantPart::DIEVariantPart() + : + fType(NULL) { } @@ -1744,10 +1907,21 @@ DIEVariantPart::Tag() const } +status_t +DIEVariantPart::AddAttribute_type(uint16 attributeName, + const AttributeValue& value) +{ + fType = dynamic_cast(value.reference); + return fType != NULL ? B_OK : B_BAD_DATA; +} + + // #pragma mark - DIEVariable DIEVariable::DIEVariable() + : + fType(NULL) { } @@ -1766,6 +1940,23 @@ DIEVariable::GetLocationDescription() } +status_t +DIEVariable::AddAttribute_const_value(uint16 attributeName, + const AttributeValue& value) +{ + return SetConstantAttributeValue(fValue, value); +} + + +status_t +DIEVariable::AddAttribute_type(uint16 attributeName, + const AttributeValue& value) +{ + fType = dynamic_cast(value.reference); + return fType != NULL ? B_OK : B_BAD_DATA; +} + + // #pragma mark - DIEVolatileType diff --git a/src/apps/debugger/dwarf/DebugInfoEntries.h b/src/apps/debugger/dwarf/DebugInfoEntries.h index 3a57e0ddfe..f538984ace 100644 --- a/src/apps/debugger/dwarf/DebugInfoEntries.h +++ b/src/apps/debugger/dwarf/DebugInfoEntries.h @@ -241,6 +241,8 @@ class DIEModifiedType : public DIEType { public: DIEModifiedType(); + DIEType* GetType() const { return fType; } + virtual status_t AddAttribute_type(uint16 attributeName, const AttributeValue& value); @@ -301,6 +303,8 @@ class DIEDerivedType : public DIEDeclaredType { public: DIEDerivedType(); + DIEType* GetType() const { return fType; } + virtual status_t AddAttribute_type(uint16 attributeName, const AttributeValue& value); @@ -317,6 +321,9 @@ public: virtual DebugInfoEntry* Specification() const; + const DebugInfoEntryList& DataMembers() const + { return fDataMembers; } + virtual status_t AddChild(DebugInfoEntry* child); virtual status_t AddAttribute_byte_size(uint16 attributeName, @@ -453,6 +460,8 @@ public: class DIEEntryPoint : public DebugInfoEntry { public: +// TODO: Maybe introduce a common base class for DIEEntryPoint and +// DIESubprogram. DIEEntryPoint(); virtual uint16 Tag() const; @@ -504,21 +513,35 @@ public: virtual uint16 Tag() const; + virtual DebugInfoEntry* AbstractOrigin() const; virtual LocationDescription* GetLocationDescription(); + DIEType* GetType() const { return fType; } + + const ConstantAttributeValue* ConstValue() const + { return &fValue; } + + virtual status_t AddAttribute_abstract_origin( + uint16 attributeName, + const AttributeValue& value); + virtual status_t AddAttribute_const_value(uint16 attributeName, + const AttributeValue& value); + virtual status_t AddAttribute_type(uint16 attributeName, + const AttributeValue& value); + // TODO: -// DW_AT_abstract_origin // DW_AT_artificial -// DW_AT_const_value // DW_AT_default_value // DW_AT_endianity // DW_AT_is_optional // DW_AT_segment -// DW_AT_type // DW_AT_variable_parameter private: LocationDescription fLocationDescription; + DebugInfoEntry* fAbstractOrigin; + DIEType* fType; + ConstantAttributeValue fValue; }; @@ -569,14 +592,20 @@ public: virtual uint16 Tag() const; + DIEType* GetType() const { return fType; } + + virtual status_t AddAttribute_type(uint16 attributeName, + const AttributeValue& value); + // TODO: // DW_AT_bit_offset // DW_AT_bit_size // DW_AT_byte_size // DW_AT_data_member_location // DW_AT_mutable -// DW_AT_type +private: + DIEType* fType; }; @@ -738,11 +767,18 @@ public: virtual uint16 Tag() const; + DIEType* GetType() const { return fType; } + + virtual status_t AddAttribute_type(uint16 attributeName, + const AttributeValue& value); + // TODO: // DW_AT_accessibility // DW_AT_data_member_location -// DW_AT_type // DW_AT_virtuality + +private: + DIEType* fType; }; @@ -857,8 +893,13 @@ public: virtual uint16 Tag() const; + DIEType* GetType() const { return fType; } + virtual LocationDescription* GetLocationDescription(); + virtual status_t AddAttribute_type(uint16 attributeName, + const AttributeValue& value); + // TODO: // DW_AT_accessibility // DW_AT_address_class @@ -867,10 +908,10 @@ public: // DW_AT_low_pc // DW_AT_ranges // DW_AT_segment -// DW_AT_type // DW_AT_visibility private: + DIEType* fType; LocationDescription fLocationDescription; }; @@ -889,6 +930,15 @@ public: virtual uint16 Tag() const; + const DynamicAttributeValue* ByteSize() const + { return &fByteSize; } + const DynamicAttributeValue* BitOffset() const + { return &fBitOffset; } + const DynamicAttributeValue* BitSize() const + { return &fBitSize; } + uint8 Encoding() const { return fEncoding; } + uint8 Endianity() const { return fEndianity; } + virtual status_t AddAttribute_encoding(uint16 attributeName, const AttributeValue& value); virtual status_t AddAttribute_byte_size(uint16 attributeName, @@ -947,12 +997,24 @@ public: virtual uint16 Tag() const; + DIEType* GetType() const { return fType; } + + const ConstantAttributeValue* ConstValue() const + { return &fValue; } + + virtual status_t AddAttribute_const_value(uint16 attributeName, + const AttributeValue& value); + virtual status_t AddAttribute_type(uint16 attributeName, + const AttributeValue& value); + // TODO: -// DW_AT_const_value // DW_AT_endianity // DW_AT_external // DW_AT_start_scope -// DW_AT_type + +private: + DIEType* fType; + ConstantAttributeValue fValue; }; @@ -962,6 +1024,9 @@ public: virtual uint16 Tag() const; + const ConstantAttributeValue* ConstValue() const + { return &fValue; } + virtual status_t AddAttribute_const_value(uint16 attributeName, const AttributeValue& value); @@ -1042,9 +1107,15 @@ public: target_addr_t LowPC() const { return fLowPC; } target_addr_t HighPC() const { return fHighPC; } + const LocationDescription* FrameBase() const { return &fFrameBase; } + + const DebugInfoEntryList Parameters() const { return fParameters; } + bool IsPrototyped() const { return fPrototyped; } uint8 Inline() const { return fInline; } + virtual status_t AddChild(DebugInfoEntry* child); + virtual status_t AddAttribute_low_pc(uint16 attributeName, const AttributeValue& value); virtual status_t AddAttribute_high_pc(uint16 attributeName, @@ -1064,33 +1135,35 @@ public: virtual status_t AddAttribute_abstract_origin( uint16 attributeName, const AttributeValue& value); + virtual status_t AddAttribute_frame_base( + uint16 attributeName, + const AttributeValue& value); protected: + DebugInfoEntryList fParameters; target_addr_t fLowPC; target_addr_t fHighPC; off_t fAddressRangesOffset; DIESubprogram* fSpecification; DIESubprogram* fAbstractOrigin; DIEType* fReturnType; + LocationDescription fFrameBase; uint8 fAddressClass; bool fPrototyped; uint8 fInline; // TODO: -// DW_AT_abstract_origin // DW_AT_artificial // DW_AT_calling_convention // DW_AT_elemental // DW_AT_entry_pc // DW_AT_explicit // DW_AT_external -// DW_AT_frame_base // DW_AT_object_pointer // DW_AT_pure // DW_AT_recursive // DW_AT_return_addr // DW_AT_segment -// DW_AT_specification // DW_AT_start_scope // DW_AT_static_link // DW_AT_trampoline @@ -1105,8 +1178,13 @@ public: virtual uint16 Tag() const; -// TODO: -// DW_AT_type + DIEType* GetType() const { return fType; } + + virtual status_t AddAttribute_type(uint16 attributeName, + const AttributeValue& value); + +private: + DIEType* fType; }; @@ -1116,9 +1194,19 @@ public: virtual uint16 Tag() const; -// TODO: -// DW_AT_const_value -// DW_AT_type + DIEType* GetType() const { return fType; } + + const ConstantAttributeValue* ConstValue() const + { return &fValue; } + + virtual status_t AddAttribute_const_value(uint16 attributeName, + const AttributeValue& value); + virtual status_t AddAttribute_type(uint16 attributeName, + const AttributeValue& value); + +private: + DIEType* fType; + ConstantAttributeValue fValue; }; @@ -1128,11 +1216,18 @@ public: virtual uint16 Tag() const; + DIEType* GetType() const { return fType; } + + virtual status_t AddAttribute_type(uint16 attributeName, + const AttributeValue& value); + // TODO: // DW_AT_allocated // DW_AT_associated // DW_AT_data_location -// DW_AT_type + +private: + DIEType* fType; }; @@ -1157,12 +1252,19 @@ public: virtual uint16 Tag() const; + DIEType* GetType() const { return fType; } + + virtual status_t AddAttribute_type(uint16 attributeName, + const AttributeValue& value); + // TODO: // DW_AT_abstract_origin // DW_AT_accessibility // DW_AT_declaration // DW_AT_discr -// DW_AT_type + +private: + DIEType* fType; }; @@ -1174,18 +1276,28 @@ public: virtual LocationDescription* GetLocationDescription(); + DIEType* GetType() const { return fType; } + + const ConstantAttributeValue* ConstValue() const + { return &fValue; } + + virtual status_t AddAttribute_const_value(uint16 attributeName, + const AttributeValue& value); + virtual status_t AddAttribute_type(uint16 attributeName, + const AttributeValue& value); + // TODO: // DW_AT_abstract_origin -// DW_AT_const_value // DW_AT_endianity // DW_AT_external // DW_AT_segment // DW_AT_specification // DW_AT_start_scope -// DW_AT_type private: LocationDescription fLocationDescription; + ConstantAttributeValue fValue; + DIEType* fType; }; diff --git a/src/apps/debugger/dwarf/DebugInfoEntry.cpp b/src/apps/debugger/dwarf/DebugInfoEntry.cpp index 792585b383..9b9b84c79e 100644 --- a/src/apps/debugger/dwarf/DebugInfoEntry.cpp +++ b/src/apps/debugger/dwarf/DebugInfoEntry.cpp @@ -202,7 +202,6 @@ DebugInfoEntry::AddAttribute_location(uint16 attributeName, return B_OK; } return B_BAD_DATA; - } return ATTRIBUTE_NOT_HANDLED; diff --git a/src/apps/debugger/dwarf/DwarfExpressionEvaluator.cpp b/src/apps/debugger/dwarf/DwarfExpressionEvaluator.cpp index 51cbdaf8b7..db45f52cf6 100644 --- a/src/apps/debugger/dwarf/DwarfExpressionEvaluator.cpp +++ b/src/apps/debugger/dwarf/DwarfExpressionEvaluator.cpp @@ -17,6 +17,7 @@ #include "DataReader.h" #include "Dwarf.h" #include "DwarfTargetInterface.h" +#include "ValueLocation.h" // number of elements to increase the stack capacity when the stack is full @@ -34,7 +35,7 @@ static const uint32 kMaxOperationCount = 10000; DwarfExpressionEvaluationContext::DwarfExpressionEvaluationContext( - DwarfTargetInterface* targetInterface, uint8 addressSize) + const DwarfTargetInterface* targetInterface, uint8 addressSize) : fTargetInterface(targetInterface), fAddressSize(addressSize) @@ -51,6 +52,13 @@ DwarfExpressionEvaluationContext::~DwarfExpressionEvaluationContext() struct DwarfExpressionEvaluator::EvaluationException { + const char* message; + + EvaluationException(const char* message) + : + message(message) + { + } }; @@ -61,7 +69,7 @@ void DwarfExpressionEvaluator::_AssertMinStackSize(size_t size) const { if (fStackSize < size) - throw EvaluationException(); + throw EvaluationException("pop from empty stack"); } @@ -71,7 +79,7 @@ DwarfExpressionEvaluator::_Push(target_addr_t value) // resize the stack, if we hit the capacity if (fStackSize == fStackCapacity) { if (fStackCapacity >= kMaxStackCapacity) - throw EvaluationException(); + throw EvaluationException("stack overflow"); size_t newCapacity = fStackCapacity + kStackCapacityIncrement; target_addr_t* newStack = (target_addr_t*)realloc(fStack, @@ -113,12 +121,11 @@ DwarfExpressionEvaluator::~DwarfExpressionEvaluator() status_t -DwarfExpressionEvaluator::Evaluate(const void* expression, size_t size) +DwarfExpressionEvaluator::Push(target_addr_t value) { - fDataReader.SetTo(expression, size, fContext->AddressSize()); - try { - return _Evaluate(); + _Push(value); + return B_OK; } catch (const EvaluationException& exception) { return B_BAD_VALUE; } catch (const std::bad_alloc& exception) { @@ -128,8 +135,122 @@ DwarfExpressionEvaluator::Evaluate(const void* expression, size_t size) status_t -DwarfExpressionEvaluator::_Evaluate() +DwarfExpressionEvaluator::Evaluate(const void* expression, size_t size, + target_addr_t& _result) { + fDataReader.SetTo(expression, size, fContext->AddressSize()); + + try { + status_t error = _Evaluate(NULL); + if (error != B_OK) + return error; + _result = _Pop(); + return B_OK; + } catch (const EvaluationException& exception) { +printf("DwarfExpressionEvaluator::Evaluate(): %s\n", exception.message); + return B_BAD_VALUE; + } catch (const std::bad_alloc& exception) { + return B_NO_MEMORY; + } +} + + +status_t +DwarfExpressionEvaluator::EvaluateLocation(const void* expression, size_t size, + ValueLocation& _location) +{ + _location.Clear(); + + // the empty expression is a valid one + if (size == 0) { + ValuePieceLocation piece; + piece.SetToUnknown(); + piece.SetSize(0); + return _location.AddPiece(piece) ? B_OK : B_NO_MEMORY; + } + + fDataReader.SetTo(expression, size, fContext->AddressSize()); + + // parse the first (and maybe only) expression + try { + ValuePieceLocation piece; + status_t error = _Evaluate(&piece); + if (error != B_OK) + return error; + + // if that's all, it's only a simple expression without composition + if (fDataReader.BytesRemaining() == 0) { + if (!piece.IsValid()) + piece.SetToMemory(_Pop()); + piece.SetSize(0); + return _location.AddPiece(piece) ? B_OK : B_NO_MEMORY; + } + + // there's more, so it must be a composition operator + uint8 opcode = fDataReader.Read(0); + if (opcode == DW_OP_piece) { + piece.SetSize(fDataReader.ReadUnsignedLEB128(0)); + } else if (opcode == DW_OP_bit_piece) { + uint64 bitSize = fDataReader.ReadUnsignedLEB128(0); + piece.SetSize(bitSize, fDataReader.ReadUnsignedLEB128(0)); + } else + return B_BAD_DATA; + + // If there's a composition operator, there must be at least two + // simple expressions, so this must not be the end. + if (fDataReader.BytesRemaining() == 0) + return B_BAD_DATA; + } catch (const EvaluationException& exception) { +printf("DwarfExpressionEvaluator::EvaluateLocation(): %s\n", exception.message); + return B_BAD_VALUE; + } catch (const std::bad_alloc& exception) { + return B_NO_MEMORY; + } + + // parse subsequent expressions (at least one) + while (fDataReader.BytesRemaining() > 0) { + // Restrict the data reader to the remaining bytes to prevent jumping + // back. + fDataReader.SetTo(fDataReader.Data(), fDataReader.BytesRemaining(), + fDataReader.AddressSize()); + + try { + ValuePieceLocation piece; + status_t error = _Evaluate(&piece); + if (error != B_OK) + return error; + + if (!piece.IsValid()) + piece.SetToMemory(_Pop()); + + // each expression must be followed by a composition operator + if (fDataReader.BytesRemaining() == 0) + return B_BAD_DATA; + + uint8 opcode = fDataReader.Read(0); + if (opcode == DW_OP_piece) { + piece.SetSize(fDataReader.ReadUnsignedLEB128(0)); + } else if (opcode == DW_OP_bit_piece) { + uint64 bitSize = fDataReader.ReadUnsignedLEB128(0); + piece.SetSize(bitSize, fDataReader.ReadUnsignedLEB128(0)); + } else + return B_BAD_DATA; + } catch (const EvaluationException& exception) { +printf("DwarfExpressionEvaluator::EvaluateLocation(): %s\n", exception.message); + return B_BAD_VALUE; + } catch (const std::bad_alloc& exception) { + return B_NO_MEMORY; + } + } + + return B_OK; +} + + +status_t +DwarfExpressionEvaluator::_Evaluate(ValuePieceLocation* _piece) +{ +printf("DwarfExpressionEvaluator::_Evaluate()\n"); uint32 operationsExecuted = 0; while (fDataReader.BytesRemaining() > 0) { @@ -137,51 +258,66 @@ DwarfExpressionEvaluator::_Evaluate() switch (opcode) { case DW_OP_addr: +printf(" DW_OP_addr\n"); _Push(fDataReader.ReadAddress(0)); break; case DW_OP_const1u: +printf(" DW_OP_const1u\n"); _Push(fDataReader.Read(0)); break; case DW_OP_const1s: +printf(" DW_OP_const1s\n"); _Push(fDataReader.Read(0)); break; case DW_OP_const2u: +printf(" DW_OP_const2u\n"); _Push(fDataReader.Read(0)); break; case DW_OP_const2s: +printf(" DW_OP_const2s\n"); _Push(fDataReader.Read(0)); break; case DW_OP_const4u: +printf(" DW_OP_const4u\n"); _Push(fDataReader.Read(0)); break; case DW_OP_const4s: +printf(" DW_OP_const4s\n"); _Push(fDataReader.Read(0)); break; case DW_OP_const8u: +printf(" DW_OP_const8u\n"); _Push(fDataReader.Read(0)); break; case DW_OP_const8s: +printf(" DW_OP_const8s\n"); _Push(fDataReader.Read(0)); break; case DW_OP_constu: +printf(" DW_OP_constu\n"); _Push(fDataReader.ReadUnsignedLEB128(0)); break; case DW_OP_consts: +printf(" DW_OP_consts\n"); _Push(fDataReader.ReadSignedLEB128(0)); break; case DW_OP_dup: +printf(" DW_OP_dup\n"); _AssertMinStackSize(1); _Push(fStack[fStackSize - 1]); break; case DW_OP_drop: +printf(" DW_OP_drop\n"); _Pop(); break; case DW_OP_over: +printf(" DW_OP_over\n"); _AssertMinStackSize(1); _Push(fStack[fStackSize - 2]); break; case DW_OP_pick: { +printf(" DW_OP_pick\n"); uint8 index = fDataReader.Read(0); _AssertMinStackSize(index + 1); _Push(fStack[fStackSize - index - 1]); @@ -189,12 +325,14 @@ DwarfExpressionEvaluator::_Evaluate() } case DW_OP_swap: { +printf(" DW_OP_swap\n"); _AssertMinStackSize(2); std::swap(fStack[fStackSize - 1], fStack[fStackSize - 2]); break; } case DW_OP_rot: { +printf(" DW_OP_rot\n"); _AssertMinStackSize(3); target_addr_t tmp = fStack[fStackSize - 1]; fStack[fStackSize - 1] = fStack[fStackSize - 2]; @@ -204,20 +342,25 @@ DwarfExpressionEvaluator::_Evaluate() } case DW_OP_deref: +printf(" DW_OP_deref\n"); _DereferenceAddress(fContext->AddressSize()); break; case DW_OP_deref_size: +printf(" DW_OP_deref_size\n"); _DereferenceAddress(fDataReader.Read(0)); break; case DW_OP_xderef: +printf(" DW_OP_xderef\n"); _DereferenceAddressSpaceAddress(fContext->AddressSize()); break; case DW_OP_xderef_size: +printf(" DW_OP_xderef_size\n"); _DereferenceAddressSpaceAddress(fDataReader.Read(0)); break; case DW_OP_abs: { +printf(" DW_OP_abs\n"); target_addr_t value = _Pop(); if (fContext->AddressSize() == 4) { int32 signedValue = (int32)value; @@ -229,10 +372,12 @@ DwarfExpressionEvaluator::_Evaluate() break; } case DW_OP_and: +printf(" DW_OP_and\n"); _Push(_Pop() & _Pop()); break; case DW_OP_div: { +printf(" DW_OP_div\n"); int64 top = (int64)_Pop(); int64 second = (int64)_Pop(); _Push(top != 0 ? second / top : 0); @@ -240,12 +385,14 @@ DwarfExpressionEvaluator::_Evaluate() } case DW_OP_minus: { +printf(" DW_OP_minus\n"); target_addr_t top = _Pop(); _Push(_Pop() - top); break; } case DW_OP_mod: { +printf(" DW_OP_mod\n"); // While the specs explicitly speak of signed integer division // for "div", nothing is mentioned for "mod". target_addr_t top = _Pop(); @@ -254,10 +401,12 @@ DwarfExpressionEvaluator::_Evaluate() break; } case DW_OP_mul: +printf(" DW_OP_mul\n"); _Push(_Pop() * _Pop()); break; case DW_OP_neg: { +printf(" DW_OP_neg\n"); if (fContext->AddressSize() == 4) _Push(-(int32)_Pop()); else @@ -265,31 +414,38 @@ DwarfExpressionEvaluator::_Evaluate() break; } case DW_OP_not: +printf(" DW_OP_not\n"); _Push(~_Pop()); break; case DW_OP_or: +printf(" DW_OP_or\n"); _Push(_Pop() | _Pop()); break; case DW_OP_plus: +printf(" DW_OP_plus\n"); _Push(_Pop() + _Pop()); break; case DW_OP_plus_uconst: +printf(" DW_OP_plus_uconst\n"); _Push(_Pop() + fDataReader.ReadUnsignedLEB128(0)); break; case DW_OP_shl: { +printf(" DW_OP_shl\n"); target_addr_t top = _Pop(); _Push(_Pop() << top); break; } case DW_OP_shr: { +printf(" DW_OP_shr\n"); target_addr_t top = _Pop(); _Push(_Pop() >> top); break; } case DW_OP_shra: { +printf(" DW_OP_shra\n"); target_addr_t top = _Pop(); int64 second = (int64)_Pop(); _Push(second >= 0 ? second >> top : -(-second >> top)); @@ -297,105 +453,135 @@ DwarfExpressionEvaluator::_Evaluate() break; } case DW_OP_xor: +printf(" DW_OP_xor\n"); _Push(_Pop() ^ _Pop()); break; case DW_OP_bra: +printf(" DW_OP_bra\n"); if (_Pop() == 0) break; // fall through case DW_OP_skip: { +printf(" DW_OP_skip\n"); int16 offset = fDataReader.Read(0); if (offset >= 0 ? offset > fDataReader.BytesRemaining() : -offset > fDataReader.Offset()) { - throw EvaluationException(); + throw EvaluationException("bra/skip: invalid offset"); } fDataReader.SeekAbsolute(fDataReader.Offset() + offset); break; } case DW_OP_eq: +printf(" DW_OP_eq\n"); _Push(_Pop() == _Pop() ? 1 : 0); break; case DW_OP_ge: { +printf(" DW_OP_ge\n"); int64 top = (int64)_Pop(); _Push((int64)_Pop() >= top ? 1 : 0); break; } case DW_OP_gt: { +printf(" DW_OP_gt\n"); int64 top = (int64)_Pop(); _Push((int64)_Pop() > top ? 1 : 0); break; } case DW_OP_le: { +printf(" DW_OP_le\n"); int64 top = (int64)_Pop(); _Push((int64)_Pop() <= top ? 1 : 0); break; } case DW_OP_lt: { +printf(" DW_OP_lt\n"); int64 top = (int64)_Pop(); _Push((int64)_Pop() < top ? 1 : 0); break; } case DW_OP_ne: +printf(" DW_OP_ne\n"); _Push(_Pop() == _Pop() ? 1 : 0); break; case DW_OP_push_object_address: { +printf(" DW_OP_push_object_address\n"); target_addr_t address; if (!fContext->GetObjectAddress(address)) - throw EvaluationException(); + throw EvaluationException("failed to get object address"); _Push(address); break; } case DW_OP_call_frame_cfa: { +printf(" DW_OP_call_frame_cfa\n"); target_addr_t address; if (!fContext->GetFrameAddress(address)) - throw EvaluationException(); + throw EvaluationException("failed to get frame address"); _Push(address); break; } case DW_OP_fbreg: { +printf(" DW_OP_fbreg\n"); target_addr_t address; - if (!fContext->GetFrameBaseAddress(address)) - throw EvaluationException(); + if (!fContext->GetFrameBaseAddress(address)) { + throw EvaluationException( + "failed to get frame base address"); + } _Push(address + fDataReader.ReadSignedLEB128(0)); break; } case DW_OP_form_tls_address: { +printf(" DW_OP_form_tls_address\n"); target_addr_t address; if (!fContext->GetTLSAddress(_Pop(), address)) - throw EvaluationException(); + throw EvaluationException("failed to get tls address"); _Push(address); break; } case DW_OP_regx: - _PushRegister(fDataReader.ReadUnsignedLEB128(0), 0); - break; + { +printf(" DW_OP_regx\n"); + if (_piece == NULL) { + throw EvaluationException( + "DW_OP_regx in non-location expression"); + } + uint32 reg = fDataReader.ReadUnsignedLEB128(0); + if (fDataReader.HasOverflow()) + throw EvaluationException("unexpected end of expression"); + _piece->SetToRegister(reg); + return B_OK; + } + case DW_OP_bregx: { +printf(" DW_OP_bregx\n"); uint32 reg = fDataReader.ReadUnsignedLEB128(0); _PushRegister(reg, fDataReader.ReadSignedLEB128(0)); break; } case DW_OP_call2: +printf(" DW_OP_call2\n"); _Call(fDataReader.Read(0), true); break; case DW_OP_call4: +printf(" DW_OP_call4\n"); _Call(fDataReader.Read(0), true); break; case DW_OP_call_ref: +printf(" DW_OP_call_ref\n"); if (fContext->AddressSize() == 4) _Call(fDataReader.Read(0), false); else @@ -404,19 +590,33 @@ DwarfExpressionEvaluator::_Evaluate() case DW_OP_piece: case DW_OP_bit_piece: -// TODO:... - break; + // are handled in EvaluateLocation() + if (_piece == NULL) + return B_BAD_DATA; + + fDataReader.SeekAbsolute(fDataReader.Offset() - 1); + // put back the operation + return B_OK; case DW_OP_nop: +printf(" DW_OP_nop\n"); break; default: if (opcode >= DW_OP_lit0 && opcode <= DW_OP_lit31) { +printf(" DW_OP_lit%u\n", opcode - DW_OP_lit0); _Push(opcode - DW_OP_lit0); } else if (opcode >= DW_OP_reg0 && opcode <= DW_OP_reg31) { - _PushRegister(opcode - DW_OP_reg0, 0); +printf(" DW_OP_reg%u\n", opcode - DW_OP_reg0); + if (_piece == NULL) { + throw EvaluationException( + "DW_OP_reg* in non-location expression"); + } + _piece->SetToRegister(opcode - DW_OP_reg0); + return B_OK; } else if (opcode >= DW_OP_breg0 && opcode <= DW_OP_breg31) { - _PushRegister(opcode - DW_OP_reg0, +printf(" DW_OP_breg%u\n", opcode - DW_OP_breg0); + _PushRegister(opcode - DW_OP_breg0, fDataReader.ReadSignedLEB128(0)); } else { printf("DwarfExpressionEvaluator::_Evaluate(): unsupported " @@ -455,14 +655,14 @@ DwarfExpressionEvaluator::_DereferenceAddress(uint8 addressSize) } // fall through default: - throw EvaluationException(); + throw EvaluationException("invalid dereference size"); } target_addr_t address = _Pop(); BVariant value; if (!fContext->TargetInterface()->ReadValueFromMemory(address, valueType, value)) { - throw EvaluationException(); + throw EvaluationException("failed to read memory"); } _Push(value.ToUInt64()); @@ -490,7 +690,7 @@ DwarfExpressionEvaluator::_DereferenceAddressSpaceAddress(uint8 addressSize) } // fall through default: - throw EvaluationException(); + throw EvaluationException("invalid dereference size"); } target_addr_t address = _Pop(); @@ -498,7 +698,7 @@ DwarfExpressionEvaluator::_DereferenceAddressSpaceAddress(uint8 addressSize) BVariant value; if (!fContext->TargetInterface()->ReadValueFromMemory(addressSpace, address, valueType, value)) { - throw EvaluationException(); + throw EvaluationException("failed to read memory"); } _Push(value.ToUInt64()); @@ -510,7 +710,7 @@ DwarfExpressionEvaluator::_PushRegister(uint32 reg, target_addr_t offset) { BVariant value; if (!fContext->TargetInterface()->GetRegisterValue(reg, value)) - throw EvaluationException(); + throw EvaluationException("failed to get register"); _Push(value.ToUInt64()); } @@ -520,13 +720,13 @@ void DwarfExpressionEvaluator::_Call(uint64 offset, bool local) { if (fDataReader.HasOverflow()) - throw EvaluationException(); + throw EvaluationException("unexpected end of expression"); // get the expression to "call" const void* block; off_t size; if (fContext->GetCallTarget(offset, local, block, size) != B_OK) - throw EvaluationException(); + throw EvaluationException("failed to get call target"); // no expression is OK, then this is just a no-op if (block == NULL) @@ -540,7 +740,8 @@ DwarfExpressionEvaluator::_Call(uint64 offset, bool local) // and evaluate it try { - _Evaluate(); + if (_Evaluate(NULL) != B_OK) + throw EvaluationException("call failed"); } catch (...) { fDataReader = savedReader; throw; diff --git a/src/apps/debugger/dwarf/DwarfExpressionEvaluator.h b/src/apps/debugger/dwarf/DwarfExpressionEvaluator.h index 32c8aa915b..cc337724a5 100644 --- a/src/apps/debugger/dwarf/DwarfExpressionEvaluator.h +++ b/src/apps/debugger/dwarf/DwarfExpressionEvaluator.h @@ -11,16 +11,18 @@ class DwarfTargetInterface; +class ValueLocation; +struct ValuePieceLocation; class DwarfExpressionEvaluationContext { public: DwarfExpressionEvaluationContext( - DwarfTargetInterface* targetInterface, + const DwarfTargetInterface* targetInterface, uint8 addressSize); virtual ~DwarfExpressionEvaluationContext(); - DwarfTargetInterface* TargetInterface() const + const DwarfTargetInterface* TargetInterface() const { return fTargetInterface; } uint8 AddressSize() const { return fAddressSize; } @@ -38,8 +40,8 @@ public: // block, when the entry doesn't have a // location attribute -private: - DwarfTargetInterface* fTargetInterface; +protected: + const DwarfTargetInterface* fTargetInterface; uint8 fAddressSize; }; @@ -50,10 +52,12 @@ public: DwarfExpressionEvaluationContext* context); ~DwarfExpressionEvaluator(); - void SetObjectAddress(target_addr_t address); - void SetFrameAddress(target_addr_t address); + status_t Push(target_addr_t value); - status_t Evaluate(const void* expression, size_t size); + status_t Evaluate(const void* expression, size_t size, + target_addr_t& _result); + status_t EvaluateLocation(const void* expression, + size_t size, ValueLocation& _location); private: struct EvaluationException; @@ -64,7 +68,7 @@ private: inline void _Push(target_addr_t value); inline target_addr_t _Pop(); - status_t _Evaluate(); + status_t _Evaluate(ValuePieceLocation* _piece); void _DereferenceAddress(uint8 addressSize); void _DereferenceAddressSpaceAddress( uint8 addressSize); diff --git a/src/apps/debugger/dwarf/DwarfFile.cpp b/src/apps/debugger/dwarf/DwarfFile.cpp index 65b8c4130c..9e89f9babd 100644 --- a/src/apps/debugger/dwarf/DwarfFile.cpp +++ b/src/apps/debugger/dwarf/DwarfFile.cpp @@ -17,10 +17,12 @@ #include "CfaContext.h" #include "CompilationUnit.h" #include "DataReader.h" +#include "DwarfExpressionEvaluator.h" #include "DwarfTargetInterface.h" #include "ElfFile.h" #include "TagNames.h" #include "TargetAddressRangeList.h" +#include "Variant.h" DwarfFile::DwarfFile() @@ -33,6 +35,7 @@ DwarfFile::DwarfFile() fDebugRangesSection(NULL), fDebugLineSection(NULL), fDebugFrameSection(NULL), + fDebugLocationSection(NULL), fCompilationUnits(20, true), fCurrentCompilationUnit(NULL), fFinished(false), @@ -53,6 +56,7 @@ DwarfFile::~DwarfFile() fElfFile->PutSection(fDebugRangesSection); fElfFile->PutSection(fDebugLineSection); fElfFile->PutSection(fDebugFrameSection); + fElfFile->PutSection(fDebugLocationSection); delete fElfFile; } @@ -91,6 +95,7 @@ DwarfFile::Load(const char* fileName) fDebugRangesSection = fElfFile->GetSection(".debug_ranges"); fDebugLineSection = fElfFile->GetSection(".debug_line"); fDebugFrameSection = fElfFile->GetSection(".debug_frame"); + fDebugLocationSection = fElfFile->GetSection(".debug_loc"); // iterate through the debug info section DataReader dataReader(fDebugInfoSection->Data(), @@ -270,7 +275,8 @@ DwarfFile::ResolveRangeList(CompilationUnit* unit, uint64 offset) const status_t -DwarfFile::UnwindCallFrame(CompilationUnit* unit, target_addr_t location, +DwarfFile::UnwindCallFrame(CompilationUnit* unit, + DIESubprogram* subprogramEntry, target_addr_t location, const DwarfTargetInterface* inputInterface, DwarfTargetInterface* outputInterface, target_addr_t& _framePointer) { @@ -365,8 +371,16 @@ printf(" found row!\n"); break; } case CFA_CFA_RULE_EXPRESSION: -// TODO: Implement! - return B_UNSUPPORTED; + { + error = EvaluateExpression(unit, subprogramEntry, + cfaCfaRule->Expression().block, + cfaCfaRule->Expression().size, + inputInterface, location, 0, 0, false, + frameAddress); + if (error != B_OK) + return error; + break; + } case CFA_CFA_RULE_UNDEFINED: default: return B_BAD_VALUE; @@ -421,13 +435,35 @@ printf(" -> CFA_RULE_REGISTER\n"); break; } case CFA_RULE_LOCATION_EXPRESSION: + { printf(" -> CFA_RULE_LOCATION_EXPRESSION\n"); -// TODO:... + target_addr_t address; + error = EvaluateExpression(unit, subprogramEntry, + rule->Expression().block, + rule->Expression().size, + inputInterface, location, frameAddress, + frameAddress, true, address); + BVariant value; + if (error == B_OK + && inputInterface->ReadValueFromMemory(address, + valueType, value)) { + outputInterface->SetRegisterValue(i, value); + } break; + } case CFA_RULE_VALUE_EXPRESSION: + { printf(" -> CFA_RULE_VALUE_EXPRESSION\n"); -// TODO:... + target_addr_t value; + error = EvaluateExpression(unit, subprogramEntry, + rule->Expression().block, + rule->Expression().size, + inputInterface, location, frameAddress, + frameAddress, true, value); + if (error == B_OK) + outputInterface->SetRegisterValue(i, value); break; + } case CFA_RULE_UNDEFINED: printf(" -> CFA_RULE_UNDEFINED\n"); default: @@ -447,6 +483,275 @@ printf(" -> CFA_RULE_UNDEFINED\n"); } +struct DwarfFile::ExpressionEvaluationContext + : DwarfExpressionEvaluationContext { +public: + ExpressionEvaluationContext(DwarfFile* file, CompilationUnit* unit, + DIESubprogram* subprogramEntry, + const DwarfTargetInterface* targetInterface, + target_addr_t instructionPointer, target_addr_t objectPointer, + target_addr_t framePointer) + : + DwarfExpressionEvaluationContext(targetInterface, unit->AddressSize()), + fFile(file), + fUnit(unit), + fSubprogramEntry(subprogramEntry), + fInstructionPointer(instructionPointer), + fObjectPointer(objectPointer), + fFramePointer(framePointer), + fFrameBasePointer(0), + fFrameBaseEvaluated(false) + { + } + + virtual bool GetObjectAddress(target_addr_t& _address) + { + if (fObjectPointer == 0) + return false; + + _address = fObjectPointer; + return true; + } + + virtual bool GetFrameAddress(target_addr_t& _address) + { + _address = fFramePointer; + return true; + } + + virtual bool GetFrameBaseAddress(target_addr_t& _address) + { + if (fFrameBaseEvaluated) { + if (fFrameBasePointer == 0) + return false; + + _address = fFrameBasePointer; + return true; + } + + // set flag already to prevent recursion for a buggy expression + fFrameBaseEvaluated = true; + + // get the subprogram's frame base location + const LocationDescription* location = fSubprogramEntry->FrameBase(); + if (!location->IsValid()) + return B_BAD_VALUE; + + // get the expression + const void* expression; + off_t expressionLength; + status_t error = fFile->_GetLocationExpression(fUnit, location, + fInstructionPointer, expression, expressionLength); + if (error != B_OK) + return error; + + // evaluate the expression + DwarfExpressionEvaluator evaluator(this); + error = evaluator.Evaluate(expression, expressionLength, + fFrameBasePointer); + if (error != B_OK) + return false; +printf(" -> frame base: %llx\n", fFrameBasePointer); + _address = fFrameBasePointer; + return true; + } + + virtual bool GetTLSAddress(target_addr_t localAddress, + target_addr_t& _address) + { + // TODO:... + return false; + } + + virtual status_t GetCallTarget(uint64 offset, bool local, + const void*& _block, off_t& _size) + { + // resolve the entry + DebugInfoEntry* entry = fFile->_ResolveReference(fUnit, offset, local); + if (entry == NULL) + return B_ENTRY_NOT_FOUND; + + // get the location description + LocationDescription* location = entry->GetLocationDescription(); + if (location == NULL || !location->IsValid()) { + _block = NULL; + _size = 0; + return B_OK; + } + + // get the expression + return fFile->_GetLocationExpression(fUnit, location, + fInstructionPointer, _block, _size); + } + +private: + DwarfFile* fFile; + CompilationUnit* fUnit; + DIESubprogram* fSubprogramEntry; + target_addr_t fInstructionPointer; + target_addr_t fObjectPointer; + target_addr_t fFramePointer; + target_addr_t fFrameBasePointer; + bool fFrameBaseEvaluated; +}; + + +status_t +DwarfFile::EvaluateExpression(CompilationUnit* unit, + DIESubprogram* subprogramEntry, const void* expression, + off_t expressionLength, const DwarfTargetInterface* targetInterface, + target_addr_t instructionPointer, target_addr_t framePointer, + target_addr_t valueToPush, bool pushValue, target_addr_t& _result) +{ + ExpressionEvaluationContext context(this, unit, subprogramEntry, + targetInterface, instructionPointer, 0, framePointer); + DwarfExpressionEvaluator evaluator(&context); + + if (pushValue && evaluator.Push(valueToPush) != B_OK) + return B_NO_MEMORY; + + return evaluator.Evaluate(expression, expressionLength, _result); +} + + +status_t +DwarfFile::ResolveLocation(CompilationUnit* unit, + DIESubprogram* subprogramEntry, const LocationDescription* location, + const DwarfTargetInterface* targetInterface, + target_addr_t instructionPointer, target_addr_t objectPointer, + target_addr_t framePointer, ValueLocation& _result) +{ + // get the expression + const void* expression; + off_t expressionLength; + status_t error = _GetLocationExpression(unit, location, instructionPointer, + expression, expressionLength); + if (error != B_OK) + return error; + + // evaluate it + ExpressionEvaluationContext context(this, unit, subprogramEntry, + targetInterface, instructionPointer, objectPointer, framePointer); + DwarfExpressionEvaluator evaluator(&context); + return evaluator.EvaluateLocation(expression, expressionLength, _result); +} + + +status_t +DwarfFile::EvaluateConstantValue(CompilationUnit* unit, + DIESubprogram* subprogramEntry, const ConstantAttributeValue* value, + const DwarfTargetInterface* targetInterface, + target_addr_t instructionPointer, target_addr_t framePointer, + BVariant& _result) +{ + if (!value->IsValid()) + return B_BAD_VALUE; + + switch (value->attributeClass) { + case ATTRIBUTE_CLASS_CONSTANT: + _result.SetTo(value->constant); + return B_OK; + case ATTRIBUTE_CLASS_STRING: + _result.SetTo(value->string); + return B_OK; + case ATTRIBUTE_CLASS_BLOCK: + { + target_addr_t result; + status_t error = EvaluateExpression(unit, subprogramEntry, + value->block.data, value->block.length, targetInterface, + instructionPointer, framePointer, 0, false, result); + if (error != B_OK) + return error; + + _result.SetTo(result); + return B_OK; + } + default: + return B_BAD_VALUE; + } +} + + +status_t +DwarfFile::EvaluateDynamicValue(CompilationUnit* unit, + DIESubprogram* subprogramEntry, const DynamicAttributeValue* value, + const DwarfTargetInterface* targetInterface, + target_addr_t instructionPointer, target_addr_t framePointer, + BVariant& _result) +{ + if (!value->IsValid()) + return B_BAD_VALUE; + + switch (value->attributeClass) { + case ATTRIBUTE_CLASS_CONSTANT: + _result.SetTo(value->constant); + return B_OK; + + case ATTRIBUTE_CLASS_REFERENCE: + { + // TODO: The specs are a bit fuzzy on this one: "the value is a + // reference to another entity whose value is the value of the + // attribute". Supposedly that also means e.g. if the referenced + // entity is a variable, we should read the value of that variable. + // ATM we only check for the types that can have a DW_AT_const_value + // attribute and evaluate it, if present. + DebugInfoEntry* entry = value->reference; + if (entry == NULL) + return B_BAD_VALUE; + + const ConstantAttributeValue* constantValue = NULL; + + switch (entry->Tag()) { + case DW_TAG_constant: + constantValue = dynamic_cast(entry) + ->ConstValue(); + break; + case DW_TAG_enumerator: + constantValue = dynamic_cast(entry) + ->ConstValue(); + break; + case DW_TAG_formal_parameter: + constantValue = dynamic_cast(entry) + ->ConstValue(); + break; + case DW_TAG_template_value_parameter: + constantValue = dynamic_cast( + entry)->ConstValue(); + break; + case DW_TAG_variable: + constantValue = dynamic_cast(entry) + ->ConstValue(); + break; + default: + return B_BAD_VALUE; + } + + if (constantValue == NULL || !constantValue->IsValid()) + return B_BAD_VALUE; + + return EvaluateConstantValue(unit, subprogramEntry, constantValue, + targetInterface, instructionPointer, framePointer, _result); + } + + case ATTRIBUTE_CLASS_BLOCK: + { + target_addr_t result; + status_t error = EvaluateExpression(unit, subprogramEntry, + value->block.data, value->block.length, targetInterface, + instructionPointer, framePointer, 0, false, result); + if (error != B_OK) + return error; + + _result.SetTo(result); + return B_OK; + } + + default: + return B_BAD_VALUE; + } +} + + status_t DwarfFile::_ParseCompilationUnit(CompilationUnit* unit) { @@ -800,8 +1105,8 @@ DwarfFile::_ParseEntryAttributes(DataReader& dataReader, break; case ATTRIBUTE_CLASS_REFERENCE: if (entry != NULL) { - attributeValue.SetToReference(_ResolveReference(value, - localReference)); + attributeValue.SetToReference(_ResolveReference( + fCurrentCompilationUnit, value, localReference)); if (attributeValue.reference == NULL) { // gcc 2 apparently somtimes produces DW_AT_sibling // attributes pointing to the end of the sibling list. @@ -1372,11 +1677,84 @@ DwarfFile::_GetAbbreviationTable(off_t offset, AbbreviationTable*& _table) DebugInfoEntry* -DwarfFile::_ResolveReference(uint64 offset, bool localReference) const +DwarfFile::_ResolveReference(CompilationUnit* unit, uint64 offset, + bool localReference) const { if (localReference) - return fCurrentCompilationUnit->EntryForOffset(offset); + return unit->EntryForOffset(offset); // TODO: Implement program-global references! return NULL; } + + +status_t +DwarfFile::_GetLocationExpression(CompilationUnit* unit, + const LocationDescription* location, target_addr_t instructionPointer, + const void*& _expression, off_t& _length) const +{ + if (!location->IsValid()) + return B_BAD_VALUE; + + if (location->IsExpression()) { + _expression = location->expression.data; + _length = location->expression.length; + return B_OK; + } + + if (location->IsLocationList()) { + return _FindLocationExpression(unit, location->listOffset, + instructionPointer, _expression, _length); + } + + return B_BAD_VALUE; +} + + +status_t +DwarfFile::_FindLocationExpression(CompilationUnit* unit, uint64 offset, + target_addr_t address, const void*& _expression, off_t& _length) const +{ + if (unit == NULL) + return B_BAD_VALUE; + + if (fDebugLocationSection == NULL) + return B_ENTRY_NOT_FOUND; + + if (offset < 0 || offset >= (uint64)fDebugLocationSection->Size()) + return B_BAD_DATA; + + target_addr_t baseAddress = unit->AddressRangeBase(); + target_addr_t maxAddress = unit->MaxAddress(); + + DataReader dataReader((uint8*)fDebugLocationSection->Data() + offset, + fDebugLocationSection->Size() - offset, unit->AddressSize()); + while (true) { + target_addr_t start = dataReader.ReadAddress(0); + target_addr_t end = dataReader.ReadAddress(0); + if (dataReader.HasOverflow()) + return B_BAD_DATA; + + if (start == 0 && end == 0) + return B_ENTRY_NOT_FOUND; + + if (start == maxAddress) { + baseAddress = end; + continue; + } + + uint16 expressionLength = dataReader.Read(0); + const void* expression = dataReader.Data(); + if (!dataReader.Skip(expressionLength)) + return B_BAD_DATA; + + if (start == end) + continue; + + if (address >= start && address < end) { + _expression = expression; + _length = expressionLength; + return B_OK; + } + } +} diff --git a/src/apps/debugger/dwarf/DwarfFile.h b/src/apps/debugger/dwarf/DwarfFile.h index 27fb2cd889..0a6ae639b6 100644 --- a/src/apps/debugger/dwarf/DwarfFile.h +++ b/src/apps/debugger/dwarf/DwarfFile.h @@ -14,6 +14,7 @@ class AbbreviationEntry; class AbbreviationTable; +class BVariant; class CfaContext; class CompilationUnit; class DataReader; @@ -21,6 +22,7 @@ class DwarfTargetInterface; class ElfFile; class ElfSection; class TargetAddressRangeList; +class ValueLocation; class DwarfFile : public DoublyLinkedListLinkImpl { @@ -43,12 +45,48 @@ public: uint64 offset) const; status_t UnwindCallFrame(CompilationUnit* unit, + DIESubprogram* subprogramEntry, target_addr_t location, const DwarfTargetInterface* inputInterface, DwarfTargetInterface* outputInterface, target_addr_t& _framePointer); + status_t EvaluateExpression(CompilationUnit* unit, + DIESubprogram* subprogramEntry, + const void* expression, + off_t expressionLength, + const DwarfTargetInterface* targetInterface, + target_addr_t instructionPointer, + target_addr_t framePointer, + target_addr_t valueToPush, bool pushValue, + target_addr_t& _result); + status_t ResolveLocation(CompilationUnit* unit, + DIESubprogram* subprogramEntry, + const LocationDescription* location, + const DwarfTargetInterface* targetInterface, + target_addr_t instructionPointer, + target_addr_t objectPointer, + target_addr_t framePointer, + ValueLocation& _result); + + status_t EvaluateConstantValue(CompilationUnit* unit, + DIESubprogram* subprogramEntry, + const ConstantAttributeValue* value, + const DwarfTargetInterface* targetInterface, + target_addr_t instructionPointer, + target_addr_t framePointer, + BVariant& _result); + status_t EvaluateDynamicValue(CompilationUnit* unit, + DIESubprogram* subprogramEntry, + const DynamicAttributeValue* value, + const DwarfTargetInterface* targetInterface, + target_addr_t instructionPointer, + target_addr_t framePointer, + BVariant& _result); + private: + struct ExpressionEvaluationContext; + typedef DoublyLinkedList AbbreviationTableList; typedef BObjectList CompilationUnitList; @@ -75,10 +113,18 @@ private: status_t _GetAbbreviationTable(off_t offset, AbbreviationTable*& _table); - DebugInfoEntry* _ResolveReference(uint64 offset, - bool localReference) const; - TargetAddressRangeList* _ResolveRangeList(uint64 offset); - // returns reference + DebugInfoEntry* _ResolveReference(CompilationUnit* unit, + uint64 offset, bool localReference) const; + + status_t _GetLocationExpression(CompilationUnit* unit, + const LocationDescription* location, + target_addr_t instructionPointer, + const void*& _expression, + off_t& _length) const; + status_t _FindLocationExpression(CompilationUnit* unit, + uint64 offset, target_addr_t address, + const void*& _expression, + off_t& _length) const; private: char* fName; @@ -89,6 +135,7 @@ private: ElfSection* fDebugRangesSection; ElfSection* fDebugLineSection; ElfSection* fDebugFrameSection; + ElfSection* fDebugLocationSection; AbbreviationTableList fAbbreviationTables; DebugInfoEntryFactory fDebugInfoFactory; CompilationUnitList fCompilationUnits; diff --git a/src/apps/debugger/gui/team_window/RegisterView.cpp b/src/apps/debugger/gui/team_window/RegistersView.cpp similarity index 89% rename from src/apps/debugger/gui/team_window/RegisterView.cpp rename to src/apps/debugger/gui/team_window/RegistersView.cpp index 306b84c13c..9439faf16e 100644 --- a/src/apps/debugger/gui/team_window/RegisterView.cpp +++ b/src/apps/debugger/gui/team_window/RegistersView.cpp @@ -3,7 +3,7 @@ * Distributed under the terms of the MIT License. */ -#include "RegisterView.h" +#include "RegistersView.h" #include @@ -19,7 +19,7 @@ // #pragma mark - RegisterValueColumn -class RegisterView::RegisterValueColumn : public StringTableColumn { +class RegistersView::RegisterValueColumn : public StringTableColumn { public: RegisterValueColumn(int32 modelIndex, const char* title, float width, float minWidth, float maxWidth, uint32 truncate = B_TRUNCATE_MIDDLE, @@ -109,7 +109,7 @@ private: // #pragma mark - RegisterTableModel -class RegisterView::RegisterTableModel : public TableModel { +class RegistersView::RegisterTableModel : public TableModel { public: RegisterTableModel(Architecture* architecture) : @@ -167,13 +167,14 @@ private: }; -// #pragma mark - RegisterView +// #pragma mark - RegistersView -RegisterView::RegisterView(Architecture* architecture) +RegistersView::RegistersView(Architecture* architecture) : BGroupView(B_VERTICAL), fArchitecture(architecture), + fCpuState(NULL), fRegisterTable(NULL), fRegisterTableModel(NULL) { @@ -181,7 +182,7 @@ RegisterView::RegisterView(Architecture* architecture) } -RegisterView::~RegisterView() +RegistersView::~RegistersView() { SetCpuState(NULL); fRegisterTable->SetTableModel(NULL); @@ -189,10 +190,10 @@ RegisterView::~RegisterView() } -/*static*/ RegisterView* -RegisterView::Create(Architecture* architecture) +/*static*/ RegistersView* +RegistersView::Create(Architecture* architecture) { - RegisterView* self = new RegisterView(architecture); + RegistersView* self = new RegistersView(architecture); try { self->_Init(); @@ -206,7 +207,7 @@ RegisterView::Create(Architecture* architecture) void -RegisterView::SetCpuState(CpuState* cpuState) +RegistersView::SetCpuState(CpuState* cpuState) { if (cpuState == fCpuState) return; @@ -224,13 +225,13 @@ RegisterView::SetCpuState(CpuState* cpuState) void -RegisterView::TableRowInvoked(Table* table, int32 rowIndex) +RegistersView::TableRowInvoked(Table* table, int32 rowIndex) { } void -RegisterView::_Init() +RegistersView::_Init() { fRegisterTable = new Table("register list", 0, B_FANCY_BORDER); AddChild(fRegisterTable->ToView()); diff --git a/src/apps/debugger/gui/team_window/RegisterView.h b/src/apps/debugger/gui/team_window/RegistersView.h similarity index 68% rename from src/apps/debugger/gui/team_window/RegisterView.h rename to src/apps/debugger/gui/team_window/RegistersView.h index c570a5ef3c..bffb6f7fd7 100644 --- a/src/apps/debugger/gui/team_window/RegisterView.h +++ b/src/apps/debugger/gui/team_window/RegistersView.h @@ -2,8 +2,8 @@ * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. * Distributed under the terms of the MIT License. */ -#ifndef REGISTER_VIEW_H -#define REGISTER_VIEW_H +#ifndef REGISTERS_VIEW_H +#define REGISTERS_VIEW_H #include @@ -14,12 +14,12 @@ class Architecture; -class RegisterView : public BGroupView, private TableListener { +class RegistersView : public BGroupView, private TableListener { public: - RegisterView(Architecture* architecture); - ~RegisterView(); + RegistersView(Architecture* architecture); + ~RegistersView(); - static RegisterView* Create(Architecture* architecture); + static RegistersView* Create(Architecture* architecture); // throws void SetCpuState(CpuState* cpuState); @@ -42,4 +42,4 @@ private: }; -#endif // REGISTER_VIEW_H +#endif // REGISTERS_VIEW_H diff --git a/src/apps/debugger/gui/team_window/TeamWindow.cpp b/src/apps/debugger/gui/team_window/TeamWindow.cpp index c93e6aaf34..950477eec7 100644 --- a/src/apps/debugger/gui/team_window/TeamWindow.cpp +++ b/src/apps/debugger/gui/team_window/TeamWindow.cpp @@ -26,9 +26,10 @@ #include "Image.h" #include "ImageDebugInfo.h" #include "MessageCodes.h" -#include "RegisterView.h" +#include "RegistersView.h" #include "StackTrace.h" #include "StackTraceView.h" +#include "VariablesView.h" enum { @@ -57,7 +58,8 @@ TeamWindow::TeamWindow(TeamDebugModel* debugModel, Listener* listener) fThreadListView(NULL), fImageListView(NULL), fImageFunctionsView(NULL), - fRegisterView(NULL), + fVariablesView(NULL), + fRegistersView(NULL), fStackTraceView(NULL), fSourceView(NULL), fRunButton(NULL), @@ -386,11 +388,12 @@ TeamWindow::_Init() .Add(fImageFunctionsView = ImageFunctionsView::Create(this)); // add local variables tab - BView* tab = new BTextView("Variables"); + BView* tab = fVariablesView = VariablesView::Create(); fLocalsTabView->AddTab(tab); // add registers tab - tab = fRegisterView = RegisterView::Create(fDebugModel->GetArchitecture()); + tab = fRegistersView = RegistersView::Create( + fDebugModel->GetArchitecture()); fLocalsTabView->AddTab(tab); fRunButton->SetMessage(new BMessage(MSG_THREAD_RUN)); @@ -529,6 +532,7 @@ TeamWindow::_SetActiveStackFrame(StackFrame* frame) _UpdateCpuState(); fStackTraceView->SetStackFrame(fActiveStackFrame); + fVariablesView->SetStackFrame(fActiveStackFrame); fSourceView->SetStackFrame(fActiveStackFrame); } @@ -627,7 +631,7 @@ TeamWindow::_UpdateCpuState() cpuState = fActiveStackFrame->GetCpuState(); } - fRegisterView->SetCpuState(cpuState); + fRegistersView->SetCpuState(cpuState); } diff --git a/src/apps/debugger/gui/team_window/TeamWindow.h b/src/apps/debugger/gui/team_window/TeamWindow.h index 66da45954a..129068d2b5 100644 --- a/src/apps/debugger/gui/team_window/TeamWindow.h +++ b/src/apps/debugger/gui/team_window/TeamWindow.h @@ -22,9 +22,10 @@ class BButton; class BMenuBar; class BTabView; class Image; -class RegisterView; +class RegistersView; class SourceCode; class StackFrame; +class VariablesView; class TeamWindow : public BWindow, ThreadListView::Listener, @@ -119,7 +120,8 @@ private: ThreadListView* fThreadListView; ImageListView* fImageListView; ImageFunctionsView* fImageFunctionsView; - RegisterView* fRegisterView; + VariablesView* fVariablesView; + RegistersView* fRegistersView; StackTraceView* fStackTraceView; SourceView* fSourceView; BButton* fRunButton; diff --git a/src/apps/debugger/gui/team_window/VariablesView.cpp b/src/apps/debugger/gui/team_window/VariablesView.cpp new file mode 100644 index 0000000000..3663a306f5 --- /dev/null +++ b/src/apps/debugger/gui/team_window/VariablesView.cpp @@ -0,0 +1,160 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + + +#include "VariablesView.h" + +#include + +#include + +#include "table/TableColumns.h" + +#include "Architecture.h" +#include "StackFrame.h" +#include "Variable.h" + + +// #pragma mark - VariableTableModel + + +class VariablesView::VariableTableModel : public TableModel { +public: + VariableTableModel() + : + fStackFrame(NULL) + { + } + + ~VariableTableModel() + { + } + + void SetStackFrame(StackFrame* stackFrame) + { + if (fStackFrame != NULL) { + int32 rowCount = CountRows(); + fStackFrame = NULL; + NotifyRowsRemoved(0, rowCount); + } + + fStackFrame = stackFrame; + + if (fStackFrame != NULL) + NotifyRowsAdded(0, CountRows()); + } + + virtual int32 CountColumns() const + { + return 1; + } + + virtual int32 CountRows() const + { + return fStackFrame != NULL + ? fStackFrame->CountParameters() + + fStackFrame->CountLocalVariables() + : 0; + } + + virtual bool GetValueAt(int32 rowIndex, int32 columnIndex, BVariant& value) + { + if (fStackFrame == NULL) + return false; + + int32 parameterCount = fStackFrame->CountParameters(); + const Variable* variable = rowIndex < parameterCount + ? fStackFrame->ParameterAt(rowIndex) + : fStackFrame->LocalVariableAt(rowIndex - parameterCount); + if (variable == NULL) + return false; + + switch (columnIndex) { + case 0: + value.SetTo(variable->Name(), B_VARIANT_DONT_COPY_DATA); + return true; + default: + return false; + } + } + +private: + StackFrame* fStackFrame; +}; + + +// #pragma mark - VariablesView + + +VariablesView::VariablesView() + : + BGroupView(B_VERTICAL), + fStackFrame(NULL), + fVariableTable(NULL), + fVariableTableModel(NULL) +{ + SetName("Variables"); +} + + +VariablesView::~VariablesView() +{ + SetStackFrame(NULL); + fVariableTable->SetTableModel(NULL); + delete fVariableTableModel; +} + + +/*static*/ VariablesView* +VariablesView::Create() +{ + VariablesView* self = new VariablesView; + + try { + self->_Init(); + } catch (...) { + delete self; + throw; + } + + return self; +} + + +void +VariablesView::SetStackFrame(StackFrame* stackFrame) +{ + if (stackFrame == fStackFrame) + return; + + if (fStackFrame != NULL) + fStackFrame->RemoveReference(); + + fStackFrame = stackFrame; + + if (fStackFrame != NULL) + fStackFrame->AddReference(); + + fVariableTableModel->SetStackFrame(fStackFrame); +} + + +void +VariablesView::_Init() +{ + fVariableTable = new Table("variable list", 0, B_FANCY_BORDER); + AddChild(fVariableTable->ToView()); + + // columns + fVariableTable->AddColumn(new StringTableColumn(0, "Variable", 80, 40, 1000, + B_TRUNCATE_END, B_ALIGN_LEFT)); +// fVariableTable->AddColumn(new VariableValueColumn(1, "Value", 80, 40, 1000, +// B_TRUNCATE_END, B_ALIGN_RIGHT)); + + fVariableTableModel = new VariableTableModel; + fVariableTable->SetTableModel(fVariableTableModel); + + fVariableTable->AddTableListener(this); +} diff --git a/src/apps/debugger/gui/team_window/VariablesView.h b/src/apps/debugger/gui/team_window/VariablesView.h new file mode 100644 index 0000000000..6552d1cec7 --- /dev/null +++ b/src/apps/debugger/gui/team_window/VariablesView.h @@ -0,0 +1,41 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef VARIABLES_VIEW_H +#define VARIABLES_VIEW_H + + +#include + +#include "table/Table.h" + + +class StackFrame; +class Variable; + + +class VariablesView : public BGroupView, private TableListener { +public: + VariablesView(); + ~VariablesView(); + + static VariablesView* Create(); + // throws + + void SetStackFrame(StackFrame* stackFrame); + +private: + class VariableTableModel; + +private: + void _Init(); + +private: + StackFrame* fStackFrame; + Table* fVariableTable; + VariableTableModel* fVariableTableModel; +}; + + +#endif // VARIABLES_VIEW_H diff --git a/src/apps/debugger/model/StackFrame.cpp b/src/apps/debugger/model/StackFrame.cpp index 24c1a1d475..9a1aa74ca6 100644 --- a/src/apps/debugger/model/StackFrame.cpp +++ b/src/apps/debugger/model/StackFrame.cpp @@ -8,6 +8,7 @@ #include "CpuState.h" #include "FunctionInstance.h" #include "Image.h" +#include "Variable.h" // #pragma mark - StackFrame @@ -24,15 +25,21 @@ StackFrame::StackFrame(stack_frame_type type, CpuState* cpuState, fImage(NULL), fFunction(NULL) { - fCpuState->AddReference(); + fCpuState->AcquireReference(); } StackFrame::~StackFrame() { + for (int32 i = 0; Variable* variable = fParameters.ItemAt(i); i++) + variable->ReleaseReference(); + + for (int32 i = 0; Variable* variable = fLocalVariables.ItemAt(i); i++) + variable->ReleaseReference(); + SetImage(NULL); SetFunction(NULL); - fCpuState->RemoveReference(); + fCpuState->ReleaseReference(); } @@ -47,12 +54,12 @@ void StackFrame::SetImage(Image* image) { if (fImage != NULL) - fImage->RemoveReference(); + fImage->ReleaseReference(); fImage = image; if (fImage != NULL) - fImage->AddReference(); + fImage->AcquireReference(); } @@ -60,10 +67,60 @@ void StackFrame::SetFunction(FunctionInstance* function) { if (fFunction != NULL) - fFunction->RemoveReference(); + fFunction->ReleaseReference(); fFunction = function; if (fFunction != NULL) - fFunction->AddReference(); + fFunction->AcquireReference(); +} + + +int32 +StackFrame::CountParameters() const +{ + return fParameters.CountItems(); +} + + +Variable* +StackFrame::ParameterAt(int32 index) const +{ + return fParameters.ItemAt(index); +} + + +bool +StackFrame::AddParameter(Variable* parameter) +{ + if (!fParameters.AddItem(parameter)) + return false; + + parameter->AcquireReference(); + return true; +} + + +int32 +StackFrame::CountLocalVariables() const +{ + return fLocalVariables.CountItems(); +} + + +Variable* +StackFrame::LocalVariableAt(int32 index) const +{ + return fLocalVariables.ItemAt(index); +} + + +bool +StackFrame::AddLocalVariable(Variable* variable) +{ + if (!fLocalVariables.AddItem(variable)) + return false; + + variable->AcquireReference(); + return true; } diff --git a/src/apps/debugger/model/StackFrame.h b/src/apps/debugger/model/StackFrame.h index 6d43e12946..23bb59e85a 100644 --- a/src/apps/debugger/model/StackFrame.h +++ b/src/apps/debugger/model/StackFrame.h @@ -7,6 +7,7 @@ #include +#include #include #include "Types.h" @@ -23,6 +24,7 @@ enum stack_frame_type { class CpuState; class Image; class FunctionInstance; +class Variable; class StackFrame : public Referenceable { @@ -49,6 +51,17 @@ public: FunctionInstance* Function() const { return fFunction; } void SetFunction(FunctionInstance* function); + int32 CountParameters() const; + Variable* ParameterAt(int32 index) const; + bool AddParameter(Variable* parameter); + + int32 CountLocalVariables() const; + Variable* LocalVariableAt(int32 index) const; + bool AddLocalVariable(Variable* variable); + +private: + typedef BObjectList VariableList; + private: stack_frame_type fType; CpuState* fCpuState; @@ -57,6 +70,8 @@ private: target_addr_t fReturnAddress; Image* fImage; FunctionInstance* fFunction; + VariableList fParameters; + VariableList fLocalVariables; }; diff --git a/src/apps/debugger/model/Type.cpp b/src/apps/debugger/model/Type.cpp new file mode 100644 index 0000000000..330a34a46c --- /dev/null +++ b/src/apps/debugger/model/Type.cpp @@ -0,0 +1,113 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + + +#include "Type.h" + + +// #pragma mark - DataMember + + +DataMember::~DataMember() +{ +} + + +// #pragma mark - Type + + +Type::~Type() +{ +} + + +// #pragma mark - PrimitiveType + + +PrimitiveType::~PrimitiveType() +{ +} + + +type_kind +PrimitiveType::Kind() const +{ + return TYPE_PRIMITIVE; +} + + +// #pragma mark - CompoundType + + +CompoundType::~CompoundType() +{ +} + + +type_kind +CompoundType::Kind() const +{ + return TYPE_COMPOUND; +} + + +// #pragma mark - ModifiedType + + +ModifiedType::~ModifiedType() +{ +} + + +type_kind +ModifiedType::Kind() const +{ + return TYPE_MODIFIED; +} + + +// #pragma mark - TypedefType + + +TypedefType::~TypedefType() +{ +} + + +type_kind +TypedefType::Kind() const +{ + return TYPE_TYPEDEF; +} + + +// #pragma mark - AddressType + + +AddressType::~AddressType() +{ +} + + +type_kind +AddressType::Kind() const +{ + return TYPE_ADDRESS; +} + + +// #pragma mark - ArrayType + + +ArrayType::~ArrayType() +{ +} + + +type_kind +ArrayType::Kind() const +{ + return TYPE_ARRAY; +} diff --git a/src/apps/debugger/model/Type.h b/src/apps/debugger/model/Type.h new file mode 100644 index 0000000000..0e11ed827b --- /dev/null +++ b/src/apps/debugger/model/Type.h @@ -0,0 +1,126 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef TYPE_H +#define TYPE_H + + +#include + +#include "Types.h" + + +enum type_kind { + TYPE_PRIMITIVE, + TYPE_COMPOUND, + TYPE_MODIFIED, + TYPE_TYPEDEF, + TYPE_ADDRESS, + TYPE_ARRAY +}; + + +enum address_type_kind { + DERIVED_TYPE_POINTER, + DERIVED_TYPE_REFERENCE +}; + + +enum { + TYPE_MODIFIER_CONST = 0x01, + TYPE_MODIFIER_VOLATILE = 0x02, + TYPE_MODIFIER_RESTRICT = 0x04, + TYPE_MODIFIER_PACKED = 0x08, + TYPE_MODIFIER_SHARED = 0x10 +}; + + +class Type; + + +class DataMember : public Referenceable { +public: + virtual ~DataMember(); + + virtual const char* Name() const = 0; + virtual Type* GetType() const = 0; +}; + + +class Type : public Referenceable { +public: + virtual ~Type(); + + virtual const char* Name() const = 0; + virtual type_kind Kind() const = 0; +}; + + +class PrimitiveType : public virtual Type { +public: + virtual ~PrimitiveType(); + + virtual type_kind Kind() const; + + virtual uint32 TypeConstant() const = 0; +}; + + +class CompoundType : public virtual Type { +public: + virtual ~CompoundType(); + + virtual type_kind Kind() const; + + virtual int32 CountDataMembers() const = 0; + virtual DataMember* DataMemberAt(int32 index) const = 0; +}; + + +class ModifiedType : public virtual Type { +public: + virtual ~ModifiedType(); + + virtual type_kind Kind() const; + + virtual uint32 Modifiers() const = 0; + virtual Type* BaseType() const = 0; +}; + + +class TypedefType : public virtual Type { +public: + virtual ~TypedefType(); + + virtual type_kind Kind() const; + + virtual Type* BaseType() const = 0; +}; + + +class AddressType : public virtual Type { +public: + virtual ~AddressType(); + + virtual type_kind Kind() const; + + virtual address_type_kind AddressKind() const = 0; + virtual Type* BaseType() const = 0; +}; + + +class ArrayType : public virtual Type { +public: + virtual ~ArrayType(); + + virtual type_kind Kind() const; + + virtual Type* BaseType() const = 0; + virtual target_size_t CountElements() const = 0; + // TODO: That doesn't work. We need a list of dimensions which in turn + // are enumeration or subrange types. +}; + + +#endif // TYPE_H diff --git a/src/apps/debugger/model/Variable.cpp b/src/apps/debugger/model/Variable.cpp new file mode 100644 index 0000000000..eb6a40f31e --- /dev/null +++ b/src/apps/debugger/model/Variable.cpp @@ -0,0 +1,28 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + + +#include "Variable.h" + +#include "Type.h" +#include "ValueLocation.h" + + +Variable::Variable(const BString& name, Type* type, ValueLocation* location) + : + fName(name), + fType(type), + fLocation(location) +{ + fType->AcquireReference(); + fLocation->AcquireReference(); +} + + +Variable::~Variable() +{ + fType->ReleaseReference(); + fLocation->ReleaseReference(); +} diff --git a/src/apps/debugger/model/Variable.h b/src/apps/debugger/model/Variable.h new file mode 100644 index 0000000000..6583a6e8ad --- /dev/null +++ b/src/apps/debugger/model/Variable.h @@ -0,0 +1,35 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef VARIABLE_H +#define VARIABLE_H + + +#include + +#include + + +class Type; +class ValueLocation; + + +class Variable : public Referenceable { +public: + Variable(const BString& name, Type* type, + ValueLocation* location); + ~Variable(); + + const BString& Name() const { return fName; } + Type* GetType() const { return fType; } + ValueLocation* Location() const { return fLocation; } + +private: + BString fName; + Type* fType; + ValueLocation* fLocation; +}; + + +#endif // VARIABLE_H diff --git a/src/apps/debugger/types/ValueLocation.cpp b/src/apps/debugger/types/ValueLocation.cpp new file mode 100644 index 0000000000..cbd71d72a3 --- /dev/null +++ b/src/apps/debugger/types/ValueLocation.cpp @@ -0,0 +1,64 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + + +#include "ValueLocation.h" + + +ValueLocation::ValueLocation() +{ +} + + +ValueLocation::ValueLocation(const ValuePieceLocation& piece) +{ + AddPiece(piece); +} + + +ValueLocation::ValueLocation(const ValueLocation& other) + : + fPieces(other.fPieces) +{ +} + + +void +ValueLocation::Clear() +{ + fPieces.Clear(); +} + + +bool +ValueLocation::AddPiece(const ValuePieceLocation& piece) +{ + return fPieces.Add(piece); +} + + +int32 +ValueLocation::CountPieces() const +{ + return fPieces.Size(); +} + + +ValuePieceLocation +ValueLocation::PieceAt(int32 index) const +{ + if (index < 0 || index >= fPieces.Size()) + return ValuePieceLocation(); + + return fPieces.ElementAt(index); +} + + +ValueLocation& +ValueLocation::operator=(const ValueLocation& other) +{ + fPieces = other.fPieces; + return *this; +} diff --git a/src/apps/debugger/types/ValueLocation.h b/src/apps/debugger/types/ValueLocation.h new file mode 100644 index 0000000000..e437f5be92 --- /dev/null +++ b/src/apps/debugger/types/ValueLocation.h @@ -0,0 +1,99 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef VALUE_LOCATION_H +#define VALUE_LOCATION_H + + +#include + +#include "Array.h" +#include "Types.h" + + +enum value_piece_location_type { + VALUE_PIECE_LOCATION_INVALID, // structure is invalid + VALUE_PIECE_LOCATION_UNKNOWN, // location unknown, but size is valid + VALUE_PIECE_LOCATION_MEMORY, // piece is in memory + VALUE_PIECE_LOCATION_REGISTER // piece is in a register +}; + + +struct ValuePieceLocation { + union { + target_addr_t address; // memory address + uint32 reg; // register number + }; + target_size_t size; // size in bytes (complete ones) + uint8 bitSize; // totalBitSize = size * 8 + bitSize + uint8 bitOffset; // offset in bits + value_piece_location_type type; + + ValuePieceLocation() + : + type(VALUE_PIECE_LOCATION_INVALID) + { + } + + bool IsValid() const + { + return type != VALUE_PIECE_LOCATION_INVALID; + } + + void SetToUnknown() + { + type = VALUE_PIECE_LOCATION_UNKNOWN; + } + + void SetToMemory(target_addr_t address) + { + type = VALUE_PIECE_LOCATION_MEMORY; + this->address = address; + } + + void SetToRegister(uint32 reg) + { + type = VALUE_PIECE_LOCATION_REGISTER; + this->reg = reg; + } + + void SetSize(target_size_t size) + { + this->size = size; + this->bitSize = 0; + this->bitOffset = 0; + } + + void SetSize(uint64 bitSize, uint8 bitOffset) + { + this->size = bitSize / 8; + this->bitSize = bitSize % 8; + this->bitOffset = bitOffset; + } +}; + + +class ValueLocation : public Referenceable { +public: + ValueLocation(); + ValueLocation(const ValuePieceLocation& piece); + ValueLocation(const ValueLocation& other); + + void Clear(); + bool AddPiece(const ValuePieceLocation& piece); + + int32 CountPieces() const; + ValuePieceLocation PieceAt(int32 index) const; + + ValueLocation& operator=(const ValueLocation& other); + +private: + typedef Array PieceArray; + +private: + PieceArray fPieces; +}; + + +#endif // VALUE_LOCATION_H