Add frame dumping capabilities to report generator.
- If the top frame of a stopped thread has no arguments or variables available, dump the memory block to which the stack frame belongs, starting at the current stack pointer and extending to the end of the block.
This commit is contained in:
parent
9a4802db55
commit
3e441f885e
@ -46,6 +46,7 @@ DebugReportGenerator::DebugReportGenerator(::Team* team,
|
||||
fNodeManager(NULL),
|
||||
fListener(listener),
|
||||
fWaitingNode(NULL),
|
||||
fCurrentBlock(NULL),
|
||||
fTraceWaitingThread(NULL)
|
||||
{
|
||||
fTeam->AddListener(this);
|
||||
@ -61,6 +62,9 @@ DebugReportGenerator::~DebugReportGenerator()
|
||||
fNodeManager->RemoveListener(this);
|
||||
fNodeManager->ReleaseReference();
|
||||
}
|
||||
|
||||
if (fCurrentBlock != NULL)
|
||||
fCurrentBlock->ReleaseReference();
|
||||
}
|
||||
|
||||
|
||||
@ -161,6 +165,19 @@ DebugReportGenerator::ThreadStackTraceChanged(const ::Team::ThreadEvent& event)
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
DebugReportGenerator::MemoryBlockRetrieved(TeamMemoryBlock* block)
|
||||
{
|
||||
if (fCurrentBlock != NULL) {
|
||||
fCurrentBlock->ReleaseReference();
|
||||
fCurrentBlock = NULL;
|
||||
}
|
||||
|
||||
fCurrentBlock = block;
|
||||
release_sem(fTeamDataSem);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
DebugReportGenerator::ValueNodeValueChanged(ValueNode* node)
|
||||
{
|
||||
@ -323,6 +340,9 @@ DebugReportGenerator::_DumpDebuggedThreadInfo(BString& _output,
|
||||
_output << data;
|
||||
if (frame->CountParameters() == 0
|
||||
&& frame->CountLocalVariables() == 0) {
|
||||
// only dump the topmost frame
|
||||
if (i == 0)
|
||||
_DumpStackFrameMemory(_output, thread->GetCpuState());
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -362,6 +382,24 @@ DebugReportGenerator::_DumpDebuggedThreadInfo(BString& _output,
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
DebugReportGenerator::_DumpStackFrameMemory(BString& _output,
|
||||
CpuState* state)
|
||||
{
|
||||
target_addr_t address = state->StackPointer();
|
||||
if (fCurrentBlock == NULL || !fCurrentBlock->Contains(address)) {
|
||||
fListener->InspectRequested(address, this);
|
||||
status_t result = B_OK;
|
||||
do {
|
||||
result = acquire_sem(fTeamDataSem);
|
||||
} while (result == B_INTERRUPTED);
|
||||
}
|
||||
_output << "\t\t\tFrame memory:\n";
|
||||
UiUtils::DumpMemory(_output, 3, fCurrentBlock, address, 1, 16,
|
||||
fCurrentBlock->BaseAddress() + fCurrentBlock->Size() - address);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
DebugReportGenerator::_ResolveValueIfNeeded(ValueNode* node, StackFrame* frame,
|
||||
int32 maxDepth)
|
||||
@ -371,7 +409,9 @@ DebugReportGenerator::_ResolveValueIfNeeded(ValueNode* node, StackFrame* frame,
|
||||
fWaitingNode = node;
|
||||
fListener->ValueNodeValueRequested(frame->GetCpuState(),
|
||||
fNodeManager->GetContainer(), node);
|
||||
result = acquire_sem(fTeamDataSem);
|
||||
do {
|
||||
result = acquire_sem(fTeamDataSem);
|
||||
} while (result == B_INTERRUPTED);
|
||||
}
|
||||
|
||||
if (node->LocationAndValueResolutionState() == B_OK && maxDepth > 0) {
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include <Looper.h>
|
||||
|
||||
#include "Team.h"
|
||||
#include "TeamMemoryBlock.h"
|
||||
#include "ValueNodeContainer.h"
|
||||
|
||||
|
||||
@ -26,7 +27,7 @@ class ValueNodeManager;
|
||||
|
||||
|
||||
class DebugReportGenerator : public BLooper, private Team::Listener,
|
||||
private ValueNodeContainer::Listener {
|
||||
private TeamMemoryBlock::Listener, private ValueNodeContainer::Listener {
|
||||
public:
|
||||
DebugReportGenerator(::Team* team,
|
||||
UserInterfaceListener* listener);
|
||||
@ -39,18 +40,27 @@ public:
|
||||
|
||||
virtual void MessageReceived(BMessage* message);
|
||||
|
||||
private:
|
||||
// Team::Listener
|
||||
virtual void ThreadStackTraceChanged(
|
||||
const Team::ThreadEvent& event);
|
||||
|
||||
// TeamMemoryBlock::Listener
|
||||
virtual void MemoryBlockRetrieved(TeamMemoryBlock* block);
|
||||
|
||||
// ValueNodeContainer::Listener
|
||||
virtual void ValueNodeValueChanged(ValueNode* node);
|
||||
|
||||
|
||||
private:
|
||||
status_t _GenerateReport(const entry_ref& outputPath);
|
||||
status_t _GenerateReportHeader(BString& output);
|
||||
status_t _DumpLoadedImages(BString& output);
|
||||
status_t _DumpRunningThreads(BString& output);
|
||||
status_t _DumpDebuggedThreadInfo(BString& output,
|
||||
status_t _GenerateReportHeader(BString& _output);
|
||||
status_t _DumpLoadedImages(BString& _output);
|
||||
status_t _DumpRunningThreads(BString& _output);
|
||||
status_t _DumpDebuggedThreadInfo(BString& _output,
|
||||
::Thread* thread);
|
||||
void _DumpStackFrameMemory(BString& _output,
|
||||
CpuState* state);
|
||||
|
||||
status_t _ResolveValueIfNeeded(ValueNode* node,
|
||||
StackFrame* frame, int32 maxDepth);
|
||||
@ -62,6 +72,7 @@ private:
|
||||
ValueNodeManager* fNodeManager;
|
||||
UserInterfaceListener* fListener;
|
||||
ValueNode* fWaitingNode;
|
||||
TeamMemoryBlock* fCurrentBlock;
|
||||
::Thread* fTraceWaitingThread;
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user