diff --git a/src/apps/debugger/Jamfile b/src/apps/debugger/Jamfile index 591b6ab150..d90e062ef8 100644 --- a/src/apps/debugger/Jamfile +++ b/src/apps/debugger/Jamfile @@ -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 : diff --git a/src/apps/debugger/Jobs.cpp b/src/apps/debugger/Jobs.cpp index 4efa15a30b..6321e2be40 100644 --- a/src/apps/debugger/Jobs.cpp +++ b/src/apps/debugger/Jobs.cpp @@ -10,6 +10,7 @@ #include #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(&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 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(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(type)->BaseType(); + break; + case TYPE_TYPEDEF: +printf(" TYPE_TYPEDEF\n"); + type = dynamic_cast(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 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; +} diff --git a/src/apps/debugger/Jobs.h b/src/apps/debugger/Jobs.h index c218c79dce..6d316cfb0a 100644 --- a/src/apps/debugger/Jobs.h +++ b/src/apps/debugger/Jobs.h @@ -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 diff --git a/src/apps/debugger/MessageCodes.h b/src/apps/debugger/MessageCodes.h index f8ed741f7e..1733247834 100644 --- a/src/apps/debugger/MessageCodes.h +++ b/src/apps/debugger/MessageCodes.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', diff --git a/src/apps/debugger/TeamDebugger.cpp b/src/apps/debugger/TeamDebugger.cpp index 2121b5123c..246f089120 100644 --- a/src/apps/debugger/TeamDebugger.cpp +++ b/src/apps/debugger/TeamDebugger.cpp @@ -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 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()); diff --git a/src/apps/debugger/TeamDebugger.h b/src/apps/debugger/TeamDebugger.h index e449e15d79..5803bc6b42 100644 --- a/src/apps/debugger/TeamDebugger.h +++ b/src/apps/debugger/TeamDebugger.h @@ -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); diff --git a/src/apps/debugger/ThreadHandler.cpp b/src/apps/debugger/ThreadHandler.cpp index 9a12936512..c5108a3bd7 100644 --- a/src/apps/debugger/ThreadHandler.cpp +++ b/src/apps/debugger/ThreadHandler.cpp @@ -304,8 +304,8 @@ ThreadHandler::HandleThreadStateChanged() AutoLocker 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 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) { diff --git a/src/apps/debugger/Worker.cpp b/src/apps/debugger/Worker.cpp index ace1d966f8..2d35f255b9 100644 --- a/src/apps/debugger/Worker.cpp +++ b/src/apps/debugger/Worker.cpp @@ -9,6 +9,58 @@ #include +// 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(&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 jobDeleter(job); + Reference jobReference(job, true); AutoLocker 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(); } diff --git a/src/apps/debugger/Worker.h b/src/apps/debugger/Worker.h index 8a15c7d35d..bef87421be 100644 --- a/src/apps/debugger/Worker.h +++ b/src/apps/debugger/Worker.h @@ -8,6 +8,7 @@ #include #include +#include #include #include @@ -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 JobList; -class Job : public DoublyLinkedListLinkImpl, public HashTableLink { +class Job : public Referenceable, public DoublyLinkedListLinkImpl, + public HashTableLink { 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); diff --git a/src/apps/debugger/debug_info/DebuggerImageDebugInfo.cpp b/src/apps/debugger/debug_info/DebuggerImageDebugInfo.cpp index a494dee146..8d0819323f 100644 --- a/src/apps/debugger/debug_info/DebuggerImageDebugInfo.cpp +++ b/src/apps/debugger/debug_info/DebuggerImageDebugInfo.cpp @@ -79,9 +79,9 @@ DebuggerImageDebugInfo::GetFunctions(BObjectList& 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; } diff --git a/src/apps/debugger/debug_info/DebuggerImageDebugInfo.h b/src/apps/debugger/debug_info/DebuggerImageDebugInfo.h index 37196661d2..9c8ee1bc50 100644 --- a/src/apps/debugger/debug_info/DebuggerImageDebugInfo.h +++ b/src/apps/debugger/debug_info/DebuggerImageDebugInfo.h @@ -27,7 +27,7 @@ public: virtual status_t GetFunctions( BObjectList& functions); virtual status_t CreateFrame(Image* image, - FunctionDebugInfo* function, + FunctionInstance* functionInstance, CpuState* cpuState, StackFrame*& _previousFrame, CpuState*& _previousCpuState); diff --git a/src/apps/debugger/debug_info/DwarfImageDebugInfo.cpp b/src/apps/debugger/debug_info/DwarfImageDebugInfo.cpp index 14fb0ba658..d9638db7e2 100644 --- a/src/apps/debugger/debug_info/DwarfImageDebugInfo.cpp +++ b/src/apps/debugger/debug_info/DwarfImageDebugInfo.cpp @@ -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(_function); + DwarfFunctionDebugInfo* function = dynamic_cast( + functionInstance->GetFunctionDebugInfo()); if (function == NULL) return B_BAD_VALUE; @@ -365,14 +367,24 @@ if (previousCpuState->GetRegisterValue(reg, value)) { return B_NO_MEMORY; Reference 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 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(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(); diff --git a/src/apps/debugger/debug_info/DwarfImageDebugInfo.h b/src/apps/debugger/debug_info/DwarfImageDebugInfo.h index 76692c92e0..e72727768c 100644 --- a/src/apps/debugger/debug_info/DwarfImageDebugInfo.h +++ b/src/apps/debugger/debug_info/DwarfImageDebugInfo.h @@ -42,7 +42,7 @@ public: virtual status_t GetFunctions( BObjectList& functions); virtual status_t CreateFrame(Image* image, - FunctionDebugInfo* function, + FunctionInstance* functionInstance, CpuState* cpuState, StackFrame*& _previousFrame, CpuState*& _previousCpuState); diff --git a/src/apps/debugger/debug_info/DwarfInterfaceFactory.cpp b/src/apps/debugger/debug_info/DwarfInterfaceFactory.cpp index 696ef018db..f9f4ae65fc 100644 --- a/src/apps/debugger/debug_info/DwarfInterfaceFactory.cpp +++ b/src/apps/debugger/debug_info/DwarfInterfaceFactory.cpp @@ -10,14 +10,59 @@ #include +#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(&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 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 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(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( + 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( + 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(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()); +} + } +} diff --git a/src/apps/debugger/debug_info/DwarfInterfaceFactory.h b/src/apps/debugger/debug_info/DwarfInterfaceFactory.h index b466e85413..0825bdbaad 100644 --- a/src/apps/debugger/debug_info/DwarfInterfaceFactory.h +++ b/src/apps/debugger/debug_info/DwarfInterfaceFactory.h @@ -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; }; diff --git a/src/apps/debugger/debug_info/Function.cpp b/src/apps/debugger/debug_info/Function.cpp index 7acd659ee0..65e3fe3410 100644 --- a/src/apps/debugger/debug_info/Function.cpp +++ b/src/apps/debugger/debug_info/Function.cpp @@ -6,6 +6,7 @@ #include "Function.h" #include "FileSourceCode.h" +#include "FunctionID.h" Function::Function() diff --git a/src/apps/debugger/debug_info/Function.h b/src/apps/debugger/debug_info/Function.h index ec40c05e0a..252fa664d7 100644 --- a/src/apps/debugger/debug_info/Function.h +++ b/src/apps/debugger/debug_info/Function.h @@ -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 diff --git a/src/apps/debugger/debug_info/FunctionInstance.cpp b/src/apps/debugger/debug_info/FunctionInstance.cpp index 6e9c6fe18a..f19ba5993f 100644 --- a/src/apps/debugger/debug_info/FunctionInstance.cpp +++ b/src/apps/debugger/debug_info/FunctionInstance.cpp @@ -5,8 +5,13 @@ #include "FunctionInstance.h" +#include + #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) { diff --git a/src/apps/debugger/debug_info/FunctionInstance.h b/src/apps/debugger/debug_info/FunctionInstance.h index 89092c498e..16b5e5094f 100644 --- a/src/apps/debugger/debug_info/FunctionInstance.h +++ b/src/apps/debugger/debug_info/FunctionInstance.h @@ -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 diff --git a/src/apps/debugger/debug_info/ImageDebugInfo.h b/src/apps/debugger/debug_info/ImageDebugInfo.h index 2f934d249c..5fd1a30455 100644 --- a/src/apps/debugger/debug_info/ImageDebugInfo.h +++ b/src/apps/debugger/debug_info/ImageDebugInfo.h @@ -28,6 +28,8 @@ public: ImageDebugInfo(const ImageInfo& imageInfo); ~ImageDebugInfo(); + const ImageInfo& GetImageInfo() const { return fImageInfo; } + bool AddSpecificInfo(SpecificImageDebugInfo* info); status_t FinishInit(); diff --git a/src/apps/debugger/debug_info/SpecificImageDebugInfo.h b/src/apps/debugger/debug_info/SpecificImageDebugInfo.h index 04998efe9d..16f15402cd 100644 --- a/src/apps/debugger/debug_info/SpecificImageDebugInfo.h +++ b/src/apps/debugger/debug_info/SpecificImageDebugInfo.h @@ -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; diff --git a/src/apps/debugger/gui/team_window/TeamWindow.cpp b/src/apps/debugger/gui/team_window/TeamWindow.cpp index 950477eec7..ee1f52adcd 100644 --- a/src/apps/debugger/gui/team_window/TeamWindow.cpp +++ b/src/apps/debugger/gui/team_window/TeamWindow.cpp @@ -3,6 +3,7 @@ * Distributed under the terms of the MIT License. */ + #include "TeamWindow.h" #include @@ -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 locker(fDebugModel); + fActiveStackFrame->RemoveListener(this); + locker.Unlock(); + fActiveStackFrame->RemoveReference(); + } fActiveStackFrame = frame; if (fActiveStackFrame != NULL) { fActiveStackFrame->AddReference(); + + AutoLocker 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) { diff --git a/src/apps/debugger/gui/team_window/TeamWindow.h b/src/apps/debugger/gui/team_window/TeamWindow.h index 129068d2b5..c232373754 100644 --- a/src/apps/debugger/gui/team_window/TeamWindow.h +++ b/src/apps/debugger/gui/team_window/TeamWindow.h @@ -5,6 +5,7 @@ #ifndef TEAM_WINDOW_H #define TEAM_WINDOW_H + #include #include @@ -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; }; diff --git a/src/apps/debugger/gui/team_window/VariablesView.cpp b/src/apps/debugger/gui/team_window/VariablesView.cpp index 3663a306f5..678588f040 100644 --- a/src/apps/debugger/gui/team_window/VariablesView.cpp +++ b/src/apps/debugger/gui/team_window/VariablesView.cpp @@ -10,30 +10,136 @@ #include +#include + #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 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 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 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 pathReference(path, true); + + fListener->StackFrameValueRequested(fThread, fStackFrame, + variable, path); +} + + +// #pragma mark - Listener + + +VariablesView::Listener::~Listener() +{ +} diff --git a/src/apps/debugger/gui/team_window/VariablesView.h b/src/apps/debugger/gui/team_window/VariablesView.h index 6552d1cec7..1bac6e7244 100644 --- a/src/apps/debugger/gui/team_window/VariablesView.h +++ b/src/apps/debugger/gui/team_window/VariablesView.h @@ -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 }; diff --git a/src/apps/debugger/model/StackFrame.cpp b/src/apps/debugger/model/StackFrame.cpp index 9a1aa74ca6..f80d0cacf0 100644 --- a/src/apps/debugger/model/StackFrame.cpp +++ b/src/apps/debugger/model/StackFrame.cpp @@ -5,9 +5,12 @@ #include "StackFrame.h" +#include + #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) +{ +} diff --git a/src/apps/debugger/model/StackFrame.h b/src/apps/debugger/model/StackFrame.h index 23bb59e85a..c1ce027680 100644 --- a/src/apps/debugger/model/StackFrame.h +++ b/src/apps/debugger/model/StackFrame.h @@ -5,10 +5,12 @@ #ifndef STACK_FRAME_H #define STACK_FRAME_H + #include #include #include +#include #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 VariableList; + typedef DoublyLinkedList 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 { +public: + virtual ~Listener(); + + virtual void StackFrameValueRetrieved(StackFrame* stackFrame, + Variable* variable, + TypeComponentPath* path); + // called with lock held }; diff --git a/src/apps/debugger/model/StackFrameValues.cpp b/src/apps/debugger/model/StackFrameValues.cpp new file mode 100644 index 0000000000..752f4cb2c2 --- /dev/null +++ b/src/apps/debugger/model/StackFrameValues.cpp @@ -0,0 +1,183 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + + +#include "StackFrameValues.h" + +#include + +#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 { + 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* 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; + } +} diff --git a/src/apps/debugger/model/StackFrameValues.h b/src/apps/debugger/model/StackFrameValues.h new file mode 100644 index 0000000000..e8de005c33 --- /dev/null +++ b/src/apps/debugger/model/StackFrameValues.h @@ -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 +#include +#include + + +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 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 diff --git a/src/apps/debugger/model/TeamDebugModel.h b/src/apps/debugger/model/TeamDebugModel.h index 2ae9d43396..2785b7e561 100644 --- a/src/apps/debugger/model/TeamDebugModel.h +++ b/src/apps/debugger/model/TeamDebugModel.h @@ -22,6 +22,7 @@ enum { class Architecture; class Breakpoint; +class FunctionID; class SourceCode; class TeamMemory; class UserBreakpoint; diff --git a/src/apps/debugger/model/TypeComponentPath.cpp b/src/apps/debugger/model/TypeComponentPath.cpp new file mode 100644 index 0000000000..d59c5eac4e --- /dev/null +++ b/src/apps/debugger/model/TypeComponentPath.cpp @@ -0,0 +1,139 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + + +#include "TypeComponentPath.h" + +#include + +#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; +} diff --git a/src/apps/debugger/model/TypeComponentPath.h b/src/apps/debugger/model/TypeComponentPath.h new file mode 100644 index 0000000000..a3189eaa0a --- /dev/null +++ b/src/apps/debugger/model/TypeComponentPath.h @@ -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 + +#include +#include + +#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 ComponentList; + +private: + ComponentList fComponents; +}; + + +#endif // TYPE_COMPONENT_PATH_H diff --git a/src/apps/debugger/model/Variable.cpp b/src/apps/debugger/model/Variable.cpp index eb6a40f31e..8e01442930 100644 --- a/src/apps/debugger/model/Variable.cpp +++ b/src/apps/debugger/model/Variable.cpp @@ -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(); } diff --git a/src/apps/debugger/model/Variable.h b/src/apps/debugger/model/Variable.h index 6583a6e8ad..0425da97f0 100644 --- a/src/apps/debugger/model/Variable.h +++ b/src/apps/debugger/model/Variable.h @@ -11,21 +11,24 @@ #include +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;