* 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
|
DebuggerInterface.cpp
|
||||||
|
|
||||||
# gui/team_window
|
# gui/team_window
|
||||||
|
ImageFunctionsView.cpp
|
||||||
ImageListView.cpp
|
ImageListView.cpp
|
||||||
RegisterView.cpp
|
RegisterView.cpp
|
||||||
SourceView.cpp
|
SourceView.cpp
|
||||||
|
|||||||
+67
-22
@@ -180,28 +180,22 @@ GetStackTraceJob::GetImageDebugInfo(Image* image, ImageDebugInfo*& _info)
|
|||||||
AutoLocker<Team> teamLocker(fThread->GetTeam());
|
AutoLocker<Team> teamLocker(fThread->GetTeam());
|
||||||
|
|
||||||
while (image->GetImageDebugInfo() == NULL) {
|
while (image->GetImageDebugInfo() == NULL) {
|
||||||
// The info has not yet been loaded -- check whether a job has already
|
// schedule a job, if not loaded
|
||||||
// been scheduled.
|
ImageDebugInfo* info;
|
||||||
AutoLocker<Worker> workerLocker(GetWorker());
|
status_t error = LoadImageDebugInfoJob::ScheduleIfNecessary(
|
||||||
JobKey key(image, JOB_TYPE_LOAD_IMAGE_DEBUG_INFO);
|
fDebuggerInterface, fArchitecture, GetWorker(), image, &info);
|
||||||
Job* loadImageDebugInfoJob = GetWorker()->GetJob(key);
|
if (error != B_OK)
|
||||||
if (loadImageDebugInfoJob == NULL) {
|
return error;
|
||||||
// no job yet -- schedule one
|
|
||||||
loadImageDebugInfoJob = new(std::nothrow) LoadImageDebugInfoJob(
|
|
||||||
fDebuggerInterface, fArchitecture, image);
|
|
||||||
if (loadImageDebugInfoJob == NULL)
|
|
||||||
return B_NO_MEMORY;
|
|
||||||
|
|
||||||
status_t error = GetWorker()->ScheduleJob(loadImageDebugInfoJob);
|
if (info != NULL) {
|
||||||
if (error != B_OK)
|
_info = info;
|
||||||
return error;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
workerLocker.Unlock();
|
|
||||||
teamLocker.Unlock();
|
teamLocker.Unlock();
|
||||||
|
|
||||||
// wait for the job to finish
|
// 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_SUCCEEDED:
|
||||||
case JOB_DEPENDENCY_NOT_FOUND:
|
case JOB_DEPENDENCY_NOT_FOUND:
|
||||||
// "Not found" can happen due to a race condition between
|
// "Not found" can happen due to a race condition between
|
||||||
@@ -262,19 +256,70 @@ LoadImageDebugInfoJob::Do()
|
|||||||
// create the debug info
|
// create the debug info
|
||||||
ImageDebugInfo* debugInfo = new(std::nothrow) ImageDebugInfo(imageInfo,
|
ImageDebugInfo* debugInfo = new(std::nothrow) ImageDebugInfo(imageInfo,
|
||||||
fDebuggerInterface, fArchitecture);
|
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;
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
status_t error = debugInfo->Init();
|
status_t error = worker->ScheduleJob(job);
|
||||||
if (error != B_OK) {
|
if (error != B_OK) {
|
||||||
delete debugInfo;
|
image->SetImageDebugInfo(NULL, IMAGE_DEBUG_INFO_UNAVAILABLE);
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
// set the info
|
image->SetImageDebugInfo(NULL, IMAGE_DEBUG_INFO_LOADING);
|
||||||
locker.Lock();
|
|
||||||
fImage->SetImageDebugInfo(debugInfo);
|
|
||||||
|
|
||||||
|
if (_imageDebugInfo != NULL)
|
||||||
|
*_imageDebugInfo = NULL;
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -95,6 +95,19 @@ public:
|
|||||||
virtual JobKey Key() const;
|
virtual JobKey Key() const;
|
||||||
virtual status_t Do();
|
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:
|
private:
|
||||||
DebuggerInterface* fDebuggerInterface;
|
DebuggerInterface* fDebuggerInterface;
|
||||||
Architecture* fArchitecture;
|
Architecture* fArchitecture;
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ enum {
|
|||||||
MSG_THREAD_STATE_CHANGED = 'tsch',
|
MSG_THREAD_STATE_CHANGED = 'tsch',
|
||||||
MSG_THREAD_CPU_STATE_CHANGED = 'tcsc',
|
MSG_THREAD_CPU_STATE_CHANGED = 'tcsc',
|
||||||
MSG_THREAD_STACK_TRACE_CHANGED = 'tstc',
|
MSG_THREAD_STACK_TRACE_CHANGED = 'tstc',
|
||||||
|
MSG_IMAGE_DEBUG_INFO_CHANGED = 'idic',
|
||||||
MSG_FUNCTION_SOURCE_CODE_CHANGED = 'fnsc',
|
MSG_FUNCTION_SOURCE_CODE_CHANGED = 'fnsc',
|
||||||
MSG_USER_BREAKPOINT_CHANGED = 'ubrc',
|
MSG_USER_BREAKPOINT_CHANGED = 'ubrc',
|
||||||
MSG_DEBUGGER_EVENT = 'dbge',
|
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
|
void
|
||||||
TeamDebugger::ThreadActionRequested(TeamWindow* window, thread_id threadID,
|
TeamDebugger::ThreadActionRequested(TeamWindow* window, thread_id threadID,
|
||||||
uint32 action)
|
uint32 action)
|
||||||
|
|||||||
@@ -41,6 +41,8 @@ private:
|
|||||||
// TeamWindow::Listener
|
// TeamWindow::Listener
|
||||||
virtual void FunctionSourceCodeRequested(TeamWindow* window,
|
virtual void FunctionSourceCodeRequested(TeamWindow* window,
|
||||||
FunctionDebugInfo* function);
|
FunctionDebugInfo* function);
|
||||||
|
virtual void ImageDebugInfoRequested(TeamWindow* window,
|
||||||
|
Image* image);
|
||||||
virtual void ThreadActionRequested(TeamWindow* window,
|
virtual void ThreadActionRequested(TeamWindow* window,
|
||||||
thread_id threadID, uint32 action);
|
thread_id threadID, uint32 action);
|
||||||
virtual void SetBreakpointRequested(target_addr_t address,
|
virtual void SetBreakpointRequested(target_addr_t address,
|
||||||
|
|||||||
@@ -0,0 +1,400 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2009, Ingo Weinhold, [email protected].
|
||||||
|
* 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, [email protected].
|
||||||
|
* 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
|
// #pragma mark - ImageListView
|
||||||
|
|
||||||
|
|
||||||
ImageListView::ImageListView()
|
ImageListView::ImageListView(Team* team, Listener* listener)
|
||||||
:
|
:
|
||||||
BGroupView(B_VERTICAL),
|
BGroupView(B_VERTICAL),
|
||||||
fTeam(NULL),
|
fTeam(team),
|
||||||
|
fImage(NULL),
|
||||||
fImagesTable(NULL),
|
fImagesTable(NULL),
|
||||||
fImagesTableModel(NULL)
|
fImagesTableModel(NULL),
|
||||||
|
fListener(listener)
|
||||||
{
|
{
|
||||||
SetName("Images");
|
SetName("Images");
|
||||||
|
|
||||||
|
fTeam->AddListener(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
ImageListView::~ImageListView()
|
ImageListView::~ImageListView()
|
||||||
{
|
{
|
||||||
SetTeam(NULL);
|
SetImage(NULL);
|
||||||
|
fTeam->RemoveListener(this);
|
||||||
fImagesTable->SetTableModel(NULL);
|
fImagesTable->SetTableModel(NULL);
|
||||||
delete fImagesTableModel;
|
delete fImagesTableModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*static*/ ImageListView*
|
/*static*/ ImageListView*
|
||||||
ImageListView::Create()
|
ImageListView::Create(Team* team, Listener* listener)
|
||||||
{
|
{
|
||||||
ImageListView* self = new ImageListView;
|
ImageListView* self = new ImageListView(team, listener);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
self->_Init();
|
self->_Init();
|
||||||
@@ -165,26 +170,38 @@ ImageListView::Create()
|
|||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
ImageListView::SetTeam(Team* team)
|
ImageListView::UnsetListener()
|
||||||
{
|
{
|
||||||
if (team == fTeam)
|
fListener = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
ImageListView::SetImage(Image* image)
|
||||||
|
{
|
||||||
|
if (image == fImage)
|
||||||
return;
|
return;
|
||||||
|
printf("ImageListView::SetImage(%p)\n", image);
|
||||||
|
|
||||||
if (fTeam != NULL) {
|
if (fImage != NULL)
|
||||||
fTeam->RemoveListener(this);
|
fImage->RemoveReference();
|
||||||
fImagesTable->SetTableModel(NULL);
|
|
||||||
delete fImagesTableModel;
|
fImage = image;
|
||||||
fImagesTableModel = NULL;
|
|
||||||
|
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;
|
fImagesTable->DeselectAllRows();
|
||||||
|
printf("ImageListView::SetImage() done\n");
|
||||||
if (fTeam != NULL) {
|
|
||||||
fImagesTableModel = new(std::nothrow) ImagesTableModel(fTeam);
|
|
||||||
fImagesTable->SetTableModel(fImagesTableModel);
|
|
||||||
fImagesTable->ResizeAllColumnsToPreferred();
|
|
||||||
fTeam->AddListener(this);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -218,13 +235,18 @@ ImageListView::ImageRemoved(const Team::ImageEvent& event)
|
|||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
ImageListView::TableRowInvoked(Table* table, int32 rowIndex)
|
ImageListView::TableSelectionChanged(Table* table)
|
||||||
{
|
{
|
||||||
// if (fImagesTableModel != NULL) {
|
if (fListener == NULL)
|
||||||
// Image* image = fImagesTableModel->ImageAt(rowIndex);
|
return;
|
||||||
// if (image != NULL)
|
|
||||||
// fParent->OpenImageWindow(image);
|
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));
|
B_TRUNCATE_END, B_ALIGN_LEFT));
|
||||||
|
|
||||||
fImagesTable->AddTableListener(this);
|
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,
|
class ImageListView : public BGroupView, private Team::Listener,
|
||||||
private TableListener {
|
private TableListener {
|
||||||
public:
|
public:
|
||||||
ImageListView();
|
class Listener;
|
||||||
|
|
||||||
|
public:
|
||||||
|
ImageListView(Team* team, Listener* listener);
|
||||||
~ImageListView();
|
~ImageListView();
|
||||||
|
|
||||||
static ImageListView* Create();
|
static ImageListView* Create(Team* team, Listener* listener);
|
||||||
// throws
|
// throws
|
||||||
|
|
||||||
void SetTeam(Team* team);
|
void UnsetListener();
|
||||||
|
|
||||||
|
void SetImage(Image* image);
|
||||||
|
|
||||||
virtual void MessageReceived(BMessage* message);
|
virtual void MessageReceived(BMessage* message);
|
||||||
|
|
||||||
@@ -33,14 +38,24 @@ private:
|
|||||||
virtual void ImageRemoved(const Team::ImageEvent& event);
|
virtual void ImageRemoved(const Team::ImageEvent& event);
|
||||||
|
|
||||||
// TableListener
|
// TableListener
|
||||||
virtual void TableRowInvoked(Table* table, int32 rowIndex);
|
virtual void TableSelectionChanged(Table* table);
|
||||||
|
|
||||||
void _Init();
|
void _Init();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Team* fTeam;
|
Team* fTeam;
|
||||||
|
Image* fImage;
|
||||||
Table* fImagesTable;
|
Table* fImagesTable;
|
||||||
ImagesTableModel* fImagesTableModel;
|
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
|
void
|
||||||
StackTraceView::_Init()
|
StackTraceView::_Init()
|
||||||
{
|
{
|
||||||
fFramesTable = new Table("register list", 0, B_FANCY_BORDER);
|
fFramesTable = new Table("stack trace", 0, B_FANCY_BORDER);
|
||||||
AddChild(fFramesTable->ToView());
|
AddChild(fFramesTable->ToView());
|
||||||
fFramesTable->SetSortingEnabled(false);
|
fFramesTable->SetSortingEnabled(false);
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,8 @@
|
|||||||
#include <AutoLocker.h>
|
#include <AutoLocker.h>
|
||||||
|
|
||||||
#include "CpuState.h"
|
#include "CpuState.h"
|
||||||
#include "ImageListView.h"
|
#include "Image.h"
|
||||||
|
#include "ImageDebugInfo.h"
|
||||||
#include "MessageCodes.h"
|
#include "MessageCodes.h"
|
||||||
#include "RegisterView.h"
|
#include "RegisterView.h"
|
||||||
#include "SourceCode.h"
|
#include "SourceCode.h"
|
||||||
@@ -35,6 +36,7 @@ TeamWindow::TeamWindow(TeamDebugModel* debugModel, Listener* listener)
|
|||||||
B_ASYNCHRONOUS_CONTROLS | B_AUTO_UPDATE_SIZE_LIMITS),
|
B_ASYNCHRONOUS_CONTROLS | B_AUTO_UPDATE_SIZE_LIMITS),
|
||||||
fDebugModel(debugModel),
|
fDebugModel(debugModel),
|
||||||
fActiveThread(NULL),
|
fActiveThread(NULL),
|
||||||
|
fActiveImage(NULL),
|
||||||
fActiveStackTrace(NULL),
|
fActiveStackTrace(NULL),
|
||||||
fActiveStackFrame(NULL),
|
fActiveStackFrame(NULL),
|
||||||
fActiveFunction(NULL),
|
fActiveFunction(NULL),
|
||||||
@@ -44,6 +46,7 @@ TeamWindow::TeamWindow(TeamDebugModel* debugModel, Listener* listener)
|
|||||||
fLocalsTabView(NULL),
|
fLocalsTabView(NULL),
|
||||||
fThreadListView(NULL),
|
fThreadListView(NULL),
|
||||||
fImageListView(NULL),
|
fImageListView(NULL),
|
||||||
|
fImageFunctionsView(NULL),
|
||||||
fRegisterView(NULL),
|
fRegisterView(NULL),
|
||||||
fStackTraceView(NULL),
|
fStackTraceView(NULL),
|
||||||
fSourceView(NULL),
|
fSourceView(NULL),
|
||||||
@@ -79,6 +82,7 @@ TeamWindow::~TeamWindow()
|
|||||||
_SetActiveFunction(NULL);
|
_SetActiveFunction(NULL);
|
||||||
_SetActiveStackFrame(NULL);
|
_SetActiveStackFrame(NULL);
|
||||||
_SetActiveStackTrace(NULL);
|
_SetActiveStackTrace(NULL);
|
||||||
|
_SetActiveImage(NULL);
|
||||||
_SetActiveThread(NULL);
|
_SetActiveThread(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -143,6 +147,16 @@ TeamWindow::MessageReceived(BMessage* message)
|
|||||||
break;
|
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:
|
case MSG_USER_BREAKPOINT_CHANGED:
|
||||||
{
|
{
|
||||||
uint64 address;
|
uint64 address;
|
||||||
@@ -180,6 +194,13 @@ TeamWindow::ThreadSelectionChanged(::Thread* thread)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TeamWindow::ImageSelectionChanged(Image* image)
|
||||||
|
{
|
||||||
|
_SetActiveImage(image);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
TeamWindow::StackFrameSelectionChanged(StackFrame* frame)
|
TeamWindow::StackFrameSelectionChanged(StackFrame* frame)
|
||||||
{
|
{
|
||||||
@@ -187,6 +208,13 @@ TeamWindow::StackFrameSelectionChanged(StackFrame* frame)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TeamWindow::FunctionSelectionChanged(FunctionDebugInfo* function)
|
||||||
|
{
|
||||||
|
_SetActiveFunction(function);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
TeamWindow::SetBreakpointRequested(target_addr_t address, bool enabled)
|
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
|
void
|
||||||
TeamWindow::UserBreakpointChanged(const TeamDebugModel::BreakpointEvent& event)
|
TeamWindow::UserBreakpointChanged(const TeamDebugModel::BreakpointEvent& event)
|
||||||
{
|
{
|
||||||
@@ -288,8 +325,9 @@ TeamWindow::_Init()
|
|||||||
imagesGroup->SetName("Images");
|
imagesGroup->SetName("Images");
|
||||||
fTabView->AddTab(imagesGroup);
|
fTabView->AddTab(imagesGroup);
|
||||||
BLayoutBuilder::Split<>(imagesGroup)
|
BLayoutBuilder::Split<>(imagesGroup)
|
||||||
.Add(fImageListView = ImageListView::Create())
|
.Add(fImageListView = ImageListView::Create(fDebugModel->GetTeam(),
|
||||||
.Add(new BTextView("source files"));
|
this))
|
||||||
|
.Add(fImageFunctionsView = ImageFunctionsView::Create(this));
|
||||||
|
|
||||||
// add local variables tab
|
// add local variables tab
|
||||||
BView* tab = new BTextView("Variables");
|
BView* tab = new BTextView("Variables");
|
||||||
@@ -300,7 +338,6 @@ TeamWindow::_Init()
|
|||||||
fLocalsTabView->AddTab(tab);
|
fLocalsTabView->AddTab(tab);
|
||||||
|
|
||||||
fThreadListView->SetTeam(fDebugModel->GetTeam());
|
fThreadListView->SetTeam(fDebugModel->GetTeam());
|
||||||
fImageListView->SetTeam(fDebugModel->GetTeam());
|
|
||||||
|
|
||||||
fRunButton->SetMessage(new BMessage(MSG_THREAD_RUN));
|
fRunButton->SetMessage(new BMessage(MSG_THREAD_RUN));
|
||||||
fStepOverButton->SetMessage(new BMessage(MSG_THREAD_STEP_OVER));
|
fStepOverButton->SetMessage(new BMessage(MSG_THREAD_STEP_OVER));
|
||||||
@@ -336,7 +373,7 @@ TeamWindow::_SetActiveThread(::Thread* thread)
|
|||||||
StackTrace* stackTrace = fActiveThread != NULL
|
StackTrace* stackTrace = fActiveThread != NULL
|
||||||
? fActiveThread->GetStackTrace() : NULL;
|
? fActiveThread->GetStackTrace() : NULL;
|
||||||
Reference<StackTrace> stackTraceReference(stackTrace);
|
Reference<StackTrace> stackTraceReference(stackTrace);
|
||||||
// hold a reference until the register view has one
|
// hold a reference until we've set it
|
||||||
|
|
||||||
locker.Unlock();
|
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
|
void
|
||||||
TeamWindow::_SetActiveStackTrace(StackTrace* stackTrace)
|
TeamWindow::_SetActiveStackTrace(StackTrace* stackTrace)
|
||||||
{
|
{
|
||||||
@@ -403,8 +474,21 @@ TeamWindow::_SetActiveFunction(FunctionDebugInfo* function)
|
|||||||
fActiveFunction->RemoveReference();
|
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;
|
fActiveFunction = function;
|
||||||
|
|
||||||
|
locker.Lock();
|
||||||
|
|
||||||
SourceCode* sourceCode = NULL;
|
SourceCode* sourceCode = NULL;
|
||||||
Reference<SourceCode> sourceCodeReference;
|
Reference<SourceCode> sourceCodeReference;
|
||||||
|
|
||||||
@@ -423,6 +507,8 @@ TeamWindow::_SetActiveFunction(FunctionDebugInfo* function)
|
|||||||
locker.Unlock();
|
locker.Unlock();
|
||||||
|
|
||||||
_SetActiveSourceCode(sourceCode);
|
_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
|
void
|
||||||
TeamWindow::_HandleSourceCodeChanged()
|
TeamWindow::_HandleSourceCodeChanged()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -10,6 +10,8 @@
|
|||||||
|
|
||||||
#include "SourceView.h"
|
#include "SourceView.h"
|
||||||
#include "FunctionDebugInfo.h"
|
#include "FunctionDebugInfo.h"
|
||||||
|
#include "ImageFunctionsView.h"
|
||||||
|
#include "ImageListView.h"
|
||||||
#include "StackTraceView.h"
|
#include "StackTraceView.h"
|
||||||
#include "Team.h"
|
#include "Team.h"
|
||||||
#include "TeamDebugModel.h"
|
#include "TeamDebugModel.h"
|
||||||
@@ -19,15 +21,16 @@
|
|||||||
class BButton;
|
class BButton;
|
||||||
class BTabView;
|
class BTabView;
|
||||||
class FunctionDebugInfo;
|
class FunctionDebugInfo;
|
||||||
class ImageListView;
|
class Image;
|
||||||
class RegisterView;
|
class RegisterView;
|
||||||
class SourceCode;
|
class SourceCode;
|
||||||
class StackFrame;
|
class StackFrame;
|
||||||
|
|
||||||
|
|
||||||
class TeamWindow : public BWindow, private ThreadListView::Listener,
|
class TeamWindow : public BWindow, ThreadListView::Listener,
|
||||||
StackTraceView::Listener, SourceView::Listener, Team::Listener,
|
ImageListView::Listener, StackTraceView::Listener,
|
||||||
private TeamDebugModel::Listener, FunctionDebugInfo::Listener {
|
ImageFunctionsView::Listener, SourceView::Listener, Team::Listener,
|
||||||
|
TeamDebugModel::Listener, FunctionDebugInfo::Listener {
|
||||||
public:
|
public:
|
||||||
class Listener;
|
class Listener;
|
||||||
|
|
||||||
@@ -47,9 +50,16 @@ private:
|
|||||||
// ThreadListView::Listener
|
// ThreadListView::Listener
|
||||||
virtual void ThreadSelectionChanged(::Thread* thread);
|
virtual void ThreadSelectionChanged(::Thread* thread);
|
||||||
|
|
||||||
|
// ImageListView::Listener
|
||||||
|
virtual void ImageSelectionChanged(Image* image);
|
||||||
|
|
||||||
// StackTraceView::Listener
|
// StackTraceView::Listener
|
||||||
virtual void StackFrameSelectionChanged(StackFrame* frame);
|
virtual void StackFrameSelectionChanged(StackFrame* frame);
|
||||||
|
|
||||||
|
// ImageFunctionsView::Listener
|
||||||
|
virtual void FunctionSelectionChanged(
|
||||||
|
FunctionDebugInfo* function);
|
||||||
|
|
||||||
// SourceView::Listener
|
// SourceView::Listener
|
||||||
virtual void SetBreakpointRequested(target_addr_t address,
|
virtual void SetBreakpointRequested(target_addr_t address,
|
||||||
bool enabled);
|
bool enabled);
|
||||||
@@ -62,6 +72,8 @@ private:
|
|||||||
const Team::ThreadEvent& event);
|
const Team::ThreadEvent& event);
|
||||||
virtual void ThreadStackTraceChanged(
|
virtual void ThreadStackTraceChanged(
|
||||||
const Team::ThreadEvent& event);
|
const Team::ThreadEvent& event);
|
||||||
|
virtual void ImageDebugInfoChanged(
|
||||||
|
const Team::ImageEvent& event);
|
||||||
|
|
||||||
// TeamDebugModel::Listener
|
// TeamDebugModel::Listener
|
||||||
virtual void UserBreakpointChanged(
|
virtual void UserBreakpointChanged(
|
||||||
@@ -75,6 +87,7 @@ private:
|
|||||||
void _Init();
|
void _Init();
|
||||||
|
|
||||||
void _SetActiveThread(::Thread* thread);
|
void _SetActiveThread(::Thread* thread);
|
||||||
|
void _SetActiveImage(Image* image);
|
||||||
void _SetActiveStackTrace(StackTrace* stackTrace);
|
void _SetActiveStackTrace(StackTrace* stackTrace);
|
||||||
void _SetActiveStackFrame(StackFrame* frame);
|
void _SetActiveStackFrame(StackFrame* frame);
|
||||||
void _SetActiveFunction(FunctionDebugInfo* function);
|
void _SetActiveFunction(FunctionDebugInfo* function);
|
||||||
@@ -85,6 +98,7 @@ private:
|
|||||||
void _HandleThreadStateChanged(thread_id threadID);
|
void _HandleThreadStateChanged(thread_id threadID);
|
||||||
void _HandleCpuStateChanged(thread_id threadID);
|
void _HandleCpuStateChanged(thread_id threadID);
|
||||||
void _HandleStackTraceChanged(thread_id threadID);
|
void _HandleStackTraceChanged(thread_id threadID);
|
||||||
|
void _HandleImageDebugInfoChanged(image_id imageID);
|
||||||
void _HandleSourceCodeChanged();
|
void _HandleSourceCodeChanged();
|
||||||
void _HandleUserBreakpointChanged(
|
void _HandleUserBreakpointChanged(
|
||||||
target_addr_t address);
|
target_addr_t address);
|
||||||
@@ -92,6 +106,7 @@ private:
|
|||||||
private:
|
private:
|
||||||
TeamDebugModel* fDebugModel;
|
TeamDebugModel* fDebugModel;
|
||||||
::Thread* fActiveThread;
|
::Thread* fActiveThread;
|
||||||
|
Image* fActiveImage;
|
||||||
StackTrace* fActiveStackTrace;
|
StackTrace* fActiveStackTrace;
|
||||||
StackFrame* fActiveStackFrame;
|
StackFrame* fActiveStackFrame;
|
||||||
FunctionDebugInfo* fActiveFunction;
|
FunctionDebugInfo* fActiveFunction;
|
||||||
@@ -101,6 +116,7 @@ private:
|
|||||||
BTabView* fLocalsTabView;
|
BTabView* fLocalsTabView;
|
||||||
ThreadListView* fThreadListView;
|
ThreadListView* fThreadListView;
|
||||||
ImageListView* fImageListView;
|
ImageListView* fImageListView;
|
||||||
|
ImageFunctionsView* fImageFunctionsView;
|
||||||
RegisterView* fRegisterView;
|
RegisterView* fRegisterView;
|
||||||
StackTraceView* fStackTraceView;
|
StackTraceView* fStackTraceView;
|
||||||
SourceView* fSourceView;
|
SourceView* fSourceView;
|
||||||
@@ -117,6 +133,8 @@ public:
|
|||||||
|
|
||||||
virtual void FunctionSourceCodeRequested(TeamWindow* window,
|
virtual void FunctionSourceCodeRequested(TeamWindow* window,
|
||||||
FunctionDebugInfo* function) = 0;
|
FunctionDebugInfo* function) = 0;
|
||||||
|
virtual void ImageDebugInfoRequested(TeamWindow* window,
|
||||||
|
Image* image) = 0;
|
||||||
virtual void ThreadActionRequested(TeamWindow* window,
|
virtual void ThreadActionRequested(TeamWindow* window,
|
||||||
thread_id threadID, uint32 action) = 0;
|
thread_id threadID, uint32 action) = 0;
|
||||||
virtual void SetBreakpointRequested(target_addr_t address,
|
virtual void SetBreakpointRequested(target_addr_t address,
|
||||||
|
|||||||
@@ -6,13 +6,15 @@
|
|||||||
#include "Image.h"
|
#include "Image.h"
|
||||||
|
|
||||||
#include "ImageDebugInfo.h"
|
#include "ImageDebugInfo.h"
|
||||||
|
#include "Team.h"
|
||||||
|
|
||||||
|
|
||||||
Image::Image(Team* team,const ImageInfo& imageInfo)
|
Image::Image(Team* team,const ImageInfo& imageInfo)
|
||||||
:
|
:
|
||||||
fTeam(team),
|
fTeam(team),
|
||||||
fInfo(imageInfo),
|
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
|
bool
|
||||||
Image::ContainsAddress(target_addr_t address) const
|
Image::ContainsAddress(target_addr_t address) const
|
||||||
{
|
{
|
||||||
@@ -55,3 +41,24 @@ Image::ContainsAddress(target_addr_t address) const
|
|||||||
|| (address >= fInfo.DataBase()
|
|| (address >= fInfo.DataBase()
|
||||||
&& address < fInfo.DataBase() + fInfo.DataSize());
|
&& 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"
|
#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 ImageDebugInfo;
|
||||||
class Team;
|
class Team;
|
||||||
|
|
||||||
@@ -30,15 +38,21 @@ public:
|
|||||||
const char* Name() const { return fInfo.Name(); }
|
const char* Name() const { return fInfo.Name(); }
|
||||||
const ImageInfo& Info() const { return fInfo; }
|
const ImageInfo& Info() const { return fInfo; }
|
||||||
|
|
||||||
ImageDebugInfo* GetImageDebugInfo() const { return fDebugInfo; }
|
|
||||||
void SetImageDebugInfo(ImageDebugInfo* debugInfo);
|
|
||||||
|
|
||||||
bool ContainsAddress(target_addr_t address) const;
|
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:
|
private:
|
||||||
Team* fTeam;
|
Team* fTeam;
|
||||||
ImageInfo fInfo;
|
ImageInfo fInfo;
|
||||||
|
// mutable
|
||||||
ImageDebugInfo* fDebugInfo;
|
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
|
void
|
||||||
Team::_NotifyThreadAdded(Thread* thread)
|
Team::_NotifyThreadAdded(Thread* thread)
|
||||||
{
|
{
|
||||||
@@ -371,3 +382,9 @@ void
|
|||||||
Team::Listener::ThreadStackTraceChanged(const Team::ThreadEvent& event)
|
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_STATE_CHANGED,
|
||||||
TEAM_EVENT_THREAD_CPU_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 NotifyThreadCpuStateChanged(Thread* thread);
|
||||||
void NotifyThreadStackTraceChanged(Thread* thread);
|
void NotifyThreadStackTraceChanged(Thread* thread);
|
||||||
|
|
||||||
|
// service methods for Image
|
||||||
|
void NotifyImageDebugInfoChanged(Image* image);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
typedef DoublyLinkedList<Listener> ListenerList;
|
typedef DoublyLinkedList<Listener> ListenerList;
|
||||||
|
|
||||||
@@ -138,6 +143,9 @@ public:
|
|||||||
const Team::ThreadEvent& event);
|
const Team::ThreadEvent& event);
|
||||||
virtual void ThreadStackTraceChanged(
|
virtual void ThreadStackTraceChanged(
|
||||||
const Team::ThreadEvent& event);
|
const Team::ThreadEvent& event);
|
||||||
|
|
||||||
|
virtual void ImageDebugInfoChanged(
|
||||||
|
const Team::ImageEvent& event);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user