* 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:
Ingo Weinhold 2009-06-22 21:51:32 +00:00
parent 7c439b2356
commit 6381d6cc4e
17 changed files with 1031 additions and 61 deletions

View File

@ -57,6 +57,7 @@ Application Debugger :
ThreadListView.cpp
# model
Breakpoint.cpp
DisassembledCode.cpp
Image.cpp
ImageInfo.cpp

View File

@ -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'
};

View File

@ -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.
}

View File

@ -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;

View File

@ -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));
}

View File

@ -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;
};

View File

@ -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

View File

@ -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;
};

View 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;
}

View 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

View File

@ -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;

View File

@ -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,

View File

@ -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;
};

View File

@ -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)
{
}

View File

@ -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; }

View File

@ -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)
{
}

View File

@ -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);
};