diff --git a/src/apps/debugger/BreakpointManager.cpp b/src/apps/debugger/BreakpointManager.cpp index d5a0ffc998..901611f58a 100644 --- a/src/apps/debugger/BreakpointManager.cpp +++ b/src/apps/debugger/BreakpointManager.cpp @@ -38,108 +38,179 @@ BreakpointManager::Init() status_t -BreakpointManager::InstallUserBreakpoint(target_addr_t address, +BreakpointManager::InstallUserBreakpoint(UserBreakpoint* userBreakpoint, bool enabled) { - user_breakpoint_state state = enabled - ? USER_BREAKPOINT_ENABLED : USER_BREAKPOINT_DISABLED; - +printf("BreakpointManager::InstallUserBreakpoint(%p, %d)\n", userBreakpoint, enabled); + AutoLocker installLocker(fLock); AutoLocker modelLocker(fDebugModel); - // If there already is a breakpoint, it might already have the requested - // state. - Breakpoint* breakpoint = fDebugModel->BreakpointAtAddress(address); - if (breakpoint != NULL && breakpoint->UserState() == state) + bool oldEnabled = userBreakpoint->IsEnabled(); + if (userBreakpoint->IsValid() && enabled == oldEnabled) +{ +printf(" user breakpoint already valid and with same enabled state\n"); return B_OK; +} - // create a breakpoint, if it doesn't exist yet - if (breakpoint == NULL) { - Image* image = fDebugModel->GetTeam()->ImageByAddress(address); - if (image == NULL) - return B_BAD_ADDRESS; + // get/create the breakpoints for all instances +printf(" creating breakpoints for breakpoint instances\n"); + status_t error = B_OK; + for (int32 i = 0; + UserBreakpointInstance* instance = userBreakpoint->InstanceAt(i); i++) { +printf(" breakpoint instance %p\n", instance); + if (instance->GetBreakpoint() != NULL) +{ +printf(" -> already has breakpoint\n"); + continue; +} - breakpoint = new(std::nothrow) Breakpoint(image, address); - if (breakpoint == NULL) - return B_NO_MEMORY; + target_addr_t address = instance->Address(); + Breakpoint* breakpoint = fDebugModel->BreakpointAtAddress(address); + if (breakpoint == NULL) { +printf(" -> no breakpoint at that address yet\n"); + Image* image = fDebugModel->GetTeam()->ImageByAddress(address); + if (image == NULL) { +printf(" -> no image at that address\n"); + error = B_BAD_ADDRESS; + break; + } - if (!fDebugModel->AddBreakpoint(breakpoint)) - return B_NO_MEMORY; + breakpoint = new(std::nothrow) Breakpoint(image, address); + if (breakpoint == NULL) { + error = B_NO_MEMORY; + break; + } + + if (!fDebugModel->AddBreakpoint(breakpoint)) { + error = B_NO_MEMORY; + break; + } + } + +printf(" -> adding instance to breakpoint %p\n", breakpoint); + breakpoint->AddUserBreakpoint(instance); + instance->SetBreakpoint(breakpoint); } - user_breakpoint_state oldState = breakpoint->UserState(); + // If everything looks good so far mark the user breakpoint according to + // its new state. + if (error == B_OK) + userBreakpoint->SetEnabled(enabled); - // set the breakpoint state - breakpoint->SetUserState(state); - fDebugModel->NotifyUserBreakpointChanged(breakpoint); + // notify user breakpoint listeners + if (error == B_OK) { + for (int32 i = 0; + UserBreakpointInstance* instance = userBreakpoint->InstanceAt(i); + i++) { + fDebugModel->NotifyUserBreakpointChanged(instance->GetBreakpoint()); + } + } - AutoLocker installLocker(fLock); - // We need to make the installation decision with both locks held, and - // we keep this lock until we have the breakpoint installed/uninstalled. - - bool install = breakpoint->ShouldBeInstalled(); - if (breakpoint->IsInstalled() == install) - return B_OK; - - // The breakpoint needs to be installed/uninstalled. - Reference breakpointReference(breakpoint); modelLocker.Unlock(); - status_t error = install - ? fDebuggerInterface->InstallBreakpoint(address) - : fDebuggerInterface->UninstallBreakpoint(address); - - // Mark the breakpoint installed/uninstalled, if everything went fine. + // install/uninstall the breakpoints as needed +printf(" updating breakpoints\n"); if (error == B_OK) { - breakpoint->SetInstalled(install); - return B_OK; + for (int32 i = 0; + UserBreakpointInstance* instance = userBreakpoint->InstanceAt(i); + i++) { +printf(" breakpoint instance %p\n", instance); + error = _UpdateBreakpointInstallation(instance->GetBreakpoint()); + if (error != B_OK) + break; + } } - // revert on error - installLocker. Unlock(); - modelLocker.Lock(); + if (error == B_OK) { +printf(" success, marking user breakpoint valid\n"); + // everything went fine -- mark the user breakpoint valid + if (!userBreakpoint->IsValid()) { + modelLocker.Lock(); + userBreakpoint->SetValid(true); + userBreakpoint->AcquireReference(); + // TODO: Put the user breakpoint some place? + modelLocker.Unlock(); + } + } else { + // something went wrong -- revert the situation +printf(" error, reverting\n"); + modelLocker.Lock(); + userBreakpoint->SetEnabled(oldEnabled); + modelLocker.Unlock(); - breakpoint->SetUserState(oldState); - fDebugModel->NotifyUserBreakpointChanged(breakpoint); + if (!oldEnabled || !userBreakpoint->IsValid()) { + for (int32 i = 0; UserBreakpointInstance* instance + = userBreakpoint->InstanceAt(i); + i++) { + Breakpoint* breakpoint = instance->GetBreakpoint(); + if (breakpoint == NULL) + continue; - if (breakpoint->IsUnused()) - fDebugModel->RemoveBreakpoint(breakpoint); + if (!userBreakpoint->IsValid()) { + instance->SetBreakpoint(NULL); + breakpoint->RemoveUserBreakpoint(instance); + } + + _UpdateBreakpointInstallation(breakpoint); + + modelLocker.Lock(); + fDebugModel->NotifyUserBreakpointChanged(breakpoint); + + if (breakpoint->IsUnused()) + fDebugModel->RemoveBreakpoint(breakpoint); + modelLocker.Unlock(); + } + } + } + + installLocker.Unlock(); return error; } void -BreakpointManager::UninstallUserBreakpoint(target_addr_t address) +BreakpointManager::UninstallUserBreakpoint(UserBreakpoint* userBreakpoint) { + AutoLocker installLocker(fLock); AutoLocker modelLocker(fDebugModel); - Breakpoint* breakpoint = fDebugModel->BreakpointAtAddress(address); - if (breakpoint == NULL || breakpoint->UserState() == USER_BREAKPOINT_NONE) + if (!userBreakpoint->IsValid()) return; - // set the breakpoint state - breakpoint->SetUserState(USER_BREAKPOINT_NONE); - fDebugModel->NotifyUserBreakpointChanged(breakpoint); - - AutoLocker installLocker(fLock); - // We need to make the uninstallation decision with both locks held, and - // we keep this lock until we have the breakpoint uninstalled. - - // check whether the breakpoint needs to be uninstalled - bool uninstall = !breakpoint->ShouldBeInstalled() - && breakpoint->IsInstalled(); - - // if unused remove it - Reference breakpointReference(breakpoint); - if (breakpoint->IsUnused()) - fDebugModel->RemoveBreakpoint(breakpoint); + userBreakpoint->SetValid(false); + userBreakpoint->SetEnabled(false); modelLocker.Unlock(); - if (uninstall) { - fDebuggerInterface->UninstallBreakpoint(address); - breakpoint->SetInstalled(false); + // uninstall the breakpoints as needed + for (int32 i = 0; + UserBreakpointInstance* instance = userBreakpoint->InstanceAt(i); i++) { + if (Breakpoint* breakpoint = instance->GetBreakpoint()) + _UpdateBreakpointInstallation(breakpoint); } + + modelLocker.Lock(); + + // detach the breakpoints from the user breakpoint instances + for (int32 i = 0; + UserBreakpointInstance* instance = userBreakpoint->InstanceAt(i); i++) { + if (Breakpoint* breakpoint = instance->GetBreakpoint()) { + instance->SetBreakpoint(NULL); + breakpoint->RemoveUserBreakpoint(instance); + + fDebugModel->NotifyUserBreakpointChanged(breakpoint); + + if (breakpoint->IsUnused()) + fDebugModel->RemoveBreakpoint(breakpoint); + } + } + + modelLocker.Unlock(); + installLocker.Unlock(); + + // release the reference from InstallUserBreakpoint() + userBreakpoint->ReleaseReference(); } @@ -147,6 +218,7 @@ status_t BreakpointManager::InstallTemporaryBreakpoint(target_addr_t address, BreakpointClient* client) { + AutoLocker installLocker(fLock); AutoLocker modelLocker(fDebugModel); // create a breakpoint, if it doesn't exist yet @@ -169,10 +241,6 @@ BreakpointManager::InstallTemporaryBreakpoint(target_addr_t address, // add the client status_t error; if (breakpoint->AddClient(client)) { - AutoLocker installLocker(fLock); - // We need to make the installation decision with both locks held, - // and we keep this lock until we have the breakpoint installed. - if (breakpoint->IsInstalled()) return B_OK; @@ -185,7 +253,6 @@ BreakpointManager::InstallTemporaryBreakpoint(target_addr_t address, return B_OK; } - installLocker.Unlock(); modelLocker.Lock(); breakpoint->RemoveClient(client); @@ -204,6 +271,7 @@ void BreakpointManager::UninstallTemporaryBreakpoint(target_addr_t address, BreakpointClient* client) { + AutoLocker installLocker(fLock); AutoLocker modelLocker(fDebugModel); Breakpoint* breakpoint = fDebugModel->BreakpointAtAddress(address); @@ -213,10 +281,6 @@ BreakpointManager::UninstallTemporaryBreakpoint(target_addr_t address, // remove the client breakpoint->RemoveClient(client); - AutoLocker installLocker(fLock); - // We need to make the uninstallation decision with both locks held, and - // we keep this lock until we have the breakpoint uninstalled. - // check whether the breakpoint needs to be uninstalled bool uninstall = !breakpoint->ShouldBeInstalled() && breakpoint->IsInstalled(); @@ -233,3 +297,30 @@ BreakpointManager::UninstallTemporaryBreakpoint(target_addr_t address, breakpoint->SetInstalled(false); } } + + +status_t +BreakpointManager::_UpdateBreakpointInstallation(Breakpoint* breakpoint) +{ + bool shouldBeInstalled = breakpoint->ShouldBeInstalled(); +printf("BreakpointManager::_UpdateBreakpointInstallation(%p): should be installed: %d, is installed: %d\n", breakpoint, shouldBeInstalled, breakpoint->IsInstalled()); + if (shouldBeInstalled == breakpoint->IsInstalled()) + return B_OK; + + if (shouldBeInstalled) { + // install + status_t error = fDebuggerInterface->InstallBreakpoint( + breakpoint->Address()); + if (error != B_OK) + return error; +printf("BREAKPOINT at %#llx installed: %s\n", breakpoint->Address(), strerror(error)); + breakpoint->SetInstalled(true); + } else { + // uninstall + fDebuggerInterface->UninstallBreakpoint(breakpoint->Address()); +printf("BREAKPOINT at %#llx uninstalled\n", breakpoint->Address()); + breakpoint->SetInstalled(false); + } + + return B_OK; +} diff --git a/src/apps/debugger/BreakpointManager.h b/src/apps/debugger/BreakpointManager.h index 8b50bd1b56..d0d16e5e69 100644 --- a/src/apps/debugger/BreakpointManager.h +++ b/src/apps/debugger/BreakpointManager.h @@ -22,9 +22,15 @@ public: status_t Init(); - status_t InstallUserBreakpoint(target_addr_t address, +// status_t InstallUserBreakpoint(target_addr_t address, +// bool enabled); +// void UninstallUserBreakpoint(target_addr_t address); + + status_t InstallUserBreakpoint( + UserBreakpoint* userBreakpoint, bool enabled); - void UninstallUserBreakpoint(target_addr_t address); + void UninstallUserBreakpoint( + UserBreakpoint* userBreakpoint); status_t InstallTemporaryBreakpoint( target_addr_t address, @@ -33,6 +39,11 @@ public: target_addr_t address, BreakpointClient* client); +private: + status_t _UpdateBreakpointInstallation( + Breakpoint* breakpoint); + // fLock must be held + private: BLocker fLock; // used to synchronize un-/installing TeamDebugModel* fDebugModel; diff --git a/src/apps/debugger/Jamfile b/src/apps/debugger/Jamfile index b56fdba480..59432d2776 100644 --- a/src/apps/debugger/Jamfile +++ b/src/apps/debugger/Jamfile @@ -56,7 +56,9 @@ Application Debugger : DwarfFunctionDebugInfo.cpp DwarfImageDebugInfo.cpp DwarfTeamDebugInfo.cpp + Function.cpp FunctionDebugInfo.cpp + FunctionInstance.cpp ImageDebugInfo.cpp ImageDebugInfoProvider.cpp SpecificImageDebugInfo.cpp @@ -97,6 +99,7 @@ Application Debugger : StackTrace.cpp Statement.cpp SymbolInfo.cpp + UserBreakpoint.cpp Team.cpp TeamDebugModel.cpp TeamMemory.cpp diff --git a/src/apps/debugger/Jobs.cpp b/src/apps/debugger/Jobs.cpp index 79b32da855..7b03f9d855 100644 --- a/src/apps/debugger/Jobs.cpp +++ b/src/apps/debugger/Jobs.cpp @@ -12,7 +12,7 @@ #include "Architecture.h" #include "CpuState.h" #include "DebuggerInterface.h" -#include "FunctionDebugInfo.h" +#include "Function.h" #include "Image.h" #include "ImageDebugInfo.h" #include "SourceCode.h" @@ -258,7 +258,7 @@ LoadImageDebugInfoJob::Do() // set the result locker.Lock(); if (error == B_OK) { - fImage->SetImageDebugInfo(debugInfo, IMAGE_DEBUG_INFO_LOADED); + error = fImage->SetImageDebugInfo(debugInfo, IMAGE_DEBUG_INFO_LOADED); debugInfo->RemoveReference(); } else { fImage->SetImageDebugInfo(NULL, IMAGE_DEBUG_INFO_UNAVAILABLE); @@ -319,7 +319,7 @@ LoadImageDebugInfoJob::ScheduleIfNecessary(Worker* worker, Image* image, LoadSourceCodeJob::LoadSourceCodeJob( DebuggerInterface* debuggerInterface, Architecture* architecture, - Team* team, FunctionDebugInfo* function) + Team* team, Function* function) : fDebuggerInterface(debuggerInterface), fArchitecture(architecture), @@ -346,13 +346,29 @@ LoadSourceCodeJob::Key() const status_t LoadSourceCodeJob::Do() { + // Get the function debug info for an instance which we can use to load the + // source code. + AutoLocker locker(fTeam); + + status_t error = B_OK; + FunctionDebugInfo* functionDebugInfo = NULL; + if (FunctionInstance* instance = fFunction->FirstInstance()) { + functionDebugInfo = instance->GetFunctionDebugInfo(); + } else + error = B_ENTRY_NOT_FOUND; + Reference functionDebugInfoReference(functionDebugInfo); + + locker.Unlock(); + // load the source code, if we can SourceCode* sourceCode = NULL; - status_t error = fFunction->GetSpecificImageDebugInfo()->LoadSourceCode( - fFunction, sourceCode); + if (error == B_OK) { + error = functionDebugInfo->GetSpecificImageDebugInfo()->LoadSourceCode( + functionDebugInfo, sourceCode); + } // set the result - AutoLocker locker(fTeam); + locker.Lock(); if (error == B_OK) { fFunction->SetSourceCode(sourceCode, FUNCTION_SOURCE_LOADED); sourceCode->RemoveReference(); diff --git a/src/apps/debugger/Jobs.h b/src/apps/debugger/Jobs.h index ce9e270323..b678fc9156 100644 --- a/src/apps/debugger/Jobs.h +++ b/src/apps/debugger/Jobs.h @@ -12,7 +12,7 @@ class Architecture; class CpuState; class DebuggerInterface; -class FunctionDebugInfo; +class Function; class Image; class StackFrame; class Team; @@ -112,8 +112,8 @@ class LoadSourceCodeJob : public Job { public: LoadSourceCodeJob( DebuggerInterface* debuggerInterface, - Architecture* architecture, - Team* team, FunctionDebugInfo* function); + Architecture* architecture, Team* team, + Function* function); virtual ~LoadSourceCodeJob(); virtual JobKey Key() const; @@ -123,7 +123,7 @@ private: DebuggerInterface* fDebuggerInterface; Architecture* fArchitecture; Team* fTeam; - FunctionDebugInfo* fFunction; + Function* fFunction; }; diff --git a/src/apps/debugger/TeamDebugger.cpp b/src/apps/debugger/TeamDebugger.cpp index e0535a009b..a1d4ffcd93 100644 --- a/src/apps/debugger/TeamDebugger.cpp +++ b/src/apps/debugger/TeamDebugger.cpp @@ -21,11 +21,15 @@ #include "CpuState.h" #include "DebuggerInterface.h" #include "FileManager.h" +#include "Function.h" +#include "ImageDebugInfo.h" #include "Jobs.h" #include "LocatableFile.h" #include "MessageCodes.h" -#include "SymbolInfo.h" +#include "SourceCode.h" +#include "SpecificImageDebugInfo.h" #include "Statement.h" +#include "SymbolInfo.h" #include "TeamDebugInfo.h" #include "TeamDebugModel.h" @@ -479,8 +483,10 @@ TeamDebugger::MessageReceived(BMessage* message) void TeamDebugger::FunctionSourceCodeRequested(TeamWindow* window, - FunctionDebugInfo* function) + FunctionInstance* functionInstance) { + Function* function = functionInstance->GetFunction(); + // mark loading AutoLocker< ::Team> locker(fTeam); if (function->SourceCodeState() != FUNCTION_SOURCE_NOT_LOADED) @@ -821,6 +827,8 @@ TeamDebugger::_HandleImageDeleted(ImageDeletedEvent* event) imageHandler->ReleaseReference(); } +// TODO: Remove breakpoints in the image! + return false; } @@ -837,7 +845,114 @@ void TeamDebugger::_HandleSetUserBreakpoint(target_addr_t address, bool enabled) { printf("TeamDebugger::_HandleSetUserBreakpoint(%#llx, %d)\n", address, enabled); - status_t error = fBreakpointManager->InstallUserBreakpoint(address, + // check whether there already is a breakpoint + AutoLocker< ::Team> locker(fTeam); + + Breakpoint* breakpoint = fDebugModel->BreakpointAtAddress(address); + UserBreakpoint* userBreakpoint = NULL; + if (breakpoint != NULL && breakpoint->FirstUserBreakpoint() != NULL) + userBreakpoint = breakpoint->FirstUserBreakpoint()->GetUserBreakpoint(); + Reference userBreakpointReference(userBreakpoint); + + if (userBreakpoint == NULL) { +printf(" no breakpoint yet\n"); + // get the function at the address + Image* image = fTeam->ImageByAddress(address); +printf(" image: %p\n", image); + if (image == NULL) + return; + ImageDebugInfo* imageDebugInfo = image->GetImageDebugInfo(); +printf(" image debug info: %p\n", imageDebugInfo); + if (imageDebugInfo == NULL) + return; + // TODO: Handle this case by loading the debug info, if possible! + FunctionInstance* functionInstance + = imageDebugInfo->FunctionAtAddress(address); +printf(" function instance: %p\n", functionInstance); + if (functionInstance == NULL) + return; + Function* function = functionInstance->GetFunction(); +printf(" function: %p\n", function); + + // get the source location for the address + FunctionDebugInfo* functionDebugInfo + = functionInstance->GetFunctionDebugInfo(); + SourceLocation sourceLocation; + Statement* breakpointStatement = NULL; +// if (SourceCode* sourceCode = functionDebugInfo->GetSourceCode()) { +// breakpointStatement = sourceCode->StatementAtAddress(address); +// if (breakpointStatement != NULL) +// sourceLocation = breakpointStatement->StartSourceLocation(); +// } + + if (breakpointStatement == NULL + && functionDebugInfo->GetSpecificImageDebugInfo()->GetStatement( + functionDebugInfo, address, breakpointStatement) != B_OK) { + return; + } + + sourceLocation = breakpointStatement->StartSourceLocation(); + breakpointStatement->ReleaseReference(); + + target_addr_t relativeAddress = address - functionInstance->Address(); +printf(" relative address: %#llx, source location: (%ld, %ld)\n", relativeAddress, sourceLocation.Line(), sourceLocation.Column()); + + // create the user breakpoint + userBreakpoint = new(std::nothrow) UserBreakpoint(function); + if (userBreakpoint == NULL) + return; + userBreakpointReference.SetTo(userBreakpoint, true); +printf(" created user breakpoint: %p\n", userBreakpoint); + + // iterate through all function instances and create + // UserBreakpointInstances + for (FunctionInstanceList::ConstIterator it + = function->Instances().GetIterator(); + FunctionInstance* instance = it.Next();) { +printf(" function instance %p: range: %#llx - %#llx\n", instance, instance->Address(), instance->Address() + instance->Size()); + // get the breakpoint address for the instance + target_addr_t instanceAddress = 0; + if (instance == functionInstance) { + instanceAddress = address; + } else if (functionInstance->SourceFile() != NULL) { + // We have a source file, so get the address for the source + // location. + Statement* statement = NULL; + functionDebugInfo = instance->GetFunctionDebugInfo(); + functionDebugInfo->GetSpecificImageDebugInfo() + ->GetStatementForSourceLocation(functionDebugInfo, + sourceLocation, statement); + if (statement != NULL) { + instanceAddress = statement->CoveringAddressRange().Start(); + // TODO: What about BreakpointAllowed()? + statement->ReleaseReference(); + } + } +printf(" breakpoint address using source info: %llx\n", instanceAddress); + + if (instanceAddress == 0) { + // No source file (or we failed getting the statement), so try + // to use the same relative address. + if (relativeAddress > instance->Size()) + continue; + instanceAddress = instance->Address() + relativeAddress; + } +printf(" final breakpoint address: %llx\n", instanceAddress); + + UserBreakpointInstance* breakpointInstance = new(std::nothrow) + UserBreakpointInstance(userBreakpoint, instanceAddress); + if (breakpointInstance == NULL + || !userBreakpoint->AddInstance(breakpointInstance)) { + delete breakpointInstance; + return; + } +printf(" breakpoint instance: %p\n", breakpointInstance); + } + } + + locker.Unlock(); + + status_t error = fBreakpointManager->InstallUserBreakpoint(userBreakpoint, enabled); if (error != B_OK) { _NotifyUser("Install Breakpoint", "Failed to install breakpoint: %s", @@ -850,7 +965,19 @@ void TeamDebugger::_HandleClearUserBreakpoint(target_addr_t address) { printf("TeamDebugger::_HandleClearUserBreakpoint(%#llx)\n", address); - fBreakpointManager->UninstallUserBreakpoint(address); + + AutoLocker< ::Team> locker(fTeam); + + Breakpoint* breakpoint = fDebugModel->BreakpointAtAddress(address); + if (breakpoint == NULL || breakpoint->FirstUserBreakpoint() == NULL) + return; + UserBreakpoint* userBreakpoint + = breakpoint->FirstUserBreakpoint()->GetUserBreakpoint(); + Reference userBreakpointReference(userBreakpoint); + + locker.Unlock(); + + fBreakpointManager->UninstallUserBreakpoint(userBreakpoint); } diff --git a/src/apps/debugger/TeamDebugger.h b/src/apps/debugger/TeamDebugger.h index 4af98241ef..e449e15d79 100644 --- a/src/apps/debugger/TeamDebugger.h +++ b/src/apps/debugger/TeamDebugger.h @@ -42,7 +42,7 @@ public: private: // TeamWindow::Listener virtual void FunctionSourceCodeRequested(TeamWindow* window, - FunctionDebugInfo* function); + FunctionInstance* function); virtual void ImageDebugInfoRequested(TeamWindow* window, Image* image); virtual void ThreadActionRequested(TeamWindow* window, diff --git a/src/apps/debugger/ThreadHandler.cpp b/src/apps/debugger/ThreadHandler.cpp index cb8f28d4f4..ed0f53736e 100644 --- a/src/apps/debugger/ThreadHandler.cpp +++ b/src/apps/debugger/ThreadHandler.cpp @@ -15,7 +15,7 @@ #include "BreakpointManager.h" #include "CpuState.h" #include "DebuggerInterface.h" -#include "FunctionDebugInfo.h" +#include "FunctionInstance.h" #include "ImageDebugInfo.h" #include "InstructionInfo.h" #include "Jobs.h" @@ -126,7 +126,7 @@ ThreadHandler::HandleBreakpointHit(BreakpointHitEvent* event) // spurious breakpoint -- might be a temporary breakpoint, that has // already been uninstalled continueThread = true; - } else if (breakpoint->UserState() != USER_BREAKPOINT_ENABLED) { + } else if (breakpoint->HasEnabledUserBreakpoint()) { // breakpoint of another thread or one that has been disabled in // the meantime continueThread = true; @@ -382,20 +382,21 @@ ThreadHandler::_GetStatementAtInstructionPointer(StackFrame* frame) { AutoLocker locker(fDebugModel); - FunctionDebugInfo* function = frame->Function(); - if (function == NULL) + FunctionInstance* functionInstance = frame->Function(); + if (functionInstance == NULL) return NULL; + FunctionDebugInfo* function = functionInstance->GetFunctionDebugInfo(); // If there's source code attached to the function, we can just get the // statement. - SourceCode* sourceCode = function->GetSourceCode(); - if (sourceCode != NULL) { - Statement* statement = sourceCode->StatementAtAddress( - frame->InstructionPointer()); - if (statement != NULL) - statement->AddReference(); - return statement; - } +// SourceCode* sourceCode = function->GetSourceCode(); +// if (sourceCode != NULL) { +// Statement* statement = sourceCode->StatementAtAddress( +// frame->InstructionPointer()); +// if (statement != NULL) +// statement->AddReference(); +// return statement; +// } locker.Unlock(); diff --git a/src/apps/debugger/arch/Architecture.cpp b/src/apps/debugger/arch/Architecture.cpp index a7a8f14ddd..b0eaf2e025 100644 --- a/src/apps/debugger/arch/Architecture.cpp +++ b/src/apps/debugger/arch/Architecture.cpp @@ -11,7 +11,7 @@ #include #include "CpuState.h" -#include "FunctionDebugInfo.h" +#include "FunctionInstance.h" #include "Image.h" #include "ImageDebugInfo.h" #include "ImageDebugInfoProvider.h" @@ -75,31 +75,38 @@ Architecture::CreateStackTrace(Team* team, // get the function teamLocker.Lock(); - FunctionDebugInfo* function = NULL; - if (imageDebugInfo != NULL) + FunctionInstance* function = NULL; + FunctionDebugInfo* functionDebugInfo = NULL; + if (imageDebugInfo != NULL) { function = imageDebugInfo->FunctionAtAddress(instructionPointer); - Reference functionReference(function); + if (function != NULL) + functionDebugInfo = function->GetFunctionDebugInfo(); + } + Reference functionReference(function); teamLocker.Unlock(); // If the last frame had been created by the architecture, we update the // CPU state. - if (architectureFrame) - UpdateStackFrameCpuState(frame, image, function, cpuState); + if (architectureFrame) { + UpdateStackFrameCpuState(frame, image, + functionDebugInfo, cpuState); + } // create the frame using the debug info StackFrame* previousFrame = NULL; CpuState* previousCpuState = NULL; if (function != NULL) { - status_t error = function->GetSpecificImageDebugInfo()->CreateFrame( - image, function, cpuState, previousFrame, previousCpuState); + status_t error = functionDebugInfo->GetSpecificImageDebugInfo() + ->CreateFrame(image, functionDebugInfo, cpuState, previousFrame, + previousCpuState); if (error != B_OK && error != B_UNSUPPORTED) break; } // If we have no frame yet, let the architecture create it. if (previousFrame == NULL) { - status_t error = CreateStackFrame(image, function, cpuState, - frame == NULL, previousFrame, previousCpuState); + status_t error = CreateStackFrame(image, functionDebugInfo, + cpuState, frame == NULL, previousFrame, previousCpuState); if (error != B_OK) break; architectureFrame = true; diff --git a/src/apps/debugger/arch/x86/ArchitectureX86.cpp b/src/apps/debugger/arch/x86/ArchitectureX86.cpp index 6238aedd4a..497ef94e35 100644 --- a/src/apps/debugger/arch/x86/ArchitectureX86.cpp +++ b/src/apps/debugger/arch/x86/ArchitectureX86.cpp @@ -296,8 +296,9 @@ ArchitectureX86::DisassembleCode(FunctionDebugInfo* function, bool breakpointAllowed; while (disassembler.GetNextInstruction(line, instructionAddress, instructionSize, breakpointAllowed) == B_OK) { +// TODO: Respect breakpointAllowed! if (!source->AddInstructionLine(line, instructionAddress, - instructionSize, breakpointAllowed)) { + instructionSize)) { return B_NO_MEMORY; } } @@ -320,9 +321,7 @@ ArchitectureX86::GetStatement(FunctionDebugInfo* function, // create a statement ContiguousStatement* statement = new(std::nothrow) ContiguousStatement( - SourceLocation(0), SourceLocation(1), - TargetAddressRange(info.Address(), info.Size()), - info.IsBreakpointAllowed()); + SourceLocation(0), TargetAddressRange(info.Address(), info.Size())); if (statement == NULL) return B_NO_MEMORY; diff --git a/src/apps/debugger/debug_info/BasicFunctionDebugInfo.cpp b/src/apps/debugger/debug_info/BasicFunctionDebugInfo.cpp index f08e6b5f7d..239843cf4b 100644 --- a/src/apps/debugger/debug_info/BasicFunctionDebugInfo.cpp +++ b/src/apps/debugger/debug_info/BasicFunctionDebugInfo.cpp @@ -49,17 +49,17 @@ BasicFunctionDebugInfo::Size() const } -const char* +const BString& BasicFunctionDebugInfo::Name() const { - return fName.String(); + return fName; } -const char* +const BString& BasicFunctionDebugInfo::PrettyName() const { - return fPrettyName.String(); + return fPrettyName; } diff --git a/src/apps/debugger/debug_info/BasicFunctionDebugInfo.h b/src/apps/debugger/debug_info/BasicFunctionDebugInfo.h index 969213b3f7..3136014d11 100644 --- a/src/apps/debugger/debug_info/BasicFunctionDebugInfo.h +++ b/src/apps/debugger/debug_info/BasicFunctionDebugInfo.h @@ -23,8 +23,8 @@ public: virtual SpecificImageDebugInfo* GetSpecificImageDebugInfo() const; virtual target_addr_t Address() const; virtual target_size_t Size() const; - virtual const char* Name() const; - virtual const char* PrettyName() const; + virtual const BString& Name() const; + virtual const BString& PrettyName() const; virtual LocatableFile* SourceFile() const; virtual SourceLocation SourceStartLocation() const; diff --git a/src/apps/debugger/debug_info/DebuggerImageDebugInfo.cpp b/src/apps/debugger/debug_info/DebuggerImageDebugInfo.cpp index 17dc3ba1c1..7842e49342 100644 --- a/src/apps/debugger/debug_info/DebuggerImageDebugInfo.cpp +++ b/src/apps/debugger/debug_info/DebuggerImageDebugInfo.cpp @@ -118,6 +118,15 @@ DebuggerImageDebugInfo::GetStatement(FunctionDebugInfo* function, } +status_t +DebuggerImageDebugInfo::GetStatementForSourceLocation( + FunctionDebugInfo* function, const SourceLocation& sourceLocation, + Statement*& _statement) +{ + return B_ENTRY_NOT_FOUND; +} + + /*static*/ int DebuggerImageDebugInfo::_CompareSymbols(const SymbolInfo* a, const SymbolInfo* b) diff --git a/src/apps/debugger/debug_info/DebuggerImageDebugInfo.h b/src/apps/debugger/debug_info/DebuggerImageDebugInfo.h index 9950d2592e..918d062753 100644 --- a/src/apps/debugger/debug_info/DebuggerImageDebugInfo.h +++ b/src/apps/debugger/debug_info/DebuggerImageDebugInfo.h @@ -36,6 +36,10 @@ public: virtual status_t GetStatement(FunctionDebugInfo* function, target_addr_t address, Statement*& _statement); + virtual status_t GetStatementForSourceLocation( + FunctionDebugInfo* function, + const SourceLocation& sourceLocation, + Statement*& _statement); private: static int _CompareSymbols(const SymbolInfo* a, diff --git a/src/apps/debugger/debug_info/DwarfFunctionDebugInfo.cpp b/src/apps/debugger/debug_info/DwarfFunctionDebugInfo.cpp index e64295a883..93bd2fdab5 100644 --- a/src/apps/debugger/debug_info/DwarfFunctionDebugInfo.cpp +++ b/src/apps/debugger/debug_info/DwarfFunctionDebugInfo.cpp @@ -63,17 +63,17 @@ DwarfFunctionDebugInfo::Size() const } -const char* +const BString& DwarfFunctionDebugInfo::Name() const { - return fName.String(); + return fName; } -const char* +const BString& DwarfFunctionDebugInfo::PrettyName() const { - return fName.String(); + return fName; } diff --git a/src/apps/debugger/debug_info/DwarfFunctionDebugInfo.h b/src/apps/debugger/debug_info/DwarfFunctionDebugInfo.h index 7190f9074d..84340170ad 100644 --- a/src/apps/debugger/debug_info/DwarfFunctionDebugInfo.h +++ b/src/apps/debugger/debug_info/DwarfFunctionDebugInfo.h @@ -32,8 +32,8 @@ public: virtual SpecificImageDebugInfo* GetSpecificImageDebugInfo() const; virtual target_addr_t Address() const; virtual target_size_t Size() const; - virtual const char* Name() const; - virtual const char* PrettyName() const; + virtual const BString& Name() const; + virtual const BString& PrettyName() const; virtual LocatableFile* SourceFile() const; virtual SourceLocation SourceStartLocation() const; diff --git a/src/apps/debugger/debug_info/DwarfImageDebugInfo.cpp b/src/apps/debugger/debug_info/DwarfImageDebugInfo.cpp index 2105dca8f1..0ae085d774 100644 --- a/src/apps/debugger/debug_info/DwarfImageDebugInfo.cpp +++ b/src/apps/debugger/debug_info/DwarfImageDebugInfo.cpp @@ -320,11 +320,179 @@ DwarfImageDebugInfo::LoadSourceCode(FunctionDebugInfo* function, status_t -DwarfImageDebugInfo::GetStatement(FunctionDebugInfo* function, +DwarfImageDebugInfo::GetStatement(FunctionDebugInfo* _function, target_addr_t address, Statement*& _statement) { - // TODO:... - return fArchitecture->GetStatement(function, address, _statement); + DwarfFunctionDebugInfo* function + = dynamic_cast(_function); + if (function == NULL) + return B_BAD_VALUE; + + AutoLocker locker(fLock); + + // get the source file + LocatableFile* file = function->SourceFile(); + if (file == NULL) + return B_ENTRY_NOT_FOUND; + + // maybe the source code is already loaded -- this will simplify things + CompilationUnit* unit = function->GetCompilationUnit(); +// FileSourceCode* sourceCode = _LookupSourceCode(unit, file); +// if (sourceCode) { +// Statement* statement = sourceCode->StatementAtAddress(address); +// if (statement == NULL) +// return B_ENTRY_NOT_FOUND; +// +// statement->AcquireReference(); +// _statement = statement; +// return B_OK; +// } + + // get the index of the source file in the compilation unit for cheaper + // comparison below + int32 fileIndex = _GetSourceFileIndex(unit, file); + + // Get the statement by executing the line number program for the + // compilation unit. + LineNumberProgram& program = unit->GetLineNumberProgram(); + if (!program.IsValid()) + return B_BAD_DATA; + + LineNumberProgram::State state; + program.GetInitialState(state); + + target_addr_t statementAddress = 0; + int32 statementLine = -1; + int32 statementColumn = -1; + while (program.GetNextRow(state)) { + bool isOurFile = state.file == fileIndex; + + if (statementAddress != 0 + && (!isOurFile || state.isStatement || state.isSequenceEnd)) { + target_addr_t endAddress = state.address; + if (address >= statementAddress && address < endAddress) { + ContiguousStatement* statement = new(std::nothrow) + ContiguousStatement( + SourceLocation(statementLine, statementColumn), + TargetAddressRange(fRelocationDelta + statementAddress, + endAddress - statementAddress)); + if (statement == NULL) + return B_NO_MEMORY; + + _statement = statement; + return B_OK; + } + + statementAddress = 0; + } + + // skip statements of other files + if (!isOurFile) + continue; + + if (state.isStatement) { + statementAddress = state.address; + statementLine = state.line - 1; + statementColumn = state.column - 1; + } + } + + return B_ENTRY_NOT_FOUND; +} + + +status_t +DwarfImageDebugInfo::GetStatementForSourceLocation(FunctionDebugInfo* _function, + const SourceLocation& sourceLocation, Statement*& _statement) +{ + DwarfFunctionDebugInfo* function + = dynamic_cast(_function); + if (function == NULL) + return B_BAD_VALUE; +target_addr_t functionStartAddress = function->Address(); +target_addr_t functionEndAddress = functionStartAddress + function->Size(); +printf("DwarfImageDebugInfo::GetStatementForSourceLocation(%p): function range: %#llx - %#llx\n", +function, functionStartAddress, functionEndAddress); + + AutoLocker locker(fLock); + + // get the source file + LocatableFile* file = function->SourceFile(); + if (file == NULL) + return B_ENTRY_NOT_FOUND; + + // maybe the source code is already loaded -- this will simplify things + CompilationUnit* unit = function->GetCompilationUnit(); + FileSourceCode* sourceCode = _LookupSourceCode(unit, file); + if (sourceCode) { +// TODO: This is not precise enough -- columns are ignored! + Statement* statement = sourceCode->StatementAtLine( + sourceLocation.Line()); + if (statement == NULL) + return B_ENTRY_NOT_FOUND; + + statement->AcquireReference(); + _statement = statement; + return B_OK; + } + + // get the index of the source file in the compilation unit for cheaper + // comparison below + int32 fileIndex = _GetSourceFileIndex(unit, file); + +// target_addr_t functionStartAddress = function->Address(); +// target_addr_t functionEndAddress = functionStartAddress + function->Size(); + + // Get the statement by executing the line number program for the + // compilation unit. + LineNumberProgram& program = unit->GetLineNumberProgram(); + if (!program.IsValid()) + return B_BAD_DATA; + + LineNumberProgram::State state; + program.GetInitialState(state); + + target_addr_t statementAddress = 0; + int32 statementLine = -1; + int32 statementColumn = -1; + while (program.GetNextRow(state)) { + bool isOurFile = state.file == fileIndex; + + if (statementAddress != 0 + && (!isOurFile || state.isStatement || state.isSequenceEnd)) { + target_addr_t endAddress = state.address; + if (statementAddress < endAddress + && statementAddress >= functionStartAddress + && statementAddress < functionEndAddress + && statementLine == (int32)sourceLocation.Line() + && statementColumn == (int32)sourceLocation.Column()) { + ContiguousStatement* statement = new(std::nothrow) + ContiguousStatement( + SourceLocation(statementLine, statementColumn), + TargetAddressRange(fRelocationDelta + statementAddress, + endAddress - statementAddress)); + if (statement == NULL) + return B_NO_MEMORY; + + _statement = statement; + return B_OK; + } + + statementAddress = 0; + } + + // skip statements of other files + if (!isOurFile) + continue; + + if (state.isStatement) { + statementAddress = state.address; + statementLine = state.line - 1; + statementColumn = state.column - 1; + } + } + + return B_ENTRY_NOT_FOUND; } @@ -353,26 +521,13 @@ DwarfImageDebugInfo::_LoadSourceCode(FunctionDebugInfo* _function, // get the index of the source file in the compilation unit for cheaper // comparison below - const char* directory; - int32 fileIndex = -1; - for (int32 i = 0; const char* fileName = unit->FileAt(i, &directory); i++) { - LocatableFile* file = fFileManager->GetSourceFile(directory, fileName); - if (file != NULL) { - file->ReleaseReference(); - if (file == function->SourceFile()) { - fileIndex = i + 1; - // indices are one-based - break; - } - } - } + int32 fileIndex = _GetSourceFileIndex(unit, function->SourceFile()); printf("DwarfImageDebugInfo::_LoadSourceCode(), file: %ld, function at: %#llx\n", fileIndex, function->Address()); -for (int32 i = 0; const char* fileName = unit->FileAt(i, &directory); i++) { +for (int32 i = 0; const char* fileName = unit->FileAt(i, NULL); i++) { printf(" file %ld: %s\n", i, fileName); } - // not loaded yet -- get the source file SourceFile* sourceFile; status_t error = fFileManager->LoadSourceFile(file, sourceFile); @@ -413,10 +568,9 @@ printf(" %#lx (%ld, %ld, %ld) %d\n", state.address, state.file, state.line, s // add the statement ContiguousStatement* statement = new(std::nothrow) ContiguousStatement( - SourceLocation(statementLine, statementColumn), SourceLocation(statementLine, statementColumn), TargetAddressRange(fRelocationDelta + statementAddress, - endAddress - statementAddress), true); + endAddress - statementAddress)); if (statement == NULL) return B_NO_MEMORY; @@ -463,3 +617,25 @@ DwarfImageDebugInfo::_LookupSourceCode(CompilationUnit* unit, SourceCodeEntry* entry = fSourceCodes->Lookup(SourceCodeKey(unit, file)); return entry != NULL ? entry->sourceCode : NULL; } + + +int32 +DwarfImageDebugInfo::_GetSourceFileIndex(CompilationUnit* unit, + LocatableFile* sourceFile) const +{ + // get the index of the source file in the compilation unit for cheaper + // comparison below + const char* directory; + for (int32 i = 0; const char* fileName = unit->FileAt(i, &directory); i++) { + LocatableFile* file = fFileManager->GetSourceFile(directory, fileName); + if (file != NULL) { + file->ReleaseReference(); + if (file == sourceFile) { + return i + 1; + // indices are one-based + } + } + } + + return -1; +} diff --git a/src/apps/debugger/debug_info/DwarfImageDebugInfo.h b/src/apps/debugger/debug_info/DwarfImageDebugInfo.h index 0bdacbcccb..a822d83cc1 100644 --- a/src/apps/debugger/debug_info/DwarfImageDebugInfo.h +++ b/src/apps/debugger/debug_info/DwarfImageDebugInfo.h @@ -47,6 +47,10 @@ public: virtual status_t GetStatement(FunctionDebugInfo* function, target_addr_t address, Statement*& _statement); + virtual status_t GetStatementForSourceLocation( + FunctionDebugInfo* function, + const SourceLocation& sourceLocation, + Statement*& _statement); private: struct SourceCodeKey; @@ -60,6 +64,8 @@ private: SourceCode*& _sourceCode); FileSourceCode* _LookupSourceCode(CompilationUnit* unit, LocatableFile* file); + int32 _GetSourceFileIndex(CompilationUnit* unit, + LocatableFile* sourceFile) const; private: BLocker fLock; diff --git a/src/apps/debugger/debug_info/Function.cpp b/src/apps/debugger/debug_info/Function.cpp new file mode 100644 index 0000000000..f99350f861 --- /dev/null +++ b/src/apps/debugger/debug_info/Function.cpp @@ -0,0 +1,90 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + +#include "Function.h" + +#include "SourceCode.h" + + +Function::Function() + : + fSourceCode(NULL), + fSourceCodeState(FUNCTION_SOURCE_NOT_LOADED) +{ +} + + +Function::~Function() +{ + SetSourceCode(NULL, FUNCTION_SOURCE_NOT_LOADED); +} + + +void +Function::SetSourceCode(SourceCode* source, function_source_state state) +{ + if (source == fSourceCode && state == fSourceCodeState) + return; + + if (fSourceCode != NULL) + fSourceCode->RemoveReference(); + + fSourceCode = source; + fSourceCodeState = state; + + if (fSourceCode != NULL) + fSourceCode->AddReference(); + + // notify listeners + for (ListenerList::Iterator it = fListeners.GetIterator(); + Listener* listener = it.Next();) { + listener->FunctionSourceCodeChanged(this); + } +} + + +void +Function::AddListener(Listener* listener) +{ + fListeners.Add(listener); +} + + +void +Function::RemoveListener(Listener* listener) +{ + fListeners.Remove(listener); +} + + +#include +void +Function::AddInstance(FunctionInstance* instance) +{ +printf(" %p: added %p\n", this, instance); + fInstances.Add(instance); +} + + +void +Function::RemoveInstance(FunctionInstance* instance) +{ +printf(" %p: removed %p\n", this, instance); + fInstances.Remove(instance); +} + + +// #pragma mark - Listener + + +Function::Listener::~Listener() +{ +} + + +void +Function::Listener::FunctionSourceCodeChanged(Function* function) +{ +} diff --git a/src/apps/debugger/debug_info/Function.h b/src/apps/debugger/debug_info/Function.h new file mode 100644 index 0000000000..339d830c65 --- /dev/null +++ b/src/apps/debugger/debug_info/Function.h @@ -0,0 +1,85 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef FUNCTION_H +#define FUNCTION_H + +#include +#include + +#include "FunctionInstance.h" + + +enum function_source_state { + FUNCTION_SOURCE_NOT_LOADED, + FUNCTION_SOURCE_LOADING, + FUNCTION_SOURCE_LOADED, + FUNCTION_SOURCE_UNAVAILABLE +}; + + +class SourceCode; + + +class Function : public Referenceable, public HashTableLink { +public: + class Listener; + +public: + Function(); + ~Function(); + + // team must be locked ot access the instances + FunctionInstance* FirstInstance() const + { return fInstances.Head(); } + FunctionInstance* LastInstance() const + { return fInstances.Tail(); } + const FunctionInstanceList& Instances() const + { return fInstances; } + + const BString& Name() const + { return FirstInstance()->Name(); } + const BString& PrettyName() const + { return FirstInstance()->PrettyName(); } + LocatableFile* SourceFile() const + { return FirstInstance()->SourceFile(); } + SourceLocation GetSourceLocation() const + { return FirstInstance() + ->GetSourceLocation(); } + + // mutable attributes follow (locking required) + SourceCode* GetSourceCode() const { return fSourceCode; } + function_source_state SourceCodeState() const + { return fSourceCodeState; } + void SetSourceCode(SourceCode* source, + function_source_state state); + + void AddListener(Listener* listener); + void RemoveListener(Listener* listener); + + // package private + void AddInstance(FunctionInstance* instance); + void RemoveInstance(FunctionInstance* instance); + +private: + typedef DoublyLinkedList ListenerList; + +private: + FunctionInstanceList fInstances; + SourceCode* fSourceCode; + function_source_state fSourceCodeState; + ListenerList fListeners; +}; + + +class Function::Listener : public DoublyLinkedListLinkImpl { +public: + virtual ~Listener(); + + virtual void FunctionSourceCodeChanged(Function* function); + // called with lock held +}; + + +#endif // FUNCTION_H diff --git a/src/apps/debugger/debug_info/FunctionDebugInfo.cpp b/src/apps/debugger/debug_info/FunctionDebugInfo.cpp index c15f984ef0..ee50fb6b68 100644 --- a/src/apps/debugger/debug_info/FunctionDebugInfo.cpp +++ b/src/apps/debugger/debug_info/FunctionDebugInfo.cpp @@ -5,71 +5,12 @@ #include "FunctionDebugInfo.h" -#include "SourceCode.h" - FunctionDebugInfo::FunctionDebugInfo() - : - fSourceCode(NULL), - fSourceCodeState(FUNCTION_SOURCE_NOT_LOADED) { } FunctionDebugInfo::~FunctionDebugInfo() -{ - SetSourceCode(NULL, FUNCTION_SOURCE_NOT_LOADED); -} - - -void -FunctionDebugInfo::SetSourceCode(SourceCode* source, - function_source_state state) -{ - if (source == fSourceCode && state == fSourceCodeState) - return; - - if (fSourceCode != NULL) - fSourceCode->RemoveReference(); - - fSourceCode = source; - fSourceCodeState = state; - - if (fSourceCode != NULL) - fSourceCode->AddReference(); - - // notify listeners - for (ListenerList::Iterator it = fListeners.GetIterator(); - Listener* listener = it.Next();) { - listener->FunctionSourceCodeChanged(this); - } -} - - -void -FunctionDebugInfo::AddListener(Listener* listener) -{ - fListeners.Add(listener); -} - - -void -FunctionDebugInfo::RemoveListener(Listener* listener) -{ - fListeners.Remove(listener); -} - - -// #pragma mark - Listener - - -FunctionDebugInfo::Listener::~Listener() -{ -} - - -void -FunctionDebugInfo::Listener::FunctionSourceCodeChanged( - FunctionDebugInfo* function) { } diff --git a/src/apps/debugger/debug_info/FunctionDebugInfo.h b/src/apps/debugger/debug_info/FunctionDebugInfo.h index 242b45f1aa..a30f51fcec 100644 --- a/src/apps/debugger/debug_info/FunctionDebugInfo.h +++ b/src/apps/debugger/debug_info/FunctionDebugInfo.h @@ -6,29 +6,17 @@ #define FUNCTION_DEBUG_INFO_H #include -#include #include "SourceLocation.h" #include "Types.h" -enum function_source_state { - FUNCTION_SOURCE_NOT_LOADED, - FUNCTION_SOURCE_LOADING, - FUNCTION_SOURCE_LOADED, - FUNCTION_SOURCE_UNAVAILABLE -}; - - +class BString; class LocatableFile; -class SourceCode; class SpecificImageDebugInfo; class FunctionDebugInfo : public Referenceable { -public: - class Listener; - public: FunctionDebugInfo(); virtual ~FunctionDebugInfo(); @@ -36,41 +24,12 @@ public: virtual SpecificImageDebugInfo* GetSpecificImageDebugInfo() const = 0; virtual target_addr_t Address() const = 0; virtual target_size_t Size() const = 0; - virtual const char* Name() const = 0; - virtual const char* PrettyName() const = 0; + virtual const BString& Name() const = 0; + virtual const BString& PrettyName() const = 0; virtual LocatableFile* SourceFile() const = 0; virtual SourceLocation SourceStartLocation() const = 0; virtual SourceLocation SourceEndLocation() const = 0; - - // mutable attributes follow (locking required) - SourceCode* GetSourceCode() const { return fSourceCode; } - function_source_state SourceCodeState() const - { return fSourceCodeState; } - void SetSourceCode(SourceCode* source, - function_source_state state); - - void AddListener(Listener* listener); - void RemoveListener(Listener* listener); - -private: - typedef DoublyLinkedList ListenerList; - -private: - // mutable - SourceCode* fSourceCode; - function_source_state fSourceCodeState; - ListenerList fListeners; -}; - - -class FunctionDebugInfo::Listener : public DoublyLinkedListLinkImpl { -public: - virtual ~Listener(); - - virtual void FunctionSourceCodeChanged( - FunctionDebugInfo* function); - // called with lock held }; diff --git a/src/apps/debugger/debug_info/FunctionInstance.cpp b/src/apps/debugger/debug_info/FunctionInstance.cpp new file mode 100644 index 0000000000..b5f53f8ca4 --- /dev/null +++ b/src/apps/debugger/debug_info/FunctionInstance.cpp @@ -0,0 +1,41 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + +#include "FunctionInstance.h" + +#include "Function.h" + + +FunctionInstance::FunctionInstance(ImageDebugInfo* imageDebugInfo, + FunctionDebugInfo* functionDebugInfo) + : + fImageDebugInfo(imageDebugInfo), + fFunction(NULL), + fFunctionDebugInfo(functionDebugInfo) +{ + fFunctionDebugInfo->AcquireReference(); + // TODO: What about fImageDebugInfo? We must be careful regarding cyclic + // references. +} + + +FunctionInstance::~FunctionInstance() +{ + SetFunction(NULL); + fFunctionDebugInfo->ReleaseReference(); +} + + +void +FunctionInstance::SetFunction(Function* function) +{ + if (fFunction != NULL) + fFunction->ReleaseReference(); + + fFunction = function; + + if (fFunction != NULL) + fFunction->AcquireReference(); +} diff --git a/src/apps/debugger/debug_info/FunctionInstance.h b/src/apps/debugger/debug_info/FunctionInstance.h new file mode 100644 index 0000000000..5f9ba669f2 --- /dev/null +++ b/src/apps/debugger/debug_info/FunctionInstance.h @@ -0,0 +1,58 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef FUNCTION_INSTANCE_H +#define FUNCTION_INSTANCE_H + +#include + +#include "FunctionDebugInfo.h" + + +class Function; +class FunctionDebugInfo; +class ImageDebugInfo; + + +class FunctionInstance : public Referenceable, + public DoublyLinkedListLinkImpl { +public: + FunctionInstance(ImageDebugInfo* imageDebugInfo, + FunctionDebugInfo* functionDebugInfo); + ~FunctionInstance(); + + ImageDebugInfo* GetImageDebugInfo() const + { return fImageDebugInfo; } + Function* GetFunction() const + { return fFunction; } + FunctionDebugInfo* GetFunctionDebugInfo() const + { return fFunctionDebugInfo; } + + target_addr_t Address() const + { return fFunctionDebugInfo->Address(); } + target_size_t Size() const + { return fFunctionDebugInfo->Size(); } + const BString& Name() const + { return fFunctionDebugInfo->Name(); } + const BString& PrettyName() const + { return fFunctionDebugInfo->PrettyName(); } + LocatableFile* SourceFile() const + { return fFunctionDebugInfo->SourceFile(); } + SourceLocation GetSourceLocation() const + { return fFunctionDebugInfo + ->SourceStartLocation(); } + + void SetFunction(Function* function); + // package private +private: + ImageDebugInfo* fImageDebugInfo; + Function* fFunction; + FunctionDebugInfo* fFunctionDebugInfo; +}; + + +typedef DoublyLinkedList FunctionInstanceList; + + +#endif // FUNCTION_INSTANCE_H diff --git a/src/apps/debugger/debug_info/ImageDebugInfo.cpp b/src/apps/debugger/debug_info/ImageDebugInfo.cpp index 27050c0fce..81b8fe3e6e 100644 --- a/src/apps/debugger/debug_info/ImageDebugInfo.cpp +++ b/src/apps/debugger/debug_info/ImageDebugInfo.cpp @@ -8,6 +8,7 @@ #include #include "FunctionDebugInfo.h" +#include "FunctionInstance.h" #include "SpecificImageDebugInfo.h" @@ -20,8 +21,8 @@ ImageDebugInfo::ImageDebugInfo(const ImageInfo& imageInfo) ImageDebugInfo::~ImageDebugInfo() { - for (int32 i = 0; FunctionDebugInfo* function = fFunctions.ItemAt(i); i++) - function->RemoveReference(); + for (int32 i = 0; FunctionInstance* function = fFunctions.ItemAt(i); i++) + function->ReleaseReference(); } @@ -39,23 +40,35 @@ ImageDebugInfo::FinishInit() // missing functions from less expressive debug infos for (int32 i = 0; SpecificImageDebugInfo* specificInfo = fSpecificInfos.ItemAt(i); i++) { - FunctionList functions; + BObjectList functions; status_t error = specificInfo->GetFunctions(functions); if (error != B_OK) return error; for (int32 k = 0; FunctionDebugInfo* function = functions.ItemAt(k); k++) { - if (FunctionAtAddress(function->Address()) == NULL) { - if (!fFunctions.BinaryInsert(function, &_CompareFunctions)) { - for (; (function = functions.ItemAt(k)); k++) { - function->RemoveReference(); - return B_NO_MEMORY; - } - } - } else - function->RemoveReference(); + if (FunctionAtAddress(function->Address()) != NULL) + continue; + + FunctionInstance* instance = new(std::nothrow) FunctionInstance( + this, function); + if (instance == NULL + || !fFunctions.BinaryInsert(instance, &_CompareFunctions)) { + delete instance; + error = B_NO_MEMORY; + break; + } } + + // Remove references returned by the specific debug info -- the + // FunctionInstance objects have references, now. + for (int32 k = 0; FunctionDebugInfo* function = functions.ItemAt(k); + k++) { + function->RemoveReference(); + } + + if (error != B_OK) + return error; } return B_OK; @@ -69,14 +82,14 @@ ImageDebugInfo::CountFunctions() const } -FunctionDebugInfo* +FunctionInstance* ImageDebugInfo::FunctionAt(int32 index) const { return fFunctions.ItemAt(index); } -FunctionDebugInfo* +FunctionInstance* ImageDebugInfo::FunctionAtAddress(target_addr_t address) const { return fFunctions.BinarySearchByKey(address, &_CompareAddressFunction); @@ -84,8 +97,8 @@ ImageDebugInfo::FunctionAtAddress(target_addr_t address) const /*static*/ int -ImageDebugInfo::_CompareFunctions(const FunctionDebugInfo* a, - const FunctionDebugInfo* b) +ImageDebugInfo::_CompareFunctions(const FunctionInstance* a, + const FunctionInstance* b) { return a->Address() < b->Address() ? -1 : (a->Address() == b->Address() ? 0 : 1); @@ -94,7 +107,7 @@ ImageDebugInfo::_CompareFunctions(const FunctionDebugInfo* a, /*static*/ int ImageDebugInfo::_CompareAddressFunction(const target_addr_t* address, - const FunctionDebugInfo* function) + const FunctionInstance* function) { if (*address < function->Address()) return -1; diff --git a/src/apps/debugger/debug_info/ImageDebugInfo.h b/src/apps/debugger/debug_info/ImageDebugInfo.h index 593fee331e..2bc9f44c2f 100644 --- a/src/apps/debugger/debug_info/ImageDebugInfo.h +++ b/src/apps/debugger/debug_info/ImageDebugInfo.h @@ -17,6 +17,7 @@ class Architecture; class DebuggerInterface; class FunctionDebugInfo; +class FunctionInstance; class SpecificImageDebugInfo; @@ -29,19 +30,19 @@ public: status_t FinishInit(); int32 CountFunctions() const; - FunctionDebugInfo* FunctionAt(int32 index) const; - FunctionDebugInfo* FunctionAtAddress(target_addr_t address) const; + FunctionInstance* FunctionAt(int32 index) const; + FunctionInstance* FunctionAtAddress(target_addr_t address) const; private: typedef BObjectList SpecificInfoList; - typedef BObjectList FunctionList; + typedef BObjectList FunctionList; private: - static int _CompareFunctions(const FunctionDebugInfo* a, - const FunctionDebugInfo* b); + static int _CompareFunctions(const FunctionInstance* a, + const FunctionInstance* b); static int _CompareAddressFunction( const target_addr_t* address, - const FunctionDebugInfo* function); + const FunctionInstance* function); private: ImageInfo fImageInfo; diff --git a/src/apps/debugger/debug_info/SpecificImageDebugInfo.h b/src/apps/debugger/debug_info/SpecificImageDebugInfo.h index 85d4fd1588..2192377c83 100644 --- a/src/apps/debugger/debug_info/SpecificImageDebugInfo.h +++ b/src/apps/debugger/debug_info/SpecificImageDebugInfo.h @@ -17,6 +17,7 @@ class DebuggerInterface; class FunctionDebugInfo; class Image; class SourceCode; +class SourceLocation; class StackFrame; class Statement; @@ -45,6 +46,11 @@ public: target_addr_t address, Statement*& _statement) = 0; // returns reference + virtual status_t GetStatementForSourceLocation( + FunctionDebugInfo* function, + const SourceLocation& sourceLocation, + Statement*& _statement) = 0; + // returns reference }; diff --git a/src/apps/debugger/debug_info/TeamDebugInfo.cpp b/src/apps/debugger/debug_info/TeamDebugInfo.cpp index 6f1036f6bb..eafd4e9045 100644 --- a/src/apps/debugger/debug_info/TeamDebugInfo.cpp +++ b/src/apps/debugger/debug_info/TeamDebugInfo.cpp @@ -11,8 +11,62 @@ #include "DebuggerTeamDebugInfo.h" #include "DwarfTeamDebugInfo.h" +#include "Function.h" #include "ImageDebugInfo.h" #include "SpecificImageDebugInfo.h" +#include "StringUtils.h" + + +// #pragma mark - FunctionHashDefinition + + +struct TeamDebugInfo::FunctionHashDefinition { + typedef const FunctionInstance* KeyType; + typedef Function ValueType; + + size_t HashKey(const FunctionInstance* key) const + { + // Instances without source file only equal themselves. + if (key->SourceFile() == NULL) + return (uint32)(addr_t)key; + + uint32 hash = StringUtils::HashValue(key->Name()); + hash = hash * 17 + (uint32)(addr_t)key->SourceFile(); + SourceLocation location = key->GetSourceLocation(); + hash = hash * 17 + location.Line(); + hash = hash * 17 + location.Column(); + + return hash; + } + + size_t Hash(const Function* value) const + { + return HashKey(value->FirstInstance()); + } + + bool Compare(const FunctionInstance* key, const Function* value) const + { + // source file must be the same + if (key->SourceFile() != value->SourceFile()) + return false; + + // Instances without source file only equal themselves. + if (key->SourceFile() == NULL) + return key == value->FirstInstance(); + + // Source location and function name must also match. + return key->GetSourceLocation() == value->GetSourceLocation() + && key->Name() == value->Name(); + } + + HashTableLink* GetLink(Function* value) const + { + return value; + } +}; + + +// #pragma mark - TeamDebugInfo TeamDebugInfo::TeamDebugInfo(DebuggerInterface* debuggerInterface, @@ -21,19 +75,39 @@ TeamDebugInfo::TeamDebugInfo(DebuggerInterface* debuggerInterface, fDebuggerInterface(debuggerInterface), fArchitecture(architecture), fFileManager(fileManager), - fSpecificInfos(10, true) + fSpecificInfos(10, true), + fFunctions(NULL) { } TeamDebugInfo::~TeamDebugInfo() { + if (fFunctions != NULL) { + Function* function = fFunctions->Clear(true); + while (function != NULL) { + Function* next = function->fNext; + function->ReleaseReference(); + function = next; + } + + delete fFunctions; + } } status_t TeamDebugInfo::Init() { + // create function hash table + fFunctions = new(std::nothrow) FunctionTable; + if (fFunctions == NULL) + return B_NO_MEMORY; + + status_t error = fFunctions->Init(); + if (error != B_OK) + return error; + // Create specific infos for all types of debug info we support, in // descending order of expressiveness. @@ -45,7 +119,7 @@ TeamDebugInfo::Init() return B_NO_MEMORY; } - status_t error = dwarfInfo->Init(); + error = dwarfInfo->Init(); if (error != B_OK) return error; @@ -98,3 +172,65 @@ TeamDebugInfo::LoadImageDebugInfo(const ImageInfo& imageInfo, _imageDebugInfo = imageDebugInfoDeleter.Detach(); return B_OK; } + + +#include +status_t +TeamDebugInfo::AddImageDebugInfo(ImageDebugInfo* imageDebugInfo) +{ +printf("TeamDebugInfo::AddImageDebugInfo(%p)\n", imageDebugInfo); + // Match all of the image debug info's functions instances with functions. + for (int32 i = 0; + FunctionInstance* instance = imageDebugInfo->FunctionAt(i); i++) { + // lookup the function or create it, if it doesn't exist yet + Function* function = fFunctions->Lookup(instance); + if (function != NULL) { +// TODO: Also update possible user breakpoints in this function! +printf(" adding instance %p to existing function %p\n", instance, function); + function->AddInstance(instance); + instance->SetFunction(function); + } else { + function = new(std::nothrow) Function; + if (function == NULL) { + RemoveImageDebugInfo(imageDebugInfo); + return B_NO_MEMORY; + } +printf(" adding instance %p to new function %p\n", instance, function); + function->AddInstance(instance); + instance->SetFunction(function); + fFunctions->Insert(function); + // Insert after adding the instance. Otherwise the function + // wouldn't be hashable/comparable. + } + } + + return B_OK; +} + + +void +TeamDebugInfo::RemoveImageDebugInfo(ImageDebugInfo* imageDebugInfo) +{ + // Remove the functions from all of the image debug info's functions + // instances. + for (int32 i = 0; + FunctionInstance* instance = imageDebugInfo->FunctionAt(i); i++) { + if (Function* function = instance->GetFunction()) { +// TODO: Also update possible user breakpoints in this function! + if (function->FirstInstance() == function->LastInstance()) { + // function unused -- remove it + // Note, that we have to remove it from the hash before removing + // the instance, since otherwise the function cannot be compared + // anymore. + fFunctions->Remove(function); + function->ReleaseReference(); + // The instance still has a reference. + } + + function->RemoveInstance(instance); + instance->SetFunction(NULL); + // If this was the last instance, it will remove the last + // reference to the function. + } + } +} diff --git a/src/apps/debugger/debug_info/TeamDebugInfo.h b/src/apps/debugger/debug_info/TeamDebugInfo.h index 6f713aa355..96fb5945ee 100644 --- a/src/apps/debugger/debug_info/TeamDebugInfo.h +++ b/src/apps/debugger/debug_info/TeamDebugInfo.h @@ -7,6 +7,7 @@ #include #include +#include #include "ImageInfo.h" @@ -14,6 +15,8 @@ class Architecture; class DebuggerInterface; class FileManager; +class Function; +class FunctionInstance; class ImageDebugInfo; class ImageInfo; class LocatableFile; @@ -34,14 +37,24 @@ public: LocatableFile* imageFile, ImageDebugInfo*& _imageDebugInfo); + // team is locked + status_t AddImageDebugInfo( + ImageDebugInfo* imageDebugInfo); + void RemoveImageDebugInfo( + ImageDebugInfo* imageDebugInfo); + private: + struct FunctionHashDefinition; + typedef BObjectList SpecificInfoList; + typedef OpenHashTable FunctionTable; private: DebuggerInterface* fDebuggerInterface; Architecture* fArchitecture; FileManager* fFileManager; SpecificInfoList fSpecificInfos; + FunctionTable* fFunctions; }; diff --git a/src/apps/debugger/gui/team_window/ImageFunctionsView.cpp b/src/apps/debugger/gui/team_window/ImageFunctionsView.cpp index 6cb0d9111b..196f78d4ad 100644 --- a/src/apps/debugger/gui/team_window/ImageFunctionsView.cpp +++ b/src/apps/debugger/gui/team_window/ImageFunctionsView.cpp @@ -14,7 +14,7 @@ #include "table/TableColumns.h" -#include "FunctionDebugInfo.h" +#include "FunctionInstance.h" #include "Image.h" #include "ImageDebugInfo.h" #include "LocatableFile.h" @@ -63,11 +63,11 @@ public: // create an array with the functions int32 functionCount = fImageDebugInfo->CountFunctions(); - FunctionDebugInfo** functions - = new(std::nothrow) FunctionDebugInfo*[functionCount]; + FunctionInstance** functions + = new(std::nothrow) FunctionInstance*[functionCount]; if (functions == NULL) return; - ArrayDeleter functionsDeleter(functions); + ArrayDeleter functionsDeleter(functions); for (int32 i = 0; i < functionCount; i++) functions[i] = fImageDebugInfo->FunctionAt(i); @@ -170,12 +170,12 @@ public: return true; } - FunctionDebugInfo* function = (FunctionDebugInfo*)object; + FunctionInstance* function = (FunctionInstance*)object; value.SetTo(function->PrettyName(), B_VARIANT_DONT_COPY_DATA); return true; } - bool GetFunctionPath(FunctionDebugInfo* function, TreeTablePath& _path) + bool GetFunctionPath(FunctionInstance* function, TreeTablePath& _path) { int32 index = -1; for (int32 i = 0; i < fFunctionCount; i++) { @@ -198,7 +198,7 @@ public: } bool GetObjectForPath(const TreeTablePath& path, - LocatableFile*& _sourceFile, FunctionDebugInfo*& _function) + LocatableFile*& _sourceFile, FunctionInstance*& _function) { int32 componentCount = path.CountComponents(); if (componentCount == 0 || componentCount > 2) @@ -256,8 +256,8 @@ private: return pathA.Compare(pathB); } - static bool _FunctionLess(const FunctionDebugInfo* a, - const FunctionDebugInfo* b) + static bool _FunctionLess(const FunctionInstance* a, + const FunctionInstance* b) { // compare source file name first int compared = _CompareSourceFileNames(a->SourceFile(), @@ -271,7 +271,7 @@ private: private: ImageDebugInfo* fImageDebugInfo; - FunctionDebugInfo** fFunctions; + FunctionInstance** fFunctions; int32 fFunctionCount; int32* fSourceFileIndices; int32 fSourceFileCount; @@ -357,7 +357,7 @@ printf("ImageFunctionsView::SetImageDebugInfo(%p) done\n", imageDebugInfo); void -ImageFunctionsView::SetFunction(FunctionDebugInfo* function) +ImageFunctionsView::SetFunction(FunctionInstance* function) { printf("ImageFunctionsView::SetFunction(%p)\n", function); TreeTablePath path; @@ -377,7 +377,7 @@ ImageFunctionsView::TreeTableSelectionChanged(TreeTable* table) return; LocatableFile* sourceFile = NULL; - FunctionDebugInfo* function = NULL; + FunctionInstance* function = NULL; TreeTablePath path; if (table->SelectionModel()->GetPathAt(0, path)) fFunctionsTableModel->GetObjectForPath(path, sourceFile, function); diff --git a/src/apps/debugger/gui/team_window/ImageFunctionsView.h b/src/apps/debugger/gui/team_window/ImageFunctionsView.h index c9ff01cda4..cf64b38642 100644 --- a/src/apps/debugger/gui/team_window/ImageFunctionsView.h +++ b/src/apps/debugger/gui/team_window/ImageFunctionsView.h @@ -11,7 +11,7 @@ #include "Team.h" -class FunctionDebugInfo; +class FunctionInstance; class ImageFunctionsView : public BGroupView, private TreeTableListener { @@ -29,7 +29,7 @@ public: void SetImageDebugInfo( ImageDebugInfo* imageDebugInfo); - void SetFunction(FunctionDebugInfo* function); + void SetFunction(FunctionInstance* function); private: class FunctionsTableModel; @@ -53,7 +53,7 @@ public: virtual ~Listener(); virtual void FunctionSelectionChanged( - FunctionDebugInfo* function) = 0; + FunctionInstance* function) = 0; }; diff --git a/src/apps/debugger/gui/team_window/SourceView.cpp b/src/apps/debugger/gui/team_window/SourceView.cpp index cee30f31af..12dfe354e4 100644 --- a/src/apps/debugger/gui/team_window/SourceView.cpp +++ b/src/apps/debugger/gui/team_window/SourceView.cpp @@ -20,6 +20,7 @@ #include #include "Breakpoint.h" +#include "Function.h" #include "SourceCode.h" #include "StackTrace.h" #include "Statement.h" @@ -519,8 +520,7 @@ SourceView::MarkerView::Draw(BRect updateRect) Statement* statement = fSourceCode->StatementAtLine(line); if (statement == NULL - || statement->StartSourceLocation().Line() != (uint32)line - || !statement->BreakpointAllowed()) { + || statement->StartSourceLocation().Line() != (uint32)line) { continue; } @@ -543,8 +543,7 @@ SourceView::MarkerView::MouseDown(BPoint where) Statement* statement = fSourceCode->StatementAtLine(line); if (statement == NULL - || statement->StartSourceLocation().Line() != (uint32)line - || !statement->BreakpointAllowed()) { + || statement->StartSourceLocation().Line() != (uint32)line) { return; } @@ -595,15 +594,24 @@ SourceView::MarkerView::_UpdateIPMarkers() fIPMarkers.MakeEmpty(); if (fSourceCode != NULL && fStackTrace != NULL) { + AutoLocker locker(fDebugModel); + for (int32 i = 0; StackFrame* frame = fStackTrace->FrameAt(i); i++) { target_addr_t ip = frame->InstructionPointer(); - Statement* statement = fSourceCode->StatementAtAddress(ip); - if (statement == NULL) + FunctionInstance* functionInstance; + Statement* statement; + if (fDebugModel->GetTeam()->GetStatementAtAddress(ip, + functionInstance, statement) != B_OK) { continue; + } + Reference statementReference(statement, true); + uint32 line = statement->StartSourceLocation().Line(); - if (line >= (uint32)LineCount()) + if (functionInstance->GetFunction()->GetSourceCode() != fSourceCode + || line < 0 || line >= (uint32)LineCount()) { continue; + } bool isTopFrame = i == 0 && frame->Type() != STACK_FRAME_TYPE_SYSCALL; @@ -638,25 +646,30 @@ SourceView::MarkerView::_UpdateBreakpointMarkers() AutoLocker locker(fDebugModel); // get the breakpoints in our source code range - BObjectList breakpoints; - fDebugModel->GetBreakpointsInAddressRange( - fSourceCode->StatementAddressRange(), breakpoints); + BObjectList breakpoints; + fDebugModel->GetBreakpointsForSourceCode(fSourceCode, breakpoints); - for (int32 i = 0; Breakpoint* breakpoint = breakpoints.ItemAt(i); i++) { - if (breakpoint->UserState() == USER_BREAKPOINT_NONE) + for (int32 i = 0; UserBreakpoint* breakpoint = breakpoints.ItemAt(i); + i++) { + UserBreakpointInstance* breakpointInstance + = breakpoint->InstanceAt(0); + FunctionInstance* functionInstance; + Statement* statement; + if (fDebugModel->GetTeam()->GetStatementAtAddress( + breakpointInstance->Address(), functionInstance, + statement) != B_OK) { continue; + } + Reference statementReference(statement, true); - Statement* statement = fSourceCode->StatementAtAddress( - breakpoint->Address()); - if (statement == NULL) - continue; uint32 line = statement->StartSourceLocation().Line(); - if (line >= (uint32)LineCount()) + if (functionInstance->GetFunction()->GetSourceCode() != fSourceCode + || line < 0 || line >= (uint32)LineCount()) { continue; + } BreakpointMarker* marker = new(std::nothrow) BreakpointMarker( - line, breakpoint->Address(), - breakpoint->UserState() == USER_BREAKPOINT_ENABLED); + line, breakpointInstance->Address(), breakpoint->IsEnabled()); if (marker == NULL || !fBreakpointMarkers.AddItem(marker)) { delete marker; break; @@ -995,9 +1008,15 @@ SourceView::ScrollToAddress(target_addr_t address) if (fSourceCode == NULL) return false; - Statement* statement = fSourceCode->StatementAtAddress(address); - if (statement == NULL) + AutoLocker locker(fDebugModel); + + FunctionInstance* functionInstance; + Statement* statement; + if (fDebugModel->GetTeam()->GetStatementAtAddress(address, functionInstance, + statement) != B_OK) { return false; + } + Reference statementReference(statement, true); return ScrollToLine(statement->StartSourceLocation().Line()); } @@ -1013,11 +1032,16 @@ SourceView::ScrollToLine(uint32 line) float bottom = top + fFontInfo.lineHeight - 1; BRect visible = _VisibleRect(); +printf("SourceView::ScrollToLine(%ld)\n", line); +printf(" visible: (%f, %f) - (%f, %f), line: %f - %f\n", visible.left, visible.top, visible.right, visible.bottom, top, bottom); // If not visible at all, scroll to the center, otherwise scroll so that at // least one more line is visible. if (top >= visible.bottom || bottom <= visible.top) +{ +printf(" -> scrolling to (%f, %f)\n", visible.left, top - (visible.Height() + 1) / 2); ScrollTo(visible.left, top - (visible.Height() + 1) / 2); +} else if (top - fFontInfo.lineHeight < visible.top) ScrollBy(0, top - fFontInfo.lineHeight - visible.top); else if (bottom + fFontInfo.lineHeight > visible.bottom) diff --git a/src/apps/debugger/gui/team_window/StackTraceView.cpp b/src/apps/debugger/gui/team_window/StackTraceView.cpp index dc1c660d62..5f716b1c70 100644 --- a/src/apps/debugger/gui/team_window/StackTraceView.cpp +++ b/src/apps/debugger/gui/team_window/StackTraceView.cpp @@ -11,7 +11,7 @@ #include "table/TableColumns.h" -#include "FunctionDebugInfo.h" +#include "FunctionInstance.h" #include "Image.h" #include "StackTrace.h" @@ -105,7 +105,7 @@ public: case 2: { Image* image = frame->GetImage(); - FunctionDebugInfo* function = frame->Function(); + FunctionInstance* function = frame->Function(); if (image == NULL && function == NULL) { value.SetTo("?", B_VARIANT_DONT_COPY_DATA); return true; diff --git a/src/apps/debugger/gui/team_window/TeamWindow.cpp b/src/apps/debugger/gui/team_window/TeamWindow.cpp index baa677461a..07f900a232 100644 --- a/src/apps/debugger/gui/team_window/TeamWindow.cpp +++ b/src/apps/debugger/gui/team_window/TeamWindow.cpp @@ -215,7 +215,7 @@ TeamWindow::StackFrameSelectionChanged(StackFrame* frame) void -TeamWindow::FunctionSelectionChanged(FunctionDebugInfo* function) +TeamWindow::FunctionSelectionChanged(FunctionInstance* function) { _SetActiveFunction(function); } @@ -281,7 +281,7 @@ TeamWindow::UserBreakpointChanged(const TeamDebugModel::BreakpointEvent& event) void -TeamWindow::FunctionSourceCodeChanged(FunctionDebugInfo* function) +TeamWindow::FunctionSourceCodeChanged(Function* function) { printf("TeamWindow::FunctionSourceCodeChanged(%p): source: %p, state: %d\n", function, function->GetSourceCode(), function->SourceCodeState()); @@ -469,15 +469,15 @@ TeamWindow::_SetActiveStackFrame(StackFrame* frame) void -TeamWindow::_SetActiveFunction(FunctionDebugInfo* function) +TeamWindow::_SetActiveFunction(FunctionInstance* functionInstance) { - if (function == fActiveFunction) + if (functionInstance == fActiveFunction) return; AutoLocker locker(fDebugModel); if (fActiveFunction != NULL) { - fActiveFunction->RemoveListener(this); + fActiveFunction->GetFunction()->RemoveListener(this); fActiveFunction->RemoveReference(); } @@ -487,12 +487,12 @@ TeamWindow::_SetActiveFunction(FunctionDebugInfo* function) fActiveFunction = NULL; - if (function != NULL) { + if (functionInstance != NULL) { _SetActiveImage(fDebugModel->GetTeam()->ImageByAddress( - function->Address())); + functionInstance->Address())); } - fActiveFunction = function; + fActiveFunction = functionInstance; locker.Lock(); @@ -501,13 +501,14 @@ TeamWindow::_SetActiveFunction(FunctionDebugInfo* function) if (fActiveFunction != NULL) { fActiveFunction->AddReference(); - fActiveFunction->AddListener(this); + fActiveFunction->GetFunction()->AddListener(this); - sourceCode = fActiveFunction->GetSourceCode(); + Function* function = fActiveFunction->GetFunction(); + sourceCode = function->GetSourceCode(); sourceCodeReference.SetTo(sourceCode); // If the source code is not loaded yet, request it. - if (fActiveFunction->SourceCodeState() == FUNCTION_SOURCE_NOT_LOADED) + if (function->SourceCodeState() == FUNCTION_SOURCE_NOT_LOADED) fListener->FunctionSourceCodeRequested(this, fActiveFunction); } @@ -522,8 +523,10 @@ TeamWindow::_SetActiveFunction(FunctionDebugInfo* function) void TeamWindow::_SetActiveSourceCode(SourceCode* sourceCode) { - if (sourceCode == fActiveSourceCode) + if (sourceCode == fActiveSourceCode) { + _ScrollToActiveFunction(); return; + } if (fActiveSourceCode != NULL) fActiveSourceCode->RemoveReference(); @@ -535,16 +538,9 @@ TeamWindow::_SetActiveSourceCode(SourceCode* sourceCode) fSourceView->SetSourceCode(fActiveSourceCode); - // Scroll to the active function, if it doesn't match the stack frame (i.e. - // has been selected manually). - if (fActiveFunction != NULL && fActiveSourceCode != NULL - && (fActiveStackFrame == NULL - || fActiveStackFrame->Function() != fActiveFunction)) { - fSourceView->ScrollToAddress(fActiveFunction->Address()); - } + _ScrollToActiveFunction(); } - void TeamWindow::_UpdateCpuState() { @@ -601,6 +597,19 @@ TeamWindow::_UpdateRunButtons() } +void +TeamWindow::_ScrollToActiveFunction() +{ + // Scroll to the active function, if it doesn't match the stack frame (i.e. + // has been selected manually). + if (fActiveFunction != NULL && fActiveSourceCode != NULL + && (fActiveStackFrame == NULL + || fActiveStackFrame->Function() != fActiveFunction)) { + fSourceView->ScrollToAddress(fActiveFunction->Address()); + } +} + + void TeamWindow::_HandleThreadStateChanged(thread_id threadID) { @@ -693,7 +702,7 @@ TeamWindow::_HandleSourceCodeChanged() // get a reference to the source code AutoLocker locker(fDebugModel); - SourceCode* sourceCode = fActiveFunction->GetSourceCode(); + SourceCode* sourceCode = fActiveFunction->GetFunction()->GetSourceCode(); Reference sourceCodeReference(sourceCode); locker.Unlock(); diff --git a/src/apps/debugger/gui/team_window/TeamWindow.h b/src/apps/debugger/gui/team_window/TeamWindow.h index ca3ecaa69c..0c5bddec49 100644 --- a/src/apps/debugger/gui/team_window/TeamWindow.h +++ b/src/apps/debugger/gui/team_window/TeamWindow.h @@ -9,7 +9,7 @@ #include #include "SourceView.h" -#include "FunctionDebugInfo.h" +#include "Function.h" #include "ImageFunctionsView.h" #include "ImageListView.h" #include "StackTraceView.h" @@ -20,7 +20,6 @@ class BButton; class BTabView; -class FunctionDebugInfo; class Image; class RegisterView; class SourceCode; @@ -30,7 +29,7 @@ class StackFrame; class TeamWindow : public BWindow, ThreadListView::Listener, ImageListView::Listener, StackTraceView::Listener, ImageFunctionsView::Listener, SourceView::Listener, Team::Listener, - TeamDebugModel::Listener, FunctionDebugInfo::Listener { + TeamDebugModel::Listener, Function::Listener { public: class Listener; @@ -58,7 +57,7 @@ private: // ImageFunctionsView::Listener virtual void FunctionSelectionChanged( - FunctionDebugInfo* function); + FunctionInstance* function); // SourceView::Listener virtual void SetBreakpointRequested(target_addr_t address, @@ -80,9 +79,8 @@ private: const TeamDebugModel::BreakpointEvent& event); - // FunctionDebugInfo::Listener - virtual void FunctionSourceCodeChanged( - FunctionDebugInfo* function); + // Function::Listener + virtual void FunctionSourceCodeChanged(Function* function); void _Init(); @@ -90,10 +88,11 @@ private: void _SetActiveImage(Image* image); void _SetActiveStackTrace(StackTrace* stackTrace); void _SetActiveStackFrame(StackFrame* frame); - void _SetActiveFunction(FunctionDebugInfo* function); + void _SetActiveFunction(FunctionInstance* function); void _SetActiveSourceCode(SourceCode* sourceCode); void _UpdateCpuState(); void _UpdateRunButtons(); + void _ScrollToActiveFunction(); void _HandleThreadStateChanged(thread_id threadID); void _HandleCpuStateChanged(thread_id threadID); @@ -109,7 +108,7 @@ private: Image* fActiveImage; StackTrace* fActiveStackTrace; StackFrame* fActiveStackFrame; - FunctionDebugInfo* fActiveFunction; + FunctionInstance* fActiveFunction; SourceCode* fActiveSourceCode; Listener* fListener; BTabView* fTabView; @@ -132,7 +131,7 @@ public: virtual ~Listener(); virtual void FunctionSourceCodeRequested(TeamWindow* window, - FunctionDebugInfo* function) = 0; + FunctionInstance* function) = 0; virtual void ImageDebugInfoRequested(TeamWindow* window, Image* image) = 0; virtual void ThreadActionRequested(TeamWindow* window, diff --git a/src/apps/debugger/model/Breakpoint.cpp b/src/apps/debugger/model/Breakpoint.cpp index 1b8ab65fee..c7c49cb17a 100644 --- a/src/apps/debugger/model/Breakpoint.cpp +++ b/src/apps/debugger/model/Breakpoint.cpp @@ -21,7 +21,6 @@ Breakpoint::Breakpoint(Image* image, target_addr_t address) : fAddress(address), fImage(image), - fUserState(USER_BREAKPOINT_NONE), fInstalled(false) { } @@ -32,13 +31,6 @@ Breakpoint::~Breakpoint() } -void -Breakpoint::SetUserState(user_breakpoint_state state) -{ - fUserState = state; -} - - void Breakpoint::SetInstalled(bool installed) { @@ -49,14 +41,45 @@ Breakpoint::SetInstalled(bool installed) bool Breakpoint::ShouldBeInstalled() const { - return fUserState == USER_BREAKPOINT_ENABLED || !fClients.IsEmpty(); + if (!fClients.IsEmpty()) + return true; + + return !fClients.IsEmpty() || HasEnabledUserBreakpoint(); } bool Breakpoint::IsUnused() const { - return fUserState == USER_BREAKPOINT_NONE && fClients.IsEmpty(); + return fClients.IsEmpty() && fUserBreakpoints.IsEmpty(); +} + + +bool +Breakpoint::HasEnabledUserBreakpoint() const +{ + for (UserBreakpointInstanceList::ConstIterator it + = fUserBreakpoints.GetIterator(); + UserBreakpointInstance* instance = it.Next();) { + if (instance->GetUserBreakpoint()->IsEnabled()) + return true; + } + + return false; +} + + +void +Breakpoint::AddUserBreakpoint(UserBreakpointInstance* instance) +{ + fUserBreakpoints.Add(instance); +} + + +void +Breakpoint::RemoveUserBreakpoint(UserBreakpointInstance* instance) +{ + fUserBreakpoints.Remove(instance); } diff --git a/src/apps/debugger/model/Breakpoint.h b/src/apps/debugger/model/Breakpoint.h index 6b25ad2e2b..06639fd79e 100644 --- a/src/apps/debugger/model/Breakpoint.h +++ b/src/apps/debugger/model/Breakpoint.h @@ -5,17 +5,7 @@ #ifndef BREAKPOINT_H #define BREAKPOINT_H -#include -#include - -#include "Types.h" - - -enum user_breakpoint_state { - USER_BREAKPOINT_NONE, - USER_BREAKPOINT_ENABLED, - USER_BREAKPOINT_DISABLED -}; +#include "UserBreakpoint.h" class Image; @@ -35,14 +25,22 @@ public: Image* GetImage() const { return fImage; } target_addr_t Address() const { return fAddress; } - user_breakpoint_state UserState() const { return fUserState; } - void SetUserState(user_breakpoint_state state); - bool IsInstalled() const { return fInstalled; } void SetInstalled(bool installed); bool ShouldBeInstalled() const; bool IsUnused() const; + bool HasEnabledUserBreakpoint() const; + + UserBreakpointInstance* FirstUserBreakpoint() const + { return fUserBreakpoints.Head(); } + UserBreakpointInstance* LastUserBreakpoint() const + { return fUserBreakpoints.Tail(); } + + void AddUserBreakpoint( + UserBreakpointInstance* instance); + void RemoveUserBreakpoint( + UserBreakpointInstance* instance); bool AddClient(BreakpointClient* client); void RemoveClient(BreakpointClient* client); @@ -59,8 +57,8 @@ private: private: target_addr_t fAddress; Image* fImage; + UserBreakpointInstanceList fUserBreakpoints; ClientList fClients; - user_breakpoint_state fUserState; bool fInstalled; }; diff --git a/src/apps/debugger/model/DisassembledCode.cpp b/src/apps/debugger/model/DisassembledCode.cpp index 353dd519fb..54e63642ee 100644 --- a/src/apps/debugger/model/DisassembledCode.cpp +++ b/src/apps/debugger/model/DisassembledCode.cpp @@ -57,20 +57,6 @@ DisassembledCode::LineAt(int32 index) const } -int32 -DisassembledCode::CountStatements() const -{ - return fStatements.CountItems(); -} - - -Statement* -DisassembledCode::StatementAt(int32 index) const -{ - return fStatements.ItemAt(index); -} - - Statement* DisassembledCode::StatementAtLine(int32 index) const { @@ -79,25 +65,25 @@ DisassembledCode::StatementAtLine(int32 index) const } -Statement* -DisassembledCode::StatementAtAddress(target_addr_t address) const -{ - return fStatements.BinarySearchByKey(address, &_CompareAddressStatement); -} +//Statement* +//DisassembledCode::StatementAtAddress(target_addr_t address) const +//{ +// return fStatements.BinarySearchByKey(address, &_CompareAddressStatement); +//} -TargetAddressRange -DisassembledCode::StatementAddressRange() const -{ - if (fStatements.IsEmpty()) - return TargetAddressRange(); - - ContiguousStatement* first = fStatements.ItemAt(0); - ContiguousStatement* last - = fStatements.ItemAt(fStatements.CountItems() - 1); - return TargetAddressRange(first->AddressRange().Start(), - last->AddressRange().End()); -} +//TargetAddressRange +//DisassembledCode::StatementAddressRange() const +//{ +// if (fStatements.IsEmpty()) +// return TargetAddressRange(); +// +// ContiguousStatement* first = fStatements.ItemAt(0); +// ContiguousStatement* last +// = fStatements.ItemAt(fStatements.CountItems() - 1); +// return TargetAddressRange(first->AddressRange().Start(), +// last->AddressRange().End()); +//} bool @@ -109,13 +95,12 @@ DisassembledCode::AddCommentLine(const BString& line) bool DisassembledCode::AddInstructionLine(const BString& line, target_addr_t address, - target_size_t size, bool breakpointAllowed) + target_size_t size) { int32 lineIndex = fLines.CountItems(); ContiguousStatement* statement = new(std::nothrow) ContiguousStatement( - SourceLocation(lineIndex), SourceLocation(lineIndex + 1), - TargetAddressRange(address, size), breakpointAllowed); + SourceLocation(lineIndex), TargetAddressRange(address, size)); if (statement == NULL) return false; diff --git a/src/apps/debugger/model/DisassembledCode.h b/src/apps/debugger/model/DisassembledCode.h index a27d011b48..8d61f82a46 100644 --- a/src/apps/debugger/model/DisassembledCode.h +++ b/src/apps/debugger/model/DisassembledCode.h @@ -22,18 +22,15 @@ public: virtual int32 CountLines() const; virtual const char* LineAt(int32 index) const; - virtual int32 CountStatements() const; - virtual Statement* StatementAt(int32 index) const; virtual Statement* StatementAtLine(int32 index) const; - virtual Statement* StatementAtAddress(target_addr_t address) const; +// Statement* StatementAtAddress(target_addr_t address) const; - virtual TargetAddressRange StatementAddressRange() const; +// TargetAddressRange StatementAddressRange() const; public: bool AddCommentLine(const BString& line); bool AddInstructionLine(const BString& line, - target_addr_t address, target_size_t size, - bool breakpointAllowed); + target_addr_t address, target_size_t size); // instructions must be added in // ascending address order diff --git a/src/apps/debugger/model/FileSourceCode.cpp b/src/apps/debugger/model/FileSourceCode.cpp index d4677bb28c..4f222e4bbd 100644 --- a/src/apps/debugger/model/FileSourceCode.cpp +++ b/src/apps/debugger/model/FileSourceCode.cpp @@ -78,20 +78,6 @@ FileSourceCode::LineAt(int32 index) const } -int32 -FileSourceCode::CountStatements() const -{ - return fStatements.CountItems(); -} - - -Statement* -FileSourceCode::StatementAt(int32 index) const -{ - return fStatements.ItemAt(index); -} - - Statement* FileSourceCode::StatementAtLine(int32 index) const { @@ -99,25 +85,25 @@ FileSourceCode::StatementAtLine(int32 index) const } -Statement* -FileSourceCode::StatementAtAddress(target_addr_t address) const -{ - return fStatements.BinarySearchByKey(address, &_CompareAddressStatement); -} +//Statement* +//FileSourceCode::StatementAtAddress(target_addr_t address) const +//{ +// return fStatements.BinarySearchByKey(address, &_CompareAddressStatement); +//} -TargetAddressRange -FileSourceCode::StatementAddressRange() const -{ - if (fStatements.IsEmpty()) - return TargetAddressRange(); - - ContiguousStatement* first = fStatements.ItemAt(0); - ContiguousStatement* last - = fStatements.ItemAt(fStatements.CountItems() - 1); - return TargetAddressRange(first->AddressRange().Start(), - last->AddressRange().End()); -} +//TargetAddressRange +//FileSourceCode::StatementAddressRange() const +//{ +// if (fStatements.IsEmpty()) +// return TargetAddressRange(); +// +// ContiguousStatement* first = fStatements.ItemAt(0); +// ContiguousStatement* last +// = fStatements.ItemAt(fStatements.CountItems() - 1); +// return TargetAddressRange(first->AddressRange().Start(), +// last->AddressRange().End()); +//} /*static*/ int diff --git a/src/apps/debugger/model/FileSourceCode.h b/src/apps/debugger/model/FileSourceCode.h index 04103f0291..52fb92cb51 100644 --- a/src/apps/debugger/model/FileSourceCode.h +++ b/src/apps/debugger/model/FileSourceCode.h @@ -25,12 +25,10 @@ public: virtual int32 CountLines() const; virtual const char* LineAt(int32 index) const; - virtual int32 CountStatements() const; - virtual Statement* StatementAt(int32 index) const; virtual Statement* StatementAtLine(int32 index) const; - virtual Statement* StatementAtAddress(target_addr_t address) const; +// Statement* StatementAtAddress(target_addr_t address) const; - virtual TargetAddressRange StatementAddressRange() const; +// virtual TargetAddressRange StatementAddressRange() const; private: typedef BObjectList StatementList; diff --git a/src/apps/debugger/model/Image.cpp b/src/apps/debugger/model/Image.cpp index 3a081fcee3..3590a9dc27 100644 --- a/src/apps/debugger/model/Image.cpp +++ b/src/apps/debugger/model/Image.cpp @@ -8,6 +8,7 @@ #include "ImageDebugInfo.h" #include "LocatableFile.h" #include "Team.h" +#include "TeamDebugInfo.h" Image::Image(Team* team,const ImageInfo& imageInfo, LocatableFile* imageFile) @@ -49,22 +50,34 @@ Image::ContainsAddress(target_addr_t address) const } -void +status_t Image::SetImageDebugInfo(ImageDebugInfo* debugInfo, image_debug_info_state state) { if (debugInfo == fDebugInfo && state == fDebugInfoState) - return; + return B_OK; - if (fDebugInfo != NULL) + if (fDebugInfo != NULL) { + fTeam->DebugInfo()->RemoveImageDebugInfo(fDebugInfo); fDebugInfo->RemoveReference(); + } fDebugInfo = debugInfo; fDebugInfoState = state; - if (fDebugInfo != NULL) - fDebugInfo->AddReference(); + status_t error = B_OK; + if (fDebugInfo != NULL) { + error = fTeam->DebugInfo()->AddImageDebugInfo(fDebugInfo); + if (error == B_OK) { + fDebugInfo->AddReference(); + } else { + fDebugInfo = NULL; + fDebugInfoState = IMAGE_DEBUG_INFO_UNAVAILABLE; + } + } // notify listeners fTeam->NotifyImageDebugInfoChanged(this); + + return error; } diff --git a/src/apps/debugger/model/Image.h b/src/apps/debugger/model/Image.h index 41abe18ce5..588557f221 100644 --- a/src/apps/debugger/model/Image.h +++ b/src/apps/debugger/model/Image.h @@ -34,7 +34,6 @@ public: status_t Init(); - Team* GetTeam() const { return fTeam; } image_id ID() const { return fInfo.ImageID(); } const char* Name() const { return fInfo.Name(); } @@ -48,7 +47,7 @@ public: ImageDebugInfo* GetImageDebugInfo() const { return fDebugInfo; } image_debug_info_state ImageDebugInfoState() const { return fDebugInfoState; } - void SetImageDebugInfo(ImageDebugInfo* debugInfo, + status_t SetImageDebugInfo(ImageDebugInfo* debugInfo, image_debug_info_state state); private: diff --git a/src/apps/debugger/model/SourceCode.h b/src/apps/debugger/model/SourceCode.h index f93ef9c9bb..a50efee4a1 100644 --- a/src/apps/debugger/model/SourceCode.h +++ b/src/apps/debugger/model/SourceCode.h @@ -20,13 +20,7 @@ public: virtual int32 CountLines() const = 0; virtual const char* LineAt(int32 index) const = 0; - virtual int32 CountStatements() const = 0; - virtual Statement* StatementAt(int32 index) const = 0; virtual Statement* StatementAtLine(int32 index) const = 0; - virtual Statement* StatementAtAddress(target_addr_t address) - const = 0; - - virtual TargetAddressRange StatementAddressRange() const = 0; }; diff --git a/src/apps/debugger/model/StackFrame.cpp b/src/apps/debugger/model/StackFrame.cpp index 427112adaf..24c1a1d475 100644 --- a/src/apps/debugger/model/StackFrame.cpp +++ b/src/apps/debugger/model/StackFrame.cpp @@ -6,7 +6,7 @@ #include "StackFrame.h" #include "CpuState.h" -#include "FunctionDebugInfo.h" +#include "FunctionInstance.h" #include "Image.h" @@ -57,7 +57,7 @@ StackFrame::SetImage(Image* image) void -StackFrame::SetFunction(FunctionDebugInfo* function) +StackFrame::SetFunction(FunctionInstance* function) { if (fFunction != NULL) fFunction->RemoveReference(); diff --git a/src/apps/debugger/model/StackFrame.h b/src/apps/debugger/model/StackFrame.h index 7b8bc80feb..6d43e12946 100644 --- a/src/apps/debugger/model/StackFrame.h +++ b/src/apps/debugger/model/StackFrame.h @@ -22,7 +22,7 @@ enum stack_frame_type { class CpuState; class Image; -class FunctionDebugInfo; +class FunctionInstance; class StackFrame : public Referenceable { @@ -46,8 +46,8 @@ public: Image* GetImage() const { return fImage; } void SetImage(Image* image); - FunctionDebugInfo* Function() const { return fFunction; } - void SetFunction(FunctionDebugInfo* function); + FunctionInstance* Function() const { return fFunction; } + void SetFunction(FunctionInstance* function); private: stack_frame_type fType; @@ -56,7 +56,7 @@ private: target_addr_t fInstructionPointer; target_addr_t fReturnAddress; Image* fImage; - FunctionDebugInfo* fFunction; + FunctionInstance* fFunction; }; diff --git a/src/apps/debugger/model/Statement.cpp b/src/apps/debugger/model/Statement.cpp index 41687aa10f..62dd7991d3 100644 --- a/src/apps/debugger/model/Statement.cpp +++ b/src/apps/debugger/model/Statement.cpp @@ -17,12 +17,9 @@ Statement::~Statement() // #pragma mark - AbstractStatement -AbstractStatement::AbstractStatement(const SourceLocation& start, - const SourceLocation& end, bool breakpointAllowed) +AbstractStatement::AbstractStatement(const SourceLocation& start) : - fStart(start), - fEnd(end), - fBreakpointAllowed(breakpointAllowed) + fStart(start) { } @@ -34,28 +31,13 @@ AbstractStatement::StartSourceLocation() const } -SourceLocation -AbstractStatement::EndSourceLocation() const -{ - return fEnd; -} - - -bool -AbstractStatement::BreakpointAllowed() const -{ - return fBreakpointAllowed; -} - - // #pragma mark - ContiguousStatement ContiguousStatement::ContiguousStatement(const SourceLocation& start, - const SourceLocation& end, const TargetAddressRange& range, - bool breakpointAllowed) + const TargetAddressRange& range) : - AbstractStatement(start, end, breakpointAllowed), + AbstractStatement(start), fRange(range) { } diff --git a/src/apps/debugger/model/Statement.h b/src/apps/debugger/model/Statement.h index 98e08d5f12..24d98e48ef 100644 --- a/src/apps/debugger/model/Statement.h +++ b/src/apps/debugger/model/Statement.h @@ -17,7 +17,6 @@ public: virtual ~Statement(); virtual SourceLocation StartSourceLocation() const = 0; - virtual SourceLocation EndSourceLocation() const = 0; virtual TargetAddressRange CoveringAddressRange() const = 0; @@ -26,35 +25,24 @@ public: virtual bool ContainsAddress(target_addr_t address) const = 0; - - virtual bool BreakpointAllowed() const = 0; }; class AbstractStatement : public Statement { public: - AbstractStatement(const SourceLocation& start, - const SourceLocation& end, - bool breakpointAllowed); + AbstractStatement(const SourceLocation& start); virtual SourceLocation StartSourceLocation() const; - virtual SourceLocation EndSourceLocation() const; - - virtual bool BreakpointAllowed() const; protected: SourceLocation fStart; - SourceLocation fEnd; - bool fBreakpointAllowed; }; class ContiguousStatement : public AbstractStatement { public: ContiguousStatement(const SourceLocation& start, - const SourceLocation& end, - const TargetAddressRange& range, - bool breakpointAllowed); + const TargetAddressRange& range); const TargetAddressRange& AddressRange() const { return fRange; } diff --git a/src/apps/debugger/model/Team.cpp b/src/apps/debugger/model/Team.cpp index a2428a0a97..b2d739af7a 100644 --- a/src/apps/debugger/model/Team.cpp +++ b/src/apps/debugger/model/Team.cpp @@ -9,6 +9,9 @@ #include +#include "FunctionInstance.h" +#include "ImageDebugInfo.h" +#include "SpecificImageDebugInfo.h" #include "TeamDebugInfo.h" @@ -201,6 +204,39 @@ Team::Images() const } +status_t +Team::GetStatementAtAddress(target_addr_t address, FunctionInstance*& _function, + Statement*& _statement) +{ + // get the image at the address + Image* image = ImageByAddress(address); + if (image == NULL) + return B_ENTRY_NOT_FOUND; + + ImageDebugInfo* imageDebugInfo = image->GetImageDebugInfo(); + if (imageDebugInfo == NULL) + return B_ENTRY_NOT_FOUND; + + // get the function + FunctionInstance* functionInstance + = imageDebugInfo->FunctionAtAddress(address); + if (functionInstance == NULL) + return B_ENTRY_NOT_FOUND; + + // get the statement from the image debug info + FunctionDebugInfo* functionDebugInfo + = functionInstance->GetFunctionDebugInfo(); + status_t error = functionDebugInfo->GetSpecificImageDebugInfo() + ->GetStatement(functionDebugInfo, address, _statement); + // TODO: Provide the corresponding SourceCode, if available! + if (error != B_OK) + return error; + + _function = functionInstance; + return B_OK; +} + + void Team::AddListener(Listener* listener) { diff --git a/src/apps/debugger/model/Team.h b/src/apps/debugger/model/Team.h index fee2c15182..2416789123 100644 --- a/src/apps/debugger/model/Team.h +++ b/src/apps/debugger/model/Team.h @@ -28,7 +28,9 @@ enum { }; +class FunctionInstance; class LocatableFile; +class Statement; class TeamDebugInfo; @@ -68,6 +70,13 @@ public: Image* ImageByAddress(target_addr_t address) const; const ImageList& Images() const; + status_t GetStatementAtAddress(target_addr_t address, + FunctionInstance*& _function, + Statement*& _statement); + // returns a reference to the statement, + // not to the functions instance, though, + // caller must lock + void AddListener(Listener* listener); void RemoveListener(Listener* listener); diff --git a/src/apps/debugger/model/TeamDebugModel.cpp b/src/apps/debugger/model/TeamDebugModel.cpp index a9bb938800..89b54e2692 100644 --- a/src/apps/debugger/model/TeamDebugModel.cpp +++ b/src/apps/debugger/model/TeamDebugModel.cpp @@ -10,6 +10,8 @@ #include #include "Breakpoint.h" +#include "Function.h" +#include "UserBreakpoint.h" // #pragma mark - BreakpointByAddressPredicate @@ -107,16 +109,36 @@ TeamDebugModel::BreakpointAtAddress(target_addr_t address) const } +//void +//TeamDebugModel::GetBreakpointsInAddressRange(TargetAddressRange range, +// BObjectList& breakpoints) const +//{ +// int32 index = fBreakpoints.FindBinaryInsertionIndex( +// BreakpointByAddressPredicate(range.Start())); +// for (; Breakpoint* breakpoint = fBreakpoints.ItemAt(index); index++) { +// if (breakpoint->Address() > range.End()) +// break; +// breakpoints.AddItem(breakpoint); +// } +//} + + void -TeamDebugModel::GetBreakpointsInAddressRange(TargetAddressRange range, - BObjectList& breakpoints) const +TeamDebugModel::GetBreakpointsForSourceCode(SourceCode* sourceCode, + BObjectList& breakpoints) const { - int32 index = fBreakpoints.FindBinaryInsertionIndex( - BreakpointByAddressPredicate(range.Start())); - for (; Breakpoint* breakpoint = fBreakpoints.ItemAt(index); index++) { - if (breakpoint->Address() > range.End()) - break; - breakpoints.AddItem(breakpoint); + // TODO: This can probably be optimized. Maybe by registering the user + // breakpoints with the team debug model and sorting them by source code. + for (int32 i = 0; Breakpoint* breakpoint = fBreakpoints.ItemAt(i); i++) { + UserBreakpointInstance* userBreakpointInstance + = breakpoint->FirstUserBreakpoint(); + if (userBreakpointInstance == NULL) + continue; + + UserBreakpoint* userBreakpoint + = userBreakpointInstance->GetUserBreakpoint(); + if (userBreakpoint->GetFunction()->GetSourceCode() == sourceCode) + breakpoints.AddItem(userBreakpoint); } } diff --git a/src/apps/debugger/model/TeamDebugModel.h b/src/apps/debugger/model/TeamDebugModel.h index 1ae6882e4d..8177a264ae 100644 --- a/src/apps/debugger/model/TeamDebugModel.h +++ b/src/apps/debugger/model/TeamDebugModel.h @@ -22,7 +22,9 @@ enum { class Architecture; class Breakpoint; +class SourceCode; class TeamMemory; +class UserBreakpoint; class TeamDebugModel { @@ -56,9 +58,13 @@ public: Breakpoint* BreakpointAt(int32 index) const; Breakpoint* BreakpointAtAddress( target_addr_t address) const; - void GetBreakpointsInAddressRange( - TargetAddressRange range, - BObjectList& breakpoints) const; +// void GetBreakpointsInAddressRange( +// TargetAddressRange range, +// BObjectList& breakpoints) const; + void GetBreakpointsForSourceCode( + SourceCode* sourceCode, + BObjectList& breakpoints) + const; void AddListener(Listener* listener); void RemoveListener(Listener* listener); diff --git a/src/apps/debugger/model/UserBreakpoint.cpp b/src/apps/debugger/model/UserBreakpoint.cpp new file mode 100644 index 0000000000..da2420e27a --- /dev/null +++ b/src/apps/debugger/model/UserBreakpoint.cpp @@ -0,0 +1,94 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + +#include "UserBreakpoint.h" + +#include "Function.h" + + +// #pragma mark - UserBreakpointInstance + + +UserBreakpointInstance::UserBreakpointInstance(UserBreakpoint* userBreakpoint, + target_addr_t address) + : + fAddress(address), + fUserBreakpoint(userBreakpoint), + fBreakpoint(NULL) +{ +} + + +void +UserBreakpointInstance::SetBreakpoint(Breakpoint* breakpoint) +{ + fBreakpoint = breakpoint; +} + + +// #pragma mark - UserBreakpoint + + +UserBreakpoint::UserBreakpoint(Function* function) + : + fFunction(function), + fValid(false), + fEnabled(false) +{ + fFunction->AcquireReference(); +} + + +UserBreakpoint::~UserBreakpoint() +{ + for (int32 i = 0; UserBreakpointInstance* instance = fInstances.ItemAt(i); + i++) { + delete instance; + } + + fFunction->ReleaseReference(); +} + + +int32 +UserBreakpoint::CountInstances() const +{ + return fInstances.CountItems(); +} + + +UserBreakpointInstance* +UserBreakpoint::InstanceAt(int32 index) const +{ + return fInstances.ItemAt(index); +} + + +bool +UserBreakpoint::AddInstance(UserBreakpointInstance* instance) +{ + return fInstances.AddItem(instance); +} + + +void +UserBreakpoint::RemoveInstance(UserBreakpointInstance* instance) +{ + fInstances.RemoveItem(instance); +} + + +void +UserBreakpoint::SetValid(bool valid) +{ + fValid = valid; +} + + +void +UserBreakpoint::SetEnabled(bool enabled) +{ + fEnabled = enabled; +} diff --git a/src/apps/debugger/model/UserBreakpoint.h b/src/apps/debugger/model/UserBreakpoint.h new file mode 100644 index 0000000000..b176580e09 --- /dev/null +++ b/src/apps/debugger/model/UserBreakpoint.h @@ -0,0 +1,79 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef USER_BREAKPOINT_H +#define USER_BREAKPOINT_H + +#include +#include +#include + +#include "Types.h" + + +class Breakpoint; +class Function; +class UserBreakpoint; + + +class UserBreakpointInstance + : public DoublyLinkedListLinkImpl { +public: + UserBreakpointInstance( + UserBreakpoint* userBreakpoint, + target_addr_t address); + + UserBreakpoint* GetUserBreakpoint() const + { return fUserBreakpoint; } + target_addr_t Address() const { return fAddress; } + + Breakpoint* GetBreakpoint() const { return fBreakpoint; } + void SetBreakpoint(Breakpoint* breakpoint); + +private: + target_addr_t fAddress; + UserBreakpoint* fUserBreakpoint; + Breakpoint* fBreakpoint; +}; + + +typedef DoublyLinkedList UserBreakpointInstanceList; + + +class UserBreakpoint : public Referenceable { +public: + UserBreakpoint(Function* function); + ~UserBreakpoint(); + + Function* GetFunction() const { return fFunction; } + + int32 CountInstances() const; + UserBreakpointInstance* InstanceAt(int32 index) const; + + // Note: After known to the BreakpointManager, those can only be + // invoked with the breakpoint manager lock held. + bool AddInstance(UserBreakpointInstance* instance); + void RemoveInstance( + UserBreakpointInstance* instance); + + bool IsValid() const { return fValid; } + void SetValid(bool valid); + // BreakpointManager only + + bool IsEnabled() const { return fEnabled; } + void SetEnabled(bool enabled); + // BreakpointManager only + +private: + typedef BObjectList InstanceList; + +private: + Function* fFunction; + InstanceList fInstances; + bool fValid; + bool fEnabled; +}; + + +#endif // USER_BREAKPOINT_H