* Added Breakpoint class and extended TeamDebugModel to manage the objects.
Extended the event mechanism respectively. * Added support to SourceView to display breakpoints and manipulate them. * Extended TeamDebugger to install/uninstall breakpoints. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@31189 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
7c439b2356
commit
6381d6cc4e
@ -57,6 +57,7 @@ Application Debugger :
|
||||
ThreadListView.cpp
|
||||
|
||||
# model
|
||||
Breakpoint.cpp
|
||||
DisassembledCode.cpp
|
||||
Image.cpp
|
||||
ImageInfo.cpp
|
||||
|
@ -12,11 +12,14 @@ enum {
|
||||
MSG_THREAD_STEP_OVER = 'stov',
|
||||
MSG_THREAD_STEP_INTO = 'stin',
|
||||
MSG_THREAD_STEP_OUT = 'stou',
|
||||
MSG_SET_BREAKPONT = 'sbrk',
|
||||
MSG_CLEAR_BREAKPONT = 'cbrk',
|
||||
|
||||
MSG_THREAD_STATE_CHANGED = 'tsch',
|
||||
MSG_THREAD_CPU_STATE_CHANGED = 'tcsc',
|
||||
MSG_THREAD_STACK_TRACE_CHANGED = 'tstc',
|
||||
MSG_STACK_FRAME_SOURCE_CODE_CHANGED = 'sfsc'
|
||||
MSG_STACK_FRAME_SOURCE_CODE_CHANGED = 'sfsc',
|
||||
MSG_USER_BREAKPOINT_CHANGED = 'ubrc'
|
||||
};
|
||||
|
||||
|
||||
|
@ -5,10 +5,12 @@
|
||||
|
||||
#include "TeamDebugger.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <new>
|
||||
|
||||
#include <Alert.h>
|
||||
#include <Message.h>
|
||||
|
||||
#include <AutoLocker.h>
|
||||
@ -19,6 +21,7 @@
|
||||
#include "DebuggerInterface.h"
|
||||
#include "Jobs.h"
|
||||
#include "MessageCodes.h"
|
||||
#include "Statement.h"
|
||||
#include "TeamDebugModel.h"
|
||||
|
||||
|
||||
@ -198,6 +201,24 @@ TeamDebugger::MessageReceived(BMessage* message)
|
||||
break;
|
||||
}
|
||||
|
||||
case MSG_SET_BREAKPONT:
|
||||
case MSG_CLEAR_BREAKPONT:
|
||||
{
|
||||
uint64 address;
|
||||
if (message->FindUInt64("address", &address) != B_OK)
|
||||
break;
|
||||
|
||||
if (message->what == MSG_SET_BREAKPONT) {
|
||||
bool enabled;
|
||||
if (message->FindBool("enabled", &enabled) != B_OK)
|
||||
enabled = true;
|
||||
|
||||
_HandleSetUserBreakpoint(address, enabled);
|
||||
} else
|
||||
_HandleClearUserBreakpoint(address);
|
||||
break;
|
||||
}
|
||||
|
||||
case MSG_THREAD_STATE_CHANGED:
|
||||
{
|
||||
int32 threadID;
|
||||
@ -267,6 +288,25 @@ TeamDebugger::ThreadActionRequested(TeamWindow* window, thread_id threadID,
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TeamDebugger::SetBreakpointRequested(target_addr_t address, bool enabled)
|
||||
{
|
||||
BMessage message(MSG_SET_BREAKPONT);
|
||||
message.AddUInt64("address", (uint64)address);
|
||||
message.AddBool("enabled", enabled);
|
||||
PostMessage(&message);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TeamDebugger::ClearBreakpointRequested(target_addr_t address)
|
||||
{
|
||||
BMessage message(MSG_CLEAR_BREAKPONT);
|
||||
message.AddUInt64("address", (uint64)address);
|
||||
PostMessage(&message);
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
TeamDebugger::TeamWindowQuitRequested(TeamWindow* window)
|
||||
{
|
||||
@ -569,6 +609,73 @@ TeamDebugger::_SetThreadState(::Thread* thread, uint32 state,
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
TeamDebugger::_SetUserBreakpoint(target_addr_t address, bool enabled)
|
||||
{
|
||||
user_breakpoint_state state = enabled
|
||||
? USER_BREAKPOINT_ENABLED : USER_BREAKPOINT_DISABLED;
|
||||
|
||||
AutoLocker<TeamDebugModel> locker(fDebugModel);
|
||||
|
||||
// If there already is a breakpoint, it might already have the requested
|
||||
// state.
|
||||
Breakpoint* breakpoint = fDebugModel->BreakpointAtAddress(address);
|
||||
if (breakpoint != NULL && breakpoint->UserState() == state)
|
||||
return B_OK;
|
||||
|
||||
// create a breakpoint, if it doesn't exist yet
|
||||
if (breakpoint == NULL) {
|
||||
Image* image = fTeam->ImageByAddress(address);
|
||||
if (image == NULL)
|
||||
return B_OK;
|
||||
|
||||
breakpoint = new(std::nothrow) Breakpoint(image, address);
|
||||
if (breakpoint == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
if (!fDebugModel->AddBreakpoint(breakpoint))
|
||||
return B_NO_MEMORY;
|
||||
}
|
||||
|
||||
user_breakpoint_state oldState = breakpoint->UserState();
|
||||
|
||||
// set the breakpoint state
|
||||
breakpoint->SetUserState(state);
|
||||
fDebugModel->NotifyUserBreakpointChanged(breakpoint);
|
||||
|
||||
bool install = breakpoint->ShouldBeInstalled();
|
||||
if (breakpoint->IsInstalled() == install)
|
||||
return B_OK;
|
||||
|
||||
// The breakpoint needs to be installed/uninstalled.
|
||||
locker.Unlock();
|
||||
|
||||
status_t error = install
|
||||
? fDebuggerInterface->InstallBreakpoint(address)
|
||||
: fDebuggerInterface->UninstallBreakpoint(address);
|
||||
|
||||
locker.Lock();
|
||||
|
||||
breakpoint = fDebugModel->BreakpointAtAddress(address);
|
||||
|
||||
// Mark the breakpoint installed/uninstalled, if everything went fine.
|
||||
if (error == B_OK) {
|
||||
breakpoint->SetInstalled(install);
|
||||
printf("-> breakpoint %sinstalled successfully!\n", install ? "" : "un");
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
// revert on error
|
||||
breakpoint->SetUserState(oldState);
|
||||
fDebugModel->NotifyUserBreakpointChanged(breakpoint);
|
||||
|
||||
if (breakpoint->IsUnused())
|
||||
fDebugModel->RemoveBreakpoint(breakpoint);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TeamDebugger::_HandleThreadAction(thread_id threadID, uint32 action)
|
||||
{
|
||||
@ -619,6 +726,47 @@ printf("MSG_THREAD_STEP_OUT\n");
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TeamDebugger::_HandleSetUserBreakpoint(target_addr_t address, bool enabled)
|
||||
{
|
||||
printf("TeamDebugger::_HandleSetUserBreakpoint(%#llx, %d)\n", address, enabled);
|
||||
status_t error = _SetUserBreakpoint(address, enabled);
|
||||
if (error != B_OK) {
|
||||
_NotifyUser("Install Breakpoint", "Failed to install breakpoint: %s",
|
||||
strerror(error));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TeamDebugger::_HandleClearUserBreakpoint(target_addr_t address)
|
||||
{
|
||||
printf("TeamDebugger::_HandleClearUserBreakpoint(%#llx)\n", address);
|
||||
AutoLocker<TeamDebugModel> locker(fDebugModel);
|
||||
|
||||
Breakpoint* breakpoint = fDebugModel->BreakpointAtAddress(address);
|
||||
if (breakpoint == NULL || breakpoint->UserState() == USER_BREAKPOINT_NONE)
|
||||
return;
|
||||
|
||||
// set the breakpoint state
|
||||
breakpoint->SetUserState(USER_BREAKPOINT_NONE);
|
||||
fDebugModel->NotifyUserBreakpointChanged(breakpoint);
|
||||
|
||||
// check whether the breakpoint needs to be uninstalled
|
||||
bool uninstall = !breakpoint->ShouldBeInstalled()
|
||||
&& breakpoint->IsInstalled();
|
||||
|
||||
// if unused remove it
|
||||
if (breakpoint->IsUnused())
|
||||
fDebugModel->RemoveBreakpoint(breakpoint);
|
||||
|
||||
locker.Unlock();
|
||||
|
||||
if (uninstall)
|
||||
fDebuggerInterface->UninstallBreakpoint(address);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TeamDebugger::_HandleThreadStateChanged(thread_id threadID)
|
||||
{
|
||||
@ -669,3 +817,25 @@ TeamDebugger::_HandleStackTraceChanged(thread_id threadID)
|
||||
{
|
||||
printf("TeamDebugger::_HandleStackTraceChanged()\n");
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TeamDebugger::_NotifyUser(const char* title, const char* text,...)
|
||||
{
|
||||
// print the message
|
||||
char buffer[1024];
|
||||
va_list args;
|
||||
va_start(args, text);
|
||||
vsnprintf(buffer, sizeof(buffer), text, args);
|
||||
va_end(args);
|
||||
|
||||
// show the alert
|
||||
BAlert* alert = new(std::nothrow) BAlert(title, buffer, "OK",
|
||||
NULL, NULL, B_WIDTH_AS_USUAL, B_WARNING_ALERT);
|
||||
if (alert != NULL)
|
||||
alert->Go(NULL);
|
||||
|
||||
// TODO: We need to let the alert run asynchronously, but we shouldn't just
|
||||
// create it and don't care anymore. Maybe an error window, which can
|
||||
// display a list of errors would be the better choice.
|
||||
}
|
||||
|
@ -39,6 +39,9 @@ private:
|
||||
TeamWindow* window, StackFrame* frame);
|
||||
virtual void ThreadActionRequested(TeamWindow* window,
|
||||
thread_id threadID, uint32 action);
|
||||
virtual void SetBreakpointRequested(target_addr_t address,
|
||||
bool enabled);
|
||||
virtual void ClearBreakpointRequested(target_addr_t address);
|
||||
virtual bool TeamWindowQuitRequested(TeamWindow* window);
|
||||
|
||||
// JobListener
|
||||
@ -88,13 +91,23 @@ private:
|
||||
void _SetThreadState(::Thread* thread, uint32 state,
|
||||
CpuState* cpuState);
|
||||
|
||||
status_t _SetUserBreakpoint(target_addr_t address,
|
||||
bool enabled);
|
||||
|
||||
void _HandleThreadAction(thread_id threadID,
|
||||
uint32 action);
|
||||
void _HandleSetUserBreakpoint(target_addr_t address,
|
||||
bool enabled);
|
||||
void _HandleClearUserBreakpoint(
|
||||
target_addr_t address);
|
||||
|
||||
void _HandleThreadStateChanged(thread_id threadID);
|
||||
void _HandleCpuStateChanged(thread_id threadID);
|
||||
void _HandleStackTraceChanged(thread_id threadID);
|
||||
|
||||
void _NotifyUser(const char* title,
|
||||
const char* text,...);
|
||||
|
||||
private:
|
||||
::Team* fTeam;
|
||||
TeamDebugModel* fDebugModel;
|
||||
|
@ -11,12 +11,15 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#include <LayoutUtils.h>
|
||||
#include <Looper.h>
|
||||
#include <Message.h>
|
||||
#include <Polygon.h>
|
||||
#include <ScrollBar.h>
|
||||
|
||||
#include <AutoLocker.h>
|
||||
#include <ObjectList.h>
|
||||
|
||||
#include "Breakpoint.h"
|
||||
#include "SourceCode.h"
|
||||
#include "StackTrace.h"
|
||||
#include "Statement.h"
|
||||
@ -41,9 +44,10 @@ protected:
|
||||
|
||||
inline float TotalHeight() const;
|
||||
|
||||
int32 LineAtOffset(float yOffset) const;
|
||||
void GetLineRange(BRect rect, int32& minLine,
|
||||
int32& maxLine);
|
||||
|
||||
int32& maxLine) const;
|
||||
BRect LineRect(uint32 line) const;
|
||||
|
||||
protected:
|
||||
SourceView* fSourceView;
|
||||
@ -55,7 +59,8 @@ protected:
|
||||
class SourceView::MarkerView : public BaseView {
|
||||
public:
|
||||
MarkerView(SourceView* sourceView,
|
||||
FontInfo* fontInfo);
|
||||
TeamDebugModel* debugModel,
|
||||
Listener* listener, FontInfo* fontInfo);
|
||||
~MarkerView();
|
||||
|
||||
virtual void SetSourceCode(SourceCode* sourceCode);
|
||||
@ -63,25 +68,52 @@ public:
|
||||
void SetStackTrace(StackTrace* stackTrace);
|
||||
void SetStackFrame(StackFrame* stackFrame);
|
||||
|
||||
void UserBreakpointChanged(target_addr_t address);
|
||||
|
||||
virtual BSize MinSize();
|
||||
virtual BSize MaxSize();
|
||||
|
||||
virtual void Draw(BRect updateRect);
|
||||
|
||||
virtual void MouseDown(BPoint where);
|
||||
|
||||
private:
|
||||
struct Marker;
|
||||
struct InstructionPointerMarker;
|
||||
struct BreakpointMarker;
|
||||
|
||||
template<typename MarkerType> struct MarkerByLinePredicate;
|
||||
|
||||
typedef BObjectList<Marker> MarkerList;
|
||||
typedef BObjectList<BreakpointMarker> BreakpointMarkerList;
|
||||
|
||||
private:
|
||||
void _UpdateMarkers();
|
||||
void _InvalidateIPMarkers();
|
||||
void _InvalidateBreakpointMarkers();
|
||||
void _UpdateIPMarkers();
|
||||
void _UpdateBreakpointMarkers();
|
||||
void _GetMarkers(uint32 minLine, uint32 maxLine,
|
||||
MarkerList& markers);
|
||||
BreakpointMarker* _BreakpointMarkerAtLine(uint32 line);
|
||||
|
||||
template<typename MarkerType>
|
||||
static int _CompareMarkers(const MarkerType* a,
|
||||
const MarkerType* b);
|
||||
|
||||
template<typename MarkerType>
|
||||
static int _CompareLineMarker(const uint32* line,
|
||||
const MarkerType* marker);
|
||||
|
||||
private:
|
||||
TeamDebugModel* fDebugModel;
|
||||
Listener* fListener;
|
||||
StackTrace* fStackTrace;
|
||||
StackFrame* fStackFrame;
|
||||
MarkerList fMarkers;
|
||||
bool fMarkersValid;
|
||||
MarkerList fIPMarkers;
|
||||
BreakpointMarkerList fBreakpointMarkers;
|
||||
bool fIPMarkersValid;
|
||||
bool fBreakpointMarkersValid;
|
||||
rgb_color fBreakpointOptionMarker;
|
||||
};
|
||||
|
||||
|
||||
@ -115,6 +147,40 @@ private:
|
||||
};
|
||||
|
||||
|
||||
struct SourceView::MarkerView::BreakpointMarker : Marker {
|
||||
BreakpointMarker(uint32 line,
|
||||
target_addr_t address, bool enabled);
|
||||
|
||||
target_addr_t Address() const { return fAddress; }
|
||||
bool IsEnabled() const { return fEnabled; }
|
||||
|
||||
virtual void Draw(MarkerView* view, BRect rect);
|
||||
|
||||
private:
|
||||
target_addr_t fAddress;
|
||||
bool fEnabled;
|
||||
};
|
||||
|
||||
|
||||
template<typename MarkerType>
|
||||
struct SourceView::MarkerView::MarkerByLinePredicate
|
||||
: UnaryPredicate<MarkerType> {
|
||||
MarkerByLinePredicate(uint32 line)
|
||||
:
|
||||
fLine(line)
|
||||
{
|
||||
}
|
||||
|
||||
virtual int operator()(const MarkerType* marker) const
|
||||
{
|
||||
return -_CompareLineMarker<MarkerType>(&fLine, marker);
|
||||
}
|
||||
|
||||
private:
|
||||
uint32 fLine;
|
||||
};
|
||||
|
||||
|
||||
class SourceView::TextView : public BaseView {
|
||||
public:
|
||||
TextView(SourceView* sourceView,
|
||||
@ -181,8 +247,21 @@ SourceView::BaseView::TotalHeight() const
|
||||
}
|
||||
|
||||
|
||||
int32
|
||||
SourceView::BaseView::LineAtOffset(float yOffset) const
|
||||
{
|
||||
int32 lineCount = LineCount();
|
||||
if (yOffset < 0 || lineCount == 0)
|
||||
return -1;
|
||||
|
||||
int32 line = (int32)yOffset / (int32)fFontInfo->lineHeight;
|
||||
return line < lineCount ? line : -1;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SourceView::BaseView::GetLineRange(BRect rect, int32& minLine, int32& maxLine)
|
||||
SourceView::BaseView::GetLineRange(BRect rect, int32& minLine,
|
||||
int32& maxLine) const
|
||||
{
|
||||
int32 lineHeight = (int32)fFontInfo->lineHeight;
|
||||
minLine = (int32)rect.top / lineHeight;
|
||||
@ -192,6 +271,14 @@ SourceView::BaseView::GetLineRange(BRect rect, int32& minLine, int32& maxLine)
|
||||
}
|
||||
|
||||
|
||||
BRect
|
||||
SourceView::BaseView::LineRect(uint32 line) const
|
||||
{
|
||||
float y = (float)line * fFontInfo->lineHeight;
|
||||
return BRect(0, y, Bounds().right, y + fFontInfo->lineHeight - 1);
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - MarkerView::Marker
|
||||
|
||||
|
||||
@ -282,18 +369,52 @@ SourceView::MarkerView::InstructionPointerMarker::_DrawArrow(BView* view,
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - MarkerView::BreakpointMarker
|
||||
|
||||
|
||||
SourceView::MarkerView::BreakpointMarker::BreakpointMarker(uint32 line,
|
||||
target_addr_t address, bool enabled)
|
||||
:
|
||||
Marker(line),
|
||||
fAddress(address),
|
||||
fEnabled(enabled)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SourceView::MarkerView::BreakpointMarker::Draw(MarkerView* view, BRect rect)
|
||||
{
|
||||
float y = (rect.top + rect.bottom) / 2;
|
||||
view->SetHighColor((rgb_color){255, 0, 0, 255});
|
||||
if (fEnabled)
|
||||
view->FillEllipse(BPoint(rect.right - 8, y), 4, 4);
|
||||
else
|
||||
view->StrokeEllipse(BPoint(rect.right - 8, y), 3.5f, 3.5f);
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - MarkerView
|
||||
|
||||
|
||||
SourceView::MarkerView::MarkerView(SourceView* sourceView, FontInfo* fontInfo)
|
||||
SourceView::MarkerView::MarkerView(SourceView* sourceView,
|
||||
TeamDebugModel* debugModel, Listener* listener, FontInfo* fontInfo)
|
||||
:
|
||||
BaseView("source marker view", sourceView, fontInfo),
|
||||
fDebugModel(debugModel),
|
||||
fListener(listener),
|
||||
fStackTrace(NULL),
|
||||
fStackFrame(NULL),
|
||||
fMarkers(20, true),
|
||||
fMarkersValid(false)
|
||||
fIPMarkers(10, true),
|
||||
fBreakpointMarkers(20, true),
|
||||
fIPMarkersValid(false),
|
||||
fBreakpointMarkersValid(false)
|
||||
|
||||
{
|
||||
SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
|
||||
rgb_color background = ui_color(B_PANEL_BACKGROUND_COLOR);
|
||||
fBreakpointOptionMarker = tint_color(ui_color(B_PANEL_BACKGROUND_COLOR),
|
||||
B_DARKEN_1_TINT);
|
||||
SetViewColor(background);
|
||||
}
|
||||
|
||||
|
||||
@ -305,8 +426,8 @@ SourceView::MarkerView::~MarkerView()
|
||||
void
|
||||
SourceView::MarkerView::SetSourceCode(SourceCode* sourceCode)
|
||||
{
|
||||
fMarkers.MakeEmpty();
|
||||
fMarkersValid = false;
|
||||
_InvalidateIPMarkers();
|
||||
_InvalidateBreakpointMarkers();
|
||||
BaseView::SetSourceCode(sourceCode);
|
||||
}
|
||||
|
||||
@ -315,8 +436,7 @@ void
|
||||
SourceView::MarkerView::SetStackTrace(StackTrace* stackTrace)
|
||||
{
|
||||
fStackTrace = stackTrace;
|
||||
fMarkers.MakeEmpty();
|
||||
fMarkersValid = false;
|
||||
_InvalidateIPMarkers();
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
@ -325,8 +445,15 @@ void
|
||||
SourceView::MarkerView::SetStackFrame(StackFrame* stackFrame)
|
||||
{
|
||||
fStackFrame = stackFrame;
|
||||
fMarkers.MakeEmpty();
|
||||
fMarkersValid = false;
|
||||
_InvalidateIPMarkers();
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SourceView::MarkerView::UserBreakpointChanged(target_addr_t address)
|
||||
{
|
||||
_InvalidateBreakpointMarkers();
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
@ -347,40 +474,112 @@ SourceView::MarkerView::MaxSize()
|
||||
void
|
||||
SourceView::MarkerView::Draw(BRect updateRect)
|
||||
{
|
||||
_UpdateMarkers();
|
||||
|
||||
if (fSourceCode == NULL || fMarkers.IsEmpty())
|
||||
if (fSourceCode == NULL)
|
||||
return;
|
||||
|
||||
// get the lines intersecting with the update rect
|
||||
int32 minLine, maxLine;
|
||||
GetLineRange(updateRect, minLine, maxLine);
|
||||
if (minLine > maxLine)
|
||||
return;
|
||||
|
||||
// get the markers in that range
|
||||
MarkerList markers;
|
||||
_GetMarkers(minLine, maxLine, markers);
|
||||
|
||||
// draw the markers
|
||||
float width = Bounds().Width();
|
||||
// TODO: The markers should be sorted, so we don't need to iterate over
|
||||
// all of them.
|
||||
for (int32 i = 0; Marker* marker = fMarkers.ItemAt(i); i++) {
|
||||
int32 line = marker->Line();
|
||||
if (line < minLine || line > maxLine)
|
||||
|
||||
int32 markerIndex = 0;
|
||||
for (int32 line = minLine; line <= maxLine; line++) {
|
||||
bool drawBreakpointOptionMarker = true;
|
||||
|
||||
Marker* marker;
|
||||
while ((marker = markers.ItemAt(markerIndex)) != NULL
|
||||
&& marker->Line() == (uint32)line) {
|
||||
marker->Draw(this, LineRect(line));
|
||||
drawBreakpointOptionMarker = false;
|
||||
markerIndex++;
|
||||
}
|
||||
|
||||
if (!drawBreakpointOptionMarker)
|
||||
continue;
|
||||
|
||||
float y = (float)line * fFontInfo->lineHeight;
|
||||
BRect rect(0, y, width, y + fFontInfo->lineHeight - 1);
|
||||
marker->Draw(this, rect);
|
||||
}
|
||||
Statement* statement = fSourceCode->StatementAtLine(line);
|
||||
if (statement == NULL
|
||||
|| statement->StartSourceLocation().Line() != (uint32)line
|
||||
|| !statement->BreakpointAllowed()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// TODO: Draw possible breakpoint marks!
|
||||
float y = ((float)line + 0.5f) * fFontInfo->lineHeight;
|
||||
SetHighColor(fBreakpointOptionMarker);
|
||||
FillEllipse(BPoint(width - 8, y), 2, 2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SourceView::MarkerView::_UpdateMarkers()
|
||||
SourceView::MarkerView::MouseDown(BPoint where)
|
||||
{
|
||||
if (fMarkersValid)
|
||||
if (fSourceCode == NULL)
|
||||
return;
|
||||
|
||||
fMarkers.MakeEmpty();
|
||||
int32 line = LineAtOffset(where.y);
|
||||
if (line < 0)
|
||||
return;
|
||||
|
||||
Statement* statement = fSourceCode->StatementAtLine(line);
|
||||
if (statement == NULL
|
||||
|| statement->StartSourceLocation().Line() != (uint32)line
|
||||
|| !statement->BreakpointAllowed()) {
|
||||
return;
|
||||
}
|
||||
|
||||
int32 modifiers;
|
||||
if (Looper()->CurrentMessage()->FindInt32("modifiers", &modifiers) != B_OK)
|
||||
modifiers = 0;
|
||||
|
||||
BreakpointMarker* marker = _BreakpointMarkerAtLine(line);
|
||||
target_addr_t address = marker != NULL
|
||||
? marker->Address() : statement->CoveringAddressRange().Start();
|
||||
|
||||
if ((modifiers & B_SHIFT_KEY) != 0) {
|
||||
if (marker != NULL && !marker->IsEnabled())
|
||||
fListener->ClearBreakpointRequested(address);
|
||||
else
|
||||
fListener->SetBreakpointRequested(address, false);
|
||||
} else {
|
||||
if (marker != NULL && marker->IsEnabled())
|
||||
fListener->ClearBreakpointRequested(address);
|
||||
else
|
||||
fListener->SetBreakpointRequested(address, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SourceView::MarkerView::_InvalidateIPMarkers()
|
||||
{
|
||||
fIPMarkersValid = false;
|
||||
fIPMarkers.MakeEmpty();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SourceView::MarkerView::_InvalidateBreakpointMarkers()
|
||||
{
|
||||
fBreakpointMarkersValid = false;
|
||||
fBreakpointMarkers.MakeEmpty();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SourceView::MarkerView::_UpdateIPMarkers()
|
||||
{
|
||||
if (fIPMarkersValid)
|
||||
return;
|
||||
|
||||
fIPMarkers.MakeEmpty();
|
||||
|
||||
if (fSourceCode != NULL && fStackTrace != NULL) {
|
||||
for (int32 i = 0; StackFrame* frame = fStackTrace->FrameAt(i);
|
||||
@ -395,15 +594,132 @@ SourceView::MarkerView::_UpdateMarkers()
|
||||
|
||||
Marker* marker = new(std::nothrow) InstructionPointerMarker(
|
||||
line, i == 0, frame == fStackFrame);
|
||||
if (marker == NULL || !fMarkers.AddItem(marker)) {
|
||||
if (marker == NULL || !fIPMarkers.AddItem(marker)) {
|
||||
delete marker;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// TODO: Filter duplicate IP markers (recursive functions)!
|
||||
|
||||
fMarkersValid = true;
|
||||
// sort by line
|
||||
fIPMarkers.SortItems(&_CompareMarkers<Marker>);
|
||||
|
||||
// TODO: Filter duplicate IP markers (recursive functions)!
|
||||
}
|
||||
|
||||
fIPMarkersValid = true;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SourceView::MarkerView::_UpdateBreakpointMarkers()
|
||||
{
|
||||
if (fBreakpointMarkersValid)
|
||||
return;
|
||||
|
||||
fBreakpointMarkers.MakeEmpty();
|
||||
|
||||
if (fSourceCode != NULL) {
|
||||
AutoLocker<TeamDebugModel> locker(fDebugModel);
|
||||
|
||||
// get the breakpoints in our source code range
|
||||
BObjectList<Breakpoint> breakpoints;
|
||||
fDebugModel->GetBreakpointsInAddressRange(
|
||||
fSourceCode->StatementAddressRange(), breakpoints);
|
||||
|
||||
for (int32 i = 0; Breakpoint* breakpoint = breakpoints.ItemAt(i); i++) {
|
||||
if (breakpoint->UserState() == USER_BREAKPOINT_NONE)
|
||||
continue;
|
||||
|
||||
Statement* statement = fSourceCode->StatementAtAddress(
|
||||
breakpoint->Address());
|
||||
if (statement == NULL)
|
||||
continue;
|
||||
uint32 line = statement->StartSourceLocation().Line();
|
||||
if (line >= (uint32)LineCount())
|
||||
continue;
|
||||
|
||||
BreakpointMarker* marker = new(std::nothrow) BreakpointMarker(
|
||||
line, breakpoint->Address(),
|
||||
breakpoint->UserState() == USER_BREAKPOINT_ENABLED);
|
||||
if (marker == NULL || !fBreakpointMarkers.AddItem(marker)) {
|
||||
delete marker;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// sort by line
|
||||
fBreakpointMarkers.SortItems(&_CompareMarkers<BreakpointMarker>);
|
||||
}
|
||||
|
||||
fBreakpointMarkersValid = true;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SourceView::MarkerView::_GetMarkers(uint32 minLine, uint32 maxLine,
|
||||
MarkerList& markers)
|
||||
{
|
||||
_UpdateIPMarkers();
|
||||
_UpdateBreakpointMarkers();
|
||||
|
||||
int32 ipIndex = fIPMarkers.FindBinaryInsertionIndex(
|
||||
MarkerByLinePredicate<Marker>(minLine));
|
||||
int32 breakpointIndex = fBreakpointMarkers.FindBinaryInsertionIndex(
|
||||
MarkerByLinePredicate<BreakpointMarker>(minLine));
|
||||
|
||||
Marker* ipMarker = fIPMarkers.ItemAt(ipIndex);
|
||||
Marker* breakpointMarker = fBreakpointMarkers.ItemAt(breakpointIndex);
|
||||
|
||||
while (ipMarker != NULL && breakpointMarker != NULL
|
||||
&& ipMarker->Line() <= maxLine && breakpointMarker->Line() <= maxLine) {
|
||||
if (breakpointMarker->Line() <= ipMarker->Line()) {
|
||||
markers.AddItem(breakpointMarker);
|
||||
breakpointMarker = fBreakpointMarkers.ItemAt(++breakpointIndex);
|
||||
} else {
|
||||
markers.AddItem(ipMarker);
|
||||
ipMarker = fIPMarkers.ItemAt(++ipIndex);
|
||||
}
|
||||
}
|
||||
|
||||
while (breakpointMarker != NULL && breakpointMarker->Line() <= maxLine) {
|
||||
markers.AddItem(breakpointMarker);
|
||||
breakpointMarker = fBreakpointMarkers.ItemAt(++breakpointIndex);
|
||||
}
|
||||
|
||||
while (ipMarker != NULL && ipMarker->Line() <= maxLine) {
|
||||
markers.AddItem(ipMarker);
|
||||
ipMarker = fIPMarkers.ItemAt(++ipIndex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
SourceView::MarkerView::BreakpointMarker*
|
||||
SourceView::MarkerView::_BreakpointMarkerAtLine(uint32 line)
|
||||
{
|
||||
return fBreakpointMarkers.BinarySearchByKey(line,
|
||||
&_CompareLineMarker<BreakpointMarker>);
|
||||
}
|
||||
|
||||
|
||||
template<typename MarkerType>
|
||||
/*static*/ int
|
||||
SourceView::MarkerView::_CompareMarkers(const MarkerType* a,
|
||||
const MarkerType* b)
|
||||
{
|
||||
if (a->Line() < b->Line())
|
||||
return -1;
|
||||
return a->Line() == b->Line() ? 0 : 1;
|
||||
}
|
||||
|
||||
|
||||
template<typename MarkerType>
|
||||
/*static*/ int
|
||||
SourceView::MarkerView::_CompareLineMarker(const uint32* line,
|
||||
const MarkerType* marker)
|
||||
{
|
||||
if (*line < marker->Line())
|
||||
return -1;
|
||||
return *line == marker->Line() ? 0 : 1;
|
||||
}
|
||||
|
||||
|
||||
@ -605,6 +921,13 @@ SourceView::SetSourceCode(SourceCode* sourceCode)
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SourceView::UserBreakpointChanged(target_addr_t address)
|
||||
{
|
||||
fMarkerView->UserBreakpointChanged(address);
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
SourceView::ScrollToAddress(target_addr_t address)
|
||||
{
|
||||
@ -622,7 +945,6 @@ SourceView::ScrollToAddress(target_addr_t address)
|
||||
bool
|
||||
SourceView::ScrollToLine(uint32 line)
|
||||
{
|
||||
printf("SourceView::ScrollToLine(%lu)\n", line);
|
||||
if (fSourceCode == NULL || line >= (uint32)fSourceCode->CountLines())
|
||||
return false;
|
||||
|
||||
@ -703,7 +1025,8 @@ SourceView::DoLayout()
|
||||
void
|
||||
SourceView::_Init()
|
||||
{
|
||||
AddChild(fMarkerView = new MarkerView(this, &fFontInfo));
|
||||
AddChild(fMarkerView = new MarkerView(this, fDebugModel, fListener,
|
||||
&fFontInfo));
|
||||
AddChild(fTextView = new TextView(this, &fFontInfo));
|
||||
}
|
||||
|
||||
|
@ -11,9 +11,11 @@
|
||||
#include "ArchitectureTypes.h"
|
||||
|
||||
|
||||
class Breakpoint;
|
||||
class SourceCode;
|
||||
class StackFrame;
|
||||
class StackTrace;
|
||||
class Statement;
|
||||
class TeamDebugModel;
|
||||
|
||||
|
||||
@ -36,6 +38,8 @@ public:
|
||||
void SetStackFrame(StackFrame* stackFrame);
|
||||
void SetSourceCode(SourceCode* sourceCode);
|
||||
|
||||
void UserBreakpointChanged(target_addr_t address);
|
||||
|
||||
bool ScrollToAddress(target_addr_t address);
|
||||
bool ScrollToLine(uint32 line);
|
||||
|
||||
@ -80,8 +84,10 @@ class SourceView::Listener {
|
||||
public:
|
||||
virtual ~Listener();
|
||||
|
||||
// virtual void StackFrameSelectionChanged(
|
||||
// StackFrame* frame) = 0;
|
||||
virtual void SetBreakpointRequested(
|
||||
target_addr_t address, bool enabled) = 0;
|
||||
virtual void ClearBreakpointRequested(
|
||||
target_addr_t address) = 0;
|
||||
};
|
||||
|
||||
|
||||
|
@ -24,7 +24,6 @@
|
||||
#include "SourceCode.h"
|
||||
#include "StackTrace.h"
|
||||
#include "StackTraceView.h"
|
||||
#include "TeamDebugModel.h"
|
||||
|
||||
|
||||
// #pragma mark - TeamWindow
|
||||
@ -58,6 +57,7 @@ TeamWindow::TeamWindow(TeamDebugModel* debugModel, Listener* listener)
|
||||
name << " (" << team->ID() << ")";
|
||||
SetTitle(name.String());
|
||||
|
||||
fDebugModel->AddListener(this);
|
||||
team->AddListener(this);
|
||||
}
|
||||
|
||||
@ -72,6 +72,7 @@ TeamWindow::~TeamWindow()
|
||||
fSourceView->UnsetListener();
|
||||
|
||||
fDebugModel->GetTeam()->RemoveListener(this);
|
||||
fDebugModel->RemoveListener(this);
|
||||
|
||||
if (fActiveSourceCode != NULL)
|
||||
fActiveSourceCode->RemoveReference();
|
||||
@ -144,9 +145,20 @@ TeamWindow::MessageReceived(BMessage* message)
|
||||
break;
|
||||
}
|
||||
|
||||
case MSG_USER_BREAKPOINT_CHANGED:
|
||||
{
|
||||
uint64 address;
|
||||
if (message->FindUInt64("address", &address) != B_OK)
|
||||
break;
|
||||
|
||||
_HandleUserBreakpointChanged(address);
|
||||
break;
|
||||
}
|
||||
|
||||
case MSG_STACK_FRAME_SOURCE_CODE_CHANGED:
|
||||
{
|
||||
_HandleSourceCodeChanged();
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
@ -177,6 +189,20 @@ TeamWindow::StackFrameSelectionChanged(StackFrame* frame)
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TeamWindow::SetBreakpointRequested(target_addr_t address, bool enabled)
|
||||
{
|
||||
fListener->SetBreakpointRequested(address, enabled);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TeamWindow::ClearBreakpointRequested(target_addr_t address)
|
||||
{
|
||||
fListener->ClearBreakpointRequested(address);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TeamWindow::ThreadStateChanged(const Team::ThreadEvent& event)
|
||||
{
|
||||
@ -204,6 +230,16 @@ TeamWindow::ThreadStackTraceChanged(const Team::ThreadEvent& event)
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
TeamWindow::UserBreakpointChanged(const TeamDebugModel::BreakpointEvent& event)
|
||||
{
|
||||
BMessage message(MSG_USER_BREAKPOINT_CHANGED);
|
||||
message.AddUInt64("address", event.GetBreakpoint()->Address());
|
||||
PostMessage(&message);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TeamWindow::StackFrameSourceCodeChanged(StackFrame* frame)
|
||||
{
|
||||
@ -520,6 +556,13 @@ TeamWindow::_HandleSourceCodeChanged()
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TeamWindow::_HandleUserBreakpointChanged(target_addr_t address)
|
||||
{
|
||||
fSourceView->UserBreakpointChanged(address);
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - Listener
|
||||
|
||||
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "StackFrame.h"
|
||||
#include "StackTraceView.h"
|
||||
#include "Team.h"
|
||||
#include "TeamDebugModel.h"
|
||||
#include "ThreadListView.h"
|
||||
|
||||
|
||||
@ -20,12 +21,11 @@ class BTabView;
|
||||
class ImageListView;
|
||||
class RegisterView;
|
||||
class SourceCode;
|
||||
class TeamDebugModel;
|
||||
|
||||
|
||||
class TeamWindow : public BWindow, private ThreadListView::Listener,
|
||||
StackTraceView::Listener, SourceView::Listener, Team::Listener,
|
||||
StackFrame::Listener {
|
||||
private TeamDebugModel::Listener, StackFrame::Listener {
|
||||
public:
|
||||
class Listener;
|
||||
|
||||
@ -48,8 +48,10 @@ private:
|
||||
// StackTraceView::Listener
|
||||
virtual void StackFrameSelectionChanged(StackFrame* frame);
|
||||
|
||||
// StackTraceView::Listener
|
||||
// nothing yet
|
||||
// SourceView::Listener
|
||||
virtual void SetBreakpointRequested(target_addr_t address,
|
||||
bool enabled);
|
||||
virtual void ClearBreakpointRequested(target_addr_t address);
|
||||
|
||||
// Team::Listener
|
||||
virtual void ThreadStateChanged(
|
||||
@ -59,6 +61,11 @@ private:
|
||||
virtual void ThreadStackTraceChanged(
|
||||
const Team::ThreadEvent& event);
|
||||
|
||||
// TeamDebugModel::Listener
|
||||
virtual void UserBreakpointChanged(
|
||||
const TeamDebugModel::BreakpointEvent&
|
||||
event);
|
||||
|
||||
// StackFrame::Listener
|
||||
virtual void StackFrameSourceCodeChanged(StackFrame* frame);
|
||||
|
||||
@ -75,6 +82,8 @@ private:
|
||||
void _HandleCpuStateChanged(thread_id threadID);
|
||||
void _HandleStackTraceChanged(thread_id threadID);
|
||||
void _HandleSourceCodeChanged();
|
||||
void _HandleUserBreakpointChanged(
|
||||
target_addr_t address);
|
||||
|
||||
private:
|
||||
TeamDebugModel* fDebugModel;
|
||||
@ -105,6 +114,10 @@ public:
|
||||
TeamWindow* window, StackFrame* frame) = 0;
|
||||
virtual void ThreadActionRequested(TeamWindow* window,
|
||||
thread_id threadID, uint32 action) = 0;
|
||||
virtual void SetBreakpointRequested(target_addr_t address,
|
||||
bool enabled) = 0;
|
||||
virtual void ClearBreakpointRequested(
|
||||
target_addr_t address) = 0;
|
||||
virtual bool TeamWindowQuitRequested(TeamWindow* window) = 0;
|
||||
};
|
||||
|
||||
|
93
src/apps/debugger/model/Breakpoint.cpp
Normal file
93
src/apps/debugger/model/Breakpoint.cpp
Normal file
@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
#include "Breakpoint.h"
|
||||
|
||||
|
||||
// #pragma mark - BreakpointClient
|
||||
|
||||
|
||||
BreakpointClient::~BreakpointClient()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - Breakpoint
|
||||
|
||||
|
||||
Breakpoint::Breakpoint(Image* image, target_addr_t address)
|
||||
:
|
||||
fAddress(address),
|
||||
fImage(image),
|
||||
fUserState(USER_BREAKPOINT_NONE),
|
||||
fInstalled(false)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
Breakpoint::~Breakpoint()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Breakpoint::SetUserState(user_breakpoint_state state)
|
||||
{
|
||||
fUserState = state;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Breakpoint::SetInstalled(bool installed)
|
||||
{
|
||||
fInstalled = installed;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Breakpoint::ShouldBeInstalled() const
|
||||
{
|
||||
return fUserState == USER_BREAKPOINT_ENABLED || !fClients.IsEmpty();
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Breakpoint::IsUnused() const
|
||||
{
|
||||
return fUserState == USER_BREAKPOINT_NONE && fClients.IsEmpty();
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Breakpoint::AddClient(BreakpointClient* client)
|
||||
{
|
||||
return fClients.AddItem(client);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Breakpoint::RemoveClient(BreakpointClient* client)
|
||||
{
|
||||
fClients.RemoveItem(client);
|
||||
}
|
||||
|
||||
|
||||
/*static*/ int
|
||||
Breakpoint::CompareBreakpoints(const Breakpoint* a, const Breakpoint* b)
|
||||
{
|
||||
if (a->Address() < b->Address())
|
||||
return -1;
|
||||
return a->Address() == b->Address() ? 0 : 1;
|
||||
}
|
||||
|
||||
|
||||
/*static*/ int
|
||||
Breakpoint::CompareAddressBreakpoint(const target_addr_t* address,
|
||||
const Breakpoint* breakpoint)
|
||||
{
|
||||
if (*address < breakpoint->Address())
|
||||
return -1;
|
||||
return *address == breakpoint->Address() ? 0 : 1;
|
||||
}
|
68
src/apps/debugger/model/Breakpoint.h
Normal file
68
src/apps/debugger/model/Breakpoint.h
Normal file
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef BREAKPOINT_H
|
||||
#define BREAKPOINT_H
|
||||
|
||||
#include <ObjectList.h>
|
||||
#include <Referenceable.h>
|
||||
|
||||
#include "ArchitectureTypes.h"
|
||||
|
||||
|
||||
enum user_breakpoint_state {
|
||||
USER_BREAKPOINT_NONE,
|
||||
USER_BREAKPOINT_ENABLED,
|
||||
USER_BREAKPOINT_DISABLED
|
||||
};
|
||||
|
||||
|
||||
class Image;
|
||||
|
||||
|
||||
class BreakpointClient {
|
||||
public:
|
||||
virtual ~BreakpointClient();
|
||||
};
|
||||
|
||||
|
||||
class Breakpoint : public Referenceable {
|
||||
public:
|
||||
Breakpoint(Image* image, target_addr_t address);
|
||||
~Breakpoint();
|
||||
|
||||
Image* GetImage() const { return fImage; }
|
||||
target_addr_t Address() const { return fAddress; }
|
||||
|
||||
user_breakpoint_state UserState() const { return fUserState; }
|
||||
void SetUserState(user_breakpoint_state state);
|
||||
|
||||
bool IsInstalled() const { return fInstalled; }
|
||||
void SetInstalled(bool installed);
|
||||
|
||||
bool ShouldBeInstalled() const;
|
||||
bool IsUnused() const;
|
||||
|
||||
bool AddClient(BreakpointClient* client);
|
||||
void RemoveClient(BreakpointClient* client);
|
||||
|
||||
static int CompareBreakpoints(const Breakpoint* a,
|
||||
const Breakpoint* b);
|
||||
static int CompareAddressBreakpoint(
|
||||
const target_addr_t* address,
|
||||
const Breakpoint* breakpoint);
|
||||
|
||||
private:
|
||||
typedef BObjectList<BreakpointClient> ClientList;
|
||||
|
||||
private:
|
||||
target_addr_t fAddress;
|
||||
Image* fImage;
|
||||
ClientList fClients;
|
||||
user_breakpoint_state fUserState;
|
||||
bool fInstalled;
|
||||
};
|
||||
|
||||
|
||||
#endif // BREAKPOINT_H
|
@ -86,6 +86,20 @@ DisassembledCode::StatementAtAddress(target_addr_t address) const
|
||||
}
|
||||
|
||||
|
||||
TargetAddressRange
|
||||
DisassembledCode::StatementAddressRange() const
|
||||
{
|
||||
if (fStatements.IsEmpty())
|
||||
return TargetAddressRange();
|
||||
|
||||
ContiguousStatement* first = fStatements.ItemAt(0);
|
||||
ContiguousStatement* last
|
||||
= fStatements.ItemAt(fStatements.CountItems() - 1);
|
||||
return TargetAddressRange(first->AddressRange().Start(),
|
||||
last->AddressRange().End());
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
DisassembledCode::AddCommentLine(const BString& line)
|
||||
{
|
||||
@ -101,8 +115,7 @@ DisassembledCode::AddInstructionLine(const BString& line, target_addr_t address,
|
||||
|
||||
ContiguousStatement* statement = new(std::nothrow) ContiguousStatement(
|
||||
SourceLocation(lineIndex), SourceLocation(lineIndex + 1),
|
||||
TargetAddressRange(address, size));
|
||||
// TODO: breakpointAllowed!
|
||||
TargetAddressRange(address, size), breakpointAllowed);
|
||||
if (statement == NULL)
|
||||
return false;
|
||||
|
||||
|
@ -27,6 +27,8 @@ public:
|
||||
virtual Statement* StatementAtLine(int32 index) const;
|
||||
virtual Statement* StatementAtAddress(target_addr_t address) const;
|
||||
|
||||
virtual TargetAddressRange StatementAddressRange() const;
|
||||
|
||||
public:
|
||||
bool AddCommentLine(const BString& line);
|
||||
bool AddInstructionLine(const BString& line,
|
||||
|
@ -7,7 +7,7 @@
|
||||
|
||||
#include <Referenceable.h>
|
||||
|
||||
#include "ArchitectureTypes.h"
|
||||
#include "TargetAddressRange.h"
|
||||
|
||||
|
||||
class Statement;
|
||||
@ -25,6 +25,8 @@ public:
|
||||
virtual Statement* StatementAtLine(int32 index) const = 0;
|
||||
virtual Statement* StatementAtAddress(target_addr_t address)
|
||||
const = 0;
|
||||
|
||||
virtual TargetAddressRange StatementAddressRange() const = 0;
|
||||
};
|
||||
|
||||
|
||||
|
@ -18,10 +18,11 @@ Statement::~Statement()
|
||||
|
||||
|
||||
AbstractStatement::AbstractStatement(const SourceLocation& start,
|
||||
const SourceLocation& end)
|
||||
const SourceLocation& end, bool breakpointAllowed)
|
||||
:
|
||||
fStart(start),
|
||||
fEnd(end)
|
||||
fEnd(end),
|
||||
fBreakpointAllowed(breakpointAllowed)
|
||||
{
|
||||
}
|
||||
|
||||
@ -40,13 +41,21 @@ AbstractStatement::EndSourceLocation() const
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
AbstractStatement::BreakpointAllowed() const
|
||||
{
|
||||
return fBreakpointAllowed;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - ContiguousStatement
|
||||
|
||||
|
||||
ContiguousStatement::ContiguousStatement(const SourceLocation& start,
|
||||
const SourceLocation& end, const TargetAddressRange& range)
|
||||
const SourceLocation& end, const TargetAddressRange& range,
|
||||
bool breakpointAllowed)
|
||||
:
|
||||
AbstractStatement(start, end),
|
||||
AbstractStatement(start, end, breakpointAllowed),
|
||||
fRange(range)
|
||||
{
|
||||
}
|
||||
|
@ -26,20 +26,26 @@ public:
|
||||
|
||||
virtual bool ContainsAddress(target_addr_t address)
|
||||
const = 0;
|
||||
|
||||
virtual bool BreakpointAllowed() const = 0;
|
||||
};
|
||||
|
||||
|
||||
class AbstractStatement : public Statement {
|
||||
public:
|
||||
AbstractStatement(const SourceLocation& start,
|
||||
const SourceLocation& end);
|
||||
const SourceLocation& end,
|
||||
bool breakpointAllowed);
|
||||
|
||||
virtual SourceLocation StartSourceLocation() const;
|
||||
virtual SourceLocation EndSourceLocation() const;
|
||||
|
||||
virtual bool BreakpointAllowed() const;
|
||||
|
||||
protected:
|
||||
SourceLocation fStart;
|
||||
SourceLocation fEnd;
|
||||
bool fBreakpointAllowed;
|
||||
};
|
||||
|
||||
|
||||
@ -47,7 +53,8 @@ class ContiguousStatement : public AbstractStatement {
|
||||
public:
|
||||
ContiguousStatement(const SourceLocation& start,
|
||||
const SourceLocation& end,
|
||||
const TargetAddressRange& range);
|
||||
const TargetAddressRange& range,
|
||||
bool breakpointAllowed);
|
||||
|
||||
const TargetAddressRange& AddressRange() const
|
||||
{ return fRange; }
|
||||
|
@ -9,6 +9,30 @@
|
||||
|
||||
#include <AutoLocker.h>
|
||||
|
||||
#include "Breakpoint.h"
|
||||
|
||||
|
||||
// #pragma mark - BreakpointByAddressPredicate
|
||||
|
||||
|
||||
struct TeamDebugModel::BreakpointByAddressPredicate
|
||||
: UnaryPredicate<Breakpoint> {
|
||||
BreakpointByAddressPredicate(target_addr_t address)
|
||||
:
|
||||
fAddress(address)
|
||||
{
|
||||
}
|
||||
|
||||
virtual int operator()(const Breakpoint* breakpoint) const
|
||||
{
|
||||
return -Breakpoint::CompareAddressBreakpoint(&fAddress, breakpoint);
|
||||
}
|
||||
|
||||
private:
|
||||
target_addr_t fAddress;
|
||||
};
|
||||
|
||||
|
||||
|
||||
// #pragma mark - TeamDebugModel
|
||||
|
||||
@ -25,6 +49,8 @@ TeamDebugModel::TeamDebugModel(Team* team, DebuggerInterface* debuggerInterface,
|
||||
|
||||
TeamDebugModel::~TeamDebugModel()
|
||||
{
|
||||
for (int32 i = 0; Breakpoint* breakpoint = fBreakpoints.ItemAt(i); i++)
|
||||
breakpoint->RemoveReference();
|
||||
}
|
||||
|
||||
|
||||
@ -35,6 +61,66 @@ TeamDebugModel::Init()
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
TeamDebugModel::AddBreakpoint(Breakpoint* breakpoint)
|
||||
{
|
||||
if (fBreakpoints.BinaryInsert(breakpoint, &Breakpoint::CompareBreakpoints))
|
||||
return true;
|
||||
|
||||
breakpoint->RemoveReference();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TeamDebugModel::RemoveBreakpoint(Breakpoint* breakpoint)
|
||||
{
|
||||
int32 index = fBreakpoints.BinarySearchIndex(*breakpoint,
|
||||
&Breakpoint::CompareBreakpoints);
|
||||
if (index < 0)
|
||||
return;
|
||||
|
||||
fBreakpoints.RemoveItemAt(index);
|
||||
breakpoint->RemoveReference();
|
||||
}
|
||||
|
||||
|
||||
int32
|
||||
TeamDebugModel::CountBreakpoints() const
|
||||
{
|
||||
return fBreakpoints.CountItems();
|
||||
}
|
||||
|
||||
|
||||
Breakpoint*
|
||||
TeamDebugModel::BreakpointAt(int32 index) const
|
||||
{
|
||||
return fBreakpoints.ItemAt(index);
|
||||
}
|
||||
|
||||
|
||||
Breakpoint*
|
||||
TeamDebugModel::BreakpointAtAddress(target_addr_t address) const
|
||||
{
|
||||
return fBreakpoints.BinarySearchByKey(address,
|
||||
&Breakpoint::CompareAddressBreakpoint);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TeamDebugModel::GetBreakpointsInAddressRange(TargetAddressRange range,
|
||||
BObjectList<Breakpoint>& breakpoints) const
|
||||
{
|
||||
int32 index = fBreakpoints.FindBinaryInsertionIndex(
|
||||
BreakpointByAddressPredicate(range.Start()));
|
||||
for (; Breakpoint* breakpoint = fBreakpoints.ItemAt(index); index++) {
|
||||
if (breakpoint->Address() > range.End())
|
||||
break;
|
||||
breakpoints.AddItem(breakpoint);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TeamDebugModel::AddListener(Listener* listener)
|
||||
{
|
||||
@ -51,6 +137,39 @@ TeamDebugModel::RemoveListener(Listener* listener)
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TeamDebugModel::NotifyUserBreakpointChanged(Breakpoint* breakpoint)
|
||||
{
|
||||
for (ListenerList::Iterator it = fListeners.GetIterator();
|
||||
Listener* listener = it.Next();) {
|
||||
listener->UserBreakpointChanged(BreakpointEvent(
|
||||
TEAM_DEBUG_MODEL_EVENT_USER_BREAKPOINT_CHANGED, this, breakpoint));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TeamDebugModel::_NotifyBreakpointAdded(Breakpoint* breakpoint)
|
||||
{
|
||||
for (ListenerList::Iterator it = fListeners.GetIterator();
|
||||
Listener* listener = it.Next();) {
|
||||
listener->BreakpointAdded(BreakpointEvent(
|
||||
TEAM_DEBUG_MODEL_EVENT_BREAKPOINT_ADDED, this, breakpoint));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TeamDebugModel::_NotifyBreakpointRemoved(Breakpoint* breakpoint)
|
||||
{
|
||||
for (ListenerList::Iterator it = fListeners.GetIterator();
|
||||
Listener* listener = it.Next();) {
|
||||
listener->BreakpointRemoved(BreakpointEvent(
|
||||
TEAM_DEBUG_MODEL_EVENT_BREAKPOINT_REMOVED, this, breakpoint));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - Event
|
||||
|
||||
|
||||
@ -62,9 +181,42 @@ TeamDebugModel::Event::Event(uint32 type, TeamDebugModel* model)
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - ThreadEvent
|
||||
|
||||
|
||||
TeamDebugModel::BreakpointEvent::BreakpointEvent(uint32 type,
|
||||
TeamDebugModel* model, Breakpoint* breakpoint)
|
||||
:
|
||||
Event(type, model),
|
||||
fBreakpoint(breakpoint)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - Listener
|
||||
|
||||
|
||||
TeamDebugModel::Listener::~Listener()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TeamDebugModel::Listener::BreakpointAdded(
|
||||
const TeamDebugModel::BreakpointEvent& event)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TeamDebugModel::Listener::BreakpointRemoved(
|
||||
const TeamDebugModel::BreakpointEvent& event)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TeamDebugModel::Listener::UserBreakpointChanged(
|
||||
const TeamDebugModel::BreakpointEvent& event)
|
||||
{
|
||||
}
|
||||
|
@ -5,22 +5,30 @@
|
||||
#ifndef TEAM_DEBUG_MODEL_H
|
||||
#define TEAM_DEBUG_MODEL_H
|
||||
|
||||
#include <ObjectList.h>
|
||||
|
||||
#include "Breakpoint.h"
|
||||
#include "TargetAddressRange.h"
|
||||
#include "Team.h"
|
||||
|
||||
|
||||
// team debug model event types
|
||||
//enum {
|
||||
// TEAM_EVENT_THREAD_ADDED
|
||||
//};
|
||||
enum {
|
||||
TEAM_DEBUG_MODEL_EVENT_BREAKPOINT_ADDED,
|
||||
TEAM_DEBUG_MODEL_EVENT_BREAKPOINT_REMOVED,
|
||||
TEAM_DEBUG_MODEL_EVENT_USER_BREAKPOINT_CHANGED
|
||||
};
|
||||
|
||||
|
||||
class Architecture;
|
||||
class Breakpoint;
|
||||
class DebuggerInterface;
|
||||
|
||||
|
||||
class TeamDebugModel {
|
||||
public:
|
||||
class Event;
|
||||
class BreakpointEvent;
|
||||
class Listener;
|
||||
|
||||
public:
|
||||
@ -40,16 +48,40 @@ public:
|
||||
Architecture* GetArchitecture() const
|
||||
{ return fArchitecture; }
|
||||
|
||||
bool AddBreakpoint(Breakpoint* breakpoint);
|
||||
// takes over reference (also on error)
|
||||
void RemoveBreakpoint(Breakpoint* breakpoint);
|
||||
// releases its own reference
|
||||
int32 CountBreakpoints() const;
|
||||
Breakpoint* BreakpointAt(int32 index) const;
|
||||
Breakpoint* BreakpointAtAddress(
|
||||
target_addr_t address) const;
|
||||
void GetBreakpointsInAddressRange(
|
||||
TargetAddressRange range,
|
||||
BObjectList<Breakpoint>& breakpoints) const;
|
||||
|
||||
void AddListener(Listener* listener);
|
||||
void RemoveListener(Listener* listener);
|
||||
|
||||
void NotifyUserBreakpointChanged(
|
||||
Breakpoint* breakpoint);
|
||||
|
||||
private:
|
||||
struct BreakpointByAddressPredicate;
|
||||
|
||||
typedef BObjectList<Breakpoint> BreakpointList;
|
||||
typedef DoublyLinkedList<Listener> ListenerList;
|
||||
|
||||
private:
|
||||
void _NotifyBreakpointAdded(Breakpoint* breakpoint);
|
||||
void _NotifyBreakpointRemoved(
|
||||
Breakpoint* breakpoint);
|
||||
|
||||
private:
|
||||
Team* fTeam;
|
||||
DebuggerInterface* fDebuggerInterface;
|
||||
Architecture* fArchitecture;
|
||||
BreakpointList fBreakpoints;
|
||||
ListenerList fListeners;
|
||||
};
|
||||
|
||||
@ -67,13 +99,33 @@ protected:
|
||||
};
|
||||
|
||||
|
||||
class TeamDebugModel::BreakpointEvent : public Event {
|
||||
public:
|
||||
BreakpointEvent(uint32 type,
|
||||
TeamDebugModel* model,
|
||||
Breakpoint* breakpoint);
|
||||
|
||||
Breakpoint* GetBreakpoint() const { return fBreakpoint; }
|
||||
|
||||
protected:
|
||||
Breakpoint* fBreakpoint;
|
||||
};
|
||||
|
||||
|
||||
class TeamDebugModel::Listener
|
||||
: public DoublyLinkedListLinkImpl<TeamDebugModel::Listener> {
|
||||
public:
|
||||
virtual ~Listener();
|
||||
|
||||
// virtual void ThreadAdded(const Team::ThreadEvent& event);
|
||||
virtual void BreakpointAdded(
|
||||
const TeamDebugModel::BreakpointEvent&
|
||||
event);
|
||||
virtual void BreakpointRemoved(
|
||||
const TeamDebugModel::BreakpointEvent&
|
||||
event);
|
||||
virtual void UserBreakpointChanged(
|
||||
const TeamDebugModel::BreakpointEvent&
|
||||
event);
|
||||
};
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user