* 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:
@@ -52,6 +52,7 @@ Application Debugger :
|
||||
DebuggerInterface.cpp
|
||||
|
||||
# gui/team_window
|
||||
ImageFunctionsView.cpp
|
||||
ImageListView.cpp
|
||||
RegisterView.cpp
|
||||
SourceView.cpp
|
||||
|
||||
+67
-22
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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()
|
||||
{
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user