Add initial version of DebugReportGenerator controller class.
Not yet complete or made use of.
This commit is contained in:
@@ -72,6 +72,7 @@ Application Debugger :
|
|||||||
CpuStateX86.cpp
|
CpuStateX86.cpp
|
||||||
|
|
||||||
# controllers
|
# controllers
|
||||||
|
DebugReportGenerator.cpp
|
||||||
TeamDebugger.cpp
|
TeamDebugger.cpp
|
||||||
ThreadHandler.cpp
|
ThreadHandler.cpp
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,197 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012, Rene Gollent, [email protected].
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "DebugReportGenerator.h"
|
||||||
|
|
||||||
|
#include <AutoLocker.h>
|
||||||
|
#include <File.h>
|
||||||
|
|
||||||
|
#include "Architecture.h"
|
||||||
|
#include "CpuState.h"
|
||||||
|
#include "Image.h"
|
||||||
|
#include "Register.h"
|
||||||
|
#include "StackFrame.h"
|
||||||
|
#include "StackTrace.h"
|
||||||
|
#include "StringUtils.h"
|
||||||
|
#include "Team.h"
|
||||||
|
#include "Thread.h"
|
||||||
|
#include "UiUtils.h"
|
||||||
|
|
||||||
|
|
||||||
|
DebugReportGenerator::DebugReportGenerator(::Team* team,
|
||||||
|
Architecture* architecture)
|
||||||
|
:
|
||||||
|
BReferenceable(),
|
||||||
|
fTeam(team),
|
||||||
|
fArchitecture(architecture)
|
||||||
|
{
|
||||||
|
fArchitecture->AcquireReference();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DebugReportGenerator::~DebugReportGenerator()
|
||||||
|
{
|
||||||
|
fArchitecture->ReleaseReference();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
DebugReportGenerator::Init()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DebugReportGenerator*
|
||||||
|
DebugReportGenerator::Create(::Team* team, Architecture* architecture)
|
||||||
|
{
|
||||||
|
DebugReportGenerator* self = new DebugReportGenerator(team, architecture);
|
||||||
|
|
||||||
|
try {
|
||||||
|
self->_Init();
|
||||||
|
} catch (...) {
|
||||||
|
delete self;
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
DebugReportGenerator::GenerateReport(const entry_ref& outputPath)
|
||||||
|
{
|
||||||
|
BFile file(&outputPath, B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE);
|
||||||
|
status_t result = file.InitCheck();
|
||||||
|
if (result != B_OK)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
BString output;
|
||||||
|
result = _GenerateReportHeader(output);
|
||||||
|
if (result != B_OK);
|
||||||
|
return result;
|
||||||
|
|
||||||
|
result = _DumpLoadedImages(output);
|
||||||
|
if (result != B_OK)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
result = _DumpRunningThreads(output);
|
||||||
|
if (result != B_OK)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
result = file.Write(output.String(), output.Length());
|
||||||
|
if (result < 0)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
DebugReportGenerator::_Init()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
DebugReportGenerator::_GenerateReportHeader(BString& _output)
|
||||||
|
{
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
DebugReportGenerator::_DumpLoadedImages(BString& _output)
|
||||||
|
{
|
||||||
|
AutoLocker<Team> locker(fTeam);
|
||||||
|
|
||||||
|
BString data;
|
||||||
|
for (ImageList::ConstIterator it = fTeam->Images().GetIterator();
|
||||||
|
Image* image = it.Next();) {
|
||||||
|
const ImageInfo& info = image->Info();
|
||||||
|
try {
|
||||||
|
data.SetToFormat("\t%s, id: %" B_PRId32", type: %" B_PRId32 ", "
|
||||||
|
"Text: 0x%" B_PRIx64 ", %" B_PRIu64 " bytes, Data: 0x%"
|
||||||
|
B_PRIx64 ", %" B_PRIu64 " bytes\n", info.Name().String(),
|
||||||
|
info.ImageID(), info.Type(), info.TextBase(), info.TextSize(),
|
||||||
|
info.DataBase(), info.DataSize());
|
||||||
|
|
||||||
|
_output << data;
|
||||||
|
} catch (...) {
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
DebugReportGenerator::_DumpRunningThreads(BString& _output)
|
||||||
|
{
|
||||||
|
AutoLocker<Team> locker(fTeam);
|
||||||
|
|
||||||
|
BString data;
|
||||||
|
status_t result = B_OK;
|
||||||
|
for (ThreadList::ConstIterator it = fTeam->Threads().GetIterator();
|
||||||
|
Thread* thread = it.Next();) {
|
||||||
|
try {
|
||||||
|
data.SetToFormat("\t%s %s, id: %" B_PRId32", state: %" B_PRId32
|
||||||
|
"\n", thread->Name(), thread->IsMainThread()
|
||||||
|
? "(main)" : "", UiUtils::ThreadStateToString(
|
||||||
|
thread->State(), thread->StoppedReason()));
|
||||||
|
|
||||||
|
_output << data;
|
||||||
|
|
||||||
|
if (thread->State() == THREAD_STATE_STOPPED)
|
||||||
|
result = _DumpDebuggedThreadInfo(_output, thread);
|
||||||
|
if (result != B_OK)
|
||||||
|
return result;
|
||||||
|
} catch (...) {
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
DebugReportGenerator::_DumpDebuggedThreadInfo(BString& _output, Thread* thread)
|
||||||
|
{
|
||||||
|
AutoLocker<Team> locker(fTeam);
|
||||||
|
|
||||||
|
StackTrace* trace = thread->GetStackTrace();
|
||||||
|
if (trace == NULL)
|
||||||
|
return B_OK;
|
||||||
|
|
||||||
|
BString data;
|
||||||
|
for (int32 i = 0; StackFrame* frame = trace->FrameAt(i); i++) {
|
||||||
|
char functionName[512];
|
||||||
|
data.SetToFormat("0x%" B_PRIx64 "\t0x%" B_PRIx64 "\t%s\n",
|
||||||
|
frame->FrameAddress(), frame->InstructionPointer(),
|
||||||
|
UiUtils::FunctionNameForFrame(frame, functionName,
|
||||||
|
sizeof(functionName)));
|
||||||
|
|
||||||
|
_output << data;
|
||||||
|
}
|
||||||
|
|
||||||
|
_output << "\nRegisters:\n\n";
|
||||||
|
|
||||||
|
CpuState* state = thread->GetCpuState();
|
||||||
|
BVariant value;
|
||||||
|
for (int32 i = 0; i < fArchitecture->CountRegisters(); i++) {
|
||||||
|
const Register* reg = fArchitecture->Registers() + i;
|
||||||
|
state->GetRegisterValue(reg, value);
|
||||||
|
|
||||||
|
char buffer[64];
|
||||||
|
data.SetToFormat("%s\t%0x%s\n", reg->Name(),
|
||||||
|
UiUtils::VariantToString(value, buffer, sizeof(buffer)));
|
||||||
|
_output << data;
|
||||||
|
}
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2012, Rene Gollent, [email protected].
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
#ifndef DEBUG_REPORT_GENERATOR_H
|
||||||
|
#define DEBUG_GENERATOR_H
|
||||||
|
|
||||||
|
#include <Referenceable.h>
|
||||||
|
|
||||||
|
|
||||||
|
class entry_ref;
|
||||||
|
class Architecture;
|
||||||
|
class BString;
|
||||||
|
class Team;
|
||||||
|
class Thread;
|
||||||
|
|
||||||
|
|
||||||
|
class DebugReportGenerator : public BReferenceable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DebugReportGenerator(::Team* team,
|
||||||
|
Architecture* architecture);
|
||||||
|
~DebugReportGenerator();
|
||||||
|
|
||||||
|
void Init();
|
||||||
|
|
||||||
|
static DebugReportGenerator* Create(::Team* team,
|
||||||
|
Architecture* architecture);
|
||||||
|
|
||||||
|
status_t GenerateReport(const entry_ref& outputPath);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void _Init();
|
||||||
|
|
||||||
|
status_t _GenerateReportHeader(BString& output);
|
||||||
|
status_t _DumpLoadedImages(BString& output);
|
||||||
|
status_t _DumpRunningThreads(BString& output);
|
||||||
|
status_t _DumpDebuggedThreadInfo(BString& output,
|
||||||
|
Thread* thread);
|
||||||
|
|
||||||
|
private:
|
||||||
|
::Team* fTeam;
|
||||||
|
Architecture* fArchitecture;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // DEBUG_REPORT_GENERATOR_H
|
||||||
Reference in New Issue
Block a user