diff --git a/src/apps/debugger/Debugger.cpp b/src/apps/debugger/Debugger.cpp index 2795c55799..6d777028b5 100644 --- a/src/apps/debugger/Debugger.cpp +++ b/src/apps/debugger/Debugger.cpp @@ -23,6 +23,8 @@ #include "MessageCodes.h" #include "SettingsManager.h" #include "TeamDebugger.h" +#include "TypeHandlerRoster.h" +#include "ValueHandlerRoster.h" extern const char* __progname; @@ -178,10 +180,20 @@ public: ~Debugger() { + ValueHandlerRoster::DeleteDefault(); + TypeHandlerRoster::DeleteDefault(); } status_t Init() { + status_t error = TypeHandlerRoster::CreateDefault(); + if (error != B_OK) + return error; + + error = ValueHandlerRoster::CreateDefault(); + if (error != B_OK) + return error; + return fSettingsManager.Init(); } diff --git a/src/apps/debugger/Jamfile b/src/apps/debugger/Jamfile index aed8091fd9..2e21538ccd 100644 --- a/src/apps/debugger/Jamfile +++ b/src/apps/debugger/Jamfile @@ -12,17 +12,23 @@ SEARCH_SOURCE += [ FDirName $(SUBDIR) debug_info ] ; SEARCH_SOURCE += [ FDirName $(SUBDIR) debugger_interface ] ; SEARCH_SOURCE += [ FDirName $(SUBDIR) elf ] ; SEARCH_SOURCE += [ FDirName $(SUBDIR) files ] ; +SEARCH_SOURCE += [ FDirName $(SUBDIR) ids ] ; +SEARCH_SOURCE += [ FDirName $(SUBDIR) model ] ; +SEARCH_SOURCE += [ FDirName $(SUBDIR) settings ] ; +SEARCH_SOURCE += [ FDirName $(SUBDIR) settings generic ] ; +SEARCH_SOURCE += [ FDirName $(SUBDIR) source_language ] ; +SEARCH_SOURCE += [ FDirName $(SUBDIR) types ] ; SEARCH_SOURCE += [ FDirName $(SUBDIR) user_interface ] ; SEARCH_SOURCE += [ FDirName $(SUBDIR) user_interface gui ] ; SEARCH_SOURCE += [ FDirName $(SUBDIR) user_interface gui model ] ; SEARCH_SOURCE += [ FDirName $(SUBDIR) user_interface gui team_window ] ; SEARCH_SOURCE += [ FDirName $(SUBDIR) user_interface gui util ] ; -SEARCH_SOURCE += [ FDirName $(SUBDIR) ids ] ; -SEARCH_SOURCE += [ FDirName $(SUBDIR) model ] ; -SEARCH_SOURCE += [ FDirName $(SUBDIR) settings ] ; -SEARCH_SOURCE += [ FDirName $(SUBDIR) source_language ] ; -SEARCH_SOURCE += [ FDirName $(SUBDIR) types ] ; +SEARCH_SOURCE += [ FDirName $(SUBDIR) user_interface gui value ] ; SEARCH_SOURCE += [ FDirName $(SUBDIR) util ] ; +SEARCH_SOURCE += [ FDirName $(SUBDIR) value ] ; +SEARCH_SOURCE += [ FDirName $(SUBDIR) value value_handlers ] ; +SEARCH_SOURCE += [ FDirName $(SUBDIR) value value_nodes ] ; +SEARCH_SOURCE += [ FDirName $(SUBDIR) value values ] ; local debugAnalyzerSources = [ FDirName $(HAIKU_TOP) src apps debuganalyzer ] ; @@ -96,31 +102,6 @@ Application Debugger : LocatableFile.cpp SourceFile.cpp - # user_interface - UserInterface.cpp - - # user_interface/gui - GraphicalUserInterface.cpp - - # user_interface/gui/model - VariablesViewState.cpp - VariablesViewStateHistory.cpp - - # user_interface/gui/team_window - BreakpointListView.cpp - BreakpointsView.cpp - ImageFunctionsView.cpp - ImageListView.cpp - RegistersView.cpp - SourceView.cpp - StackTraceView.cpp - TeamWindow.cpp - ThreadListView.cpp - VariablesView.cpp - - # user_interface/gui/util - TargetAddressTableColumn.cpp - # ids FunctionID.cpp LocalVariableID.cpp @@ -154,6 +135,11 @@ Application Debugger : TeamSettings.cpp SettingsManager.cpp + # settings/generic + Setting.cpp + Settings.cpp + SettingsDescription.cpp + # source_language CLanguage.cpp CLanguageFamily.cpp @@ -168,11 +154,80 @@ Application Debugger : TargetAddressRangeList.cpp ValueLocation.cpp + # user_interface + UserInterface.cpp + + # user_interface/gui + GraphicalUserInterface.cpp + + # user_interface/gui/model + VariablesViewState.cpp + VariablesViewStateHistory.cpp + + # user_interface/gui/team_window + BreakpointListView.cpp + BreakpointsView.cpp + ImageFunctionsView.cpp + ImageListView.cpp + RegistersView.cpp + SourceView.cpp + StackTraceView.cpp + TeamWindow.cpp + ThreadListView.cpp + VariablesView.cpp + + # user_interface/gui/util + SettingsMenu.cpp + TargetAddressTableColumn.cpp + + # user_interface/gui/value + TableCellBoolRenderer.cpp + TableCellEnumerationRenderer.cpp + TableCellFloatRenderer.cpp + TableCellIntegerRenderer.cpp + TableCellStringRenderer.cpp + TableCellValueRenderer.cpp + TableCellValueRendererUtils.cpp + # util ArchivingUtils.cpp BitBuffer.cpp + IntegerFormatter.cpp StringUtils.cpp + # value + TypeHandler.cpp + TypeHandlerRoster.cpp + Value.cpp + ValueHandler.cpp + ValueHandlerRoster.cpp + ValueLoader.cpp + ValueNode.cpp + ValueNodeContainer.cpp + + # value/value_handlers + AddressValueHandler.cpp + BoolValueHandler.cpp + EnumerationValueHandler.cpp + FloatValueHandler.cpp + IntegerValueHandler.cpp + + # value/value_nodes + AddressValueNode.cpp + ArrayValueNode.cpp + CompoundValueNode.cpp + EnumerationValueNode.cpp + PointerToMemberValueNode.cpp + PrimitiveValueNode.cpp + VariableValueNodeChild.cpp + + # value/values + AddressValue.cpp + BoolValue.cpp + EnumerationValue.cpp + FloatValue.cpp + IntegerValue.cpp + : Debugger_demangler.o Debugger_disasm_x86.o diff --git a/src/apps/debugger/Jobs.cpp b/src/apps/debugger/Jobs.cpp index a20ce0aabb..ba1ad4bde9 100644 --- a/src/apps/debugger/Jobs.cpp +++ b/src/apps/debugger/Jobs.cpp @@ -29,7 +29,11 @@ #include "Tracing.h" #include "Type.h" #include "TypeComponentPath.h" +#include "Value.h" +#include "ValueLoader.h" #include "ValueLocation.h" +#include "ValueNode.h" +#include "ValueNodeContainer.h" #include "Variable.h" @@ -406,627 +410,211 @@ LoadSourceCodeJob::Do() } -// #pragma mark - GetStackFrameValueJobKey +// #pragma mark - ResolveValueNodeValueJob -GetStackFrameValueJobKey::GetStackFrameValueJobKey(StackFrame* stackFrame, - Variable* variable, TypeComponentPath* path) - : - stackFrame(stackFrame), - variable(variable), - path(path) -{ -} - - -uint32 -GetStackFrameValueJobKey::HashValue() const -{ - uint32 hash = (uint32)(addr_t)stackFrame; - hash = hash * 13 + (uint32)(addr_t)variable; - return hash * 13 + path->HashValue(); -} - - -bool -GetStackFrameValueJobKey::operator==(const JobKey& other) const -{ - const GetStackFrameValueJobKey* otherKey - = dynamic_cast(&other); - return otherKey != NULL && stackFrame == otherKey->stackFrame - && variable == otherKey->variable && *path == *otherKey->path; -} - - -// #pragma mark - GetStackFrameValueJob - - -GetStackFrameValueJob::GetStackFrameValueJob( +ResolveValueNodeValueJob::ResolveValueNodeValueJob( DebuggerInterface* debuggerInterface, Architecture* architecture, - Thread* thread, StackFrame* stackFrame, Variable* variable, - TypeComponentPath* path) + CpuState* cpuState, ValueNodeContainer* container, ValueNode* valueNode) : - fKey(stackFrame, variable, path), + fKey(valueNode, JOB_TYPE_RESOLVE_VALUE_NODE_VALUE), fDebuggerInterface(debuggerInterface), fArchitecture(architecture), - fThread(thread), - fStackFrame(stackFrame), - fVariable(variable), - fPath(path) + fCpuState(cpuState), + fContainer(container), + fValueNode(valueNode) { - fThread->AcquireReference(); - fStackFrame->AcquireReference(); - fVariable->AcquireReference(); - fPath->AcquireReference(); + if (fCpuState != NULL) + fCpuState->AcquireReference(); + fContainer->AcquireReference(); + fValueNode->AcquireReference(); } -GetStackFrameValueJob::~GetStackFrameValueJob() +ResolveValueNodeValueJob::~ResolveValueNodeValueJob() { - fThread->ReleaseReference(); - fStackFrame->ReleaseReference(); - fVariable->ReleaseReference(); - fPath->ReleaseReference(); + if (fCpuState != NULL) + fCpuState->ReleaseReference(); + fContainer->ReleaseReference(); + fValueNode->ReleaseReference(); } const JobKey& -GetStackFrameValueJob::Key() const +ResolveValueNodeValueJob::Key() const { return fKey; } status_t -GetStackFrameValueJob::Do() +ResolveValueNodeValueJob::Do() { - status_t error = _GetValue(); - if (error == B_OK) - return B_OK; + // check whether the node still belongs to the container + AutoLocker containerLocker(fContainer); + if (fValueNode->Container() != fContainer) + return B_BAD_VALUE; - // in case of error, set the value to invalid to avoid triggering this job - // again - AutoLocker locker(fThread->GetTeam()); - fStackFrame->Values()->SetValue(fVariable->ID(), fPath, BVariant()); + // if already resolved, we're done + status_t nodeResolutionState + = fValueNode->LocationAndValueResolutionState(); + if (nodeResolutionState != VALUE_NODE_UNRESOLVED) + return nodeResolutionState; + + containerLocker.Unlock(); + + // resolve + status_t error = _ResolveNodeValue(); + if (error != B_OK) { + nodeResolutionState = fValueNode->LocationAndValueResolutionState(); + if (nodeResolutionState != VALUE_NODE_UNRESOLVED) + return nodeResolutionState; + + containerLocker.Lock(); + fValueNode->SetLocationAndValue(NULL, NULL, error); + containerLocker.Unlock(); + } return error; } status_t -GetStackFrameValueJob::_GetValue() +ResolveValueNodeValueJob::_ResolveNodeValue() { - TRACE_LOCALS_ONLY( - TRACE_LOCALS("GetStackFrameValueJob::_GetValue(): %s ", - fVariable->Name().String()); - fPath->Dump(); - TRACE_LOCALS("\n"); - ) + // get the node child and parent node + AutoLocker containerLocker(fContainer); + ValueNodeChild* nodeChild = fValueNode->NodeChild(); + Reference nodeChildReference(nodeChild); - Type* type; + ValueNode* parentNode = nodeChild->Parent(); + Reference parentNodeReference(parentNode); + + // Check whether the node child location has been resolved already + // (successfully). + status_t nodeChildResolutionState = nodeChild->LocationResolutionState(); + bool nodeChildDone = nodeChildResolutionState != VALUE_NODE_UNRESOLVED; + if (nodeChildDone && nodeChildResolutionState != B_OK) + return nodeChildResolutionState; + + // If the child node location has not been resolved yet, check whether the + // parent node location and value have been resolved already (successfully). + bool parentDone = true; + if (!nodeChildDone && parentNode != NULL) { + status_t parentResolutionState + = parentNode->LocationAndValueResolutionState(); + parentDone = parentResolutionState != VALUE_NODE_UNRESOLVED; + if (parentDone && parentResolutionState != B_OK) + return parentResolutionState; + } + + containerLocker.Unlock(); + + // resolve the parent node location and value, if necessary + if (!parentDone) { + status_t error = _ResolveParentNodeValue(parentNode); + if (error != B_OK) { + TRACE_LOCALS("ResolveValueNodeValueJob::_ResolveNodeValue(): value " + "node: %p (\"%s\"): _ResolveParentNodeValue(%p) failed\n", + fValueNode, fValueNode->Name().String(), parentNode); + return error; + } + } + + // resolve the node child location, if necessary + if (!nodeChildDone) { + status_t error = _ResolveNodeChildLocation(nodeChild); + if (error != B_OK) { + TRACE_LOCALS("ResolveValueNodeValueJob::_ResolveNodeValue(): value " + "node: %p (\"%s\"): _ResolveNodeChildLocation(%p) failed\n", + fValueNode, fValueNode->Name().String(), nodeChild); + return error; + } + } + + // resolve the node location and value + ValueLoader valueLoader(fArchitecture, fDebuggerInterface, fCpuState); ValueLocation* location; - bool valueResolved; - status_t error = _ResolveTypeAndLocation(type, location, valueResolved); - if (error != B_OK || valueResolved) { - TRACE_LOCALS(" -> error: %#lx, valueResolved: %d\n", error, - valueResolved); - return error; - } - Type* actualType = type; - Reference typeReference(type); - Reference actualTypeReference(actualType); - Reference locationReference(location); - - // find out the type of the data we want to read - type_code valueType = 0; - bool shortValueIsFine = false; - while (valueType == 0) { - switch (type->Kind()) { - case TYPE_PRIMITIVE: - valueType = dynamic_cast(type)->TypeConstant(); - shortValueIsFine = BVariant::TypeIsInteger(valueType) - || valueType == B_BOOL_TYPE; - - TRACE_LOCALS(" TYPE_PRIMITIVE: '%c%c%c%c'\n", - int(valueType >> 24), int(valueType >> 16), - int(valueType >> 8), int(valueType)); - - if (valueType == 0) { - TRACE_LOCALS(" -> unknown type constant\n"); - return B_BAD_VALUE; - } - break; - case TYPE_MODIFIED: - TRACE_LOCALS(" TYPE_MODIFIED\n"); - // ignore modifiers - type = dynamic_cast(type)->BaseType(); - break; - case TYPE_TYPEDEF: - TRACE_LOCALS(" TYPE_TYPEDEF\n"); - type = dynamic_cast(type)->BaseType(); - break; - case TYPE_ADDRESS: - case TYPE_POINTER_TO_MEMBER: - TRACE_LOCALS(" TYPE_ADDRESS/TYPE_POINTER_TO_MEMBER\n"); - if (fArchitecture->AddressSize() == 4) { - valueType = B_UINT32_TYPE; - TRACE_LOCALS(" -> 32 bit\n"); - } else { - valueType = B_UINT64_TYPE; - TRACE_LOCALS(" -> 64 bit\n"); - } - break; - case TYPE_COMPOUND: - case TYPE_ARRAY: - TRACE_LOCALS(" TYPE_COMPOUND/TYPE_ARRAY\n"); - // We can't retrieve the actual value of the compound object/ - // array (just of its components/elements), but to make the - // recursion work smoothly, we have to set the type and - // location at least. - return _SetValue(BVariant(), actualType, location); - case TYPE_ENUMERATION: - { - TRACE_LOCALS(" TYPE_ENUMERATION\n"); - // If a base type is known, use that. - EnumerationType* enumType - = dynamic_cast(type); - if (enumType->BaseType() != NULL) { - type = enumType->BaseType(); - break; - } - - // get the value type constant - // TODO: This is C source language specific! - switch (enumType->ByteSize()) { - case 1: - valueType = B_INT8_TYPE; - break; - case 2: - valueType = B_INT16_TYPE; - break; - case 4: - default: - valueType = B_INT32_TYPE; - break; - case 8: - valueType = B_INT64_TYPE; - break; - } - - shortValueIsFine = true; - break; - } - case TYPE_SUBRANGE: - TRACE_LOCALS(" TYPE_SUBRANGE -> unsupported\n"); - return B_UNSUPPORTED; - case TYPE_UNSPECIFIED: - // Can't get the value for an unspecified type! - return B_BAD_VALUE; - case TYPE_FUNCTION: - TRACE_LOCALS(" TYPE_FUNCTION\n"); - // Can't get the value for a function type! - return B_BAD_VALUE; - } - } - - // update the reference in case the type has changed - typeReference.SetTo(type); - - if (valueType == B_STRING_TYPE) { - TRACE_LOCALS(" -> B_STRING_TYPE: unsupported\n"); - return B_UNSUPPORTED; - // TODO:... - } - - // check whether we know the complete location - int32 count = location->CountPieces(); - - TRACE_LOCALS_ONLY(location->Dump();) - - if (count == 0) { - TRACE_LOCALS(" -> no location\n"); - return B_ENTRY_NOT_FOUND; - } - - // If the source language implementation uses descriptors to point to - // objects, we need to resolve the object address to the data address. - if (count == 1) { - ValuePieceLocation piece = location->PieceAt(0); - if (piece.type == VALUE_PIECE_LOCATION_MEMORY) { - ValueLocation* dataLocation; - error = type->ResolveObjectDataLocation(*location, dataLocation); - if (error != B_OK) - return error; - - location = dataLocation; - locationReference.SetTo(location, true); - } - } - - static const size_t kMaxPieceSize = 16; - uint64 totalBitSize = 0; - for (int32 i = 0; i < count; i++) { - ValuePieceLocation piece = location->PieceAt(i); - switch (piece.type) { - case VALUE_PIECE_LOCATION_INVALID: - case VALUE_PIECE_LOCATION_UNKNOWN: - return B_ENTRY_NOT_FOUND; - case VALUE_PIECE_LOCATION_MEMORY: - case VALUE_PIECE_LOCATION_REGISTER: - break; - } - - if (piece.size > kMaxPieceSize) { - TRACE_LOCALS(" -> overly long piece size (%llu bytes)\n", - piece.size); - return B_UNSUPPORTED; - } - - totalBitSize += piece.bitSize; - } - - TRACE_LOCALS(" -> totalBitSize: %llu\n", totalBitSize); - - if (totalBitSize == 0) { - TRACE_LOCALS(" -> no size\n"); - return B_ENTRY_NOT_FOUND; - } - - if (totalBitSize > 64) { - TRACE_LOCALS(" -> longer than 64 bits: unsupported\n"); - return B_UNSUPPORTED; - } - - uint64 valueBitSize = BVariant::SizeOfType(valueType) * 8; - if (!shortValueIsFine && totalBitSize < valueBitSize) { - TRACE_LOCALS(" -> too short for value type (%llu vs. %llu bits)\n", - totalBitSize, valueBitSize); - return B_BAD_VALUE; - } - - // Load the data. Since the BitBuffer class we're using only supports big - // endian bit semantics, we convert all data to big endian before pushing - // them to the buffer. For later conversion to BVariant we need to make sure - // the final buffer has the size of the value type, so we pad the most - // significant bits with zeros. - BitBuffer valueBuffer; - if (totalBitSize < valueBitSize) - valueBuffer.AddZeroBits(valueBitSize - totalBitSize); - - bool bigEndian = fArchitecture->IsBigEndian(); - const Register* registers = fArchitecture->Registers(); - for (int32 i = 0; i < count; i++) { - ValuePieceLocation piece = location->PieceAt( - bigEndian ? i : count - i - 1); - uint32 bytesToRead = piece.size; - uint32 bitSize = piece.bitSize; - uint8 bitOffset = piece.bitOffset; - - switch (piece.type) { - case VALUE_PIECE_LOCATION_INVALID: - case VALUE_PIECE_LOCATION_UNKNOWN: - return B_ENTRY_NOT_FOUND; - case VALUE_PIECE_LOCATION_MEMORY: - { - target_addr_t address = piece.address; - - TRACE_LOCALS(" piece %ld: memory address: %#llx, bits: %lu\n", - i, address, bitSize); - - uint8 pieceBuffer[kMaxPieceSize]; - ssize_t bytesRead = fDebuggerInterface->ReadMemory(address, - pieceBuffer, bytesToRead); - if (bytesRead < 0) - return bytesRead; - if ((uint32)bytesRead != bytesToRead) - return B_BAD_ADDRESS; - - TRACE_LOCALS_ONLY( - TRACE_LOCALS(" -> read: "); - for (ssize_t k = 0; k < bytesRead; k++) - TRACE_LOCALS("%02x", pieceBuffer[k]); - TRACE_LOCALS("\n"); - ) - - // convert to big endian - if (!bigEndian) { - for (int32 k = bytesRead / 2 - 1; k >= 0; k--) { - std::swap(pieceBuffer[k], - pieceBuffer[bytesRead - k - 1]); - } - } - - valueBuffer.AddBits(pieceBuffer, bitSize, bitOffset); - break; - } - case VALUE_PIECE_LOCATION_REGISTER: - { - TRACE_LOCALS(" piece %ld: register: %lu, bits: %lu\n", i, - piece.reg, bitSize); - - BVariant registerValue; - if (!fStackFrame->GetCpuState()->GetRegisterValue( - registers + piece.reg, registerValue)) { - return B_ENTRY_NOT_FOUND; - } - if (registerValue.Size() < bytesToRead) - return B_ENTRY_NOT_FOUND; - - if (!bigEndian) - registerValue.SwapEndianess(); - valueBuffer.AddBits(registerValue.Bytes(), bitSize, bitOffset); - break; - } - } - } - - // If we don't have enough bits in the buffer apparently adding some failed. - if (valueBuffer.BitSize() < valueBitSize) - return B_NO_MEMORY; - - // convert the bits into something we can work with - BVariant value; - error = value.SetToTypedData(valueBuffer.Bytes(), valueType); + Value* value; + status_t error = fValueNode->ResolvedLocationAndValue(&valueLoader, + location, value); if (error != B_OK) { - TRACE_LOCALS(" -> failed to set typed data: %s\n", strerror(error)); + TRACE_LOCALS("ResolveValueNodeValueJob::_ResolveNodeValue(): value " + "node: %p (\"%s\"): fValueNode->ResolvedLocationAndValue() " + "failed\n", fValueNode, fValueNode->Name().String()); return error; } + Reference locationReference(location, true); + Reference valueReference(value, true); - // convert to host endianess - #if B_HOST_IS_LENDIAN - value.SwapEndianess(); - #endif + // set location and value on the node + containerLocker.Lock(); + status_t nodeResolutionState + = fValueNode->LocationAndValueResolutionState(); + if (nodeResolutionState != VALUE_NODE_UNRESOLVED) + return nodeResolutionState; + fValueNode->SetLocationAndValue(location, value, B_OK); + containerLocker.Unlock(); - return _SetValue(value, actualType, location); -} - - -status_t -GetStackFrameValueJob::_SetValue(const BVariant& value, Type* type, - ValueLocation* location) -{ - // set the value - AutoLocker locker(fThread->GetTeam()); - - status_t error = fStackFrame->Values()->SetValue(fVariable->ID(), fPath, - value); - if (error != B_OK) { - TRACE_LOCALS(" -> failed to set value: %s\n", strerror(error)); - return error; - } - - fStackFrame->ValueInfos()->SetInfo(fVariable->ID(), fPath, type, location); - - fStackFrame->NotifyValueRetrieved(fVariable, fPath); return B_OK; } status_t -GetStackFrameValueJob::_ResolveTypeAndLocation(Type*& _type, - ValueLocation*& _location, bool& _valueResolved) +ResolveValueNodeValueJob::_ResolveNodeChildLocation(ValueNodeChild* nodeChild) { - if (fPath->CountComponents() == 0) { - fVariable->GetType()->AcquireReference(); - fVariable->Location()->AcquireReference(); - _type = fVariable->GetType(); - _location = fVariable->Location(); - _valueResolved = false; - return B_OK; - } + // resolve the location + ValueLoader valueLoader(fArchitecture, fDebuggerInterface, fCpuState); + ValueLocation* location = NULL; + status_t error = nodeChild->ResolveLocation(&valueLoader, location); + Reference locationReference(location, true); - // get the parent value - int32 componentCount = fPath->CountComponents(); - TypeComponentPath* parentPath = fPath->CreateSubPath(componentCount - 1); - if (parentPath == NULL) - return B_NO_MEMORY; - Reference parentPathReference(parentPath, true); + // set the location on the node child + AutoLocker containerLocker(fContainer); + status_t nodeChildResolutionState = nodeChild->LocationResolutionState(); + if (nodeChildResolutionState == VALUE_NODE_UNRESOLVED) + nodeChild->SetLocation(location, error); + else + error = nodeChildResolutionState; - Type* parentType; - ValueLocation* parentLocation; - BVariant parentValue; - status_t error = _GetTypeLocationAndValue(parentPath, parentType, - parentLocation, parentValue); - if (error != B_OK) { - TRACE_LOCALS("GetStackFrameValueJob::_ResolveTypeAndLocation(): " - "_GetTypeLocationAndValue() failed: %s\n", strerror(error)); - return error; - } - Reference parentTypeReference(parentType, true); - Reference parentLocationReference(parentLocation, true); - - // resolve the last component - TypeComponent component = fPath->ComponentAt(componentCount - 1); - switch (component.typeKind) { - case TYPE_PRIMITIVE: - case TYPE_ENUMERATION: - case TYPE_SUBRANGE: - case TYPE_UNSPECIFIED: - case TYPE_FUNCTION: - case TYPE_POINTER_TO_MEMBER: - // cannot happen - TRACE_LOCALS("GetStackFrameValueJob::_ResolveTypeAndLocation(): " - "TYPE_PRIMITIVE/TYPE_ENUMERATION/TYPE_SUBRANGE/" - "TYPE_UNSPECIFIED/TYPE_FUNCTION/TYPE_POINTER_TO_MEMBER " - "subcomponent!\n"); - return B_BAD_VALUE; - case TYPE_COMPOUND: - { - CompoundType* compoundType - = dynamic_cast(parentType); - - // base type - if (component.componentKind == TYPE_COMPONENT_BASE_TYPE) { - BaseType* baseType = compoundType->BaseTypeAt( - component.index); - if (baseType == NULL) - return B_BAD_VALUE; - - // The parent's location refers to the location of the complete - // object. We want to extract the location of a member. - ValueLocation* location; - error = compoundType->ResolveBaseTypeLocation(baseType, - *parentLocation, location); - if (error != B_OK) { - TRACE_LOCALS("GetStackFrameValueJob::" - "_ResolveTypeAndLocation(): TYPE_COMPOUND: " - "ResolveBaseTypeLocation() failed: %s\n", - strerror(error)); - return error; - } - - baseType->GetType()->AcquireReference(); - _type = baseType->GetType(); - _location = location; - _valueResolved = false; - - return B_OK; - } - - // data member - if (component.componentKind == TYPE_COMPONENT_DATA_MEMBER) { - DataMember* dataMember = compoundType->DataMemberAt( - component.index); - if (dataMember == NULL) - return B_BAD_VALUE; - - // The parent's location refers to the location of the complete - // object. We want to extract the location of a member. - ValueLocation* location; - error = compoundType->ResolveDataMemberLocation(dataMember, - *parentLocation, location); - if (error != B_OK) { - TRACE_LOCALS("GetStackFrameValueJob::" - "_ResolveTypeAndLocation(): TYPE_COMPOUND: " - "ResolveDataMemberLocation() failed: %s\n", - strerror(error)); - return error; - } - - dataMember->GetType()->AcquireReference(); - _type = dataMember->GetType(); - _location = location; - _valueResolved = false; - - return B_OK; - } - - return B_UNSUPPORTED; - } - case TYPE_MODIFIED: - case TYPE_TYPEDEF: - { - Type* type = component.typeKind == TYPE_MODIFIED - ? dynamic_cast(parentType)->BaseType() - : dynamic_cast(parentType)->BaseType(); - _valueResolved = true; - return _SetValue(parentValue, type, parentLocation); - } - case TYPE_ADDRESS: - { - // The parent's value is an address pointing to this component. - // resolve the location - Type* type = dynamic_cast(parentType)->BaseType(); - ValueLocation* location; - error = type->ResolveObjectDataLocation(parentValue.ToUInt64(), - location); - if (error != B_OK) { - TRACE_LOCALS("GetStackFrameValueJob::" - "_ResolveTypeAndLocation(): " - "TYPE_ADDRESS/TYPE_POINTER_TO_MEMBER: " - "ResolveObjectDataLocation() failed: %s\n", - strerror(error)); - return error; - } - - type->AcquireReference(); - _type = type; - _location = location; - _valueResolved = false; - - return B_OK; - } - case TYPE_ARRAY: - { - ArrayType* arrayType = dynamic_cast(parentType); - - if (component.componentKind != TYPE_COMPONENT_ARRAY_ELEMENT) - return B_UNSUPPORTED; - - // get the index path - ArrayIndexPath indexPath; - error = indexPath.SetTo(component.name.String()); - if (error != B_OK) - return error; - - if (indexPath.CountIndices() != arrayType->CountDimensions()) - return B_UNSUPPORTED; - - // resolve the element location - ValueLocation* location; - error = arrayType->ResolveElementLocation(indexPath, - *parentLocation, location); - if (error != B_OK) { - TRACE_LOCALS("GetStackFrameValueJob::" - "_ResolveTypeAndLocation(): TYPE_ARRAY: " - "ResolveElementLocation() failed: %s\n", - strerror(error)); - return error; - } - - arrayType->BaseType()->AcquireReference(); - _type = arrayType->BaseType(); - _location = location; - _valueResolved = false; - - return B_OK; - } - } - - // Can never get here. - return B_UNSUPPORTED; + return error; } status_t -GetStackFrameValueJob::_GetTypeLocationAndValue(TypeComponentPath* parentPath, - Type*& _parentType, ValueLocation*& _parentLocation, BVariant& _parentValue) +ResolveValueNodeValueJob::_ResolveParentNodeValue(ValueNode* parentNode) { - AutoLocker teamLocker(fThread->GetTeam()); + AutoLocker containerLocker(fContainer); - // If there's already a value for the parent path, we're done. - StackFrameValues* values = fStackFrame->Values(); - StackFrameValueInfos* valueInfos = fStackFrame->ValueInfos(); - if (values->HasValue(fVariable->ID(), parentPath)) { - if (!values->GetValue(fVariable->ID(), parentPath, _parentValue) - || !valueInfos->GetInfo(fVariable->ID(), parentPath, &_parentType, - &_parentLocation)) { - return B_ERROR; - } + if (parentNode->Container() != fContainer) + return B_BAD_VALUE; - return B_OK; - } + // if the parent node already has a value, we're done + status_t nodeResolutionState + = parentNode->LocationAndValueResolutionState(); + if (nodeResolutionState != VALUE_NODE_UNRESOLVED) + return nodeResolutionState; // check whether a job is already in progress AutoLocker workerLocker(GetWorker()); - GetStackFrameValueJobKey jobKey(fStackFrame, fVariable, parentPath); + SimpleJobKey jobKey(parentNode, JOB_TYPE_RESOLVE_VALUE_NODE_VALUE); if (GetWorker()->GetJob(jobKey) == NULL) { workerLocker.Unlock(); // schedule the job status_t error = GetWorker()->ScheduleJob( - new(std::nothrow) GetStackFrameValueJob(fDebuggerInterface, - fArchitecture, fThread, fStackFrame, fVariable, parentPath)); + new(std::nothrow) ResolveValueNodeValueJob(fDebuggerInterface, + fArchitecture, fCpuState, fContainer, parentNode)); if (error != B_OK) { // scheduling failed -- set the value to invalid - values->SetValue(fVariable->ID(), parentPath, BVariant()); + parentNode->SetLocationAndValue(NULL, NULL, error); return error; } } // wait for the job to finish workerLocker.Unlock(); - teamLocker.Unlock(); + containerLocker.Unlock(); switch (WaitFor(jobKey)) { case JOB_DEPENDENCY_SUCCEEDED: @@ -1040,14 +628,10 @@ GetStackFrameValueJob::_GetTypeLocationAndValue(TypeComponentPath* parentPath, return B_ERROR; } - teamLocker.Lock(); + containerLocker.Lock(); - // now there should be a value for the path - if (!values->GetValue(fVariable->ID(), parentPath, _parentValue) - || !valueInfos->GetInfo(fVariable->ID(), parentPath, &_parentType, - &_parentLocation)) { - return B_ERROR; - } - - return B_OK; + // now there should be a value for the node + nodeResolutionState = parentNode->LocationAndValueResolutionState(); + return nodeResolutionState != VALUE_NODE_UNRESOLVED + ? nodeResolutionState : B_ERROR; } diff --git a/src/apps/debugger/Jobs.h b/src/apps/debugger/Jobs.h index 9f2cfda428..76cc2862c8 100644 --- a/src/apps/debugger/Jobs.h +++ b/src/apps/debugger/Jobs.h @@ -24,6 +24,9 @@ class Thread; class Type; class TypeComponentPath; class ValueLocation; +class ValueNode; +class ValueNodeChild; +class ValueNodeContainer; class Variable; @@ -34,7 +37,8 @@ enum { JOB_TYPE_GET_STACK_TRACE, JOB_TYPE_LOAD_IMAGE_DEBUG_INFO, JOB_TYPE_LOAD_SOURCE_CODE, - JOB_TYPE_GET_STACK_FRAME_VALUE + JOB_TYPE_GET_STACK_FRAME_VALUE, + JOB_TYPE_RESOLVE_VALUE_NODE_VALUE }; @@ -143,63 +147,33 @@ private: }; - -struct GetStackFrameValueJobKey : JobKey { - StackFrame* stackFrame; - Variable* variable; - TypeComponentPath* path; - +class ResolveValueNodeValueJob : public Job { public: - GetStackFrameValueJobKey( - StackFrame* stackFrame, - Variable* variable, - TypeComponentPath* path); - - virtual uint32 HashValue() const; - - virtual bool operator==(const JobKey& other) const; -}; - - -class GetStackFrameValueJob : public Job { -public: - GetStackFrameValueJob( + ResolveValueNodeValueJob( DebuggerInterface* debuggerInterface, Architecture* architecture, - Thread* thread, StackFrame* stackFrame, - Variable* variable, - TypeComponentPath* path); - virtual ~GetStackFrameValueJob(); + CpuState* cpuState, + ValueNodeContainer* container, + ValueNode* valueNode); + virtual ~ResolveValueNodeValueJob(); virtual const JobKey& Key() const; virtual status_t Do(); private: - struct ValueJobKey; + status_t _ResolveNodeValue(); + status_t _ResolveNodeChildLocation( + ValueNodeChild* nodeChild); + status_t _ResolveParentNodeValue(ValueNode* parentNode); + private: - status_t _GetValue(); - status_t _SetValue(const BVariant& value, Type* type, - ValueLocation* location); - status_t _ResolveTypeAndLocation(Type*& _type, - ValueLocation*& _location, - bool& _valueResolved); - // returns references - status_t _GetTypeLocationAndValue( - TypeComponentPath* parentPath, - Type*& _parentType, - ValueLocation*& _parentLocation, - BVariant& _parentValue); - // returns references - -private: - GetStackFrameValueJobKey fKey; + SimpleJobKey fKey; DebuggerInterface* fDebuggerInterface; Architecture* fArchitecture; - Thread* fThread; - StackFrame* fStackFrame; - Variable* fVariable; - TypeComponentPath* fPath; + CpuState* fCpuState; + ValueNodeContainer* fContainer; + ValueNode* fValueNode; }; diff --git a/src/apps/debugger/MessageCodes.h b/src/apps/debugger/MessageCodes.h index afc0dcfe22..bf2ddfe863 100644 --- a/src/apps/debugger/MessageCodes.h +++ b/src/apps/debugger/MessageCodes.h @@ -7,30 +7,41 @@ enum { - MSG_THREAD_RUN = 'run_', - MSG_THREAD_STOP = 'stop', - MSG_THREAD_STEP_OVER = 'stov', - MSG_THREAD_STEP_INTO = 'stin', - MSG_THREAD_STEP_OUT = 'stou', - MSG_SET_BREAKPOINT = 'sbrk', - MSG_CLEAR_BREAKPOINT = 'cbrk', - MSG_ENABLE_BREAKPOINT = 'ebrk', - MSG_DISABLE_BREAKPOINT = 'dbrk', + MSG_THREAD_RUN = 'run_', + MSG_THREAD_STOP = 'stop', + MSG_THREAD_STEP_OVER = 'stov', + MSG_THREAD_STEP_INTO = 'stin', + MSG_THREAD_STEP_OUT = 'stou', + MSG_SET_BREAKPOINT = 'sbrk', + MSG_CLEAR_BREAKPOINT = 'cbrk', + MSG_ENABLE_BREAKPOINT = 'ebrk', + MSG_DISABLE_BREAKPOINT = 'dbrk', - MSG_THREAD_STATE_CHANGED = 'tsch', - MSG_THREAD_CPU_STATE_CHANGED = 'tcsc', - MSG_THREAD_STACK_TRACE_CHANGED = 'tstc', - MSG_STACK_FRAME_VALUE_RETRIEVED = 'sfvr', - MSG_IMAGE_DEBUG_INFO_CHANGED = 'idic', - MSG_IMAGE_FILE_CHANGED = 'ifch', - MSG_FUNCTION_SOURCE_CODE_CHANGED = 'fnsc', - MSG_USER_BREAKPOINT_CHANGED = 'ubrc', - MSG_DEBUGGER_EVENT = 'dbge', - MSG_LOAD_SETTINGS = 'ldst', + MSG_THREAD_STATE_CHANGED = 'tsch', + MSG_THREAD_CPU_STATE_CHANGED = 'tcsc', + MSG_THREAD_STACK_TRACE_CHANGED = 'tstc', + MSG_STACK_FRAME_VALUE_RETRIEVED = 'sfvr', + MSG_IMAGE_DEBUG_INFO_CHANGED = 'idic', + MSG_IMAGE_FILE_CHANGED = 'ifch', + MSG_FUNCTION_SOURCE_CODE_CHANGED = 'fnsc', + MSG_USER_BREAKPOINT_CHANGED = 'ubrc', + MSG_DEBUGGER_EVENT = 'dbge', + MSG_LOAD_SETTINGS = 'ldst', - MSG_TEXTVIEW_AUTOSCROLL = 'tvas', + MSG_SETTINGS_MENU_IMPL_ITEM_SELECTED = 'smii', + MSG_SETTINGS_MENU_IMPL_OPTION_ITEM_SELECTED = 'smio', - MSG_TEAM_DEBUGGER_QUIT = 'dbqt' + MSG_TEXTVIEW_AUTOSCROLL = 'tvas', + + MSG_VARIABLES_VIEW_CONTEXT_MENU_DONE = 'ctxd', + MSG_VARIABLES_VIEW_NODE_SETTINGS_CHANGED = 'vvns', + + MSG_VALUE_NODE_CHANGED = 'vnch', + MSG_VALUE_NODE_CHILDREN_CREATED = 'vncc', + MSG_VALUE_NODE_CHILDREN_DELETED = 'vncd', + MSG_VALUE_NODE_VALUE_CHANGED = 'vnvc', + + MSG_TEAM_DEBUGGER_QUIT = 'dbqt' }; diff --git a/src/apps/debugger/TeamDebugger.cpp b/src/apps/debugger/TeamDebugger.cpp index 36ec833416..3f196431d2 100644 --- a/src/apps/debugger/TeamDebugger.cpp +++ b/src/apps/debugger/TeamDebugger.cpp @@ -38,6 +38,8 @@ #include "TeamDebugInfo.h" #include "TeamSettings.h" #include "Tracing.h" +#include "ValueNode.h" +#include "ValueNodeContainer.h" #include "Variable.h" // #pragma mark - ImageHandler @@ -558,26 +560,29 @@ TeamDebugger::ImageDebugInfoRequested(Image* image) void -TeamDebugger::StackFrameValueRequested(::Thread* thread, StackFrame* stackFrame, - Variable* variable, TypeComponentPath* path) +TeamDebugger::ValueNodeValueRequested(CpuState* cpuState, + ValueNodeContainer* container, ValueNode* valueNode) { - // the team is already locked + AutoLocker containerLocker(container); + if (valueNode->Container() != container) + return; // check whether a job is already in progress AutoLocker workerLocker(fWorker); - GetStackFrameValueJobKey jobKey(stackFrame, variable, path); + SimpleJobKey jobKey(valueNode, JOB_TYPE_RESOLVE_VALUE_NODE_VALUE); if (fWorker->GetJob(jobKey) != NULL) return; workerLocker.Unlock(); // schedule the job - if (fWorker->ScheduleJob( - new(std::nothrow) GetStackFrameValueJob(fDebuggerInterface, - fDebuggerInterface->GetArchitecture(), thread, stackFrame, - variable, path), - this) != B_OK) { + status_t error = fWorker->ScheduleJob( + new(std::nothrow) ResolveValueNodeValueJob(fDebuggerInterface, + fDebuggerInterface->GetArchitecture(), cpuState, container, + valueNode), + this); + if (error != B_OK) { // scheduling failed -- set the value to invalid - stackFrame->Values()->SetValue(variable->ID(), path, BVariant()); + valueNode->SetLocationAndValue(NULL, NULL, error); } } diff --git a/src/apps/debugger/TeamDebugger.h b/src/apps/debugger/TeamDebugger.h index 1f743057a9..164577339a 100644 --- a/src/apps/debugger/TeamDebugger.h +++ b/src/apps/debugger/TeamDebugger.h @@ -47,9 +47,9 @@ private: virtual void FunctionSourceCodeRequested( FunctionInstance* function); virtual void ImageDebugInfoRequested(Image* image); - virtual void StackFrameValueRequested(::Thread* thread, - StackFrame* stackFrame, Variable* variable, - TypeComponentPath* path); + virtual void ValueNodeValueRequested(CpuState* cpuState, + ValueNodeContainer* container, + ValueNode* valueNode); virtual void ThreadActionRequested(thread_id threadID, uint32 action); virtual void SetBreakpointRequested(target_addr_t address, diff --git a/src/apps/debugger/debug_info/DwarfTypeFactory.cpp b/src/apps/debugger/debug_info/DwarfTypeFactory.cpp index de9efb6f0c..0fb6c968a0 100644 --- a/src/apps/debugger/debug_info/DwarfTypeFactory.cpp +++ b/src/apps/debugger/debug_info/DwarfTypeFactory.cpp @@ -193,6 +193,13 @@ DwarfTypeFactory::CreateType(DIEType* typeEntry, DwarfType*& _type) AutoLocker cacheLocker(fTypeCache); Type* globalType = name.Length() > 0 ? fTypeCache->GetType(name) : NULL; + if (globalType == NULL) { + // lookup by name failed -- try lookup by ID + BString id; + if (DwarfType::GetTypeID(typeEntry, id)) + globalType = fTypeCache->GetTypeByID(id); + } + if (globalType != NULL) { DwarfType* globalDwarfType = dynamic_cast(globalType); if (globalDwarfType != NULL) { @@ -228,15 +235,15 @@ DwarfTypeFactory::CreateType(DIEType* typeEntry, DwarfType*& _type) // Insert the type into the cache. Re-check, as the type may already // have been inserted (e.g. in the compound type case). - if (name.Length() > 0) { - cacheLocker.Lock(); - if (fTypeCache->GetType(name) == NULL) { - error = fTypeCache->AddType(name, type); - if (error != B_OK) - return error; - } - cacheLocker.Unlock(); + cacheLocker.Lock(); + if (name.Length() > 0 + ? fTypeCache->GetType(name) == NULL + : fTypeCache->GetTypeByID(type->ID()) == NULL) { + error = fTypeCache->AddType(type); + if (error != B_OK) + return error; } + cacheLocker.Unlock(); // try to get the type's size uint64 size; @@ -354,9 +361,12 @@ DwarfTypeFactory::_CreateCompoundType(const BString& name, // incomplete type could become visible to other threads. Hence we keep the // context locked, but that essentially kills multi-threading for this context. AutoLocker cacheLocker(fTypeCache); - status_t error = fTypeCache->AddType(name, type); + status_t error = fTypeCache->AddType(type); if (error != B_OK) +{ +printf(" -> failed to add type to cache\n"); return error; +} // cacheLocker.Unlock(); // find the abstract origin or specification that defines the data members @@ -388,7 +398,7 @@ DwarfTypeFactory::_CreateCompoundType(const BString& name, Reference memberReference(member, true); if (member == NULL || !type->AddDataMember(member)) { cacheLocker.Lock(); - fTypeCache->RemoveType(name); + fTypeCache->RemoveType(type); return B_NO_MEMORY; } } @@ -423,7 +433,7 @@ DwarfTypeFactory::_CreateCompoundType(const BString& name, true); if (inheritance == NULL || !type->AddInheritance(inheritance)) { cacheLocker.Lock(); - fTypeCache->RemoveType(name); + fTypeCache->RemoveType(type); return B_NO_MEMORY; } } @@ -808,10 +818,10 @@ DwarfTypeFactory::_CreateEnumerationType(const BString& name, } // create and add the enumeration value object - DwarfEnumerationValue* enumValue - = new(std::nothrow) DwarfEnumerationValue(enumeratorEntry, + DwarfEnumeratorValue* enumValue + = new(std::nothrow) DwarfEnumeratorValue(enumeratorEntry, enumeratorEntry->Name(), value); - Reference enumValueReference(enumValue, true); + Reference enumValueReference(enumValue, true); if (enumValue == NULL || !type->AddValue(enumValue)) return B_NO_MEMORY; } diff --git a/src/apps/debugger/debug_info/DwarfTypeFactory.h b/src/apps/debugger/debug_info/DwarfTypeFactory.h index d9b3c1c341..f877f8db98 100644 --- a/src/apps/debugger/debug_info/DwarfTypeFactory.h +++ b/src/apps/debugger/debug_info/DwarfTypeFactory.h @@ -32,7 +32,7 @@ class DwarfArrayType; class DwarfCompoundType; class DwarfDataMember; class DwarfEnumerationType; -class DwarfEnumerationValue; +class DwarfEnumeratorValue; class DwarfFile; class DwarfFunctionParameter; class DwarfFunctionType; diff --git a/src/apps/debugger/debug_info/DwarfTypes.cpp b/src/apps/debugger/debug_info/DwarfTypes.cpp index 9cfc0ae0e5..36126dacfa 100644 --- a/src/apps/debugger/debug_info/DwarfTypes.cpp +++ b/src/apps/debugger/debug_info/DwarfTypes.cpp @@ -85,13 +85,16 @@ DwarfTypeContext::~DwarfTypeContext() // #pragma mark - DwarfType -DwarfType::DwarfType(DwarfTypeContext* typeContext, const BString& name) +DwarfType::DwarfType(DwarfTypeContext* typeContext, const BString& name, + const DIEType* entry) : fTypeContext(typeContext), fName(name), fByteSize(0) { fTypeContext->AcquireReference(); + + GetTypeID(entry, fID); } @@ -101,6 +104,20 @@ DwarfType::~DwarfType() } +/*static*/ bool +DwarfType::GetTypeID(const DIEType* entry, BString& _id) +{ + char buffer[32]; + snprintf(buffer, sizeof(buffer), "dwarf:%p", entry); + BString id = buffer; + if (id.Length() == 0) + return false; + + _id = id; + return true; +} + + image_id DwarfType::ImageID() const { @@ -108,10 +125,17 @@ DwarfType::ImageID() const } -const char* +const BString& +DwarfType::ID() const +{ + return fID; +} + + +const BString& DwarfType::Name() const { - return fName.Length() > 0 ? fName.String() : NULL; + return fName; } @@ -308,10 +332,10 @@ DwarfDataMember::GetType() const } -// #pragma mark - DwarfEnumerationValue +// #pragma mark - DwarfEnumeratorValue -DwarfEnumerationValue::DwarfEnumerationValue(DIEEnumerator* entry, +DwarfEnumeratorValue::DwarfEnumeratorValue(DIEEnumerator* entry, const BString& name, const BVariant& value) : fEntry(entry), @@ -321,19 +345,19 @@ DwarfEnumerationValue::DwarfEnumerationValue(DIEEnumerator* entry, } -DwarfEnumerationValue::~DwarfEnumerationValue() +DwarfEnumeratorValue::~DwarfEnumeratorValue() { } const char* -DwarfEnumerationValue::Name() const +DwarfEnumeratorValue::Name() const { return fName.Length() > 0 ? fName.String() : NULL; } BVariant -DwarfEnumerationValue::Value() const +DwarfEnumeratorValue::Value() const { return fValue; } @@ -403,7 +427,7 @@ DwarfFunctionParameter::GetType() const DwarfPrimitiveType::DwarfPrimitiveType(DwarfTypeContext* typeContext, const BString& name, DIEBaseType* entry, uint32 typeConstant) : - DwarfType(typeContext, name), + DwarfType(typeContext, name, entry), fEntry(entry), fTypeConstant(typeConstant) { @@ -430,7 +454,7 @@ DwarfPrimitiveType::TypeConstant() const DwarfCompoundType::DwarfCompoundType(DwarfTypeContext* typeContext, const BString& name, DIECompoundType* entry) : - DwarfType(typeContext, name), + DwarfType(typeContext, name, entry), fEntry(entry) { } @@ -684,7 +708,7 @@ DwarfCompoundType::_ResolveDataMemberLocation(DwarfType* memberType, DwarfArrayType::DwarfArrayType(DwarfTypeContext* typeContext, const BString& name, DIEArrayType* entry, DwarfType* baseType) : - DwarfType(typeContext, name), + DwarfType(typeContext, name, entry), fEntry(entry), fBaseType(baseType) { @@ -908,7 +932,7 @@ DwarfModifiedType::DwarfModifiedType(DwarfTypeContext* typeContext, const BString& name, DIEModifiedType* entry, uint32 modifiers, DwarfType* baseType) : - DwarfType(typeContext, name), + DwarfType(typeContext, name, entry), fEntry(entry), fModifiers(modifiers), fBaseType(baseType) @@ -950,7 +974,7 @@ DwarfModifiedType::GetDIEType() const DwarfTypedefType::DwarfTypedefType(DwarfTypeContext* typeContext, const BString& name, DIETypedef* entry, DwarfType* baseType) : - DwarfType(typeContext, name), + DwarfType(typeContext, name, entry), fEntry(entry), fBaseType(baseType) { @@ -985,7 +1009,7 @@ DwarfAddressType::DwarfAddressType(DwarfTypeContext* typeContext, const BString& name, DIEAddressingType* entry, address_type_kind addressKind, DwarfType* baseType) : - DwarfType(typeContext, name), + DwarfType(typeContext, name, entry), fEntry(entry), fAddressKind(addressKind), fBaseType(baseType) @@ -1027,7 +1051,7 @@ DwarfAddressType::GetDIEType() const DwarfEnumerationType::DwarfEnumerationType(DwarfTypeContext* typeContext, const BString& name, DIEEnumerationType* entry, DwarfType* baseType) : - DwarfType(typeContext, name), + DwarfType(typeContext, name, entry), fEntry(entry), fBaseType(baseType) { @@ -1038,7 +1062,7 @@ DwarfEnumerationType::DwarfEnumerationType(DwarfTypeContext* typeContext, DwarfEnumerationType::~DwarfEnumerationType() { - for (int32 i = 0; DwarfEnumerationValue* value = fValues.ItemAt(i); i++) + for (int32 i = 0; DwarfEnumeratorValue* value = fValues.ItemAt(i); i++) value->ReleaseReference(); if (fBaseType != NULL) @@ -1060,7 +1084,7 @@ DwarfEnumerationType::CountValues() const } -EnumerationValue* +EnumeratorValue* DwarfEnumerationType::ValueAt(int32 index) const { return fValues.ItemAt(index); @@ -1075,7 +1099,7 @@ DwarfEnumerationType::GetDIEType() const bool -DwarfEnumerationType::AddValue(DwarfEnumerationValue* value) +DwarfEnumerationType::AddValue(DwarfEnumeratorValue* value) { if (!fValues.AddItem(value)) return false; @@ -1092,7 +1116,7 @@ DwarfSubrangeType::DwarfSubrangeType(DwarfTypeContext* typeContext, const BString& name, DIESubrangeType* entry, DwarfType* baseType, const BVariant& lowerBound, const BVariant& upperBound) : - DwarfType(typeContext, name), + DwarfType(typeContext, name, entry), fEntry(entry), fBaseType(baseType), fLowerBound(lowerBound), @@ -1142,7 +1166,7 @@ DwarfSubrangeType::UpperBound() const DwarfUnspecifiedType::DwarfUnspecifiedType(DwarfTypeContext* typeContext, const BString& name, DIEUnspecifiedType* entry) : - DwarfType(typeContext, name), + DwarfType(typeContext, name, entry), fEntry(entry) { } @@ -1166,7 +1190,7 @@ DwarfUnspecifiedType::GetDIEType() const DwarfFunctionType::DwarfFunctionType(DwarfTypeContext* typeContext, const BString& name, DIESubroutineType* entry, DwarfType* returnType) : - DwarfType(typeContext, name), + DwarfType(typeContext, name, entry), fEntry(entry), fReturnType(returnType), fHasVariableArguments(false) @@ -1249,7 +1273,7 @@ DwarfPointerToMemberType::DwarfPointerToMemberType( DIEPointerToMemberType* entry, DwarfCompoundType* containingType, DwarfType* baseType) : - DwarfType(typeContext, name), + DwarfType(typeContext, name, entry), fEntry(entry), fContainingType(containingType), fBaseType(baseType) diff --git a/src/apps/debugger/debug_info/DwarfTypes.h b/src/apps/debugger/debug_info/DwarfTypes.h index b6fab3faf5..b761944787 100644 --- a/src/apps/debugger/debug_info/DwarfTypes.h +++ b/src/apps/debugger/debug_info/DwarfTypes.h @@ -88,11 +88,14 @@ private: class DwarfType : public virtual Type { public: DwarfType(DwarfTypeContext* typeContext, - const BString& name); + const BString& name, const DIEType* entry); ~DwarfType(); + static bool GetTypeID(const DIEType* entry, BString& _id); + virtual image_id ImageID() const; - virtual const char* Name() const; + virtual const BString& ID() const; + virtual const BString& Name() const; virtual target_size_t ByteSize() const; virtual status_t ResolveObjectDataLocation( @@ -118,6 +121,7 @@ public: private: DwarfTypeContext* fTypeContext; BString fName; + BString fID; target_size_t fByteSize; }; @@ -162,11 +166,11 @@ private: }; -class DwarfEnumerationValue : public EnumerationValue { +class DwarfEnumeratorValue : public EnumeratorValue { public: - DwarfEnumerationValue(DIEEnumerator* entry, + DwarfEnumeratorValue(DIEEnumerator* entry, const BString& name, const BVariant& value); - ~DwarfEnumerationValue(); + ~DwarfEnumeratorValue(); virtual const char* Name() const; virtual BVariant Value() const; @@ -396,17 +400,17 @@ public: virtual Type* BaseType() const; virtual int32 CountValues() const; - virtual EnumerationValue* ValueAt(int32 index) const; + virtual EnumeratorValue* ValueAt(int32 index) const; virtual DIEType* GetDIEType() const; - bool AddValue(DwarfEnumerationValue* value); + bool AddValue(DwarfEnumeratorValue* value); DIEEnumerationType* Entry() const { return fEntry; } private: - typedef BObjectList ValueList; + typedef BObjectList ValueList; private: DIEEnumerationType* fEntry; diff --git a/src/apps/debugger/debug_info/GlobalTypeLookup.cpp b/src/apps/debugger/debug_info/GlobalTypeLookup.cpp index e378e14fd1..84f500c9f1 100644 --- a/src/apps/debugger/debug_info/GlobalTypeLookup.cpp +++ b/src/apps/debugger/debug_info/GlobalTypeLookup.cpp @@ -17,13 +17,12 @@ struct GlobalTypeCache::TypeEntry { - BString name; Type* type; - TypeEntry* fNext; + TypeEntry* fNextByName; + TypeEntry* fNextByID; - TypeEntry(const BString& name, Type* type) + TypeEntry(Type* type) : - name(name), type(type) { type->AcquireReference(); @@ -36,7 +35,7 @@ struct GlobalTypeCache::TypeEntry { }; -struct GlobalTypeCache::TypeEntryHashDefinition { +struct GlobalTypeCache::TypeEntryHashDefinitionByName { typedef const BString KeyType; typedef TypeEntry ValueType; @@ -47,17 +46,43 @@ struct GlobalTypeCache::TypeEntryHashDefinition { size_t Hash(const TypeEntry* value) const { - return HashKey(value->name); + return HashKey(value->type->Name()); } bool Compare(const BString& key, const TypeEntry* value) const { - return key == value->name; + return key == value->type->Name(); } TypeEntry*& GetLink(TypeEntry* value) const { - return value->fNext; + return value->fNextByName; + } +}; + + +struct GlobalTypeCache::TypeEntryHashDefinitionByID { + typedef const BString KeyType; + typedef TypeEntry ValueType; + + size_t HashKey(const BString& key) const + { + return StringUtils::HashValue(key); + } + + size_t Hash(const TypeEntry* value) const + { + return HashKey(value->type->ID()); + } + + bool Compare(const BString& key, const TypeEntry* value) const + { + return key == value->type->ID(); + } + + TypeEntry*& GetLink(TypeEntry* value) const + { + return value->fNextByID; } }; @@ -67,19 +92,23 @@ struct GlobalTypeCache::TypeEntryHashDefinition { GlobalTypeCache::GlobalTypeCache() : - fLock("global type lookup"), - fTypes(NULL) + fLock("global type cache"), + fTypesByName(NULL), + fTypesByID(NULL) { } GlobalTypeCache::~GlobalTypeCache() { + if (fTypesByName != NULL) + fTypesByName->Clear(); + // release all cached type references - if (fTypes != NULL) { - TypeEntry* entry = fTypes->Clear(true); + if (fTypesByID != NULL) { + TypeEntry* entry = fTypesByID->Clear(true); while (entry != NULL) { - TypeEntry* nextEntry = entry->fNext; + TypeEntry* nextEntry = entry->fNextByID; delete entry; entry = nextEntry; } @@ -90,48 +119,85 @@ GlobalTypeCache::~GlobalTypeCache() status_t GlobalTypeCache::Init() { + // check lock status_t error = fLock.InitCheck(); if (error != B_OK) return error; - fTypes = new(std::nothrow) TypeTable; - if (fTypes == NULL) + // create name table + fTypesByName = new(std::nothrow) NameTable; + if (fTypesByName == NULL) return B_NO_MEMORY; - return fTypes->Init(); + error = fTypesByName->Init(); + if (error != B_OK) + return error; + + // create ID table + fTypesByID = new(std::nothrow) IDTable; + if (fTypesByID == NULL) + return B_NO_MEMORY; + + error = fTypesByID->Init(); + if (error != B_OK) + return error; + + return B_OK; } Type* GlobalTypeCache::GetType(const BString& name) const { - TypeEntry* typeEntry = fTypes->Lookup(name); + TypeEntry* typeEntry = fTypesByName->Lookup(name); + return typeEntry != NULL ? typeEntry->type : NULL; +} + + +Type* +GlobalTypeCache::GetTypeByID(const BString& id) const +{ + TypeEntry* typeEntry = fTypesByID->Lookup(id); return typeEntry != NULL ? typeEntry->type : NULL; } status_t -GlobalTypeCache::AddType(const BString& name, Type* type) +GlobalTypeCache::AddType(Type* type) { - TypeEntry* typeEntry = fTypes->Lookup(name); - if (typeEntry != NULL) - return B_BAD_VALUE; + const BString& id = type->ID(); + const BString& name = type->Name(); - typeEntry = new(std::nothrow) TypeEntry(name, type); + if (fTypesByID->Lookup(id) != NULL + || (name.Length() > 0 && fTypesByID->Lookup(name) != NULL)) { + return B_BAD_VALUE; + } + + TypeEntry* typeEntry = new(std::nothrow) TypeEntry(type); if (typeEntry == NULL) return B_NO_MEMORY; - fTypes->Insert(typeEntry); + fTypesByID->Insert(typeEntry); + + if (name.Length() > 0) + fTypesByName->Insert(typeEntry); + return B_OK; } void -GlobalTypeCache::RemoveType(const BString& name) +GlobalTypeCache::RemoveType(Type* type) { - if (TypeEntry* typeEntry = fTypes->Lookup(name)) { - fTypes->Remove(typeEntry); - delete typeEntry; + if (TypeEntry* typeEntry = fTypesByID->Lookup(type->ID())) { + if (typeEntry->type == type) { + fTypesByID->Remove(typeEntry); + + if (type->Name().Length() > 0) + fTypesByName->Remove(typeEntry); + + delete typeEntry; + } } } @@ -141,10 +207,14 @@ GlobalTypeCache::RemoveTypes(image_id imageID) { AutoLocker locker(this); - for (TypeTable::Iterator it = fTypes->GetIterator(); + for (IDTable::Iterator it = fTypesByID->GetIterator(); TypeEntry* typeEntry = it.Next();) { if (typeEntry->type->ImageID() == imageID) { - fTypes->RemoveUnchecked(typeEntry); + fTypesByID->RemoveUnchecked(typeEntry); + + if (typeEntry->type->Name().Length() > 0) + fTypesByName->Remove(typeEntry); + delete typeEntry; } } diff --git a/src/apps/debugger/debug_info/GlobalTypeLookup.h b/src/apps/debugger/debug_info/GlobalTypeLookup.h index e8ca45be96..d2094f5ee4 100644 --- a/src/apps/debugger/debug_info/GlobalTypeLookup.h +++ b/src/apps/debugger/debug_info/GlobalTypeLookup.h @@ -17,6 +17,12 @@ class BString; class Type; +enum global_type_cache_scope { + GLOBAL_TYPE_CACHE_SCOPE_GLOBAL, + GLOBAL_TYPE_CACHE_SCOPE_COMPILATION_UNIT +}; + + class GlobalTypeCache : public Referenceable { public: GlobalTypeCache(); @@ -29,21 +35,25 @@ public: // cache must be locked Type* GetType(const BString& name) const; - status_t AddType(const BString& name, Type* type); - void RemoveType(const BString& name); + Type* GetTypeByID(const BString& id) const; + status_t AddType(Type* type); + void RemoveType(Type* type); // cache locked by method void RemoveTypes(image_id imageID); private: struct TypeEntry; - struct TypeEntryHashDefinition; + struct TypeEntryHashDefinitionByName; + struct TypeEntryHashDefinitionByID; - typedef BOpenHashTable TypeTable; + typedef BOpenHashTable NameTable; + typedef BOpenHashTable IDTable; private: BLocker fLock; - TypeTable* fTypes; + NameTable* fTypesByName; + IDTable* fTypesByID; }; diff --git a/src/apps/debugger/model/Type.cpp b/src/apps/debugger/model/Type.cpp index 2316dc69a6..e898682525 100644 --- a/src/apps/debugger/model/Type.cpp +++ b/src/apps/debugger/model/Type.cpp @@ -23,10 +23,10 @@ DataMember::~DataMember() } -// #pragma mark - EnumerationValue +// #pragma mark - EnumeratorValue -EnumerationValue::~EnumerationValue() +EnumeratorValue::~EnumeratorValue() { } @@ -81,7 +81,7 @@ Type::~Type() Type* -Type::ResolveRawType() const +Type::ResolveRawType(bool nextOneOnly) const { return const_cast(this); } @@ -133,9 +133,10 @@ ModifiedType::Kind() const Type* -ModifiedType::ResolveRawType() const +ModifiedType::ResolveRawType(bool nextOneOnly) const { - return BaseType(); + Type* baseType = BaseType(); + return nextOneOnly ? baseType : baseType->ResolveRawType(true); } @@ -155,9 +156,10 @@ TypedefType::Kind() const Type* -TypedefType::ResolveRawType() const +TypedefType::ResolveRawType(bool nextOneOnly) const { - return BaseType(); + Type* baseType = BaseType(); + return nextOneOnly ? baseType : baseType->ResolveRawType(true); } @@ -191,11 +193,11 @@ EnumerationType::Kind() const } -EnumerationValue* +EnumeratorValue* EnumerationType::ValueFor(const BVariant& value) const { // TODO: Optimize? - for (int32 i = 0; EnumerationValue* enumValue = ValueAt(i); i++) { + for (int32 i = 0; EnumeratorValue* enumValue = ValueAt(i); i++) { if (enumValue->Value() == value) return enumValue; } diff --git a/src/apps/debugger/model/Type.h b/src/apps/debugger/model/Type.h index fcf4252b62..716ee6e833 100644 --- a/src/apps/debugger/model/Type.h +++ b/src/apps/debugger/model/Type.h @@ -45,6 +45,7 @@ enum { class ArrayIndexPath; +class BString; class Type; class ValueLocation; @@ -66,9 +67,9 @@ public: }; -class EnumerationValue : public Referenceable { +class EnumeratorValue : public Referenceable { public: - virtual ~EnumerationValue(); + virtual ~EnumeratorValue(); virtual const char* Name() const = 0; virtual BVariant Value() const = 0; @@ -100,11 +101,13 @@ public: virtual ~Type(); virtual image_id ImageID() const = 0; - virtual const char* Name() const = 0; + virtual const BString& ID() const = 0; + virtual const BString& Name() const = 0; virtual type_kind Kind() const = 0; virtual target_size_t ByteSize() const = 0; - virtual Type* ResolveRawType() const; - // strips modifiers and typedefs + virtual Type* ResolveRawType(bool nextOneOnly) const; + // strips modifiers and typedefs (only one, + // if requested) virtual status_t ResolveObjectDataLocation( const ValueLocation& objectLocation, @@ -158,7 +161,7 @@ public: virtual uint32 Modifiers() const = 0; virtual Type* BaseType() const = 0; - virtual Type* ResolveRawType() const; + virtual Type* ResolveRawType(bool nextOneOnly) const; }; @@ -169,7 +172,7 @@ public: virtual type_kind Kind() const; virtual Type* BaseType() const = 0; - virtual Type* ResolveRawType() const; + virtual Type* ResolveRawType(bool nextOneOnly) const; }; @@ -194,8 +197,8 @@ public: // may return NULL virtual int32 CountValues() const = 0; - virtual EnumerationValue* ValueAt(int32 index) const = 0; - virtual EnumerationValue* ValueFor(const BVariant& value) const; + virtual EnumeratorValue* ValueAt(int32 index) const = 0; + virtual EnumeratorValue* ValueFor(const BVariant& value) const; }; diff --git a/src/apps/debugger/user_interface/UserInterface.h b/src/apps/debugger/user_interface/UserInterface.h index bbb80a80ea..6891a32e97 100644 --- a/src/apps/debugger/user_interface/UserInterface.h +++ b/src/apps/debugger/user_interface/UserInterface.h @@ -13,6 +13,7 @@ #include "Types.h" +class CpuState; class FunctionInstance; class Image; class StackFrame; @@ -21,6 +22,8 @@ class Thread; class TypeComponentPath; class UserBreakpoint; class UserInterfaceListener; +class ValueNode; +class ValueNodeContainer; class Variable; @@ -59,10 +62,9 @@ public: virtual void FunctionSourceCodeRequested( FunctionInstance* function) = 0; virtual void ImageDebugInfoRequested(Image* image) = 0; - virtual void StackFrameValueRequested(Thread* thread, - StackFrame* stackFrame, Variable* variable, - TypeComponentPath* path) = 0; - // called with team locked + virtual void ValueNodeValueRequested(CpuState* cpuState, + ValueNodeContainer* container, + ValueNode* valueNode) = 0; virtual void ThreadActionRequested(thread_id threadID, uint32 action) = 0; diff --git a/src/apps/debugger/user_interface/gui/team_window/TeamWindow.cpp b/src/apps/debugger/user_interface/gui/team_window/TeamWindow.cpp index 67035d3d74..9001b40c3d 100644 --- a/src/apps/debugger/user_interface/gui/team_window/TeamWindow.cpp +++ b/src/apps/debugger/user_interface/gui/team_window/TeamWindow.cpp @@ -211,24 +211,6 @@ TeamWindow::MessageReceived(BMessage* message) break; } - case MSG_STACK_FRAME_VALUE_RETRIEVED: - { - void* _stackFrame; - void* _variable; - void* _path; - if (message->FindPointer("stackFrame", &_stackFrame) == B_OK - && message->FindPointer("variable", &_variable) == B_OK - && message->FindPointer("path", &_path) == B_OK) { - StackFrame* stackFrame = (StackFrame*)_stackFrame; - Variable* variable = (Variable*)_variable; - TypeComponentPath* path = (TypeComponentPath*)_path; - _HandleStackFrameValueRetrieved(stackFrame, variable, path); - path->ReleaseReference(); - variable->ReleaseReference(); - stackFrame->ReleaseReference(); - } - } - case MSG_IMAGE_DEBUG_INFO_CHANGED: { int32 imageID; @@ -339,10 +321,10 @@ TeamWindow::ClearBreakpointRequested(target_addr_t address) void -TeamWindow::StackFrameValueRequested(::Thread* thread, StackFrame* stackFrame, - Variable* variable, TypeComponentPath* path) +TeamWindow::ValueNodeValueRequested(CpuState* cpuState, + ValueNodeContainer* container, ValueNode* valueNode) { - fListener->StackFrameValueRequested(thread, stackFrame, variable, path); + fListener->ValueNodeValueRequested(cpuState, container, valueNode); } @@ -405,22 +387,6 @@ TeamWindow::FunctionSourceCodeChanged(Function* function) } -void -TeamWindow::StackFrameValueRetrieved(StackFrame* stackFrame, Variable* variable, - TypeComponentPath* path) -{ - BMessage message(MSG_STACK_FRAME_VALUE_RETRIEVED); - if (message.AddPointer("stackFrame", stackFrame) == B_OK - && message.AddPointer("variable", variable) == B_OK - && message.AddPointer("path", path) == B_OK - && PostMessage(&message) == B_OK) { - stackFrame->AcquireReference(); - variable->AcquireReference(); - path->AcquireReference(); - } -} - - void TeamWindow::_Init() { @@ -906,17 +872,6 @@ TeamWindow::_HandleStackTraceChanged(thread_id threadID) } -void -TeamWindow::_HandleStackFrameValueRetrieved(StackFrame* stackFrame, - Variable* variable, TypeComponentPath* path) -{ - if (stackFrame != fActiveStackFrame) - return; - - fVariablesView->StackFrameValueRetrieved(stackFrame, variable, path); -} - - void TeamWindow::_HandleImageDebugInfoChanged(image_id imageID) { diff --git a/src/apps/debugger/user_interface/gui/team_window/TeamWindow.h b/src/apps/debugger/user_interface/gui/team_window/TeamWindow.h index bdc40cff24..65c9af7f5f 100644 --- a/src/apps/debugger/user_interface/gui/team_window/TeamWindow.h +++ b/src/apps/debugger/user_interface/gui/team_window/TeamWindow.h @@ -89,9 +89,9 @@ private: virtual void ClearBreakpointRequested(target_addr_t address); // VariablesView::Listener - virtual void StackFrameValueRequested(::Thread* thread, - StackFrame* stackFrame, Variable* variable, - TypeComponentPath* path); + virtual void ValueNodeValueRequested(CpuState* cpuState, + ValueNodeContainer* container, + ValueNode* valueNode); // Team::Listener virtual void ThreadStateChanged( @@ -108,11 +108,6 @@ private: // Function::Listener virtual void FunctionSourceCodeChanged(Function* function); - // StackFrame::Listener - virtual void StackFrameValueRetrieved(StackFrame* stackFrame, - Variable* variable, - TypeComponentPath* path); - void _Init(); void _SetActiveThread(::Thread* thread); @@ -130,9 +125,6 @@ private: void _HandleThreadStateChanged(thread_id threadID); void _HandleCpuStateChanged(thread_id threadID); void _HandleStackTraceChanged(thread_id threadID); - void _HandleStackFrameValueRetrieved( - StackFrame* stackFrame, Variable* variable, - TypeComponentPath* path); void _HandleImageDebugInfoChanged(image_id imageID); void _HandleSourceCodeChanged(); void _HandleUserBreakpointChanged( diff --git a/src/apps/debugger/user_interface/gui/team_window/VariablesView.cpp b/src/apps/debugger/user_interface/gui/team_window/VariablesView.cpp index e011945797..cc032b9f5c 100644 --- a/src/apps/debugger/user_interface/gui/team_window/VariablesView.cpp +++ b/src/apps/debugger/user_interface/gui/team_window/VariablesView.cpp @@ -10,6 +10,10 @@ #include +#include +#include + +#include #include #include "table/TableColumns.h" @@ -17,13 +21,23 @@ #include "Architecture.h" #include "FunctionID.h" #include "FunctionInstance.h" +#include "MessageCodes.h" +#include "SettingsMenu.h" #include "StackFrame.h" #include "StackFrameValues.h" +#include "TableCellValueRenderer.h" #include "Team.h" #include "Thread.h" #include "Tracing.h" #include "TypeComponentPath.h" +#include "TypeHandlerRoster.h" +#include "Value.h" +#include "ValueHandler.h" +#include "ValueHandlerRoster.h" +#include "ValueNode.h" +#include "ValueNodeContainer.h" #include "Variable.h" +#include "VariableValueNodeChild.h" #include "VariablesViewState.h" #include "VariablesViewStateHistory.h" @@ -36,75 +50,128 @@ enum { static const uint64 kMaxArrayElementCount = 10; -class VariablesView::ValueNode : public Referenceable { +class VariablesView::ContainerListener : public ValueNodeContainer::Listener { public: - ValueNode(ValueNode* parent, Variable* variable, TypeComponentPath* path, - const BString& name, Type* type, bool isPresentationNode) + ContainerListener(BHandler* indirectTarget); + + void SetModel(VariableTableModel* model); + + virtual void ValueNodeChanged(ValueNodeChild* nodeChild, + ValueNode* oldNode, ValueNode* newNode); + virtual void ValueNodeChildrenCreated(ValueNode* node); + virtual void ValueNodeChildrenDeleted(ValueNode* node); + virtual void ValueNodeValueChanged(ValueNode* node); + +private: + BHandler* fIndirectTarget; + VariableTableModel* fModel; +}; + + +class VariablesView::ModelNode : public Referenceable { +public: + ModelNode(ModelNode* parent, ValueNodeChild* nodeChild, + bool isPresentationNode) : fParent(parent), - fVariable(variable), - fPath(path), - fName(name), - fType(type), - fRawType(type->ResolveRawType()), - fChildrenAdded(false), - fIsPresentationNode(isPresentationNode) + fNodeChild(nodeChild), + fValue(NULL), + fValueHandler(NULL), + fTableCellRenderer(NULL), + fIsPresentationNode(isPresentationNode), + fHidden(false) { - fVariable->AcquireReference(); - fPath->AcquireReference(); - fType->AcquireReference(); - fRawType->AcquireReference(); + fNodeChild->AcquireReference(); } - ~ValueNode() + ~ModelNode() { - for (int32 i = 0; ValueNode* child = fChildren.ItemAt(i); i++) + SetTableCellRenderer(NULL); + SetValueHandler(NULL); + SetValue(NULL); + + for (int32 i = 0; ModelNode* child = fChildren.ItemAt(i); i++) child->ReleaseReference(); - fVariable->ReleaseReference(); - fPath->ReleaseReference(); - fType->ReleaseReference(); - fRawType->ReleaseReference(); + fNodeChild->ReleaseReference(); } - ValueNode* Parent() const + ModelNode* Parent() const { return fParent; } - Variable* GetVariable() const + ValueNodeChild* NodeChild() const { - return fVariable; - } - - TypeComponentPath* Path() const - { - return fPath; + return fNodeChild; } const BString& Name() const { - return fName; + return fNodeChild->Name(); } Type* GetType() const { - return fType; + return fNodeChild->GetType(); } - Type* RawType() const - { - return fRawType; - } - - const BVariant& Value() const + Value* GetValue() const { return fValue; } - void SetValue(const BVariant& value) + void SetValue(Value* value) { + if (value == fValue) + return; + + if (fValue != NULL) + fValue->ReleaseReference(); + fValue = value; + + if (fValue != NULL) + fValue->AcquireReference(); + } + + ValueHandler* GetValueHandler() const + { + return fValueHandler; + } + + void SetValueHandler(ValueHandler* handler) + { + if (handler == fValueHandler) + return; + + if (fValueHandler != NULL) + fValueHandler->ReleaseReference(); + + fValueHandler = handler; + + if (fValueHandler != NULL) + fValueHandler->AcquireReference(); + } + + + TableCellValueRenderer* TableCellRenderer() const + { + return fTableCellRenderer; + } + + void SetTableCellRenderer(TableCellValueRenderer* renderer) + { + if (renderer == fTableCellRenderer) + return; + + if (fTableCellRenderer != NULL) + fTableCellRenderer->ReleaseReference(); + + fTableCellRenderer = renderer; + + if (fTableCellRenderer != NULL) + fTableCellRenderer->AcquireReference(); } bool IsPresentationNode() const @@ -112,22 +179,32 @@ public: return fIsPresentationNode; } + bool IsHidden() const + { + return fHidden; + } + + void SetHidden(bool hidden) + { + fHidden = hidden; + } + int32 CountChildren() const { return fChildren.CountItems(); } - ValueNode* ChildAt(int32 index) const + ModelNode* ChildAt(int32 index) const { return fChildren.ItemAt(index); } - int32 IndexOf(ValueNode* child) const + int32 IndexOf(ModelNode* child) const { return fChildren.IndexOf(child); } - bool AddChild(ValueNode* child) + bool AddChild(ModelNode* child) { if (!fChildren.AddItem(child)) return false; @@ -136,30 +213,21 @@ public: return true; } - bool ChildrenAdded() const - { - return fChildrenAdded; - } - - void SetChildrenAdded(bool added) - { - fChildrenAdded = added; - } +private: + typedef BObjectList ChildList; private: - typedef BObjectList ChildList; + ModelNode* fParent; + ValueNodeChild* fNodeChild; + Value* fValue; + ValueHandler* fValueHandler; + TableCellValueRenderer* fTableCellRenderer; + ChildList fChildren; + bool fIsPresentationNode; + bool fHidden; -private: - ValueNode* fParent; - Variable* fVariable; - TypeComponentPath* fPath; - BString fName; - Type* fType; - Type* fRawType; - BVariant fValue; - ChildList fChildren; - bool fChildrenAdded; - bool fIsPresentationNode; +public: + ModelNode* fNext; }; @@ -178,104 +246,43 @@ public: } protected: + void DrawValue(const BVariant& value, BRect rect, BView* targetView) + { + // draw the node's value with the designated renderer + if (value.Type() == VALUE_NODE_TYPE) { + ModelNode* node = dynamic_cast(value.ToReferenceable()); + if (node != NULL && node->GetValue() != NULL + && node->TableCellRenderer() != NULL) { + node->TableCellRenderer()->RenderValue(node->GetValue(), rect, + targetView); + return; + } + } + + // fall back to drawing an empty string + fField.SetString(""); + fField.SetWidth(Width()); + fColumn.DrawField(&fField, rect, targetView); + } + + float GetPreferredWidth(const BVariant& value, BView* targetView) const + { + // get the preferred width from the node's designated renderer + if (value.Type() == VALUE_NODE_TYPE) { + ModelNode* node = dynamic_cast(value.ToReferenceable()); + if (node != NULL && node->GetValue() != NULL + && node->TableCellRenderer() != NULL) { + return node->TableCellRenderer()->PreferredValueWidth( + node->GetValue(), targetView); + } + } + + return fColumn.BTitledColumn::GetPreferredWidth(NULL, targetView); + } + virtual BField* PrepareField(const BVariant& _value) const { - BVariant value = _ResolveValue(_value); - - char buffer[64]; - return StringTableColumn::PrepareField( - BVariant(_ToString(value, buffer, sizeof(buffer)), - B_VARIANT_DONT_COPY_DATA)); - } - - virtual int CompareValues(const BVariant& _a, const BVariant& _b) - { - BVariant a = _ResolveValue(_a); - BVariant b = _ResolveValue(_b); - - // If neither value is a number, compare the strings. If only one value - // is a number, it is considered to be greater. - if (!a.IsNumber()) { - if (b.IsNumber()) - return -1; - char bufferA[64]; - char bufferB[64]; - return StringTableColumn::CompareValues( - BVariant(_ToString(a, bufferA, sizeof(bufferA)), - B_VARIANT_DONT_COPY_DATA), - BVariant(_ToString(b, bufferB, sizeof(bufferB)), - B_VARIANT_DONT_COPY_DATA)); - } - - if (!b.IsNumber()) - return 1; - - // If either value is floating point, we compare floating point values. - if (a.IsFloat() || b.IsFloat()) { - double valueA = a.ToDouble(); - double valueB = b.ToDouble(); - return valueA < valueB ? -1 : (valueA == valueB ? 0 : 1); - } - - uint64 valueA = a.ToUInt64(); - uint64 valueB = b.ToUInt64(); - return valueA < valueB ? -1 : (valueA == valueB ? 0 : 1); - } - -private: - BVariant _ResolveValue(const BVariant& nodeValue) const - { - BVariant value; - if (nodeValue.Type() != VALUE_NODE_TYPE) - return BVariant(); - - ValueNode* node = dynamic_cast(nodeValue.ToReferenceable()); - - // replace enumerations values with their names - if (node->RawType()->Kind() == TYPE_ENUMERATION) { - EnumerationValue* enumValue - = dynamic_cast(node->RawType()) - ->ValueFor(node->Value()); - if (enumValue != NULL) - return enumValue->Name(); - } - - return node->Value(); - } - - const char* _ToString(const BVariant& value, char* buffer, - size_t bufferSize) const - { - switch (value.Type()) { - case B_BOOL_TYPE: - return value.ToBool() ? "true" : "false"; - case B_FLOAT_TYPE: - case B_DOUBLE_TYPE: - snprintf(buffer, bufferSize, "%g", value.ToDouble()); - break; - case B_INT8_TYPE: - case B_UINT8_TYPE: - snprintf(buffer, bufferSize, "0x%02x", value.ToUInt8()); - break; - case B_INT16_TYPE: - case B_UINT16_TYPE: - snprintf(buffer, bufferSize, "0x%04x", value.ToUInt16()); - break; - case B_INT32_TYPE: - case B_UINT32_TYPE: - snprintf(buffer, bufferSize, "0x%08lx", value.ToUInt32()); - break; - case B_INT64_TYPE: - case B_UINT64_TYPE: - snprintf(buffer, bufferSize, "0x%016llx", value.ToUInt64()); - break; - case B_STRING_TYPE: - return value.ToString(); - default: - return NULL; - } - - return buffer; + return NULL; } }; @@ -285,464 +292,885 @@ private: class VariablesView::VariableTableModel : public TreeTableModel { public: - VariableTableModel() - : - fStackFrame(NULL), - fNodes(20, true) - { - } + VariableTableModel(); + ~VariableTableModel(); - ~VariableTableModel() - { - SetStackFrame(NULL, NULL); - } + status_t Init(); - void SetStackFrame(Thread* thread, StackFrame* stackFrame) - { - if (!fNodes.IsEmpty()) { - int32 count = fNodes.CountItems(); - fNodes.MakeEmpty(); - NotifyNodesRemoved(TreeTablePath(), 0, count); - } + void SetContainerListener( + ContainerListener* listener); - fStackFrame = stackFrame; - fThread = thread; + void SetStackFrame(Thread* thread, + StackFrame* stackFrame); - if (fStackFrame != NULL) { - for (int32 i = 0; Variable* variable = fStackFrame->ParameterAt(i); - i++) { - _AddNode(variable); - } + void ValueNodeChanged(ValueNodeChild* nodeChild, + ValueNode* oldNode, ValueNode* newNode); + void ValueNodeChildrenCreated(ValueNode* node); + void ValueNodeChildrenDeleted(ValueNode* node); + void ValueNodeValueChanged(ValueNode* node); - for (int32 i = 0; Variable* variable - = fStackFrame->LocalVariableAt(i); i++) { - _AddNode(variable); - } + virtual int32 CountColumns() const; + virtual void* Root() const; + virtual int32 CountChildren(void* parent) const; + virtual void* ChildAt(void* parent, int32 index) const; + virtual bool GetValueAt(void* object, int32 columnIndex, + BVariant& _value); - if (!fNodes.IsEmpty()) - NotifyNodesAdded(TreeTablePath(), 0, fNodes.CountItems()); - } - } + void NodeExpanded(ModelNode* node); - void StackFrameValueRetrieved(StackFrame* stackFrame, Variable* variable, - TypeComponentPath* path) - { - if (stackFrame != fStackFrame) - return; - - // update the respective node's value - AutoLocker locker(fThread->GetTeam()); - BVariant value; - if (fStackFrame->Values()->GetValue(variable->ID(), path, value)) { - ValueNode* node = _GetNode(variable, path); - TreeTablePath treePath; - if (node != NULL && _GetTreePath(node, treePath)) { - node->SetValue(value); - int32 index = treePath.RemoveLastComponent(); - NotifyNodesChanged(treePath, index, 1); - } - } - } - - virtual int32 CountColumns() const - { - return 2; - } - - virtual void* Root() const - { - return (void*)this; - } - - virtual int32 CountChildren(void* parent) const - { - if (parent == this) - return fNodes.CountItems(); - - return ((ValueNode*)parent)->CountChildren(); - } - - virtual void* ChildAt(void* parent, int32 index) const - { - if (parent == this) - return fNodes.ItemAt(index); - - return ((ValueNode*)parent)->ChildAt(index); - } - - virtual bool GetValueAt(void* object, int32 columnIndex, BVariant& _value) - { - ValueNode* node = (ValueNode*)object; - - switch (columnIndex) { - case 0: - _value.SetTo(node->Name(), B_VARIANT_DONT_COPY_DATA); - return true; - case 1: - if (node->Value().Type() == 0) - return false; - - _value.SetTo(node, VALUE_NODE_TYPE); - return true; - default: - return false; - } - } - - void NodeExpanded(ValueNode* node) - { - // add children of all children - for (int32 i = 0; ValueNode* child = node->ChildAt(i); i++) - _AddChildNodes(child); - } + void NotifyNodeChanged(ModelNode* node); private: - typedef BObjectList ValueList; + struct NodeHashDefinition { + typedef ValueNodeChild* KeyType; + typedef ModelNode ValueType; -private: - void _AddNode(Variable* variable) - { - TypeComponentPath* path = new(std::nothrow) TypeComponentPath; - if (path == NULL) - return; - Reference pathReference(path, true); - - ValueNode* node = new(std::nothrow) ValueNode(NULL, variable, path, - variable->Name(), variable->GetType(), false); - if (node == NULL || !fNodes.AddItem(node)) { - delete node; - return; - } - - // automatically add child nodes for the top level nodes - _AddChildNodes(node); - } - - void _AddChildNodes(ValueNode* node) - { - if (node == NULL || node->ChildrenAdded()) - return; - - _AddChildNodesInternal(node); - node->SetChildrenAdded(true); - - // If the node is already known, notify the model listeners about the - // new child nodes. We assume that this holds true for the all but the - // top-level nodes. - TreeTablePath treePath; - if (node->Parent() != NULL && node->CountChildren() > 0 - && _GetTreePath(node, treePath)) { - NotifyNodesAdded(treePath, 0, node->CountChildren()); - } - } - - void _AddChildNodesInternal(ValueNode* node) - { - TRACE_LOCALS("_AddChildNodesInternal(%p)\n", node); - - Type* type = node->GetType(); - TypeComponentPath* path - = new(std::nothrow) TypeComponentPath(*node->Path()); - if (path == NULL - || path->CountComponents() != node->Path()->CountComponents()) { - delete path; - return; - } - Reference pathReference(path, true); - - bool dereferencedType = false; - while (true) { - bool done = false; - TypeComponent component; - - switch (type->Kind()) { - case TYPE_PRIMITIVE: - TRACE_LOCALS("TYPE_PRIMITIVE\n"); - done = true; - break; - case TYPE_COMPOUND: + size_t HashKey(const ValueNodeChild* key) const { - TRACE_LOCALS("TYPE_COMPOUND\n"); - CompoundType* compoundType - = dynamic_cast(type); - - // base types - for (int32 i = 0; BaseType* baseType - = compoundType->BaseTypeAt(i); i++) { - TRACE_LOCALS(" base %ld\n", i); - - component.SetToBaseType(type->Kind(), i); - TypeComponentPath* baseTypePath - = new(std::nothrow) TypeComponentPath(*path); - if (baseTypePath == NULL - || baseTypePath->CountComponents() - != path->CountComponents() - || !baseTypePath->AddComponent(component)) { - delete baseTypePath; - return; - } - Reference baseTypePathReference( - baseTypePath, true); - _AddChildNode(node, node->GetVariable(), baseTypePath, - baseType->GetType()->Name(), baseType->GetType()); - } - - // members - for (int32 i = 0; DataMember* member - = compoundType->DataMemberAt(i); i++) { - BString name = member->Name(); - - TRACE_LOCALS(" member %ld: \"%s\"\n", i, name.String()); - - component.SetToDataMember(type->Kind(), i, name); - TypeComponentPath* memberPath - = new(std::nothrow) TypeComponentPath(*path); - if (memberPath == NULL - || memberPath->CountComponents() - != path->CountComponents() - || !memberPath->AddComponent(component)) { - delete memberPath; - return; - } - Reference memberPathReference( - memberPath, true); - _AddChildNode(node, node->GetVariable(), memberPath, - name, member->GetType()); - } - return; + return (size_t)key; } - case TYPE_MODIFIED: - TRACE_LOCALS("TYPE_MODIFIED\n"); - component.SetToBaseType(type->Kind()); - type = dynamic_cast(type)->BaseType(); - break; - case TYPE_TYPEDEF: - TRACE_LOCALS("TYPE_TYPEDEF\n"); - component.SetToBaseType(type->Kind()); - type = dynamic_cast(type)->BaseType(); - break; - case TYPE_ADDRESS: - TRACE_LOCALS("TYPE_ADDRESS\n"); - // don't dereference twice - if (dereferencedType) { - done = true; - break; - } - component.SetToBaseType(type->Kind()); - type = dynamic_cast(type)->BaseType(); - dereferencedType = true; - break; - case TYPE_ARRAY: + size_t Hash(const ModelNode* value) const { - TRACE_LOCALS("TYPE_ARRAY\n"); - ArrayType* arrayType = dynamic_cast(type); - int32 dimensionCount = arrayType->CountDimensions(); - - // get the base array indices - ArrayIndexPath baseIndexPath; - int32 baseDimension = 0; - if (node->Parent() != NULL - && node->Parent()->GetType() == type) { - TypeComponent arrayComponent - = path->ComponentAt(path->CountComponents() - 1); - if (arrayComponent.componentKind - != TYPE_COMPONENT_ARRAY_ELEMENT) { - ERROR("Unexpected array type path component!\n"); - return; - } - - status_t error - = baseIndexPath.SetTo(arrayComponent.name.String()); - if (error != B_OK) - return; - - baseDimension = baseIndexPath.CountIndices(); - } - - if (baseDimension >= dimensionCount) { - ERROR("Unexpected array base dimension!\n"); - return; - } - bool isFinalDimension = baseDimension + 1 == dimensionCount; - - ArrayDimension* dimension = arrayType->DimensionAt( - baseDimension); - uint64 elementCount = dimension->CountElements(); - if (elementCount == 0 - || elementCount > kMaxArrayElementCount) { - elementCount = kMaxArrayElementCount; - } - - // create children for the array elements - for (int32 i = 0; i < (int32)elementCount; i++) { - ArrayIndexPath indexPath(baseIndexPath); - if (indexPath.CountIndices() - != baseIndexPath.CountIndices() - || !indexPath.AddIndex(i)) { - return; - } - - component.SetToArrayElement(type->Kind(), indexPath); - TypeComponentPath* elementPath = path->CreateSubPath( - path->CountComponents() - - (baseDimension == 0 ? 0 : 1)); - if (elementPath == NULL - || !elementPath->AddComponent(component)) { - delete elementPath; - return; - } - Reference elementPathReference( - elementPath, true); - - BString name(node->Name()); - name << '[' << i << ']'; - - _AddChildNode(node, node->GetVariable(), elementPath, - name, - isFinalDimension ? arrayType->BaseType() : type, - !isFinalDimension); - } - - return; - } - case TYPE_ENUMERATION: - TRACE_LOCALS("TYPE_ENUMERATION\n"); - done = true; - break; - case TYPE_SUBRANGE: - TRACE_LOCALS("TYPE_SUBRANGE -> unsupported\n"); - // TODO: Support! - return; - case TYPE_UNSPECIFIED: - // Should never get here -- we don't create nodes for - // unspecified types. - TRACE_LOCALS("TYPE_UNSPECIFIED\n"); - return; - case TYPE_FUNCTION: - TRACE_LOCALS("TYPE_FUNCTION -> unsupported\n"); - // TODO: Support! - return; - case TYPE_POINTER_TO_MEMBER: - TRACE_LOCALS("TYPE_POINTER_TO_MEMBER\n"); - done = true; - break; - } - - if (done) { - if (dereferencedType) { - _AddChildNode(node, node->GetVariable(), path, - BString("*") << node->Name(), type); - } - return; - } - - if (!path->AddComponent(component)) - return; - } - } - - void _AddChildNode(ValueNode* parent, Variable* variable, - TypeComponentPath* path, const BString& name, Type* type, - bool isPresentationNode = false) - { - // Don't create nodes for unspecified types -- we can't get/show their - // value anyway. - if (type->Kind() == TYPE_UNSPECIFIED) - return; - - ValueNode* node = new(std::nothrow) ValueNode(parent, variable, path, - name, type, isPresentationNode); - if (node == NULL || !parent->AddChild(node)) { - delete node; - return; - } - } - - ValueNode* _GetNode(Variable* variable, TypeComponentPath* path) const - { - // find the variable node - ValueNode* node; - for (int32 i = 0; (node = fNodes.ItemAt(i)) != NULL; i++) { - if (node->GetVariable() == variable) - break; - } - if (node == NULL) - return NULL; - - // Now walk along the path, finding the respective child node for each - // component (might be several components at once). - int32 componentCount = path->CountComponents(); - for (int32 i = 0; i < componentCount;) { - ValueNode* childNode = NULL; - - for (int32 k = 0; (childNode = node->ChildAt(k)) != NULL; k++) { - TypeComponentPath* childPath = childNode->Path(); - int32 childComponentCount = childPath->CountComponents(); - if (childComponentCount > componentCount) - continue; - - for (int32 componentIndex = i; - componentIndex < childComponentCount; componentIndex++) { - TypeComponent childComponent - = childPath->ComponentAt(componentIndex); - TypeComponent pathComponent - = path->ComponentAt(componentIndex); - if (childComponent != pathComponent) { - if (componentIndex + 1 == childComponentCount - && pathComponent.HasPrefix(childComponent)) { - // The last child component is a prefix of the - // corresponding path component. We consider this a - // match, but need to recheck the component with the - // next node level. - childComponentCount--; - break; - } - - // mismatch -- skip the child - childNode = NULL; - break; - } + return HashKey(value->NodeChild()); } - if (childNode != NULL) { - // got a match -- skip the matched children components - i = childComponentCount; - break; + bool Compare(const ValueNodeChild* key, + const ModelNode* value) const + { + return value->NodeChild() == key; } - } - if (childNode == NULL) - return NULL; + ModelNode*& GetLink(ModelNode* value) const + { + return value->fNext; + } + }; - node = childNode; - } - - return node; - } - - bool _GetTreePath(ValueNode* node, TreeTablePath& _path) const - { - // recurse, if the node has a parent - if (ValueNode* parent = node->Parent()) { - if (!_GetTreePath(parent, _path)) - return false; - return _path.AddComponent(parent->IndexOf(node)); - } - - // no parent -- get the index and start the path - int32 index = fNodes.IndexOf(node); - _path.Clear(); - return index >= 0 && _path.AddComponent(index); - } + typedef BObjectList NodeList; + typedef BOpenHashTable NodeTable; private: - Thread* fThread; - StackFrame* fStackFrame; - ValueList fNodes; + // container must be locked + + status_t _AddNode(ModelNode* parent, + ValueNodeChild* nodeChild, + bool isPresentationNode = false); + void _AddNode(Variable* variable); + status_t _CreateValueNode(ValueNodeChild* nodeChild); + status_t _AddChildNodes(ValueNodeChild* nodeChild); + +// ModelNode* _GetNode(Variable* variable, +// TypeComponentPath* path) const; + bool _GetTreePath(ModelNode* node, + TreeTablePath& _path) const; + +private: + Thread* fThread; + StackFrame* fStackFrame; + ValueNodeContainer* fContainer; + ContainerListener* fContainerListener; + NodeList fNodes; + NodeTable fNodeTable; }; +class VariablesView::ContextMenu : public BPopUpMenu { +public: + ContextMenu(const BMessenger& parent, const char* name) + : BPopUpMenu(name, false, false), + fParent(parent) + { + } + + virtual void Hide() + { + BPopUpMenu::Hide(); + + BMessage message(MSG_VARIABLES_VIEW_CONTEXT_MENU_DONE); + message.AddPointer("menu", this); + fParent.SendMessage(&message); + } + +private: + BMessenger fParent; +}; + + +// #pragma mark - TableCellContextMenuTracker + + +class VariablesView::TableCellContextMenuTracker : public BReferenceable, + Settings::Listener { +public: + TableCellContextMenuTracker(ModelNode* node, BLooper* parentLooper, + const BMessenger& parent) + : + fNode(node), + fParentLooper(parentLooper), + fParent(parent), + fRendererSettings(NULL), + fRendererSettingsMenu(NULL), + fRendererMenuAdded(false), + fMenuPreparedToShow(false) + { + fNode->AcquireReference(); + } + + ~TableCellContextMenuTracker() + { + FinishMenu(true); + + if (fRendererSettingsMenu != NULL) + fRendererSettingsMenu->ReleaseReference(); + + if (fRendererSettings != NULL) + fRendererSettings->ReleaseReference(); + + fNode->ReleaseReference(); + } + + status_t Init(Settings* rendererSettings, + SettingsMenu* rendererSettingsMenu) + { + fRendererSettings = rendererSettings; + fRendererSettings->AcquireReference(); + + fRendererSettingsMenu = rendererSettingsMenu; + fRendererSettingsMenu->AcquireReference(); + + fContextMenu = new(std::nothrow) ContextMenu(fParent, + "table cell settings popup"); + if (fContextMenu == NULL) + return B_NO_MEMORY; + + status_t error = fRendererSettingsMenu->AddToMenu(fContextMenu, 0); + if (error != B_OK) + return error; + + AutoLocker settingsLocker(fRendererSettings); + fRendererSettings->AddListener(this); + + fRendererMenuAdded = true; + + return B_OK; + } + + void ShowMenu(BPoint screenWhere) + { + fRendererSettingsMenu->PrepareToShow(fParentLooper); + + fMenuPreparedToShow = true; + + BRect mouseRect(screenWhere, screenWhere); + mouseRect.InsetBy(-4.0, -4.0); + fContextMenu->Go(screenWhere, true, false, mouseRect, true); + } + + bool FinishMenu(bool force) + { + bool stillActive; + + if (fMenuPreparedToShow) { + stillActive = fRendererSettingsMenu->Finish(fParentLooper, force); + fMenuPreparedToShow = stillActive; + } + + if (fRendererMenuAdded) { + fRendererSettingsMenu->RemoveFromMenu(); + fRendererSettings->RemoveListener(this); + fRendererMenuAdded = false; + } + + if (fContextMenu != NULL) { + delete fContextMenu; + fContextMenu = NULL; + } + + return stillActive; + } + +private: + // Settings::Listener + + virtual void SettingValueChanged(Setting* setting) + { + BMessage message(MSG_VARIABLES_VIEW_NODE_SETTINGS_CHANGED); + fNode->AcquireReference(); + if (message.AddPointer("node", fNode) != B_OK + || fParent.SendMessage(&message) != B_OK) { + fNode->ReleaseReference(); + } + } + +private: + ModelNode* fNode; + BLooper* fParentLooper; + BMessenger fParent; + ContextMenu* fContextMenu; + Settings* fRendererSettings; + SettingsMenu* fRendererSettingsMenu; + bool fRendererMenuAdded; + bool fMenuPreparedToShow; +}; + + +// #pragma mark - ContainerListener + + +VariablesView::ContainerListener::ContainerListener(BHandler* indirectTarget) + : + fIndirectTarget(indirectTarget), + fModel(NULL) +{ +} + + +void +VariablesView::ContainerListener::SetModel(VariableTableModel* model) +{ + fModel = model; +} + + +void +VariablesView::ContainerListener::ValueNodeChanged(ValueNodeChild* nodeChild, + ValueNode* oldNode, ValueNode* newNode) +{ + // If the looper is already locked, invoke the model's hook synchronously. + if (fIndirectTarget->Looper()->IsLocked()) { + fModel->ValueNodeChanged(nodeChild, oldNode, newNode); + return; + } + + // looper not locked yet -- call asynchronously to avoid reverse locking + // order + BReference nodeChildReference(nodeChild); + BReference oldNodeReference(oldNode); + BReference newNodeReference(newNode); + + BMessage message(MSG_VALUE_NODE_CHANGED); + if (message.AddPointer("nodeChild", nodeChild) == B_OK + && message.AddPointer("oldNode", oldNode) == B_OK + && message.AddPointer("newNode", newNode) == B_OK + && fIndirectTarget->Looper()->PostMessage(&message, fIndirectTarget) + == B_OK) { + nodeChildReference.Detach(); + oldNodeReference.Detach(); + newNodeReference.Detach(); + } +} + + +void +VariablesView::ContainerListener::ValueNodeChildrenCreated(ValueNode* node) +{ + // If the looper is already locked, invoke the model's hook synchronously. + if (fIndirectTarget->Looper()->IsLocked()) { + fModel->ValueNodeChildrenCreated(node); + return; + } + + // looper not locked yet -- call asynchronously to avoid reverse locking + // order + BReference nodeReference(node); + + BMessage message(MSG_VALUE_NODE_CHILDREN_CREATED); + if (message.AddPointer("node", node) == B_OK + && fIndirectTarget->Looper()->PostMessage(&message, fIndirectTarget) + == B_OK) { + nodeReference.Detach(); + } +} + + +void +VariablesView::ContainerListener::ValueNodeChildrenDeleted(ValueNode* node) +{ + // If the looper is already locked, invoke the model's hook synchronously. + if (fIndirectTarget->Looper()->IsLocked()) { + fModel->ValueNodeChildrenDeleted(node); + return; + } + + // looper not locked yet -- call asynchronously to avoid reverse locking + // order + BReference nodeReference(node); + + BMessage message(MSG_VALUE_NODE_CHILDREN_DELETED); + if (message.AddPointer("node", node) == B_OK + && fIndirectTarget->Looper()->PostMessage(&message, fIndirectTarget) + == B_OK) { + nodeReference.Detach(); + } +} + + +void +VariablesView::ContainerListener::ValueNodeValueChanged(ValueNode* node) +{ + // If the looper is already locked, invoke the model's hook synchronously. + if (fIndirectTarget->Looper()->IsLocked()) { + fModel->ValueNodeValueChanged(node); + return; + } + + // looper not locked yet -- call asynchronously to avoid reverse locking + // order + BReference nodeReference(node); + + BMessage message(MSG_VALUE_NODE_VALUE_CHANGED); + if (message.AddPointer("node", node) == B_OK + && fIndirectTarget->Looper()->PostMessage(&message, fIndirectTarget) + == B_OK) { + nodeReference.Detach(); + } +} + + +// #pragma mark - VariableTableModel + + +VariablesView::VariableTableModel::VariableTableModel() + : + fStackFrame(NULL), + fContainer(NULL), + fContainerListener(NULL), + fNodeTable() +{ +} + + +VariablesView::VariableTableModel::~VariableTableModel() +{ + SetStackFrame(NULL, NULL); +} + + +status_t +VariablesView::VariableTableModel::Init() +{ + return fNodeTable.Init(); +} + + +void +VariablesView::VariableTableModel::SetContainerListener( + ContainerListener* listener) +{ + if (listener == fContainerListener) + return; + + if (fContainerListener != NULL) { + if (fContainer != NULL) { + AutoLocker containerLocker(fContainer); + fContainer->RemoveListener(fContainerListener); + } + + fContainerListener->SetModel(NULL); + } + + fContainerListener = listener; + + if (fContainerListener != NULL) { + fContainerListener->SetModel(this); + + if (fContainer != NULL) { + AutoLocker containerLocker(fContainer); + fContainer->AddListener(fContainerListener); + } + } +} + + +void +VariablesView::VariableTableModel::SetStackFrame(Thread* thread, + StackFrame* stackFrame) +{ + if (fContainer != NULL) { + AutoLocker containerLocker(fContainer); + + if (fContainerListener != NULL) + fContainer->RemoveListener(fContainerListener); + + fContainer->RemoveAllChildren(); + containerLocker.Unlock(); + fContainer->ReleaseReference(); + fContainer = NULL; + } + + fNodeTable.Clear(true); + + if (!fNodes.IsEmpty()) { + int32 count = fNodes.CountItems(); + for (int32 i = 0; i < count; i++) + fNodes.ItemAt(i)->ReleaseReference(); + fNodes.MakeEmpty(); + NotifyNodesRemoved(TreeTablePath(), 0, count); + } + + fStackFrame = stackFrame; + fThread = thread; + + if (fStackFrame != NULL) { + fContainer = new(std::nothrow) ValueNodeContainer; + if (fContainer == NULL) + return; + + status_t error = fContainer->Init(); + if (error != B_OK) { + delete fContainer; + fContainer = NULL; + return; + } + + AutoLocker containerLocker(fContainer); + + if (fContainerListener != NULL) + fContainer->AddListener(fContainerListener); + + for (int32 i = 0; Variable* variable = fStackFrame->ParameterAt(i); + i++) { + _AddNode(variable); + } + + for (int32 i = 0; Variable* variable + = fStackFrame->LocalVariableAt(i); i++) { + _AddNode(variable); + } + +// if (!fNodes.IsEmpty()) +// NotifyNodesAdded(TreeTablePath(), 0, fNodes.CountItems()); + } +} + + +void +VariablesView::VariableTableModel::ValueNodeChanged(ValueNodeChild* nodeChild, + ValueNode* oldNode, ValueNode* newNode) +{ + if (fContainer == NULL) + return; + + AutoLocker containerLocker(fContainer); +// TODO:... +} + + +void +VariablesView::VariableTableModel::ValueNodeChildrenCreated( + ValueNode* valueNode) +{ + if (fContainer == NULL) + return; + + AutoLocker containerLocker(fContainer); + + // check whether we know the node + ValueNodeChild* nodeChild = valueNode->NodeChild(); + if (nodeChild == NULL) + return; + + ModelNode* modelNode = fNodeTable.Lookup(nodeChild); + if (modelNode == NULL) + return; + + // Iterate through the children and create model nodes for the ones we + // don't know yet. + int32 childCount = valueNode->CountChildren(); + for (int32 i = 0; i < childCount; i++) { + ValueNodeChild* child = valueNode->ChildAt(i); + if (fNodeTable.Lookup(child) == NULL) + _AddNode(modelNode, child, child->IsInternal()); + } +} + + +void +VariablesView::VariableTableModel::ValueNodeChildrenDeleted(ValueNode* node) +{ + if (fContainer == NULL) + return; + + AutoLocker containerLocker(fContainer); +// TODO:... +} + + +void +VariablesView::VariableTableModel::ValueNodeValueChanged(ValueNode* valueNode) +{ + if (fContainer == NULL) + return; + + AutoLocker containerLocker(fContainer); + + // check whether we know the node + ValueNodeChild* nodeChild = valueNode->NodeChild(); + if (nodeChild == NULL) + return; + + ModelNode* modelNode = fNodeTable.Lookup(nodeChild); + if (modelNode == NULL) + return; + + // check whether the value actually changed + Value* value = valueNode->GetValue(); + if (value == modelNode->GetValue()) + return; + + // get a value handler + ValueHandler* valueHandler; + status_t error = ValueHandlerRoster::Default()->FindValueHandler(value, + valueHandler); + if (error != B_OK) + return; + BReference handlerReference(valueHandler, true); + + // create a table cell renderer for the value + TableCellValueRenderer* renderer = NULL; + error = valueHandler->GetTableCellValueRenderer(value, renderer); + if (error != B_OK) + return; + + // set value/handler/renderer + modelNode->SetValue(value); + modelNode->SetValueHandler(valueHandler); + modelNode->SetTableCellRenderer(renderer); + + // notify table model listeners + NotifyNodeChanged(modelNode); +} + + +int32 +VariablesView::VariableTableModel::CountColumns() const +{ + return 2; +} + + +void* +VariablesView::VariableTableModel::Root() const +{ + return (void*)this; +} + + +int32 +VariablesView::VariableTableModel::CountChildren(void* parent) const +{ + if (parent == this) + return fNodes.CountItems(); + + // If the node only has a hidden child, pretend the node directly has the + // child's children. + ModelNode* modelNode = (ModelNode*)parent; + int32 childCount = modelNode->CountChildren(); + if (childCount == 1) { + ModelNode* child = modelNode->ChildAt(0); + if (child->IsHidden()) + return child->CountChildren(); + } + + return childCount; +} + + +void* +VariablesView::VariableTableModel::ChildAt(void* parent, int32 index) const +{ + if (parent == this) + return fNodes.ItemAt(index); + + // If the node only has a hidden child, pretend the node directly has the + // child's children. + ModelNode* modelNode = (ModelNode*)parent; + int32 childCount = modelNode->CountChildren(); + if (childCount == 1) { + ModelNode* child = modelNode->ChildAt(0); + if (child->IsHidden()) + return child->ChildAt(index); + } + + return modelNode->ChildAt(index); +} + + +bool +VariablesView::VariableTableModel::GetValueAt(void* object, int32 columnIndex, + BVariant& _value) +{ + ModelNode* node = (ModelNode*)object; + + switch (columnIndex) { + case 0: + _value.SetTo(node->Name(), B_VARIANT_DONT_COPY_DATA); + return true; + case 1: + if (node->GetValue() == NULL) + return false; + + _value.SetTo(node, VALUE_NODE_TYPE); + return true; + default: + return false; + } +} + + +void +VariablesView::VariableTableModel::NodeExpanded(ModelNode* node) +{ + if (fContainer == NULL) + return; + + AutoLocker containerLocker(fContainer); + + // add children of all children + + // If the node only has a hidden child, add the child's children instead. + if (node->CountChildren() == 1) { + ModelNode* child = node->ChildAt(0); + if (child->IsHidden()) + node = child; + } + + // add the children + for (int32 i = 0; ModelNode* child = node->ChildAt(i); i++) + _AddChildNodes(child->NodeChild()); +} + + +void +VariablesView::VariableTableModel::NotifyNodeChanged(ModelNode* node) +{ + if (!node->IsHidden()) { + TreeTablePath treePath; + if (_GetTreePath(node, treePath)) { + int32 index = treePath.RemoveLastComponent(); + NotifyNodesChanged(treePath, index, 1); + } + } +} + + +status_t +VariablesView::VariableTableModel::_AddNode(ModelNode* parent, + ValueNodeChild* nodeChild, bool isPresentationNode) +{ + // Don't create nodes for unspecified types -- we can't get/show their + // value anyway. + Type* nodeChildRawType = nodeChild->GetType()->ResolveRawType(false); + if (nodeChildRawType->Kind() == TYPE_UNSPECIFIED) + return B_OK; + + ModelNode* node = new(std::nothrow) ModelNode(parent, nodeChild, + isPresentationNode); + BReference nodeReference(node, true); + if (node == NULL) + return B_NO_MEMORY; + + int32 childIndex; + + if (parent != NULL) { + childIndex = parent->CountChildren(); + + if (!parent->AddChild(node)) + return B_NO_MEMORY; + // the parent has a reference, now + } else { + childIndex = fNodes.CountItems(); + + if (!fNodes.AddItem(node)) + return B_NO_MEMORY; + nodeReference.Detach(); + // the fNodes list has a reference, now + } + + fNodeTable.Insert(node); + + // mark a compound type child of a address type parent hidden + if (parent != NULL) { + ValueNode* parentValueNode = parent->NodeChild()->Node(); + if (parentValueNode != NULL + && parentValueNode->GetType()->ResolveRawType(false)->Kind() + == TYPE_ADDRESS + && nodeChildRawType->Kind() == TYPE_COMPOUND) { + node->SetHidden(true); + } + } + + // notify table model listeners + if (!node->IsHidden()) { + TreeTablePath path; + if (parent == NULL || _GetTreePath(parent, path)) + NotifyNodesAdded(path, childIndex, 1); + } + + // if the node is hidden, add its children + if (node->IsHidden()) + _AddChildNodes(nodeChild); + + return B_OK; +} + + +void +VariablesView::VariableTableModel::_AddNode(Variable* variable) +{ + // create the node child for the variable + ValueNodeChild* nodeChild = new (std::nothrow) VariableValueNodeChild( + variable); + BReference nodeChildReference(nodeChild, true); + if (nodeChild == NULL || !fContainer->AddChild(nodeChild)) { + delete nodeChild; + return; + } + + // create the model node + status_t error = _AddNode(NULL, nodeChild, false); + if (error != B_OK) + return; + + // automatically add child nodes for the top level nodes + _AddChildNodes(nodeChild); +} + + +status_t +VariablesView::VariableTableModel::_CreateValueNode(ValueNodeChild* nodeChild) +{ + if (nodeChild->Node() != NULL) + return B_OK; + + // create the node + ValueNode* valueNode; + status_t error; + if (nodeChild->IsInternal()) { + error = nodeChild->CreateInternalNode(valueNode); + } else { + error = TypeHandlerRoster::Default()->CreateValueNode(nodeChild, + nodeChild->GetType(), valueNode); + } + + if (error != B_OK) + return error; + + nodeChild->SetNode(valueNode); + valueNode->ReleaseReference(); + + return B_OK; +} + + +status_t +VariablesView::VariableTableModel::_AddChildNodes(ValueNodeChild* nodeChild) +{ + // create a value node for the value node child, if doesn't have one yet + ValueNode* valueNode = nodeChild->Node(); + if (valueNode == NULL) { + status_t error = _CreateValueNode(nodeChild); + if (error != B_OK) + return error; + valueNode = nodeChild->Node(); + } + + // create the children, if not done yet + if (valueNode->ChildrenCreated()) + return B_OK; + + return valueNode->CreateChildren(); +} + + +//VariablesView::ModelNode* +//VariablesView::VariableTableModel::_GetNode(Variable* variable, +// TypeComponentPath* path) const +//{ +// // find the variable node +// ModelNode* node; +// for (int32 i = 0; (node = fNodes.ItemAt(i)) != NULL; i++) { +// if (node->GetVariable() == variable) +// break; +// } +// if (node == NULL) +// return NULL; +// +// // Now walk along the path, finding the respective child node for each +// // component (might be several components at once). +// int32 componentCount = path->CountComponents(); +// for (int32 i = 0; i < componentCount;) { +// ModelNode* childNode = NULL; +// +// for (int32 k = 0; (childNode = node->ChildAt(k)) != NULL; k++) { +// TypeComponentPath* childPath = childNode->Path(); +// int32 childComponentCount = childPath->CountComponents(); +// if (childComponentCount > componentCount) +// continue; +// +// for (int32 componentIndex = i; +// componentIndex < childComponentCount; componentIndex++) { +// TypeComponent childComponent +// = childPath->ComponentAt(componentIndex); +// TypeComponent pathComponent +// = path->ComponentAt(componentIndex); +// if (childComponent != pathComponent) { +// if (componentIndex + 1 == childComponentCount +// && pathComponent.HasPrefix(childComponent)) { +// // The last child component is a prefix of the +// // corresponding path component. We consider this a +// // match, but need to recheck the component with the +// // next node level. +// childComponentCount--; +// break; +// } +// +// // mismatch -- skip the child +// childNode = NULL; +// break; +// } +// } +// +// if (childNode != NULL) { +// // got a match -- skip the matched children components +// i = childComponentCount; +// break; +// } +// } +// +// if (childNode == NULL) +// return NULL; +// +// node = childNode; +// } +// +// return node; +//} + + +bool +VariablesView::VariableTableModel::_GetTreePath(ModelNode* node, + TreeTablePath& _path) const +{ + // recurse, if the node has a parent + if (ModelNode* parent = node->Parent()) { + if (!_GetTreePath(parent, _path)) + return false; + + if (node->IsHidden()) + return true; + + return _path.AddComponent(parent->IndexOf(node)); + } + + // no parent -- get the index and start the path + int32 index = fNodes.IndexOf(node); + _path.Clear(); + return index >= 0 && _path.AddComponent(index); +} + + // #pragma mark - VariablesView @@ -753,8 +1181,10 @@ VariablesView::VariablesView(Listener* listener) fStackFrame(NULL), fVariableTable(NULL), fVariableTableModel(NULL), + fContainerListener(NULL), fPreviousViewState(NULL), fViewStateHistory(NULL), + fTableCellContextMenuTracker(NULL), fListener(listener) { SetName("Variables"); @@ -765,10 +1195,17 @@ VariablesView::~VariablesView() { SetStackFrame(NULL, NULL); fVariableTable->SetTreeTableModel(NULL); + if (fPreviousViewState != NULL) fPreviousViewState->ReleaseReference(); delete fViewStateHistory; - delete fVariableTableModel; + + if (fVariableTableModel != NULL) { + fVariableTableModel->SetContainerListener(NULL); + delete fVariableTableModel; + } + + delete fContainerListener; } @@ -794,7 +1231,9 @@ VariablesView::SetStackFrame(Thread* thread, StackFrame* stackFrame) if (thread == fThread && stackFrame == fStackFrame) return; - _SaveViewState(); +// _SaveViewState(); + + _FinishContextMenu(true); if (fThread != NULL) fThread->ReleaseReference(); @@ -815,24 +1254,96 @@ VariablesView::SetStackFrame(Thread* thread, StackFrame* stackFrame) if (fThread != NULL && fStackFrame != NULL) { AutoLocker locker(fThread->GetTeam()); - for (int32 i = 0; Variable* variable = fStackFrame->ParameterAt(i); i++) - _RequestVariableValue(variable); - - for (int32 i = 0; Variable* variable = fStackFrame->LocalVariableAt(i); - i++) { - _RequestVariableValue(variable); + void* root = fVariableTableModel->Root(); + int32 count = fVariableTableModel->CountChildren(root); + for (int32 i = 0; i < count; i++) { + ModelNode* node = (ModelNode*)fVariableTableModel->ChildAt(root, i); + _RequestNodeValue(node); } } - _RestoreViewState(); +// _RestoreViewState(); } void -VariablesView::StackFrameValueRetrieved(StackFrame* stackFrame, - Variable* variable, TypeComponentPath* path) +VariablesView::MessageReceived(BMessage* message) { - fVariableTableModel->StackFrameValueRetrieved(stackFrame, variable, path); + switch (message->what) { + case MSG_VALUE_NODE_CHANGED: + { + ValueNodeChild* nodeChild; + ValueNode* oldNode; + ValueNode* newNode; + if (message->FindPointer("nodeChild", (void**)&nodeChild) == B_OK + && message->FindPointer("oldNode", (void**)&oldNode) == B_OK + && message->FindPointer("newNode", (void**)&newNode) == B_OK) { + BReference nodeChildReference(nodeChild, true); + BReference oldNodeReference(oldNode, true); + BReference newNodeReference(newNode, true); + + fVariableTableModel->ValueNodeChanged(nodeChild, oldNode, + newNode); + } + + break; + } + case MSG_VALUE_NODE_CHILDREN_CREATED: + { + ValueNode* node; + if (message->FindPointer("node", (void**)&node) == B_OK) { + BReference newNodeReference(node, true); + fVariableTableModel->ValueNodeChildrenCreated(node); + } + + break; + } + case MSG_VALUE_NODE_CHILDREN_DELETED: + { + ValueNode* node; + if (message->FindPointer("node", (void**)&node) == B_OK) { + BReference newNodeReference(node, true); + fVariableTableModel->ValueNodeChildrenDeleted(node); + } + + break; + } + case MSG_VALUE_NODE_VALUE_CHANGED: + { + ValueNode* node; + if (message->FindPointer("node", (void**)&node) == B_OK) { + BReference newNodeReference(node, true); + fVariableTableModel->ValueNodeValueChanged(node); + } + + break; + } + case MSG_VARIABLES_VIEW_CONTEXT_MENU_DONE: + { + _FinishContextMenu(false); + break; + } + case MSG_VARIABLES_VIEW_NODE_SETTINGS_CHANGED: + { + ModelNode* node; + if (message->FindPointer("node", (void**)&node) != B_OK) + break; + BReference nodeReference(node, true); + + fVariableTableModel->NotifyNodeChanged(node); + break; + } + default: + BGroupView::MessageReceived(message); + break; + } +} + + +void +VariablesView::DetachedFromWindow() +{ + _FinishContextMenu(true); } @@ -841,29 +1352,73 @@ VariablesView::TreeTableNodeExpandedChanged(TreeTable* table, const TreeTablePath& path, bool expanded) { if (expanded) { - ValueNode* node = (ValueNode*)fVariableTableModel->NodeForPath(path); + ModelNode* node = (ModelNode*)fVariableTableModel->NodeForPath(path); if (node == NULL) return; fVariableTableModel->NodeExpanded(node); // request the values of all children that don't have any yet - for (int32 i = 0; ValueNode* child = node->ChildAt(i); i++) { + + // If the node only has a hidden child, directly load the child's + // children's values. + if (node->CountChildren() == 1) { + ModelNode* child = node->ChildAt(0); + if (child->IsHidden()) + node = child; + } + + // request the values + for (int32 i = 0; ModelNode* child = node->ChildAt(i); i++) { if (child->IsPresentationNode()) continue; - Variable* variable = child->GetVariable(); - TypeComponentPath* path = child->Path(); - if (fStackFrame->Values()->HasValue(variable->ID(), *path)) - continue; - - fListener->StackFrameValueRequested(fThread, fStackFrame, variable, - path); + _RequestNodeValue(child); } } } +void +VariablesView::TreeTableCellMouseDown(TreeTable* table, + const TreeTablePath& path, int32 columnIndex, BPoint screenWhere, + uint32 buttons) +{ + if ((buttons & B_SECONDARY_MOUSE_BUTTON) == 0) + return; + + _FinishContextMenu(true); + + ModelNode* node = (ModelNode*)fVariableTableModel->NodeForPath(path); + if (node == NULL) + return; + + TableCellValueRenderer* cellRenderer = node->TableCellRenderer(); + if (cellRenderer == NULL) + return; + + Settings* settings = cellRenderer->GetSettings(); + if (settings == NULL) + return; + + SettingsMenu* settingsMenu; + status_t error = node->GetValueHandler()->CreateTableCellValueSettingsMenu( + node->GetValue(), settings, settingsMenu); + Reference settingsMenuReference(settingsMenu, true); + if (error != B_OK) + return; + + TableCellContextMenuTracker* tracker = new(std::nothrow) + TableCellContextMenuTracker(node, Looper(), this); + Reference trackerReference(tracker); + if (tracker == NULL || tracker->Init(settings, settingsMenu) != B_OK) + return; + + fTableCellContextMenuTracker = trackerReference.Detach(); + fTableCellContextMenuTracker->ShowMenu(screenWhere); +} + + void VariablesView::_Init() { @@ -878,8 +1433,13 @@ VariablesView::_Init() B_TRUNCATE_END, B_ALIGN_RIGHT)); fVariableTableModel = new VariableTableModel; + if (fVariableTableModel->Init() != B_OK) + throw std::bad_alloc(); fVariableTable->SetTreeTableModel(fVariableTableModel); + fContainerListener = new ContainerListener(this); + fVariableTableModel->SetContainerListener(fContainerListener); + fVariableTable->AddTreeTableListener(this); fViewStateHistory = new VariablesViewStateHistory; @@ -889,21 +1449,48 @@ VariablesView::_Init() void -VariablesView::_RequestVariableValue(Variable* variable) +VariablesView::_RequestNodeValue(ModelNode* node) { - StackFrameValues* values = fStackFrame->Values(); - if (values->HasValue(variable->ID(), TypeComponentPath())) + // get the node child and its container + ValueNodeChild* nodeChild = node->NodeChild(); + ValueNodeContainer* container = nodeChild->Container(); + + Reference containerReference(container); + AutoLocker containerLocker(container); + + if (container == NULL || nodeChild->Container() != container) return; - TypeComponentPath* path = new(std::nothrow) TypeComponentPath; - if (path == NULL) + // get the value node and check whether its value has not yet been resolved + ValueNode* valueNode = nodeChild->Node(); + if (valueNode == NULL + || valueNode->LocationAndValueResolutionState() + != VALUE_NODE_UNRESOLVED) { return; - Reference pathReference(path, true); + } - fListener->StackFrameValueRequested(fThread, fStackFrame, variable, path); + Reference valueNodeReference(valueNode); + containerLocker.Unlock(); + + // request resolution of the value + fListener->ValueNodeValueRequested(fStackFrame->GetCpuState(), container, + valueNode); } +void +VariablesView::_FinishContextMenu(bool force) +{ + if (fTableCellContextMenuTracker != NULL) { + if (!fTableCellContextMenuTracker->FinishMenu(force) || force) { + fTableCellContextMenuTracker->ReleaseReference(); + fTableCellContextMenuTracker = NULL; + } + } +} + + +#if 0 void VariablesView::_SaveViewState() const { @@ -978,7 +1565,7 @@ VariablesView::_AddViewStateDescendentNodeInfos(VariablesViewState* viewState, { int32 childCount = fVariableTableModel->CountChildren(parent); for (int32 i = 0; i < childCount; i++) { - ValueNode* node = (ValueNode*)fVariableTableModel->ChildAt(parent, i); + ModelNode* node = (ModelNode*)fVariableTableModel->ChildAt(parent, i); if (!path.AddComponent(i)) return B_NO_MEMORY; @@ -1009,7 +1596,7 @@ VariablesView::_ApplyViewStateDescendentNodeInfos(VariablesViewState* viewState, { int32 childCount = fVariableTableModel->CountChildren(parent); for (int32 i = 0; i < childCount; i++) { - ValueNode* node = (ValueNode*)fVariableTableModel->ChildAt(parent, i); + ModelNode* node = (ModelNode*)fVariableTableModel->ChildAt(parent, i); if (!path.AddComponent(i)) return B_NO_MEMORY; @@ -1031,6 +1618,7 @@ VariablesView::_ApplyViewStateDescendentNodeInfos(VariablesViewState* viewState, return B_OK; } +#endif // 0 // #pragma mark - Listener diff --git a/src/apps/debugger/user_interface/gui/team_window/VariablesView.h b/src/apps/debugger/user_interface/gui/team_window/VariablesView.h index 6570c4d6ae..49f2f2d7c0 100644 --- a/src/apps/debugger/user_interface/gui/team_window/VariablesView.h +++ b/src/apps/debugger/user_interface/gui/team_window/VariablesView.h @@ -11,9 +11,13 @@ #include "table/TreeTable.h" +class CpuState; +class SettingsMenu; class StackFrame; class Thread; class TypeComponentPath; +class ValueNode; +class ValueNodeContainer; class Variable; class VariablesViewState; class VariablesViewStateHistory; @@ -32,41 +36,53 @@ public: void SetStackFrame(Thread* thread, StackFrame* stackFrame); - void StackFrameValueRetrieved(StackFrame* stackFrame, - Variable* variable, - TypeComponentPath* path); + + virtual void MessageReceived(BMessage* message); + + virtual void DetachedFromWindow(); private: // TreeTableListener virtual void TreeTableNodeExpandedChanged(TreeTable* table, const TreeTablePath& path, bool expanded); + virtual void TreeTableCellMouseDown(TreeTable* table, + const TreeTablePath& path, + int32 columnIndex, BPoint screenWhere, + uint32 buttons); + private: - class ValueNode; + class ContainerListener; + class ModelNode; class VariableValueColumn; class VariableTableModel; + class ContextMenu; + class TableCellContextMenuTracker; private: void _Init(); - void _RequestVariableValue(Variable* variable); + void _RequestNodeValue(ModelNode* node); + void _FinishContextMenu(bool force); - void _SaveViewState() const; - void _RestoreViewState(); - status_t _AddViewStateDescendentNodeInfos( - VariablesViewState* viewState, void* parent, - TreeTablePath& path) const; - status_t _ApplyViewStateDescendentNodeInfos( - VariablesViewState* viewState, void* parent, - TreeTablePath& path); +// void _SaveViewState() const; +// void _RestoreViewState(); +// status_t _AddViewStateDescendentNodeInfos( +// VariablesViewState* viewState, void* parent, +// TreeTablePath& path) const; +// status_t _ApplyViewStateDescendentNodeInfos( +// VariablesViewState* viewState, void* parent, +// TreeTablePath& path); private: Thread* fThread; StackFrame* fStackFrame; TreeTable* fVariableTable; VariableTableModel* fVariableTableModel; + ContainerListener* fContainerListener; VariablesViewState* fPreviousViewState; VariablesViewStateHistory* fViewStateHistory; + TableCellContextMenuTracker* fTableCellContextMenuTracker; Listener* fListener; }; @@ -75,10 +91,9 @@ class VariablesView::Listener { public: virtual ~Listener(); - virtual void StackFrameValueRequested(Thread* thread, - StackFrame* stackFrame, Variable* variable, - TypeComponentPath* path) = 0; - // called with team locked + virtual void ValueNodeValueRequested(CpuState* cpuState, + ValueNodeContainer* container, + ValueNode* valueNode) = 0; }; diff --git a/src/apps/debugger/user_interface/gui/value/TableCellBoolRenderer.cpp b/src/apps/debugger/user_interface/gui/value/TableCellBoolRenderer.cpp new file mode 100644 index 0000000000..d7c19953d0 --- /dev/null +++ b/src/apps/debugger/user_interface/gui/value/TableCellBoolRenderer.cpp @@ -0,0 +1,41 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + + +#include "TableCellBoolRenderer.h" + +#include "BoolValue.h" +#include "TableCellValueRendererUtils.h" + + +static inline const char* +bool_value_string(BoolValue* value) +{ + return value->GetValue() ? "true" : "false"; +} + + +void +TableCellBoolRenderer::RenderValue(Value* _value, BRect rect, BView* targetView) +{ + BoolValue* value = dynamic_cast(_value); + if (value == NULL) + return; + + TableCellValueRendererUtils::DrawString(targetView, rect, + bool_value_string(value), B_ALIGN_RIGHT, true); +} + + +float +TableCellBoolRenderer::PreferredValueWidth(Value* _value, BView* targetView) +{ + BoolValue* value = dynamic_cast(_value); + if (value == NULL) + return 0; + + return TableCellValueRendererUtils::PreferredStringWidth(targetView, + bool_value_string(value)); +} diff --git a/src/apps/debugger/user_interface/gui/value/TableCellBoolRenderer.h b/src/apps/debugger/user_interface/gui/value/TableCellBoolRenderer.h new file mode 100644 index 0000000000..d3f4246755 --- /dev/null +++ b/src/apps/debugger/user_interface/gui/value/TableCellBoolRenderer.h @@ -0,0 +1,23 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef TABLE_CELL_BOOL_RENDERER_H +#define TABLE_CELL_BOOL_RENDERER_H + + +#include + +#include "TableCellValueRenderer.h" + + +class TableCellBoolRenderer : public TableCellValueRenderer { +public: + virtual void RenderValue(Value* value, BRect rect, + BView* targetView); + virtual float PreferredValueWidth(Value* value, + BView* targetView); +}; + + +#endif // TABLE_CELL_BOOL_RENDERER_H diff --git a/src/apps/debugger/user_interface/gui/value/TableCellEnumerationRenderer.cpp b/src/apps/debugger/user_interface/gui/value/TableCellEnumerationRenderer.cpp new file mode 100644 index 0000000000..1852e5eaa1 --- /dev/null +++ b/src/apps/debugger/user_interface/gui/value/TableCellEnumerationRenderer.cpp @@ -0,0 +1,61 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + + +#include "TableCellEnumerationRenderer.h" + +#include "EnumerationValue.h" +#include "TableCellValueRendererUtils.h" +#include "Type.h" + + +TableCellEnumerationRenderer::TableCellEnumerationRenderer(Config* config) + : + TableCellIntegerRenderer(config) +{ +} + + +void +TableCellEnumerationRenderer::RenderValue(Value* _value, BRect rect, + BView* targetView) +{ + Config* config = GetConfig(); + if (config != NULL && config->IntegerFormat() == INTEGER_FORMAT_DEFAULT) { + EnumerationValue* value = dynamic_cast(_value); + if (value == NULL) + return; + + if (EnumeratorValue* enumValue + = value->GetType()->ValueFor(value->GetValue())) { + TableCellValueRendererUtils::DrawString(targetView, rect, + enumValue->Name(), B_ALIGN_RIGHT, true); + return; + } + } + + TableCellIntegerRenderer::RenderValue(_value, rect, targetView); +} + + +float +TableCellEnumerationRenderer::PreferredValueWidth(Value* _value, + BView* targetView) +{ + Config* config = GetConfig(); + if (config != NULL && config->IntegerFormat() == INTEGER_FORMAT_DEFAULT) { + EnumerationValue* value = dynamic_cast(_value); + if (value == NULL) + return 0; + + if (EnumeratorValue* enumValue + = value->GetType()->ValueFor(value->GetValue())) { + return TableCellValueRendererUtils::PreferredStringWidth(targetView, + enumValue->Name()); + } + } + + return TableCellIntegerRenderer::PreferredValueWidth(_value, targetView); +} diff --git a/src/apps/debugger/user_interface/gui/value/TableCellEnumerationRenderer.h b/src/apps/debugger/user_interface/gui/value/TableCellEnumerationRenderer.h new file mode 100644 index 0000000000..6a68fb544a --- /dev/null +++ b/src/apps/debugger/user_interface/gui/value/TableCellEnumerationRenderer.h @@ -0,0 +1,25 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef TABLE_CELL_ENUMERATION_RENDERER_H +#define TABLE_CELL_ENUMERATION_RENDERER_H + + +#include + +#include "TableCellIntegerRenderer.h" + + +class TableCellEnumerationRenderer : public TableCellIntegerRenderer { +public: + TableCellEnumerationRenderer(Config* config); + + virtual void RenderValue(Value* value, BRect rect, + BView* targetView); + virtual float PreferredValueWidth(Value* value, + BView* targetView); +}; + + +#endif // TABLE_CELL_ENUMERATION_RENDERER_H diff --git a/src/apps/debugger/user_interface/gui/value/TableCellFloatRenderer.cpp b/src/apps/debugger/user_interface/gui/value/TableCellFloatRenderer.cpp new file mode 100644 index 0000000000..fa71cb841f --- /dev/null +++ b/src/apps/debugger/user_interface/gui/value/TableCellFloatRenderer.cpp @@ -0,0 +1,42 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + + +#include "TableCellFloatRenderer.h" + +#include + +#include "FloatValue.h" +#include "TableCellValueRendererUtils.h" + + +void +TableCellFloatRenderer::RenderValue(Value* _value, BRect rect, BView* targetView) +{ + FloatValue* value = dynamic_cast(_value); + if (value == NULL) + return; + + char buffer[64]; + snprintf(buffer, sizeof(buffer), "%g", value->GetValue()); + + TableCellValueRendererUtils::DrawString(targetView, rect, buffer, + B_ALIGN_RIGHT, true); +} + + +float +TableCellFloatRenderer::PreferredValueWidth(Value* _value, BView* targetView) +{ + FloatValue* value = dynamic_cast(_value); + if (value == NULL) + return 0; + + char buffer[64]; + snprintf(buffer, sizeof(buffer), "%g", value->GetValue()); + + return TableCellValueRendererUtils::PreferredStringWidth(targetView, + buffer); +} diff --git a/src/apps/debugger/user_interface/gui/value/TableCellFloatRenderer.h b/src/apps/debugger/user_interface/gui/value/TableCellFloatRenderer.h new file mode 100644 index 0000000000..2058d9ae61 --- /dev/null +++ b/src/apps/debugger/user_interface/gui/value/TableCellFloatRenderer.h @@ -0,0 +1,23 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef TABLE_CELL_FLOAT_RENDERER_H +#define TABLE_CELL_FLOAT_RENDERER_H + + +#include + +#include "TableCellValueRenderer.h" + + +class TableCellFloatRenderer : public TableCellValueRenderer { +public: + virtual void RenderValue(Value* value, BRect rect, + BView* targetView); + virtual float PreferredValueWidth(Value* value, + BView* targetView); +}; + + +#endif // TABLE_CELL_FLOAT_RENDERER_H diff --git a/src/apps/debugger/user_interface/gui/value/TableCellIntegerRenderer.cpp b/src/apps/debugger/user_interface/gui/value/TableCellIntegerRenderer.cpp new file mode 100644 index 0000000000..751fcfac7b --- /dev/null +++ b/src/apps/debugger/user_interface/gui/value/TableCellIntegerRenderer.cpp @@ -0,0 +1,93 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + + +#include "TableCellIntegerRenderer.h" + +#include + +#include + +#include "TableCellValueRendererUtils.h" +#include "IntegerValue.h" + + +// #pragma mark - TableCellIntegerRenderer + + +TableCellIntegerRenderer::TableCellIntegerRenderer(Config* config) + : + fConfig(config) +{ + if (fConfig != NULL) + fConfig->AcquireReference(); +} + + +TableCellIntegerRenderer::~TableCellIntegerRenderer() +{ + if (fConfig != NULL) + fConfig->ReleaseReference(); +} + + +Settings* +TableCellIntegerRenderer::GetSettings() const +{ + return fConfig != NULL ? fConfig->GetSettings() : NULL; +} + + +void +TableCellIntegerRenderer::RenderValue(Value* _value, BRect rect, + BView* targetView) +{ + IntegerValue* value = dynamic_cast(_value); + if (value == NULL) + return; + + // format the value + integer_format format = fConfig != NULL + ? fConfig->IntegerFormat() : INTEGER_FORMAT_DEFAULT; + char buffer[32]; + if (!IntegerFormatter::FormatValue(value->GetValue(), format, buffer, + sizeof(buffer))) { + return; + } + + // render + TableCellValueRendererUtils::DrawString(targetView, rect, buffer, + B_ALIGN_RIGHT, true); +} + + +float +TableCellIntegerRenderer::PreferredValueWidth(Value* _value, BView* targetView) +{ + IntegerValue* value = dynamic_cast(_value); + if (value == NULL) + return 0; + + // format the value + integer_format format = fConfig != NULL + ? fConfig->IntegerFormat() : INTEGER_FORMAT_DEFAULT; + char buffer[32]; + if (!IntegerFormatter::FormatValue(value->GetValue(), format, buffer, + sizeof(buffer))) { + return 0; + } + + // render + return TableCellValueRendererUtils::PreferredStringWidth(targetView, + buffer); +} + + +// #pragma mark - Config + + +TableCellIntegerRenderer::Config::~Config() +{ +} diff --git a/src/apps/debugger/user_interface/gui/value/TableCellIntegerRenderer.h b/src/apps/debugger/user_interface/gui/value/TableCellIntegerRenderer.h new file mode 100644 index 0000000000..2061fec649 --- /dev/null +++ b/src/apps/debugger/user_interface/gui/value/TableCellIntegerRenderer.h @@ -0,0 +1,47 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef TABLE_CELL_INTEGER_RENDERER_H +#define TABLE_CELL_INTEGER_RENDERER_H + + +#include + +#include "IntegerFormatter.h" +#include "TableCellValueRenderer.h" + + +class TableCellIntegerRenderer : public TableCellValueRenderer { +public: + class Config; + +public: + TableCellIntegerRenderer(Config* config); + virtual ~TableCellIntegerRenderer(); + + Config* GetConfig() const + { return fConfig; } + + virtual Settings* GetSettings() const; + + virtual void RenderValue(Value* value, BRect rect, + BView* targetView); + virtual float PreferredValueWidth(Value* value, + BView* targetView); + +private: + Config* fConfig; +}; + + +class TableCellIntegerRenderer::Config : public BReferenceable { +public: + virtual ~Config(); + + virtual Settings* GetSettings() const = 0; + virtual integer_format IntegerFormat() const = 0; +}; + + +#endif // TABLE_CELL_INTEGER_RENDERER_H diff --git a/src/apps/debugger/user_interface/gui/value/TableCellStringRenderer.cpp b/src/apps/debugger/user_interface/gui/value/TableCellStringRenderer.cpp new file mode 100644 index 0000000000..b6f8ac538b --- /dev/null +++ b/src/apps/debugger/user_interface/gui/value/TableCellStringRenderer.cpp @@ -0,0 +1,37 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + + +#include "TableCellStringRenderer.h" + +#include + +#include "TableCellValueRendererUtils.h" +#include "Value.h" + + +void +TableCellStringRenderer::RenderValue(Value* value, BRect rect, + BView* targetView) +{ + BString string; + if (!value->ToString(string)) + return; + + TableCellValueRendererUtils::DrawString(targetView, rect, string, + B_ALIGN_LEFT, true); +} + + +float +TableCellStringRenderer::PreferredValueWidth(Value* value, BView* targetView) +{ + BString string; + if (!value->ToString(string)) + return 0; + + return TableCellValueRendererUtils::PreferredStringWidth(targetView, + string); +} diff --git a/src/apps/debugger/user_interface/gui/value/TableCellStringRenderer.h b/src/apps/debugger/user_interface/gui/value/TableCellStringRenderer.h new file mode 100644 index 0000000000..5e05efd6f7 --- /dev/null +++ b/src/apps/debugger/user_interface/gui/value/TableCellStringRenderer.h @@ -0,0 +1,23 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef TABLE_CELL_STRING_RENDERER_H +#define TABLE_CELL_STRING_RENDERER_H + + +#include "TableCellValueRenderer.h" + +#include + + +class TableCellStringRenderer : public TableCellValueRenderer { +public: + virtual void RenderValue(Value* value, BRect rect, + BView* targetView); + virtual float PreferredValueWidth(Value* value, + BView* targetView); +}; + + +#endif // TABLE_CELL_STRING_RENDERER_H diff --git a/src/apps/debugger/user_interface/gui/value/TableCellValueRenderer.cpp b/src/apps/debugger/user_interface/gui/value/TableCellValueRenderer.cpp new file mode 100644 index 0000000000..0e4e9f850f --- /dev/null +++ b/src/apps/debugger/user_interface/gui/value/TableCellValueRenderer.cpp @@ -0,0 +1,19 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + + +#include "TableCellValueRenderer.h" + + +TableCellValueRenderer::~TableCellValueRenderer() +{ +} + + +Settings* +TableCellValueRenderer::GetSettings() const +{ + return NULL; +} diff --git a/src/apps/debugger/user_interface/gui/value/TableCellValueRenderer.h b/src/apps/debugger/user_interface/gui/value/TableCellValueRenderer.h new file mode 100644 index 0000000000..019e4c9102 --- /dev/null +++ b/src/apps/debugger/user_interface/gui/value/TableCellValueRenderer.h @@ -0,0 +1,33 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef TABLE_CELL_VALUE_RENDERER_H +#define TABLE_CELL_VALUE_RENDERER_H + + +#include + +#include + + +class BView; +class Settings; +class Value; + + +class TableCellValueRenderer : public BReferenceable { +public: + virtual ~TableCellValueRenderer(); + + virtual Settings* GetSettings() const; + // returns NULL, if no settings + + virtual void RenderValue(Value* value, BRect rect, + BView* targetView) = 0; + virtual float PreferredValueWidth(Value* value, + BView* targetView) = 0; +}; + + +#endif // TABLE_CELL_VALUE_RENDERER_H diff --git a/src/apps/debugger/user_interface/gui/value/TableCellValueRendererUtils.cpp b/src/apps/debugger/user_interface/gui/value/TableCellValueRendererUtils.cpp new file mode 100644 index 0000000000..3af19347cd --- /dev/null +++ b/src/apps/debugger/user_interface/gui/value/TableCellValueRendererUtils.cpp @@ -0,0 +1,68 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + + +#include "TableCellValueRendererUtils.h" + +#include +#include +#include + + +static const float kTextMargin = 8; + + +/*static*/ void +TableCellValueRendererUtils::DrawString(BView* view, BRect rect, + const char* string, enum alignment alignment, bool truncate) +{ + // get font height info + font_height fontHeight; + view->GetFontHeight(&fontHeight); + + // truncate, if requested + BString truncatedString; + if (truncate) { + truncatedString = string; + view->TruncateString(&truncatedString, B_TRUNCATE_END, + rect.Width() - 2 * kTextMargin + 2); + string = truncatedString.String(); + } + + // compute horizontal position according to alignment + float x; + switch (alignment) { + default: + case B_ALIGN_LEFT: + x = rect.left + kTextMargin; + break; + + case B_ALIGN_CENTER: + x = rect.left + (rect.Width() - view->StringWidth(string)) / 2; + break; + + case B_ALIGN_RIGHT: + x = rect.right - kTextMargin - view->StringWidth(string); + break; + } + + // compute vertical position (base line) + float y = rect.top + + (rect.Height() - (fontHeight.ascent + fontHeight.descent + + fontHeight.leading)) / 2 + + (fontHeight.ascent + fontHeight.descent) - 2; + // TODO: This is the computation BColumnListView (respectively + // BTitledColumn) is using, which I find somewhat weird. + + view->DrawString(string, BPoint(x, y)); +} + + +/*static*/ float +TableCellValueRendererUtils::PreferredStringWidth(BView* view, + const char* string) +{ + return view->StringWidth(string) + 2 * kTextMargin; +} diff --git a/src/apps/debugger/user_interface/gui/value/TableCellValueRendererUtils.h b/src/apps/debugger/user_interface/gui/value/TableCellValueRendererUtils.h new file mode 100644 index 0000000000..1f48993532 --- /dev/null +++ b/src/apps/debugger/user_interface/gui/value/TableCellValueRendererUtils.h @@ -0,0 +1,27 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef TABLE_CELL_VALUE_RENDERER_UTILS_H +#define TABLE_CELL_VALUE_RENDERER_UTILS_H + + +#include +#include + + +class BView; + + +class TableCellValueRendererUtils { +public: + static void DrawString(BView* view, BRect rect, + const char* string, + enum alignment alignment, + bool truncate = false); + static float PreferredStringWidth(BView* view, + const char* string); +}; + + +#endif // TABLE_CELL_VALUE_RENDERER_UTILS_H diff --git a/src/apps/debugger/value/TypeHandler.cpp b/src/apps/debugger/value/TypeHandler.cpp new file mode 100644 index 0000000000..3b1433cdf9 --- /dev/null +++ b/src/apps/debugger/value/TypeHandler.cpp @@ -0,0 +1,12 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + + +#include "TypeHandler.h" + + +TypeHandler::~TypeHandler() +{ +} diff --git a/src/apps/debugger/value/TypeHandler.h b/src/apps/debugger/value/TypeHandler.h new file mode 100644 index 0000000000..01c4444937 --- /dev/null +++ b/src/apps/debugger/value/TypeHandler.h @@ -0,0 +1,28 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef TYPE_HANDLER_H +#define TYPE_HANDLER_H + + +#include + + +class Type; +class ValueNode; +class ValueNodeChild; + + +class TypeHandler : public BReferenceable { +public: + virtual ~TypeHandler(); + + virtual float SupportsType(Type* type) = 0; + virtual status_t CreateValueNode(ValueNodeChild* nodeChild, + Type* type, ValueNode*& _node) = 0; + // returns a reference +}; + + +#endif // TYPE_HANDLER_H diff --git a/src/apps/debugger/value/TypeHandlerRoster.cpp b/src/apps/debugger/value/TypeHandlerRoster.cpp new file mode 100644 index 0000000000..d4ae215567 --- /dev/null +++ b/src/apps/debugger/value/TypeHandlerRoster.cpp @@ -0,0 +1,214 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + + +#include "TypeHandlerRoster.h" + +#include + +#include +#include + +#include "AddressValueNode.h" +#include "ArrayValueNode.h" +#include "CompoundValueNode.h" +#include "EnumerationValueNode.h" +#include "PointerToMemberValueNode.h" +#include "PrimitiveValueNode.h" +#include "Type.h" +#include "TypeHandler.h" + + +// #pragma mark - BasicTypeHandler + + +namespace { + + +template +class BasicTypeHandler : public TypeHandler { +public: + virtual float SupportsType(Type* type) + { + return dynamic_cast(type) != NULL ? 0.5f : 0; + } + + virtual status_t CreateValueNode(ValueNodeChild* nodeChild, + Type* type, ValueNode*& _node) + { + TypeClass* supportedType = dynamic_cast(type); + if (supportedType == NULL) + return B_BAD_VALUE; + + ValueNode* node = new(std::nothrow) NodeClass(nodeChild, supportedType); + if (node == NULL) + return B_NO_MEMORY; + + _node = node; + return B_OK; + } +}; + + +} // unnamed namespace + + +// #pragma mark - TypeHandlerRoster + + +/*static*/ TypeHandlerRoster* TypeHandlerRoster::sDefaultInstance = NULL; + + +TypeHandlerRoster::TypeHandlerRoster() + : + fLock("type handler roster") +{ +} + + +TypeHandlerRoster::~TypeHandlerRoster() +{ +} + +/*static*/ TypeHandlerRoster* +TypeHandlerRoster::Default() +{ + return sDefaultInstance; +} + + +/*static*/ status_t +TypeHandlerRoster::CreateDefault() +{ + if (sDefaultInstance != NULL) + return B_OK; + + TypeHandlerRoster* roster = new(std::nothrow) TypeHandlerRoster; + if (roster == NULL) + return B_NO_MEMORY; + ObjectDeleter rosterDeleter(roster); + + status_t error = roster->Init(); + if (error != B_OK) + return error; + + error = roster->RegisterDefaultHandlers(); + if (error != B_OK) + return error; + + sDefaultInstance = rosterDeleter.Detach(); + return B_OK; +} + + +/*static*/ void +TypeHandlerRoster::DeleteDefault() +{ + TypeHandlerRoster* roster = sDefaultInstance; + sDefaultInstance = NULL; + delete roster; +} + + +status_t +TypeHandlerRoster::Init() +{ + return fLock.InitCheck(); +} + + +status_t +TypeHandlerRoster::RegisterDefaultHandlers() +{ + TypeHandler* handler; + Reference handlerReference; + + #undef REGISTER_HANDLER + #define REGISTER_HANDLER(name) \ + handler = new(std::nothrow) \ + BasicTypeHandler(); \ + handlerReference.SetTo(handler, true); \ + if (handler == NULL || !RegisterHandler(handler)) \ + return B_NO_MEMORY; + + REGISTER_HANDLER(Address); + REGISTER_HANDLER(Array); + REGISTER_HANDLER(Compound); + REGISTER_HANDLER(Enumeration); + REGISTER_HANDLER(PointerToMember); + REGISTER_HANDLER(Primitive); + + return B_OK; +} + + +status_t +TypeHandlerRoster::FindTypeHandler(ValueNodeChild* nodeChild, Type* type, + TypeHandler*& _handler) +{ + // find the best-supporting handler + AutoLocker locker(fLock); + + TypeHandler* bestHandler = NULL; + float bestSupport = 0; + + for (int32 i = 0; TypeHandler* handler = fTypeHandlers.ItemAt(i); i++) { + float support = handler->SupportsType(type); + if (support > 0 && support > bestSupport) { + bestHandler = handler; + bestSupport = support; + } + } + + if (bestHandler == NULL) + return B_ENTRY_NOT_FOUND; + + bestHandler->AcquireReference(); + _handler = bestHandler; + return B_OK; +} + + +status_t +TypeHandlerRoster::CreateValueNode(ValueNodeChild* nodeChild, Type* type, + ValueNode*& _node) +{ + // find the best-supporting handler + while (true) { + TypeHandler* handler; + status_t error = FindTypeHandler(nodeChild, type, handler); + if (error == B_OK) { + // let the handler create the node + Reference handlerReference(handler, true); + return handler->CreateValueNode(nodeChild, type, _node); + } + + // not found yet -- try to strip a modifier/typedef from the type + Type* nextType = type->ResolveRawType(true); + if (nextType == NULL || nextType == type) + return B_UNSUPPORTED; + + type = nextType; + } +} + + +bool +TypeHandlerRoster::RegisterHandler(TypeHandler* handler) +{ + if (!fTypeHandlers.AddItem(handler)) + return false; + + handler->AcquireReference(); + return true; +} + + +void +TypeHandlerRoster::UnregisterHandler(TypeHandler* handler) +{ + if (fTypeHandlers.RemoveItem(handler)) + handler->RemoveReference(); +} diff --git a/src/apps/debugger/value/TypeHandlerRoster.h b/src/apps/debugger/value/TypeHandlerRoster.h new file mode 100644 index 0000000000..973f202e1e --- /dev/null +++ b/src/apps/debugger/value/TypeHandlerRoster.h @@ -0,0 +1,51 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef TYPE_HANDLER_ROSTER_H +#define TYPE_HANDLER_ROSTER_H + + +#include +#include + + +class Type; +class TypeHandler; +class ValueNode; +class ValueNodeChild; + + +typedef BObjectList TypeHandlerList; + + +class TypeHandlerRoster { +public: + TypeHandlerRoster(); + ~TypeHandlerRoster(); + + static TypeHandlerRoster* Default(); + static status_t CreateDefault(); + static void DeleteDefault(); + + status_t Init(); + status_t RegisterDefaultHandlers(); + + status_t FindTypeHandler(ValueNodeChild* nodeChild, + Type* type, TypeHandler*& _handler); + // returns a reference + status_t CreateValueNode(ValueNodeChild* nodeChild, + Type* type, ValueNode*& _node); + // returns a reference + + bool RegisterHandler(TypeHandler* handler); + void UnregisterHandler(TypeHandler* handler); + +private: + BLocker fLock; + TypeHandlerList fTypeHandlers; + static TypeHandlerRoster* sDefaultInstance; +}; + + +#endif // TYPE_HANDLER_ROSTER_H diff --git a/src/apps/debugger/value/Value.cpp b/src/apps/debugger/value/Value.cpp new file mode 100644 index 0000000000..caf15f7d63 --- /dev/null +++ b/src/apps/debugger/value/Value.cpp @@ -0,0 +1,12 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + + +#include "Value.h" + + +Value::~Value() +{ +} diff --git a/src/apps/debugger/value/Value.h b/src/apps/debugger/value/Value.h new file mode 100644 index 0000000000..31b191305b --- /dev/null +++ b/src/apps/debugger/value/Value.h @@ -0,0 +1,27 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef VALUE_H +#define VALUE_H + + +#include + +#include + + +class Value : public BReferenceable { +public: + virtual ~Value(); + + virtual bool ToString(BString& _string) const = 0; + virtual bool ToVariant(BVariant& _value) const = 0; + + virtual bool operator==(const Value& other) const = 0; + inline bool operator!=(const Value& other) const + { return !(*this == other); } +}; + + +#endif // VALUE_H diff --git a/src/apps/debugger/value/ValueHandler.cpp b/src/apps/debugger/value/ValueHandler.cpp new file mode 100644 index 0000000000..fc3bf875a2 --- /dev/null +++ b/src/apps/debugger/value/ValueHandler.cpp @@ -0,0 +1,21 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + + +#include "ValueHandler.h" + + +ValueHandler::~ValueHandler() +{ +} + + +status_t +ValueHandler::CreateTableCellValueSettingsMenu(Value* value, Settings* settings, + SettingsMenu*& _menu) +{ + _menu = NULL; + return B_OK; +} diff --git a/src/apps/debugger/value/ValueHandler.h b/src/apps/debugger/value/ValueHandler.h new file mode 100644 index 0000000000..fac0f7eb30 --- /dev/null +++ b/src/apps/debugger/value/ValueHandler.h @@ -0,0 +1,36 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef VALUE_HANDLER_H +#define VALUE_HANDLER_H + + +#include + + +class Settings; +class SettingsMenu; +class TableCellValueRenderer; +class Value; +class ValueFormatter; + + +class ValueHandler : public BReferenceable { +public: + virtual ~ValueHandler(); + + virtual float SupportsValue(Value* value) = 0; + virtual status_t GetValueFormatter(Value* value, + ValueFormatter*& _formatter) = 0; + // returns a reference + virtual status_t GetTableCellValueRenderer(Value* value, + TableCellValueRenderer*& _renderer) = 0; + // returns a reference + virtual status_t CreateTableCellValueSettingsMenu(Value* value, + Settings* settings, SettingsMenu*& _menu); + // may return NULL, otherwise a reference +}; + + +#endif // VALUE_HANDLER_H diff --git a/src/apps/debugger/value/ValueHandlerRoster.cpp b/src/apps/debugger/value/ValueHandlerRoster.cpp new file mode 100644 index 0000000000..dd517397e0 --- /dev/null +++ b/src/apps/debugger/value/ValueHandlerRoster.cpp @@ -0,0 +1,188 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + + +#include "ValueHandlerRoster.h" + +#include + +#include +#include + +#include "AddressValueHandler.h" +#include "BoolValueHandler.h" +#include "EnumerationValueHandler.h" +#include "FloatValueHandler.h" +#include "Value.h" + + +/*static*/ ValueHandlerRoster* ValueHandlerRoster::sDefaultInstance = NULL; + + +ValueHandlerRoster::ValueHandlerRoster() + : + fLock("value handler roster") +{ +} + + +ValueHandlerRoster::~ValueHandlerRoster() +{ +} + +/*static*/ ValueHandlerRoster* +ValueHandlerRoster::Default() +{ + return sDefaultInstance; +} + + +/*static*/ status_t +ValueHandlerRoster::CreateDefault() +{ + if (sDefaultInstance != NULL) + return B_OK; + + ValueHandlerRoster* roster = new(std::nothrow) ValueHandlerRoster; + if (roster == NULL) + return B_NO_MEMORY; + ObjectDeleter rosterDeleter(roster); + + status_t error = roster->Init(); + if (error != B_OK) + return error; + + error = roster->RegisterDefaultHandlers(); + if (error != B_OK) + return error; + + sDefaultInstance = rosterDeleter.Detach(); + return B_OK; +} + + +/*static*/ void +ValueHandlerRoster::DeleteDefault() +{ + ValueHandlerRoster* roster = sDefaultInstance; + sDefaultInstance = NULL; + delete roster; +} + + +status_t +ValueHandlerRoster::Init() +{ + return fLock.InitCheck(); +} + + +status_t +ValueHandlerRoster::RegisterDefaultHandlers() +{ + status_t error; + + #undef REGISTER_HANDLER + #define REGISTER_HANDLER(name) \ + { \ + name##ValueHandler* handler \ + = new(std::nothrow) name##ValueHandler; \ + if (handler == NULL) \ + return B_NO_MEMORY; \ + BReference handlerReference(handler, true); \ + \ + error = handler->Init(); \ + if (error != B_OK) \ + return error; \ + \ + if (!RegisterHandler(handler)) \ + return B_NO_MEMORY; \ + } + + REGISTER_HANDLER(Address) + REGISTER_HANDLER(Bool) + REGISTER_HANDLER(Enumeration) + REGISTER_HANDLER(Float) + REGISTER_HANDLER(Integer) + + return B_OK; +} + + +status_t +ValueHandlerRoster::FindValueHandler(Value* value, ValueHandler*& _handler) +{ + // find the best-supporting handler + AutoLocker locker(fLock); + + ValueHandler* bestHandler = NULL; + float bestSupport = 0; + + for (int32 i = 0; ValueHandler* handler = fValueHandlers.ItemAt(i); i++) { + float support = handler->SupportsValue(value); + if (support > 0 && support > bestSupport) { + bestHandler = handler; + bestSupport = support; + } + } + + if (bestHandler == NULL) + return B_ENTRY_NOT_FOUND; + + bestHandler->AcquireReference(); + _handler = bestHandler; + return B_OK; +} + + +status_t +ValueHandlerRoster::GetValueFormatter(Value* value, + ValueFormatter*& _formatter) +{ + // get the best supporting value handler + ValueHandler* handler; + status_t error = FindValueHandler(value, handler); + if (error != B_OK) + return error; + BReference handlerReference(handler, true); + + // create the formatter + return handler->GetValueFormatter(value, _formatter); +} + + +status_t +ValueHandlerRoster::GetTableCellValueRenderer(Value* value, + TableCellValueRenderer*& _renderer) +{ + // get the best supporting value handler + ValueHandler* handler; + status_t error = FindValueHandler(value, handler); + if (error != B_OK) + return error; + BReference handlerReference(handler, true); + + // create the renderer + return handler->GetTableCellValueRenderer(value, _renderer); +} + + +bool +ValueHandlerRoster::RegisterHandler(ValueHandler* handler) +{ + if (!fValueHandlers.AddItem(handler)) + return false; + + handler->AcquireReference(); + return true; +} + + +void +ValueHandlerRoster::UnregisterHandler(ValueHandler* handler) +{ + if (fValueHandlers.RemoveItem(handler)) + handler->RemoveReference(); +} diff --git a/src/apps/debugger/value/ValueHandlerRoster.h b/src/apps/debugger/value/ValueHandlerRoster.h new file mode 100644 index 0000000000..ae04381c14 --- /dev/null +++ b/src/apps/debugger/value/ValueHandlerRoster.h @@ -0,0 +1,54 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef VALUE_HANDLER_ROSTER_H +#define VALUE_HANDLER_ROSTER_H + + +#include +#include + + +class TableCellValueRenderer; +class Value; +class ValueFormatter; +class ValueHandler; + + +typedef BObjectList ValueHandlerList; + + +class ValueHandlerRoster { +public: + ValueHandlerRoster(); + ~ValueHandlerRoster(); + + static ValueHandlerRoster* Default(); + static status_t CreateDefault(); + static void DeleteDefault(); + + status_t Init(); + status_t RegisterDefaultHandlers(); + + status_t FindValueHandler(Value* value, + ValueHandler*& _handler); + // returns a reference + status_t GetValueFormatter(Value* value, + ValueFormatter*& _formatter); + // returns a reference + status_t GetTableCellValueRenderer(Value* value, + TableCellValueRenderer*& _renderer); + // returns a reference + + bool RegisterHandler(ValueHandler* handler); + void UnregisterHandler(ValueHandler* handler); + +private: + BLocker fLock; + ValueHandlerList fValueHandlers; + static ValueHandlerRoster* sDefaultInstance; +}; + + +#endif // VALUE_HANDLER_ROSTER_H diff --git a/src/apps/debugger/value/ValueLoader.cpp b/src/apps/debugger/value/ValueLoader.cpp new file mode 100644 index 0000000000..75d53da3e3 --- /dev/null +++ b/src/apps/debugger/value/ValueLoader.cpp @@ -0,0 +1,187 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + + +#include "ValueLoader.h" + +#include "Architecture.h" +#include "BitBuffer.h" +#include "CpuState.h" +#include "Register.h" +#include "TeamMemory.h" +#include "Tracing.h" +#include "ValueLocation.h" + + +ValueLoader::ValueLoader(Architecture* architecture, TeamMemory* teamMemory, + CpuState* cpuState) + : + fArchitecture(architecture), + fTeamMemory(teamMemory), + fCpuState(cpuState) +{ +// TODO: TeamMemory is not BReferenceable! + fArchitecture->AcquireReference(); + if (fCpuState != NULL) + fCpuState->AcquireReference(); +} + + +ValueLoader::~ValueLoader() +{ + fArchitecture->ReleaseReference(); + if (fCpuState != NULL) + fCpuState->ReleaseReference(); +} + + +status_t +ValueLoader::LoadValue(ValueLocation* location, type_code valueType, + bool shortValueIsFine, BVariant& _value) +{ + static const size_t kMaxPieceSize = 16; + uint64 totalBitSize = 0; + int32 count = location->CountPieces(); + for (int32 i = 0; i < count; i++) { + ValuePieceLocation piece = location->PieceAt(i); + switch (piece.type) { + case VALUE_PIECE_LOCATION_INVALID: + case VALUE_PIECE_LOCATION_UNKNOWN: + return B_ENTRY_NOT_FOUND; + case VALUE_PIECE_LOCATION_MEMORY: + case VALUE_PIECE_LOCATION_REGISTER: + break; + } + + if (piece.size > kMaxPieceSize) { + TRACE_LOCALS(" -> overly long piece size (%llu bytes)\n", + piece.size); + return B_UNSUPPORTED; + } + + totalBitSize += piece.bitSize; + } + + TRACE_LOCALS(" -> totalBitSize: %llu\n", totalBitSize); + + if (totalBitSize == 0) { + TRACE_LOCALS(" -> no size\n"); + return B_ENTRY_NOT_FOUND; + } + + if (totalBitSize > 64) { + TRACE_LOCALS(" -> longer than 64 bits: unsupported\n"); + return B_UNSUPPORTED; + } + + uint64 valueBitSize = BVariant::SizeOfType(valueType) * 8; + if (!shortValueIsFine && totalBitSize < valueBitSize) { + TRACE_LOCALS(" -> too short for value type (%llu vs. %llu bits)\n", + totalBitSize, valueBitSize); + return B_BAD_VALUE; + } + + // Load the data. Since the BitBuffer class we're using only supports big + // endian bit semantics, we convert all data to big endian before pushing + // them to the buffer. For later conversion to BVariant we need to make sure + // the final buffer has the size of the value type, so we pad the most + // significant bits with zeros. + BitBuffer valueBuffer; + if (totalBitSize < valueBitSize) + valueBuffer.AddZeroBits(valueBitSize - totalBitSize); + + bool bigEndian = fArchitecture->IsBigEndian(); + const Register* registers = fArchitecture->Registers(); + for (int32 i = 0; i < count; i++) { + ValuePieceLocation piece = location->PieceAt( + bigEndian ? i : count - i - 1); + uint32 bytesToRead = piece.size; + uint32 bitSize = piece.bitSize; + uint8 bitOffset = piece.bitOffset; + + switch (piece.type) { + case VALUE_PIECE_LOCATION_INVALID: + case VALUE_PIECE_LOCATION_UNKNOWN: + return B_ENTRY_NOT_FOUND; + case VALUE_PIECE_LOCATION_MEMORY: + { + target_addr_t address = piece.address; + + TRACE_LOCALS(" piece %ld: memory address: %#llx, bits: %lu\n", + i, address, bitSize); + + uint8 pieceBuffer[kMaxPieceSize]; + ssize_t bytesRead = fTeamMemory->ReadMemory(address, + pieceBuffer, bytesToRead); + if (bytesRead < 0) + return bytesRead; + if ((uint32)bytesRead != bytesToRead) + return B_BAD_ADDRESS; + + TRACE_LOCALS_ONLY( + TRACE_LOCALS(" -> read: "); + for (ssize_t k = 0; k < bytesRead; k++) + TRACE_LOCALS("%02x", pieceBuffer[k]); + TRACE_LOCALS("\n"); + ) + + // convert to big endian + if (!bigEndian) { + for (int32 k = bytesRead / 2 - 1; k >= 0; k--) { + std::swap(pieceBuffer[k], + pieceBuffer[bytesRead - k - 1]); + } + } + + valueBuffer.AddBits(pieceBuffer, bitSize, bitOffset); + break; + } + case VALUE_PIECE_LOCATION_REGISTER: + { + TRACE_LOCALS(" piece %ld: register: %lu, bits: %lu\n", i, + piece.reg, bitSize); + + if (fCpuState == NULL) { + WARNING("ValueLoader::LoadValue(): register piece, but no " + "CpuState\n"); + return B_UNSUPPORTED; + } + + BVariant registerValue; + if (!fCpuState->GetRegisterValue(registers + piece.reg, + registerValue)) { + return B_ENTRY_NOT_FOUND; + } + if (registerValue.Size() < bytesToRead) + return B_ENTRY_NOT_FOUND; + + if (!bigEndian) + registerValue.SwapEndianess(); + valueBuffer.AddBits(registerValue.Bytes(), bitSize, bitOffset); + break; + } + } + } + + // If we don't have enough bits in the buffer apparently adding some failed. + if (valueBuffer.BitSize() < valueBitSize) + return B_NO_MEMORY; + + // convert the bits into something we can work with + BVariant value; + status_t error = value.SetToTypedData(valueBuffer.Bytes(), valueType); + if (error != B_OK) { + TRACE_LOCALS(" -> failed to set typed data: %s\n", strerror(error)); + return error; + } + + // convert to host endianess + #if B_HOST_IS_LENDIAN + value.SwapEndianess(); + #endif + + _value = value; + return B_OK; +} diff --git a/src/apps/debugger/value/ValueLoader.h b/src/apps/debugger/value/ValueLoader.h new file mode 100644 index 0000000000..b69f89f9b2 --- /dev/null +++ b/src/apps/debugger/value/ValueLoader.h @@ -0,0 +1,41 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef VALUE_LOADER_H +#define VALUE_LOADER_H + + +#include + +#include + + +class Architecture; +class CpuState; +class TeamMemory; +class ValueLocation; + + +class ValueLoader { +public: + ValueLoader(Architecture* architecture, + TeamMemory* teamMemory, CpuState* cpuState); + // cpuState can be NULL + ~ValueLoader(); + + Architecture* GetArchitecture() const + { return fArchitecture; } + + status_t LoadValue(ValueLocation* location, + type_code valueType, bool shortValueIsFine, + BVariant& _value); + +private: + Architecture* fArchitecture; + TeamMemory* fTeamMemory; + CpuState* fCpuState; +}; + + +#endif // VALUE_LOADER_H diff --git a/src/apps/debugger/value/ValueNode.cpp b/src/apps/debugger/value/ValueNode.cpp new file mode 100644 index 0000000000..233dbe2a7a --- /dev/null +++ b/src/apps/debugger/value/ValueNode.cpp @@ -0,0 +1,229 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + + +#include "ValueNode.h" + +#include "Value.h" +#include "ValueLocation.h" +#include "ValueNodeContainer.h" + + +// #pragma mark - ValueNode + + +ValueNode::ValueNode(ValueNodeChild* nodeChild) + : + fContainer(NULL), + fNodeChild(nodeChild), + fLocation(NULL), + fValue(NULL), + fLocationResolutionState(VALUE_NODE_UNRESOLVED), + fChildrenCreated(false) +{ + fNodeChild->AcquireReference(); +} + + +ValueNode::~ValueNode() +{ + SetLocationAndValue(NULL, NULL, VALUE_NODE_UNRESOLVED); + SetContainer(NULL); + fNodeChild->ReleaseReference(); +} + + +const BString& +ValueNode::Name() const +{ + return fNodeChild->Name(); +} + + +void +ValueNode::SetContainer(ValueNodeContainer* container) +{ + if (container == fContainer) + return; + + if (fContainer != NULL) + fContainer->ReleaseReference(); + + fContainer = container; + + if (fContainer != NULL) + fContainer->AcquireReference(); + + // propagate to children + int32 childCount = CountChildren(); + for (int32 i = 0; i < childCount; i++) + ChildAt(i)->SetContainer(fContainer); +} + + +void +ValueNode::SetLocationAndValue(ValueLocation* location, Value* value, + status_t resolutionState) +{ + if (fLocation != location) { + if (fLocation != NULL) + fLocation->ReleaseReference(); + + fLocation = location; + + if (fLocation != NULL) + fLocation->AcquireReference(); + } + + if (fValue != value) { + if (fValue != NULL) + fValue->ReleaseReference(); + + fValue = value; + + if (fValue != NULL) + fValue->AcquireReference(); + } + + fLocationResolutionState = resolutionState; + + // notify listeners + if (fContainer != NULL) + fContainer->NotifyValueNodeValueChanged(this); +} + + +// #pragma mark - ValueNodeChild + + +ValueNodeChild::ValueNodeChild() + : + fContainer(NULL), + fNode(NULL), + fLocation(NULL), + fLocationResolutionState(VALUE_NODE_UNRESOLVED) +{ +} + + +ValueNodeChild::~ValueNodeChild() +{ + SetLocation(NULL, VALUE_NODE_UNRESOLVED); + SetNode(NULL); + SetContainer(NULL); +} + + +bool +ValueNodeChild::IsInternal() const +{ + return false; +} + + +status_t +ValueNodeChild::CreateInternalNode(ValueNode*& _node) +{ + return B_BAD_VALUE; +} + + +void +ValueNodeChild::SetContainer(ValueNodeContainer* container) +{ + if (container == fContainer) + return; + + if (fContainer != NULL) + fContainer->ReleaseReference(); + + fContainer = container; + + if (fContainer != NULL) + fContainer->AcquireReference(); + + // propagate to node + if (fNode != NULL) + fNode->SetContainer(fContainer); +} + + +void +ValueNodeChild::SetNode(ValueNode* node) +{ + if (node == fNode) + return; + + ValueNode* oldNode = fNode; + Reference oldNodeReference(oldNode, true); + + if (fNode != NULL) + fNode->SetContainer(NULL); + + fNode = node; + + if (fNode != NULL) { + fNode->AcquireReference(); + fNode->SetContainer(fContainer); + } + + if (fContainer != NULL) + fContainer->NotifyValueNodeChanged(this, oldNode, fNode); +} + + +ValueLocation* +ValueNodeChild::Location() const +{ + return fLocation; +} + + +void +ValueNodeChild::SetLocation(ValueLocation* location, status_t resolutionState) +{ + if (fLocation != location) { + if (fLocation != NULL) + fLocation->ReleaseReference(); + + fLocation = location; + + if (fLocation != NULL) + fLocation->AcquireReference(); + } + + fLocationResolutionState = resolutionState; +} + + +// #pragma mark - ChildlessValueNode + + +ChildlessValueNode::ChildlessValueNode(ValueNodeChild* nodeChild) + : + ValueNode(nodeChild) +{ + fChildrenCreated = true; +} + + +status_t +ChildlessValueNode::CreateChildren() +{ + return B_OK; +} + +int32 +ChildlessValueNode::CountChildren() const +{ + return 0; +} + + +ValueNodeChild* +ChildlessValueNode::ChildAt(int32 index) const +{ + return NULL; +} diff --git a/src/apps/debugger/value/ValueNode.h b/src/apps/debugger/value/ValueNode.h new file mode 100644 index 0000000000..13c78872f4 --- /dev/null +++ b/src/apps/debugger/value/ValueNode.h @@ -0,0 +1,124 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef VALUE_NODE_H +#define VALUE_NODE_H + + +#include + +#include + + +class Type; +class Value; +class ValueLoader; +class ValueLocation; +class ValueNodeChild; +class ValueNodeContainer; + + +enum { + VALUE_NODE_UNRESOLVED = 1 +}; + + +class ValueNode : public BReferenceable { +public: + ValueNode(ValueNodeChild* nodeChild); + virtual ~ValueNode(); + + ValueNodeChild* NodeChild() const { return fNodeChild; } + + virtual const BString& Name() const; + virtual Type* GetType() const = 0; + + virtual status_t ResolvedLocationAndValue( + ValueLoader* valueLoader, + ValueLocation*& _location, + Value*& _value) = 0; + // returns references, a NULL value can be + // returned + + // locking required + + ValueNodeContainer* Container() const + { return fContainer; } + void SetContainer(ValueNodeContainer* container); + + bool ChildrenCreated() const + { return fChildrenCreated; } + virtual status_t CreateChildren() = 0; + virtual int32 CountChildren() const = 0; + virtual ValueNodeChild* ChildAt(int32 index) const = 0; + + status_t LocationAndValueResolutionState() const + { return fLocationResolutionState; } + void SetLocationAndValue(ValueLocation* location, + Value* value, status_t resolutionState); + ValueLocation* Location() const { return fLocation; } + Value* GetValue() const { return fValue; } + // immutable after SetLocationAndValue() + +protected: + ValueNodeContainer* fContainer; + ValueNodeChild* fNodeChild; + ValueLocation* fLocation; + Value* fValue; + status_t fLocationResolutionState; + bool fChildrenCreated; +}; + + +class ValueNodeChild : public BReferenceable { +public: + ValueNodeChild(); + virtual ~ValueNodeChild(); + + virtual const BString& Name() const = 0; + virtual Type* GetType() const = 0; + virtual ValueNode* Parent() const = 0; + + virtual bool IsInternal() const; + virtual status_t CreateInternalNode(ValueNode*& _node); + + virtual status_t ResolveLocation(ValueLoader* valueLoader, + ValueLocation*& _location) = 0; + // returns a reference + + // locking required + + ValueNodeContainer* Container() const + { return fContainer; } + void SetContainer(ValueNodeContainer* container); + + ValueNode* Node() const { return fNode; } + void SetNode(ValueNode* node); + + status_t LocationResolutionState() const + { return fLocationResolutionState; } + ValueLocation* Location() const; + // immutable after SetLocation() + void SetLocation(ValueLocation* location, + status_t resolutionState); + +protected: + ValueNodeContainer* fContainer; + ValueNode* fNode; + ValueLocation* fLocation; + status_t fLocationResolutionState; +}; + + +class ChildlessValueNode : public ValueNode { +public: + ChildlessValueNode(ValueNodeChild* nodeChild); + + virtual status_t CreateChildren(); + virtual int32 CountChildren() const; + virtual ValueNodeChild* ChildAt(int32 index) const; +}; + + +#endif // VALUE_NODE_H diff --git a/src/apps/debugger/value/ValueNodeContainer.cpp b/src/apps/debugger/value/ValueNodeContainer.cpp new file mode 100644 index 0000000000..a31d4c0d0e --- /dev/null +++ b/src/apps/debugger/value/ValueNodeContainer.cpp @@ -0,0 +1,166 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + + +#include "ValueNodeContainer.h" + +#include + +#include "ValueNode.h" + + +// #pragma mark - ValueNodeContainer + + +ValueNodeContainer::ValueNodeContainer() + : + fLock("value node container") +{ +} + + +ValueNodeContainer::~ValueNodeContainer() +{ + RemoveAllChildren(); +} + + +status_t +ValueNodeContainer::Init() +{ + return fLock.InitCheck(); +} + + +int32 +ValueNodeContainer::CountChildren() const +{ + return fChildren.CountItems(); +} + + +ValueNodeChild* +ValueNodeContainer::ChildAt(int32 index) const +{ + return fChildren.ItemAt(index); +} + + +bool +ValueNodeContainer::AddChild(ValueNodeChild* child) +{ + AutoLocker locker(this); + + if (!fChildren.AddItem(child)) + return false; + + child->AcquireReference(); + child->SetContainer(this); + + return true; +} + + +void +ValueNodeContainer::RemoveChild(ValueNodeChild* child) +{ + if (child->Container() != this || !fChildren.RemoveItem(child)) + return; + + child->SetContainer(NULL); + child->RemoveReference(); +} + + +void +ValueNodeContainer::RemoveAllChildren() +{ + for (int32 i = 0; ValueNodeChild* child = ChildAt(i); i++) { + child->SetContainer(NULL); + child->RemoveReference(); + } + + fChildren.MakeEmpty(); +} + + +bool +ValueNodeContainer::AddListener(Listener* listener) +{ + return fListeners.AddItem(listener); +} + + +void +ValueNodeContainer::RemoveListener(Listener* listener) +{ + fListeners.RemoveItem(listener); +} + + +void +ValueNodeContainer::NotifyValueNodeChanged(ValueNodeChild* nodeChild, + ValueNode* oldNode, ValueNode* newNode) +{ + for (int32 i = fListeners.CountItems() - 1; i >= 0; i--) + fListeners.ItemAt(i)->ValueNodeChanged(nodeChild, oldNode, newNode); +} + + +void +ValueNodeContainer::NotifyValueNodeChildrenCreated(ValueNode* node) +{ + for (int32 i = fListeners.CountItems() - 1; i >= 0; i--) + fListeners.ItemAt(i)->ValueNodeChildrenCreated(node); +} + + +void +ValueNodeContainer::NotifyValueNodeChildrenDeleted(ValueNode* node) +{ + for (int32 i = fListeners.CountItems() - 1; i >= 0; i--) + fListeners.ItemAt(i)->ValueNodeChildrenDeleted(node); +} + + +void +ValueNodeContainer::NotifyValueNodeValueChanged(ValueNode* node) +{ + for (int32 i = fListeners.CountItems() - 1; i >= 0; i--) + fListeners.ItemAt(i)->ValueNodeValueChanged(node); +} + + +// #pragma mark - ValueNodeContainer + + +ValueNodeContainer::Listener::~Listener() +{ +} + + +void +ValueNodeContainer::Listener::ValueNodeChanged(ValueNodeChild* nodeChild, + ValueNode* oldNode, ValueNode* newNode) +{ +} + + +void +ValueNodeContainer::Listener::ValueNodeChildrenCreated(ValueNode* node) +{ +} + + +void +ValueNodeContainer::Listener::ValueNodeChildrenDeleted(ValueNode* node) +{ +} + + +void +ValueNodeContainer::Listener::ValueNodeValueChanged(ValueNode* node) +{ +} diff --git a/src/apps/debugger/value/ValueNodeContainer.h b/src/apps/debugger/value/ValueNodeContainer.h new file mode 100644 index 0000000000..3f10c5b360 --- /dev/null +++ b/src/apps/debugger/value/ValueNodeContainer.h @@ -0,0 +1,75 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef VALUE_NODE_CONTAINER_H +#define VALUE_NODE_CONTAINER_H + + +#include + +#include +#include + + +class ValueNode; +class ValueNodeChild; + + +class ValueNodeContainer : public BReferenceable { +public: + class Listener; + +public: + ValueNodeContainer(); + virtual ~ValueNodeContainer(); + + status_t Init(); + + inline bool Lock() { return fLock.Lock(); } + inline void Unlock() { fLock.Unlock(); } + + int32 CountChildren() const; + ValueNodeChild* ChildAt(int32 index) const; + bool AddChild(ValueNodeChild* child); + void RemoveChild(ValueNodeChild* child); + void RemoveAllChildren(); + + bool AddListener(Listener* listener); + void RemoveListener(Listener* listener); + + // container must be locked + + void NotifyValueNodeChanged( + ValueNodeChild* nodeChild, + ValueNode* oldNode, ValueNode* newNode); + void NotifyValueNodeChildrenCreated(ValueNode* node); + void NotifyValueNodeChildrenDeleted(ValueNode* node); + void NotifyValueNodeValueChanged(ValueNode* node); + +private: + typedef BObjectList NodeChildList; + typedef BObjectList ListenerList; + +private: + BLocker fLock; + NodeChildList fChildren; + ListenerList fListeners; +}; + + +class ValueNodeContainer::Listener { +public: + virtual ~Listener(); + + // container is locked + + virtual void ValueNodeChanged(ValueNodeChild* nodeChild, + ValueNode* oldNode, ValueNode* newNode); + virtual void ValueNodeChildrenCreated(ValueNode* node); + virtual void ValueNodeChildrenDeleted(ValueNode* node); + virtual void ValueNodeValueChanged(ValueNode* node); +}; + + +#endif // VALUE_NODE_CONTAINER_H diff --git a/src/apps/debugger/value/value_handlers/AddressValueHandler.cpp b/src/apps/debugger/value/value_handlers/AddressValueHandler.cpp new file mode 100644 index 0000000000..1aa6179e89 --- /dev/null +++ b/src/apps/debugger/value/value_handlers/AddressValueHandler.cpp @@ -0,0 +1,23 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + + +#include "AddressValueHandler.h" + +#include "AddressValue.h" + + +float +AddressValueHandler::SupportsValue(Value* value) +{ + return dynamic_cast(value) ? 0.8f : 0; +} + + +integer_format +AddressValueHandler::DefaultIntegerFormat(IntegerValue* value) +{ + return INTEGER_FORMAT_HEX_DEFAULT; +} diff --git a/src/apps/debugger/value/value_handlers/AddressValueHandler.h b/src/apps/debugger/value/value_handlers/AddressValueHandler.h new file mode 100644 index 0000000000..09762b6cc3 --- /dev/null +++ b/src/apps/debugger/value/value_handlers/AddressValueHandler.h @@ -0,0 +1,21 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef ADDRESS_VALUE_HANDLER_H +#define ADDRESS_VALUE_HANDLER_H + + +#include "IntegerValueHandler.h" + + +class AddressValueHandler : public IntegerValueHandler { +public: + virtual float SupportsValue(Value* value); + +protected: + virtual integer_format DefaultIntegerFormat(IntegerValue* value); +}; + + +#endif // ADDRESS_VALUE_HANDLER_H diff --git a/src/apps/debugger/value/value_handlers/BoolValueHandler.cpp b/src/apps/debugger/value/value_handlers/BoolValueHandler.cpp new file mode 100644 index 0000000000..a8ddcf33eb --- /dev/null +++ b/src/apps/debugger/value/value_handlers/BoolValueHandler.cpp @@ -0,0 +1,62 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + + +#include "BoolValueHandler.h" + +#include + +#include "BoolValue.h" +#include "TableCellBoolRenderer.h" + + +BoolValueHandler::BoolValueHandler() +{ +} + + +BoolValueHandler::~BoolValueHandler() +{ +} + + +status_t +BoolValueHandler::Init() +{ + return B_OK; +} + + +float +BoolValueHandler::SupportsValue(Value* value) +{ + return dynamic_cast(value) != NULL ? 0.5f : 0; +} + + +status_t +BoolValueHandler::GetValueFormatter(Value* value, + ValueFormatter*& _formatter) +{ + // TODO:... + return B_UNSUPPORTED; +} + + +status_t +BoolValueHandler::GetTableCellValueRenderer(Value* value, + TableCellValueRenderer*& _renderer) +{ + if (dynamic_cast(value) == NULL) + return B_BAD_VALUE; + + // create the renderer + TableCellValueRenderer* renderer = new(std::nothrow) TableCellBoolRenderer; + if (renderer == NULL) + return B_NO_MEMORY; + + _renderer = renderer; + return B_OK; +} diff --git a/src/apps/debugger/value/value_handlers/BoolValueHandler.h b/src/apps/debugger/value/value_handlers/BoolValueHandler.h new file mode 100644 index 0000000000..15acb89db7 --- /dev/null +++ b/src/apps/debugger/value/value_handlers/BoolValueHandler.h @@ -0,0 +1,27 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef BOOL_VALUE_HANDLER_H +#define BOOL_VALUE_HANDLER_H + + +#include "ValueHandler.h" + + +class BoolValueHandler : public ValueHandler { +public: + BoolValueHandler(); + ~BoolValueHandler(); + + status_t Init(); + + virtual float SupportsValue(Value* value); + virtual status_t GetValueFormatter(Value* value, + ValueFormatter*& _formatter); + virtual status_t GetTableCellValueRenderer(Value* value, + TableCellValueRenderer*& _renderer); +}; + + +#endif // BOOL_VALUE_HANDLER_H diff --git a/src/apps/debugger/value/value_handlers/EnumerationValueHandler.cpp b/src/apps/debugger/value/value_handlers/EnumerationValueHandler.cpp new file mode 100644 index 0000000000..79149c7510 --- /dev/null +++ b/src/apps/debugger/value/value_handlers/EnumerationValueHandler.cpp @@ -0,0 +1,88 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + + +#include "EnumerationValueHandler.h" + +#include + +#include "EnumerationValue.h" +#include "TableCellEnumerationRenderer.h" +#include "Type.h" + + +EnumerationValueHandler::EnumerationValueHandler() +{ +} + + +EnumerationValueHandler::~EnumerationValueHandler() +{ +} + + +status_t +EnumerationValueHandler::Init() +{ + return B_OK; +} + + +float +EnumerationValueHandler::SupportsValue(Value* value) +{ + return dynamic_cast(value) != NULL ? 0.7f : 0; +} + + + +integer_format +EnumerationValueHandler::DefaultIntegerFormat(IntegerValue* _value) +{ + EnumerationValue* value = dynamic_cast(_value); + if (value != NULL && value->GetType()->ValueFor(value->GetValue()) != NULL) + return INTEGER_FORMAT_DEFAULT; + + return IntegerValueHandler::DefaultIntegerFormat(_value); +} + + +status_t +EnumerationValueHandler::AddIntegerFormatSettingOptions(IntegerValue* _value, + OptionsSettingImpl* setting) +{ + EnumerationValue* value = dynamic_cast(_value); + if (value != NULL + && value->GetType()->ValueFor(value->GetValue()) != NULL) { + status_t error = AddIntegerFormatOption(setting, "name", "Enum Name", + INTEGER_FORMAT_DEFAULT); + if (error != B_OK) + return error; + } + + return IntegerValueHandler::AddIntegerFormatSettingOptions(_value, setting); +} + + +status_t +EnumerationValueHandler::CreateTableCellValueRenderer(IntegerValue* _value, + TableCellIntegerRenderer::Config* config, + TableCellValueRenderer*& _renderer) +{ + EnumerationValue* value = dynamic_cast(_value); + if (value != NULL + && value->GetType()->ValueFor(value->GetValue()) != NULL) { + TableCellValueRenderer* renderer + = new(std::nothrow) TableCellEnumerationRenderer(config); + if (renderer == NULL) + return B_NO_MEMORY; + + _renderer = renderer; + return B_OK; + } + + return IntegerValueHandler::CreateTableCellValueRenderer(_value, config, + _renderer); +} diff --git a/src/apps/debugger/value/value_handlers/EnumerationValueHandler.h b/src/apps/debugger/value/value_handlers/EnumerationValueHandler.h new file mode 100644 index 0000000000..5914621e73 --- /dev/null +++ b/src/apps/debugger/value/value_handlers/EnumerationValueHandler.h @@ -0,0 +1,33 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef ENUMERATION_VALUE_HANDLER_H +#define ENUMERATION_VALUE_HANDLER_H + + +#include "IntegerValueHandler.h" + + +class EnumerationValueHandler : public IntegerValueHandler { +public: + EnumerationValueHandler(); + ~EnumerationValueHandler(); + + status_t Init(); + + virtual float SupportsValue(Value* value); + +protected: + virtual integer_format DefaultIntegerFormat(IntegerValue* value); + virtual status_t AddIntegerFormatSettingOptions( + IntegerValue* value, + OptionsSettingImpl* setting); + virtual status_t CreateTableCellValueRenderer( + IntegerValue* value, + TableCellIntegerRenderer::Config* config, + TableCellValueRenderer*& _renderer); +}; + + +#endif // ENUMERATION_VALUE_HANDLER_H diff --git a/src/apps/debugger/value/value_handlers/FloatValueHandler.cpp b/src/apps/debugger/value/value_handlers/FloatValueHandler.cpp new file mode 100644 index 0000000000..372ba55274 --- /dev/null +++ b/src/apps/debugger/value/value_handlers/FloatValueHandler.cpp @@ -0,0 +1,62 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + + +#include "FloatValueHandler.h" + +#include + +#include "FloatValue.h" +#include "TableCellFloatRenderer.h" + + +FloatValueHandler::FloatValueHandler() +{ +} + + +FloatValueHandler::~FloatValueHandler() +{ +} + + +status_t +FloatValueHandler::Init() +{ + return B_OK; +} + + +float +FloatValueHandler::SupportsValue(Value* value) +{ + return dynamic_cast(value) != NULL ? 0.5f : 0; +} + + +status_t +FloatValueHandler::GetValueFormatter(Value* value, + ValueFormatter*& _formatter) +{ + // TODO:... + return B_UNSUPPORTED; +} + + +status_t +FloatValueHandler::GetTableCellValueRenderer(Value* value, + TableCellValueRenderer*& _renderer) +{ + if (dynamic_cast(value) == NULL) + return B_BAD_VALUE; + + // create the renderer + TableCellValueRenderer* renderer = new(std::nothrow) TableCellFloatRenderer; + if (renderer == NULL) + return B_NO_MEMORY; + + _renderer = renderer; + return B_OK; +} diff --git a/src/apps/debugger/value/value_handlers/FloatValueHandler.h b/src/apps/debugger/value/value_handlers/FloatValueHandler.h new file mode 100644 index 0000000000..153bce78c6 --- /dev/null +++ b/src/apps/debugger/value/value_handlers/FloatValueHandler.h @@ -0,0 +1,27 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef FLOAT_VALUE_HANDLER_H +#define FLOAT_VALUE_HANDLER_H + + +#include "ValueHandler.h" + + +class FloatValueHandler : public ValueHandler { +public: + FloatValueHandler(); + ~FloatValueHandler(); + + status_t Init(); + + virtual float SupportsValue(Value* value); + virtual status_t GetValueFormatter(Value* value, + ValueFormatter*& _formatter); + virtual status_t GetTableCellValueRenderer(Value* value, + TableCellValueRenderer*& _renderer); +}; + + +#endif // FLOAT_VALUE_HANDLER_H diff --git a/src/apps/debugger/value/value_handlers/IntegerValueHandler.cpp b/src/apps/debugger/value/value_handlers/IntegerValueHandler.cpp new file mode 100644 index 0000000000..505396819a --- /dev/null +++ b/src/apps/debugger/value/value_handlers/IntegerValueHandler.cpp @@ -0,0 +1,306 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + + +#include "IntegerValueHandler.h" + +#include + +#include + +#include "IntegerValue.h" +#include "Setting.h" +#include "Settings.h" +#include "SettingsDescription.h" +#include "SettingsMenu.h" +#include "TableCellIntegerRenderer.h" + + +static const char* const kFormatSettingID = "format"; + + +// #pragma mark - FormatOption + + +class IntegerValueHandler::FormatOption : public SettingsOption { +public: + FormatOption(const char* id, const char* name, integer_format format) + : + fID(id), + fName(name), + fFormat(format) + { + } + + virtual const char* ID() const + { + return fID; + } + + virtual const char* Name() const + { + return fName; + } + + integer_format Format() const + { + return fFormat; + } + +private: + const char* fID; + const char* fName; + integer_format fFormat; +}; + + +// #pragma mark - TableCellRendererConfig + + +class IntegerValueHandler::TableCellRendererConfig + : public TableCellIntegerRenderer::Config { +public: + TableCellRendererConfig() + : + fSettings(NULL), + fFormatSetting(NULL) + { + } + + ~TableCellRendererConfig() + { + if (fSettings != NULL) + fSettings->ReleaseReference(); + } + + status_t Init(SettingsDescription* settingsDescription) + { + fSettings = new(std::nothrow) Settings(settingsDescription); + if (fSettings == NULL) + return B_NO_MEMORY; + + status_t error = fSettings->Init(); + if (error != B_OK) + return error; + + fFormatSetting = dynamic_cast( + settingsDescription->SettingByID(kFormatSettingID)); + if (fFormatSetting == NULL) + return B_BAD_VALUE; + + return B_OK; + } + + virtual Settings* GetSettings() const + { + return fSettings; + } + + virtual integer_format IntegerFormat() const + { + FormatOption* option = dynamic_cast( + fSettings->OptionValue(fFormatSetting)); + return option != NULL ? option->Format() : INTEGER_FORMAT_DEFAULT; + } + +private: + Settings* fSettings; + OptionsSetting* fFormatSetting; +}; + + +// #pragma mark - IntegerValueHandler + + +IntegerValueHandler::IntegerValueHandler() +{ +} + + +IntegerValueHandler::~IntegerValueHandler() +{ +} + + +status_t +IntegerValueHandler::Init() +{ + return B_OK; +} + + +float +IntegerValueHandler::SupportsValue(Value* value) +{ + return dynamic_cast(value) != NULL ? 0.5f : 0; +} + + +status_t +IntegerValueHandler::GetValueFormatter(Value* value, + ValueFormatter*& _formatter) +{ + // TODO:... + return B_UNSUPPORTED; +} + + +status_t +IntegerValueHandler::GetTableCellValueRenderer(Value* _value, + TableCellValueRenderer*& _renderer) +{ + IntegerValue* value = dynamic_cast(_value); + if (value == NULL) + return B_BAD_VALUE; + + // create a settings description + SettingsDescription* settingsDescription + = _CreateTableCellSettingsDescription(value); + if (settingsDescription == NULL) + return B_NO_MEMORY; + Reference settingsDescriptionReference( + settingsDescription, true); + + // create config + TableCellRendererConfig* config = new(std::nothrow) TableCellRendererConfig; + if (config == NULL) + return B_NO_MEMORY; + Reference configReference(config, true); + + status_t error = config->Init(settingsDescription); + if (error != B_OK) + return error; + + // create the renderer + return CreateTableCellValueRenderer(value, config, _renderer); +} + + +status_t +IntegerValueHandler::CreateTableCellValueSettingsMenu(Value* value, + Settings* settings, SettingsMenu*& _menu) +{ + // get the format option + OptionsSetting* formatSetting = dynamic_cast( + settings->Description()->SettingByID(kFormatSettingID)); + if (formatSetting == NULL) + return B_BAD_VALUE; + + // create the settings menu + SettingsMenuImpl* menu = new(std::nothrow) SettingsMenuImpl(settings); + if (menu == NULL) + return B_NO_MEMORY; + ObjectDeleter menuDeleter(menu); + + // add the format option menu item + if (!menu->AddOptionsItem(formatSetting)) + return B_NO_MEMORY; + + _menu = menuDeleter.Detach(); + return B_OK; +} + + +integer_format +IntegerValueHandler::DefaultIntegerFormat(IntegerValue* value) +{ + return value->IsSigned() ? INTEGER_FORMAT_SIGNED : INTEGER_FORMAT_UNSIGNED; +} + + +status_t +IntegerValueHandler::AddIntegerFormatSettingOptions(IntegerValue* value, + OptionsSettingImpl* setting) +{ + status_t error = AddIntegerFormatOption(setting, "signed", "Signed", + INTEGER_FORMAT_SIGNED); + if (error != B_OK) + return error; + + error = AddIntegerFormatOption(setting, "unsigned", "Unsigned", + INTEGER_FORMAT_UNSIGNED); + if (error != B_OK) + return error; + + error = AddIntegerFormatOption(setting, "hex", "Hexadecimal", + INTEGER_FORMAT_HEX_DEFAULT); + if (error != B_OK) + return error; + + return B_OK; +} + + +status_t +IntegerValueHandler::CreateTableCellValueRenderer(IntegerValue* value, + TableCellIntegerRenderer::Config* config, + TableCellValueRenderer*& _renderer) +{ + TableCellValueRenderer* renderer + = new(std::nothrow) TableCellIntegerRenderer(config); + if (renderer == NULL) + return B_NO_MEMORY; + + _renderer = renderer; + return B_OK; +} + + +status_t +IntegerValueHandler::AddIntegerFormatOption(OptionsSettingImpl* setting, + const char* id, const char* name, integer_format format) +{ + FormatOption* option = new(std::nothrow) FormatOption(id, name, format); + if (option == NULL || !setting->AddOption(option)) { + delete option; + return B_NO_MEMORY; + } + + return B_OK; +} + + +SettingsDescription* +IntegerValueHandler::_CreateTableCellSettingsDescription( + IntegerValue* value) +{ + // create description object + SettingsDescription* description = new(std::nothrow) SettingsDescription; + if (description == NULL) + return NULL; + Reference descriptionReference(description, true); + + // integer format setting + OptionsSettingImpl* setting = new(std::nothrow) OptionsSettingImpl( + kFormatSettingID, "Format"); + if (setting == NULL) + return NULL; + Reference settingReference(setting, true); + + // add options + if (AddIntegerFormatSettingOptions(value, setting) != B_OK) + return NULL; + + // set default + integer_format defaultFormat = DefaultIntegerFormat(value); + SettingsOption* defaultOption = setting->OptionAt(0); + for (int32 i = 0; + FormatOption* option + = dynamic_cast(setting->OptionAt(i)); + i++) { + if (option->Format() == defaultFormat) { + defaultOption = option; + break; + } + } + + setting->SetDefaultOption(defaultOption); + + // add setting + if (!description->AddSetting(setting)) + return NULL; + + return descriptionReference.Detach(); +} diff --git a/src/apps/debugger/value/value_handlers/IntegerValueHandler.h b/src/apps/debugger/value/value_handlers/IntegerValueHandler.h new file mode 100644 index 0000000000..e98a47ac7e --- /dev/null +++ b/src/apps/debugger/value/value_handlers/IntegerValueHandler.h @@ -0,0 +1,58 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef INTEGER_VALUE_HANDLER_H +#define INTEGER_VALUE_HANDLER_H + + +#include "IntegerFormatter.h" +#include "TableCellIntegerRenderer.h" +#include "ValueHandler.h" + + +class IntegerValue; +class OptionsSettingImpl; +class SettingsDescription; + + +class IntegerValueHandler : public ValueHandler { +public: + IntegerValueHandler(); + ~IntegerValueHandler(); + + status_t Init(); + + virtual float SupportsValue(Value* value); + virtual status_t GetValueFormatter(Value* value, + ValueFormatter*& _formatter); + virtual status_t GetTableCellValueRenderer(Value* value, + TableCellValueRenderer*& _renderer); + virtual status_t CreateTableCellValueSettingsMenu(Value* value, + Settings* settings, SettingsMenu*& _menu); + +protected: + virtual integer_format DefaultIntegerFormat(IntegerValue* value); + virtual status_t AddIntegerFormatSettingOptions( + IntegerValue* value, + OptionsSettingImpl* setting); + virtual status_t CreateTableCellValueRenderer( + IntegerValue* value, + TableCellIntegerRenderer::Config* config, + TableCellValueRenderer*& _renderer); + + status_t AddIntegerFormatOption( + OptionsSettingImpl* setting, const char* id, + const char* name, integer_format format); + +private: + class FormatOption; + class TableCellRendererConfig; + +private: + SettingsDescription* _CreateTableCellSettingsDescription( + IntegerValue* value); +}; + + +#endif // INTEGER_VALUE_HANDLER_H diff --git a/src/apps/debugger/value/value_nodes/AddressValueNode.cpp b/src/apps/debugger/value/value_nodes/AddressValueNode.cpp new file mode 100644 index 0000000000..37e80a3b63 --- /dev/null +++ b/src/apps/debugger/value/value_nodes/AddressValueNode.cpp @@ -0,0 +1,191 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + + +#include "AddressValueNode.h" + +#include + +#include "AddressValue.h" +#include "Architecture.h" +#include "Tracing.h" +#include "Type.h" +#include "ValueLoader.h" +#include "ValueLocation.h" +#include "ValueNodeContainer.h" + + +// #pragma mark - AddressValueNode + + +AddressValueNode::AddressValueNode(ValueNodeChild* nodeChild, + AddressType* type) + : + ValueNode(nodeChild), + fType(type), + fChild(NULL) +{ + fType->AcquireReference(); +} + + +AddressValueNode::~AddressValueNode() +{ + if (fChild != NULL) + fChild->ReleaseReference(); + fType->ReleaseReference(); +} + + +Type* +AddressValueNode::GetType() const +{ + return fType; +} + + +status_t +AddressValueNode::ResolvedLocationAndValue(ValueLoader* valueLoader, + ValueLocation*& _location, Value*& _value) +{ + // get the location + ValueLocation* location = NodeChild()->Location(); + if (location == NULL) + return B_BAD_VALUE; + + TRACE_LOCALS(" TYPE_ADDRESS\n"); + + // get the value type + type_code valueType; + if (valueLoader->GetArchitecture()->AddressSize() == 4) { + valueType = B_UINT32_TYPE; + TRACE_LOCALS(" -> 32 bit\n"); + } else { + valueType = B_UINT64_TYPE; + TRACE_LOCALS(" -> 64 bit\n"); + } + + // load the value data + BVariant valueData; + status_t error = valueLoader->LoadValue(location, valueType, false, + valueData); + if (error != B_OK) + return error; + + // create the type object + Value* value = new(std::nothrow) AddressValue(valueData); + if (value == NULL) + return B_NO_MEMORY; + + location->AcquireReference(); + _location = location; + _value = value; + return B_OK; +} + + +status_t +AddressValueNode::CreateChildren() +{ + if (fChild != NULL) + return B_OK; + + // construct name + BString name = "*"; + name << Name(); + + // create the child + fChild = new(std::nothrow) AddressValueNodeChild(this, name, + fType->BaseType()); + if (fChild == NULL) + return B_NO_MEMORY; + + fChild->SetContainer(fContainer); + + if (fContainer != NULL) + fContainer->NotifyValueNodeChildrenCreated(this); + + return B_OK; +} + + +int32 +AddressValueNode::CountChildren() const +{ + return fChild != NULL ? 1 : 0; +} + + +ValueNodeChild* +AddressValueNode::ChildAt(int32 index) const +{ + return index == 0 ? fChild : NULL; +} + + +// #pragma mark - AddressValueNodeChild + + +AddressValueNodeChild::AddressValueNodeChild(AddressValueNode* parent, + const BString& name, Type* type) + : + fParent(parent), + fName(name), + fType(type) +{ + fType->AcquireReference(); +} + + +AddressValueNodeChild::~AddressValueNodeChild() +{ + fType->ReleaseReference(); +} + + +const BString& +AddressValueNodeChild::Name() const +{ + return fName; +} + + +Type* +AddressValueNodeChild::GetType() const +{ + return fType; +} + + +ValueNode* +AddressValueNodeChild::Parent() const +{ + return fParent; +} + + +status_t +AddressValueNodeChild::ResolveLocation(ValueLoader* valueLoader, + ValueLocation*& _location) +{ + // The parent's value is an address pointing to this component. + AddressValue* parentValue = dynamic_cast( + fParent->GetValue()); + if (parentValue == NULL) + return B_BAD_VALUE; + + // resolve the location + ValueLocation* location; + status_t error = fType->ResolveObjectDataLocation(parentValue->ToUInt64(), + location); + if (error != B_OK) { + TRACE_LOCALS("AddressValueNodeChild::ResolveLocation(): " + "ResolveObjectDataLocation() failed: %s\n", strerror(error)); + return error; + } + + _location = location; + return B_OK; +} diff --git a/src/apps/debugger/value/value_nodes/AddressValueNode.h b/src/apps/debugger/value/value_nodes/AddressValueNode.h new file mode 100644 index 0000000000..d1dc16e3a1 --- /dev/null +++ b/src/apps/debugger/value/value_nodes/AddressValueNode.h @@ -0,0 +1,61 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef ADDRESS_VALUE_NODE_H +#define ADDRESS_VALUE_NODE_H + + +#include "ValueNode.h" + + +class AddressValueNodeChild; +class AddressType; + + +class AddressValueNode : public ValueNode { +public: + AddressValueNode(ValueNodeChild* nodeChild, + AddressType* type); + virtual ~AddressValueNode(); + + virtual Type* GetType() const; + + virtual status_t ResolvedLocationAndValue( + ValueLoader* valueLoader, + ValueLocation*& _location, + Value*& _value); + + // locking required + + virtual status_t CreateChildren(); + virtual int32 CountChildren() const; + virtual ValueNodeChild* ChildAt(int32 index) const; + +private: + AddressType* fType; + AddressValueNodeChild* fChild; +}; + + +class AddressValueNodeChild : public ValueNodeChild { +public: + AddressValueNodeChild(AddressValueNode* parent, + const BString& name, Type* type); + virtual ~AddressValueNodeChild(); + + virtual const BString& Name() const; + virtual Type* GetType() const; + virtual ValueNode* Parent() const; + + virtual status_t ResolveLocation(ValueLoader* valueLoader, + ValueLocation*& _location); + +private: + AddressValueNode* fParent; + BString fName; + Type* fType; +}; + + +#endif // ADDRESS_VALUE_NODE_H diff --git a/src/apps/debugger/value/value_nodes/ArrayValueNode.cpp b/src/apps/debugger/value/value_nodes/ArrayValueNode.cpp new file mode 100644 index 0000000000..78a35d255d --- /dev/null +++ b/src/apps/debugger/value/value_nodes/ArrayValueNode.cpp @@ -0,0 +1,328 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + + +#include "ArrayValueNode.h" + +#include + +#include "Architecture.h" +#include "ArrayIndexPath.h" +#include "IntegerValue.h" +#include "Tracing.h" +#include "Type.h" +#include "ValueLoader.h" +#include "ValueLocation.h" +#include "ValueNodeContainer.h" + + +// maximum number of array elements to show by default +static const uint64 kMaxArrayElementCount = 10; + + +// #pragma mark - AbstractArrayValueNode + + +AbstractArrayValueNode::AbstractArrayValueNode(ValueNodeChild* nodeChild, + ArrayType* type, int32 dimension) + : + ValueNode(nodeChild), + fType(type), + fDimension(dimension) +{ + fType->AcquireReference(); +} + + +AbstractArrayValueNode::~AbstractArrayValueNode() +{ + fType->ReleaseReference(); + + for (int32 i = 0; AbstractArrayValueNodeChild* child = fChildren.ItemAt(i); + i++) { + child->RemoveReference(); + } +} + + +Type* +AbstractArrayValueNode::GetType() const +{ + return fType; +} + + +status_t +AbstractArrayValueNode::ResolvedLocationAndValue(ValueLoader* valueLoader, + ValueLocation*& _location, Value*& _value) +{ + // get the location + ValueLocation* location = NodeChild()->Location(); + if (location == NULL) + return B_BAD_VALUE; + + location->AcquireReference(); + _location = location; + _value = NULL; + return B_OK; +} + + +status_t +AbstractArrayValueNode::CreateChildren() +{ + if (!fChildren.IsEmpty()) + return B_OK; + + TRACE_LOCALS("TYPE_ARRAY\n"); + + int32 dimensionCount = fType->CountDimensions(); + bool isFinalDimension = fDimension + 1 == dimensionCount; + + ArrayDimension* dimension = fType->DimensionAt(fDimension); + uint64 elementCount = dimension->CountElements(); + if (elementCount == 0 || elementCount > kMaxArrayElementCount) + elementCount = kMaxArrayElementCount; + + // create children for the array elements + for (int32 i = 0; i < (int32)elementCount; i++) { + BString name(Name()); + name << '[' << i << ']'; + if (name.Length() <= Name().Length()) + return B_NO_MEMORY; + + AbstractArrayValueNodeChild* child; + if (isFinalDimension) { + child = new(std::nothrow) ArrayValueNodeChild(this, name, i, + fType->BaseType()); + } else { + child = new(std::nothrow) InternalArrayValueNodeChild(this, name, i, + fType); + } + + if (child == NULL || !fChildren.AddItem(child)) { + delete child; + return B_NO_MEMORY; + } + + child->SetContainer(fContainer); + } + + if (fContainer != NULL) + fContainer->NotifyValueNodeChildrenCreated(this); + + return B_OK; +} + + +int32 +AbstractArrayValueNode::CountChildren() const +{ + return fChildren.CountItems(); +} + + +ValueNodeChild* +AbstractArrayValueNode::ChildAt(int32 index) const +{ + return fChildren.ItemAt(index); +} + + +// #pragma mark - ArrayValueNode + + +ArrayValueNode::ArrayValueNode(ValueNodeChild* nodeChild, ArrayType* type) + : + AbstractArrayValueNode(nodeChild, type, 0) +{ +} + + +ArrayValueNode::~ArrayValueNode() +{ +} + + +// #pragma mark - InternalArrayValueNode + + +InternalArrayValueNode::InternalArrayValueNode(ValueNodeChild* nodeChild, + ArrayType* type, int32 dimension) + : + AbstractArrayValueNode(nodeChild, type, dimension) +{ +} + + +InternalArrayValueNode::~InternalArrayValueNode() +{ +} + + +// #pragma mark - AbstractArrayValueNodeChild + + +AbstractArrayValueNodeChild::AbstractArrayValueNodeChild( + AbstractArrayValueNode* parent, const BString& name, int64 elementIndex) + : + fParent(parent), + fName(name), + fElementIndex(elementIndex) +{ +} + + +AbstractArrayValueNodeChild::~AbstractArrayValueNodeChild() +{ +} + + +const BString& +AbstractArrayValueNodeChild::Name() const +{ + return fName; +} + + +ValueNode* +AbstractArrayValueNodeChild::Parent() const +{ + return fParent; +} + + +// #pragma mark - ArrayValueNodeChild + + +ArrayValueNodeChild::ArrayValueNodeChild(AbstractArrayValueNode* parent, + const BString& name, int64 elementIndex, Type* type) + : + AbstractArrayValueNodeChild(parent, name, elementIndex), + fType(type) +{ + fType->AcquireReference(); +} + + +ArrayValueNodeChild::~ArrayValueNodeChild() +{ + fType->ReleaseReference(); +} + + +Type* +ArrayValueNodeChild::GetType() const +{ + return fType; +} + + +status_t +ArrayValueNodeChild::ResolveLocation(ValueLoader* valueLoader, + ValueLocation*& _location) +{ + // get the parent (== array) location + ValueLocation* parentLocation = fParent->Location(); + if (parentLocation == NULL) + return B_BAD_VALUE; + + // create an array index path + ArrayType* arrayType = fParent->GetArrayType(); + int32 dimensionCount = arrayType->CountDimensions(); + + // add dummy indices first -- we'll replace them on our way back through + // our ancestors + ArrayIndexPath indexPath; + for (int32 i = 0; i < dimensionCount; i++) { + if (!indexPath.AddIndex(0)) + return B_NO_MEMORY; + } + + AbstractArrayValueNodeChild* child = this; + for (int32 i = dimensionCount - 1; i >= 0; i--) { + indexPath.SetIndexAt(i, child->ElementIndex()); + + child = dynamic_cast( + child->ArrayParent()->NodeChild()); + } + + // resolve the element location + ValueLocation* location; + status_t error = arrayType->ResolveElementLocation(indexPath, + *parentLocation, location); + if (error != B_OK) { + TRACE_LOCALS("ArrayValueNodeChild::ResolveLocation(): " + "ResolveElementLocation() failed: %s\n", strerror(error)); + return error; + } + + _location = location; + return B_OK; +} + + +// #pragma mark - InternalArrayValueNodeChild + + +InternalArrayValueNodeChild::InternalArrayValueNodeChild( + AbstractArrayValueNode* parent, const BString& name, int64 elementIndex, + ArrayType* type) + : + AbstractArrayValueNodeChild(parent, name, elementIndex), + fType(type) +{ + fType->AcquireReference(); +} + + +InternalArrayValueNodeChild::~InternalArrayValueNodeChild() +{ + fType->ReleaseReference(); +} + + +Type* +InternalArrayValueNodeChild::GetType() const +{ + return fType; +} + + +bool +InternalArrayValueNodeChild::IsInternal() const +{ + return true; +} + + +status_t +InternalArrayValueNodeChild::CreateInternalNode(ValueNode*& _node) +{ + ValueNode* node = new(std::nothrow) InternalArrayValueNode(this, fType, + fParent->Dimension() + 1); + if (node == NULL) + return B_NO_MEMORY; + + _node = node; + return B_OK; +} + + +status_t +InternalArrayValueNodeChild::ResolveLocation(ValueLoader* valueLoader, + ValueLocation*& _location) +{ + // This is an internal child node for a non-final dimension -- just clone + // the parent's location. + ValueLocation* parentLocation = fParent->Location(); + if (parentLocation == NULL) + return B_BAD_VALUE; + + parentLocation->AcquireReference(); + _location = parentLocation; + + return B_OK; +} diff --git a/src/apps/debugger/value/value_nodes/ArrayValueNode.h b/src/apps/debugger/value/value_nodes/ArrayValueNode.h new file mode 100644 index 0000000000..dcef1e95d0 --- /dev/null +++ b/src/apps/debugger/value/value_nodes/ArrayValueNode.h @@ -0,0 +1,131 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef ARRAY_VALUE_NODE_H +#define ARRAY_VALUE_NODE_H + + +#include + +#include "ValueNode.h" + + +class AbstractArrayValueNodeChild; +class ArrayType; + + +class AbstractArrayValueNode : public ValueNode { +public: + AbstractArrayValueNode( + ValueNodeChild* nodeChild, ArrayType* type, + int32 dimension); + virtual ~AbstractArrayValueNode(); + + ArrayType* GetArrayType() const + { return fType; } + int32 Dimension() const + { return fDimension; } + + virtual Type* GetType() const; + + virtual status_t ResolvedLocationAndValue( + ValueLoader* valueLoader, + ValueLocation*& _location, + Value*& _value); + + // locking required + + virtual status_t CreateChildren(); + virtual int32 CountChildren() const; + virtual ValueNodeChild* ChildAt(int32 index) const; + +protected: + typedef BObjectList ChildList; + +protected: + ArrayType* fType; + ChildList fChildren; + int32 fDimension; +}; + + +// TODO: Are ArrayValueNode and InternalArrayValueNode still needed? + +class ArrayValueNode : public AbstractArrayValueNode { +public: + ArrayValueNode(ValueNodeChild* nodeChild, + ArrayType* type); + virtual ~ArrayValueNode(); +}; + + +class InternalArrayValueNode : public AbstractArrayValueNode { +public: + InternalArrayValueNode( + ValueNodeChild* nodeChild, + ArrayType* type, int32 dimension); + virtual ~InternalArrayValueNode(); +}; + + +class AbstractArrayValueNodeChild : public ValueNodeChild { +public: + AbstractArrayValueNodeChild( + AbstractArrayValueNode* parent, + const BString& name, int64 elementIndex); + virtual ~AbstractArrayValueNodeChild(); + + AbstractArrayValueNode* ArrayParent() const { return fParent; } + int32 ElementIndex() const { return fElementIndex; } + + virtual const BString& Name() const; + virtual ValueNode* Parent() const; + +protected: + AbstractArrayValueNode* fParent; + BString fName; + int64 fElementIndex; +}; + + +class ArrayValueNodeChild : public AbstractArrayValueNodeChild { +public: + ArrayValueNodeChild( + AbstractArrayValueNode* parent, + const BString& name, int64 elementIndex, + Type* type); + virtual ~ArrayValueNodeChild(); + + virtual Type* GetType() const; + + virtual status_t ResolveLocation(ValueLoader* valueLoader, + ValueLocation*& _location); + +private: + Type* fType; +}; + + +class InternalArrayValueNodeChild : public AbstractArrayValueNodeChild { +public: + InternalArrayValueNodeChild( + AbstractArrayValueNode* parent, + const BString& name, int64 elementIndex, + ArrayType* type); + virtual ~InternalArrayValueNodeChild(); + + virtual Type* GetType() const; + + virtual bool IsInternal() const; + virtual status_t CreateInternalNode(ValueNode*& _node); + + virtual status_t ResolveLocation(ValueLoader* valueLoader, + ValueLocation*& _location); + +private: + ArrayType* fType; +}; + + +#endif // ARRAY_VALUE_NODE_H diff --git a/src/apps/debugger/value/value_nodes/CompoundValueNode.cpp b/src/apps/debugger/value/value_nodes/CompoundValueNode.cpp new file mode 100644 index 0000000000..0479d35b33 --- /dev/null +++ b/src/apps/debugger/value/value_nodes/CompoundValueNode.cpp @@ -0,0 +1,243 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + + +#include "CompoundValueNode.h" + +#include + +#include "Architecture.h" +#include "IntegerValue.h" +#include "Tracing.h" +#include "Type.h" +#include "ValueLoader.h" +#include "ValueLocation.h" +#include "ValueNodeContainer.h" + + +// #pragma mark - Child + + +class CompoundValueNode::Child : public ValueNodeChild { +public: + Child(CompoundValueNode* parent, const BString& name) + : + fParent(parent), + fName(name) + { + } + + virtual const BString& Name() const + { + return fName; + } + + virtual ValueNode* Parent() const + { + return fParent; + } + +protected: + CompoundValueNode* fParent; + BString fName; +}; + + +// #pragma mark - BaseTypeChild + + +class CompoundValueNode::BaseTypeChild : public Child { +public: + BaseTypeChild(CompoundValueNode* parent, BaseType* baseType) + : + Child(parent, baseType->GetType()->Name()), + fBaseType(baseType) + { + fBaseType->AcquireReference(); + } + + virtual ~BaseTypeChild() + { + fBaseType->ReleaseReference(); + } + + virtual Type* GetType() const + { + return fBaseType->GetType(); + } + + virtual status_t ResolveLocation(ValueLoader* valueLoader, + ValueLocation*& _location) + { + // The parent's location refers to the location of the complete + // object. We want to extract the location of a member. + ValueLocation* parentLocation = fParent->Location(); + if (parentLocation == NULL) + return B_BAD_VALUE; + + ValueLocation* location; + status_t error = fParent->fType->ResolveBaseTypeLocation(fBaseType, + *parentLocation, location); + if (error != B_OK) { + TRACE_LOCALS("CompoundValueNode::BaseTypeChild::ResolveLocation(): " + "ResolveBaseTypeLocation() failed: %s\n", strerror(error)); + return error; + } + + _location = location; + return B_OK; + } + +private: + BaseType* fBaseType; +}; + + +// #pragma mark - MemberChild + + +class CompoundValueNode::MemberChild : public Child { +public: + MemberChild(CompoundValueNode* parent, DataMember* member) + : + Child(parent, member->Name()), + fMember(member) + { + fMember->AcquireReference(); + } + + virtual ~MemberChild() + { + fMember->ReleaseReference(); + } + + virtual Type* GetType() const + { + return fMember->GetType(); + } + + virtual status_t ResolveLocation(ValueLoader* valueLoader, + ValueLocation*& _location) + { + // The parent's location refers to the location of the complete + // object. We want to extract the location of a member. + ValueLocation* parentLocation = fParent->Location(); + if (parentLocation == NULL) + return B_BAD_VALUE; + + ValueLocation* location; + status_t error = fParent->fType->ResolveDataMemberLocation(fMember, + *parentLocation, location); + if (error != B_OK) { + TRACE_LOCALS("CompoundValueNode::MemberChild::ResolveLocation(): " + "ResolveDataMemberLocation() failed: %s\n", strerror(error)); + return error; + } + + _location = location; + return B_OK; + } + +private: + DataMember* fMember; +}; + + +// #pragma mark - CompoundValueNode + + +CompoundValueNode::CompoundValueNode(ValueNodeChild* nodeChild, + CompoundType* type) + : + ValueNode(nodeChild), + fType(type) +{ + fType->AcquireReference(); +} + + +CompoundValueNode::~CompoundValueNode() +{ + fType->ReleaseReference(); + + for (int32 i = 0; Child* child = fChildren.ItemAt(i); i++) + child->RemoveReference(); +} + + +Type* +CompoundValueNode::GetType() const +{ + return fType; +} + + +status_t +CompoundValueNode::ResolvedLocationAndValue(ValueLoader* valueLoader, + ValueLocation*& _location, Value*& _value) +{ + // get the location + ValueLocation* location = NodeChild()->Location(); + if (location == NULL) + return B_BAD_VALUE; + + location->AcquireReference(); + _location = location; + _value = NULL; + return B_OK; +} + + +status_t +CompoundValueNode::CreateChildren() +{ + if (!fChildren.IsEmpty()) + return B_OK; + + // base types + for (int32 i = 0; BaseType* baseType = fType->BaseTypeAt(i); i++) { + TRACE_LOCALS(" base %ld\n", i); + + BaseTypeChild* child = new(std::nothrow) BaseTypeChild(this, baseType); + if (child == NULL || !fChildren.AddItem(child)) { + delete child; + return B_NO_MEMORY; + } + + child->SetContainer(fContainer); + } + + // members + for (int32 i = 0; DataMember* member = fType->DataMemberAt(i); i++) { + TRACE_LOCALS(" member %ld: \"%s\"\n", i, member->Name()); + + MemberChild* child = new(std::nothrow) MemberChild(this, member); + if (child == NULL || !fChildren.AddItem(child)) { + delete child; + return B_NO_MEMORY; + } + + child->SetContainer(fContainer); + } + + if (fContainer != NULL) + fContainer->NotifyValueNodeChildrenCreated(this); + + return B_OK; +} + + +int32 +CompoundValueNode::CountChildren() const +{ + return fChildren.CountItems(); +} + + +ValueNodeChild* +CompoundValueNode::ChildAt(int32 index) const +{ + return fChildren.ItemAt(index); +} diff --git a/src/apps/debugger/value/value_nodes/CompoundValueNode.h b/src/apps/debugger/value/value_nodes/CompoundValueNode.h new file mode 100644 index 0000000000..3c556e4611 --- /dev/null +++ b/src/apps/debugger/value/value_nodes/CompoundValueNode.h @@ -0,0 +1,49 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef COMPOUND_VALUE_NODE_H +#define COMPOUND_VALUE_NODE_H + + +#include + +#include "ValueNode.h" + + +class CompoundType; + + +class CompoundValueNode : public ValueNode { +public: + CompoundValueNode(ValueNodeChild* nodeChild, + CompoundType* type); + virtual ~CompoundValueNode(); + + virtual Type* GetType() const; + + virtual status_t ResolvedLocationAndValue( + ValueLoader* valueLoader, + ValueLocation*& _location, + Value*& _value); + + // locking required + + virtual status_t CreateChildren(); + virtual int32 CountChildren() const; + virtual ValueNodeChild* ChildAt(int32 index) const; + +private: + class Child; + class BaseTypeChild; + class MemberChild; + + typedef BObjectList ChildList; + +private: + CompoundType* fType; + ChildList fChildren; +}; + + +#endif // ADDRESS_VALUE_NODE_H diff --git a/src/apps/debugger/value/value_nodes/EnumerationValueNode.cpp b/src/apps/debugger/value/value_nodes/EnumerationValueNode.cpp new file mode 100644 index 0000000000..6cff1f4d22 --- /dev/null +++ b/src/apps/debugger/value/value_nodes/EnumerationValueNode.cpp @@ -0,0 +1,99 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + + +#include "EnumerationValueNode.h" + +#include + +#include "EnumerationValue.h" +#include "Tracing.h" +#include "Type.h" +#include "ValueLoader.h" +#include "ValueLocation.h" + + +EnumerationValueNode::EnumerationValueNode(ValueNodeChild* nodeChild, + EnumerationType* type) + : + ChildlessValueNode(nodeChild), + fType(type) +{ + fType->AcquireReference(); +} + + +EnumerationValueNode::~EnumerationValueNode() +{ + fType->ReleaseReference(); +} + + +Type* +EnumerationValueNode::GetType() const +{ + return fType; +} + + +status_t +EnumerationValueNode::ResolvedLocationAndValue(ValueLoader* valueLoader, + ValueLocation*& _location, Value*& _value) +{ + // get the location + ValueLocation* location = NodeChild()->Location(); + if (location == NULL) + return B_BAD_VALUE; + + TRACE_LOCALS(" TYPE_ENUMERATION\n"); + + // get the value type + type_code valueType = 0; + + // If a base type is known, try that. + if (PrimitiveType* baseType = dynamic_cast( + fType->BaseType())) { + valueType = baseType->TypeConstant(); + if (!BVariant::TypeIsInteger(valueType)) + valueType = 0; + } + + // If we don't have a value type yet, guess it from the type size. + if (valueType == 0) { + // TODO: This is C source language specific! + switch (fType->ByteSize()) { + case 1: + valueType = B_INT8_TYPE; + break; + case 2: + valueType = B_INT16_TYPE; + break; + case 4: + default: + valueType = B_INT32_TYPE; + break; + case 8: + valueType = B_INT64_TYPE; + break; + } + } + + // load the value data + BVariant valueData; + status_t error = valueLoader->LoadValue(location, valueType, true, + valueData); + if (error != B_OK) + return error; + + // create the type object + Value* value = new(std::nothrow) EnumerationValue(fType, valueData); + if (value == NULL) + return B_NO_MEMORY; + + location->AcquireReference(); + _location = location; + _value = value; + return B_OK; +} diff --git a/src/apps/debugger/value/value_nodes/EnumerationValueNode.h b/src/apps/debugger/value/value_nodes/EnumerationValueNode.h new file mode 100644 index 0000000000..ebe2f4512b --- /dev/null +++ b/src/apps/debugger/value/value_nodes/EnumerationValueNode.h @@ -0,0 +1,33 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef ENUMERATION_VALUE_NODE_H +#define ENUMERATION_VALUE_NODE_H + + +#include "ValueNode.h" + + +class EnumerationType; + + +class EnumerationValueNode : public ChildlessValueNode { +public: + EnumerationValueNode(ValueNodeChild* nodeChild, + EnumerationType* type); + virtual ~EnumerationValueNode(); + + virtual Type* GetType() const; + + virtual status_t ResolvedLocationAndValue( + ValueLoader* valueLoader, + ValueLocation*& _location, + Value*& _value); + +private: + EnumerationType* fType; +}; + + +#endif // ENUMERATION_VALUE_NODE_H diff --git a/src/apps/debugger/value/value_nodes/PointerToMemberValueNode.cpp b/src/apps/debugger/value/value_nodes/PointerToMemberValueNode.cpp new file mode 100644 index 0000000000..21a02daa83 --- /dev/null +++ b/src/apps/debugger/value/value_nodes/PointerToMemberValueNode.cpp @@ -0,0 +1,79 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + + +#include "PointerToMemberValueNode.h" + +#include + +#include "Architecture.h" +#include "IntegerValue.h" +#include "Tracing.h" +#include "Type.h" +#include "ValueLoader.h" +#include "ValueLocation.h" + + +PointerToMemberValueNode::PointerToMemberValueNode(ValueNodeChild* nodeChild, + PointerToMemberType* type) + : + ChildlessValueNode(nodeChild), + fType(type) +{ + fType->AcquireReference(); +} + + +PointerToMemberValueNode::~PointerToMemberValueNode() +{ + fType->ReleaseReference(); +} + + +Type* +PointerToMemberValueNode::GetType() const +{ + return fType; +} + + +status_t +PointerToMemberValueNode::ResolvedLocationAndValue(ValueLoader* valueLoader, + ValueLocation*& _location, Value*& _value) +{ + // get the location + ValueLocation* location = NodeChild()->Location(); + if (location == NULL) + return B_BAD_VALUE; + + TRACE_LOCALS(" TYPE_POINTER_TO_MEMBER\n"); + + // get the value type + type_code valueType; + if (valueLoader->GetArchitecture()->AddressSize() == 4) { + valueType = B_UINT32_TYPE; + TRACE_LOCALS(" -> 32 bit\n"); + } else { + valueType = B_UINT64_TYPE; + TRACE_LOCALS(" -> 64 bit\n"); + } + + // load the value data + BVariant valueData; + status_t error = valueLoader->LoadValue(location, valueType, false, + valueData); + if (error != B_OK) + return error; + + // create the type object + Value* value = new(std::nothrow) IntegerValue(valueData); + if (value == NULL) + return B_NO_MEMORY; + + location->AcquireReference(); + _location = location; + _value = value; + return B_OK; +} diff --git a/src/apps/debugger/value/value_nodes/PointerToMemberValueNode.h b/src/apps/debugger/value/value_nodes/PointerToMemberValueNode.h new file mode 100644 index 0000000000..7c58b0cfab --- /dev/null +++ b/src/apps/debugger/value/value_nodes/PointerToMemberValueNode.h @@ -0,0 +1,34 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef POINTER_TO_MEMBER_VALUE_NODE_H +#define POINTER_TO_MEMBER_VALUE_NODE_H + + +#include "ValueNode.h" + + +class PointerToMemberType; + + +class PointerToMemberValueNode : public ChildlessValueNode { +public: + PointerToMemberValueNode( + ValueNodeChild* nodeChild, + PointerToMemberType* type); + virtual ~PointerToMemberValueNode(); + + virtual Type* GetType() const; + + virtual status_t ResolvedLocationAndValue( + ValueLoader* valueLoader, + ValueLocation*& _location, + Value*& _value); + +private: + PointerToMemberType* fType; +}; + + +#endif // POINTER_TO_MEMBER_VALUE_NODE_H diff --git a/src/apps/debugger/value/value_nodes/PrimitiveValueNode.cpp b/src/apps/debugger/value/value_nodes/PrimitiveValueNode.cpp new file mode 100644 index 0000000000..106c653aeb --- /dev/null +++ b/src/apps/debugger/value/value_nodes/PrimitiveValueNode.cpp @@ -0,0 +1,91 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + + +#include "PrimitiveValueNode.h" + +#include + +#include "BoolValue.h" +#include "FloatValue.h" +#include "IntegerValue.h" +#include "Tracing.h" +#include "Type.h" +#include "ValueLoader.h" +#include "ValueLocation.h" + + +PrimitiveValueNode::PrimitiveValueNode(ValueNodeChild* nodeChild, + PrimitiveType* type) + : + ChildlessValueNode(nodeChild), + fType(type) +{ + fType->AcquireReference(); +} + + +PrimitiveValueNode::~PrimitiveValueNode() +{ + fType->ReleaseReference(); +} + + +Type* +PrimitiveValueNode::GetType() const +{ + return fType; +} + + +status_t +PrimitiveValueNode::ResolvedLocationAndValue(ValueLoader* valueLoader, + ValueLocation*& _location, Value*& _value) +{ + // get the location + ValueLocation* location = NodeChild()->Location(); + if (location == NULL) + return B_BAD_VALUE; + + // get the value type + type_code valueType = fType->TypeConstant(); + if (!BVariant::TypeIsNumber(valueType) && valueType != B_BOOL_TYPE) { + TRACE_LOCALS(" -> unknown type constant\n"); + return B_UNSUPPORTED; + } + + bool shortValueIsFine = BVariant::TypeIsInteger(valueType) + || valueType == B_BOOL_TYPE; + + TRACE_LOCALS(" TYPE_PRIMITIVE: '%c%c%c%c'\n", + int(valueType >> 24), int(valueType >> 16), + int(valueType >> 8), int(valueType)); + + // load the value data + BVariant valueData; + status_t error = valueLoader->LoadValue(location, valueType, + shortValueIsFine, valueData); + if (error != B_OK) + return error; + + // create the type object + Value* value; + if (valueType == B_BOOL_TYPE) + value = new(std::nothrow) BoolValue(valueData.ToBool()); + else if (BVariant::TypeIsInteger(valueType)) + value = new(std::nothrow) IntegerValue(valueData); + else if (BVariant::TypeIsFloat(valueType)) + value = new(std::nothrow) FloatValue(valueData.ToDouble()); + else + return B_UNSUPPORTED; + + if (value == NULL) + return B_NO_MEMORY; + + location->AcquireReference(); + _location = location; + _value = value; + return B_OK; +} diff --git a/src/apps/debugger/value/value_nodes/PrimitiveValueNode.h b/src/apps/debugger/value/value_nodes/PrimitiveValueNode.h new file mode 100644 index 0000000000..19c3439819 --- /dev/null +++ b/src/apps/debugger/value/value_nodes/PrimitiveValueNode.h @@ -0,0 +1,33 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef PRIMITIVE_VALUE_NODE_H +#define PRIMITIVE_VALUE_NODE_H + + +#include "ValueNode.h" + + +class PrimitiveType; + + +class PrimitiveValueNode : public ChildlessValueNode { +public: + PrimitiveValueNode(ValueNodeChild* nodeChild, + PrimitiveType* type); + virtual ~PrimitiveValueNode(); + + virtual Type* GetType() const; + + virtual status_t ResolvedLocationAndValue( + ValueLoader* valueLoader, + ValueLocation*& _location, + Value*& _value); + +private: + PrimitiveType* fType; +}; + + +#endif // PRIMITIVE_VALUE_NODE_H diff --git a/src/apps/debugger/value/value_nodes/VariableValueNodeChild.cpp b/src/apps/debugger/value/value_nodes/VariableValueNodeChild.cpp new file mode 100644 index 0000000000..82711de0f5 --- /dev/null +++ b/src/apps/debugger/value/value_nodes/VariableValueNodeChild.cpp @@ -0,0 +1,56 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + + +#include "VariableValueNodeChild.h" + +#include "Variable.h" +#include "ValueLocation.h" + + +VariableValueNodeChild::VariableValueNodeChild(Variable* variable) + : + fVariable(variable) +{ + fVariable->AcquireReference(); + SetLocation(fVariable->Location(), B_OK); +} + + +VariableValueNodeChild::~VariableValueNodeChild() +{ + fVariable->ReleaseReference(); +} + + +const BString& +VariableValueNodeChild::Name() const +{ + return fVariable->Name(); +} + + +Type* +VariableValueNodeChild::GetType() const +{ + return fVariable->GetType(); +} + + +ValueNode* +VariableValueNodeChild::Parent() const +{ + return NULL; +} + + +status_t +VariableValueNodeChild::ResolveLocation(ValueLoader* valueLoader, + ValueLocation*& _location) +{ + _location = fVariable->Location(); + _location->AcquireReference(); + return B_OK; +} diff --git a/src/apps/debugger/value/value_nodes/VariableValueNodeChild.h b/src/apps/debugger/value/value_nodes/VariableValueNodeChild.h new file mode 100644 index 0000000000..efa05fe211 --- /dev/null +++ b/src/apps/debugger/value/value_nodes/VariableValueNodeChild.h @@ -0,0 +1,32 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef VARIABLE_VALUE_NODE_CHILD_H +#define VARIABLE_VALUE_NODE_CHILD_H + + +#include "ValueNode.h" + + +class Variable; + + +class VariableValueNodeChild : public ValueNodeChild { +public: + VariableValueNodeChild(Variable* variable); + virtual ~VariableValueNodeChild(); + + virtual const BString& Name() const; + virtual Type* GetType() const; + virtual ValueNode* Parent() const; + + virtual status_t ResolveLocation(ValueLoader* valueLoader, + ValueLocation*& _location); + +private: + Variable* fVariable; +}; + + +#endif // VARIABLE_VALUE_NODE_CHILD_H diff --git a/src/apps/debugger/value/values/AddressValue.cpp b/src/apps/debugger/value/values/AddressValue.cpp new file mode 100644 index 0000000000..0e90bbc4a7 --- /dev/null +++ b/src/apps/debugger/value/values/AddressValue.cpp @@ -0,0 +1,39 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + + +#include "AddressValue.h" + +#include + + +AddressValue::AddressValue(const BVariant& value) + : + IntegerValue(value) +{ +} + + +AddressValue::~AddressValue() +{ +} + + +bool +AddressValue::ToString(BString& _string) const +{ + if (!fValue.IsInteger()) + return false; + + char buffer[32]; + snprintf(buffer, sizeof(buffer), "%#llx", fValue.ToUInt64()); + + BString string(buffer); + if (string.Length() == 0) + return false; + + _string = string; + return true; +} diff --git a/src/apps/debugger/value/values/AddressValue.h b/src/apps/debugger/value/values/AddressValue.h new file mode 100644 index 0000000000..228cedfe97 --- /dev/null +++ b/src/apps/debugger/value/values/AddressValue.h @@ -0,0 +1,21 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef ADDRESS_VALUE_H +#define ADDRESS_VALUE_H + + +#include "IntegerValue.h" + + +class AddressValue : public IntegerValue { +public: + AddressValue(const BVariant& value); + virtual ~AddressValue(); + + virtual bool ToString(BString& _string) const; +}; + + +#endif // ADDRESS_VALUE_H diff --git a/src/apps/debugger/value/values/BoolValue.cpp b/src/apps/debugger/value/values/BoolValue.cpp new file mode 100644 index 0000000000..4d2c97ed02 --- /dev/null +++ b/src/apps/debugger/value/values/BoolValue.cpp @@ -0,0 +1,47 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + + +#include "BoolValue.h" + + +BoolValue::BoolValue(bool value) + : + fValue(value) +{ +} + + +BoolValue::~BoolValue() +{ +} + + +bool +BoolValue::ToString(BString& _string) const +{ + BString string = fValue ? "true" : "false"; + if (string.Length() == 0) + return false; + + _string = string; + return true; +} + + +bool +BoolValue::ToVariant(BVariant& _value) const +{ + _value = fValue; + return true; +} + + +bool +BoolValue::operator==(const Value& other) const +{ + const BoolValue* otherBool = dynamic_cast(&other); + return otherBool != NULL ? fValue == otherBool->fValue : false; +} diff --git a/src/apps/debugger/value/values/BoolValue.h b/src/apps/debugger/value/values/BoolValue.h new file mode 100644 index 0000000000..ad82d7c3ab --- /dev/null +++ b/src/apps/debugger/value/values/BoolValue.h @@ -0,0 +1,30 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef BOOL_VALUE_H +#define BOOL_VALUE_H + + +#include "Value.h" + + +class BoolValue : public Value { +public: + BoolValue(bool value); + virtual ~BoolValue(); + + bool GetValue() const + { return fValue; } + + virtual bool ToString(BString& _string) const; + virtual bool ToVariant(BVariant& _value) const; + + virtual bool operator==(const Value& other) const; + +private: + bool fValue; +}; + + +#endif // BOOL_VALUE_H diff --git a/src/apps/debugger/value/values/EnumerationValue.cpp b/src/apps/debugger/value/values/EnumerationValue.cpp new file mode 100644 index 0000000000..c32cb8f095 --- /dev/null +++ b/src/apps/debugger/value/values/EnumerationValue.cpp @@ -0,0 +1,43 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + + +#include "EnumerationValue.h" + +#include "Type.h" + + +EnumerationValue::EnumerationValue(EnumerationType* type, const BVariant& value) + : + IntegerValue(value), + fType(type) +{ + fType->AcquireReference(); +} + + +EnumerationValue::~EnumerationValue() +{ + fType->ReleaseReference(); +} + + +bool +EnumerationValue::ToString(BString& _string) const +{ + if (!fValue.IsInteger()) + return false; + + EnumeratorValue* enumValue = fType->ValueFor(fValue); + if (enumValue == NULL) + return IntegerValue::ToString(_string); + + BString string(enumValue->Name()); + if (string.Length() == 0) + return false; + + _string = string; + return true; +} diff --git a/src/apps/debugger/value/values/EnumerationValue.h b/src/apps/debugger/value/values/EnumerationValue.h new file mode 100644 index 0000000000..915f1897ac --- /dev/null +++ b/src/apps/debugger/value/values/EnumerationValue.h @@ -0,0 +1,31 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef ENUMERATION_VALUE_H +#define ENUMERATION_VALUE_H + + +#include "IntegerValue.h" + + +class EnumerationType; + + +class EnumerationValue : public IntegerValue { +public: + EnumerationValue(EnumerationType* type, + const BVariant& value); + virtual ~EnumerationValue(); + + EnumerationType* GetType() const + { return fType; } + + virtual bool ToString(BString& _string) const; + +private: + EnumerationType* fType; +}; + + +#endif // ENUMERATION_VALUE_H diff --git a/src/apps/debugger/value/values/FloatValue.cpp b/src/apps/debugger/value/values/FloatValue.cpp new file mode 100644 index 0000000000..52f0cc0b6b --- /dev/null +++ b/src/apps/debugger/value/values/FloatValue.cpp @@ -0,0 +1,52 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + + +#include "FloatValue.h" + +#include + + +FloatValue::FloatValue(double value) + : + fValue(value) +{ +} + + +FloatValue::~FloatValue() +{ +} + + +bool +FloatValue::ToString(BString& _string) const +{ + char buffer[128]; + snprintf(buffer, sizeof(buffer), "%g", fValue); + + BString string(buffer); + if (string.Length() == 0) + return false; + + _string = string; + return true; +} + + +bool +FloatValue::ToVariant(BVariant& _value) const +{ + _value = fValue; + return true; +} + + +bool +FloatValue::operator==(const Value& other) const +{ + const FloatValue* otherInt = dynamic_cast(&other); + return otherInt != NULL ? fValue == otherInt->fValue : false; +} diff --git a/src/apps/debugger/value/values/FloatValue.h b/src/apps/debugger/value/values/FloatValue.h new file mode 100644 index 0000000000..a974e98edd --- /dev/null +++ b/src/apps/debugger/value/values/FloatValue.h @@ -0,0 +1,30 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef FLOAT_VALUE_H +#define FLOAT_VALUE_H + + +#include "Value.h" + + +class FloatValue : public Value { +public: + FloatValue(double value); + virtual ~FloatValue(); + + double GetValue() const + { return fValue; } + + virtual bool ToString(BString& _string) const; + virtual bool ToVariant(BVariant& _value) const; + + virtual bool operator==(const Value& other) const; + +private: + double fValue; +}; + + +#endif // FLOAT_VALUE_H diff --git a/src/apps/debugger/value/values/IntegerValue.cpp b/src/apps/debugger/value/values/IntegerValue.cpp new file mode 100644 index 0000000000..3fafa2306f --- /dev/null +++ b/src/apps/debugger/value/values/IntegerValue.cpp @@ -0,0 +1,64 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + + +#include "IntegerValue.h" + + +IntegerValue::IntegerValue(const BVariant& value) + : + fValue(value) +{ +} + + +IntegerValue::~IntegerValue() +{ +} + + +bool +IntegerValue::IsSigned() const +{ + bool isSigned; + return fValue.IsInteger(&isSigned) && isSigned; +} + + +bool +IntegerValue::ToString(BString& _string) const +{ + bool isSigned; + if (!fValue.IsInteger(&isSigned)) + return false; + + BString string; + if (isSigned) + string << fValue.ToInt64(); + else + string << fValue.ToUInt64(); + + if (string.Length() == 0) + return false; + + _string = string; + return true; +} + + +bool +IntegerValue::ToVariant(BVariant& _value) const +{ + _value = fValue; + return true; +} + + +bool +IntegerValue::operator==(const Value& other) const +{ + const IntegerValue* otherInt = dynamic_cast(&other); + return otherInt != NULL ? fValue == otherInt->fValue : false; +} diff --git a/src/apps/debugger/value/values/IntegerValue.h b/src/apps/debugger/value/values/IntegerValue.h new file mode 100644 index 0000000000..1641cf92e1 --- /dev/null +++ b/src/apps/debugger/value/values/IntegerValue.h @@ -0,0 +1,36 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef INTEGER_VALUE_H +#define INTEGER_VALUE_H + + +#include "Value.h" + + +class IntegerValue : public Value { +public: + IntegerValue(const BVariant& value); + virtual ~IntegerValue(); + + bool IsSigned() const; + + int64 ToInt64() const + { return fValue.ToInt64(); } + uint64 ToUInt64() const + { return fValue.ToUInt64(); } + const BVariant& GetValue() const + { return fValue; } + + virtual bool ToString(BString& _string) const; + virtual bool ToVariant(BVariant& _value) const; + + virtual bool operator==(const Value& other) const; + +protected: + BVariant fValue; +}; + + +#endif // INTEGER_VALUE_H