* Added support for loading the debug info for an image lazily and adjusted

the jobs accordingly.
* Added a view to list the source files and functions for an image.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@31271 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Ingo Weinhold
2009-06-27 16:49:55 +00:00
parent 90011666aa
commit 93b6484548
17 changed files with 835 additions and 84 deletions
+1
View File
@@ -52,6 +52,7 @@ Application Debugger :
DebuggerInterface.cpp
# gui/team_window
ImageFunctionsView.cpp
ImageListView.cpp
RegisterView.cpp
SourceView.cpp
+67 -22
View File
@@ -180,28 +180,22 @@ GetStackTraceJob::GetImageDebugInfo(Image* image, ImageDebugInfo*& _info)
AutoLocker<Team> teamLocker(fThread->GetTeam());
while (image->GetImageDebugInfo() == NULL) {
// The info has not yet been loaded -- check whether a job has already
// been scheduled.
AutoLocker<Worker> workerLocker(GetWorker());
JobKey key(image, JOB_TYPE_LOAD_IMAGE_DEBUG_INFO);
Job* loadImageDebugInfoJob = GetWorker()->GetJob(key);
if (loadImageDebugInfoJob == NULL) {
// no job yet -- schedule one
loadImageDebugInfoJob = new(std::nothrow) LoadImageDebugInfoJob(
fDebuggerInterface, fArchitecture, image);
if (loadImageDebugInfoJob == NULL)
return B_NO_MEMORY;
// schedule a job, if not loaded
ImageDebugInfo* info;
status_t error = LoadImageDebugInfoJob::ScheduleIfNecessary(
fDebuggerInterface, fArchitecture, GetWorker(), image, &info);
if (error != B_OK)
return error;
status_t error = GetWorker()->ScheduleJob(loadImageDebugInfoJob);
if (error != B_OK)
return error;
if (info != NULL) {
_info = info;
return B_OK;
}
workerLocker.Unlock();
teamLocker.Unlock();
// wait for the job to finish
switch (WaitFor(key)) {
switch (WaitFor(JobKey(image, JOB_TYPE_LOAD_IMAGE_DEBUG_INFO))) {
case JOB_DEPENDENCY_SUCCEEDED:
case JOB_DEPENDENCY_NOT_FOUND:
// "Not found" can happen due to a race condition between
@@ -262,19 +256,70 @@ LoadImageDebugInfoJob::Do()
// create the debug info
ImageDebugInfo* debugInfo = new(std::nothrow) ImageDebugInfo(imageInfo,
fDebuggerInterface, fArchitecture);
if (debugInfo == NULL)
status_t error;;
if (debugInfo != NULL)
error = debugInfo->Init();
else
error = B_NO_MEMORY;
// set the result
locker.Lock();
if (error == B_OK) {
fImage->SetImageDebugInfo(debugInfo, IMAGE_DEBUG_INFO_LOADED);
debugInfo->RemoveReference();
} else {
fImage->SetImageDebugInfo(NULL, IMAGE_DEBUG_INFO_UNAVAILABLE);
delete debugInfo;
}
return error;
}
/*static*/ status_t
LoadImageDebugInfoJob::ScheduleIfNecessary(DebuggerInterface* debuggerInterface,
Architecture* architecture, Worker* worker, Image* image,
ImageDebugInfo** _imageDebugInfo)
{
AutoLocker<Team> teamLocker(image->GetTeam());
// If already loaded, we're done.
if (image->GetImageDebugInfo() != NULL) {
if (_imageDebugInfo != NULL) {
*_imageDebugInfo = image->GetImageDebugInfo();
(*_imageDebugInfo)->AddReference();
}
return B_OK;
}
// If already loading, the caller has to wait, if desired.
if (image->ImageDebugInfoState() == IMAGE_DEBUG_INFO_LOADING) {
if (_imageDebugInfo != NULL)
*_imageDebugInfo = NULL;
return B_OK;
}
// If an earlier load attempt failed, bail out.
if (image->ImageDebugInfoState() != IMAGE_DEBUG_INFO_NOT_LOADED)
return B_ERROR;
// schedule a job
LoadImageDebugInfoJob* job = new(std::nothrow) LoadImageDebugInfoJob(
debuggerInterface, architecture, image);
if (job == NULL)
return B_NO_MEMORY;
status_t error = debugInfo->Init();
status_t error = worker->ScheduleJob(job);
if (error != B_OK) {
delete debugInfo;
image->SetImageDebugInfo(NULL, IMAGE_DEBUG_INFO_UNAVAILABLE);
return error;
}
// set the info
locker.Lock();
fImage->SetImageDebugInfo(debugInfo);
image->SetImageDebugInfo(NULL, IMAGE_DEBUG_INFO_LOADING);
if (_imageDebugInfo != NULL)
*_imageDebugInfo = NULL;
return B_OK;
}
+13
View File
@@ -95,6 +95,19 @@ public:
virtual JobKey Key() const;
virtual status_t Do();
static status_t ScheduleIfNecessary(
DebuggerInterface* debuggerInterface,
Architecture* architecture, Worker* worker,
Image* image,
ImageDebugInfo** _imageDebugInfo = NULL);
// If already loaded returns a
// reference, if desired. If not loaded
// schedules a job, but does not wait;
// returns B_OK and NULL. An error,
// if scheduling the job failed, or the
// debug info already failed to load
// earlier.
private:
DebuggerInterface* fDebuggerInterface;
Architecture* fArchitecture;
+1
View File
@@ -18,6 +18,7 @@ enum {
MSG_THREAD_STATE_CHANGED = 'tsch',
MSG_THREAD_CPU_STATE_CHANGED = 'tcsc',
MSG_THREAD_STACK_TRACE_CHANGED = 'tstc',
MSG_IMAGE_DEBUG_INFO_CHANGED = 'idic',
MSG_FUNCTION_SOURCE_CODE_CHANGED = 'fnsc',
MSG_USER_BREAKPOINT_CHANGED = 'ubrc',
MSG_DEBUGGER_EVENT = 'dbge',
+8
View File
@@ -348,6 +348,14 @@ TeamDebugger::FunctionSourceCodeRequested(TeamWindow* window,
}
void
TeamDebugger::ImageDebugInfoRequested(TeamWindow* window, Image* image)
{
LoadImageDebugInfoJob::ScheduleIfNecessary(fDebuggerInterface,
fDebuggerInterface->GetArchitecture(), fWorker, image);
}
void
TeamDebugger::ThreadActionRequested(TeamWindow* window, thread_id threadID,
uint32 action)
+2
View File
@@ -41,6 +41,8 @@ private:
// TeamWindow::Listener
virtual void FunctionSourceCodeRequested(TeamWindow* window,
FunctionDebugInfo* function);
virtual void ImageDebugInfoRequested(TeamWindow* window,
Image* image);
virtual void ThreadActionRequested(TeamWindow* window,
thread_id threadID, uint32 action);
virtual void SetBreakpointRequested(target_addr_t address,
@@ -0,0 +1,400 @@
/*
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#include "ImageFunctionsView.h"
#include <stdio.h>
#include <algorithm>
#include <new>
#include <AutoDeleter.h>
#include "table/TableColumns.h"
#include "FunctionDebugInfo.h"
#include "Image.h"
#include "ImageDebugInfo.h"
// #pragma mark - FunctionsTableModel
class ImageFunctionsView::FunctionsTableModel : public TreeTableModel {
public:
FunctionsTableModel()
:
fImageDebugInfo(NULL),
fFunctions(NULL),
fFunctionCount(0),
fSourceFileIndices(NULL),
fSourceFileCount(0)
{
}
~FunctionsTableModel()
{
SetImageDebugInfo(NULL);
}
void SetImageDebugInfo(ImageDebugInfo* imageDebugInfo)
{
// unset old functions
if (fSourceFileIndices != NULL) {
NotifyNodesRemoved(TreeTablePath(), 0, fSourceFileCount);
delete[] fFunctions;
fFunctions = NULL;
fFunctionCount = 0;
delete[] fSourceFileIndices;
fSourceFileIndices = NULL;
fSourceFileCount = 0;
}
fImageDebugInfo = imageDebugInfo;
// set new functions
if (fImageDebugInfo == NULL || fImageDebugInfo->CountFunctions() == 0)
return;
// create an array with the functions
int32 functionCount = fImageDebugInfo->CountFunctions();
FunctionDebugInfo** functions
= new(std::nothrow) FunctionDebugInfo*[functionCount];
if (functions == NULL)
return;
ArrayDeleter<FunctionDebugInfo*> functionsDeleter(functions);
for (int32 i = 0; i < functionCount; i++)
functions[i] = fImageDebugInfo->FunctionAt(i);
// sort them
std::sort(functions, functions + functionCount, &_FunctionLess);
// count the different source files
int32 sourceFileCount = 1;
for (int32 i = 1; i < functionCount; i++) {
if (_CompareSourceFileNames(functions[i - 1]->SourceFileName(),
functions[i]->SourceFileName()) != 0) {
sourceFileCount++;
}
}
// allocate and init the indices for the source files
fSourceFileIndices = new(std::nothrow) int32[sourceFileCount];
if (fSourceFileIndices == NULL)
return;
fSourceFileCount = sourceFileCount;
fSourceFileIndices[0] = 0;
int32 sourceFileIndex = 1;
for (int32 i = 1; i < functionCount; i++) {
if (_CompareSourceFileNames(functions[i - 1]->SourceFileName(),
functions[i]->SourceFileName()) != 0) {
fSourceFileIndices[sourceFileIndex++] = 1;
}
}
fFunctions = functionsDeleter.Detach();
fFunctionCount = functionCount;
NotifyNodesAdded(TreeTablePath(), 0, fSourceFileCount);
}
virtual int32 CountColumns() const
{
return 1;
}
virtual void* Root() const
{
return (void*)this;
}
virtual int32 CountChildren(void* parent) const
{
if (parent == this)
return fSourceFileCount;
if (parent >= fSourceFileIndices
&& parent < fSourceFileIndices + fSourceFileCount) {
int32 sourceIndex = (int32*)parent - fSourceFileIndices;
int32 count;
if (sourceIndex + 1 < fSourceFileCount) {
count = fSourceFileIndices[sourceIndex + 1]
- fSourceFileIndices[sourceIndex];
} else
count = fFunctionCount - fSourceFileIndices[sourceIndex];
return count;
}
return 0;
}
virtual void* ChildAt(void* parent, int32 index) const
{
if (parent == this) {
return index >= 0 && index < fSourceFileCount
? fSourceFileIndices + index : NULL;
}
if (parent >= fSourceFileIndices
&& parent < fSourceFileIndices + fSourceFileCount) {
int32 sourceIndex = (int32*)parent - fSourceFileIndices;
int32 count;
if (sourceIndex + 1 < fSourceFileCount) {
count = fSourceFileIndices[sourceIndex + 1]
- fSourceFileIndices[sourceIndex];
} else
count = fFunctionCount - fSourceFileIndices[sourceIndex];
return index >= 0 && index < count ? fFunctions[index] : NULL;
}
return NULL;
}
virtual bool GetValueAt(void* object, int32 columnIndex, BVariant& value)
{
if (columnIndex != 0)
return false;
if (object == this)
return false;
if (object >= fSourceFileIndices
&& object < fSourceFileIndices + fSourceFileCount) {
const char* name = fFunctions[*(int32*)object]->SourceFileName();
value.SetTo(name != NULL ? name : "<no source file>",
B_VARIANT_DONT_COPY_DATA);
return true;
}
FunctionDebugInfo* function = (FunctionDebugInfo*)object;
value.SetTo(function->PrettyName(), B_VARIANT_DONT_COPY_DATA);
return true;
}
bool GetFunctionPath(FunctionDebugInfo* function, TreeTablePath& _path)
{
int32 index = -1;
for (int32 i = 0; i < fFunctionCount; i++) {
if (fFunctions[i] == function) {
index = i;
break;
}
}
if (index < 0)
return false;
int32 sourceIndex = fSourceFileCount - 1;
while (fSourceFileIndices[sourceIndex] > index)
sourceIndex--;
_path.Clear();
return _path.AddComponent(sourceIndex)
&& _path.AddComponent(index);
}
bool GetObjectForPath(const TreeTablePath& path, const char*& _sourceFile,
FunctionDebugInfo*& _function)
{
int32 componentCount = path.CountComponents();
if (componentCount == 0 || componentCount > 2)
return false;
int32 sourceIndex = path.ComponentAt(0);
if (sourceIndex < 0 || sourceIndex >= fSourceFileCount)
return false;
_sourceFile = fFunctions[fSourceFileIndices[sourceIndex]]
->SourceFileName();
_function = NULL;
if (componentCount == 2) {
int32 index = path.ComponentAt(1);
if (index >= 0 && index < fFunctionCount)
_function = fFunctions[index];
}
return true;
}
int32 CountSourceFiles() const
{
return fSourceFileCount;
}
private:
static int _CompareSourceFileNames(const char* a, const char* b)
{
if (a == b)
return 0;
if (a == NULL)
return false;
if (b == NULL)
return true;
return strcmp(a, b);
}
static bool _FunctionLess(const FunctionDebugInfo* a,
const FunctionDebugInfo* b)
{
// compare source file name first
int compared = _CompareSourceFileNames(a->SourceFileName(),
b->SourceFileName());
if (compared != 0)
return compared < 0;
// source file names are equal -- compare the function names
return strcasecmp(a->PrettyName(), b->PrettyName()) < 0;
}
private:
ImageDebugInfo* fImageDebugInfo;
FunctionDebugInfo** fFunctions;
int32 fFunctionCount;
int32* fSourceFileIndices;
int32 fSourceFileCount;
};
// #pragma mark - ImageFunctionsView
ImageFunctionsView::ImageFunctionsView(Listener* listener)
:
BGroupView(B_VERTICAL),
fImageDebugInfo(NULL),
fFunctionsTable(NULL),
fFunctionsTableModel(NULL),
fListener(listener)
{
SetName("Functions");
}
ImageFunctionsView::~ImageFunctionsView()
{
SetImageDebugInfo(NULL);
fFunctionsTable->SetTreeTableModel(NULL);
delete fFunctionsTableModel;
}
/*static*/ ImageFunctionsView*
ImageFunctionsView::Create(Listener* listener)
{
ImageFunctionsView* self = new ImageFunctionsView(listener);
try {
self->_Init();
} catch (...) {
delete self;
throw;
}
return self;
}
void
ImageFunctionsView::UnsetListener()
{
fListener = NULL;
}
void
ImageFunctionsView::SetImageDebugInfo(ImageDebugInfo* imageDebugInfo)
{
if (imageDebugInfo == fImageDebugInfo)
return;
printf("ImageFunctionsView::SetImageDebugInfo(%p)\n", imageDebugInfo);
if (fImageDebugInfo != NULL)
fImageDebugInfo->RemoveReference();
fImageDebugInfo = imageDebugInfo;
if (fImageDebugInfo != NULL)
fImageDebugInfo->AddReference();
fFunctionsTableModel->SetImageDebugInfo(fImageDebugInfo);
// If there's only one source file (i.e. "no source file"), expand the item.
if (fImageDebugInfo != NULL
&& fFunctionsTableModel->CountSourceFiles() == 1) {
TreeTablePath path;
path.AddComponent(0);
fFunctionsTable->SetNodeExpanded(path, true, false);
}
printf("ImageFunctionsView::SetImageDebugInfo(%p) done\n", imageDebugInfo);
}
void
ImageFunctionsView::SetFunction(FunctionDebugInfo* function)
{
printf("ImageFunctionsView::SetFunction(%p)\n", function);
TreeTablePath path;
if (fFunctionsTableModel->GetFunctionPath(function, path)) {
fFunctionsTable->SetNodeExpanded(path, true, true);
fFunctionsTable->SelectNode(path, false);
fFunctionsTable->ScrollToNode(path);
} else
fFunctionsTable->DeselectAllNodes();
}
void
ImageFunctionsView::TreeTableSelectionChanged(TreeTable* table)
{
if (fListener == NULL)
return;
const char* sourceFile = NULL;
FunctionDebugInfo* function = NULL;
TreeTablePath path;
if (table->SelectionModel()->GetPathAt(0, path))
fFunctionsTableModel->GetObjectForPath(path, sourceFile, function);
fListener->FunctionSelectionChanged(function);
}
void
ImageFunctionsView::_Init()
{
fFunctionsTable = new TreeTable("functions", 0, B_FANCY_BORDER);
AddChild(fFunctionsTable->ToView());
fFunctionsTable->SetSortingEnabled(false);
// columns
fFunctionsTable->AddColumn(new StringTableColumn(0, "File/Function", 300,
100, 1000, B_TRUNCATE_END, B_ALIGN_LEFT));
fFunctionsTableModel = new FunctionsTableModel();
fFunctionsTable->SetTreeTableModel(fFunctionsTableModel);
fFunctionsTable->SetSelectionMode(B_SINGLE_SELECTION_LIST);
fFunctionsTable->AddTreeTableListener(this);
}
// #pragma mark - Listener
ImageFunctionsView::Listener::~Listener()
{
}
@@ -0,0 +1,60 @@
/*
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#ifndef IMAGE_FUNCTIONS_VIEW_H
#define IMAGE_FUNCTIONS_VIEW_H
#include <GroupView.h>
#include "table/TreeTable.h"
#include "Team.h"
class FunctionDebugInfo;
class ImageFunctionsView : public BGroupView, private TreeTableListener {
public:
class Listener;
public:
ImageFunctionsView(Listener* listener);
~ImageFunctionsView();
static ImageFunctionsView* Create(Listener* listener);
// throws
void UnsetListener();
void SetImageDebugInfo(
ImageDebugInfo* imageDebugInfo);
void SetFunction(FunctionDebugInfo* function);
private:
class FunctionsTableModel;
private:
// TreeTableListener
virtual void TreeTableSelectionChanged(TreeTable* table);
void _Init();
private:
ImageDebugInfo* fImageDebugInfo;
TreeTable* fFunctionsTable;
FunctionsTableModel* fFunctionsTableModel;
Listener* fListener;
};
class ImageFunctionsView::Listener {
public:
virtual ~Listener();
virtual void FunctionSelectionChanged(
FunctionDebugInfo* function) = 0;
};
#endif // IMAGE_FUNCTIONS_VIEW_H
@@ -129,29 +129,34 @@ private:
// #pragma mark - ImageListView
ImageListView::ImageListView()
ImageListView::ImageListView(Team* team, Listener* listener)
:
BGroupView(B_VERTICAL),
fTeam(NULL),
fTeam(team),
fImage(NULL),
fImagesTable(NULL),
fImagesTableModel(NULL)
fImagesTableModel(NULL),
fListener(listener)
{
SetName("Images");
fTeam->AddListener(this);
}
ImageListView::~ImageListView()
{
SetTeam(NULL);
SetImage(NULL);
fTeam->RemoveListener(this);
fImagesTable->SetTableModel(NULL);
delete fImagesTableModel;
}
/*static*/ ImageListView*
ImageListView::Create()
ImageListView::Create(Team* team, Listener* listener)
{
ImageListView* self = new ImageListView;
ImageListView* self = new ImageListView(team, listener);
try {
self->_Init();
@@ -165,26 +170,38 @@ ImageListView::Create()
void
ImageListView::SetTeam(Team* team)
ImageListView::UnsetListener()
{
if (team == fTeam)
fListener = NULL;
}
void
ImageListView::SetImage(Image* image)
{
if (image == fImage)
return;
printf("ImageListView::SetImage(%p)\n", image);
if (fTeam != NULL) {
fTeam->RemoveListener(this);
fImagesTable->SetTableModel(NULL);
delete fImagesTableModel;
fImagesTableModel = NULL;
if (fImage != NULL)
fImage->RemoveReference();
fImage = image;
if (fImage != NULL) {
fImage->AddReference();
for (int32 i = 0; Image* other = fImagesTableModel->ImageAt(i); i++) {
if (fImage == other) {
fImagesTable->SelectRow(i, false);
printf("ImageListView::SetImage() done\n");
return;
}
}
}
fTeam = team;
if (fTeam != NULL) {
fImagesTableModel = new(std::nothrow) ImagesTableModel(fTeam);
fImagesTable->SetTableModel(fImagesTableModel);
fImagesTable->ResizeAllColumnsToPreferred();
fTeam->AddListener(this);
}
fImagesTable->DeselectAllRows();
printf("ImageListView::SetImage() done\n");
}
@@ -218,13 +235,18 @@ ImageListView::ImageRemoved(const Team::ImageEvent& event)
void
ImageListView::TableRowInvoked(Table* table, int32 rowIndex)
ImageListView::TableSelectionChanged(Table* table)
{
// if (fImagesTableModel != NULL) {
// Image* image = fImagesTableModel->ImageAt(rowIndex);
// if (image != NULL)
// fParent->OpenImageWindow(image);
// }
if (fListener == NULL)
return;
Image* image = NULL;
if (fImagesTableModel != NULL) {
TableSelectionModel* selectionModel = table->SelectionModel();
image = fImagesTableModel->ImageAt(selectionModel->RowAt(0));
}
fListener->ImageSelectionChanged(image);
}
@@ -241,4 +263,16 @@ ImageListView::_Init()
B_TRUNCATE_END, B_ALIGN_LEFT));
fImagesTable->AddTableListener(this);
fImagesTableModel = new ImagesTableModel(fTeam);
fImagesTable->SetTableModel(fImagesTableModel);
fImagesTable->ResizeAllColumnsToPreferred();
}
// #pragma mark - Listener
ImageListView::Listener::~Listener()
{
}
@@ -14,13 +14,18 @@
class ImageListView : public BGroupView, private Team::Listener,
private TableListener {
public:
ImageListView();
class Listener;
public:
ImageListView(Team* team, Listener* listener);
~ImageListView();
static ImageListView* Create();
static ImageListView* Create(Team* team, Listener* listener);
// throws
void SetTeam(Team* team);
void UnsetListener();
void SetImage(Image* image);
virtual void MessageReceived(BMessage* message);
@@ -33,14 +38,24 @@ private:
virtual void ImageRemoved(const Team::ImageEvent& event);
// TableListener
virtual void TableRowInvoked(Table* table, int32 rowIndex);
virtual void TableSelectionChanged(Table* table);
void _Init();
private:
Team* fTeam;
Image* fImage;
Table* fImagesTable;
ImagesTableModel* fImagesTableModel;
Listener* fListener;
};
class ImageListView::Listener {
public:
virtual ~Listener();
virtual void ImageSelectionChanged(Image* image) = 0;
};
@@ -241,7 +241,7 @@ StackTraceView::TableSelectionChanged(Table* table)
void
StackTraceView::_Init()
{
fFramesTable = new Table("register list", 0, B_FANCY_BORDER);
fFramesTable = new Table("stack trace", 0, B_FANCY_BORDER);
AddChild(fFramesTable->ToView());
fFramesTable->SetSortingEnabled(false);
@@ -18,7 +18,8 @@
#include <AutoLocker.h>
#include "CpuState.h"
#include "ImageListView.h"
#include "Image.h"
#include "ImageDebugInfo.h"
#include "MessageCodes.h"
#include "RegisterView.h"
#include "SourceCode.h"
@@ -35,6 +36,7 @@ TeamWindow::TeamWindow(TeamDebugModel* debugModel, Listener* listener)
B_ASYNCHRONOUS_CONTROLS | B_AUTO_UPDATE_SIZE_LIMITS),
fDebugModel(debugModel),
fActiveThread(NULL),
fActiveImage(NULL),
fActiveStackTrace(NULL),
fActiveStackFrame(NULL),
fActiveFunction(NULL),
@@ -44,6 +46,7 @@ TeamWindow::TeamWindow(TeamDebugModel* debugModel, Listener* listener)
fLocalsTabView(NULL),
fThreadListView(NULL),
fImageListView(NULL),
fImageFunctionsView(NULL),
fRegisterView(NULL),
fStackTraceView(NULL),
fSourceView(NULL),
@@ -79,6 +82,7 @@ TeamWindow::~TeamWindow()
_SetActiveFunction(NULL);
_SetActiveStackFrame(NULL);
_SetActiveStackTrace(NULL);
_SetActiveImage(NULL);
_SetActiveThread(NULL);
}
@@ -143,6 +147,16 @@ TeamWindow::MessageReceived(BMessage* message)
break;
}
case MSG_IMAGE_DEBUG_INFO_CHANGED:
{
int32 imageID;
if (message->FindInt32("image", &imageID) != B_OK)
break;
_HandleImageDebugInfoChanged(imageID);
break;
}
case MSG_USER_BREAKPOINT_CHANGED:
{
uint64 address;
@@ -180,6 +194,13 @@ TeamWindow::ThreadSelectionChanged(::Thread* thread)
}
void
TeamWindow::ImageSelectionChanged(Image* image)
{
_SetActiveImage(image);
}
void
TeamWindow::StackFrameSelectionChanged(StackFrame* frame)
{
@@ -187,6 +208,13 @@ TeamWindow::StackFrameSelectionChanged(StackFrame* frame)
}
void
TeamWindow::FunctionSelectionChanged(FunctionDebugInfo* function)
{
_SetActiveFunction(function);
}
void
TeamWindow::SetBreakpointRequested(target_addr_t address, bool enabled)
{
@@ -228,6 +256,15 @@ TeamWindow::ThreadStackTraceChanged(const Team::ThreadEvent& event)
}
void
TeamWindow::ImageDebugInfoChanged(const Team::ImageEvent& event)
{
BMessage message(MSG_IMAGE_DEBUG_INFO_CHANGED);
message.AddInt32("image", event.GetImage()->ID());
PostMessage(&message);
}
void
TeamWindow::UserBreakpointChanged(const TeamDebugModel::BreakpointEvent& event)
{
@@ -288,8 +325,9 @@ TeamWindow::_Init()
imagesGroup->SetName("Images");
fTabView->AddTab(imagesGroup);
BLayoutBuilder::Split<>(imagesGroup)
.Add(fImageListView = ImageListView::Create())
.Add(new BTextView("source files"));
.Add(fImageListView = ImageListView::Create(fDebugModel->GetTeam(),
this))
.Add(fImageFunctionsView = ImageFunctionsView::Create(this));
// add local variables tab
BView* tab = new BTextView("Variables");
@@ -300,7 +338,6 @@ TeamWindow::_Init()
fLocalsTabView->AddTab(tab);
fThreadListView->SetTeam(fDebugModel->GetTeam());
fImageListView->SetTeam(fDebugModel->GetTeam());
fRunButton->SetMessage(new BMessage(MSG_THREAD_RUN));
fStepOverButton->SetMessage(new BMessage(MSG_THREAD_STEP_OVER));
@@ -336,7 +373,7 @@ TeamWindow::_SetActiveThread(::Thread* thread)
StackTrace* stackTrace = fActiveThread != NULL
? fActiveThread->GetStackTrace() : NULL;
Reference<StackTrace> stackTraceReference(stackTrace);
// hold a reference until the register view has one
// hold a reference until we've set it
locker.Unlock();
@@ -345,6 +382,40 @@ TeamWindow::_SetActiveThread(::Thread* thread)
}
void
TeamWindow::_SetActiveImage(Image* image)
{
if (image == fActiveImage)
return;
if (fActiveImage != NULL)
fActiveImage->RemoveReference();
fActiveImage = image;
AutoLocker<TeamDebugModel> locker(fDebugModel);
ImageDebugInfo* imageDebugInfo = NULL;
Reference<ImageDebugInfo> imageDebugInfoReference;
if (fActiveImage != NULL) {
fActiveImage->AddReference();
imageDebugInfo = fActiveImage->GetImageDebugInfo();
imageDebugInfoReference.SetTo(imageDebugInfo);
// If the debug info is not loaded yet, request it.
if (fActiveImage->ImageDebugInfoState() == IMAGE_DEBUG_INFO_NOT_LOADED)
fListener->ImageDebugInfoRequested(this, fActiveImage);
}
locker.Unlock();
fImageListView->SetImage(fActiveImage);
fImageFunctionsView->SetImageDebugInfo(imageDebugInfo);
}
void
TeamWindow::_SetActiveStackTrace(StackTrace* stackTrace)
{
@@ -403,8 +474,21 @@ TeamWindow::_SetActiveFunction(FunctionDebugInfo* function)
fActiveFunction->RemoveReference();
}
// to avoid listener feedback problems, first unset the active function and
// set the new image, if any
locker.Unlock();
fActiveFunction = NULL;
if (function != NULL) {
_SetActiveImage(fDebugModel->GetTeam()->ImageByAddress(
function->Address()));
}
fActiveFunction = function;
locker.Lock();
SourceCode* sourceCode = NULL;
Reference<SourceCode> sourceCodeReference;
@@ -423,6 +507,8 @@ TeamWindow::_SetActiveFunction(FunctionDebugInfo* function)
locker.Unlock();
_SetActiveSourceCode(sourceCode);
fImageFunctionsView->SetFunction(fActiveFunction);
}
@@ -543,6 +629,28 @@ TeamWindow::_HandleStackTraceChanged(thread_id threadID)
}
void
TeamWindow::_HandleImageDebugInfoChanged(image_id imageID)
{
printf("TeamWindow::_HandleImageDebugInfoChanged(%ld)\n", imageID);
// We're only interested in the currently selected thread
if (fActiveImage == NULL || imageID != fActiveImage->ID())
return;
AutoLocker<TeamDebugModel> locker(fDebugModel);
ImageDebugInfo* imageDebugInfo = fActiveImage != NULL
? fActiveImage->GetImageDebugInfo() : NULL;
printf(" image debug info: %p\n", imageDebugInfo);
Reference<ImageDebugInfo> imageDebugInfoReference(imageDebugInfo);
// hold a reference until we've set it
locker.Unlock();
fImageFunctionsView->SetImageDebugInfo(imageDebugInfo);
}
void
TeamWindow::_HandleSourceCodeChanged()
{
+22 -4
View File
@@ -10,6 +10,8 @@
#include "SourceView.h"
#include "FunctionDebugInfo.h"
#include "ImageFunctionsView.h"
#include "ImageListView.h"
#include "StackTraceView.h"
#include "Team.h"
#include "TeamDebugModel.h"
@@ -19,15 +21,16 @@
class BButton;
class BTabView;
class FunctionDebugInfo;
class ImageListView;
class Image;
class RegisterView;
class SourceCode;
class StackFrame;
class TeamWindow : public BWindow, private ThreadListView::Listener,
StackTraceView::Listener, SourceView::Listener, Team::Listener,
private TeamDebugModel::Listener, FunctionDebugInfo::Listener {
class TeamWindow : public BWindow, ThreadListView::Listener,
ImageListView::Listener, StackTraceView::Listener,
ImageFunctionsView::Listener, SourceView::Listener, Team::Listener,
TeamDebugModel::Listener, FunctionDebugInfo::Listener {
public:
class Listener;
@@ -47,9 +50,16 @@ private:
// ThreadListView::Listener
virtual void ThreadSelectionChanged(::Thread* thread);
// ImageListView::Listener
virtual void ImageSelectionChanged(Image* image);
// StackTraceView::Listener
virtual void StackFrameSelectionChanged(StackFrame* frame);
// ImageFunctionsView::Listener
virtual void FunctionSelectionChanged(
FunctionDebugInfo* function);
// SourceView::Listener
virtual void SetBreakpointRequested(target_addr_t address,
bool enabled);
@@ -62,6 +72,8 @@ private:
const Team::ThreadEvent& event);
virtual void ThreadStackTraceChanged(
const Team::ThreadEvent& event);
virtual void ImageDebugInfoChanged(
const Team::ImageEvent& event);
// TeamDebugModel::Listener
virtual void UserBreakpointChanged(
@@ -75,6 +87,7 @@ private:
void _Init();
void _SetActiveThread(::Thread* thread);
void _SetActiveImage(Image* image);
void _SetActiveStackTrace(StackTrace* stackTrace);
void _SetActiveStackFrame(StackFrame* frame);
void _SetActiveFunction(FunctionDebugInfo* function);
@@ -85,6 +98,7 @@ private:
void _HandleThreadStateChanged(thread_id threadID);
void _HandleCpuStateChanged(thread_id threadID);
void _HandleStackTraceChanged(thread_id threadID);
void _HandleImageDebugInfoChanged(image_id imageID);
void _HandleSourceCodeChanged();
void _HandleUserBreakpointChanged(
target_addr_t address);
@@ -92,6 +106,7 @@ private:
private:
TeamDebugModel* fDebugModel;
::Thread* fActiveThread;
Image* fActiveImage;
StackTrace* fActiveStackTrace;
StackFrame* fActiveStackFrame;
FunctionDebugInfo* fActiveFunction;
@@ -101,6 +116,7 @@ private:
BTabView* fLocalsTabView;
ThreadListView* fThreadListView;
ImageListView* fImageListView;
ImageFunctionsView* fImageFunctionsView;
RegisterView* fRegisterView;
StackTraceView* fStackTraceView;
SourceView* fSourceView;
@@ -117,6 +133,8 @@ public:
virtual void FunctionSourceCodeRequested(TeamWindow* window,
FunctionDebugInfo* function) = 0;
virtual void ImageDebugInfoRequested(TeamWindow* window,
Image* image) = 0;
virtual void ThreadActionRequested(TeamWindow* window,
thread_id threadID, uint32 action) = 0;
virtual void SetBreakpointRequested(target_addr_t address,
+24 -17
View File
@@ -6,13 +6,15 @@
#include "Image.h"
#include "ImageDebugInfo.h"
#include "Team.h"
Image::Image(Team* team,const ImageInfo& imageInfo)
:
fTeam(team),
fInfo(imageInfo),
fDebugInfo(NULL)
fDebugInfo(NULL),
fDebugInfoState(IMAGE_DEBUG_INFO_NOT_LOADED)
{
}
@@ -31,22 +33,6 @@ Image::Init()
}
void
Image::SetImageDebugInfo(ImageDebugInfo* debugInfo)
{
if (debugInfo == fDebugInfo)
return;
if (fDebugInfo != NULL)
fDebugInfo->RemoveReference();
fDebugInfo = debugInfo;
if (fDebugInfo != NULL)
fDebugInfo->AddReference();
}
bool
Image::ContainsAddress(target_addr_t address) const
{
@@ -55,3 +41,24 @@ Image::ContainsAddress(target_addr_t address) const
|| (address >= fInfo.DataBase()
&& address < fInfo.DataBase() + fInfo.DataSize());
}
void
Image::SetImageDebugInfo(ImageDebugInfo* debugInfo,
image_debug_info_state state)
{
if (debugInfo == fDebugInfo && state == fDebugInfoState)
return;
if (fDebugInfo != NULL)
fDebugInfo->RemoveReference();
fDebugInfo = debugInfo;
fDebugInfoState = state;
if (fDebugInfo != NULL)
fDebugInfo->AddReference();
// notify listeners
fTeam->NotifyImageDebugInfoChanged(this);
}
+17 -3
View File
@@ -13,6 +13,14 @@
#include "ImageInfo.h"
enum image_debug_info_state {
IMAGE_DEBUG_INFO_NOT_LOADED,
IMAGE_DEBUG_INFO_LOADING,
IMAGE_DEBUG_INFO_LOADED,
IMAGE_DEBUG_INFO_UNAVAILABLE
};
class ImageDebugInfo;
class Team;
@@ -30,15 +38,21 @@ public:
const char* Name() const { return fInfo.Name(); }
const ImageInfo& Info() const { return fInfo; }
ImageDebugInfo* GetImageDebugInfo() const { return fDebugInfo; }
void SetImageDebugInfo(ImageDebugInfo* debugInfo);
bool ContainsAddress(target_addr_t address) const;
// mutable attributes follow (locking required)
ImageDebugInfo* GetImageDebugInfo() const { return fDebugInfo; }
image_debug_info_state ImageDebugInfoState() const
{ return fDebugInfoState; }
void SetImageDebugInfo(ImageDebugInfo* debugInfo,
image_debug_info_state state);
private:
Team* fTeam;
ImageInfo fInfo;
// mutable
ImageDebugInfo* fDebugInfo;
image_debug_info_state fDebugInfoState;
};
+17
View File
@@ -250,6 +250,17 @@ Team::NotifyThreadStackTraceChanged(Thread* thread)
}
void
Team::NotifyImageDebugInfoChanged(Image* image)
{
for (ListenerList::Iterator it = fListeners.GetIterator();
Listener* listener = it.Next();) {
listener->ImageDebugInfoChanged(
ImageEvent(TEAM_EVENT_IMAGE_DEBUG_INFO_CHANGED, image));
}
}
void
Team::_NotifyThreadAdded(Thread* thread)
{
@@ -371,3 +382,9 @@ void
Team::Listener::ThreadStackTraceChanged(const Team::ThreadEvent& event)
{
}
void
Team::Listener::ImageDebugInfoChanged(const Team::ImageEvent& event)
{
}
+9 -1
View File
@@ -22,7 +22,9 @@ enum {
TEAM_EVENT_THREAD_STATE_CHANGED,
TEAM_EVENT_THREAD_CPU_STATE_CHANGED,
TEAM_EVENT_THREAD_STACK_TRACE_CHANGED
TEAM_EVENT_THREAD_STACK_TRACE_CHANGED,
TEAM_EVENT_IMAGE_DEBUG_INFO_CHANGED
};
@@ -69,6 +71,9 @@ public:
void NotifyThreadCpuStateChanged(Thread* thread);
void NotifyThreadStackTraceChanged(Thread* thread);
// service methods for Image
void NotifyImageDebugInfoChanged(Image* image);
private:
typedef DoublyLinkedList<Listener> ListenerList;
@@ -138,6 +143,9 @@ public:
const Team::ThreadEvent& event);
virtual void ThreadStackTraceChanged(
const Team::ThreadEvent& event);
virtual void ImageDebugInfoChanged(
const Team::ImageEvent& event);
};