* Added DebuggerInterface::GetSymbolInfos() to get the symbols for an image.
* Added the beginnings of the debug info abstraction. Currently we can only load
the symbols via the debugger.
* Added a job to retrieve debug info for an image. Extended the GetStackTraceJob
to support waiting for image debug info to be loaded.
* Extended ImageInfo by text/data address and size.
* Removed StackFrameX86 and made StackFrame a simple non-polymorphic class
featuring all the needed data. The really architecture-dependent is in the
referenced CpuState already. Added Image* and FunctionDebugInfo* attributes,
referring to the image respectively debug info for the function hit by the
instruction pointer.
* Switched StrackTrace's StackFrame management from DoublyLinkedList to
BObjectList. This makes it more comfortable to use.
* Changed the code for creating stack traces:
- The creation of the StackTrace object and the main loop to collect the
frames are now located in the no longer virtual
Architecture::CreateStackTrace().
- The decision how to create a StackFrame is based on the instruction pointer.
If it hit a function for which debug info is available, the respective
DebugInfo::CreateStackFrame() is used, otherwise we fall back to the new
virtual Architecture::CreateStackFrame().
* Adjusted the stack trace view to also show function names (mangled ATM).
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@31142 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -5,17 +5,22 @@
|
||||
|
||||
#include "Image.h"
|
||||
|
||||
#include "ImageDebugInfo.h"
|
||||
|
||||
|
||||
Image::Image(Team* team,const ImageInfo& imageInfo)
|
||||
:
|
||||
fTeam(team),
|
||||
fInfo(imageInfo)
|
||||
fInfo(imageInfo),
|
||||
fDebugInfo(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
Image::~Image()
|
||||
{
|
||||
if (fDebugInfo != NULL)
|
||||
fDebugInfo->RemoveReference();
|
||||
}
|
||||
|
||||
|
||||
@@ -24,3 +29,29 @@ Image::Init()
|
||||
{
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
{
|
||||
return (address >= fInfo.TextBase()
|
||||
&& address < fInfo.TextBase() + fInfo.TextSize())
|
||||
|| (address >= fInfo.DataBase()
|
||||
&& address < fInfo.DataBase() + fInfo.DataSize());
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "ImageInfo.h"
|
||||
|
||||
|
||||
class ImageDebugInfo;
|
||||
class Team;
|
||||
|
||||
|
||||
@@ -24,14 +25,20 @@ public:
|
||||
status_t Init();
|
||||
|
||||
|
||||
Team* GetTeam() const { return fTeam; }
|
||||
image_id ID() const { return fInfo.ImageID(); }
|
||||
const char* Name() const { return fInfo.Name(); }
|
||||
const ImageInfo& Info() const { return fInfo; }
|
||||
Team* GetTeam() const { return fTeam; }
|
||||
image_id ID() const { return fInfo.ImageID(); }
|
||||
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;
|
||||
|
||||
private:
|
||||
Team* fTeam;
|
||||
ImageInfo fInfo;
|
||||
ImageDebugInfo* fDebugInfo;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -10,7 +10,11 @@ ImageInfo::ImageInfo()
|
||||
:
|
||||
fTeam(-1),
|
||||
fImage(-1),
|
||||
fName()
|
||||
fName(),
|
||||
fTextBase(0),
|
||||
fTextSize(0),
|
||||
fDataBase(0),
|
||||
fDataSize(0)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -18,24 +22,40 @@ ImageInfo::ImageInfo(const ImageInfo& other)
|
||||
:
|
||||
fTeam(other.fTeam),
|
||||
fImage(other.fImage),
|
||||
fName(other.fName)
|
||||
fName(other.fName),
|
||||
fTextBase(other.fTextBase),
|
||||
fTextSize(other.fTextSize),
|
||||
fDataBase(other.fDataBase),
|
||||
fDataSize(other.fDataSize)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
ImageInfo::ImageInfo(team_id team, image_id image, const BString& name)
|
||||
ImageInfo::ImageInfo(team_id team, image_id image, const BString& name,
|
||||
target_addr_t textBase, target_size_t textSize, target_addr_t dataBase,
|
||||
target_size_t dataSize)
|
||||
:
|
||||
fTeam(team),
|
||||
fImage(image),
|
||||
fName(name)
|
||||
fName(name),
|
||||
fTextBase(textBase),
|
||||
fTextSize(textSize),
|
||||
fDataBase(dataBase),
|
||||
fDataSize(dataSize)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ImageInfo::SetTo(team_id team, image_id image, const BString& name)
|
||||
ImageInfo::SetTo(team_id team, image_id image, const BString& name,
|
||||
target_addr_t textBase, target_size_t textSize, target_addr_t dataBase,
|
||||
target_size_t dataSize)
|
||||
{
|
||||
fTeam = team;
|
||||
fImage = image;
|
||||
fName = name;
|
||||
fTextBase = textBase;
|
||||
fTextSize = textSize;
|
||||
fDataBase = dataBase;
|
||||
fDataSize = dataSize;
|
||||
}
|
||||
|
||||
@@ -8,25 +8,44 @@
|
||||
#include <image.h>
|
||||
#include <String.h>
|
||||
|
||||
#include "ArchitectureTypes.h"
|
||||
|
||||
|
||||
class ImageInfo {
|
||||
public:
|
||||
ImageInfo();
|
||||
ImageInfo(const ImageInfo& other);
|
||||
ImageInfo(team_id team, image_id image,
|
||||
const BString& name);
|
||||
const BString& name,
|
||||
target_addr_t textBase,
|
||||
target_size_t textSize,
|
||||
target_addr_t dataBase,
|
||||
target_size_t dataSize);
|
||||
|
||||
void SetTo(team_id team, image_id image,
|
||||
const BString& name);
|
||||
const BString& name,
|
||||
target_addr_t textBase,
|
||||
target_size_t textSize,
|
||||
target_addr_t dataBase,
|
||||
target_size_t dataSize);
|
||||
|
||||
team_id TeamID() const { return fTeam; }
|
||||
image_id ImageID() const { return fImage; }
|
||||
const char* Name() const { return fName.String(); }
|
||||
|
||||
target_addr_t TextBase() const { return fTextBase; }
|
||||
target_size_t TextSize() const { return fTextSize; }
|
||||
target_addr_t DataBase() const { return fDataBase; }
|
||||
target_size_t DataSize() const { return fDataSize; }
|
||||
|
||||
private:
|
||||
thread_id fTeam;
|
||||
image_id fImage;
|
||||
BString fName;
|
||||
target_addr_t fTextBase;
|
||||
target_size_t fTextSize;
|
||||
target_addr_t fDataBase;
|
||||
target_size_t fDataSize;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ UsePrivateSystemHeaders ;
|
||||
|
||||
SEARCH_SOURCE += [ FDirName $(SUBDIR) arch ] ;
|
||||
SEARCH_SOURCE += [ FDirName $(SUBDIR) arch x86 ] ;
|
||||
SEARCH_SOURCE += [ FDirName $(SUBDIR) debug_info ] ;
|
||||
SEARCH_SOURCE += [ FDirName $(SUBDIR) debugger_interface ] ;
|
||||
SEARCH_SOURCE += [ FDirName $(SUBDIR) gui team_window ] ;
|
||||
|
||||
@@ -23,6 +24,7 @@ Application Debugger :
|
||||
Image.cpp
|
||||
ImageInfo.cpp
|
||||
Jobs.cpp
|
||||
SymbolInfo.cpp
|
||||
Team.cpp
|
||||
TeamDebugger.cpp
|
||||
TeamDebugModel.cpp
|
||||
@@ -40,7 +42,14 @@ Application Debugger :
|
||||
# arch/x86
|
||||
ArchitectureX86.cpp
|
||||
CpuStateX86.cpp
|
||||
StackFrameX86.cpp
|
||||
|
||||
# debug_info
|
||||
BasicFunctionDebugInfo.cpp
|
||||
DebuggerDebugInfo.cpp
|
||||
DebugInfo.cpp
|
||||
FunctionDebugInfo.cpp
|
||||
ImageDebugInfo.cpp
|
||||
ImageDebugInfoProvider.cpp
|
||||
|
||||
# debugger_interface
|
||||
DebugEvent.cpp
|
||||
|
||||
+110
-1
@@ -5,11 +5,15 @@
|
||||
|
||||
#include "Jobs.h"
|
||||
|
||||
#include <new>
|
||||
|
||||
#include <AutoLocker.h>
|
||||
|
||||
#include "Architecture.h"
|
||||
#include "CpuState.h"
|
||||
#include "DebuggerInterface.h"
|
||||
#include "Image.h"
|
||||
#include "ImageDebugInfo.h"
|
||||
#include "StackTrace.h"
|
||||
#include "Team.h"
|
||||
#include "Thread.h"
|
||||
@@ -101,7 +105,7 @@ GetStackTraceJob::Do()
|
||||
|
||||
// get the stack trace
|
||||
StackTrace* stackTrace;
|
||||
status_t error = fArchitecture->CreateStackTrace(fThread->GetTeam(),
|
||||
status_t error = fArchitecture->CreateStackTrace(fThread->GetTeam(), this,
|
||||
fCpuState, stackTrace);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
@@ -115,3 +119,108 @@ GetStackTraceJob::Do()
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
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;
|
||||
|
||||
status_t error = GetWorker()->ScheduleJob(loadImageDebugInfoJob);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
}
|
||||
|
||||
workerLocker.Unlock();
|
||||
teamLocker.Unlock();
|
||||
|
||||
// wait for the job to finish
|
||||
switch (WaitFor(key)) {
|
||||
case JOB_DEPENDENCY_SUCCEEDED:
|
||||
case JOB_DEPENDENCY_NOT_FOUND:
|
||||
// "Not found" can happen due to a race condition between
|
||||
// unlocking the worker and starting to wait.
|
||||
break;
|
||||
case JOB_DEPENDENCY_FAILED:
|
||||
case JOB_DEPENDENCY_ABORTED:
|
||||
default:
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
teamLocker.Lock();
|
||||
}
|
||||
|
||||
_info = image->GetImageDebugInfo();
|
||||
_info->AddReference();
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - GetStackTraceJob
|
||||
|
||||
|
||||
LoadImageDebugInfoJob::LoadImageDebugInfoJob(
|
||||
DebuggerInterface* debuggerInterface, Architecture* architecture,
|
||||
Image* image)
|
||||
:
|
||||
fDebuggerInterface(debuggerInterface),
|
||||
fArchitecture(architecture),
|
||||
fImage(image)
|
||||
{
|
||||
fImage->AddReference();
|
||||
}
|
||||
|
||||
|
||||
LoadImageDebugInfoJob::~LoadImageDebugInfoJob()
|
||||
{
|
||||
fImage->RemoveReference();
|
||||
}
|
||||
|
||||
|
||||
JobKey
|
||||
LoadImageDebugInfoJob::Key() const
|
||||
{
|
||||
return JobKey(fImage, JOB_TYPE_LOAD_IMAGE_DEBUG_INFO);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
LoadImageDebugInfoJob::Do()
|
||||
{
|
||||
// get an image info for the image
|
||||
AutoLocker<Team> locker(fImage->GetTeam());
|
||||
ImageInfo imageInfo(fImage->Info());
|
||||
locker.Unlock();
|
||||
|
||||
// create the debug info
|
||||
ImageDebugInfo* debugInfo = new(std::nothrow) ImageDebugInfo(imageInfo,
|
||||
fDebuggerInterface, fArchitecture);
|
||||
if (debugInfo == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
status_t error = debugInfo->Init();
|
||||
if (error != B_OK) {
|
||||
delete debugInfo;
|
||||
return error;
|
||||
}
|
||||
|
||||
// set the info
|
||||
locker.Lock();
|
||||
fImage->SetImageDebugInfo(debugInfo);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
@@ -5,19 +5,22 @@
|
||||
#ifndef JOBS_H
|
||||
#define JOBS_H
|
||||
|
||||
#include "ImageDebugInfoProvider.h"
|
||||
#include "Worker.h"
|
||||
|
||||
|
||||
class Architecture;
|
||||
class CpuState;
|
||||
class DebuggerInterface;
|
||||
class Image;
|
||||
class Thread;
|
||||
|
||||
|
||||
// job types
|
||||
enum {
|
||||
JOB_TYPE_GET_CPU_STATE,
|
||||
JOB_TYPE_GET_STACK_TRACE
|
||||
JOB_TYPE_GET_STACK_TRACE,
|
||||
JOB_TYPE_LOAD_IMAGE_DEBUG_INFO
|
||||
};
|
||||
|
||||
|
||||
@@ -37,17 +40,21 @@ private:
|
||||
};
|
||||
|
||||
|
||||
class GetStackTraceJob : public Job {
|
||||
class GetStackTraceJob : public Job, private ImageDebugInfoProvider {
|
||||
public:
|
||||
GetStackTraceJob(
|
||||
DebuggerInterface* debuggerInterface,
|
||||
Architecture* architecture,
|
||||
Thread* thread);
|
||||
Architecture* architecture, Thread* thread);
|
||||
virtual ~GetStackTraceJob();
|
||||
|
||||
virtual JobKey Key() const;
|
||||
virtual status_t Do();
|
||||
|
||||
private:
|
||||
// ImageDebugInfoProvider
|
||||
virtual status_t GetImageDebugInfo(Image* image,
|
||||
ImageDebugInfo*& _info);
|
||||
|
||||
private:
|
||||
DebuggerInterface* fDebuggerInterface;
|
||||
Architecture* fArchitecture;
|
||||
@@ -56,4 +63,22 @@ private:
|
||||
};
|
||||
|
||||
|
||||
class LoadImageDebugInfoJob : public Job {
|
||||
public:
|
||||
LoadImageDebugInfoJob(
|
||||
DebuggerInterface* debuggerInterface,
|
||||
Architecture* architecture,
|
||||
Image* image);
|
||||
virtual ~LoadImageDebugInfoJob();
|
||||
|
||||
virtual JobKey Key() const;
|
||||
virtual status_t Do();
|
||||
|
||||
private:
|
||||
DebuggerInterface* fDebuggerInterface;
|
||||
Architecture* fArchitecture;
|
||||
Image* fImage;
|
||||
};
|
||||
|
||||
|
||||
#endif // JOBS_H
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright 2009, Ingo Weinhold, [email protected].
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
#include "SymbolInfo.h"
|
||||
|
||||
|
||||
SymbolInfo::SymbolInfo(target_addr_t address, target_size_t size, uint32 type,
|
||||
const BString& name)
|
||||
:
|
||||
fAddress(address),
|
||||
fSize(size),
|
||||
fType(type),
|
||||
fName(name)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
SymbolInfo::~SymbolInfo()
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright 2009, Ingo Weinhold, [email protected].
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef SYMBOL_INFO_H
|
||||
#define SYMBOL_INFO_H
|
||||
|
||||
#include <String.h>
|
||||
|
||||
#include "ArchitectureTypes.h"
|
||||
|
||||
|
||||
class SymbolInfo {
|
||||
public:
|
||||
SymbolInfo(target_addr_t address,
|
||||
target_size_t size, uint32 type,
|
||||
const BString& name);
|
||||
~SymbolInfo();
|
||||
|
||||
target_addr_t Address() const { return fAddress; }
|
||||
target_size_t Size() const { return fSize; }
|
||||
uint32 Type() const { return fType; }
|
||||
const char* Name() const { return fName.String(); }
|
||||
|
||||
private:
|
||||
target_addr_t fAddress;
|
||||
target_size_t fSize;
|
||||
uint32 fType;
|
||||
BString fName;
|
||||
};
|
||||
|
||||
|
||||
#endif // SYMBOL_INFO_H
|
||||
@@ -181,6 +181,19 @@ Team::ImageByID(image_id imageID) const
|
||||
}
|
||||
|
||||
|
||||
Image*
|
||||
Team::ImageByAddress(target_addr_t address) const
|
||||
{
|
||||
for (ImageList::ConstIterator it = fImages.GetIterator();
|
||||
Image* image = it.Next();) {
|
||||
if (image->ContainsAddress(address))
|
||||
return image;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
const ImageList&
|
||||
Team::Images() const
|
||||
{
|
||||
|
||||
@@ -58,6 +58,7 @@ public:
|
||||
void RemoveImage(Image* image);
|
||||
bool RemoveImage(image_id imageID);
|
||||
Image* ImageByID(image_id imageID) const;
|
||||
Image* ImageByAddress(target_addr_t address) const;
|
||||
const ImageList& Images() const;
|
||||
|
||||
void AddListener(Listener* listener);
|
||||
|
||||
@@ -5,6 +5,20 @@
|
||||
|
||||
#include "Architecture.h"
|
||||
|
||||
#include <new>
|
||||
|
||||
#include <AutoDeleter.h>
|
||||
#include <AutoLocker.h>
|
||||
|
||||
#include "CpuState.h"
|
||||
#include "DebugInfo.h"
|
||||
#include "FunctionDebugInfo.h"
|
||||
#include "Image.h"
|
||||
#include "ImageDebugInfo.h"
|
||||
#include "ImageDebugInfoProvider.h"
|
||||
#include "StackTrace.h"
|
||||
#include "Team.h"
|
||||
|
||||
|
||||
Architecture::Architecture(DebuggerInterface* debuggerInterface)
|
||||
:
|
||||
@@ -23,3 +37,78 @@ Architecture::Init()
|
||||
{
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
Architecture::CreateStackTrace(Team* team,
|
||||
ImageDebugInfoProvider* imageInfoProvider, CpuState* cpuState,
|
||||
StackTrace*& _stackTrace)
|
||||
{
|
||||
Reference<CpuState> cpuStateReference(cpuState);
|
||||
|
||||
// create the object
|
||||
StackTrace* stackTrace = new(std::nothrow) StackTrace;
|
||||
if (stackTrace == NULL)
|
||||
return B_NO_MEMORY;
|
||||
ObjectDeleter<StackTrace> stackTraceDeleter(stackTrace);
|
||||
|
||||
StackFrame* frame = NULL;
|
||||
|
||||
while (cpuState != NULL) {
|
||||
// get the instruction pointer
|
||||
target_addr_t instructionPointer = cpuState->InstructionPointer();
|
||||
if (instructionPointer == 0)
|
||||
break;
|
||||
|
||||
// get the image for the instruction pointer
|
||||
AutoLocker<Team> teamLocker(team);
|
||||
Image* image = team->ImageByAddress(instructionPointer);
|
||||
Reference<Image> imageReference(image);
|
||||
teamLocker.Unlock();
|
||||
|
||||
// get the image debug info
|
||||
ImageDebugInfo* imageDebugInfo = NULL;
|
||||
if (image != NULL)
|
||||
imageInfoProvider->GetImageDebugInfo(image, imageDebugInfo);
|
||||
Reference<ImageDebugInfo> imageDebugInfoReference(imageDebugInfo, true);
|
||||
|
||||
// get the function
|
||||
FunctionDebugInfo* function = NULL;
|
||||
if (imageDebugInfo != NULL)
|
||||
function = imageDebugInfo->FindFunction(instructionPointer);
|
||||
Reference<FunctionDebugInfo> functionReference(function, true);
|
||||
|
||||
// create the frame using the debug info
|
||||
StackFrame* previousFrame = NULL;
|
||||
CpuState* previousCpuState = NULL;
|
||||
if (function != NULL) {
|
||||
status_t error = function->GetDebugInfo()->CreateFrame(image,
|
||||
function, cpuState, previousFrame, previousCpuState);
|
||||
if (error != B_OK && error != B_UNSUPPORTED)
|
||||
break;
|
||||
}
|
||||
|
||||
// If we have no frame yet, let the architecture create it.
|
||||
if (previousFrame == NULL) {
|
||||
status_t error = CreateStackFrame(image, function, cpuState,
|
||||
previousFrame, previousCpuState);
|
||||
if (error != B_OK)
|
||||
break;
|
||||
}
|
||||
|
||||
cpuStateReference.SetTo(previousCpuState, true);
|
||||
|
||||
previousFrame->SetImage(image);
|
||||
previousFrame->SetFunction(function);
|
||||
|
||||
if (!stackTrace->AddFrame(previousFrame))
|
||||
return B_NO_MEMORY;
|
||||
|
||||
frame = previousFrame;
|
||||
cpuState = previousCpuState;
|
||||
}
|
||||
|
||||
stackTraceDeleter.Detach();
|
||||
_stackTrace = stackTrace;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
@@ -12,7 +12,11 @@
|
||||
|
||||
class CpuState;
|
||||
class DebuggerInterface;
|
||||
class FunctionDebugInfo;
|
||||
class Image;
|
||||
class ImageDebugInfoProvider;
|
||||
class Register;
|
||||
class StackFrame;
|
||||
class StackTrace;
|
||||
class Team;
|
||||
|
||||
@@ -30,8 +34,19 @@ public:
|
||||
|
||||
virtual status_t CreateCpuState(const void* cpuStateData,
|
||||
size_t size, CpuState*& _state) = 0;
|
||||
virtual status_t CreateStackTrace(Team* team, CpuState* cpuState,
|
||||
StackTrace*& _stackTrace) = 0;
|
||||
virtual status_t CreateStackFrame(Image* image,
|
||||
FunctionDebugInfo* function,
|
||||
CpuState* cpuState,
|
||||
StackFrame*& _previousFrame,
|
||||
CpuState*& _previousCpuState) = 0;
|
||||
// returns reference to previous frame
|
||||
// and CPU state; returned CPU state
|
||||
// can be NULL
|
||||
|
||||
status_t CreateStackTrace(Team* team,
|
||||
ImageDebugInfoProvider* imageInfoProvider,
|
||||
CpuState* cpuState,
|
||||
StackTrace*& _stackTrace);
|
||||
// team is not locked
|
||||
|
||||
protected:
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
|
||||
typedef uint64 target_addr_t;
|
||||
typedef uint64 target_size_t;
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
#include <Referenceable.h>
|
||||
#include <Variant.h>
|
||||
|
||||
#include "ArchitectureTypes.h"
|
||||
|
||||
|
||||
class Register;
|
||||
|
||||
@@ -18,6 +20,7 @@ class CpuState : public Referenceable {
|
||||
public:
|
||||
virtual ~CpuState();
|
||||
|
||||
virtual target_addr_t InstructionPointer() const = 0;
|
||||
virtual bool GetRegisterValue(const Register* reg,
|
||||
BVariant& _value) = 0;
|
||||
};
|
||||
|
||||
@@ -5,7 +5,68 @@
|
||||
|
||||
#include "StackFrame.h"
|
||||
|
||||
#include "CpuState.h"
|
||||
#include "FunctionDebugInfo.h"
|
||||
#include "Image.h"
|
||||
|
||||
|
||||
StackFrame::StackFrame(stack_frame_type type, CpuState* cpuState,
|
||||
target_addr_t frameAddress)
|
||||
:
|
||||
fType(type),
|
||||
fCpuState(cpuState),
|
||||
fFrameAddress(frameAddress),
|
||||
fReturnAddress(0),
|
||||
fImage(NULL),
|
||||
fFunction(NULL)
|
||||
{
|
||||
fCpuState->AddReference();
|
||||
}
|
||||
|
||||
|
||||
StackFrame::~StackFrame()
|
||||
{
|
||||
SetImage(NULL);
|
||||
SetFunction(NULL);
|
||||
fCpuState->RemoveReference();
|
||||
}
|
||||
|
||||
|
||||
target_addr_t
|
||||
StackFrame::InstructionPointer() const
|
||||
{
|
||||
return fCpuState->InstructionPointer();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
StackFrame::SetReturnAddress(target_addr_t address)
|
||||
{
|
||||
fReturnAddress = address;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
StackFrame::SetImage(Image* image)
|
||||
{
|
||||
if (fImage != NULL)
|
||||
fImage->RemoveReference();
|
||||
|
||||
fImage = image;
|
||||
|
||||
if (fImage != NULL)
|
||||
fImage->AddReference();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
StackFrame::SetFunction(FunctionDebugInfo* function)
|
||||
{
|
||||
if (fFunction != NULL)
|
||||
fFunction->RemoveReference();
|
||||
|
||||
fFunction = function;
|
||||
|
||||
if (fFunction != NULL)
|
||||
fFunction->AddReference();
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
#include <OS.h>
|
||||
|
||||
#include <Referenceable.h>
|
||||
#include <util/DoublyLinkedList.h>
|
||||
|
||||
#include "ArchitectureTypes.h"
|
||||
|
||||
@@ -22,25 +21,39 @@ enum stack_frame_type {
|
||||
|
||||
|
||||
class CpuState;
|
||||
class Image;
|
||||
class FunctionDebugInfo;
|
||||
|
||||
|
||||
class StackFrame : public Referenceable,
|
||||
public DoublyLinkedListLinkImpl<StackFrame> {
|
||||
class StackFrame : public Referenceable {
|
||||
public:
|
||||
virtual ~StackFrame();
|
||||
StackFrame(stack_frame_type type,
|
||||
CpuState* cpuState,
|
||||
target_addr_t frameAddress);
|
||||
~StackFrame();
|
||||
|
||||
virtual stack_frame_type Type() const = 0;
|
||||
stack_frame_type Type() const { return fType; }
|
||||
CpuState* GetCpuState() const { return fCpuState; }
|
||||
target_addr_t InstructionPointer() const;
|
||||
target_addr_t FrameAddress() const { return fFrameAddress; }
|
||||
|
||||
virtual CpuState* GetCpuState() const = 0;
|
||||
target_addr_t ReturnAddress() const { return fReturnAddress; }
|
||||
void SetReturnAddress(target_addr_t address);
|
||||
|
||||
virtual target_addr_t InstructionPointer() const = 0;
|
||||
virtual target_addr_t FrameAddress() const = 0;
|
||||
virtual target_addr_t ReturnAddress() const = 0;
|
||||
virtual target_addr_t PreviousFrameAddress() const = 0;
|
||||
Image* GetImage() const { return fImage; }
|
||||
void SetImage(Image* image);
|
||||
|
||||
FunctionDebugInfo* Function() const { return fFunction; }
|
||||
void SetFunction(FunctionDebugInfo* function);
|
||||
|
||||
private:
|
||||
stack_frame_type fType;
|
||||
CpuState* fCpuState;
|
||||
target_addr_t fFrameAddress;
|
||||
target_addr_t fReturnAddress;
|
||||
Image* fImage;
|
||||
FunctionDebugInfo* fFunction;
|
||||
};
|
||||
|
||||
|
||||
typedef DoublyLinkedList<StackFrame> StackFrameList;
|
||||
|
||||
|
||||
#endif // STACK_FRAME_H
|
||||
|
||||
@@ -13,13 +13,31 @@ StackTrace::StackTrace()
|
||||
|
||||
StackTrace::~StackTrace()
|
||||
{
|
||||
while (StackFrame* frame = fStackFrames.RemoveHead())
|
||||
for (int32 i = 0; StackFrame* frame = FrameAt(i); i++)
|
||||
frame->RemoveReference();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
bool
|
||||
StackTrace::AddFrame(StackFrame* frame)
|
||||
{
|
||||
fStackFrames.Add(frame);
|
||||
if (fStackFrames.AddItem(frame))
|
||||
return true;
|
||||
|
||||
frame->RemoveReference();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
int32
|
||||
StackTrace::CountFrames() const
|
||||
{
|
||||
return fStackFrames.CountItems();
|
||||
}
|
||||
|
||||
|
||||
StackFrame*
|
||||
StackTrace::FrameAt(int32 index) const
|
||||
{
|
||||
return fStackFrames.ItemAt(index);
|
||||
}
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
#ifndef STACK_TRACE_H
|
||||
#define STACK_TRACE_H
|
||||
|
||||
#include <ObjectList.h>
|
||||
|
||||
#include "StackFrame.h"
|
||||
|
||||
|
||||
@@ -13,15 +15,14 @@ public:
|
||||
StackTrace();
|
||||
virtual ~StackTrace();
|
||||
|
||||
void AddFrame(StackFrame* frame);
|
||||
// takes over reference
|
||||
bool AddFrame(StackFrame* frame);
|
||||
// takes over reference (also on error)
|
||||
|
||||
const StackFrameList& Frames() const { return fStackFrames; }
|
||||
int32 CountFrames() const;
|
||||
StackFrame* FrameAt(int32 index) const;
|
||||
|
||||
StackFrame* TopFrame() const
|
||||
{ return fStackFrames.Head(); }
|
||||
StackFrame* BottomFrame() const
|
||||
{ return fStackFrames.Tail(); }
|
||||
private:
|
||||
typedef BObjectList<StackFrame> StackFrameList;
|
||||
|
||||
private:
|
||||
StackFrameList fStackFrames;
|
||||
|
||||
@@ -11,8 +11,7 @@
|
||||
|
||||
#include "CpuStateX86.h"
|
||||
#include "DebuggerInterface.h"
|
||||
#include "StackFrameX86.h"
|
||||
#include "StackTrace.h"
|
||||
#include "StackFrame.h"
|
||||
|
||||
|
||||
ArchitectureX86::ArchitectureX86(DebuggerInterface* debuggerInterface)
|
||||
@@ -104,59 +103,38 @@ ArchitectureX86::CreateCpuState(const void* cpuStateData, size_t size,
|
||||
|
||||
|
||||
status_t
|
||||
ArchitectureX86::CreateStackTrace(Team* team, CpuState* _cpuState,
|
||||
StackTrace*& _stackTrace)
|
||||
ArchitectureX86::CreateStackFrame(Image* image, FunctionDebugInfo* function,
|
||||
CpuState* _cpuState, StackFrame*& _previousFrame,
|
||||
CpuState*& _previousCpuState)
|
||||
{
|
||||
CpuStateX86* cpuState = dynamic_cast<CpuStateX86*>(_cpuState);
|
||||
|
||||
// create the object
|
||||
StackTrace* stackTrace = new(std::nothrow) StackTrace;
|
||||
if (stackTrace == NULL)
|
||||
return B_NO_MEMORY;
|
||||
ObjectDeleter<StackTrace> stackTraceDeleter(stackTrace);
|
||||
uint32 framePointer = cpuState->IntRegisterValue(X86_REGISTER_EBP);
|
||||
|
||||
// create the top frame
|
||||
StackFrameX86* frame = new StackFrameX86(STACK_FRAME_TYPE_TOP, cpuState);
|
||||
// create the stack frame
|
||||
StackFrame* frame = new(std::nothrow) StackFrame(
|
||||
STACK_FRAME_TYPE_STANDARD, cpuState, framePointer);
|
||||
if (frame == NULL)
|
||||
return B_NO_MEMORY;
|
||||
stackTrace->AddFrame(frame);
|
||||
|
||||
while (true) {
|
||||
uint32 framePointer = (uint32)frame->FrameAddress();
|
||||
if (framePointer == 0)
|
||||
break;
|
||||
|
||||
// get previous frame and return address
|
||||
uint32 frameData[2];
|
||||
ssize_t bytesRead = fDebuggerInterface->ReadMemory(framePointer,
|
||||
frameData, 8);
|
||||
if (bytesRead != 8)
|
||||
break;
|
||||
|
||||
frame->SetPreviousAddresses(frameData[0], frameData[1]);
|
||||
|
||||
if (frameData[0] == 0 || frameData[1] == 0)
|
||||
break;
|
||||
Reference<StackFrame> frameReference(frame, true);
|
||||
|
||||
// read the previous frame and return address and create the CPU state
|
||||
CpuStateX86* previousCpuState = NULL;
|
||||
uint32 frameData[2];
|
||||
if (framePointer != 0
|
||||
&& fDebuggerInterface->ReadMemory(framePointer, frameData, 8) == 8) {
|
||||
// prepare the previous CPU state
|
||||
cpuState = new(std::nothrow) CpuStateX86;
|
||||
if (cpuState == NULL)
|
||||
previousCpuState = new(std::nothrow) CpuStateX86;
|
||||
if (previousCpuState == NULL)
|
||||
return B_NO_MEMORY;
|
||||
Reference<CpuState> cpuStateReference(cpuState, true);
|
||||
|
||||
cpuState->SetIntRegister(X86_REGISTER_EBP, frameData[0]);
|
||||
cpuState->SetIntRegister(X86_REGISTER_EIP, frameData[1]);
|
||||
previousCpuState->SetIntRegister(X86_REGISTER_EBP, frameData[0]);
|
||||
previousCpuState->SetIntRegister(X86_REGISTER_EIP, frameData[1]);
|
||||
// TODO: Actually it's the instruction before!
|
||||
|
||||
// create the next frame
|
||||
frame = new StackFrameX86(STACK_FRAME_TYPE_STANDARD, cpuState);
|
||||
if (frame == NULL)
|
||||
return B_NO_MEMORY;
|
||||
stackTrace->AddFrame(frame);
|
||||
}
|
||||
|
||||
stackTraceDeleter.Detach();
|
||||
_stackTrace = stackTrace;
|
||||
_previousFrame = frameReference.Detach();
|
||||
_previousCpuState = previousCpuState;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -23,8 +23,11 @@ public:
|
||||
|
||||
virtual status_t CreateCpuState(const void* cpuStateData,
|
||||
size_t size, CpuState*& _state);
|
||||
virtual status_t CreateStackTrace(Team* team, CpuState* cpuState,
|
||||
StackTrace*& _stackTrace);
|
||||
virtual status_t CreateStackFrame(Image* image,
|
||||
FunctionDebugInfo* function,
|
||||
CpuState* cpuState,
|
||||
StackFrame*& _previousFrame,
|
||||
CpuState*& _previousCpuState);
|
||||
|
||||
private:
|
||||
void _AddRegister(int32 index, const char* name,
|
||||
|
||||
@@ -42,6 +42,14 @@ CpuStateX86::~CpuStateX86()
|
||||
}
|
||||
|
||||
|
||||
target_addr_t
|
||||
CpuStateX86::InstructionPointer() const
|
||||
{
|
||||
return IsRegisterSet(X86_REGISTER_EIP)
|
||||
? IntRegisterValue(X86_REGISTER_EIP) : 0;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
CpuStateX86::GetRegisterValue(const Register* reg, BVariant& _value)
|
||||
{
|
||||
|
||||
@@ -46,6 +46,7 @@ public:
|
||||
CpuStateX86(const debug_cpu_state_x86& state);
|
||||
virtual ~CpuStateX86();
|
||||
|
||||
virtual target_addr_t InstructionPointer() const;
|
||||
virtual bool GetRegisterValue(const Register* reg,
|
||||
BVariant& _value);
|
||||
|
||||
|
||||
@@ -1,76 +0,0 @@
|
||||
/*
|
||||
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
#include "StackFrameX86.h"
|
||||
|
||||
#include "CpuStateX86.h"
|
||||
|
||||
|
||||
StackFrameX86::StackFrameX86(stack_frame_type type, CpuStateX86* cpuState)
|
||||
:
|
||||
fType(type),
|
||||
fCpuState(cpuState),
|
||||
fPreviousFrameAddress(0),
|
||||
fReturnAddress(0)
|
||||
{
|
||||
fCpuState->AddReference();
|
||||
}
|
||||
|
||||
|
||||
StackFrameX86::~StackFrameX86()
|
||||
{
|
||||
fCpuState->RemoveReference();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
StackFrameX86::SetPreviousAddresses(target_addr_t previousFrameAddress,
|
||||
target_addr_t returnAddress)
|
||||
{
|
||||
fPreviousFrameAddress = previousFrameAddress;
|
||||
fReturnAddress = returnAddress;
|
||||
}
|
||||
|
||||
|
||||
stack_frame_type
|
||||
StackFrameX86::Type() const
|
||||
{
|
||||
return fType;
|
||||
}
|
||||
|
||||
|
||||
CpuState*
|
||||
StackFrameX86::GetCpuState() const
|
||||
{
|
||||
return fCpuState;
|
||||
}
|
||||
|
||||
|
||||
target_addr_t
|
||||
StackFrameX86::InstructionPointer() const
|
||||
{
|
||||
return fCpuState->IntRegisterValue(X86_REGISTER_EIP);
|
||||
}
|
||||
|
||||
|
||||
target_addr_t
|
||||
StackFrameX86::FrameAddress() const
|
||||
{
|
||||
return fCpuState->IntRegisterValue(X86_REGISTER_EBP);
|
||||
}
|
||||
|
||||
|
||||
target_addr_t
|
||||
StackFrameX86::ReturnAddress() const
|
||||
{
|
||||
return fReturnAddress;
|
||||
}
|
||||
|
||||
|
||||
target_addr_t
|
||||
StackFrameX86::PreviousFrameAddress() const
|
||||
{
|
||||
return fPreviousFrameAddress;
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
/*
|
||||
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef STACK_FRAME_X86_H
|
||||
#define STACK_FRAME_X86_H
|
||||
|
||||
#include "StackFrame.h"
|
||||
|
||||
|
||||
class CpuStateX86;
|
||||
|
||||
|
||||
class StackFrameX86 : public StackFrame {
|
||||
public:
|
||||
StackFrameX86(stack_frame_type type,
|
||||
CpuStateX86* cpuState);
|
||||
virtual ~StackFrameX86();
|
||||
|
||||
void SetPreviousAddresses(
|
||||
target_addr_t previousFrameAddress,
|
||||
target_addr_t returnAddress);
|
||||
|
||||
virtual stack_frame_type Type() const;
|
||||
|
||||
virtual CpuState* GetCpuState() const;
|
||||
|
||||
virtual target_addr_t InstructionPointer() const;
|
||||
virtual target_addr_t FrameAddress() const;
|
||||
virtual target_addr_t ReturnAddress() const;
|
||||
virtual target_addr_t PreviousFrameAddress() const;
|
||||
|
||||
private:
|
||||
stack_frame_type fType;
|
||||
CpuStateX86* fCpuState;
|
||||
target_addr_t fPreviousFrameAddress;
|
||||
target_addr_t fReturnAddress;
|
||||
};
|
||||
|
||||
|
||||
#endif // STACK_FRAME_X86_H
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
#include "BasicFunctionDebugInfo.h"
|
||||
|
||||
#include "DebugInfo.h"
|
||||
|
||||
|
||||
BasicFunctionDebugInfo::BasicFunctionDebugInfo(DebugInfo* debugInfo,
|
||||
target_addr_t address, target_size_t size, const BString& name,
|
||||
const BString& prettyName)
|
||||
:
|
||||
fDebugInfo(debugInfo),
|
||||
fAddress(address),
|
||||
fSize(size),
|
||||
fName(name),
|
||||
fPrettyName(prettyName)
|
||||
{
|
||||
fDebugInfo->AddReference();
|
||||
}
|
||||
|
||||
|
||||
BasicFunctionDebugInfo::~BasicFunctionDebugInfo()
|
||||
{
|
||||
fDebugInfo->RemoveReference();
|
||||
}
|
||||
|
||||
|
||||
DebugInfo*
|
||||
BasicFunctionDebugInfo::GetDebugInfo() const
|
||||
{
|
||||
return fDebugInfo;
|
||||
}
|
||||
|
||||
|
||||
target_addr_t
|
||||
BasicFunctionDebugInfo::Address() const
|
||||
{
|
||||
return fAddress;
|
||||
}
|
||||
|
||||
|
||||
target_size_t
|
||||
BasicFunctionDebugInfo::Size() const
|
||||
{
|
||||
return fSize;
|
||||
}
|
||||
|
||||
|
||||
const char*
|
||||
BasicFunctionDebugInfo::Name() const
|
||||
{
|
||||
return fName.String();
|
||||
}
|
||||
|
||||
|
||||
const char*
|
||||
BasicFunctionDebugInfo::PrettyName() const
|
||||
{
|
||||
return fPrettyName.String();
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef BASIC_FUNCTION_DEBUG_INFO_H
|
||||
#define BASIC_FUNCTION_DEBUG_INFO_H
|
||||
|
||||
#include <String.h>
|
||||
|
||||
#include "FunctionDebugInfo.h"
|
||||
|
||||
|
||||
class BasicFunctionDebugInfo : public FunctionDebugInfo {
|
||||
public:
|
||||
BasicFunctionDebugInfo(
|
||||
DebugInfo* debugInfo,
|
||||
target_addr_t address,
|
||||
target_size_t size,
|
||||
const BString& name,
|
||||
const BString& prettyName);
|
||||
virtual ~BasicFunctionDebugInfo();
|
||||
|
||||
virtual DebugInfo* GetDebugInfo() const;
|
||||
virtual target_addr_t Address() const;
|
||||
virtual target_size_t Size() const;
|
||||
virtual const char* Name() const;
|
||||
virtual const char* PrettyName() const;
|
||||
|
||||
private:
|
||||
DebugInfo* fDebugInfo;
|
||||
target_addr_t fAddress;
|
||||
target_size_t fSize;
|
||||
const BString fName;
|
||||
const BString fPrettyName;
|
||||
};
|
||||
|
||||
|
||||
#endif // BASIC_FUNCTION_DEBUG_INFO_H
|
||||
@@ -0,0 +1,11 @@
|
||||
/*
|
||||
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
#include "DebugInfo.h"
|
||||
|
||||
|
||||
DebugInfo::~DebugInfo()
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef DEBUG_INFO_H
|
||||
#define DEBUG_INFO_H
|
||||
|
||||
#include <Referenceable.h>
|
||||
|
||||
#include "ArchitectureTypes.h"
|
||||
|
||||
|
||||
class Architecture;
|
||||
class CpuState;
|
||||
class DebuggerInterface;
|
||||
class FunctionDebugInfo;
|
||||
class Image;
|
||||
class StackFrame;
|
||||
|
||||
|
||||
class DebugInfo : public Referenceable {
|
||||
public:
|
||||
virtual ~DebugInfo();
|
||||
|
||||
virtual FunctionDebugInfo* FindFunction(target_addr_t address) = 0;
|
||||
// returns a reference
|
||||
|
||||
virtual status_t CreateFrame(Image* image,
|
||||
FunctionDebugInfo* function,
|
||||
CpuState* cpuState,
|
||||
StackFrame*& _previousFrame,
|
||||
CpuState*& _previousCpuState) = 0;
|
||||
// returns reference to previous frame
|
||||
// and CPU state; returned CPU state
|
||||
// can be NULL; can return B_UNSUPPORTED
|
||||
};
|
||||
|
||||
|
||||
#endif // DEBUG_INFO_H
|
||||
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
#include "DebuggerDebugInfo.h"
|
||||
|
||||
#include <new>
|
||||
|
||||
#include "BasicFunctionDebugInfo.h"
|
||||
#include "DebuggerInterface.h"
|
||||
#include "SymbolInfo.h"
|
||||
|
||||
|
||||
struct DebuggerDebugInfo::FindByAddressPredicate : UnaryPredicate<SymbolInfo> {
|
||||
FindByAddressPredicate(target_addr_t address)
|
||||
:
|
||||
fAddress(address)
|
||||
{
|
||||
}
|
||||
|
||||
virtual int operator()(const SymbolInfo* info) const
|
||||
{
|
||||
if (fAddress < info->Address())
|
||||
return -1;
|
||||
return fAddress < info->Address() + info->Size() ? 0 : 1;
|
||||
}
|
||||
|
||||
private:
|
||||
target_addr_t fAddress;
|
||||
};
|
||||
|
||||
|
||||
DebuggerDebugInfo::DebuggerDebugInfo(const ImageInfo& imageInfo,
|
||||
DebuggerInterface* debuggerInterface, Architecture* architecture)
|
||||
:
|
||||
fImageInfo(imageInfo),
|
||||
fDebuggerInterface(debuggerInterface),
|
||||
fArchitecture(architecture),
|
||||
fSymbols(20, true)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
DebuggerDebugInfo::~DebuggerDebugInfo()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
DebuggerDebugInfo::Init()
|
||||
{
|
||||
// TODO: Extend DebuggerInterface to find a symbol on demand!
|
||||
|
||||
status_t error = fDebuggerInterface->GetSymbolInfos(fImageInfo.TeamID(),
|
||||
fImageInfo.ImageID(), fSymbols);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
// sort the symbols
|
||||
fSymbols.SortItems(&_CompareSymbols);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
FunctionDebugInfo*
|
||||
DebuggerDebugInfo::FindFunction(target_addr_t address)
|
||||
{
|
||||
SymbolInfo* symbolInfo = _FindSymbol(address);
|
||||
if (symbolInfo == NULL || symbolInfo->Type() != B_SYMBOL_TYPE_TEXT)
|
||||
return NULL;
|
||||
|
||||
return new(std::nothrow) BasicFunctionDebugInfo(this, symbolInfo->Address(),
|
||||
symbolInfo->Size(), symbolInfo->Name(), symbolInfo->Name());
|
||||
// TODO: Demangle!
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
DebuggerDebugInfo::CreateFrame(Image* image, FunctionDebugInfo* function,
|
||||
CpuState* cpuState, StackFrame*& _previousFrame,
|
||||
CpuState*& _previousCpuState)
|
||||
{
|
||||
return B_UNSUPPORTED;
|
||||
}
|
||||
|
||||
|
||||
SymbolInfo*
|
||||
DebuggerDebugInfo::_FindSymbol(target_addr_t address)
|
||||
{
|
||||
return fSymbols.BinarySearchByKey(address, &_CompareAddressSymbol);
|
||||
}
|
||||
|
||||
|
||||
/*static*/ int
|
||||
DebuggerDebugInfo::_CompareSymbols(const SymbolInfo* a, const SymbolInfo* b)
|
||||
{
|
||||
return a->Address() < b->Address()
|
||||
? -1 : (a->Address() == b->Address() ? 0 : 1);
|
||||
}
|
||||
|
||||
|
||||
/*static*/ int
|
||||
DebuggerDebugInfo::_CompareAddressSymbol(const target_addr_t* address,
|
||||
const SymbolInfo* info)
|
||||
{
|
||||
if (*address < info->Address())
|
||||
return -1;
|
||||
return *address < info->Address() + info->Size() ? 0 : 1;
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef DEBUGGER_DEBUG_INFO_H
|
||||
#define DEBUGGER_DEBUG_INFO_H
|
||||
|
||||
#include <String.h>
|
||||
|
||||
#include <ObjectList.h>
|
||||
|
||||
#include "DebugInfo.h"
|
||||
#include "ImageInfo.h"
|
||||
|
||||
|
||||
class Architecture;
|
||||
class DebuggerInterface;
|
||||
class FunctionDebugInfo;
|
||||
class SymbolInfo;
|
||||
|
||||
|
||||
class DebuggerDebugInfo : public DebugInfo {
|
||||
public:
|
||||
DebuggerDebugInfo(const ImageInfo& imageInfo,
|
||||
DebuggerInterface* debuggerInterface,
|
||||
Architecture* architecture);
|
||||
virtual ~DebuggerDebugInfo();
|
||||
|
||||
status_t Init();
|
||||
|
||||
virtual FunctionDebugInfo* FindFunction(target_addr_t address);
|
||||
virtual status_t CreateFrame(Image* image,
|
||||
FunctionDebugInfo* function,
|
||||
CpuState* cpuState,
|
||||
StackFrame*& _previousFrame,
|
||||
CpuState*& _previousCpuState);
|
||||
|
||||
private:
|
||||
typedef BObjectList<SymbolInfo> SymbolList;
|
||||
|
||||
struct FindByAddressPredicate;
|
||||
|
||||
private:
|
||||
SymbolInfo* _FindSymbol(target_addr_t address);
|
||||
static int _CompareSymbols(const SymbolInfo* a,
|
||||
const SymbolInfo* b);
|
||||
static int _CompareAddressSymbol(
|
||||
const target_addr_t* address,
|
||||
const SymbolInfo* info);
|
||||
|
||||
private:
|
||||
ImageInfo fImageInfo;
|
||||
DebuggerInterface* fDebuggerInterface;
|
||||
Architecture* fArchitecture;
|
||||
SymbolList fSymbols;
|
||||
};
|
||||
|
||||
|
||||
#endif // DEBUGGER_DEBUG_INFO_H
|
||||
@@ -0,0 +1,12 @@
|
||||
/*
|
||||
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
#include "FunctionDebugInfo.h"
|
||||
|
||||
|
||||
FunctionDebugInfo::~FunctionDebugInfo()
|
||||
{
|
||||
}
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef FUNCTION_DEBUG_INFO_H
|
||||
#define FUNCTION_DEBUG_INFO_H
|
||||
|
||||
#include <Referenceable.h>
|
||||
|
||||
#include "ArchitectureTypes.h"
|
||||
|
||||
|
||||
class DebugInfo;
|
||||
|
||||
|
||||
class FunctionDebugInfo : public Referenceable {
|
||||
public:
|
||||
virtual ~FunctionDebugInfo();
|
||||
|
||||
virtual DebugInfo* GetDebugInfo() const = 0;
|
||||
virtual target_addr_t Address() const = 0;
|
||||
virtual target_size_t Size() const = 0;
|
||||
virtual const char* Name() const = 0;
|
||||
virtual const char* PrettyName() const = 0;
|
||||
};
|
||||
|
||||
|
||||
#endif // FUNCTION_DEBUG_INFO_H
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
#include "ImageDebugInfo.h"
|
||||
|
||||
#include <new>
|
||||
|
||||
#include "DebuggerDebugInfo.h"
|
||||
|
||||
|
||||
ImageDebugInfo::ImageDebugInfo(const ImageInfo& imageInfo,
|
||||
DebuggerInterface* debuggerInterface, Architecture* architecture)
|
||||
:
|
||||
fImageInfo(imageInfo),
|
||||
fDebuggerInterface(debuggerInterface),
|
||||
fArchitecture(architecture)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
ImageDebugInfo::~ImageDebugInfo()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
ImageDebugInfo::Init()
|
||||
{
|
||||
// Create debug infos for every kind debug info available, sorted
|
||||
// descendingly by expressiveness.
|
||||
|
||||
// TODO: DWARF, etc.
|
||||
|
||||
// debugger based info
|
||||
DebuggerDebugInfo* debuggerDebugInfo = new(std::nothrow) DebuggerDebugInfo(
|
||||
fImageInfo, fDebuggerInterface, fArchitecture);
|
||||
if (debuggerDebugInfo == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
status_t error = debuggerDebugInfo->Init();
|
||||
if (error == B_OK && !fDebugInfos.AddItem(debuggerDebugInfo))
|
||||
error = B_NO_MEMORY;
|
||||
|
||||
if (error != B_OK) {
|
||||
delete debuggerDebugInfo;
|
||||
if (error == B_NO_MEMORY)
|
||||
return error;
|
||||
// only "no memory" is fatal
|
||||
}
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
FunctionDebugInfo*
|
||||
ImageDebugInfo::FindFunction(target_addr_t address)
|
||||
{
|
||||
for (int32 i = 0; DebugInfo* debugInfo = fDebugInfos.ItemAt(i); i++) {
|
||||
FunctionDebugInfo* functionInfo = debugInfo->FindFunction(address);
|
||||
if (functionInfo)
|
||||
return functionInfo;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef IMAGE_DEBUG_INFO_H
|
||||
#define IMAGE_DEBUG_INFO_H
|
||||
|
||||
#include <String.h>
|
||||
|
||||
#include <ObjectList.h>
|
||||
#include <Referenceable.h>
|
||||
|
||||
#include "ArchitectureTypes.h"
|
||||
#include "ImageInfo.h"
|
||||
|
||||
|
||||
class Architecture;
|
||||
class DebuggerInterface;
|
||||
class DebugInfo;
|
||||
class FunctionDebugInfo;
|
||||
|
||||
|
||||
class ImageDebugInfo : public Referenceable {
|
||||
public:
|
||||
ImageDebugInfo(const ImageInfo& imageInfo,
|
||||
DebuggerInterface* debuggerInterface,
|
||||
Architecture* architecture);
|
||||
~ImageDebugInfo();
|
||||
|
||||
status_t Init();
|
||||
|
||||
FunctionDebugInfo* FindFunction(target_addr_t address);
|
||||
// returns a reference
|
||||
|
||||
private:
|
||||
typedef BObjectList<DebugInfo> DebugInfoList;
|
||||
|
||||
private:
|
||||
ImageInfo fImageInfo;
|
||||
DebuggerInterface* fDebuggerInterface;
|
||||
Architecture* fArchitecture;
|
||||
DebugInfoList fDebugInfos;
|
||||
};
|
||||
|
||||
|
||||
#endif // IMAGE_DEBUG_INFO_H
|
||||
@@ -0,0 +1,11 @@
|
||||
/*
|
||||
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
#include "ImageDebugInfoProvider.h"
|
||||
|
||||
|
||||
ImageDebugInfoProvider::~ImageDebugInfoProvider()
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef IMAGE_DEBUG_INFO_PROVIDER_H
|
||||
#define IMAGE_DEBUG_INFO_PROVIDER_H
|
||||
|
||||
#include <SupportDefs.h>
|
||||
|
||||
|
||||
class Image;
|
||||
class ImageDebugInfo;
|
||||
|
||||
|
||||
class ImageDebugInfoProvider {
|
||||
public:
|
||||
virtual ~ImageDebugInfoProvider();
|
||||
|
||||
virtual status_t GetImageDebugInfo(Image* image,
|
||||
ImageDebugInfo*& _info) = 0;
|
||||
// returns a reference
|
||||
};
|
||||
|
||||
|
||||
#endif // IMAGE_DEBUG_INFO_PROVIDER_H
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "CpuState.h"
|
||||
#include "DebugEvent.h"
|
||||
#include "ImageInfo.h"
|
||||
#include "SymbolInfo.h"
|
||||
#include "ThreadInfo.h"
|
||||
|
||||
|
||||
@@ -386,7 +387,8 @@ DebuggerInterface::GetImageInfos(BObjectList<ImageInfo>& infos)
|
||||
int32 cookie = 0;
|
||||
while (get_next_image_info(fTeamID, &cookie, &imageInfo) == B_OK) {
|
||||
ImageInfo* info = new(std::nothrow) ImageInfo(fTeamID, imageInfo.id,
|
||||
imageInfo.name);
|
||||
imageInfo.name, (addr_t)imageInfo.text, imageInfo.text_size,
|
||||
(addr_t)imageInfo.data, imageInfo.data_size);
|
||||
if (info == NULL || !infos.AddItem(info)) {
|
||||
delete info;
|
||||
return B_NO_MEMORY;
|
||||
@@ -397,6 +399,51 @@ DebuggerInterface::GetImageInfos(BObjectList<ImageInfo>& infos)
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
DebuggerInterface::GetSymbolInfos(team_id team, image_id image,
|
||||
BObjectList<SymbolInfo>& infos)
|
||||
{
|
||||
// create a lookup context
|
||||
// TODO: It's too expensive to create a lookup context for each image!
|
||||
debug_symbol_lookup_context* lookupContext;
|
||||
status_t error = debug_create_symbol_lookup_context(team, &lookupContext);
|
||||
if (error != B_OK)
|
||||
return error;
|
||||
|
||||
// create a symbol iterator
|
||||
debug_symbol_iterator* iterator;
|
||||
error = debug_create_image_symbol_iterator(
|
||||
lookupContext, image, &iterator);
|
||||
if (error != B_OK) {
|
||||
debug_delete_symbol_lookup_context(lookupContext);
|
||||
return error;
|
||||
}
|
||||
|
||||
// get the symbols
|
||||
char name[1024];
|
||||
int32 type;
|
||||
void* address;
|
||||
size_t size;
|
||||
while (debug_next_image_symbol(iterator, name, sizeof(name), &type,
|
||||
&address, &size) == B_OK) {
|
||||
SymbolInfo* info = new(std::nothrow) SymbolInfo(
|
||||
(target_addr_t)(addr_t)address, size, type, name);
|
||||
if (info == NULL)
|
||||
break;
|
||||
if (!infos.AddItem(info)) {
|
||||
delete info;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// delete the symbol iterator and lookup context
|
||||
debug_delete_symbol_iterator(iterator);
|
||||
debug_delete_symbol_lookup_context(lookupContext);
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
DebuggerInterface::GetThreadInfo(thread_id thread, ThreadInfo& info)
|
||||
{
|
||||
@@ -536,14 +583,18 @@ DebuggerInterface::_CreateDebugEvent(int32 messageCode,
|
||||
{
|
||||
const image_info& info = message.image_created.info;
|
||||
event = new(std::nothrow) ImageCreatedEvent(message.origin.team,
|
||||
message.origin.thread, ImageInfo(fTeamID, info.id, info.name));
|
||||
message.origin.thread,
|
||||
ImageInfo(fTeamID, info.id, info.name, (addr_t)info.text,
|
||||
info.text_size, (addr_t)info.data, info.data_size));
|
||||
break;
|
||||
}
|
||||
case B_DEBUGGER_MESSAGE_IMAGE_DELETED:
|
||||
{
|
||||
const image_info& info = message.image_deleted.info;
|
||||
event = new(std::nothrow) ImageDeletedEvent(message.origin.team,
|
||||
message.origin.thread, ImageInfo(fTeamID, info.id, info.name));
|
||||
message.origin.thread,
|
||||
ImageInfo(fTeamID, info.id, info.name, (addr_t)info.text,
|
||||
info.text_size, (addr_t)info.data, info.data_size));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
||||
@@ -17,6 +17,7 @@ class Architecture;
|
||||
class CpuState;
|
||||
class DebugEvent;
|
||||
class ImageInfo;
|
||||
class SymbolInfo;
|
||||
class ThreadInfo;
|
||||
|
||||
|
||||
@@ -41,6 +42,8 @@ public:
|
||||
|
||||
virtual status_t GetThreadInfos(BObjectList<ThreadInfo>& infos);
|
||||
virtual status_t GetImageInfos(BObjectList<ImageInfo>& infos);
|
||||
virtual status_t GetSymbolInfos(team_id team, image_id image,
|
||||
BObjectList<SymbolInfo>& infos);
|
||||
|
||||
virtual status_t GetThreadInfo(thread_id thread,
|
||||
ThreadInfo& info);
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
|
||||
#include "table/TableColumns.h"
|
||||
|
||||
#include "FunctionDebugInfo.h"
|
||||
#include "Image.h"
|
||||
#include "StackTrace.h"
|
||||
|
||||
|
||||
@@ -66,30 +68,14 @@ public:
|
||||
void SetStackTrace(StackTrace* stackTrace)
|
||||
{
|
||||
// unset old frames
|
||||
if (fFrames.CountItems() > 0) {
|
||||
NotifyRowsRemoved(0, fFrames.CountItems());
|
||||
|
||||
for (int32 i = 0; StackFrame* frame = fFrames.ItemAt(i); i++)
|
||||
frame->RemoveReference();
|
||||
|
||||
fFrames.MakeEmpty();
|
||||
}
|
||||
if (fStackTrace != NULL && fStackTrace->CountFrames())
|
||||
NotifyRowsRemoved(0, fStackTrace->CountFrames());
|
||||
|
||||
fStackTrace = stackTrace;
|
||||
|
||||
// set new frames
|
||||
if (fStackTrace != NULL) {
|
||||
for (StackFrameList::ConstIterator it
|
||||
= fStackTrace->Frames().GetIterator();
|
||||
StackFrame* frame = it.Next();) {
|
||||
if (!fFrames.AddItem(frame))
|
||||
return;
|
||||
frame->AddReference();
|
||||
}
|
||||
|
||||
if (fFrames.CountItems() > 0)
|
||||
NotifyRowsAdded(0, fFrames.CountItems());
|
||||
}
|
||||
if (fStackTrace != NULL && fStackTrace->CountFrames() > 0)
|
||||
NotifyRowsAdded(0, fStackTrace->CountFrames());
|
||||
}
|
||||
|
||||
virtual int32 CountColumns() const
|
||||
@@ -99,12 +85,13 @@ public:
|
||||
|
||||
virtual int32 CountRows() const
|
||||
{
|
||||
return fFrames.CountItems();
|
||||
return fStackTrace != NULL ? fStackTrace->CountFrames() : 0;
|
||||
}
|
||||
|
||||
virtual bool GetValueAt(int32 rowIndex, int32 columnIndex, BVariant& value)
|
||||
{
|
||||
StackFrame* frame = fFrames.ItemAt(rowIndex);
|
||||
StackFrame* frame
|
||||
= fStackTrace != NULL ? fStackTrace->FrameAt(rowIndex) : NULL;
|
||||
if (frame == NULL)
|
||||
return false;
|
||||
|
||||
@@ -116,8 +103,33 @@ public:
|
||||
value.SetTo(frame->InstructionPointer());
|
||||
return true;
|
||||
case 2:
|
||||
// TODO: function name...
|
||||
return false;
|
||||
{
|
||||
Image* image = frame->GetImage();
|
||||
FunctionDebugInfo* function = frame->Function();
|
||||
if (image == NULL && function == NULL) {
|
||||
value.SetTo("?", B_VARIANT_DONT_COPY_DATA);
|
||||
return true;
|
||||
}
|
||||
|
||||
BString name;
|
||||
target_addr_t baseAddress;
|
||||
if (function != NULL) {
|
||||
name = function->PrettyName();
|
||||
baseAddress = function->Address();
|
||||
} else {
|
||||
name = image->Name();
|
||||
baseAddress = image->Info().TextBase();
|
||||
}
|
||||
|
||||
char offset[32];
|
||||
snprintf(offset, sizeof(offset), " + %#llx",
|
||||
frame->InstructionPointer() - baseAddress);
|
||||
|
||||
name << offset;
|
||||
value.SetTo(name.String());
|
||||
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
@@ -125,7 +137,6 @@ public:
|
||||
|
||||
private:
|
||||
StackTrace* fStackTrace;
|
||||
BObjectList<StackFrame> fFrames;
|
||||
};
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user