* 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
|
||||
ImageListView.cpp
|
||||
RegisterView.cpp
|
||||
SourceView.cpp
|
||||
StackTraceView.cpp
|
||||
TeamWindow.cpp
|
||||
ThreadListView.cpp
|
||||
@@ -58,8 +59,10 @@ Application Debugger :
|
||||
# model
|
||||
Image.cpp
|
||||
ImageInfo.cpp
|
||||
SourceCode.cpp
|
||||
StackFrame.cpp
|
||||
StackTrace.cpp
|
||||
Statement.cpp
|
||||
SymbolInfo.cpp
|
||||
Team.cpp
|
||||
TeamDebugModel.cpp
|
||||
@@ -77,8 +80,10 @@ Application Debugger :
|
||||
|
||||
:
|
||||
<nogrist>Debugger_demangler.o
|
||||
<nogrist>Debugger_disasm_x86.o
|
||||
<nogrist>DebugAnalyzer_gui_table.o
|
||||
|
||||
libudis86.a
|
||||
<bin>debug_utils.a
|
||||
libcolumnlistview.a
|
||||
libshared.a
|
||||
@@ -89,5 +94,6 @@ Application Debugger :
|
||||
: Debugger.rdef
|
||||
;
|
||||
|
||||
HaikuSubInclude arch x86 disasm ;
|
||||
HaikuSubInclude demangler ;
|
||||
HaikuSubInclude gui running_teams_window ;
|
||||
|
||||
@@ -12,8 +12,11 @@
|
||||
#include "Architecture.h"
|
||||
#include "CpuState.h"
|
||||
#include "DebuggerInterface.h"
|
||||
#include "DebugInfo.h"
|
||||
#include "FunctionDebugInfo.h"
|
||||
#include "Image.h"
|
||||
#include "ImageDebugInfo.h"
|
||||
#include "SourceCode.h"
|
||||
#include "StackTrace.h"
|
||||
#include "Team.h"
|
||||
#include "Thread.h"
|
||||
@@ -170,7 +173,7 @@ GetStackTraceJob::GetImageDebugInfo(Image* image, ImageDebugInfo*& _info)
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - GetStackTraceJob
|
||||
// #pragma mark - LoadImageDebugInfoJob
|
||||
|
||||
|
||||
LoadImageDebugInfoJob::LoadImageDebugInfoJob(
|
||||
@@ -224,3 +227,54 @@ LoadImageDebugInfoJob::Do()
|
||||
|
||||
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 DebuggerInterface;
|
||||
class Image;
|
||||
class StackFrame;
|
||||
class Team;
|
||||
class Thread;
|
||||
|
||||
|
||||
@@ -20,7 +22,8 @@ class Thread;
|
||||
enum {
|
||||
JOB_TYPE_GET_CPU_STATE,
|
||||
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
|
||||
|
||||
@@ -7,15 +7,16 @@
|
||||
|
||||
|
||||
enum {
|
||||
MSG_THREAD_RUN = 'run_',
|
||||
MSG_THREAD_STOP = 'stop',
|
||||
MSG_THREAD_STEP_OVER = 'stov',
|
||||
MSG_THREAD_STEP_INTO = 'stin',
|
||||
MSG_THREAD_STEP_OUT = 'stou',
|
||||
MSG_THREAD_RUN = 'run_',
|
||||
MSG_THREAD_STOP = 'stop',
|
||||
MSG_THREAD_STEP_OVER = 'stov',
|
||||
MSG_THREAD_STEP_INTO = 'stin',
|
||||
MSG_THREAD_STEP_OUT = 'stou',
|
||||
|
||||
MSG_THREAD_STATE_CHANGED = 'tsch',
|
||||
MSG_THREAD_CPU_STATE_CHANGED = 'tcsc',
|
||||
MSG_THREAD_STACK_TRACE_CHANGED = 'tstc'
|
||||
MSG_THREAD_STATE_CHANGED = 'tsch',
|
||||
MSG_THREAD_CPU_STATE_CHANGED = 'tcsc',
|
||||
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
|
||||
TeamDebugger::ThreadActionRequested(TeamWindow* window, thread_id threadID,
|
||||
uint32 action)
|
||||
@@ -269,6 +293,8 @@ void
|
||||
TeamDebugger::JobAborted(Job* 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);
|
||||
|
||||
// TeamWindow::Listener
|
||||
virtual void StackFrameSourceCodeRequested(
|
||||
TeamWindow* window, StackFrame* frame);
|
||||
virtual void ThreadActionRequested(TeamWindow* window,
|
||||
thread_id threadID, uint32 action);
|
||||
virtual bool TeamWindowQuitRequested(TeamWindow* window);
|
||||
|
||||
@@ -16,6 +16,7 @@ class FunctionDebugInfo;
|
||||
class Image;
|
||||
class ImageDebugInfoProvider;
|
||||
class Register;
|
||||
class SourceCode;
|
||||
class StackFrame;
|
||||
class StackTrace;
|
||||
class Team;
|
||||
@@ -42,6 +43,9 @@ public:
|
||||
// returns reference to previous frame
|
||||
// and CPU state; returned CPU state
|
||||
// can be NULL
|
||||
virtual status_t DisassembleCode(FunctionDebugInfo* function,
|
||||
const void* buffer, size_t bufferSize,
|
||||
SourceCode*& _sourceCode) = 0;
|
||||
|
||||
status_t CreateStackTrace(Team* team,
|
||||
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 <String.h>
|
||||
|
||||
#include <AutoDeleter.h>
|
||||
|
||||
#include "CpuStateX86.h"
|
||||
#include "DebuggerInterface.h"
|
||||
#include "FunctionDebugInfo.h"
|
||||
#include "SourceCode.h"
|
||||
#include "StackFrame.h"
|
||||
#include "Statement.h"
|
||||
|
||||
#include "disasm/DisassemblerX86.h"
|
||||
|
||||
|
||||
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
|
||||
ArchitectureX86::_AddRegister(int32 index, const char* name,
|
||||
register_format format, uint32 bitSize, register_type type)
|
||||
|
||||
@@ -28,6 +28,9 @@ public:
|
||||
CpuState* cpuState,
|
||||
StackFrame*& _previousFrame,
|
||||
CpuState*& _previousCpuState);
|
||||
virtual status_t DisassembleCode(FunctionDebugInfo* function,
|
||||
const void* buffer, size_t bufferSize,
|
||||
SourceCode*& _sourceCode);
|
||||
|
||||
private:
|
||||
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 FunctionDebugInfo;
|
||||
class Image;
|
||||
class SourceCode;
|
||||
class StackFrame;
|
||||
|
||||
|
||||
@@ -33,6 +34,9 @@ public:
|
||||
// returns reference to previous frame
|
||||
// and CPU state; returned CPU state
|
||||
// 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 <algorithm>
|
||||
#include <new>
|
||||
|
||||
#include <AutoDeleter.h>
|
||||
|
||||
#include "Architecture.h"
|
||||
#include "BasicFunctionDebugInfo.h"
|
||||
#include "DebuggerInterface.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*
|
||||
DebuggerDebugInfo::_FindSymbol(target_addr_t address)
|
||||
{
|
||||
|
||||
@@ -34,6 +34,8 @@ public:
|
||||
CpuState* cpuState,
|
||||
StackFrame*& _previousFrame,
|
||||
CpuState*& _previousCpuState);
|
||||
virtual status_t LoadSourceCode(FunctionDebugInfo* function,
|
||||
SourceCode*& _sourceCode);
|
||||
|
||||
private:
|
||||
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 <Message.h>
|
||||
#include <TabView.h>
|
||||
#include <ScrollView.h>
|
||||
#include <SplitView.h>
|
||||
#include <TextView.h>
|
||||
|
||||
@@ -42,6 +43,7 @@ TeamWindow::TeamWindow(TeamDebugModel* debugModel, Listener* listener)
|
||||
fImageListView(NULL),
|
||||
fRegisterView(NULL),
|
||||
fStackTraceView(NULL),
|
||||
fSourceView(NULL),
|
||||
fRunButton(NULL),
|
||||
fStepOverButton(NULL),
|
||||
fStepIntoButton(NULL),
|
||||
@@ -63,6 +65,8 @@ TeamWindow::~TeamWindow()
|
||||
fThreadListView->UnsetListener();
|
||||
if (fStackTraceView != NULL)
|
||||
fStackTraceView->UnsetListener();
|
||||
if (fSourceView != NULL)
|
||||
fSourceView->UnsetListener();
|
||||
|
||||
fDebugModel->GetTeam()->RemoveListener(this);
|
||||
}
|
||||
@@ -128,6 +132,11 @@ TeamWindow::MessageReceived(BMessage* message)
|
||||
break;
|
||||
}
|
||||
|
||||
case MSG_STACK_FRAME_SOURCE_CODE_CHANGED:
|
||||
{
|
||||
_HandleSourceCodeChanged();
|
||||
}
|
||||
|
||||
default:
|
||||
BWindow::MessageReceived(message);
|
||||
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
|
||||
TeamWindow::_Init()
|
||||
{
|
||||
BScrollView* sourceScrollView;
|
||||
|
||||
BLayoutBuilder::Group<>(this, B_VERTICAL)
|
||||
.AddSplit(B_VERTICAL, 3.0f)
|
||||
.AddGroup(B_VERTICAL, 0.0f, 0.4f)
|
||||
@@ -202,7 +222,8 @@ TeamWindow::_Init()
|
||||
.SetInsets(4.0f, 0.0f, 4.0f, 0.0f)
|
||||
.End()
|
||||
.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)
|
||||
.Add(fLocalsTabView = new BTabView("locals view"))
|
||||
.SetInsets(0.0f, 0.0f, 4.0f, 4.0f)
|
||||
@@ -211,6 +232,10 @@ TeamWindow::_Init()
|
||||
.End()
|
||||
.End();
|
||||
|
||||
// add source view
|
||||
sourceScrollView->SetTarget(fSourceView = SourceView::Create(fDebugModel,
|
||||
this));
|
||||
|
||||
// add threads tab
|
||||
BSplitView* threadGroup = new BSplitView(B_HORIZONTAL);
|
||||
threadGroup->SetName("Threads");
|
||||
@@ -281,15 +306,29 @@ TeamWindow::_SetActiveStackFrame(StackFrame* frame)
|
||||
if (frame == fActiveStackFrame)
|
||||
return;
|
||||
|
||||
if (fActiveStackFrame != NULL)
|
||||
AutoLocker<TeamDebugModel> locker(fDebugModel);
|
||||
|
||||
if (fActiveStackFrame != NULL) {
|
||||
fActiveStackFrame->RemoveListener(this);
|
||||
fActiveStackFrame->RemoveReference();
|
||||
}
|
||||
|
||||
fActiveStackFrame = frame;
|
||||
|
||||
if (fActiveStackFrame != NULL)
|
||||
if (fActiveStackFrame != NULL) {
|
||||
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();
|
||||
|
||||
locker.Unlock();
|
||||
|
||||
fSourceView->SetStackFrame(fActiveStackFrame);
|
||||
}
|
||||
|
||||
|
||||
@@ -392,6 +431,13 @@ TeamWindow::_HandleStackTraceChanged(thread_id threadID)
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TeamWindow::_HandleSourceCodeChanged()
|
||||
{
|
||||
fSourceView->UpdateSourceCode();
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - Listener
|
||||
|
||||
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
#include <String.h>
|
||||
#include <Window.h>
|
||||
|
||||
#include "SourceView.h"
|
||||
#include "StackFrame.h"
|
||||
#include "StackTraceView.h"
|
||||
#include "Team.h"
|
||||
#include "ThreadListView.h"
|
||||
@@ -21,7 +23,8 @@ class TeamDebugModel;
|
||||
|
||||
|
||||
class TeamWindow : public BWindow, private ThreadListView::Listener,
|
||||
StackTraceView::Listener, Team::Listener {
|
||||
StackTraceView::Listener, SourceView::Listener, Team::Listener,
|
||||
StackFrame::Listener {
|
||||
public:
|
||||
class Listener;
|
||||
|
||||
@@ -44,6 +47,9 @@ private:
|
||||
// StackTraceView::Listener
|
||||
virtual void StackFrameSelectionChanged(StackFrame* frame);
|
||||
|
||||
// StackTraceView::Listener
|
||||
// nothing yet
|
||||
|
||||
// Team::Listener
|
||||
virtual void ThreadStateChanged(
|
||||
const Team::ThreadEvent& event);
|
||||
@@ -52,6 +58,9 @@ private:
|
||||
virtual void ThreadStackTraceChanged(
|
||||
const Team::ThreadEvent& event);
|
||||
|
||||
// StackFrame::Listener
|
||||
virtual void StackFrameSourceCodeChanged(StackFrame* frame);
|
||||
|
||||
void _Init();
|
||||
|
||||
void _SetActiveThread(::Thread* thread);
|
||||
@@ -62,6 +71,7 @@ private:
|
||||
void _HandleThreadStateChanged(thread_id threadID);
|
||||
void _HandleCpuStateChanged(thread_id threadID);
|
||||
void _HandleStackTraceChanged(thread_id threadID);
|
||||
void _HandleSourceCodeChanged();
|
||||
|
||||
private:
|
||||
TeamDebugModel* fDebugModel;
|
||||
@@ -74,6 +84,7 @@ private:
|
||||
ImageListView* fImageListView;
|
||||
RegisterView* fRegisterView;
|
||||
StackTraceView* fStackTraceView;
|
||||
SourceView* fSourceView;
|
||||
BButton* fRunButton;
|
||||
BButton* fStepOverButton;
|
||||
BButton* fStepIntoButton;
|
||||
@@ -85,6 +96,8 @@ class TeamWindow::Listener {
|
||||
public:
|
||||
virtual ~Listener();
|
||||
|
||||
virtual void StackFrameSourceCodeRequested(
|
||||
TeamWindow* window, StackFrame* frame) = 0;
|
||||
virtual void ThreadActionRequested(TeamWindow* window,
|
||||
thread_id threadID, uint32 action) = 0;
|
||||
virtual bool TeamWindowQuitRequested(TeamWindow* window) = 0;
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||
* 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, ingo_weinhold@gmx.de.
|
||||
* 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, ingo_weinhold@gmx.de.
|
||||
* 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 "FunctionDebugInfo.h"
|
||||
#include "Image.h"
|
||||
#include "SourceCode.h"
|
||||
|
||||
|
||||
// #pragma mark - StackFrame
|
||||
|
||||
|
||||
StackFrame::StackFrame(stack_frame_type type, CpuState* cpuState,
|
||||
@@ -18,7 +22,9 @@ StackFrame::StackFrame(stack_frame_type type, CpuState* cpuState,
|
||||
fFrameAddress(frameAddress),
|
||||
fReturnAddress(0),
|
||||
fImage(NULL),
|
||||
fFunction(NULL)
|
||||
fFunction(NULL),
|
||||
fSourceCode(NULL),
|
||||
fSourceCodeState(STACK_SOURCE_NOT_LOADED)
|
||||
{
|
||||
fCpuState->AddReference();
|
||||
}
|
||||
@@ -26,6 +32,7 @@ StackFrame::StackFrame(stack_frame_type type, CpuState* cpuState,
|
||||
|
||||
StackFrame::~StackFrame()
|
||||
{
|
||||
SetSourceCode(NULL, STACK_SOURCE_NOT_LOADED);
|
||||
SetImage(NULL);
|
||||
SetFunction(NULL);
|
||||
fCpuState->RemoveReference();
|
||||
@@ -70,3 +77,51 @@ StackFrame::SetFunction(FunctionDebugInfo* function)
|
||||
if (fFunction != NULL)
|
||||
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 <Referenceable.h>
|
||||
#include <util/DoublyLinkedList.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 Image;
|
||||
class FunctionDebugInfo;
|
||||
class SourceCode;
|
||||
|
||||
|
||||
class StackFrame : public Referenceable {
|
||||
public:
|
||||
class Listener;
|
||||
|
||||
public:
|
||||
StackFrame(stack_frame_type type,
|
||||
CpuState* cpuState,
|
||||
@@ -46,6 +59,19 @@ public:
|
||||
FunctionDebugInfo* Function() const { return fFunction; }
|
||||
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:
|
||||
stack_frame_type fType;
|
||||
CpuState* fCpuState;
|
||||
@@ -53,6 +79,19 @@ private:
|
||||
target_addr_t fReturnAddress;
|
||||
Image* fImage;
|
||||
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, ingo_weinhold@gmx.de.
|
||||
* 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, ingo_weinhold@gmx.de.
|
||||
* 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