* 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:
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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,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();
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user