Merge branch 'debugger_report_add_disassembly'
This commit is contained in:
@@ -18,12 +18,15 @@
|
|||||||
#include "AreaInfo.h"
|
#include "AreaInfo.h"
|
||||||
#include "CpuState.h"
|
#include "CpuState.h"
|
||||||
#include "DebuggerInterface.h"
|
#include "DebuggerInterface.h"
|
||||||
|
#include "DisassembledCode.h"
|
||||||
|
#include "FunctionInstance.h"
|
||||||
#include "Image.h"
|
#include "Image.h"
|
||||||
#include "MessageCodes.h"
|
#include "MessageCodes.h"
|
||||||
#include "Register.h"
|
#include "Register.h"
|
||||||
#include "SemaphoreInfo.h"
|
#include "SemaphoreInfo.h"
|
||||||
#include "StackFrame.h"
|
#include "StackFrame.h"
|
||||||
#include "StackTrace.h"
|
#include "StackTrace.h"
|
||||||
|
#include "Statement.h"
|
||||||
#include "StringUtils.h"
|
#include "StringUtils.h"
|
||||||
#include "SystemInfo.h"
|
#include "SystemInfo.h"
|
||||||
#include "Team.h"
|
#include "Team.h"
|
||||||
@@ -51,7 +54,8 @@ DebugReportGenerator::DebugReportGenerator(::Team* team,
|
|||||||
fWaitingNode(NULL),
|
fWaitingNode(NULL),
|
||||||
fCurrentBlock(NULL),
|
fCurrentBlock(NULL),
|
||||||
fBlockRetrievalStatus(B_OK),
|
fBlockRetrievalStatus(B_OK),
|
||||||
fTraceWaitingThread(NULL)
|
fTraceWaitingThread(NULL),
|
||||||
|
fSourceWaitingFunction(NULL)
|
||||||
{
|
{
|
||||||
fTeam->AddListener(this);
|
fTeam->AddListener(this);
|
||||||
fArchitecture->AcquireReference();
|
fArchitecture->AcquireReference();
|
||||||
@@ -204,6 +208,20 @@ DebugReportGenerator::ValueNodeValueChanged(ValueNode* node)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
DebugReportGenerator::FunctionSourceCodeChanged(Function* function)
|
||||||
|
{
|
||||||
|
AutoLocker< ::Team> teamLocker(fTeam);
|
||||||
|
if (function == fSourceWaitingFunction) {
|
||||||
|
if (function->FirstInstance()->SourceCodeState()
|
||||||
|
== FUNCTION_SOURCE_LOADED
|
||||||
|
|| function->FirstInstance()->SourceCodeState()
|
||||||
|
== FUNCTION_SOURCE_UNAVAILABLE) {
|
||||||
|
release_sem(fTeamDataSem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
DebugReportGenerator::_GenerateReportHeader(BString& _output)
|
DebugReportGenerator::_GenerateReportHeader(BString& _output)
|
||||||
{
|
{
|
||||||
@@ -452,9 +470,12 @@ DebugReportGenerator::_DumpDebuggedThreadInfo(BString& _output,
|
|||||||
&& frame->CountLocalVariables() == 0) {
|
&& frame->CountLocalVariables() == 0) {
|
||||||
// only dump the topmost frame
|
// only dump the topmost frame
|
||||||
if (i == 0) {
|
if (i == 0) {
|
||||||
|
locker.Unlock();
|
||||||
|
_DumpFunctionDisassembly(_output, frame->InstructionPointer());
|
||||||
_DumpStackFrameMemory(_output, thread->GetCpuState(),
|
_DumpStackFrameMemory(_output, thread->GetCpuState(),
|
||||||
frame->FrameAddress(), thread->GetTeam()->GetArchitecture()
|
frame->FrameAddress(), thread->GetTeam()->GetArchitecture()
|
||||||
->StackGrowthDirection());
|
->StackGrowthDirection());
|
||||||
|
locker.Lock();
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -495,6 +516,66 @@ DebugReportGenerator::_DumpDebuggedThreadInfo(BString& _output,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
DebugReportGenerator::_DumpFunctionDisassembly(BString& _output,
|
||||||
|
target_addr_t instructionPointer)
|
||||||
|
{
|
||||||
|
AutoLocker< ::Team> teamLocker(fTeam);
|
||||||
|
BString data;
|
||||||
|
FunctionInstance* instance = NULL;
|
||||||
|
Statement* statement = NULL;
|
||||||
|
status_t error = fTeam->GetStatementAtAddress(instructionPointer, instance,
|
||||||
|
statement);
|
||||||
|
if (error != B_OK) {
|
||||||
|
data.SetToFormat("Unable to retrieve disassembly for IP %#" B_PRIx64
|
||||||
|
": %s\n", instructionPointer, strerror(error));
|
||||||
|
_output << data;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DisassembledCode* code = instance->GetSourceCode();
|
||||||
|
Function* function = instance->GetFunction();
|
||||||
|
if (code == NULL) {
|
||||||
|
switch (function->SourceCodeState()) {
|
||||||
|
case FUNCTION_SOURCE_NOT_LOADED:
|
||||||
|
function->AddListener(this);
|
||||||
|
fSourceWaitingFunction = function;
|
||||||
|
fListener->FunctionSourceCodeRequested(instance, true);
|
||||||
|
// fall through
|
||||||
|
case FUNCTION_SOURCE_LOADING:
|
||||||
|
{
|
||||||
|
teamLocker.Unlock();
|
||||||
|
error = acquire_sem(fTeamDataSem);
|
||||||
|
if (error != B_OK)
|
||||||
|
return;
|
||||||
|
teamLocker.Lock();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (instance->SourceCodeState() == FUNCTION_SOURCE_UNAVAILABLE)
|
||||||
|
return;
|
||||||
|
|
||||||
|
error = fTeam->GetStatementAtAddress(instructionPointer, instance,
|
||||||
|
statement);
|
||||||
|
code = instance->GetSourceCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
SourceLocation location = statement->StartSourceLocation();
|
||||||
|
|
||||||
|
_output << "\t\t\tDisassembly:\n";
|
||||||
|
for (int32 i = 0; i < location.Line(); i++) {
|
||||||
|
_output << "\t\t\t\t" << code->LineAt(i);
|
||||||
|
if (i == location.Line() - 1)
|
||||||
|
_output << " <--";
|
||||||
|
_output << "\n";
|
||||||
|
}
|
||||||
|
_output << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
DebugReportGenerator::_DumpStackFrameMemory(BString& _output,
|
DebugReportGenerator::_DumpStackFrameMemory(BString& _output,
|
||||||
CpuState* state, target_addr_t framePointer, uint8 stackDirection)
|
CpuState* state, target_addr_t framePointer, uint8 stackDirection)
|
||||||
@@ -519,11 +600,11 @@ DebugReportGenerator::_DumpStackFrameMemory(BString& _output,
|
|||||||
|
|
||||||
_output << "\t\t\tFrame memory:\n";
|
_output << "\t\t\tFrame memory:\n";
|
||||||
if (fBlockRetrievalStatus == B_OK) {
|
if (fBlockRetrievalStatus == B_OK) {
|
||||||
UiUtils::DumpMemory(_output, 3, fCurrentBlock, startAddress, 1, 16,
|
UiUtils::DumpMemory(_output, 4 , fCurrentBlock, startAddress, 1, 16,
|
||||||
endAddress - startAddress);
|
endAddress - startAddress);
|
||||||
} else {
|
} else {
|
||||||
BString data;
|
BString data;
|
||||||
data.SetToFormat("\t\t\tUnavailable (%s)\n", strerror(
|
data.SetToFormat("\t\t\t\tUnavailable (%s)\n", strerror(
|
||||||
fBlockRetrievalStatus));
|
fBlockRetrievalStatus));
|
||||||
_output += data;
|
_output += data;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
#include <Looper.h>
|
#include <Looper.h>
|
||||||
|
|
||||||
|
#include "Function.h"
|
||||||
#include "Team.h"
|
#include "Team.h"
|
||||||
#include "TeamMemoryBlock.h"
|
#include "TeamMemoryBlock.h"
|
||||||
#include "ValueNodeContainer.h"
|
#include "ValueNodeContainer.h"
|
||||||
@@ -30,7 +31,8 @@ class ValueNodeManager;
|
|||||||
|
|
||||||
|
|
||||||
class DebugReportGenerator : public BLooper, private Team::Listener,
|
class DebugReportGenerator : public BLooper, private Team::Listener,
|
||||||
private TeamMemoryBlock::Listener, private ValueNodeContainer::Listener {
|
private TeamMemoryBlock::Listener, private ValueNodeContainer::Listener,
|
||||||
|
private Function::Listener {
|
||||||
public:
|
public:
|
||||||
DebugReportGenerator(::Team* team,
|
DebugReportGenerator(::Team* team,
|
||||||
UserInterfaceListener* listener,
|
UserInterfaceListener* listener,
|
||||||
@@ -58,6 +60,8 @@ private:
|
|||||||
// ValueNodeContainer::Listener
|
// ValueNodeContainer::Listener
|
||||||
virtual void ValueNodeValueChanged(ValueNode* node);
|
virtual void ValueNodeValueChanged(ValueNode* node);
|
||||||
|
|
||||||
|
// Function::Listener
|
||||||
|
virtual void FunctionSourceCodeChanged(Function* function);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
status_t _GenerateReport(const entry_ref& outputPath);
|
status_t _GenerateReport(const entry_ref& outputPath);
|
||||||
@@ -68,6 +72,8 @@ private:
|
|||||||
status_t _DumpRunningThreads(BString& _output);
|
status_t _DumpRunningThreads(BString& _output);
|
||||||
status_t _DumpDebuggedThreadInfo(BString& _output,
|
status_t _DumpDebuggedThreadInfo(BString& _output,
|
||||||
::Thread* thread);
|
::Thread* thread);
|
||||||
|
void _DumpFunctionDisassembly(BString& _output,
|
||||||
|
target_addr_t instructionPointer);
|
||||||
void _DumpStackFrameMemory(BString& _output,
|
void _DumpStackFrameMemory(BString& _output,
|
||||||
CpuState* state,
|
CpuState* state,
|
||||||
target_addr_t framePointer,
|
target_addr_t framePointer,
|
||||||
@@ -97,6 +103,7 @@ private:
|
|||||||
TeamMemoryBlock* fCurrentBlock;
|
TeamMemoryBlock* fCurrentBlock;
|
||||||
status_t fBlockRetrievalStatus;
|
status_t fBlockRetrievalStatus;
|
||||||
::Thread* fTraceWaitingThread;
|
::Thread* fTraceWaitingThread;
|
||||||
|
Function* fSourceWaitingFunction;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // DEBUG_REPORT_GENERATOR_H
|
#endif // DEBUG_REPORT_GENERATOR_H
|
||||||
|
|||||||
Reference in New Issue
Block a user