* Worker:

- Made Job Referenceable.
  - Turned JobKey into an abstract base class to add flexibility. The new
    SimpleJobKey is a subclass with the former functionality.
* TeamWindow: Removed the TeamWindow* parameter from the listener hooks. The
  TeamDebugger knows anyway.
* Added IDs to Variable, Function, and FunctionInstance. The latter two generate
  the ID on the fly, Variable stores it.
* SpecificImageDebugInfo::CreateFrame(): Changed FunctionDebugInfo* debug
  parameter to FunctionInstance* to provide more info (the function ID).
* DwarfInterfaceFactory/DwarfImageDebugInfo:
  - Added class DwarfFunctionParameterID, an ID class implementation for
    function parameters and set the IDs on the parameter objects.
  - Retrieve the size of a type (i.e. the size of its objects) and store it in
    DwarfType.
  - If a parameter's ValueLocation doesn't have a size, set that of the
    respective type.
  - Map the register indicies in the parameters' ValueLocations from DWARF to
    our indices.
* Added class TypeComponentPath for identifying subcomponents in types.
* Added class StackFrameValues, a container associating variables and their
  subcomponents with values.
* StackFrame does now have a StackFrameValues object for parameters and local
  variables and a mechanism to notify listeners when values have been retrieved.
* Added GetStackFrameValueJob to retrieve variable values. Lots of functionality
  is missing yet. Most notably it doesn't retrieves values for subcomponents.
* Wired everything to trigger loading of variable values and getting notified
  when done.
* VariablesView: Added a value column. This is all very basic and has to be
  done differently, but at least values for the parameters can be seen already.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@31636 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Ingo Weinhold
2009-07-18 23:52:16 +00:00
parent bcbd46eba3
commit da4d62db94
34 changed files with 1792 additions and 151 deletions
+10
View File
@@ -13,6 +13,7 @@ SEARCH_SOURCE += [ FDirName $(SUBDIR) debugger_interface ] ;
SEARCH_SOURCE += [ FDirName $(SUBDIR) elf ] ;
SEARCH_SOURCE += [ FDirName $(SUBDIR) files ] ;
SEARCH_SOURCE += [ FDirName $(SUBDIR) gui team_window ] ;
SEARCH_SOURCE += [ FDirName $(SUBDIR) ids ] ;
SEARCH_SOURCE += [ FDirName $(SUBDIR) model ] ;
SEARCH_SOURCE += [ FDirName $(SUBDIR) source_language ] ;
SEARCH_SOURCE += [ FDirName $(SUBDIR) types ] ;
@@ -93,6 +94,12 @@ Application Debugger :
ThreadListView.cpp
VariablesView.cpp
# ids
FunctionID.cpp
LocalVariableID.cpp
ObjectID.cpp
FunctionParameterID.cpp
# model
Breakpoint.cpp
DisassembledCode.cpp
@@ -101,6 +108,7 @@ Application Debugger :
ImageInfo.cpp
SourceCode.cpp
StackFrame.cpp
StackFrameValues.cpp
StackTrace.cpp
Statement.cpp
SymbolInfo.cpp
@@ -111,6 +119,7 @@ Application Debugger :
Thread.cpp
ThreadInfo.cpp
Type.cpp
TypeComponentPath.cpp
Variable.cpp
# source_language
@@ -127,6 +136,7 @@ Application Debugger :
ValueLocation.cpp
# util
BitBuffer.cpp
StringUtils.cpp
:
+339 -28
View File
@@ -10,6 +10,7 @@
#include <AutoLocker.h>
#include "Architecture.h"
#include "BitBuffer.h"
#include "CpuState.h"
#include "DebuggerInterface.h"
#include "DisassembledCode.h"
@@ -17,12 +18,19 @@
#include "Function.h"
#include "Image.h"
#include "ImageDebugInfo.h"
#include "Register.h"
#include "SourceCode.h"
#include "SpecificImageDebugInfo.h"
#include "StackFrameValues.h"
#include "StackTrace.h"
#include "Team.h"
#include "TeamDebugInfo.h"
#include "TeamDebugModel.h"
#include "Thread.h"
#include "Type.h"
#include "TypeComponentPath.h"
#include "ValueLocation.h"
#include "Variable.h"
// #pragma mark - GetThreadStateJob
@@ -31,23 +39,24 @@
GetThreadStateJob::GetThreadStateJob(DebuggerInterface* debuggerInterface,
Thread* thread)
:
fKey(thread, JOB_TYPE_GET_THREAD_STATE),
fDebuggerInterface(debuggerInterface),
fThread(thread)
{
fThread->AddReference();
fThread->AcquireReference();
}
GetThreadStateJob::~GetThreadStateJob()
{
fThread->RemoveReference();
fThread->ReleaseReference();
}
JobKey
const JobKey&
GetThreadStateJob::Key() const
{
return JobKey(fThread, JOB_TYPE_GET_THREAD_STATE);
return fKey;
}
@@ -81,23 +90,24 @@ GetThreadStateJob::Do()
GetCpuStateJob::GetCpuStateJob(DebuggerInterface* debuggerInterface,
Thread* thread)
:
fKey(thread, JOB_TYPE_GET_CPU_STATE),
fDebuggerInterface(debuggerInterface),
fThread(thread)
{
fThread->AddReference();
fThread->AcquireReference();
}
GetCpuStateJob::~GetCpuStateJob()
{
fThread->RemoveReference();
fThread->ReleaseReference();
}
JobKey
const JobKey&
GetCpuStateJob::Key() const
{
return JobKey(fThread, JOB_TYPE_GET_CPU_STATE);
return fKey;
}
@@ -125,31 +135,32 @@ GetCpuStateJob::Do()
GetStackTraceJob::GetStackTraceJob(DebuggerInterface* debuggerInterface,
Architecture* architecture, Thread* thread)
:
fKey(thread, JOB_TYPE_GET_STACK_TRACE),
fDebuggerInterface(debuggerInterface),
fArchitecture(architecture),
fThread(thread)
{
fThread->AddReference();
fThread->AcquireReference();
fCpuState = fThread->GetCpuState();
if (fCpuState != NULL)
fCpuState->AddReference();
fCpuState->AcquireReference();
}
GetStackTraceJob::~GetStackTraceJob()
{
if (fCpuState != NULL)
fCpuState->RemoveReference();
fCpuState->ReleaseReference();
fThread->RemoveReference();
fThread->ReleaseReference();
}
JobKey
const JobKey&
GetStackTraceJob::Key() const
{
return JobKey(fThread, JOB_TYPE_GET_CPU_STATE);
return fKey;
}
@@ -198,7 +209,7 @@ GetStackTraceJob::GetImageDebugInfo(Image* image, ImageDebugInfo*& _info)
teamLocker.Unlock();
// wait for the job to finish
switch (WaitFor(JobKey(image, JOB_TYPE_LOAD_IMAGE_DEBUG_INFO))) {
switch (WaitFor(SimpleJobKey(image, JOB_TYPE_LOAD_IMAGE_DEBUG_INFO))) {
case JOB_DEPENDENCY_SUCCEEDED:
case JOB_DEPENDENCY_NOT_FOUND:
// "Not found" can happen due to a race condition between
@@ -214,7 +225,7 @@ GetStackTraceJob::GetImageDebugInfo(Image* image, ImageDebugInfo*& _info)
}
_info = image->GetImageDebugInfo();
_info->AddReference();
_info->AcquireReference();
return B_OK;
}
@@ -225,22 +236,23 @@ GetStackTraceJob::GetImageDebugInfo(Image* image, ImageDebugInfo*& _info)
LoadImageDebugInfoJob::LoadImageDebugInfoJob(Image* image)
:
fKey(image, JOB_TYPE_LOAD_IMAGE_DEBUG_INFO),
fImage(image)
{
fImage->AddReference();
fImage->AcquireReference();
}
LoadImageDebugInfoJob::~LoadImageDebugInfoJob()
{
fImage->RemoveReference();
fImage->ReleaseReference();
}
JobKey
const JobKey&
LoadImageDebugInfoJob::Key() const
{
return JobKey(fImage, JOB_TYPE_LOAD_IMAGE_DEBUG_INFO);
return fKey;
}
@@ -261,7 +273,7 @@ LoadImageDebugInfoJob::Do()
locker.Lock();
if (error == B_OK) {
error = fImage->SetImageDebugInfo(debugInfo, IMAGE_DEBUG_INFO_LOADED);
debugInfo->RemoveReference();
debugInfo->ReleaseReference();
} else {
fImage->SetImageDebugInfo(NULL, IMAGE_DEBUG_INFO_UNAVAILABLE);
delete debugInfo;
@@ -281,7 +293,7 @@ LoadImageDebugInfoJob::ScheduleIfNecessary(Worker* worker, Image* image,
if (image->GetImageDebugInfo() != NULL) {
if (_imageDebugInfo != NULL) {
*_imageDebugInfo = image->GetImageDebugInfo();
(*_imageDebugInfo)->AddReference();
(*_imageDebugInfo)->AcquireReference();
}
return B_OK;
}
@@ -323,26 +335,27 @@ LoadSourceCodeJob::LoadSourceCodeJob(
DebuggerInterface* debuggerInterface, Architecture* architecture,
Team* team, FunctionInstance* functionInstance, bool loadForFunction)
:
fKey(functionInstance, JOB_TYPE_LOAD_SOURCE_CODE),
fDebuggerInterface(debuggerInterface),
fArchitecture(architecture),
fTeam(team),
fFunctionInstance(functionInstance),
fLoadForFunction(loadForFunction)
{
fFunctionInstance->AddReference();
fFunctionInstance->AcquireReference();
}
LoadSourceCodeJob::~LoadSourceCodeJob()
{
fFunctionInstance->RemoveReference();
fFunctionInstance->ReleaseReference();
}
JobKey
const JobKey&
LoadSourceCodeJob::Key() const
{
return JobKey(fFunctionInstance, JOB_TYPE_LOAD_SOURCE_CODE);
return fKey;
}
@@ -360,7 +373,7 @@ LoadSourceCodeJob::Do()
if (error == B_OK) {
function->SetSourceCode(sourceCode, FUNCTION_SOURCE_LOADED);
sourceCode->RemoveReference();
sourceCode->ReleaseReference();
return B_OK;
}
@@ -384,10 +397,308 @@ LoadSourceCodeJob::Do()
if (fFunctionInstance->SourceCodeState() == FUNCTION_SOURCE_LOADING) {
fFunctionInstance->SetSourceCode(sourceCode,
FUNCTION_SOURCE_LOADED);
sourceCode->RemoveReference();
sourceCode->ReleaseReference();
}
} else
fFunctionInstance->SetSourceCode(NULL, FUNCTION_SOURCE_UNAVAILABLE);
return error;
}
// #pragma mark - GetStackFrameValueJobKey
GetStackFrameValueJobKey::GetStackFrameValueJobKey(StackFrame* stackFrame,
Variable* variable, TypeComponentPath* path)
:
stackFrame(stackFrame),
variable(variable),
path(path)
{
}
uint32
GetStackFrameValueJobKey::HashValue() const
{
uint32 hash = (uint32)(addr_t)stackFrame;
hash = hash * 13 + (uint32)(addr_t)variable;
return hash * 13 + path->HashValue();
}
bool
GetStackFrameValueJobKey::operator==(const JobKey& other) const
{
const GetStackFrameValueJobKey* otherKey
= dynamic_cast<const GetStackFrameValueJobKey*>(&other);
return otherKey != NULL && stackFrame == otherKey->stackFrame
&& variable == otherKey->variable && *path == *otherKey->path;
}
// #pragma mark - GetStackFrameValueJob
GetStackFrameValueJob::GetStackFrameValueJob(
DebuggerInterface* debuggerInterface, Architecture* architecture,
TeamDebugModel* debugModel, Thread* thread, StackFrame* stackFrame,
Variable* variable, TypeComponentPath* path)
:
fKey(stackFrame, variable, path),
fDebuggerInterface(debuggerInterface),
fArchitecture(architecture),
fDebugModel(debugModel),
fThread(thread),
fStackFrame(stackFrame),
fVariable(variable),
fPath(path)
{
fThread->AcquireReference();
fStackFrame->AcquireReference();
fVariable->AcquireReference();
fPath->AcquireReference();
}
GetStackFrameValueJob::~GetStackFrameValueJob()
{
fThread->ReleaseReference();
fStackFrame->ReleaseReference();
fVariable->ReleaseReference();
fPath->ReleaseReference();
}
const JobKey&
GetStackFrameValueJob::Key() const
{
return fKey;
}
status_t
GetStackFrameValueJob::Do()
{
status_t error = _GetValue();
if (error == B_OK)
return B_OK;
// in case of error, set the value to invalid to avoid triggering this job
// again
AutoLocker<TeamDebugModel> locker(fDebugModel);
fStackFrame->Values()->SetValue(fVariable->ID(), fPath, BVariant());
return error;
}
status_t
GetStackFrameValueJob::_GetValue()
{
printf("GetStackFrameValueJob::_GetValue()\n");
if (fPath->CountComponents() > 0)
{
printf(" -> non-empty path\n");
return B_UNSUPPORTED;
// TODO: Implement!
}
// find out the type of the data we want to read
Type* type = fVariable->GetType();
type_code valueType = 0;
while (valueType == 0) {
switch (type->Kind()) {
case TYPE_PRIMITIVE:
valueType = dynamic_cast<PrimitiveType*>(type)->TypeConstant();
printf(" TYPE_PRIMITIVE: '%c%c%c%c'\n", int(valueType >> 24),
int(valueType >> 16), int(valueType >> 8), int(valueType));
if (valueType == 0)
{
printf(" -> unknown type constant\n");
return B_BAD_VALUE;
}
break;
case TYPE_MODIFIED:
printf(" TYPE_MODIFIED\n");
// ignore modifiers
type = dynamic_cast<ModifiedType*>(type)->BaseType();
break;
case TYPE_TYPEDEF:
printf(" TYPE_TYPEDEF\n");
type = dynamic_cast<TypedefType*>(type)->BaseType();
break;
case TYPE_ADDRESS:
printf(" TYPE_ADDRESS\n");
if (fArchitecture->AddressSize() == 4)
{
valueType = B_UINT32_TYPE;
printf(" -> 32 bit\n");
}
else
{
valueType = B_UINT64_TYPE;
printf(" -> 64 bit\n");
}
break;
case TYPE_COMPOUND:
case TYPE_ARRAY:
default:
printf(" TYPE_COMPOUND/TYPE_ARRAY/default\n");
// TODO:...
printf(" -> unsupported\n");
return B_UNSUPPORTED;
}
}
if (valueType == B_STRING_TYPE)
{
printf(" -> B_STRING_TYPE: unsupported\n");
return B_UNSUPPORTED;
// TODO:...
}
// check whether we know the complete location
ValueLocation* location = fVariable->Location();
int32 count = location->CountPieces();
printf(" location: %p, %ld pieces\n", location, count);
if (count == 0)
{
printf(" -> no location\n");
return B_ENTRY_NOT_FOUND;
}
target_size_t totalSize = 0;
uint64 totalBitSize = 0;
for (int32 i = 0; i < count; i++) {
ValuePieceLocation piece = location->PieceAt(i);
switch (piece.type) {
case VALUE_PIECE_LOCATION_INVALID:
case VALUE_PIECE_LOCATION_UNKNOWN:
return B_ENTRY_NOT_FOUND;
case VALUE_PIECE_LOCATION_MEMORY:
case VALUE_PIECE_LOCATION_REGISTER:
break;
}
totalSize += piece.size;
totalBitSize += piece.bitSize;
}
printf(" -> totalSize: %llu, totalBitSize: %llu\n", totalSize, totalBitSize);
if (totalSize == 0 && totalBitSize == 0)
{
printf(" -> no size\n");
return B_ENTRY_NOT_FOUND;
}
if (totalSize > 8 || totalSize + (totalBitSize + 7) / 8 > 8)
{
printf(" -> longer than 8 bytes: unsupported\n");
return B_UNSUPPORTED;
}
if (totalSize + (totalBitSize + 7) / 8 < BVariant::SizeOfType(valueType))
{
printf(" -> too short for value type (%llu vs. %lu)\n",
totalSize + (totalBitSize + 7) / 8, BVariant::SizeOfType(valueType));
return B_BAD_VALUE;
}
// load the data
BitBuffer valueBuffer;
// If the total bit size is not byte aligned, push the respective number of
// 0 bits on a big endian architecture to get an immediately usable value.
// On a little endian architecture we'll play with the last read byte
// instead.
if (fArchitecture->IsBigEndian() && totalBitSize % 8 != 0) {
const uint8 zero = 0;
valueBuffer.AddBits(&zero, 8 - totalBitSize % 8, 0);
}
const Register* registers = fArchitecture->Registers();
for (int32 i = 0; i < count; i++) {
ValuePieceLocation piece = location->PieceAt(i);
uint8 bitOffset = piece.bitOffset;
uint32 bitSize = piece.size * 8 + piece.bitSize;
uint32 bytesToRead = (bitSize + 7) / 8;
switch (piece.type) {
case VALUE_PIECE_LOCATION_INVALID:
case VALUE_PIECE_LOCATION_UNKNOWN:
return B_ENTRY_NOT_FOUND;
case VALUE_PIECE_LOCATION_MEMORY:
{
target_addr_t address = piece.address + bitOffset / 8;
printf(" piece %ld: memory address: %#llx, bits: %lu\n", i, address, bitSize);
bitOffset %= 8;
uint8 pieceBuffer[8];
ssize_t bytesRead = fDebuggerInterface->ReadMemory(address,
pieceBuffer, bytesToRead);
if (bytesRead < 0)
return bytesRead;
if ((uint32)bytesRead != bytesToRead)
return B_BAD_ADDRESS;
printf(" -> read: ");
for (ssize_t k = 0; k < bytesRead; k++)
printf("%02x", pieceBuffer[k]);
printf("\n");
valueBuffer.AddBits(pieceBuffer, bitSize, bitOffset);
break;
}
case VALUE_PIECE_LOCATION_REGISTER:
{
printf(" piece %ld: register: %lu, bits: %lu\n", i, piece.reg, bitSize);
BVariant registerValue;
if (!fStackFrame->GetCpuState()->GetRegisterValue(
registers + piece.reg, registerValue)) {
return B_ENTRY_NOT_FOUND;
}
if (registerValue.Size() < bytesToRead)
return B_ENTRY_NOT_FOUND;
if (!fArchitecture->IsHostEndian())
registerValue.SwapEndianess();
valueBuffer.AddBits(registerValue.Bytes(), bitSize, bitOffset);
break;
}
}
}
// If the total bit size is not byte aligned, shift the last byte by the
// respective number of bits on a little endian architecture to get a usable
// value.
if (!fArchitecture->IsBigEndian() && totalBitSize % 8 != 0)
valueBuffer.Bytes()[totalBitSize / 8] >>= 8 - totalBitSize % 8;
// TODO: Verify that this is the way to handle it!
// convert the bits into something we can work with
BVariant value;
status_t error = value.SetToTypedData(valueBuffer.Bytes(), valueType);
if (error != B_OK)
{
printf(" -> failed to set typed data: %s\n", strerror(error));
return error;
}
if (!fArchitecture->IsHostEndian())
value.SwapEndianess();
// set the value
AutoLocker<TeamDebugModel> locker(fDebugModel);
StackFrameValues* values = fStackFrame->Values();
error = values->SetValue(fVariable->ID(), fPath, value);
if (error != B_OK)
{
printf(" -> failed to set value: %s\n", strerror(error));
return error;
}
fStackFrame->NotifyValueRetrieved(fVariable, fPath);
return B_OK;
}
+67 -6
View File
@@ -5,6 +5,7 @@
#ifndef JOBS_H
#define JOBS_H
#include "ImageDebugInfoProvider.h"
#include "Worker.h"
@@ -16,8 +17,12 @@ class Function;
class FunctionInstance;
class Image;
class StackFrame;
class StackFrameValues;
class Team;
class TeamDebugModel;
class Thread;
class TypeComponentPath;
class Variable;
// job types
@@ -26,7 +31,8 @@ enum {
JOB_TYPE_GET_CPU_STATE,
JOB_TYPE_GET_STACK_TRACE,
JOB_TYPE_LOAD_IMAGE_DEBUG_INFO,
JOB_TYPE_LOAD_SOURCE_CODE
JOB_TYPE_LOAD_SOURCE_CODE,
JOB_TYPE_GET_STACK_FRAME_VALUE
};
@@ -37,10 +43,11 @@ public:
Thread* thread);
virtual ~GetThreadStateJob();
virtual JobKey Key() const;
virtual const JobKey& Key() const;
virtual status_t Do();
private:
SimpleJobKey fKey;
DebuggerInterface* fDebuggerInterface;
Thread* fThread;
};
@@ -53,10 +60,11 @@ public:
Thread* thread);
virtual ~GetCpuStateJob();
virtual JobKey Key() const;
virtual const JobKey& Key() const;
virtual status_t Do();
private:
SimpleJobKey fKey;
DebuggerInterface* fDebuggerInterface;
Thread* fThread;
};
@@ -69,7 +77,7 @@ public:
Architecture* architecture, Thread* thread);
virtual ~GetStackTraceJob();
virtual JobKey Key() const;
virtual const JobKey& Key() const;
virtual status_t Do();
private:
@@ -78,6 +86,7 @@ private:
ImageDebugInfo*& _info);
private:
SimpleJobKey fKey;
DebuggerInterface* fDebuggerInterface;
Architecture* fArchitecture;
Thread* fThread;
@@ -90,7 +99,7 @@ public:
LoadImageDebugInfoJob(Image* image);
virtual ~LoadImageDebugInfoJob();
virtual JobKey Key() const;
virtual const JobKey& Key() const;
virtual status_t Do();
static status_t ScheduleIfNecessary(Worker* worker,
@@ -105,6 +114,7 @@ public:
// earlier.
private:
SimpleJobKey fKey;
Image* fImage;
};
@@ -118,10 +128,11 @@ public:
bool loadForFunction);
virtual ~LoadSourceCodeJob();
virtual JobKey Key() const;
virtual const JobKey& Key() const;
virtual status_t Do();
private:
SimpleJobKey fKey;
DebuggerInterface* fDebuggerInterface;
Architecture* fArchitecture;
Team* fTeam;
@@ -130,4 +141,54 @@ private:
};
struct GetStackFrameValueJobKey : JobKey {
StackFrame* stackFrame;
Variable* variable;
TypeComponentPath* path;
public:
GetStackFrameValueJobKey(
StackFrame* stackFrame,
Variable* variable,
TypeComponentPath* path);
virtual uint32 HashValue() const;
virtual bool operator==(const JobKey& other) const;
};
class GetStackFrameValueJob : public Job {
public:
GetStackFrameValueJob(
DebuggerInterface* debuggerInterface,
Architecture* architecture,
TeamDebugModel* debugModel,
Thread* thread, StackFrame* stackFrame,
Variable* variable,
TypeComponentPath* path);
virtual ~GetStackFrameValueJob();
virtual const JobKey& Key() const;
virtual status_t Do();
private:
struct ValueJobKey;
private:
status_t _GetValue();
private:
GetStackFrameValueJobKey fKey;
DebuggerInterface* fDebuggerInterface;
Architecture* fArchitecture;
TeamDebugModel* fDebugModel;
Thread* fThread;
StackFrame* fStackFrame;
Variable* fVariable;
TypeComponentPath* fPath;
};
#endif // JOBS_H
+1
View File
@@ -18,6 +18,7 @@ enum {
MSG_THREAD_STATE_CHANGED = 'tsch',
MSG_THREAD_CPU_STATE_CHANGED = 'tcsc',
MSG_THREAD_STACK_TRACE_CHANGED = 'tstc',
MSG_STACK_FRAME_VALUE_RETRIEVED = 'sfvr',
MSG_IMAGE_DEBUG_INFO_CHANGED = 'idic',
MSG_IMAGE_FILE_CHANGED = 'ifch',
MSG_FUNCTION_SOURCE_CODE_CHANGED = 'fnsc',
+32 -5
View File
@@ -28,10 +28,13 @@
#include "MessageCodes.h"
#include "SourceCode.h"
#include "SpecificImageDebugInfo.h"
#include "StackFrame.h"
#include "StackFrameValues.h"
#include "Statement.h"
#include "SymbolInfo.h"
#include "TeamDebugInfo.h"
#include "TeamDebugModel.h"
#include "Variable.h"
// #pragma mark - ImageHandler
@@ -482,8 +485,7 @@ TeamDebugger::MessageReceived(BMessage* message)
void
TeamDebugger::FunctionSourceCodeRequested(TeamWindow* window,
FunctionInstance* functionInstance)
TeamDebugger::FunctionSourceCodeRequested(FunctionInstance* functionInstance)
{
Function* function = functionInstance->GetFunction();
@@ -520,14 +522,39 @@ TeamDebugger::FunctionSourceCodeRequested(TeamWindow* window,
void
TeamDebugger::ImageDebugInfoRequested(TeamWindow* window, Image* image)
TeamDebugger::ImageDebugInfoRequested(Image* image)
{
LoadImageDebugInfoJob::ScheduleIfNecessary(fWorker, image);
}
void
TeamDebugger::ThreadActionRequested(TeamWindow* window, thread_id threadID,
TeamDebugger::StackFrameValueRequested(::Thread* thread, StackFrame* stackFrame,
Variable* variable, TypeComponentPath* path)
{
// the team is already locked
// check whether a job is already in progress
AutoLocker<Worker> workerLocker(fWorker);
GetStackFrameValueJobKey jobKey(stackFrame, variable, path);
if (fWorker->GetJob(jobKey) != NULL)
return;
workerLocker.Unlock();
// schedule the job
if (fWorker->ScheduleJob(
new(std::nothrow) GetStackFrameValueJob(fDebuggerInterface,
fDebuggerInterface->GetArchitecture(), fDebugModel, thread,
stackFrame, variable, path),
this) != B_OK) {
// scheduling failed -- set the value to invalid
stackFrame->Values()->SetValue(variable->ID(), path, BVariant());
}
}
void
TeamDebugger::ThreadActionRequested(thread_id threadID,
uint32 action)
{
BMessage message(action);
@@ -556,7 +583,7 @@ TeamDebugger::ClearBreakpointRequested(target_addr_t address)
bool
TeamDebugger::TeamWindowQuitRequested(TeamWindow* window)
TeamDebugger::TeamWindowQuitRequested()
{
AutoLocker< ::Team> locker(fTeam);
BString name(fTeam->Name());
+8 -6
View File
@@ -41,16 +41,18 @@ public:
private:
// TeamWindow::Listener
virtual void FunctionSourceCodeRequested(TeamWindow* window,
virtual void FunctionSourceCodeRequested(
FunctionInstance* function);
virtual void ImageDebugInfoRequested(TeamWindow* window,
Image* image);
virtual void ThreadActionRequested(TeamWindow* window,
thread_id threadID, uint32 action);
virtual void ImageDebugInfoRequested(Image* image);
virtual void StackFrameValueRequested(::Thread* thread,
StackFrame* stackFrame, Variable* variable,
TypeComponentPath* path);
virtual void ThreadActionRequested(thread_id threadID,
uint32 action);
virtual void SetBreakpointRequested(target_addr_t address,
bool enabled);
virtual void ClearBreakpointRequested(target_addr_t address);
virtual bool TeamWindowQuitRequested(TeamWindow* window);
virtual bool TeamWindowQuitRequested();
// JobListener
virtual void JobDone(Job* job);
+3 -3
View File
@@ -304,8 +304,8 @@ ThreadHandler::HandleThreadStateChanged()
AutoLocker<TeamDebugModel> locker(fDebugModel);
// cancel jobs for this thread
fWorker->AbortJob(JobKey(fThread, JOB_TYPE_GET_CPU_STATE));
fWorker->AbortJob(JobKey(fThread, JOB_TYPE_GET_STACK_TRACE));
fWorker->AbortJob(SimpleJobKey(fThread, JOB_TYPE_GET_CPU_STATE));
fWorker->AbortJob(SimpleJobKey(fThread, JOB_TYPE_GET_STACK_TRACE));
// If the thread is stopped and has no CPU state yet, schedule a job.
if (fThread->State() == THREAD_STATE_STOPPED
@@ -322,7 +322,7 @@ ThreadHandler::HandleCpuStateChanged()
AutoLocker<TeamDebugModel> locker(fDebugModel);
// cancel stack trace job for this thread
fWorker->AbortJob(JobKey(fThread, JOB_TYPE_GET_STACK_TRACE));
fWorker->AbortJob(SimpleJobKey(fThread, JOB_TYPE_GET_STACK_TRACE));
// If the thread has a CPU state, but no stack trace yet, schedule a job.
if (fThread->GetCpuState() != NULL && fThread->GetStackTrace() == NULL) {
+55 -4
View File
@@ -9,6 +9,58 @@
#include <AutoLocker.h>
// pragma mark - JobKey
JobKey::~JobKey()
{
}
// pragma mark - SimpleJobKey
SimpleJobKey::SimpleJobKey(void* object, uint32 type)
:
object(object),
type(type)
{
}
SimpleJobKey::SimpleJobKey(const SimpleJobKey& other)
:
object(other.object),
type(other.type)
{
}
size_t
SimpleJobKey::HashValue() const
{
return (size_t)(addr_t)object ^ (size_t)type;
}
bool
SimpleJobKey::operator==(const JobKey& other) const
{
const SimpleJobKey* otherKey = dynamic_cast<const SimpleJobKey*>(&other);
return otherKey != NULL && object == otherKey->object
&& type == otherKey->type;
}
SimpleJobKey&
SimpleJobKey::operator=(const SimpleJobKey& other)
{
object = other.object;
type = other.type;
return *this;
}
// #pragma mark - JobListener
@@ -207,7 +259,7 @@ Worker::ScheduleJob(Job* job, JobListener* listener)
if (job == NULL)
return B_NO_MEMORY;
ObjectDeleter<Job> jobDeleter(job);
Reference<Job> jobReference(job, true);
AutoLocker<Worker> locker(this);
if (fTerminating)
@@ -224,8 +276,7 @@ Worker::ScheduleJob(Job* job, JobListener* listener)
job->SetWorker(this);
job->SetState(JOB_STATE_UNSCHEDULED);
fJobs.Insert(job);
fUnscheduledJobs.Add(job);
jobDeleter.Detach();
fUnscheduledJobs.Add(jobReference.Detach());
if (notify)
release_sem(fWorkToDoSem);
@@ -447,5 +498,5 @@ Worker::_FinishJob(Job* job)
if (job->State() != JOB_STATE_ABORTED)
fJobs.Remove(job);
job->NotifyListeners();
delete job;
job->ReleaseReference();
}
+23 -32
View File
@@ -8,6 +8,7 @@
#include <Locker.h>
#include <ObjectList.h>
#include <Referenceable.h>
#include <util/DoublyLinkedList.h>
#include <util/OpenHashTable.h>
@@ -35,40 +36,29 @@ enum job_wait_status {
};
struct JobKey {
void* object;
uint32 type;
class JobKey {
public:
virtual ~JobKey();
JobKey(void* object, uint32 type)
:
object(object),
type(type)
{
}
virtual uint32 HashValue() const = 0;
JobKey(const JobKey& other)
:
object(other.object),
type(other.type)
{
}
virtual bool operator==(const JobKey& other) const = 0;
};
JobKey& operator=(const JobKey& other)
{
object = other.object;
type = other.type;
return *this;
}
bool operator==(const JobKey& other) const
{
return object == other.object && type == other.type;
}
struct SimpleJobKey : public JobKey {
void* object;
uint32 type;
size_t HashValue() const
{
return (size_t)(addr_t)object ^ (size_t)type;
}
public:
SimpleJobKey(void* object, uint32 type);
SimpleJobKey(const SimpleJobKey& other);
virtual uint32 HashValue() const;
virtual bool operator==(const JobKey& other) const;
SimpleJobKey& operator=(const SimpleJobKey& other);
};
@@ -85,12 +75,13 @@ public:
typedef DoublyLinkedList<Job> JobList;
class Job : public DoublyLinkedListLinkImpl<Job>, public HashTableLink<Job> {
class Job : public Referenceable, public DoublyLinkedListLinkImpl<Job>,
public HashTableLink<Job> {
public:
Job();
virtual ~Job();
virtual JobKey Key() const = 0;
virtual const JobKey& Key() const = 0;
virtual status_t Do() = 0;
Worker* GetWorker() const { return fWorker; }
@@ -144,7 +135,7 @@ public:
status_t ScheduleJob(Job* job,
JobListener* listener = NULL);
// always takes over ownership
// always takes over reference
void AbortJob(const JobKey& key);
Job* GetJob(const JobKey& key);
@@ -79,9 +79,9 @@ DebuggerImageDebugInfo::GetFunctions(BObjectList<FunctionDebugInfo>& functions)
status_t
DebuggerImageDebugInfo::CreateFrame(Image* image, FunctionDebugInfo* function,
CpuState* cpuState, StackFrame*& _previousFrame,
CpuState*& _previousCpuState)
DebuggerImageDebugInfo::CreateFrame(Image* image,
FunctionInstance* functionInstance, CpuState* cpuState,
StackFrame*& _previousFrame, CpuState*& _previousCpuState)
{
return B_UNSUPPORTED;
}
@@ -27,7 +27,7 @@ public:
virtual status_t GetFunctions(
BObjectList<FunctionDebugInfo>& functions);
virtual status_t CreateFrame(Image* image,
FunctionDebugInfo* function,
FunctionInstance* functionInstance,
CpuState* cpuState,
StackFrame*& _previousFrame,
CpuState*& _previousCpuState);
@@ -31,6 +31,8 @@
#include "ElfFile.h"
#include "FileManager.h"
#include "FileSourceCode.h"
#include "FunctionID.h"
#include "FunctionInstance.h"
#include "LocatableFile.h"
#include "Register.h"
#include "RegisterMap.h"
@@ -303,12 +305,12 @@ printf(" %ld compilation units\n", fFile->CountCompilationUnits());
status_t
DwarfImageDebugInfo::CreateFrame(Image* image, FunctionDebugInfo* _function,
CpuState* cpuState, StackFrame*& _previousFrame,
CpuState*& _previousCpuState)
DwarfImageDebugInfo::CreateFrame(Image* image,
FunctionInstance* functionInstance, CpuState* cpuState,
StackFrame*& _previousFrame, CpuState*& _previousCpuState)
{
DwarfFunctionDebugInfo* function
= dynamic_cast<DwarfFunctionDebugInfo*>(_function);
DwarfFunctionDebugInfo* function = dynamic_cast<DwarfFunctionDebugInfo*>(
functionInstance->GetFunctionDebugInfo());
if (function == NULL)
return B_BAD_VALUE;
@@ -365,14 +367,24 @@ if (previousCpuState->GetRegisterValue(reg, value)) {
return B_NO_MEMORY;
Reference<StackFrame> frameReference(frame, true);
error = frame->Init();
if (error != B_OK)
return error;
frame->SetReturnAddress(previousCpuState->InstructionPointer());
// Note, this is correct, since we actually retrieved the return
// address. Our caller will fix the IP for us.
FunctionID* functionID = functionInstance->GetFunctionID();
if (functionID == NULL)
return B_NO_MEMORY;
Reference<FunctionID> functionIDReference(functionID, true);
// create function parameter objects
DIESubprogram* subprogramEntry = function->SubprogramEntry();
DwarfInterfaceFactory factory(fFile, function->GetCompilationUnit(),
subprogramEntry, instructionPointer, framePointer, &inputInterface);
subprogramEntry, instructionPointer, framePointer, &inputInterface,
fromDwarfMap);
error = factory.Init();
if (error != B_OK)
return error;
@@ -387,8 +399,10 @@ if (previousCpuState->GetRegisterValue(reg, value)) {
DIEFormalParameter* parameterEntry
= dynamic_cast<DIEFormalParameter*>(entry);
Variable* parameter;
if (factory.CreateParameter(parameterEntry, parameter) != B_OK)
if (factory.CreateParameter(functionID, parameterEntry, parameter)
!= B_OK) {
continue;
}
if (!frame->AddParameter(parameter)) {
parameter->ReleaseReference();
@@ -42,7 +42,7 @@ public:
virtual status_t GetFunctions(
BObjectList<FunctionDebugInfo>& functions);
virtual status_t CreateFrame(Image* image,
FunctionDebugInfo* function,
FunctionInstance* functionInstance,
CpuState* cpuState,
StackFrame*& _previousFrame,
CpuState*& _previousCpuState);
@@ -10,14 +10,59 @@
#include <Variant.h>
#include "CompilationUnit.h"
#include "DebugInfoEntries.h"
#include "Dwarf.h"
#include "DwarfFile.h"
#include "DwarfUtils.h"
#include "FunctionID.h"
#include "FunctionParameterID.h"
#include "RegisterMap.h"
#include "StringUtils.h"
#include "ValueLocation.h"
#include "Variable.h"
// #pragma mark - DwarfFunctionParameterID
struct DwarfInterfaceFactory::DwarfFunctionParameterID
: public FunctionParameterID {
DwarfFunctionParameterID(FunctionID* functionID, const BString& name)
:
fFunctionID(functionID),
fName(name)
{
fFunctionID->AcquireReference();
}
virtual ~DwarfFunctionParameterID()
{
fFunctionID->ReleaseReference();
}
virtual bool operator==(const ObjectID& other) const
{
const DwarfFunctionParameterID* parameterID
= dynamic_cast<const DwarfFunctionParameterID*>(&other);
return parameterID != NULL && *fFunctionID == *parameterID->fFunctionID
&& fName == parameterID->fName;
}
protected:
virtual uint32 ComputeHashValue() const
{
uint32 hash = fFunctionID->HashValue();
return hash * 19 + StringUtils::HashValue(fName);
}
private:
FunctionID* fFunctionID;
const BString fName;
};
// #pragma mark - DwarfType
@@ -26,7 +71,8 @@ struct DwarfInterfaceFactory::DwarfType : virtual Type,
public:
DwarfType(const BString& name)
:
fName(name)
fName(name),
fByteSize(0)
{
}
@@ -35,10 +81,21 @@ public:
return fName.Length() > 0 ? fName.String() : NULL;
}
uint64 ByteSize() const
{
return fByteSize;
}
void SetByteSize(uint64 size)
{
fByteSize = size;
}
virtual DIEType* GetDIEType() const = 0;
private:
BString fName;
uint64 fByteSize;
};
@@ -394,7 +451,7 @@ struct DwarfInterfaceFactory::DwarfTypeHashDefinition {
DwarfInterfaceFactory::DwarfInterfaceFactory(DwarfFile* file,
CompilationUnit* compilationUnit, DIESubprogram* subprogramEntry,
target_addr_t instructionPointer, target_addr_t framePointer,
DwarfTargetInterface* targetInterface)
DwarfTargetInterface* targetInterface, RegisterMap* fromDwarfRegisterMap)
:
fFile(file),
fCompilationUnit(compilationUnit),
@@ -402,6 +459,7 @@ DwarfInterfaceFactory::DwarfInterfaceFactory(DwarfFile* file,
fInstructionPointer(instructionPointer),
fFramePointer(framePointer),
fTargetInterface(targetInterface),
fFromDwarfRegisterMap(fromDwarfRegisterMap),
fTypes(NULL)
{
}
@@ -447,12 +505,21 @@ DwarfInterfaceFactory::CreateType(DIEType* typeEntry, Type*& _type)
status_t
DwarfInterfaceFactory::CreateParameter(DIEFormalParameter* parameterEntry,
Variable*& _parameter)
DwarfInterfaceFactory::CreateParameter(FunctionID* functionID,
DIEFormalParameter* parameterEntry, Variable*& _parameter)
{
// get the name
BString name;
DwarfUtils::GetFullyQualifiedDIEName(parameterEntry, name);
DwarfUtils::GetDIEName(parameterEntry, name);
printf("DwarfInterfaceFactory::CreateParameter(DIE: %p): name: \"%s\"\n",
parameterEntry, name.String());
// create the ID
DwarfFunctionParameterID* id = new(std::nothrow) DwarfFunctionParameterID(
functionID, name);
if (id == NULL)
return B_NO_MEMORY;
Reference<DwarfFunctionParameterID> idReference(id, true);
// get the type entry
DIEFormalParameter* typeOwnerEntry = parameterEntry;
@@ -490,6 +557,7 @@ DwarfInterfaceFactory::CreateParameter(DIEFormalParameter* parameterEntry,
fFile->ResolveLocation(fCompilationUnit,
fSubprogramEntry, locationDescription, fTargetInterface,
fInstructionPointer, 0, fFramePointer, *location);
location->Dump();
}
// create the type
@@ -499,8 +567,10 @@ DwarfInterfaceFactory::CreateParameter(DIEFormalParameter* parameterEntry,
return error;
Reference<DwarfType> typeReference(type, true);
_FixLocation(location, type);
// create the variable
Variable* variable = new(std::nothrow) Variable(name, type, location);
Variable* variable = new(std::nothrow) Variable(id, name, type, location);
if (variable == NULL)
return B_NO_MEMORY;
@@ -521,6 +591,11 @@ DwarfInterfaceFactory::_CreateType(DIEType* typeEntry, DwarfType*& _type)
return error;
fTypes->Insert(type);
// try to get the type's size
uint64 size;
if (_ResolveTypeByteSize(typeEntry, size) == B_OK)
type->SetByteSize(size);
}
type->AcquireReference();
@@ -1011,3 +1086,121 @@ DwarfInterfaceFactory::_ResolveTypedef(DIETypedef* entry,
}
}
status_t
DwarfInterfaceFactory::_ResolveTypeByteSize(DIEType* typeEntry, uint64& _size)
{
printf("DwarfInterfaceFactory::_ResolveTypeByteSize(%p)\n", typeEntry);
// get the size attribute
const DynamicAttributeValue* sizeValue;
while (true) {
// resolve a typedef
if (typeEntry->Tag() == DW_TAG_typedef) {
printf(" resolving typedef...\n");
status_t error = _ResolveTypedef(
dynamic_cast<DIETypedef*>(typeEntry), typeEntry);
if (error != B_OK)
return error;
}
sizeValue = typeEntry->ByteSize();
if (sizeValue != NULL && sizeValue->IsValid())
break;
// resolve abstract origin
if (DIEType* abstractOrigin = dynamic_cast<DIEType*>(
typeEntry->AbstractOrigin())) {
printf(" resolving abstract origin (%p)...\n", abstractOrigin);
typeEntry = abstractOrigin;
sizeValue = typeEntry->ByteSize();
if (sizeValue != NULL && sizeValue->IsValid())
break;
}
// resolve specification
if (DIEType* specification = dynamic_cast<DIEType*>(
typeEntry->Specification())) {
printf(" resolving specification (%p)...\n", specification);
typeEntry = specification;
sizeValue = typeEntry->ByteSize();
if (sizeValue != NULL && sizeValue->IsValid())
break;
}
// For some types we have a special handling. For modified types we
// follow the base type, for address types we know the size anyway.
printf(" nothing yet, special type handling\n");
switch (typeEntry->Tag()) {
case DW_TAG_const_type:
case DW_TAG_packed_type:
case DW_TAG_volatile_type:
case DW_TAG_restrict_type:
case DW_TAG_shared_type:
typeEntry = dynamic_cast<DIEModifiedType*>(typeEntry)
->GetType();
printf(" following modified type -> %p\n", typeEntry);
if (typeEntry == NULL)
return B_ENTRY_NOT_FOUND;
break;
case DW_TAG_pointer_type:
case DW_TAG_reference_type:
_size = fCompilationUnit->AddressSize();
printf(" pointer/reference type: size: %llu\n", _size);
return B_OK;
default:
return B_ENTRY_NOT_FOUND;
}
}
printf(" found attribute\n");
// get the actual value
BVariant size;
status_t error = fFile->EvaluateDynamicValue(fCompilationUnit,
fSubprogramEntry, sizeValue, fTargetInterface, fInstructionPointer,
fFramePointer, size);
if (error != B_OK)
{
printf(" failed to resolve attribute: %s\n", strerror(error));
return error;
}
_size = size.ToUInt64();
printf(" -> size: %llu\n", _size);
return B_OK;
}
void
DwarfInterfaceFactory::_FixLocation(ValueLocation* location, DwarfType* type)
{
printf("DwarfInterfaceFactory::_FixLocation(%p, %p), type entry: %p\n",
location, type, type->GetDIEType());
// translate the DWARF register indices
int32 count = location->CountPieces();
for (int32 i = 0; i < count; i++) {
ValuePieceLocation piece = location->PieceAt(i);
if (piece.type == VALUE_PIECE_LOCATION_REGISTER) {
int32 reg = fFromDwarfRegisterMap->MapRegisterIndex(piece.reg);
if (reg >= 0)
piece.reg = reg;
else
piece.SetToUnknown();
location->SetPieceAt(i, piece);
}
}
// If we only have one piece and that doesn't have a size, try to retrieve
// the size of the type.
if (count == 1) {
ValuePieceLocation piece = location->PieceAt(0);
if (piece.IsValid() && piece.size == 0 && piece.bitSize == 0)
{
piece.SetSize(type->ByteSize());
location->SetPieceAt(0, piece);
printf(" set single piece size to %llu\n", type->ByteSize());
}
}
}
@@ -25,7 +25,10 @@ class DIEType;
class DIETypedef;
class DwarfFile;
class DwarfTargetInterface;
class FunctionID;
class RegisterMap;
class Type;
class ValueLocation;
class Variable;
@@ -36,19 +39,21 @@ public:
DIESubprogram* subprogramEntry,
target_addr_t instructionPointer,
target_addr_t framePointer,
DwarfTargetInterface* targetInterface);
DwarfTargetInterface* targetInterface,
RegisterMap* fromDwarfRegisterMap);
~DwarfInterfaceFactory();
status_t Init();
status_t CreateType(DIEType* typeEntry, Type*& _type);
// returns reference
status_t CreateParameter(
status_t CreateParameter(FunctionID* functionID,
DIEFormalParameter* parameterEntry,
Variable*& _parameter);
// returns reference
private:
struct DwarfFunctionParameterID;
struct DwarfType;
struct DwarfDataMember;
struct DwarfPrimitiveType;
@@ -88,6 +93,11 @@ private:
status_t _ResolveTypedef(DIETypedef* entry,
DIEType*& _baseTypeEntry);
status_t _ResolveTypeByteSize(DIEType* typeEntry,
uint64& _size);
void _FixLocation(ValueLocation* location,
DwarfType* type);
private:
DwarfFile* fFile;
@@ -96,6 +106,7 @@ private:
target_addr_t fInstructionPointer;
target_addr_t fFramePointer;
DwarfTargetInterface* fTargetInterface;
RegisterMap* fFromDwarfRegisterMap;
TypeTable* fTypes;
};
@@ -6,6 +6,7 @@
#include "Function.h"
#include "FileSourceCode.h"
#include "FunctionID.h"
Function::Function()
+5 -1
View File
@@ -22,7 +22,7 @@ public:
Function();
~Function();
// team must be locked ot access the instances
// team must be locked to access the instances
FunctionInstance* FirstInstance() const
{ return fInstances.Head(); }
FunctionInstance* LastInstance() const
@@ -40,6 +40,10 @@ public:
{ return FirstInstance()
->GetSourceLocation(); }
FunctionID* GetFunctionID() const
{ return FirstInstance()->GetFunctionID(); }
// returns a reference
// mutable attributes follow (locking required)
FileSourceCode* GetSourceCode() const { return fSourceCode; }
function_source_state SourceCodeState() const
@@ -5,8 +5,13 @@
#include "FunctionInstance.h"
#include <new>
#include "DisassembledCode.h"
#include "Function.h"
#include "FunctionID.h"
#include "ImageDebugInfo.h"
#include "LocatableFile.h"
FunctionInstance::FunctionInstance(ImageDebugInfo* imageDebugInfo,
@@ -31,6 +36,25 @@ FunctionInstance::~FunctionInstance()
}
FunctionID*
FunctionInstance::GetFunctionID() const
{
BString idString;
BString path;
if (LocatableFile* file = SourceFile()) {
idString << "s:";
file->GetPath(path);
} else {
idString << "i:";
path << GetImageDebugInfo()->GetImageInfo().Name();
}
idString << path << "//" << Name();
return new(std::nothrow) FunctionID(idString);
}
void
FunctionInstance::SetFunction(Function* function)
{
@@ -21,6 +21,7 @@ enum function_source_state {
class DisassembledCode;
class Function;
class FunctionDebugInfo;
class FunctionID;
class ImageDebugInfo;
@@ -52,6 +53,9 @@ public:
{ return fFunctionDebugInfo
->SourceStartLocation(); }
FunctionID* GetFunctionID() const;
// returns a reference
void SetFunction(Function* function);
// package private
@@ -28,6 +28,8 @@ public:
ImageDebugInfo(const ImageInfo& imageInfo);
~ImageDebugInfo();
const ImageInfo& GetImageInfo() const { return fImageInfo; }
bool AddSpecificInfo(SpecificImageDebugInfo* info);
status_t FinishInit();
@@ -16,6 +16,7 @@ class CpuState;
class DebuggerInterface;
class FileSourceCode;
class FunctionDebugInfo;
class FunctionInstance;
class Image;
class LocatableFile;
class SourceLanguage;
@@ -34,7 +35,7 @@ public:
// returns references
virtual status_t CreateFrame(Image* image,
FunctionDebugInfo* function,
FunctionInstance* functionInstance,
CpuState* cpuState,
StackFrame*& _previousFrame,
CpuState*& _previousCpuState) = 0;
@@ -3,6 +3,7 @@
* Distributed under the terms of the MIT License.
*/
#include "TeamWindow.h"
#include <stdio.h>
@@ -29,7 +30,8 @@
#include "RegistersView.h"
#include "StackTrace.h"
#include "StackTraceView.h"
#include "VariablesView.h"
#include "TypeComponentPath.h"
#include "Variable.h"
enum {
@@ -129,15 +131,15 @@ TeamWindow::DispatchMessage(BMessage* message, BHandler* handler)
== B_OK) {
switch (key) {
case B_F10_KEY:
fListener->ThreadActionRequested(this,
fListener->ThreadActionRequested(
fActiveThread->ID(), MSG_THREAD_STEP_OVER);
break;
case B_F11_KEY:
if ((modifiers & B_SHIFT_KEY) != 0) {
fListener->ThreadActionRequested(this,
fListener->ThreadActionRequested(
fActiveThread->ID(), MSG_THREAD_STEP_OUT);
} else {
fListener->ThreadActionRequested(this,
fListener->ThreadActionRequested(
fActiveThread->ID(), MSG_THREAD_STEP_INTO);
}
break;
@@ -169,7 +171,7 @@ TeamWindow::MessageReceived(BMessage* message)
case MSG_THREAD_STEP_INTO:
case MSG_THREAD_STEP_OUT:
if (fActiveThread != NULL) {
fListener->ThreadActionRequested(this, fActiveThread->ID(),
fListener->ThreadActionRequested(fActiveThread->ID(),
message->what);
}
break;
@@ -203,6 +205,24 @@ TeamWindow::MessageReceived(BMessage* message)
break;
}
case MSG_STACK_FRAME_VALUE_RETRIEVED:
{
void* _stackFrame;
void* _variable;
void* _path;
if (message->FindPointer("stackFrame", &_stackFrame) == B_OK
&& message->FindPointer("variable", &_variable) == B_OK
&& message->FindPointer("path", &_path) == B_OK) {
StackFrame* stackFrame = (StackFrame*)_stackFrame;
Variable* variable = (Variable*)_variable;
TypeComponentPath* path = (TypeComponentPath*)_path;
_HandleStackFrameValueRetrieved(stackFrame, variable, path);
path->ReleaseReference();
variable->ReleaseReference();
stackFrame->ReleaseReference();
}
}
case MSG_IMAGE_DEBUG_INFO_CHANGED:
{
int32 imageID;
@@ -239,7 +259,7 @@ TeamWindow::MessageReceived(BMessage* message)
bool
TeamWindow::QuitRequested()
{
return fListener->TeamWindowQuitRequested(this);
return fListener->TeamWindowQuitRequested();
}
@@ -285,6 +305,14 @@ TeamWindow::ClearBreakpointRequested(target_addr_t address)
}
void
TeamWindow::StackFrameValueRequested(::Thread* thread, StackFrame* stackFrame,
Variable* variable, TypeComponentPath* path)
{
fListener->StackFrameValueRequested(thread, stackFrame, variable, path);
}
void
TeamWindow::ThreadStateChanged(const Team::ThreadEvent& event)
{
@@ -339,6 +367,22 @@ function, function->GetSourceCode(), function->SourceCodeState());
}
void
TeamWindow::StackFrameValueRetrieved(StackFrame* stackFrame, Variable* variable,
TypeComponentPath* path)
{
BMessage message(MSG_STACK_FRAME_VALUE_RETRIEVED);
if (message.AddPointer("stackFrame", stackFrame) == B_OK
&& message.AddPointer("variable", variable) == B_OK
&& message.AddPointer("path", path) == B_OK
&& PostMessage(&message) == B_OK) {
stackFrame->AcquireReference();
variable->AcquireReference();
path->AcquireReference();
}
}
void
TeamWindow::_Init()
{
@@ -388,7 +432,7 @@ TeamWindow::_Init()
.Add(fImageFunctionsView = ImageFunctionsView::Create(this));
// add local variables tab
BView* tab = fVariablesView = VariablesView::Create();
BView* tab = fVariablesView = VariablesView::Create(this);
fLocalsTabView->AddTab(tab);
// add registers tab
@@ -481,7 +525,7 @@ TeamWindow::_SetActiveImage(Image* image)
// If the debug info is not loaded yet, request it.
if (fActiveImage->ImageDebugInfoState() == IMAGE_DEBUG_INFO_NOT_LOADED)
fListener->ImageDebugInfoRequested(this, fActiveImage);
fListener->ImageDebugInfoRequested(fActiveImage);
}
locker.Unlock();
@@ -519,20 +563,33 @@ TeamWindow::_SetActiveStackFrame(StackFrame* frame)
if (frame == fActiveStackFrame)
return;
if (fActiveStackFrame != NULL)
if (fActiveStackFrame != NULL) {
AutoLocker<TeamDebugModel> locker(fDebugModel);
fActiveStackFrame->RemoveListener(this);
locker.Unlock();
fActiveStackFrame->RemoveReference();
}
fActiveStackFrame = frame;
if (fActiveStackFrame != NULL) {
fActiveStackFrame->AddReference();
AutoLocker<TeamDebugModel> locker(fDebugModel);
fActiveStackFrame->AddListener(this);
locker.Unlock();
_SetActiveFunction(fActiveStackFrame->Function());
}
_UpdateCpuState();
fStackTraceView->SetStackFrame(fActiveStackFrame);
fVariablesView->SetStackFrame(fActiveStackFrame);
if (fActiveStackFrame != NULL)
fVariablesView->SetStackFrame(fActiveThread, fActiveStackFrame);
else
fVariablesView->SetStackFrame(NULL, NULL);
fSourceView->SetStackFrame(fActiveStackFrame);
}
@@ -580,7 +637,7 @@ TeamWindow::_SetActiveFunction(FunctionInstance* functionInstance)
// If the source code is not loaded yet, request it.
if (function->SourceCodeState() == FUNCTION_SOURCE_NOT_LOADED)
fListener->FunctionSourceCodeRequested(this, fActiveFunction);
fListener->FunctionSourceCodeRequested(fActiveFunction);
}
locker.Unlock();
@@ -741,6 +798,17 @@ TeamWindow::_HandleStackTraceChanged(thread_id threadID)
}
void
TeamWindow::_HandleStackFrameValueRetrieved(StackFrame* stackFrame,
Variable* variable, TypeComponentPath* path)
{
if (stackFrame != fActiveStackFrame)
return;
fVariablesView->StackFrameValueRetrieved(stackFrame, variable, path);
}
void
TeamWindow::_HandleImageDebugInfoChanged(image_id imageID)
{
+28 -8
View File
@@ -5,6 +5,7 @@
#ifndef TEAM_WINDOW_H
#define TEAM_WINDOW_H
#include <String.h>
#include <Window.h>
@@ -12,10 +13,12 @@
#include "Function.h"
#include "ImageFunctionsView.h"
#include "ImageListView.h"
#include "StackFrame.h"
#include "StackTraceView.h"
#include "Team.h"
#include "TeamDebugModel.h"
#include "ThreadListView.h"
#include "VariablesView.h"
class BButton;
@@ -30,8 +33,9 @@ class VariablesView;
class TeamWindow : public BWindow, ThreadListView::Listener,
ImageListView::Listener, StackTraceView::Listener,
ImageFunctionsView::Listener, SourceView::Listener, Team::Listener,
TeamDebugModel::Listener, Function::Listener {
ImageFunctionsView::Listener, SourceView::Listener, VariablesView::Listener,
Team::Listener, TeamDebugModel::Listener, Function::Listener,
StackFrame::Listener {
public:
class Listener;
@@ -68,6 +72,11 @@ private:
bool enabled);
virtual void ClearBreakpointRequested(target_addr_t address);
// VariablesView::Listener
virtual void StackFrameValueRequested(::Thread* thread,
StackFrame* stackFrame, Variable* variable,
TypeComponentPath* path);
// Team::Listener
virtual void ThreadStateChanged(
const Team::ThreadEvent& event);
@@ -86,6 +95,11 @@ private:
// Function::Listener
virtual void FunctionSourceCodeChanged(Function* function);
// StackFrame::Listener
virtual void StackFrameValueRetrieved(StackFrame* stackFrame,
Variable* variable,
TypeComponentPath* path);
void _Init();
void _SetActiveThread(::Thread* thread);
@@ -101,6 +115,9 @@ private:
void _HandleThreadStateChanged(thread_id threadID);
void _HandleCpuStateChanged(thread_id threadID);
void _HandleStackTraceChanged(thread_id threadID);
void _HandleStackFrameValueRetrieved(
StackFrame* stackFrame, Variable* variable,
TypeComponentPath* path);
void _HandleImageDebugInfoChanged(image_id imageID);
void _HandleSourceCodeChanged();
void _HandleUserBreakpointChanged(
@@ -136,17 +153,20 @@ class TeamWindow::Listener {
public:
virtual ~Listener();
virtual void FunctionSourceCodeRequested(TeamWindow* window,
virtual void FunctionSourceCodeRequested(
FunctionInstance* function) = 0;
virtual void ImageDebugInfoRequested(TeamWindow* window,
Image* image) = 0;
virtual void ThreadActionRequested(TeamWindow* window,
thread_id threadID, uint32 action) = 0;
virtual void ImageDebugInfoRequested(Image* image) = 0;
virtual void StackFrameValueRequested(::Thread* thread,
StackFrame* stackFrame, Variable* variable,
TypeComponentPath* path) = 0;
// called with team locked
virtual void ThreadActionRequested(thread_id threadID,
uint32 action) = 0;
virtual void SetBreakpointRequested(target_addr_t address,
bool enabled) = 0;
virtual void ClearBreakpointRequested(
target_addr_t address) = 0;
virtual bool TeamWindowQuitRequested(TeamWindow* window) = 0;
virtual bool TeamWindowQuitRequested() = 0;
};
@@ -10,30 +10,136 @@
#include <new>
#include <AutoLocker.h>
#include "table/TableColumns.h"
#include "Architecture.h"
#include "StackFrame.h"
#include "StackFrameValues.h"
#include "Team.h"
#include "Thread.h"
#include "TypeComponentPath.h"
#include "Variable.h"
// #pragma mark - VariableValueColumn
class VariablesView::VariableValueColumn : public StringTableColumn {
public:
VariableValueColumn(int32 modelIndex, const char* title, float width,
float minWidth, float maxWidth, uint32 truncate = B_TRUNCATE_MIDDLE,
alignment align = B_ALIGN_RIGHT)
:
StringTableColumn(modelIndex, title, width, minWidth, maxWidth,
truncate, align)
{
}
protected:
virtual BField* PrepareField(const BVariant& value) const
{
char buffer[64];
return StringTableColumn::PrepareField(
BVariant(_ToString(value, buffer, sizeof(buffer)),
B_VARIANT_DONT_COPY_DATA));
}
virtual int CompareValues(const BVariant& a, const BVariant& b)
{
// If neither value is a number, compare the strings. If only one value
// is a number, it is considered to be greater.
if (!a.IsNumber()) {
if (b.IsNumber())
return -1;
char bufferA[64];
char bufferB[64];
return StringTableColumn::CompareValues(
BVariant(_ToString(a, bufferA, sizeof(bufferA)),
B_VARIANT_DONT_COPY_DATA),
BVariant(_ToString(b, bufferB, sizeof(bufferB)),
B_VARIANT_DONT_COPY_DATA));
}
if (!b.IsNumber())
return 1;
// If either value is floating point, we compare floating point values.
if (a.IsFloat() || b.IsFloat()) {
double valueA = a.ToDouble();
double valueB = b.ToDouble();
return valueA < valueB ? -1 : (valueA == valueB ? 0 : 1);
}
uint64 valueA = a.ToUInt64();
uint64 valueB = b.ToUInt64();
return valueA < valueB ? -1 : (valueA == valueB ? 0 : 1);
}
private:
const char* _ToString(const BVariant& value, char* buffer,
size_t bufferSize) const
{
switch (value.Type()) {
case B_BOOL_TYPE:
return value.ToBool() ? "true" : "false";
case B_FLOAT_TYPE:
case B_DOUBLE_TYPE:
snprintf(buffer, bufferSize, "%g", value.ToDouble());
break;
case B_INT8_TYPE:
case B_UINT8_TYPE:
snprintf(buffer, bufferSize, "0x%02x", value.ToUInt8());
break;
case B_INT16_TYPE:
case B_UINT16_TYPE:
snprintf(buffer, bufferSize, "0x%04x", value.ToUInt16());
break;
case B_INT32_TYPE:
case B_UINT32_TYPE:
snprintf(buffer, bufferSize, "0x%08lx", value.ToUInt32());
break;
case B_INT64_TYPE:
case B_UINT64_TYPE:
snprintf(buffer, bufferSize, "0x%016llx", value.ToUInt64());
break;
case B_STRING_TYPE:
return value.ToString();
default:
return NULL;
}
return buffer;
}
};
// #pragma mark - VariableTableModel
#include "ObjectID.h"
class VariablesView::VariableTableModel : public TableModel {
public:
VariableTableModel()
:
fStackFrame(NULL)
fStackFrame(NULL),
fValues(NULL)
{
}
~VariableTableModel()
{
SetStackFrame(NULL, NULL);
}
void SetStackFrame(StackFrame* stackFrame)
void SetStackFrame(Thread* thread, StackFrame* stackFrame)
{
if (fValues != NULL) {
fValues->ReleaseReference();
fValues = NULL;
}
if (fStackFrame != NULL) {
int32 rowCount = CountRows();
fStackFrame = NULL;
@@ -41,14 +147,38 @@ public:
}
fStackFrame = stackFrame;
fThread = thread;
if (fStackFrame != NULL) {
try {
AutoLocker<Team> locker(fThread->GetTeam());
fValues = new StackFrameValues(*fStackFrame->Values());
} catch (std::bad_alloc) {
}
if (fStackFrame != NULL)
NotifyRowsAdded(0, CountRows());
}
}
void StackFrameValueRetrieved(StackFrame* stackFrame, Variable* variable,
TypeComponentPath* path)
{
if (stackFrame != fStackFrame || fValues == NULL)
return;
// update the respective value
AutoLocker<Team> locker(fThread->GetTeam());
BVariant value;
if (fStackFrame->Values()->GetValue(variable->ID(), path, value)) {
fValues->SetValue(variable->ID(), path, value);
NotifyRowsChanged(0, CountRows());
// TODO: Only notify for the respective node.
}
}
virtual int32 CountColumns() const
{
return 1;
return 2;
}
virtual int32 CountRows() const
@@ -59,7 +189,7 @@ public:
: 0;
}
virtual bool GetValueAt(int32 rowIndex, int32 columnIndex, BVariant& value)
virtual bool GetValueAt(int32 rowIndex, int32 columnIndex, BVariant& _value)
{
if (fStackFrame == NULL)
return false;
@@ -70,30 +200,49 @@ public:
: fStackFrame->LocalVariableAt(rowIndex - parameterCount);
if (variable == NULL)
return false;
printf("VariablesView::VariableTableModel::GetValueAt(%ld, %ld): "
"variable id: %p, hash: %lu\n", rowIndex, columnIndex, variable->ID(),
variable->ID()->HashValue());
switch (columnIndex) {
case 0:
value.SetTo(variable->Name(), B_VARIANT_DONT_COPY_DATA);
_value.SetTo(variable->Name(), B_VARIANT_DONT_COPY_DATA);
return true;
case 1:
if (fValues == NULL)
return false;
// return fValues->GetValue(variable->ID(), TypeComponentPath(),
// _value);
{
bool success = fValues->GetValue(variable->ID(), TypeComponentPath(), _value);
if (!success)
return false;
printf(" -> %llx\n", _value.ToUInt64());
return true;
}
default:
return false;
}
}
private:
StackFrame* fStackFrame;
Thread* fThread;
StackFrame* fStackFrame;
StackFrameValues* fValues;
};
// #pragma mark - VariablesView
VariablesView::VariablesView()
VariablesView::VariablesView(Listener* listener)
:
BGroupView(B_VERTICAL),
fThread(NULL),
fStackFrame(NULL),
fVariableTable(NULL),
fVariableTableModel(NULL)
fVariableTableModel(NULL),
fListener(listener)
{
SetName("Variables");
}
@@ -101,16 +250,16 @@ VariablesView::VariablesView()
VariablesView::~VariablesView()
{
SetStackFrame(NULL);
SetStackFrame(NULL, NULL);
fVariableTable->SetTableModel(NULL);
delete fVariableTableModel;
}
/*static*/ VariablesView*
VariablesView::Create()
VariablesView::Create(Listener* listener)
{
VariablesView* self = new VariablesView;
VariablesView* self = new VariablesView(listener);
try {
self->_Init();
@@ -124,20 +273,46 @@ VariablesView::Create()
void
VariablesView::SetStackFrame(StackFrame* stackFrame)
VariablesView::SetStackFrame(Thread* thread, StackFrame* stackFrame)
{
if (stackFrame == fStackFrame)
if (thread == fThread && stackFrame == fStackFrame)
return;
if (fThread != NULL)
fThread->ReleaseReference();
if (fStackFrame != NULL)
fStackFrame->RemoveReference();
fStackFrame->ReleaseReference();
fThread = thread;
fStackFrame = stackFrame;
if (fThread != NULL)
fThread->AcquireReference();
if (fStackFrame != NULL)
fStackFrame->AddReference();
fStackFrame->AcquireReference();
fVariableTableModel->SetStackFrame(fStackFrame);
fVariableTableModel->SetStackFrame(fThread, fStackFrame);
// request loading the parameter and variable values
if (fThread != NULL && fStackFrame != NULL) {
AutoLocker<Team> locker(fThread->GetTeam());
for (int32 i = 0; Variable* variable = fStackFrame->ParameterAt(i); i++)
_RequestVariableValue(variable);
for (int32 i = 0; Variable* variable = fStackFrame->LocalVariableAt(i);
i++) {
_RequestVariableValue(variable);
}
}
}
void
VariablesView::StackFrameValueRetrieved(StackFrame* stackFrame,
Variable* variable, TypeComponentPath* path)
{
fVariableTableModel->StackFrameValueRetrieved(stackFrame, variable, path);
}
@@ -150,11 +325,36 @@ VariablesView::_Init()
// columns
fVariableTable->AddColumn(new StringTableColumn(0, "Variable", 80, 40, 1000,
B_TRUNCATE_END, B_ALIGN_LEFT));
// fVariableTable->AddColumn(new VariableValueColumn(1, "Value", 80, 40, 1000,
// B_TRUNCATE_END, B_ALIGN_RIGHT));
fVariableTable->AddColumn(new VariableValueColumn(1, "Value", 80, 40, 1000,
B_TRUNCATE_END, B_ALIGN_RIGHT));
fVariableTableModel = new VariableTableModel;
fVariableTable->SetTableModel(fVariableTableModel);
fVariableTable->AddTableListener(this);
}
void
VariablesView::_RequestVariableValue(Variable* variable)
{
StackFrameValues* values = fStackFrame->Values();
if (values->HasValue(variable->ID(), TypeComponentPath()))
return;
TypeComponentPath* path = new(std::nothrow) TypeComponentPath;
if (path == NULL)
return;
Reference<TypeComponentPath> pathReference(path, true);
fListener->StackFrameValueRequested(fThread, fStackFrame,
variable, path);
}
// #pragma mark - Listener
VariablesView::Listener::~Listener()
{
}
@@ -12,29 +12,54 @@
class StackFrame;
class Thread;
class TypeComponentPath;
class Variable;
class VariablesView : public BGroupView, private TableListener {
public:
VariablesView();
class Listener;
public:
VariablesView(Listener* listener);
~VariablesView();
static VariablesView* Create();
static VariablesView* Create(Listener* listener);
// throws
void SetStackFrame(StackFrame* stackFrame);
void SetStackFrame(Thread* thread,
StackFrame* stackFrame);
void StackFrameValueRetrieved(StackFrame* stackFrame,
Variable* variable,
TypeComponentPath* path);
private:
class VariableValueColumn;
class VariableTableModel;
private:
void _Init();
void _RequestVariableValue(Variable* variable);
private:
Thread* fThread;
StackFrame* fStackFrame;
Table* fVariableTable;
VariableTableModel* fVariableTableModel;
Listener* fListener;
};
class VariablesView::Listener {
public:
virtual ~Listener();
virtual void StackFrameValueRequested(Thread* thread,
StackFrame* stackFrame, Variable* variable,
TypeComponentPath* path) = 0;
// called with team locked
};
+55 -1
View File
@@ -5,9 +5,12 @@
#include "StackFrame.h"
#include <new>
#include "CpuState.h"
#include "FunctionInstance.h"
#include "Image.h"
#include "StackFrameValues.h"
#include "Variable.h"
@@ -23,7 +26,8 @@ StackFrame::StackFrame(stack_frame_type type, CpuState* cpuState,
fInstructionPointer(instructionPointer),
fReturnAddress(0),
fImage(NULL),
fFunction(NULL)
fFunction(NULL),
fValues(NULL)
{
fCpuState->AcquireReference();
}
@@ -43,6 +47,17 @@ StackFrame::~StackFrame()
}
status_t
StackFrame::Init()
{
fValues = new(std::nothrow) StackFrameValues;
if (fValues == NULL)
return B_NO_MEMORY;
return fValues->Init();
}
void
StackFrame::SetReturnAddress(target_addr_t address)
{
@@ -124,3 +139,42 @@ StackFrame::AddLocalVariable(Variable* variable)
variable->AcquireReference();
return true;
}
void
StackFrame::AddListener(Listener* listener)
{
fListeners.Add(listener);
}
void
StackFrame::RemoveListener(Listener* listener)
{
fListeners.Remove(listener);
}
void
StackFrame::NotifyValueRetrieved(Variable* variable, TypeComponentPath* path)
{
for (ListenerList::Iterator it = fListeners.GetIterator();
Listener* listener = it.Next();) {
listener->StackFrameValueRetrieved(this, variable, path);
}
}
// #pragma mark - StackFrame
StackFrame::Listener::~Listener()
{
}
void
StackFrame::Listener::StackFrameValueRetrieved(StackFrame* stackFrame,
Variable* variable, TypeComponentPath* path)
{
}
+32
View File
@@ -5,10 +5,12 @@
#ifndef STACK_FRAME_H
#define STACK_FRAME_H
#include <OS.h>
#include <ObjectList.h>
#include <Referenceable.h>
#include <util/DoublyLinkedList.h>
#include "Types.h"
@@ -24,10 +26,15 @@ enum stack_frame_type {
class CpuState;
class Image;
class FunctionInstance;
class StackFrameValues;
class TypeComponentPath;
class Variable;
class StackFrame : public Referenceable {
public:
class Listener;
public:
StackFrame(stack_frame_type type,
CpuState* cpuState,
@@ -35,6 +42,8 @@ public:
target_addr_t instructionPointer);
~StackFrame();
status_t Init();
stack_frame_type Type() const { return fType; }
CpuState* GetCpuState() const { return fCpuState; }
target_addr_t FrameAddress() const { return fFrameAddress; }
@@ -59,8 +68,18 @@ public:
Variable* LocalVariableAt(int32 index) const;
bool AddLocalVariable(Variable* variable);
StackFrameValues* Values() const { return fValues; }
// team lock must be held
void AddListener(Listener* listener);
void RemoveListener(Listener* listener);
void NotifyValueRetrieved(Variable* variable,
TypeComponentPath* path);
private:
typedef BObjectList<Variable> VariableList;
typedef DoublyLinkedList<Listener> ListenerList;
private:
stack_frame_type fType;
@@ -72,6 +91,19 @@ private:
FunctionInstance* fFunction;
VariableList fParameters;
VariableList fLocalVariables;
StackFrameValues* fValues;
ListenerList fListeners;
};
class StackFrame::Listener : public DoublyLinkedListLinkImpl<Listener> {
public:
virtual ~Listener();
virtual void StackFrameValueRetrieved(StackFrame* stackFrame,
Variable* variable,
TypeComponentPath* path);
// called with lock held
};
@@ -0,0 +1,183 @@
/*
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#include "StackFrameValues.h"
#include <new>
#include "FunctionID.h"
#include "TypeComponentPath.h"
struct StackFrameValues::Key {
ObjectID* variable;
TypeComponentPath* path;
Key(ObjectID* variable, TypeComponentPath* path)
:
variable(variable),
path(path)
{
}
uint32 HashValue() const
{
return variable->HashValue() ^ path->HashValue();
}
bool operator==(const Key& other) const
{
return *variable == *other.variable && *path == *other.path;
}
};
struct StackFrameValues::ValueEntry : Key, HashTableLink<ValueEntry> {
BVariant value;
ValueEntry(ObjectID* variable, TypeComponentPath* path)
:
Key(variable, path)
{
variable->AcquireReference();
path->AcquireReference();
}
~ValueEntry()
{
variable->ReleaseReference();
path->ReleaseReference();
}
};
struct StackFrameValues::ValueEntryHashDefinition {
typedef Key KeyType;
typedef ValueEntry ValueType;
size_t HashKey(const Key& key) const
{
return key.HashValue();
}
size_t Hash(const ValueEntry* value) const
{
return value->HashValue();
}
bool Compare(const Key& key, const ValueEntry* value) const
{
return key == *value;
}
HashTableLink<ValueEntry>* GetLink(ValueEntry* value) const
{
return value;
}
};
StackFrameValues::StackFrameValues()
:
fValues(NULL)
{
}
StackFrameValues::StackFrameValues(const StackFrameValues& other)
:
fValues(NULL)
{
try {
// init
if (Init() != B_OK)
throw std::bad_alloc();
// clone all values
for (ValueTable::Iterator it = other.fValues->GetIterator();
ValueEntry* entry = it.Next();) {
if (SetValue(entry->variable, entry->path, entry->value) != B_OK)
throw std::bad_alloc();
}
} catch (...) {
_Cleanup();
throw;
}
}
StackFrameValues::~StackFrameValues()
{
_Cleanup();
}
status_t
StackFrameValues::Init()
{
fValues = new(std::nothrow) ValueTable;
if (fValues == NULL)
return B_NO_MEMORY;
return fValues->Init();
}
bool
StackFrameValues::GetValue(ObjectID* variable, const TypeComponentPath* path,
BVariant& _value) const
{
ValueEntry* entry = fValues->Lookup(
Key(variable, (TypeComponentPath*)path));
if (entry == NULL)
return false;
_value = entry->value;
return true;
}
bool
StackFrameValues::HasValue(ObjectID* variable, const TypeComponentPath* path)
const
{
return fValues->Lookup(Key(variable, (TypeComponentPath*)path)) != NULL;
}
status_t
StackFrameValues::SetValue(ObjectID* variable, TypeComponentPath* path,
const BVariant& value)
{
ValueEntry* entry = fValues->Lookup(Key(variable, path));
if (entry == NULL) {
entry = new(std::nothrow) ValueEntry(variable, path);
if (entry == NULL)
return B_NO_MEMORY;
fValues->Insert(entry);
}
entry->value = value;
return B_OK;
}
void
StackFrameValues::_Cleanup()
{
if (fValues != NULL) {
ValueEntry* entry = fValues->Clear(true);
while (entry != NULL) {
ValueEntry* next = entry->fNext;
delete entry;
entry = next;
}
delete fValues;
fValues = NULL;
}
}
@@ -0,0 +1,74 @@
/*
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#ifndef STACK_FRAME_VALUES_H
#define STACK_FRAME_VALUES_H
#include <Referenceable.h>
#include <util/OpenHashTable.h>
#include <Variant.h>
class ObjectID;
class TypeComponentPath;
class StackFrameValues : public Referenceable {
public:
StackFrameValues();
StackFrameValues(const StackFrameValues& other);
// throws std::bad_alloc
virtual ~StackFrameValues();
status_t Init();
bool GetValue(ObjectID* variable,
const TypeComponentPath* path,
BVariant& _value) const;
inline bool GetValue(ObjectID* variable,
const TypeComponentPath& path,
BVariant& _value) const;
bool HasValue(ObjectID* variable,
const TypeComponentPath* path) const;
inline bool HasValue(ObjectID* variable,
const TypeComponentPath& path) const;
status_t SetValue(ObjectID* variable,
TypeComponentPath* path,
const BVariant& value);
private:
struct Key;
struct ValueEntry;
struct ValueEntryHashDefinition;
typedef OpenHashTable<ValueEntryHashDefinition> ValueTable;
private:
StackFrameValues& operator=(const StackFrameValues& other);
void _Cleanup();
private:
ValueTable* fValues;
};
bool
StackFrameValues::GetValue(ObjectID* variable, const TypeComponentPath& path,
BVariant& _value) const
{
return GetValue(variable, &path, _value);
}
bool
StackFrameValues::HasValue(ObjectID* variable, const TypeComponentPath& path)
const
{
return HasValue(variable, &path);
}
#endif // STACK_FRAME_VALUES_H
+1
View File
@@ -22,6 +22,7 @@ enum {
class Architecture;
class Breakpoint;
class FunctionID;
class SourceCode;
class TeamMemory;
class UserBreakpoint;
@@ -0,0 +1,139 @@
/*
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#include "TypeComponentPath.h"
#include <new>
#include "StringUtils.h"
// #pragma mark - TypeComponent
uint32
TypeComponent::HashValue() const
{
uint32 hash = ((uint32)index << 8) | (componentKind << 4) | typeKind;
return StringUtils::HashValue(name) * 13 + hash;
}
bool
TypeComponent::operator==(const TypeComponent& other) const
{
return componentKind == other.componentKind
&& typeKind == other.typeKind
&& index == other.index
&& name == other.name;
}
// #pragma mark - TypeComponentPath
TypeComponentPath::TypeComponentPath()
:
fComponents(10, true)
{
}
TypeComponentPath::TypeComponentPath(const TypeComponentPath& other)
:
fComponents(10, true)
{
*this = other;
}
TypeComponentPath::~TypeComponentPath()
{
}
int32
TypeComponentPath::CountComponents() const
{
return fComponents.CountItems();
}
TypeComponent
TypeComponentPath::ComponentAt(int32 index) const
{
TypeComponent* component = fComponents.ItemAt(index);
return component != NULL ? *component : TypeComponent();
}
bool
TypeComponentPath::AddComponent(const TypeComponent& component)
{
TypeComponent* myComponent = new(std::nothrow) TypeComponent(component);
if (myComponent == NULL || !fComponents.AddItem(myComponent)) {
delete myComponent;
return false;
}
return true;
}
void
TypeComponentPath::Clear()
{
fComponents.MakeEmpty();
}
uint32
TypeComponentPath::HashValue() const
{
int32 count = fComponents.CountItems();
if (count == 0)
return 0;
uint32 hash = fComponents.ItemAt(0)->HashValue();
for (int32 i = 1; i < count; i++)
hash = hash * 17 + fComponents.ItemAt(i)->HashValue();
return hash;
}
TypeComponentPath&
TypeComponentPath::operator=(const TypeComponentPath& other)
{
if (this != &other) {
fComponents.MakeEmpty();
for (int32 i = 0;
TypeComponent* component = other.fComponents.ItemAt(i); i++) {
if (!AddComponent(*component))
break;
}
}
return *this;
}
bool
TypeComponentPath::operator==(const TypeComponentPath& other) const
{
int32 count = fComponents.CountItems();
if (count != other.fComponents.CountItems())
return false;
for (int32 i = 0; i < count; i++) {
if (*fComponents.ItemAt(i) != *other.fComponents.ItemAt(i))
return false;
}
return true;
}
+129
View File
@@ -0,0 +1,129 @@
/*
* Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
* Distributed under the terms of the MIT License.
*/
#ifndef TYPE_COMPONENT_PATH_H
#define TYPE_COMPONENT_PATH_H
#include <String.h>
#include <ObjectList.h>
#include <Referenceable.h>
#include "Type.h"
enum type_component_kind {
TYPE_COMPONENT_UNDEFINED,
TYPE_COMPONENT_BASE_TYPE,
TYPE_COMPONENT_DATA_MEMBER,
TYPE_COMPONENT_ARRAY_ELEMENT
};
struct TypeComponent {
uint64 index;
BString name;
type_component_kind componentKind;
type_kind typeKind;
TypeComponent()
:
componentKind(TYPE_COMPONENT_UNDEFINED)
{
}
TypeComponent(const TypeComponent& other)
:
index(other.index),
name(other.name),
componentKind(other.componentKind),
typeKind(other.typeKind)
{
}
bool IsValid() const
{
return componentKind != TYPE_COMPONENT_UNDEFINED;
}
void SetToBaseType(type_kind typeKind, uint64 index = 0,
const BString& name = BString())
{
this->componentKind = TYPE_COMPONENT_BASE_TYPE;
this->typeKind = typeKind;
this->index = index;
this->name = name;
}
void SetToDataMember(type_kind typeKind, uint64 index,
const BString& name)
{
this->componentKind = TYPE_COMPONENT_DATA_MEMBER;
this->typeKind = typeKind;
this->index = index;
this->name = name;
}
void SetToArrayElement(type_kind typeKind, uint64 index)
{
this->componentKind = TYPE_COMPONENT_ARRAY_ELEMENT;
this->typeKind = typeKind;
this->index = index;
this->name = name;
}
uint32 HashValue() const;
TypeComponent& operator=(const TypeComponent& other)
{
index = other.index;
name = other.name;
componentKind = other.componentKind;
typeKind = other.typeKind;
return *this;
}
bool operator==(const TypeComponent& other) const;
bool operator!=(const TypeComponent& other) const
{
return !(*this == other);
}
};
class TypeComponentPath : public Referenceable {
public:
TypeComponentPath();
TypeComponentPath(
const TypeComponentPath& other);
virtual ~TypeComponentPath();
int32 CountComponents() const;
TypeComponent ComponentAt(int32 index) const;
bool AddComponent(const TypeComponent& component);
void Clear();
uint32 HashValue() const;
TypeComponentPath& operator=(const TypeComponentPath& other);
bool operator==(const TypeComponentPath& other) const;
bool operator!=(const TypeComponentPath& other) const
{ return !(*this == other); }
private:
typedef BObjectList<TypeComponent> ComponentList;
private:
ComponentList fComponents;
};
#endif // TYPE_COMPONENT_PATH_H
+6 -1
View File
@@ -6,16 +6,20 @@
#include "Variable.h"
#include "ObjectID.h"
#include "Type.h"
#include "ValueLocation.h"
Variable::Variable(const BString& name, Type* type, ValueLocation* location)
Variable::Variable(ObjectID* id, const BString& name, Type* type,
ValueLocation* location)
:
fID(id),
fName(name),
fType(type),
fLocation(location)
{
fID->AcquireReference();
fType->AcquireReference();
fLocation->AcquireReference();
}
@@ -23,6 +27,7 @@ Variable::Variable(const BString& name, Type* type, ValueLocation* location)
Variable::~Variable()
{
fID->ReleaseReference();
fType->ReleaseReference();
fLocation->ReleaseReference();
}
+5 -2
View File
@@ -11,21 +11,24 @@
#include <Referenceable.h>
class ObjectID;
class Type;
class ValueLocation;
class Variable : public Referenceable {
public:
Variable(const BString& name, Type* type,
ValueLocation* location);
Variable(ObjectID* id, const BString& name,
Type* type, ValueLocation* location);
~Variable();
ObjectID* ID() const { return fID; }
const BString& Name() const { return fName; }
Type* GetType() const { return fType; }
ValueLocation* Location() const { return fLocation; }
private:
ObjectID* fID;
BString fName;
Type* fType;
ValueLocation* fLocation;