* Added classes to represent source code (SourceCode, Statement).
* Added x86 disassembler (via libudis86). * Added Architecture::DisassembleCode() to disassemble a function to SourceCode. * Added virtual DebugInfo::LoadSourceCode() to retrieve the source code for a given function. The implementation in DebuggerDebugInfo disassembles the function. * Added source code info to StackFrame. Also added a listener mechanism to get notified on source code changes. * Added job to load the source code for a stack frame. * Added (very basic) source code view and wired everything so that when a stack frame is selected the source code (respectively disassembly) for the underlying function is retrieved and shown. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@31158 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -51,6 +51,7 @@ Application Debugger :
|
|||||||
# gui/team_window
|
# gui/team_window
|
||||||
ImageListView.cpp
|
ImageListView.cpp
|
||||||
RegisterView.cpp
|
RegisterView.cpp
|
||||||
|
SourceView.cpp
|
||||||
StackTraceView.cpp
|
StackTraceView.cpp
|
||||||
TeamWindow.cpp
|
TeamWindow.cpp
|
||||||
ThreadListView.cpp
|
ThreadListView.cpp
|
||||||
@@ -58,8 +59,10 @@ Application Debugger :
|
|||||||
# model
|
# model
|
||||||
Image.cpp
|
Image.cpp
|
||||||
ImageInfo.cpp
|
ImageInfo.cpp
|
||||||
|
SourceCode.cpp
|
||||||
StackFrame.cpp
|
StackFrame.cpp
|
||||||
StackTrace.cpp
|
StackTrace.cpp
|
||||||
|
Statement.cpp
|
||||||
SymbolInfo.cpp
|
SymbolInfo.cpp
|
||||||
Team.cpp
|
Team.cpp
|
||||||
TeamDebugModel.cpp
|
TeamDebugModel.cpp
|
||||||
@@ -77,8 +80,10 @@ Application Debugger :
|
|||||||
|
|
||||||
:
|
:
|
||||||
<nogrist>Debugger_demangler.o
|
<nogrist>Debugger_demangler.o
|
||||||
|
<nogrist>Debugger_disasm_x86.o
|
||||||
<nogrist>DebugAnalyzer_gui_table.o
|
<nogrist>DebugAnalyzer_gui_table.o
|
||||||
|
|
||||||
|
libudis86.a
|
||||||
<bin>debug_utils.a
|
<bin>debug_utils.a
|
||||||
libcolumnlistview.a
|
libcolumnlistview.a
|
||||||
libshared.a
|
libshared.a
|
||||||
@@ -89,5 +94,6 @@ Application Debugger :
|
|||||||
: Debugger.rdef
|
: Debugger.rdef
|
||||||
;
|
;
|
||||||
|
|
||||||
|
HaikuSubInclude arch x86 disasm ;
|
||||||
HaikuSubInclude demangler ;
|
HaikuSubInclude demangler ;
|
||||||
HaikuSubInclude gui running_teams_window ;
|
HaikuSubInclude gui running_teams_window ;
|
||||||
|
|||||||
@@ -12,8 +12,11 @@
|
|||||||
#include "Architecture.h"
|
#include "Architecture.h"
|
||||||
#include "CpuState.h"
|
#include "CpuState.h"
|
||||||
#include "DebuggerInterface.h"
|
#include "DebuggerInterface.h"
|
||||||
|
#include "DebugInfo.h"
|
||||||
|
#include "FunctionDebugInfo.h"
|
||||||
#include "Image.h"
|
#include "Image.h"
|
||||||
#include "ImageDebugInfo.h"
|
#include "ImageDebugInfo.h"
|
||||||
|
#include "SourceCode.h"
|
||||||
#include "StackTrace.h"
|
#include "StackTrace.h"
|
||||||
#include "Team.h"
|
#include "Team.h"
|
||||||
#include "Thread.h"
|
#include "Thread.h"
|
||||||
@@ -170,7 +173,7 @@ GetStackTraceJob::GetImageDebugInfo(Image* image, ImageDebugInfo*& _info)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark - GetStackTraceJob
|
// #pragma mark - LoadImageDebugInfoJob
|
||||||
|
|
||||||
|
|
||||||
LoadImageDebugInfoJob::LoadImageDebugInfoJob(
|
LoadImageDebugInfoJob::LoadImageDebugInfoJob(
|
||||||
@@ -224,3 +227,54 @@ LoadImageDebugInfoJob::Do()
|
|||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - LoadSourceCodeJob
|
||||||
|
|
||||||
|
|
||||||
|
LoadSourceCodeJob::LoadSourceCodeJob(
|
||||||
|
DebuggerInterface* debuggerInterface, Architecture* architecture,
|
||||||
|
Team* team, StackFrame* stackFrame)
|
||||||
|
:
|
||||||
|
fDebuggerInterface(debuggerInterface),
|
||||||
|
fArchitecture(architecture),
|
||||||
|
fTeam(team),
|
||||||
|
fStackFrame(stackFrame)
|
||||||
|
{
|
||||||
|
fStackFrame->AddReference();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
LoadSourceCodeJob::~LoadSourceCodeJob()
|
||||||
|
{
|
||||||
|
fStackFrame->RemoveReference();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
JobKey
|
||||||
|
LoadSourceCodeJob::Key() const
|
||||||
|
{
|
||||||
|
return JobKey(fStackFrame, JOB_TYPE_LOAD_SOURCE_CODE);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
LoadSourceCodeJob::Do()
|
||||||
|
{
|
||||||
|
// load the source code, if we can
|
||||||
|
SourceCode* sourceCode = NULL;
|
||||||
|
status_t error = B_BAD_VALUE;
|
||||||
|
FunctionDebugInfo* function = fStackFrame->Function();
|
||||||
|
if (function != NULL)
|
||||||
|
error = function->GetDebugInfo()->LoadSourceCode(function, sourceCode);
|
||||||
|
|
||||||
|
// set the result
|
||||||
|
AutoLocker<Team> locker(fTeam);
|
||||||
|
if (error == B_OK) {
|
||||||
|
fStackFrame->SetSourceCode(sourceCode, STACK_SOURCE_LOADED);
|
||||||
|
sourceCode->RemoveReference();
|
||||||
|
} else
|
||||||
|
fStackFrame->SetSourceCode(NULL, STACK_SOURCE_UNAVAILABLE);
|
||||||
|
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ class Architecture;
|
|||||||
class CpuState;
|
class CpuState;
|
||||||
class DebuggerInterface;
|
class DebuggerInterface;
|
||||||
class Image;
|
class Image;
|
||||||
|
class StackFrame;
|
||||||
|
class Team;
|
||||||
class Thread;
|
class Thread;
|
||||||
|
|
||||||
|
|
||||||
@@ -20,7 +22,8 @@ class Thread;
|
|||||||
enum {
|
enum {
|
||||||
JOB_TYPE_GET_CPU_STATE,
|
JOB_TYPE_GET_CPU_STATE,
|
||||||
JOB_TYPE_GET_STACK_TRACE,
|
JOB_TYPE_GET_STACK_TRACE,
|
||||||
JOB_TYPE_LOAD_IMAGE_DEBUG_INFO
|
JOB_TYPE_LOAD_IMAGE_DEBUG_INFO,
|
||||||
|
JOB_TYPE_LOAD_SOURCE_CODE
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -81,4 +84,23 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class LoadSourceCodeJob : public Job {
|
||||||
|
public:
|
||||||
|
LoadSourceCodeJob(
|
||||||
|
DebuggerInterface* debuggerInterface,
|
||||||
|
Architecture* architecture,
|
||||||
|
Team* team, StackFrame* stackFrame);
|
||||||
|
virtual ~LoadSourceCodeJob();
|
||||||
|
|
||||||
|
virtual JobKey Key() const;
|
||||||
|
virtual status_t Do();
|
||||||
|
|
||||||
|
private:
|
||||||
|
DebuggerInterface* fDebuggerInterface;
|
||||||
|
Architecture* fArchitecture;
|
||||||
|
Team* fTeam;
|
||||||
|
StackFrame* fStackFrame;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
#endif // JOBS_H
|
#endif // JOBS_H
|
||||||
|
|||||||
@@ -7,15 +7,16 @@
|
|||||||
|
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
MSG_THREAD_RUN = 'run_',
|
MSG_THREAD_RUN = 'run_',
|
||||||
MSG_THREAD_STOP = 'stop',
|
MSG_THREAD_STOP = 'stop',
|
||||||
MSG_THREAD_STEP_OVER = 'stov',
|
MSG_THREAD_STEP_OVER = 'stov',
|
||||||
MSG_THREAD_STEP_INTO = 'stin',
|
MSG_THREAD_STEP_INTO = 'stin',
|
||||||
MSG_THREAD_STEP_OUT = 'stou',
|
MSG_THREAD_STEP_OUT = 'stou',
|
||||||
|
|
||||||
MSG_THREAD_STATE_CHANGED = 'tsch',
|
MSG_THREAD_STATE_CHANGED = 'tsch',
|
||||||
MSG_THREAD_CPU_STATE_CHANGED = 'tcsc',
|
MSG_THREAD_CPU_STATE_CHANGED = 'tcsc',
|
||||||
MSG_THREAD_STACK_TRACE_CHANGED = 'tstc'
|
MSG_THREAD_STACK_TRACE_CHANGED = 'tstc',
|
||||||
|
MSG_STACK_FRAME_SOURCE_CODE_CHANGED = 'sfsc'
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -233,6 +233,30 @@ TeamDebugger::MessageReceived(BMessage* message)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TeamDebugger::StackFrameSourceCodeRequested(TeamWindow* window,
|
||||||
|
StackFrame* frame)
|
||||||
|
{
|
||||||
|
// mark loading
|
||||||
|
AutoLocker< ::Team> locker(fTeam);
|
||||||
|
if (frame->SourceCodeState() != STACK_SOURCE_NOT_LOADED)
|
||||||
|
return;
|
||||||
|
frame->SetSourceCode(NULL, STACK_SOURCE_LOADING);
|
||||||
|
locker.Unlock();
|
||||||
|
|
||||||
|
// schedule the job
|
||||||
|
if (fWorker->ScheduleJob(
|
||||||
|
new(std::nothrow) LoadSourceCodeJob(fDebuggerInterface,
|
||||||
|
fDebuggerInterface->GetArchitecture(), fTeam, frame),
|
||||||
|
this) != B_OK) {
|
||||||
|
// scheduling failed -- mark unavailable
|
||||||
|
locker.Lock();
|
||||||
|
frame->SetSourceCode(NULL, STACK_SOURCE_UNAVAILABLE);
|
||||||
|
locker.Unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
TeamDebugger::ThreadActionRequested(TeamWindow* window, thread_id threadID,
|
TeamDebugger::ThreadActionRequested(TeamWindow* window, thread_id threadID,
|
||||||
uint32 action)
|
uint32 action)
|
||||||
@@ -269,6 +293,8 @@ void
|
|||||||
TeamDebugger::JobAborted(Job* job)
|
TeamDebugger::JobAborted(Job* job)
|
||||||
{
|
{
|
||||||
printf("TeamDebugger::JobAborted(%p)\n", job);
|
printf("TeamDebugger::JobAborted(%p)\n", job);
|
||||||
|
// TODO: For a stack frame source loader thread we should reset the
|
||||||
|
// loading state! Asynchronously due to locking order.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -35,6 +35,8 @@ private:
|
|||||||
virtual void MessageReceived(BMessage* message);
|
virtual void MessageReceived(BMessage* message);
|
||||||
|
|
||||||
// TeamWindow::Listener
|
// TeamWindow::Listener
|
||||||
|
virtual void StackFrameSourceCodeRequested(
|
||||||
|
TeamWindow* window, StackFrame* frame);
|
||||||
virtual void ThreadActionRequested(TeamWindow* window,
|
virtual void ThreadActionRequested(TeamWindow* window,
|
||||||
thread_id threadID, uint32 action);
|
thread_id threadID, uint32 action);
|
||||||
virtual bool TeamWindowQuitRequested(TeamWindow* window);
|
virtual bool TeamWindowQuitRequested(TeamWindow* window);
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ class FunctionDebugInfo;
|
|||||||
class Image;
|
class Image;
|
||||||
class ImageDebugInfoProvider;
|
class ImageDebugInfoProvider;
|
||||||
class Register;
|
class Register;
|
||||||
|
class SourceCode;
|
||||||
class StackFrame;
|
class StackFrame;
|
||||||
class StackTrace;
|
class StackTrace;
|
||||||
class Team;
|
class Team;
|
||||||
@@ -42,6 +43,9 @@ public:
|
|||||||
// returns reference to previous frame
|
// returns reference to previous frame
|
||||||
// and CPU state; returned CPU state
|
// and CPU state; returned CPU state
|
||||||
// can be NULL
|
// can be NULL
|
||||||
|
virtual status_t DisassembleCode(FunctionDebugInfo* function,
|
||||||
|
const void* buffer, size_t bufferSize,
|
||||||
|
SourceCode*& _sourceCode) = 0;
|
||||||
|
|
||||||
status_t CreateStackTrace(Team* team,
|
status_t CreateStackTrace(Team* team,
|
||||||
ImageDebugInfoProvider* imageInfoProvider,
|
ImageDebugInfoProvider* imageInfoProvider,
|
||||||
|
|||||||
@@ -0,0 +1,87 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2009, Ingo Weinhold, [email protected].
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
#ifndef TARGET_ADDRESS_RANGE_H
|
||||||
|
#define TARGET_ADDRESS_RANGE_H
|
||||||
|
|
||||||
|
#include "ArchitectureTypes.h"
|
||||||
|
|
||||||
|
|
||||||
|
class TargetAddressRange {
|
||||||
|
public:
|
||||||
|
TargetAddressRange()
|
||||||
|
:
|
||||||
|
fStart(0),
|
||||||
|
fSize(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
TargetAddressRange(target_addr_t start, target_size_t size)
|
||||||
|
:
|
||||||
|
fStart(start),
|
||||||
|
fSize(size)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
TargetAddressRange(const TargetAddressRange& other)
|
||||||
|
:
|
||||||
|
fStart(other.fStart),
|
||||||
|
fSize(other.fSize)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
TargetAddressRange& operator=(const TargetAddressRange& other)
|
||||||
|
{
|
||||||
|
fStart = other.fStart;
|
||||||
|
fSize = other.fSize;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const TargetAddressRange& other) const
|
||||||
|
{
|
||||||
|
return fStart == other.fStart && fSize == other.fSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!=(const TargetAddressRange& other) const
|
||||||
|
{
|
||||||
|
return !(*this == other);
|
||||||
|
}
|
||||||
|
|
||||||
|
target_addr_t Start() const
|
||||||
|
{
|
||||||
|
return fStart;
|
||||||
|
}
|
||||||
|
|
||||||
|
target_size_t Size() const
|
||||||
|
{
|
||||||
|
return fSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
target_addr_t End() const
|
||||||
|
{
|
||||||
|
return fStart + fSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Contains(target_addr_t address) const
|
||||||
|
{
|
||||||
|
return address >= Start() && address < End();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Contains(const TargetAddressRange& other) const
|
||||||
|
{
|
||||||
|
return Start() <= other.Start() && End() >= other.End();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IntersectsWith(const TargetAddressRange& other) const
|
||||||
|
{
|
||||||
|
return Contains(other.Start()) || other.Contains(Start());
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
target_addr_t fStart;
|
||||||
|
target_size_t fSize;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // TARGET_ADDRESS_RANGE_H
|
||||||
@@ -7,11 +7,18 @@
|
|||||||
|
|
||||||
#include <new>
|
#include <new>
|
||||||
|
|
||||||
|
#include <String.h>
|
||||||
|
|
||||||
#include <AutoDeleter.h>
|
#include <AutoDeleter.h>
|
||||||
|
|
||||||
#include "CpuStateX86.h"
|
#include "CpuStateX86.h"
|
||||||
#include "DebuggerInterface.h"
|
#include "DebuggerInterface.h"
|
||||||
|
#include "FunctionDebugInfo.h"
|
||||||
|
#include "SourceCode.h"
|
||||||
#include "StackFrame.h"
|
#include "StackFrame.h"
|
||||||
|
#include "Statement.h"
|
||||||
|
|
||||||
|
#include "disasm/DisassemblerX86.h"
|
||||||
|
|
||||||
|
|
||||||
ArchitectureX86::ArchitectureX86(DebuggerInterface* debuggerInterface)
|
ArchitectureX86::ArchitectureX86(DebuggerInterface* debuggerInterface)
|
||||||
@@ -139,6 +146,51 @@ ArchitectureX86::CreateStackFrame(Image* image, FunctionDebugInfo* function,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
ArchitectureX86::DisassembleCode(FunctionDebugInfo* function,
|
||||||
|
const void* buffer, size_t bufferSize, SourceCode*& _sourceCode)
|
||||||
|
{
|
||||||
|
SourceCode* source = new(std::nothrow) SourceCode;
|
||||||
|
if (source == NULL)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
Reference<SourceCode> sourceReference(source, true);
|
||||||
|
|
||||||
|
// init disassembler
|
||||||
|
DisassemblerX86 disassembler;
|
||||||
|
status_t error = disassembler.Init(function->Address(), buffer, bufferSize);
|
||||||
|
if (error != B_OK)
|
||||||
|
return error;
|
||||||
|
|
||||||
|
// add a function name line
|
||||||
|
BString functionName(function->PrettyName());
|
||||||
|
if (!source->AddLine((functionName << ':').String()))
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
uint32 lineIndex = 1;
|
||||||
|
|
||||||
|
// disassemble the instructions
|
||||||
|
BString line;
|
||||||
|
target_addr_t instructionAddress;
|
||||||
|
target_size_t instructionSize;
|
||||||
|
bool breakpointAllowed;
|
||||||
|
while (disassembler.GetNextInstruction(line, instructionAddress,
|
||||||
|
instructionSize, breakpointAllowed) == B_OK) {
|
||||||
|
Statement* statement = new(std::nothrow) ContiguousStatement(
|
||||||
|
SourceLocation(lineIndex), SourceLocation(lineIndex + 1),
|
||||||
|
TargetAddressRange(instructionAddress, instructionAddress));
|
||||||
|
if (statement == NULL)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
if (!source->AddStatement(statement) || !source->AddLine(line.String()))
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
lineIndex++;
|
||||||
|
}
|
||||||
|
|
||||||
|
_sourceCode = sourceReference.Detach();
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
ArchitectureX86::_AddRegister(int32 index, const char* name,
|
ArchitectureX86::_AddRegister(int32 index, const char* name,
|
||||||
register_format format, uint32 bitSize, register_type type)
|
register_format format, uint32 bitSize, register_type type)
|
||||||
|
|||||||
@@ -28,6 +28,9 @@ public:
|
|||||||
CpuState* cpuState,
|
CpuState* cpuState,
|
||||||
StackFrame*& _previousFrame,
|
StackFrame*& _previousFrame,
|
||||||
CpuState*& _previousCpuState);
|
CpuState*& _previousCpuState);
|
||||||
|
virtual status_t DisassembleCode(FunctionDebugInfo* function,
|
||||||
|
const void* buffer, size_t bufferSize,
|
||||||
|
SourceCode*& _sourceCode);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void _AddRegister(int32 index, const char* name,
|
void _AddRegister(int32 index, const char* name,
|
||||||
|
|||||||
@@ -0,0 +1,88 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2009, Ingo Weinhold, [email protected].
|
||||||
|
* Copyright 2008, François Revol, [email protected]
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "DisassemblerX86.h"
|
||||||
|
|
||||||
|
#include <new>
|
||||||
|
|
||||||
|
#include "udis86.h"
|
||||||
|
|
||||||
|
#include <OS.h>
|
||||||
|
|
||||||
|
|
||||||
|
struct DisassemblerX86::UdisData : ud_t {
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
DisassemblerX86::DisassemblerX86()
|
||||||
|
:
|
||||||
|
fAddress(0),
|
||||||
|
fCode(NULL),
|
||||||
|
fCodeSize(0),
|
||||||
|
fUdisData(NULL)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DisassemblerX86::~DisassemblerX86()
|
||||||
|
{
|
||||||
|
delete fUdisData;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
DisassemblerX86::Init(target_addr_t address, const void* code, size_t codeSize)
|
||||||
|
{
|
||||||
|
// unset old data
|
||||||
|
delete fUdisData;
|
||||||
|
fUdisData = NULL;
|
||||||
|
|
||||||
|
// set new data
|
||||||
|
fUdisData = new(std::nothrow) UdisData;
|
||||||
|
if (fUdisData == NULL)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
fAddress = address;
|
||||||
|
fCode = (const uint8*)code;
|
||||||
|
fCodeSize = codeSize;
|
||||||
|
|
||||||
|
// init udis
|
||||||
|
ud_init(fUdisData);
|
||||||
|
ud_set_input_buffer(fUdisData, (unsigned char*)fCode, fCodeSize);
|
||||||
|
ud_set_mode(fUdisData, 32);
|
||||||
|
ud_set_pc(fUdisData, (uint64_t)fAddress);
|
||||||
|
ud_set_syntax(fUdisData, UD_SYN_ATT);
|
||||||
|
ud_set_vendor(fUdisData, UD_VENDOR_INTEL);
|
||||||
|
// TODO: Set the correct vendor!
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
DisassemblerX86::GetNextInstruction(BString& line, target_addr_t& _address,
|
||||||
|
target_size_t& _size, bool& _breakpointAllowed)
|
||||||
|
{
|
||||||
|
unsigned int size = ud_disassemble(fUdisData);
|
||||||
|
if (size < 1)
|
||||||
|
return B_ENTRY_NOT_FOUND;
|
||||||
|
|
||||||
|
uint32 address = (uint32)ud_insn_off(fUdisData);
|
||||||
|
|
||||||
|
char buffer[256];
|
||||||
|
snprintf(buffer, sizeof(buffer), "0x%08lx: %16.16s %s", address,
|
||||||
|
ud_insn_hex(fUdisData), ud_insn_asm(fUdisData));
|
||||||
|
// TODO: Resolve symbols!
|
||||||
|
|
||||||
|
line = buffer;
|
||||||
|
_address = address;
|
||||||
|
_size = size;
|
||||||
|
_breakpointAllowed = true;
|
||||||
|
// TODO: Implement (rep!)!
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2009, Ingo Weinhold, [email protected].
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
#ifndef DISASSEMBLER_X86_H
|
||||||
|
#define DISASSEMBLER_X86_H
|
||||||
|
|
||||||
|
#include <String.h>
|
||||||
|
|
||||||
|
#include "ArchitectureTypes.h"
|
||||||
|
|
||||||
|
|
||||||
|
class DisassemblerX86 {
|
||||||
|
public:
|
||||||
|
DisassemblerX86();
|
||||||
|
virtual ~DisassemblerX86();
|
||||||
|
|
||||||
|
virtual status_t Init(target_addr_t address, const void* code,
|
||||||
|
size_t codeSize);
|
||||||
|
|
||||||
|
virtual status_t GetNextInstruction(BString& line,
|
||||||
|
target_addr_t& _address,
|
||||||
|
target_size_t& _size,
|
||||||
|
bool& _breakpointAllowed);
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct UdisData;
|
||||||
|
|
||||||
|
private:
|
||||||
|
target_addr_t fAddress;
|
||||||
|
const uint8* fCode;
|
||||||
|
size_t fCodeSize;
|
||||||
|
UdisData* fUdisData;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // DISASSEMBLER_X86_H
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
SubDir HAIKU_TOP src apps debugger arch x86 disasm ;
|
||||||
|
|
||||||
|
CCFLAGS += -Werror ;
|
||||||
|
C++FLAGS += -Werror ;
|
||||||
|
|
||||||
|
UseHeaders [ LibraryHeaders udis86 ] ;
|
||||||
|
UseHeaders [ LibraryHeaders [ FDirName udis86 libudis86 ] ] ;
|
||||||
|
|
||||||
|
SubDirHdrs [ FDirName $(SUBDIR) $(DOTDOT) $(DOTDOT) ] ;
|
||||||
|
|
||||||
|
|
||||||
|
MergeObject Debugger_disasm_x86.o
|
||||||
|
:
|
||||||
|
DisassemblerX86.cpp
|
||||||
|
;
|
||||||
@@ -15,6 +15,7 @@ class CpuState;
|
|||||||
class DebuggerInterface;
|
class DebuggerInterface;
|
||||||
class FunctionDebugInfo;
|
class FunctionDebugInfo;
|
||||||
class Image;
|
class Image;
|
||||||
|
class SourceCode;
|
||||||
class StackFrame;
|
class StackFrame;
|
||||||
|
|
||||||
|
|
||||||
@@ -33,6 +34,9 @@ public:
|
|||||||
// returns reference to previous frame
|
// returns reference to previous frame
|
||||||
// and CPU state; returned CPU state
|
// and CPU state; returned CPU state
|
||||||
// can be NULL; can return B_UNSUPPORTED
|
// can be NULL; can return B_UNSUPPORTED
|
||||||
|
virtual status_t LoadSourceCode(FunctionDebugInfo* function,
|
||||||
|
SourceCode*& _sourceCode) = 0;
|
||||||
|
// returns reference
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -5,8 +5,12 @@
|
|||||||
|
|
||||||
#include "DebuggerDebugInfo.h"
|
#include "DebuggerDebugInfo.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <new>
|
#include <new>
|
||||||
|
|
||||||
|
#include <AutoDeleter.h>
|
||||||
|
|
||||||
|
#include "Architecture.h"
|
||||||
#include "BasicFunctionDebugInfo.h"
|
#include "BasicFunctionDebugInfo.h"
|
||||||
#include "DebuggerInterface.h"
|
#include "DebuggerInterface.h"
|
||||||
#include "Demangler.h"
|
#include "Demangler.h"
|
||||||
@@ -87,6 +91,29 @@ DebuggerDebugInfo::CreateFrame(Image* image, FunctionDebugInfo* function,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
DebuggerDebugInfo::LoadSourceCode(FunctionDebugInfo* function,
|
||||||
|
SourceCode*& _sourceCode)
|
||||||
|
{
|
||||||
|
// allocate a buffer for the function code
|
||||||
|
static const target_size_t kMaxBufferSize = 64 * 1024;
|
||||||
|
target_size_t bufferSize = std::min(function->Size(), kMaxBufferSize);
|
||||||
|
void* buffer = malloc(bufferSize);
|
||||||
|
if (buffer == NULL)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
MemoryDeleter bufferDeleter(buffer);
|
||||||
|
|
||||||
|
// read the function code
|
||||||
|
ssize_t bytesRead = fDebuggerInterface->ReadMemory(function->Address(),
|
||||||
|
buffer, bufferSize);
|
||||||
|
if (bytesRead < 0)
|
||||||
|
return bytesRead;
|
||||||
|
|
||||||
|
return fArchitecture->DisassembleCode(function, buffer, bytesRead,
|
||||||
|
_sourceCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
SymbolInfo*
|
SymbolInfo*
|
||||||
DebuggerDebugInfo::_FindSymbol(target_addr_t address)
|
DebuggerDebugInfo::_FindSymbol(target_addr_t address)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -34,6 +34,8 @@ public:
|
|||||||
CpuState* cpuState,
|
CpuState* cpuState,
|
||||||
StackFrame*& _previousFrame,
|
StackFrame*& _previousFrame,
|
||||||
CpuState*& _previousCpuState);
|
CpuState*& _previousCpuState);
|
||||||
|
virtual status_t LoadSourceCode(FunctionDebugInfo* function,
|
||||||
|
SourceCode*& _sourceCode);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
typedef BObjectList<SymbolInfo> SymbolList;
|
typedef BObjectList<SymbolInfo> SymbolList;
|
||||||
|
|||||||
@@ -0,0 +1,368 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2009, Ingo Weinhold, [email protected].
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "SourceView.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <new>
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include <LayoutUtils.h>
|
||||||
|
#include <ScrollBar.h>
|
||||||
|
|
||||||
|
#include <AutoLocker.h>
|
||||||
|
|
||||||
|
#include "SourceCode.h"
|
||||||
|
#include "StackFrame.h"
|
||||||
|
#include "TeamDebugModel.h"
|
||||||
|
|
||||||
|
|
||||||
|
static const int32 kLeftTextMargin = 3;
|
||||||
|
|
||||||
|
|
||||||
|
class SourceView::MarkerView : public BView {
|
||||||
|
public:
|
||||||
|
MarkerView(SourceView* sourceView, FontInfo* fontInfo)
|
||||||
|
:
|
||||||
|
BView("source marker view", B_WILL_DRAW),
|
||||||
|
fSourceView(sourceView),
|
||||||
|
fFontInfo(fontInfo)
|
||||||
|
{
|
||||||
|
SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual BSize MinSize()
|
||||||
|
{
|
||||||
|
return BSize(40, 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual BSize MaxSize()
|
||||||
|
{
|
||||||
|
return BSize(MinSize().width, B_SIZE_UNLIMITED);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual BSize PreferredSize()
|
||||||
|
{
|
||||||
|
return MinSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void Draw(BRect updateRect)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
SourceView* fSourceView;
|
||||||
|
FontInfo* fFontInfo;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class SourceView::TextView : public BView {
|
||||||
|
public:
|
||||||
|
TextView(SourceView* sourceView, FontInfo* fontInfo)
|
||||||
|
:
|
||||||
|
BView("source text view", B_WILL_DRAW),
|
||||||
|
fSourceView(sourceView),
|
||||||
|
fFontInfo(fontInfo),
|
||||||
|
fSourceCode(NULL),
|
||||||
|
fMaxLineWidth(-1)
|
||||||
|
{
|
||||||
|
SetViewColor(ui_color(B_DOCUMENT_BACKGROUND_COLOR));
|
||||||
|
fTextColor = ui_color(B_DOCUMENT_TEXT_COLOR);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetSourceCode(SourceCode* sourceCode)
|
||||||
|
{
|
||||||
|
fSourceCode = sourceCode;
|
||||||
|
fMaxLineWidth = -1;
|
||||||
|
|
||||||
|
InvalidateLayout();
|
||||||
|
Invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual BSize MinSize()
|
||||||
|
{
|
||||||
|
float height = _LineCount() * fFontInfo->lineHeight;
|
||||||
|
return BSize(kLeftTextMargin + _MaxLineWidth() - 1,
|
||||||
|
std::max(height - 1, 100.0f));
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual BSize MaxSize()
|
||||||
|
{
|
||||||
|
return BSize(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual BSize PreferredSize()
|
||||||
|
{
|
||||||
|
return MinSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void Draw(BRect updateRect)
|
||||||
|
{
|
||||||
|
if (fSourceCode == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// get the lines intersecting with the update rect
|
||||||
|
int32 lineHeight = (int32)fFontInfo->lineHeight;
|
||||||
|
int32 minLine = (int32)updateRect.top / lineHeight;
|
||||||
|
int32 maxLine = ((int32)ceilf(updateRect.bottom) + lineHeight - 1)
|
||||||
|
/ lineHeight;
|
||||||
|
minLine = std::max(minLine, 0L);
|
||||||
|
maxLine = std::min(maxLine, fSourceCode->CountLines() - 1);
|
||||||
|
|
||||||
|
// draw the affected lines
|
||||||
|
SetHighColor(fTextColor);
|
||||||
|
SetFont(&fFontInfo->font);
|
||||||
|
for (int32 i = minLine; i <= maxLine; i++) {
|
||||||
|
float y = (float)(i + 1) * fFontInfo->lineHeight
|
||||||
|
- fFontInfo->fontHeight.descent;
|
||||||
|
DrawString(fSourceCode->LineAt(i), BPoint(kLeftTextMargin, y));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
int32 _LineCount() const
|
||||||
|
{
|
||||||
|
return fSourceCode != NULL ? fSourceCode->CountLines() : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
float _MaxLineWidth()
|
||||||
|
{
|
||||||
|
if (fMaxLineWidth >= 0)
|
||||||
|
return fMaxLineWidth;
|
||||||
|
|
||||||
|
fMaxLineWidth = 0;
|
||||||
|
if (fSourceCode != NULL) {
|
||||||
|
for (int32 i = 0; const char* line = fSourceCode->LineAt(i); i++) {
|
||||||
|
fMaxLineWidth = std::max(fMaxLineWidth,
|
||||||
|
fFontInfo->font.StringWidth(line));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return fMaxLineWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
SourceView* fSourceView;
|
||||||
|
FontInfo* fFontInfo;
|
||||||
|
SourceCode* fSourceCode;
|
||||||
|
float fMaxLineWidth;
|
||||||
|
rgb_color fTextColor;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - SourceView
|
||||||
|
|
||||||
|
|
||||||
|
SourceView::SourceView(TeamDebugModel* debugModel, Listener* listener)
|
||||||
|
:
|
||||||
|
BView("source view", 0),
|
||||||
|
fDebugModel(debugModel),
|
||||||
|
fStackFrame(NULL),
|
||||||
|
fSourceCode(NULL),
|
||||||
|
fMarkerView(NULL),
|
||||||
|
fTextView(NULL),
|
||||||
|
fListener(listener)
|
||||||
|
{
|
||||||
|
// init font info
|
||||||
|
fFontInfo.font = *be_fixed_font;
|
||||||
|
fFontInfo.font.GetHeight(&fFontInfo.fontHeight);
|
||||||
|
fFontInfo.lineHeight = ceilf(fFontInfo.fontHeight.ascent)
|
||||||
|
+ ceilf(fFontInfo.fontHeight.descent);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SourceView::~SourceView()
|
||||||
|
{
|
||||||
|
SetStackFrame(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*static*/ SourceView*
|
||||||
|
SourceView::Create(TeamDebugModel* debugModel, Listener* listener)
|
||||||
|
{
|
||||||
|
SourceView* self = new SourceView(debugModel, listener);
|
||||||
|
|
||||||
|
try {
|
||||||
|
self->_Init();
|
||||||
|
} catch (...) {
|
||||||
|
delete self;
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
SourceView::UnsetListener()
|
||||||
|
{
|
||||||
|
fListener = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
SourceView::SetStackFrame(StackFrame* frame)
|
||||||
|
{
|
||||||
|
printf("SourceView::SetStackFrame(%p)\n", frame);
|
||||||
|
if (frame == fStackFrame)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (fStackFrame != NULL)
|
||||||
|
fStackFrame->RemoveReference();
|
||||||
|
|
||||||
|
fStackFrame = frame;
|
||||||
|
|
||||||
|
if (fStackFrame != NULL)
|
||||||
|
fStackFrame->AddReference();
|
||||||
|
|
||||||
|
UpdateSourceCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
SourceView::UpdateSourceCode()
|
||||||
|
{
|
||||||
|
// get a reference to the source code
|
||||||
|
AutoLocker<TeamDebugModel> locker(fDebugModel);
|
||||||
|
|
||||||
|
SourceCode* sourceCode = fStackFrame != NULL
|
||||||
|
? fStackFrame->GetSourceCode() : NULL;
|
||||||
|
Reference<SourceCode> sourceCodeReference(sourceCode);
|
||||||
|
|
||||||
|
locker.Unlock();
|
||||||
|
|
||||||
|
// set the source code, if it changed
|
||||||
|
if (sourceCode == fSourceCode)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (fSourceCode != NULL) {
|
||||||
|
fTextView->SetSourceCode(NULL);
|
||||||
|
fSourceCode->RemoveReference();
|
||||||
|
}
|
||||||
|
|
||||||
|
fSourceCode = sourceCodeReference.Detach();
|
||||||
|
|
||||||
|
fTextView->SetSourceCode(fSourceCode);
|
||||||
|
_UpdateScrollBars();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
SourceView::TargetedByScrollView(BScrollView* scrollView)
|
||||||
|
{
|
||||||
|
_UpdateScrollBars();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BSize
|
||||||
|
SourceView::MinSize()
|
||||||
|
{
|
||||||
|
// BSize markerSize(fMarkerView->MinSize());
|
||||||
|
// BSize textSize(fTextView->MinSize());
|
||||||
|
// return BSize(BLayoutUtils::AddDistances(markerSize.width, textSize.width),
|
||||||
|
// std::max(markerSize.height, textSize.height));
|
||||||
|
return BSize(10, 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BSize
|
||||||
|
SourceView::MaxSize()
|
||||||
|
{
|
||||||
|
// BSize markerSize(fMarkerView->MaxSize());
|
||||||
|
// BSize textSize(fTextView->MaxSize());
|
||||||
|
// return BSize(BLayoutUtils::AddDistances(markerSize.width, textSize.width),
|
||||||
|
// std::min(markerSize.height, textSize.height));
|
||||||
|
return BSize(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BSize
|
||||||
|
SourceView::PreferredSize()
|
||||||
|
{
|
||||||
|
BSize markerSize(fMarkerView->PreferredSize());
|
||||||
|
BSize textSize(fTextView->PreferredSize());
|
||||||
|
return BSize(BLayoutUtils::AddDistances(markerSize.width, textSize.width),
|
||||||
|
std::max(markerSize.height, textSize.height));
|
||||||
|
// return MinSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
SourceView::DoLayout()
|
||||||
|
{
|
||||||
|
BSize size = _DataRectSize();
|
||||||
|
float markerWidth = fMarkerView->MinSize().width;
|
||||||
|
|
||||||
|
fMarkerView->MoveTo(0, 0);
|
||||||
|
fMarkerView->ResizeTo(markerWidth, size.height);
|
||||||
|
|
||||||
|
fTextView->MoveTo(markerWidth + 1, 0);
|
||||||
|
fTextView->ResizeTo(size.width - markerWidth - 1, size.height);
|
||||||
|
|
||||||
|
_UpdateScrollBars();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
SourceView::_Init()
|
||||||
|
{
|
||||||
|
AddChild(fMarkerView = new MarkerView(this, &fFontInfo));
|
||||||
|
AddChild(fTextView = new TextView(this, &fFontInfo));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
SourceView::_UpdateScrollBars()
|
||||||
|
{
|
||||||
|
BSize dataRectSize = _DataRectSize();
|
||||||
|
BSize size = Frame().Size();
|
||||||
|
|
||||||
|
if (BScrollBar* scrollBar = ScrollBar(B_HORIZONTAL)) {
|
||||||
|
float range = dataRectSize.width - size.width;
|
||||||
|
if (range > 0) {
|
||||||
|
scrollBar->SetRange(0, range);
|
||||||
|
scrollBar->SetProportion(
|
||||||
|
(size.width + 1) / (dataRectSize.width + 1));
|
||||||
|
scrollBar->SetSteps(fFontInfo.lineHeight, size.width + 1);
|
||||||
|
} else {
|
||||||
|
scrollBar->SetRange(0, 0);
|
||||||
|
scrollBar->SetProportion(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (BScrollBar* scrollBar = ScrollBar(B_VERTICAL)) {
|
||||||
|
float range = dataRectSize.height - size.height;
|
||||||
|
if (range > 0) {
|
||||||
|
scrollBar->SetRange(0, range);
|
||||||
|
scrollBar->SetProportion(
|
||||||
|
(size.height + 1) / (dataRectSize.height + 1));
|
||||||
|
scrollBar->SetSteps(fFontInfo.lineHeight, size.height + 1);
|
||||||
|
} else {
|
||||||
|
scrollBar->SetRange(0, 0);
|
||||||
|
scrollBar->SetProportion(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BSize
|
||||||
|
SourceView::_DataRectSize() const
|
||||||
|
{
|
||||||
|
float width = fMarkerView->MinSize().width + fTextView->MinSize().width + 1;
|
||||||
|
float height = std::max(fMarkerView->MinSize().height,
|
||||||
|
fTextView->MinSize().height);
|
||||||
|
|
||||||
|
BSize size = Frame().Size();
|
||||||
|
return BSize(std::max(size.width, width), std::max(size.height, height));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - Listener
|
||||||
|
|
||||||
|
|
||||||
|
SourceView::Listener::~Listener()
|
||||||
|
{
|
||||||
|
}
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2009, Ingo Weinhold, [email protected].
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
#ifndef SOURCE_VIEW_H
|
||||||
|
#define SOURCE_VIEW_H
|
||||||
|
|
||||||
|
#include <Font.h>
|
||||||
|
#include <View.h>
|
||||||
|
|
||||||
|
|
||||||
|
class SourceCode;
|
||||||
|
class StackFrame;
|
||||||
|
class TeamDebugModel;
|
||||||
|
|
||||||
|
|
||||||
|
class SourceView : public BView {
|
||||||
|
public:
|
||||||
|
class Listener;
|
||||||
|
|
||||||
|
public:
|
||||||
|
SourceView(TeamDebugModel* debugModel,
|
||||||
|
Listener* listener);
|
||||||
|
~SourceView();
|
||||||
|
|
||||||
|
static SourceView* Create(TeamDebugModel* debugModel,
|
||||||
|
Listener* listener);
|
||||||
|
// throws
|
||||||
|
|
||||||
|
void UnsetListener();
|
||||||
|
|
||||||
|
void SetStackFrame(StackFrame* frame);
|
||||||
|
void UpdateSourceCode();
|
||||||
|
|
||||||
|
virtual void TargetedByScrollView(BScrollView* scrollView);
|
||||||
|
|
||||||
|
virtual BSize MinSize();
|
||||||
|
virtual BSize MaxSize();
|
||||||
|
virtual BSize PreferredSize();
|
||||||
|
|
||||||
|
virtual void DoLayout();
|
||||||
|
|
||||||
|
private:
|
||||||
|
class MarkerView;
|
||||||
|
class TextView;
|
||||||
|
|
||||||
|
struct FontInfo {
|
||||||
|
BFont font;
|
||||||
|
font_height fontHeight;
|
||||||
|
float lineHeight;
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
void _Init();
|
||||||
|
void _UpdateScrollBars();
|
||||||
|
BSize _DataRectSize() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
TeamDebugModel* fDebugModel;
|
||||||
|
StackFrame* fStackFrame;
|
||||||
|
SourceCode* fSourceCode;
|
||||||
|
MarkerView* fMarkerView;
|
||||||
|
TextView* fTextView;
|
||||||
|
FontInfo fFontInfo;
|
||||||
|
Listener* fListener;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class SourceView::Listener {
|
||||||
|
public:
|
||||||
|
virtual ~Listener();
|
||||||
|
|
||||||
|
// virtual void StackFrameSelectionChanged(
|
||||||
|
// StackFrame* frame) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // SOURCE_VIEW_H
|
||||||
@@ -11,6 +11,7 @@
|
|||||||
#include <LayoutBuilder.h>
|
#include <LayoutBuilder.h>
|
||||||
#include <Message.h>
|
#include <Message.h>
|
||||||
#include <TabView.h>
|
#include <TabView.h>
|
||||||
|
#include <ScrollView.h>
|
||||||
#include <SplitView.h>
|
#include <SplitView.h>
|
||||||
#include <TextView.h>
|
#include <TextView.h>
|
||||||
|
|
||||||
@@ -42,6 +43,7 @@ TeamWindow::TeamWindow(TeamDebugModel* debugModel, Listener* listener)
|
|||||||
fImageListView(NULL),
|
fImageListView(NULL),
|
||||||
fRegisterView(NULL),
|
fRegisterView(NULL),
|
||||||
fStackTraceView(NULL),
|
fStackTraceView(NULL),
|
||||||
|
fSourceView(NULL),
|
||||||
fRunButton(NULL),
|
fRunButton(NULL),
|
||||||
fStepOverButton(NULL),
|
fStepOverButton(NULL),
|
||||||
fStepIntoButton(NULL),
|
fStepIntoButton(NULL),
|
||||||
@@ -63,6 +65,8 @@ TeamWindow::~TeamWindow()
|
|||||||
fThreadListView->UnsetListener();
|
fThreadListView->UnsetListener();
|
||||||
if (fStackTraceView != NULL)
|
if (fStackTraceView != NULL)
|
||||||
fStackTraceView->UnsetListener();
|
fStackTraceView->UnsetListener();
|
||||||
|
if (fSourceView != NULL)
|
||||||
|
fSourceView->UnsetListener();
|
||||||
|
|
||||||
fDebugModel->GetTeam()->RemoveListener(this);
|
fDebugModel->GetTeam()->RemoveListener(this);
|
||||||
}
|
}
|
||||||
@@ -128,6 +132,11 @@ TeamWindow::MessageReceived(BMessage* message)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case MSG_STACK_FRAME_SOURCE_CODE_CHANGED:
|
||||||
|
{
|
||||||
|
_HandleSourceCodeChanged();
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
BWindow::MessageReceived(message);
|
BWindow::MessageReceived(message);
|
||||||
break;
|
break;
|
||||||
@@ -183,9 +192,20 @@ TeamWindow::ThreadStackTraceChanged(const Team::ThreadEvent& event)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TeamWindow::StackFrameSourceCodeChanged(StackFrame* frame)
|
||||||
|
{
|
||||||
|
printf("TeamWindow::StackFrameSourceCodeChanged(%p): source: %p, state: %d\n",
|
||||||
|
frame, frame->GetSourceCode(), frame->SourceCodeState());
|
||||||
|
PostMessage(MSG_STACK_FRAME_SOURCE_CODE_CHANGED);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
TeamWindow::_Init()
|
TeamWindow::_Init()
|
||||||
{
|
{
|
||||||
|
BScrollView* sourceScrollView;
|
||||||
|
|
||||||
BLayoutBuilder::Group<>(this, B_VERTICAL)
|
BLayoutBuilder::Group<>(this, B_VERTICAL)
|
||||||
.AddSplit(B_VERTICAL, 3.0f)
|
.AddSplit(B_VERTICAL, 3.0f)
|
||||||
.AddGroup(B_VERTICAL, 0.0f, 0.4f)
|
.AddGroup(B_VERTICAL, 0.0f, 0.4f)
|
||||||
@@ -202,7 +222,8 @@ TeamWindow::_Init()
|
|||||||
.SetInsets(4.0f, 0.0f, 4.0f, 0.0f)
|
.SetInsets(4.0f, 0.0f, 4.0f, 0.0f)
|
||||||
.End()
|
.End()
|
||||||
.AddSplit(B_HORIZONTAL, 3.0f)
|
.AddSplit(B_HORIZONTAL, 3.0f)
|
||||||
.Add(new BTextView("source view"), 3.0f)
|
.Add(sourceScrollView = new BScrollView("source scroll",
|
||||||
|
NULL, 0, true, true), 3.0f)
|
||||||
.AddGroup(B_VERTICAL)
|
.AddGroup(B_VERTICAL)
|
||||||
.Add(fLocalsTabView = new BTabView("locals view"))
|
.Add(fLocalsTabView = new BTabView("locals view"))
|
||||||
.SetInsets(0.0f, 0.0f, 4.0f, 4.0f)
|
.SetInsets(0.0f, 0.0f, 4.0f, 4.0f)
|
||||||
@@ -211,6 +232,10 @@ TeamWindow::_Init()
|
|||||||
.End()
|
.End()
|
||||||
.End();
|
.End();
|
||||||
|
|
||||||
|
// add source view
|
||||||
|
sourceScrollView->SetTarget(fSourceView = SourceView::Create(fDebugModel,
|
||||||
|
this));
|
||||||
|
|
||||||
// add threads tab
|
// add threads tab
|
||||||
BSplitView* threadGroup = new BSplitView(B_HORIZONTAL);
|
BSplitView* threadGroup = new BSplitView(B_HORIZONTAL);
|
||||||
threadGroup->SetName("Threads");
|
threadGroup->SetName("Threads");
|
||||||
@@ -281,15 +306,29 @@ TeamWindow::_SetActiveStackFrame(StackFrame* frame)
|
|||||||
if (frame == fActiveStackFrame)
|
if (frame == fActiveStackFrame)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (fActiveStackFrame != NULL)
|
AutoLocker<TeamDebugModel> locker(fDebugModel);
|
||||||
|
|
||||||
|
if (fActiveStackFrame != NULL) {
|
||||||
|
fActiveStackFrame->RemoveListener(this);
|
||||||
fActiveStackFrame->RemoveReference();
|
fActiveStackFrame->RemoveReference();
|
||||||
|
}
|
||||||
|
|
||||||
fActiveStackFrame = frame;
|
fActiveStackFrame = frame;
|
||||||
|
|
||||||
if (fActiveStackFrame != NULL)
|
if (fActiveStackFrame != NULL) {
|
||||||
fActiveStackFrame->AddReference();
|
fActiveStackFrame->AddReference();
|
||||||
|
fActiveStackFrame->AddListener(this);
|
||||||
|
|
||||||
|
// If the source code is not loaded yet, request it.
|
||||||
|
if (fActiveStackFrame->SourceCodeState() == STACK_SOURCE_NOT_LOADED)
|
||||||
|
fListener->StackFrameSourceCodeRequested(this, fActiveStackFrame);
|
||||||
|
}
|
||||||
|
|
||||||
_UpdateCpuState();
|
_UpdateCpuState();
|
||||||
|
|
||||||
|
locker.Unlock();
|
||||||
|
|
||||||
|
fSourceView->SetStackFrame(fActiveStackFrame);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -392,6 +431,13 @@ TeamWindow::_HandleStackTraceChanged(thread_id threadID)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TeamWindow::_HandleSourceCodeChanged()
|
||||||
|
{
|
||||||
|
fSourceView->UpdateSourceCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark - Listener
|
// #pragma mark - Listener
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,8 @@
|
|||||||
#include <String.h>
|
#include <String.h>
|
||||||
#include <Window.h>
|
#include <Window.h>
|
||||||
|
|
||||||
|
#include "SourceView.h"
|
||||||
|
#include "StackFrame.h"
|
||||||
#include "StackTraceView.h"
|
#include "StackTraceView.h"
|
||||||
#include "Team.h"
|
#include "Team.h"
|
||||||
#include "ThreadListView.h"
|
#include "ThreadListView.h"
|
||||||
@@ -21,7 +23,8 @@ class TeamDebugModel;
|
|||||||
|
|
||||||
|
|
||||||
class TeamWindow : public BWindow, private ThreadListView::Listener,
|
class TeamWindow : public BWindow, private ThreadListView::Listener,
|
||||||
StackTraceView::Listener, Team::Listener {
|
StackTraceView::Listener, SourceView::Listener, Team::Listener,
|
||||||
|
StackFrame::Listener {
|
||||||
public:
|
public:
|
||||||
class Listener;
|
class Listener;
|
||||||
|
|
||||||
@@ -44,6 +47,9 @@ private:
|
|||||||
// StackTraceView::Listener
|
// StackTraceView::Listener
|
||||||
virtual void StackFrameSelectionChanged(StackFrame* frame);
|
virtual void StackFrameSelectionChanged(StackFrame* frame);
|
||||||
|
|
||||||
|
// StackTraceView::Listener
|
||||||
|
// nothing yet
|
||||||
|
|
||||||
// Team::Listener
|
// Team::Listener
|
||||||
virtual void ThreadStateChanged(
|
virtual void ThreadStateChanged(
|
||||||
const Team::ThreadEvent& event);
|
const Team::ThreadEvent& event);
|
||||||
@@ -52,6 +58,9 @@ private:
|
|||||||
virtual void ThreadStackTraceChanged(
|
virtual void ThreadStackTraceChanged(
|
||||||
const Team::ThreadEvent& event);
|
const Team::ThreadEvent& event);
|
||||||
|
|
||||||
|
// StackFrame::Listener
|
||||||
|
virtual void StackFrameSourceCodeChanged(StackFrame* frame);
|
||||||
|
|
||||||
void _Init();
|
void _Init();
|
||||||
|
|
||||||
void _SetActiveThread(::Thread* thread);
|
void _SetActiveThread(::Thread* thread);
|
||||||
@@ -62,6 +71,7 @@ private:
|
|||||||
void _HandleThreadStateChanged(thread_id threadID);
|
void _HandleThreadStateChanged(thread_id threadID);
|
||||||
void _HandleCpuStateChanged(thread_id threadID);
|
void _HandleCpuStateChanged(thread_id threadID);
|
||||||
void _HandleStackTraceChanged(thread_id threadID);
|
void _HandleStackTraceChanged(thread_id threadID);
|
||||||
|
void _HandleSourceCodeChanged();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
TeamDebugModel* fDebugModel;
|
TeamDebugModel* fDebugModel;
|
||||||
@@ -74,6 +84,7 @@ private:
|
|||||||
ImageListView* fImageListView;
|
ImageListView* fImageListView;
|
||||||
RegisterView* fRegisterView;
|
RegisterView* fRegisterView;
|
||||||
StackTraceView* fStackTraceView;
|
StackTraceView* fStackTraceView;
|
||||||
|
SourceView* fSourceView;
|
||||||
BButton* fRunButton;
|
BButton* fRunButton;
|
||||||
BButton* fStepOverButton;
|
BButton* fStepOverButton;
|
||||||
BButton* fStepIntoButton;
|
BButton* fStepIntoButton;
|
||||||
@@ -85,6 +96,8 @@ class TeamWindow::Listener {
|
|||||||
public:
|
public:
|
||||||
virtual ~Listener();
|
virtual ~Listener();
|
||||||
|
|
||||||
|
virtual void StackFrameSourceCodeRequested(
|
||||||
|
TeamWindow* window, StackFrame* frame) = 0;
|
||||||
virtual void ThreadActionRequested(TeamWindow* window,
|
virtual void ThreadActionRequested(TeamWindow* window,
|
||||||
thread_id threadID, uint32 action) = 0;
|
thread_id threadID, uint32 action) = 0;
|
||||||
virtual bool TeamWindowQuitRequested(TeamWindow* window) = 0;
|
virtual bool TeamWindowQuitRequested(TeamWindow* window) = 0;
|
||||||
|
|||||||
@@ -0,0 +1,80 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2009, Ingo Weinhold, [email protected].
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "SourceCode.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "Statement.h"
|
||||||
|
|
||||||
|
|
||||||
|
SourceCode::SourceCode()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SourceCode::~SourceCode()
|
||||||
|
{
|
||||||
|
for (int32 i = 0; char* line = fLines.ItemAt(i); i++)
|
||||||
|
free(line);
|
||||||
|
for (int32 i = 0; Statement* statement = fStatements.ItemAt(i); i++)
|
||||||
|
statement->RemoveReference();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int32
|
||||||
|
SourceCode::CountLines() const
|
||||||
|
{
|
||||||
|
return fLines.CountItems();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const char*
|
||||||
|
SourceCode::LineAt(int32 index) const
|
||||||
|
{
|
||||||
|
return fLines.ItemAt(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int32
|
||||||
|
SourceCode::CountStatements() const
|
||||||
|
{
|
||||||
|
return fStatements.CountItems();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Statement*
|
||||||
|
SourceCode::StatementAt(int32 index) const
|
||||||
|
{
|
||||||
|
return fStatements.ItemAt(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
SourceCode::AddLine(const char* _line)
|
||||||
|
{
|
||||||
|
char* line = strdup(_line);
|
||||||
|
if (line == NULL)
|
||||||
|
return false;
|
||||||
|
if (!fLines.AddItem(line)) {
|
||||||
|
free(line);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
SourceCode::AddStatement(Statement* statement)
|
||||||
|
{
|
||||||
|
if (!fStatements.AddItem(statement)) {
|
||||||
|
statement->RemoveReference();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2009, Ingo Weinhold, [email protected].
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
#ifndef SOURCE_CODE_H
|
||||||
|
#define SOURCE_CODE_H
|
||||||
|
|
||||||
|
#include <ObjectList.h>
|
||||||
|
#include <Referenceable.h>
|
||||||
|
|
||||||
|
#include "ArchitectureTypes.h"
|
||||||
|
|
||||||
|
|
||||||
|
class Statement;
|
||||||
|
|
||||||
|
|
||||||
|
class SourceCode : public Referenceable {
|
||||||
|
public:
|
||||||
|
SourceCode();
|
||||||
|
~SourceCode();
|
||||||
|
|
||||||
|
int32 CountLines() const;
|
||||||
|
const char* LineAt(int32 index) const;
|
||||||
|
|
||||||
|
int32 CountStatements() const;
|
||||||
|
Statement* StatementAt(int32 index) const;
|
||||||
|
|
||||||
|
bool AddLine(const char* line);
|
||||||
|
// clones
|
||||||
|
bool AddStatement(Statement* statement);
|
||||||
|
// takes over reference
|
||||||
|
|
||||||
|
private:
|
||||||
|
typedef BObjectList<char> LineList;
|
||||||
|
typedef BObjectList<Statement> StatementList;
|
||||||
|
|
||||||
|
private:
|
||||||
|
LineList fLines;
|
||||||
|
StatementList fStatements;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // SOURCE_CODE_H
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2009, Ingo Weinhold, [email protected].
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
#ifndef SOURCE_LOCATION_H
|
||||||
|
#define SOURCE_LOCATION_H
|
||||||
|
|
||||||
|
#include <SupportDefs.h>
|
||||||
|
|
||||||
|
|
||||||
|
class SourceLocation {
|
||||||
|
public:
|
||||||
|
SourceLocation(uint32 line = 0, uint32 column = 0)
|
||||||
|
:
|
||||||
|
fLine(line),
|
||||||
|
fColumn(column)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
SourceLocation(const SourceLocation& other)
|
||||||
|
:
|
||||||
|
fLine(other.fLine),
|
||||||
|
fColumn(other.fColumn)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
SourceLocation& operator=(const SourceLocation& other)
|
||||||
|
{
|
||||||
|
fLine = other.fLine;
|
||||||
|
fColumn = other.fColumn;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const SourceLocation& other) const
|
||||||
|
{
|
||||||
|
return fLine == other.fLine && fColumn == other.fColumn;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!=(const SourceLocation& other) const
|
||||||
|
{
|
||||||
|
return !(*this == other);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 Line() const
|
||||||
|
{
|
||||||
|
return fLine;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 Column() const
|
||||||
|
{
|
||||||
|
return fColumn;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint32 fLine;
|
||||||
|
uint32 fColumn;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // SOURCE_LOCATION_H
|
||||||
@@ -8,6 +8,10 @@
|
|||||||
#include "CpuState.h"
|
#include "CpuState.h"
|
||||||
#include "FunctionDebugInfo.h"
|
#include "FunctionDebugInfo.h"
|
||||||
#include "Image.h"
|
#include "Image.h"
|
||||||
|
#include "SourceCode.h"
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - StackFrame
|
||||||
|
|
||||||
|
|
||||||
StackFrame::StackFrame(stack_frame_type type, CpuState* cpuState,
|
StackFrame::StackFrame(stack_frame_type type, CpuState* cpuState,
|
||||||
@@ -18,7 +22,9 @@ StackFrame::StackFrame(stack_frame_type type, CpuState* cpuState,
|
|||||||
fFrameAddress(frameAddress),
|
fFrameAddress(frameAddress),
|
||||||
fReturnAddress(0),
|
fReturnAddress(0),
|
||||||
fImage(NULL),
|
fImage(NULL),
|
||||||
fFunction(NULL)
|
fFunction(NULL),
|
||||||
|
fSourceCode(NULL),
|
||||||
|
fSourceCodeState(STACK_SOURCE_NOT_LOADED)
|
||||||
{
|
{
|
||||||
fCpuState->AddReference();
|
fCpuState->AddReference();
|
||||||
}
|
}
|
||||||
@@ -26,6 +32,7 @@ StackFrame::StackFrame(stack_frame_type type, CpuState* cpuState,
|
|||||||
|
|
||||||
StackFrame::~StackFrame()
|
StackFrame::~StackFrame()
|
||||||
{
|
{
|
||||||
|
SetSourceCode(NULL, STACK_SOURCE_NOT_LOADED);
|
||||||
SetImage(NULL);
|
SetImage(NULL);
|
||||||
SetFunction(NULL);
|
SetFunction(NULL);
|
||||||
fCpuState->RemoveReference();
|
fCpuState->RemoveReference();
|
||||||
@@ -70,3 +77,51 @@ StackFrame::SetFunction(FunctionDebugInfo* function)
|
|||||||
if (fFunction != NULL)
|
if (fFunction != NULL)
|
||||||
fFunction->AddReference();
|
fFunction->AddReference();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
StackFrame::SetSourceCode(SourceCode* source, stack_frame_source_state state)
|
||||||
|
{
|
||||||
|
if (fSourceCode != NULL)
|
||||||
|
fSourceCode->RemoveReference();
|
||||||
|
|
||||||
|
fSourceCode = source;
|
||||||
|
fSourceCodeState = state;
|
||||||
|
|
||||||
|
if (fSourceCode != NULL)
|
||||||
|
fSourceCode->AddReference();
|
||||||
|
|
||||||
|
// notify listeners
|
||||||
|
for (ListenerList::Iterator it = fListeners.GetIterator();
|
||||||
|
Listener* listener = it.Next();) {
|
||||||
|
listener->StackFrameSourceCodeChanged(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
StackFrame::AddListener(Listener* listener)
|
||||||
|
{
|
||||||
|
fListeners.Add(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
StackFrame::RemoveListener(Listener* listener)
|
||||||
|
{
|
||||||
|
fListeners.Remove(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - Listener
|
||||||
|
|
||||||
|
|
||||||
|
StackFrame::Listener::~Listener()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
StackFrame::Listener::StackFrameSourceCodeChanged(StackFrame* frame)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
#include <OS.h>
|
#include <OS.h>
|
||||||
|
|
||||||
#include <Referenceable.h>
|
#include <Referenceable.h>
|
||||||
|
#include <util/DoublyLinkedList.h>
|
||||||
|
|
||||||
#include "ArchitectureTypes.h"
|
#include "ArchitectureTypes.h"
|
||||||
|
|
||||||
@@ -20,12 +21,24 @@ enum stack_frame_type {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
enum stack_frame_source_state {
|
||||||
|
STACK_SOURCE_NOT_LOADED,
|
||||||
|
STACK_SOURCE_LOADING,
|
||||||
|
STACK_SOURCE_LOADED,
|
||||||
|
STACK_SOURCE_UNAVAILABLE
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
class CpuState;
|
class CpuState;
|
||||||
class Image;
|
class Image;
|
||||||
class FunctionDebugInfo;
|
class FunctionDebugInfo;
|
||||||
|
class SourceCode;
|
||||||
|
|
||||||
|
|
||||||
class StackFrame : public Referenceable {
|
class StackFrame : public Referenceable {
|
||||||
|
public:
|
||||||
|
class Listener;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
StackFrame(stack_frame_type type,
|
StackFrame(stack_frame_type type,
|
||||||
CpuState* cpuState,
|
CpuState* cpuState,
|
||||||
@@ -46,6 +59,19 @@ public:
|
|||||||
FunctionDebugInfo* Function() const { return fFunction; }
|
FunctionDebugInfo* Function() const { return fFunction; }
|
||||||
void SetFunction(FunctionDebugInfo* function);
|
void SetFunction(FunctionDebugInfo* function);
|
||||||
|
|
||||||
|
// mutable attributes follow (locking required)
|
||||||
|
SourceCode* GetSourceCode() const { return fSourceCode; }
|
||||||
|
stack_frame_source_state SourceCodeState() const
|
||||||
|
{ return fSourceCodeState; }
|
||||||
|
void SetSourceCode(SourceCode* source,
|
||||||
|
stack_frame_source_state state);
|
||||||
|
|
||||||
|
void AddListener(Listener* listener);
|
||||||
|
void RemoveListener(Listener* listener);
|
||||||
|
|
||||||
|
private:
|
||||||
|
typedef DoublyLinkedList<Listener> ListenerList;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
stack_frame_type fType;
|
stack_frame_type fType;
|
||||||
CpuState* fCpuState;
|
CpuState* fCpuState;
|
||||||
@@ -53,6 +79,19 @@ private:
|
|||||||
target_addr_t fReturnAddress;
|
target_addr_t fReturnAddress;
|
||||||
Image* fImage;
|
Image* fImage;
|
||||||
FunctionDebugInfo* fFunction;
|
FunctionDebugInfo* fFunction;
|
||||||
|
// mutable
|
||||||
|
SourceCode* fSourceCode;
|
||||||
|
stack_frame_source_state fSourceCodeState;
|
||||||
|
ListenerList fListeners;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class StackFrame::Listener : public DoublyLinkedListLinkImpl<Listener> {
|
||||||
|
public:
|
||||||
|
virtual ~Listener();
|
||||||
|
|
||||||
|
virtual void StackFrameSourceCodeChanged(StackFrame* frame);
|
||||||
|
// called with lock held
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,73 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2009, Ingo Weinhold, [email protected].
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "Statement.h"
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - Statement
|
||||||
|
|
||||||
|
|
||||||
|
Statement::~Statement()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - AbstractStatement
|
||||||
|
|
||||||
|
|
||||||
|
AbstractStatement::AbstractStatement(const SourceLocation& start,
|
||||||
|
const SourceLocation& end)
|
||||||
|
:
|
||||||
|
fStart(start),
|
||||||
|
fEnd(end)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SourceLocation
|
||||||
|
AbstractStatement::StartSourceLocation() const
|
||||||
|
{
|
||||||
|
return fStart;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SourceLocation
|
||||||
|
AbstractStatement::EndSourceLocation() const
|
||||||
|
{
|
||||||
|
return fEnd;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - ContiguousStatement
|
||||||
|
|
||||||
|
|
||||||
|
ContiguousStatement::ContiguousStatement(const SourceLocation& start,
|
||||||
|
const SourceLocation& end, const TargetAddressRange& range)
|
||||||
|
:
|
||||||
|
AbstractStatement(start, end),
|
||||||
|
fRange(range)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TargetAddressRange
|
||||||
|
ContiguousStatement::CoveringAddressRange() const
|
||||||
|
{
|
||||||
|
return fRange;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int32
|
||||||
|
ContiguousStatement::CountAddressRanges() const
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TargetAddressRange
|
||||||
|
ContiguousStatement::AddressRangeAt(int32 index) const
|
||||||
|
{
|
||||||
|
return index == 0 ? fRange : TargetAddressRange();
|
||||||
|
}
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2009, Ingo Weinhold, [email protected].
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
#ifndef STATEMENT_H
|
||||||
|
#define STATEMENT_H
|
||||||
|
|
||||||
|
#include <Referenceable.h>
|
||||||
|
|
||||||
|
#include "ArchitectureTypes.h"
|
||||||
|
#include "SourceLocation.h"
|
||||||
|
#include "TargetAddressRange.h"
|
||||||
|
|
||||||
|
|
||||||
|
class Statement : public Referenceable {
|
||||||
|
public:
|
||||||
|
virtual ~Statement();
|
||||||
|
|
||||||
|
virtual SourceLocation StartSourceLocation() const = 0;
|
||||||
|
virtual SourceLocation EndSourceLocation() const = 0;
|
||||||
|
|
||||||
|
virtual TargetAddressRange CoveringAddressRange() const = 0;
|
||||||
|
|
||||||
|
virtual int32 CountAddressRanges() const = 0;
|
||||||
|
virtual TargetAddressRange AddressRangeAt(int32 index) const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class AbstractStatement : public Statement {
|
||||||
|
public:
|
||||||
|
AbstractStatement(const SourceLocation& start,
|
||||||
|
const SourceLocation& end);
|
||||||
|
|
||||||
|
virtual SourceLocation StartSourceLocation() const;
|
||||||
|
virtual SourceLocation EndSourceLocation() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
SourceLocation fStart;
|
||||||
|
SourceLocation fEnd;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class ContiguousStatement : public AbstractStatement {
|
||||||
|
public:
|
||||||
|
ContiguousStatement(const SourceLocation& start,
|
||||||
|
const SourceLocation& end,
|
||||||
|
const TargetAddressRange& range);
|
||||||
|
|
||||||
|
virtual TargetAddressRange CoveringAddressRange() const;
|
||||||
|
|
||||||
|
virtual int32 CountAddressRanges() const;
|
||||||
|
virtual TargetAddressRange AddressRangeAt(int32 index) const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
TargetAddressRange fRange;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // STATEMENT_H
|
||||||
Reference in New Issue
Block a user