diff --git a/src/apps/debugger/controllers/DebugReportGenerator.cpp b/src/apps/debugger/controllers/DebugReportGenerator.cpp index 996e67f631..d8a16d7cf8 100644 --- a/src/apps/debugger/controllers/DebugReportGenerator.cpp +++ b/src/apps/debugger/controllers/DebugReportGenerator.cpp @@ -26,7 +26,13 @@ #include "StringUtils.h" #include "Team.h" #include "Thread.h" +#include "Type.h" #include "UiUtils.h" +#include "Value.h" +#include "ValueLoader.h" +#include "ValueLocation.h" +#include "ValueNode.h" +#include "ValueNodeManager.h" DebugReportGenerator::DebugReportGenerator(::Team* team) @@ -34,7 +40,8 @@ DebugReportGenerator::DebugReportGenerator(::Team* team) BLooper("DebugReportGenerator"), fTeam(team), fArchitecture(team->GetArchitecture()), - fTeamDataSem(-1) + fTeamDataSem(-1), + fNodeManager(NULL) { fTeam->AddListener(this); fArchitecture->AcquireReference(); @@ -45,6 +52,8 @@ DebugReportGenerator::~DebugReportGenerator() { fTeam->RemoveListener(this); fArchitecture->ReleaseReference(); + if (fNodeManager != NULL) + fNodeManager->ReleaseReference(); } @@ -55,6 +64,10 @@ DebugReportGenerator::Init() if (fTeamDataSem < B_OK) return fTeamDataSem; + fNodeManager = new(std::nothrow) ValueNodeManager(); + if (fNodeManager == NULL) + return B_NO_MEMORY; + Run(); return B_OK; @@ -285,6 +298,23 @@ DebugReportGenerator::_DumpDebuggedThreadInfo(BString& _output, sizeof(functionName))); _output << data; + if (frame->CountParameters() == 0 + && frame->CountLocalVariables() == 0) { + continue; + } + + _output << "\t\t\tVariables:\n"; + status_t result = fNodeManager->SetStackFrame(thread, frame); + if (result != B_OK) + continue; + + ValueNodeContainer* container = fNodeManager->GetContainer(); + AutoLocker containerLocker(container); + for (int32 i = 0; i < container->CountChildren(); i++) { + ValueNodeChild* child = container->ChildAt(i); + _DumpValueNode(_output, frame, child); + } + _output << "\n"; } _output << "\n\t\tRegisters:\n"; @@ -304,3 +334,108 @@ DebugReportGenerator::_DumpDebuggedThreadInfo(BString& _output, return B_OK; } + + +status_t +DebugReportGenerator::_DumpValueNode(BString& _output, StackFrame* frame, + ValueNodeChild* child, bool recurse) +{ + status_t result = _ResolveLocationIfNeeded(child, frame); + if (result != B_OK) + return result; + + _output << "\t\t\t"; + if (!recurse) + _output << "\t"; + _output << child->Name() << ": "; + + ValueNode* node = child->Node(); + if (node->LocationAndValueResolutionState() == VALUE_NODE_UNRESOLVED) { + if (_ResolveValueIfNeeded(node, frame) == B_OK) { + Value* value = node->GetValue(); + if (value != NULL) { + BString valueData; + value->ToString(valueData); + _output << valueData; + } else + _output << "Unavailable"; + } else + _output << "Unknown"; + } + if (recurse && node->CountChildren() != 0) + _output << " {"; + + _output << "\n"; + + if (recurse) { + if (node->CountChildren() == 0) + return B_OK; + + if (node->CountChildren() == 1 + && node->GetType()->Kind() == TYPE_ADDRESS + && node->ChildAt(0)->GetType()->Kind() == TYPE_COMPOUND) { + // for the case of a pointer to a compound type, + // we want to hide the intervening compound node and print + // the children directly. + status_t result = fNodeManager->AddChildNodes(node->ChildAt(0)); + if (result == B_OK) { + result = _ResolveLocationIfNeeded(node->ChildAt(0), frame); + if (result == B_OK) { + node = node->ChildAt(0)->Node(); + // attempt to resolve the value here since the node's + // representation may requires its value to be resolved + // before its children can be created + result = _ResolveValueIfNeeded(node, frame); + } + } + } + + for (int32 i = 0; i < node->CountChildren(); i++) { + if (fNodeManager->AddChildNodes(node->ChildAt(i)) != B_OK) + continue; + + // don't dump compound nodes since we won't traverse into + // them anyways and their top level node has no interesting + // information. + if (node->ChildAt(i)->GetType()->Kind() != TYPE_COMPOUND) + _DumpValueNode(_output, frame, node->ChildAt(i), false); + } + _output << "\t\t\t}\n"; + } + + return B_OK; +} + + +status_t +DebugReportGenerator::_ResolveValueIfNeeded(ValueNode* node, StackFrame* frame) +{ + ValueLocation* location = NULL; + Value* value = NULL; + ValueLoader loader(fTeam->GetArchitecture(), fTeam->GetTeamMemory(), + fTeam->GetTeamTypeInformation(), frame->GetCpuState()); + status_t result = node->ResolvedLocationAndValue(&loader, location, + value); + node->SetLocationAndValue(location, value, result); + if (location != NULL) + location->ReleaseReference(); + if (value != NULL) + value->ReleaseReference(); + + return result; +} + + +status_t +DebugReportGenerator::_ResolveLocationIfNeeded(ValueNodeChild* child, + StackFrame* frame) +{ + ValueLocation* location = NULL; + ValueLoader loader(fTeam->GetArchitecture(), fTeam->GetTeamMemory(), + fTeam->GetTeamTypeInformation(), frame->GetCpuState()); + status_t result = child->ResolveLocation(&loader, location); + child->SetLocation(location, result); + if (location != NULL) + location->ReleaseReference(); + return result; +} diff --git a/src/apps/debugger/controllers/DebugReportGenerator.h b/src/apps/debugger/controllers/DebugReportGenerator.h index 1ea4dff8e0..03d7f5c6db 100644 --- a/src/apps/debugger/controllers/DebugReportGenerator.h +++ b/src/apps/debugger/controllers/DebugReportGenerator.h @@ -14,8 +14,13 @@ class entry_ref; class Architecture; class BString; +class StackFrame; class Team; class Thread; +class Value; +class ValueNode; +class ValueNodeChild; +class ValueNodeManager; class DebugReportGenerator : public BLooper, public Team::Listener { @@ -39,11 +44,20 @@ private: status_t _DumpRunningThreads(BString& output); status_t _DumpDebuggedThreadInfo(BString& output, ::Thread* thread); + status_t _DumpValueNode(BString& output, + StackFrame* frame, ValueNodeChild* child, + bool recurse = true); + + status_t _ResolveLocationIfNeeded(ValueNodeChild* child, + StackFrame* frame); + status_t _ResolveValueIfNeeded(ValueNode* node, + StackFrame* frame); private: ::Team* fTeam; Architecture* fArchitecture; sem_id fTeamDataSem; + ValueNodeManager* fNodeManager; }; #endif // DEBUG_REPORT_GENERATOR_H