From 2bf55b39a5119e092a52d9e50da6efcb38393d54 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Fri, 24 Jul 2009 02:35:30 +0000 Subject: [PATCH] * Made FunctionID abstract. There are now two implementing subclasses, SourceFunctionID (where we know the souce location of the function) and ImageFunctionID (where we don't know the source location). Made the classes archivable. * Added support to find functions by ID. * Improved user breakpoint handling. We can now "install" a breakpoint before we even know the function instances in which to install it. Whenever image debug information become available, breakpoints are installed in the concerned function instances of the respective image. * Always trigger loading image debug info as soon as we become aware of an image. * Implemented a settings management mechanism. ATM only the breakpoint locations for debugged teams are persisted. This seriously improves the debugging fun, though. :-) git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@31728 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/apps/debugger/BreakpointManager.cpp | 182 ++++++++++++++- src/apps/debugger/BreakpointManager.h | 9 +- src/apps/debugger/Debugger.cpp | 17 +- src/apps/debugger/Jamfile | 7 + src/apps/debugger/MessageCodes.h | 1 + src/apps/debugger/TeamDebugger.cpp | 144 +++++++++++- src/apps/debugger/TeamDebugger.h | 11 +- .../debugger/debug_info/FunctionInstance.cpp | 13 +- .../debugger/debug_info/ImageDebugInfo.cpp | 13 ++ src/apps/debugger/debug_info/ImageDebugInfo.h | 1 + .../debugger/debug_info/TeamDebugInfo.cpp | 58 ++++- src/apps/debugger/debug_info/TeamDebugInfo.h | 6 +- .../debugger/gui/team_window/TeamWindow.cpp | 2 + src/apps/debugger/ids/FunctionID.cpp | 149 ++++++++++++- src/apps/debugger/ids/FunctionID.h | 51 ++++- src/apps/debugger/model/Image.h | 2 +- src/apps/debugger/model/ImageInfo.h | 2 +- src/apps/debugger/model/Team.cpp | 49 ++++- src/apps/debugger/model/Team.h | 13 +- src/apps/debugger/model/UserBreakpoint.cpp | 78 ++++++- src/apps/debugger/model/UserBreakpoint.h | 46 +++- .../debugger/settings/BreakpointSetting.cpp | 155 +++++++++++++ .../debugger/settings/BreakpointSetting.h | 57 +++++ .../debugger/settings/SettingsManager.cpp | 207 ++++++++++++++++++ src/apps/debugger/settings/SettingsManager.h | 47 ++++ src/apps/debugger/settings/TeamSettings.cpp | 177 +++++++++++++++ src/apps/debugger/settings/TeamSettings.h | 50 +++++ 27 files changed, 1480 insertions(+), 67 deletions(-) create mode 100644 src/apps/debugger/settings/BreakpointSetting.cpp create mode 100644 src/apps/debugger/settings/BreakpointSetting.h create mode 100644 src/apps/debugger/settings/SettingsManager.cpp create mode 100644 src/apps/debugger/settings/SettingsManager.h create mode 100644 src/apps/debugger/settings/TeamSettings.cpp create mode 100644 src/apps/debugger/settings/TeamSettings.h diff --git a/src/apps/debugger/BreakpointManager.cpp b/src/apps/debugger/BreakpointManager.cpp index 4a03389374..d31187114b 100644 --- a/src/apps/debugger/BreakpointManager.cpp +++ b/src/apps/debugger/BreakpointManager.cpp @@ -12,6 +12,9 @@ #include #include "DebuggerInterface.h" +#include "Function.h" +#include "SpecificImageDebugInfo.h" +#include "Statement.h" #include "Team.h" @@ -76,12 +79,8 @@ printf(" -> no image at that address\n"); } breakpoint = new(std::nothrow) Breakpoint(image, address); - if (breakpoint == NULL) { - error = B_NO_MEMORY; - break; - } - - if (!fTeam->AddBreakpoint(breakpoint)) { + if (breakpoint == NULL || !fTeam->AddBreakpoint(breakpoint)) { + delete breakpoint; error = B_NO_MEMORY; break; } @@ -128,7 +127,7 @@ printf(" success, marking user breakpoint valid\n"); teamLocker.Lock(); userBreakpoint->SetValid(true); userBreakpoint->AcquireReference(); - // TODO: Put the user breakpoint some place? + fTeam->AddUserBreakpoint(userBreakpoint); teamLocker.Unlock(); } } else { @@ -178,6 +177,8 @@ BreakpointManager::UninstallUserBreakpoint(UserBreakpoint* userBreakpoint) if (!userBreakpoint->IsValid()) return; + fTeam->RemoveUserBreakpoint(userBreakpoint); + userBreakpoint->SetValid(false); userBreakpoint->SetEnabled(false); @@ -299,6 +300,173 @@ BreakpointManager::UninstallTemporaryBreakpoint(target_addr_t address, } +void +BreakpointManager::UpdateImageBreakpoints(Image* image) +{ + _UpdateImageBreakpoints(image, false); +} + + +void +BreakpointManager::RemoveImageBreakpoints(Image* image) +{ + _UpdateImageBreakpoints(image, true); +} + + +void +BreakpointManager::_UpdateImageBreakpoints(Image* image, bool removeOnly) +{ + AutoLocker installLocker(fLock); + AutoLocker teamLocker(fTeam); + + // remove obsolete user breakpoint instances + BObjectList breakpointsToUpdate; + for (UserBreakpointList::ConstIterator it + = fTeam->UserBreakpoints().GetIterator(); + UserBreakpoint* userBreakpoint = it.Next();) { + int32 instanceCount = userBreakpoint->CountInstances(); + for (int32 i = instanceCount - 1; i >= 0; i--) { + UserBreakpointInstance* instance = userBreakpoint->InstanceAt(i); + Breakpoint* breakpoint = instance->GetBreakpoint(); + if (breakpoint == NULL || breakpoint->GetImage() != image) + continue; + + userBreakpoint->RemoveInstanceAt(i); + breakpoint->RemoveUserBreakpoint(instance); + + if (!breakpointsToUpdate.AddItem(breakpoint)) { + _UpdateBreakpointInstallation(breakpoint); + if (breakpoint->IsUnused()) + fTeam->RemoveBreakpoint(breakpoint); + } + + delete instance; + } + } + + // update breakpoints + teamLocker.Unlock(); + for (int32 i = 0; Breakpoint* breakpoint = breakpointsToUpdate.ItemAt(i); + i++) { + _UpdateBreakpointInstallation(breakpoint); + } + + teamLocker.Lock(); + for (int32 i = 0; Breakpoint* breakpoint = breakpointsToUpdate.ItemAt(i); + i++) { + if (breakpoint->IsUnused()) + fTeam->RemoveBreakpoint(breakpoint); + } + + // add breakpoint instances for function instances in the image (if we have + // an image debug info) + BObjectList newInstances; + ImageDebugInfo* imageDebugInfo = image->GetImageDebugInfo(); + if (imageDebugInfo == NULL) + return; + + for (UserBreakpointList::ConstIterator it + = fTeam->UserBreakpoints().GetIterator(); + UserBreakpoint* userBreakpoint = it.Next();) { + // get the function + Function* function = fTeam->FunctionByID( + userBreakpoint->Location().GetFunctionID()); + if (function == NULL) + continue; + + const SourceLocation& sourceLocation + = userBreakpoint->Location().GetSourceLocation(); + target_addr_t relativeAddress + = userBreakpoint->Location().RelativeAddress(); + + // iterate through the function instances + for (FunctionInstanceList::ConstIterator it + = function->Instances().GetIterator(); + FunctionInstance* functionInstance = it.Next();) { + if (functionInstance->GetImageDebugInfo() != imageDebugInfo) + continue; + + // get the breakpoint address for the instance + target_addr_t instanceAddress = 0; + if (functionInstance->SourceFile() != NULL) { + // We have a source file, so get the address for the source + // location. + Statement* statement = NULL; + FunctionDebugInfo* functionDebugInfo + = functionInstance->GetFunctionDebugInfo(); + functionDebugInfo->GetSpecificImageDebugInfo() + ->GetStatementAtSourceLocation(functionDebugInfo, + sourceLocation, statement); + if (statement != NULL) { + instanceAddress = statement->CoveringAddressRange().Start(); + // TODO: What about BreakpointAllowed()? + statement->ReleaseReference(); + // TODO: Make sure we do hit the function in question! + } + } + + if (instanceAddress == 0) { + // No source file (or we failed getting the statement), so try + // to use the same relative address. + if (relativeAddress > functionInstance->Size()) + continue; + instanceAddress = functionInstance->Address() + relativeAddress; + // TODO: Make sure it does at least hit an instruction! + } + + // create the user breakpoint instance + UserBreakpointInstance* instance = new(std::nothrow) + UserBreakpointInstance(userBreakpoint, instanceAddress); + if (instance == NULL || !newInstances.AddItem(instance)) { + delete instance; + continue; + } + + if (!userBreakpoint->AddInstance(instance)) { + newInstances.RemoveItemAt(newInstances.CountItems() - 1); + delete instance; + } + + // get/create the breakpoint for the address + target_addr_t address = instance->Address(); + Breakpoint* breakpoint = fTeam->BreakpointAtAddress(address); + if (breakpoint == NULL) { + breakpoint = new(std::nothrow) Breakpoint(image, address); + if (breakpoint == NULL || !fTeam->AddBreakpoint(breakpoint)) { + delete breakpoint; + break; + } + } + + breakpoint->AddUserBreakpoint(instance); + instance->SetBreakpoint(breakpoint); + } + } + + // install the breakpoints for the new user breakpoint instances + teamLocker.Unlock(); + for (int32 i = 0; UserBreakpointInstance* instance = newInstances.ItemAt(i); + i++) { + Breakpoint* breakpoint = instance->GetBreakpoint(); + if (breakpoint == NULL + || _UpdateBreakpointInstallation(breakpoint) != B_OK) { + // something went wrong -- remove the instance + teamLocker.Lock(); + + instance->GetUserBreakpoint()->RemoveInstance(instance); + if (breakpoint != NULL) { + breakpoint->AddUserBreakpoint(instance); + if (breakpoint->IsUnused()) + fTeam->RemoveBreakpoint(breakpoint); + } + + teamLocker.Unlock(); + } + } +} + + status_t BreakpointManager::_UpdateBreakpointInstallation(Breakpoint* breakpoint) { diff --git a/src/apps/debugger/BreakpointManager.h b/src/apps/debugger/BreakpointManager.h index 0f89e2cf8d..0933c4d184 100644 --- a/src/apps/debugger/BreakpointManager.h +++ b/src/apps/debugger/BreakpointManager.h @@ -22,10 +22,6 @@ public: status_t Init(); -// status_t InstallUserBreakpoint(target_addr_t address, -// bool enabled); -// void UninstallUserBreakpoint(target_addr_t address); - status_t InstallUserBreakpoint( UserBreakpoint* userBreakpoint, bool enabled); @@ -39,7 +35,12 @@ public: target_addr_t address, BreakpointClient* client); + void UpdateImageBreakpoints(Image* image); + void RemoveImageBreakpoints(Image* image); + private: + void _UpdateImageBreakpoints(Image* image, + bool removeOnly); status_t _UpdateBreakpointInstallation( Breakpoint* breakpoint); // fLock must be held diff --git a/src/apps/debugger/Debugger.cpp b/src/apps/debugger/Debugger.cpp index 253a99e2ba..cf99a45e0c 100644 --- a/src/apps/debugger/Debugger.cpp +++ b/src/apps/debugger/Debugger.cpp @@ -3,6 +3,7 @@ * Distributed under the terms of the MIT License. */ + #include #include #include @@ -19,6 +20,7 @@ #include "debug_utils.h" #include "MessageCodes.h" +#include "SettingsManager.h" #include "TeamDebugger.h" @@ -177,6 +179,11 @@ public: { } + status_t Init() + { + return fSettingsManager.Init(); + } + virtual void MessageReceived(BMessage* message) { switch (message->what) { @@ -254,7 +261,7 @@ printf("There's already a debugger for team: %ld\n", team); return; } - debugger = new(std::nothrow) TeamDebugger(this); + debugger = new(std::nothrow) TeamDebugger(this, &fSettingsManager); if (debugger == NULL) { // TODO: Notify the user! fprintf(stderr, "Error: Out of memory!\n"); @@ -326,6 +333,7 @@ private: } private: + SettingsManager fSettingsManager; TeamDebuggerList fTeamDebuggers; int32 fRunningTeamDebuggers; }; @@ -343,6 +351,13 @@ main(int argc, const char* const* argv) } Debugger app; + status_t error = app.Init(); + if (error != B_OK) { + fprintf(stderr, "Error: Failed to init application: %s\n", + strerror(error)); + return 1; + } + app.Run(); return 0; } diff --git a/src/apps/debugger/Jamfile b/src/apps/debugger/Jamfile index 91d8fa6955..4771f3655f 100644 --- a/src/apps/debugger/Jamfile +++ b/src/apps/debugger/Jamfile @@ -15,6 +15,7 @@ SEARCH_SOURCE += [ FDirName $(SUBDIR) files ] ; SEARCH_SOURCE += [ FDirName $(SUBDIR) gui team_window ] ; SEARCH_SOURCE += [ FDirName $(SUBDIR) ids ] ; SEARCH_SOURCE += [ FDirName $(SUBDIR) model ] ; +SEARCH_SOURCE += [ FDirName $(SUBDIR) settings ] ; SEARCH_SOURCE += [ FDirName $(SUBDIR) source_language ] ; SEARCH_SOURCE += [ FDirName $(SUBDIR) types ] ; SEARCH_SOURCE += [ FDirName $(SUBDIR) util ] ; @@ -121,6 +122,11 @@ Application Debugger : TypeComponentPath.cpp Variable.cpp + # settings + BreakpointSetting.cpp + TeamSettings.cpp + SettingsManager.cpp + # source_language CLanguage.cpp CLanguageFamily.cpp @@ -135,6 +141,7 @@ Application Debugger : ValueLocation.cpp # util + ArchivingUtils.cpp BitBuffer.cpp StringUtils.cpp diff --git a/src/apps/debugger/MessageCodes.h b/src/apps/debugger/MessageCodes.h index 1733247834..24232b2656 100644 --- a/src/apps/debugger/MessageCodes.h +++ b/src/apps/debugger/MessageCodes.h @@ -24,6 +24,7 @@ enum { MSG_FUNCTION_SOURCE_CODE_CHANGED = 'fnsc', MSG_USER_BREAKPOINT_CHANGED = 'ubrc', MSG_DEBUGGER_EVENT = 'dbge', + MSG_LOAD_SETTINGS = 'ldst', MSG_TEXTVIEW_AUTOSCROLL = 'tvas', diff --git a/src/apps/debugger/TeamDebugger.cpp b/src/apps/debugger/TeamDebugger.cpp index b0ec1cd3c3..fcd7ffb4a1 100644 --- a/src/apps/debugger/TeamDebugger.cpp +++ b/src/apps/debugger/TeamDebugger.cpp @@ -19,14 +19,17 @@ #include "debug_utils.h" #include "BreakpointManager.h" +#include "BreakpointSetting.h" #include "CpuState.h" #include "DebuggerInterface.h" #include "FileManager.h" #include "Function.h" +#include "FunctionID.h" #include "ImageDebugInfo.h" #include "Jobs.h" #include "LocatableFile.h" #include "MessageCodes.h" +#include "SettingsManager.h" #include "SourceCode.h" #include "SpecificImageDebugInfo.h" #include "StackFrame.h" @@ -34,6 +37,7 @@ #include "Statement.h" #include "SymbolInfo.h" #include "TeamDebugInfo.h" +#include "TeamSettings.h" #include "Variable.h" // #pragma mark - ImageHandler @@ -116,10 +120,11 @@ struct TeamDebugger::ImageHandlerHashDefinition { // #pragma mark - TeamDebugger -TeamDebugger::TeamDebugger(Listener* listener) +TeamDebugger::TeamDebugger(Listener* listener, SettingsManager* settingsManager) : BLooper("team debugger"), fListener(listener), + fSettingsManager(settingsManager), fTeam(NULL), fTeamID(-1), fImageHandlers(NULL), @@ -137,6 +142,9 @@ TeamDebugger::TeamDebugger(Listener* listener) TeamDebugger::~TeamDebugger() { + if (fTeam != NULL) + _SaveSettings(); + AutoLocker locker(this); fTerminating = true; @@ -192,6 +200,9 @@ TeamDebugger::Init(team_id teamID, thread_id threadID, bool stopInMain) bool targetIsLocal = true; // TODO: Support non-local targets! + // the first thing we want to do when running + PostMessage(MSG_LOAD_SETTINGS); + fTeamID = teamID; // create debugger interface @@ -321,6 +332,8 @@ TeamDebugger::Init(team_id teamID, thread_id threadID, bool stopInMain) return error; if (image->Type() == B_APP_IMAGE) appImage = image; + + ImageDebugInfoRequested(image); } } @@ -446,6 +459,16 @@ TeamDebugger::MessageReceived(BMessage* message) break; } + case MSG_IMAGE_DEBUG_INFO_CHANGED: + { + int32 imageID; + if (message->FindInt32("image", &imageID) != B_OK) + break; + + _HandleImageDebugInfoChanged(imageID); + break; + } + case MSG_IMAGE_FILE_CHANGED: { int32 imageID; @@ -464,8 +487,13 @@ TeamDebugger::MessageReceived(BMessage* message) _HandleDebuggerMessage(event); delete event; + break; } + case MSG_LOAD_SETTINGS: + _LoadSettings(); + break; + default: BLooper::MessageReceived(message); break; @@ -661,6 +689,15 @@ TeamDebugger::ThreadStackTraceChanged(const ::Team::ThreadEvent& event) } +void +TeamDebugger::ImageDebugInfoChanged(const ::Team::ImageEvent& event) +{ + BMessage message(MSG_IMAGE_DEBUG_INFO_CHANGED); + message.AddInt32("image", event.GetImage()->ID()); + PostMessage(&message); +} + + /*static*/ status_t TeamDebugger::_DebugEventListenerEntry(void* data) { @@ -850,17 +887,39 @@ TeamDebugger::_HandleImageDeleted(ImageDeletedEvent* event) ImageHandler* imageHandler = fImageHandlers->Lookup( event->GetImageInfo().ImageID()); - if (imageHandler != NULL) { - fImageHandlers->Remove(imageHandler); - imageHandler->ReleaseReference(); - } + if (imageHandler == NULL) + return false; -// TODO: Remove breakpoints in the image! + fImageHandlers->Remove(imageHandler); + Reference imageHandlerReference(imageHandler, true); + locker.Unlock(); + + // remove breakpoints in the image + fBreakpointManager->RemoveImageBreakpoints(imageHandler->GetImage()); return false; } +void +TeamDebugger::_HandleImageDebugInfoChanged(image_id imageID) +{ + // get the image (via the image handler) + AutoLocker< ::Team> locker(fTeam); + ImageHandler* imageHandler = fImageHandlers->Lookup(imageID); + if (imageHandler == NULL) + return; + + Image* image = imageHandler->GetImage(); + Reference imageReference(image); + + locker.Unlock(); + + // update breakpoints in the image + fBreakpointManager->UpdateImageBreakpoints(image); +} + + void TeamDebugger::_HandleImageFileChanged(image_id imageID) { @@ -918,8 +977,16 @@ printf(" function: %p\n", function); target_addr_t relativeAddress = address - functionInstance->Address(); printf(" relative address: %#llx, source location: (%ld, %ld)\n", relativeAddress, sourceLocation.Line(), sourceLocation.Column()); + // get function id + FunctionID* functionID = functionInstance->GetFunctionID(); + if (functionID == NULL) + return; + Reference functionIDReference(functionID, true); + // create the user breakpoint - userBreakpoint = new(std::nothrow) UserBreakpoint(function); + userBreakpoint = new(std::nothrow) UserBreakpoint( + UserBreakpointLocation(functionID, function->SourceFile(), + sourceLocation, relativeAddress)); if (userBreakpoint == NULL) return; userBreakpointReference.SetTo(userBreakpoint, true); @@ -1027,6 +1094,8 @@ TeamDebugger::_AddImage(const ImageInfo& imageInfo, Image** _image) if (error != B_OK) return error; + ImageDebugInfoRequested(image); + ImageHandler* imageHandler = new(std::nothrow) ImageHandler(this, image); if (imageHandler != NULL) fImageHandlers->Insert(imageHandler); @@ -1038,6 +1107,67 @@ TeamDebugger::_AddImage(const ImageInfo& imageInfo, Image** _image) } +void +TeamDebugger::_LoadSettings() +{ + // get the team name + AutoLocker< ::Team> locker(fTeam); + BString teamName = fTeam->Name(); + locker.Unlock(); + + // load the settings + TeamSettings settings; + if (fSettingsManager->LoadTeamSettings(teamName, settings) != B_OK) + return; + + // create the saved breakpoints + for (int32 i = 0; const BreakpointSetting* breakpointSetting + = settings.BreakpointAt(i); i++) { + if (breakpointSetting->GetFunctionID() == NULL) + continue; + + // get the source file, if any + LocatableFile* sourceFile = NULL; + if (breakpointSetting->SourceFile().Length() > 0) { + sourceFile = fFileManager->GetSourceFile( + breakpointSetting->SourceFile()); + if (sourceFile == NULL) + continue; + } + Reference sourceFileReference(sourceFile, true); + + // create the breakpoint + UserBreakpointLocation location(breakpointSetting->GetFunctionID(), + sourceFile, breakpointSetting->GetSourceLocation(), + breakpointSetting->RelativeAddress()); + + UserBreakpoint* breakpoint = new(std::nothrow) UserBreakpoint(location); + if (breakpoint == NULL) + return; + Reference breakpointReference(breakpoint, true); + + // install it + fBreakpointManager->InstallUserBreakpoint(breakpoint, + breakpointSetting->IsEnabled()); + } +} + + +void +TeamDebugger::_SaveSettings() +{ + // get the settings + AutoLocker< ::Team> locker(fTeam); + TeamSettings settings; + if (settings.SetTo(fTeam) != B_OK) + return; + locker.Unlock(); + + // save the settings + fSettingsManager->SaveTeamSettings(settings); +} + + void TeamDebugger::_NotifyUser(const char* title, const char* text,...) { diff --git a/src/apps/debugger/TeamDebugger.h b/src/apps/debugger/TeamDebugger.h index 1e47d78f3a..df9e39d1e1 100644 --- a/src/apps/debugger/TeamDebugger.h +++ b/src/apps/debugger/TeamDebugger.h @@ -20,6 +20,7 @@ class DebuggerInterface; class FileManager; +class SettingsManager; class TeamDebugInfo; @@ -29,7 +30,8 @@ public: class Listener; public: - TeamDebugger(Listener* listener); + TeamDebugger(Listener* listener, + SettingsManager* settingsManager); ~TeamDebugger(); status_t Init(team_id teamID, thread_id threadID, @@ -66,6 +68,8 @@ private: const ::Team::ThreadEvent& event); virtual void ThreadStackTraceChanged( const ::Team::ThreadEvent& event); + virtual void ImageDebugInfoChanged( + const ::Team::ImageEvent& event); private: struct ImageHandler; @@ -87,6 +91,7 @@ private: bool _HandleImageDeleted( ImageDeletedEvent* event); + void _HandleImageDebugInfoChanged(image_id imageID); void _HandleImageFileChanged(image_id imageID); void _HandleSetUserBreakpoint(target_addr_t address, @@ -99,11 +104,15 @@ private: status_t _AddImage(const ImageInfo& imageInfo, Image** _image = NULL); + void _LoadSettings(); + void _SaveSettings(); + void _NotifyUser(const char* title, const char* text,...); private: Listener* fListener; + SettingsManager* fSettingsManager; ::Team* fTeam; team_id fTeamID; ThreadHandlerTable fThreadHandlers; diff --git a/src/apps/debugger/debug_info/FunctionInstance.cpp b/src/apps/debugger/debug_info/FunctionInstance.cpp index f19ba5993f..111db604c7 100644 --- a/src/apps/debugger/debug_info/FunctionInstance.cpp +++ b/src/apps/debugger/debug_info/FunctionInstance.cpp @@ -39,19 +39,14 @@ FunctionInstance::~FunctionInstance() FunctionID* FunctionInstance::GetFunctionID() const { - BString idString; - BString path; if (LocatableFile* file = SourceFile()) { - idString << "s:"; + BString path; file->GetPath(path); - } else { - idString << "i:"; - path << GetImageDebugInfo()->GetImageInfo().Name(); + return new(std::nothrow) SourceFunctionID(path, Name()); } - idString << path << "//" << Name(); - - return new(std::nothrow) FunctionID(idString); + return new(std::nothrow) ImageFunctionID( + GetImageDebugInfo()->GetImageInfo().Name(), Name()); } diff --git a/src/apps/debugger/debug_info/ImageDebugInfo.cpp b/src/apps/debugger/debug_info/ImageDebugInfo.cpp index f337128b22..e98be6223d 100644 --- a/src/apps/debugger/debug_info/ImageDebugInfo.cpp +++ b/src/apps/debugger/debug_info/ImageDebugInfo.cpp @@ -96,6 +96,19 @@ ImageDebugInfo::FunctionAtAddress(target_addr_t address) const } +FunctionInstance* +ImageDebugInfo::FunctionByName(const char* name) const +{ + // TODO: Not really optimal. + for (int32 i = 0; FunctionInstance* function = fFunctions.ItemAt(i); i++) { + if (function->Name() == name) + return function; + } + + return NULL; +} + + status_t ImageDebugInfo::AddSourceCodeInfo(LocatableFile* file, FileSourceCode* sourceCode) const diff --git a/src/apps/debugger/debug_info/ImageDebugInfo.h b/src/apps/debugger/debug_info/ImageDebugInfo.h index 5fd1a30455..887129efb7 100644 --- a/src/apps/debugger/debug_info/ImageDebugInfo.h +++ b/src/apps/debugger/debug_info/ImageDebugInfo.h @@ -36,6 +36,7 @@ public: int32 CountFunctions() const; FunctionInstance* FunctionAt(int32 index) const; FunctionInstance* FunctionAtAddress(target_addr_t address) const; + FunctionInstance* FunctionByName(const char* name) const; status_t AddSourceCodeInfo(LocatableFile* file, FileSourceCode* sourceCode) const; diff --git a/src/apps/debugger/debug_info/TeamDebugInfo.cpp b/src/apps/debugger/debug_info/TeamDebugInfo.cpp index 1ee389c097..caaab88f6f 100644 --- a/src/apps/debugger/debug_info/TeamDebugInfo.cpp +++ b/src/apps/debugger/debug_info/TeamDebugInfo.cpp @@ -21,6 +21,7 @@ #include "FileManager.h" #include "FileSourceCode.h" #include "Function.h" +#include "FunctionID.h" #include "ImageDebugInfo.h" #include "LocatableFile.h" #include "SourceFile.h" @@ -169,6 +170,16 @@ struct TeamDebugInfo::SourceFileEntry : public HashTableLink { return fFunctions.ItemAt(index); } + Function* FunctionByName(const BString& name) const + { + // TODO: That's not exactly optimal. + for (int32 i = 0; Function* function = fFunctions.ItemAt(i); i++) { + if (name == function->Name()) + return function; + } + return NULL; + } + private: typedef BObjectList FunctionList; @@ -568,9 +579,21 @@ TeamDebugInfo::RemoveImageDebugInfo(ImageDebugInfo* imageDebugInfo) } +ImageDebugInfo* +TeamDebugInfo::ImageDebugInfoByName(const char* name) const +{ + for (int32 i = 0; ImageDebugInfo* imageDebugInfo = fImages.ItemAt(i); i++) { + if (imageDebugInfo->GetImageInfo().Name() == name) + return imageDebugInfo; + } + + return NULL; +} + + Function* TeamDebugInfo::FunctionAtSourceLocation(LocatableFile* file, - const SourceLocation& location) + const SourceLocation& location) const { if (SourceFileEntry* entry = fSourceFiles->Lookup(file)) return entry->FunctionAtLocation(location); @@ -578,6 +601,39 @@ TeamDebugInfo::FunctionAtSourceLocation(LocatableFile* file, } +Function* +TeamDebugInfo::FunctionByID(FunctionID* functionID) const +{ + if (SourceFunctionID* sourceFunctionID + = dynamic_cast(functionID)) { + // get the source file + LocatableFile* file = fFileManager->GetSourceFile( + sourceFunctionID->SourceFilePath()); + if (file == NULL) + return NULL; + Reference fileReference(file, true); + + if (SourceFileEntry* entry = fSourceFiles->Lookup(file)) + return entry->FunctionByName(functionID->FunctionName()); + return NULL; + } + + ImageFunctionID* imageFunctionID + = dynamic_cast(functionID); + if (imageFunctionID == NULL) + return NULL; + + ImageDebugInfo* imageDebugInfo + = ImageDebugInfoByName(imageFunctionID->ImageName()); + if (imageDebugInfo == NULL) + return NULL; + + FunctionInstance* functionInstance = imageDebugInfo->FunctionByName( + functionID->FunctionName()); + return functionInstance != NULL ? functionInstance->GetFunction() : NULL; +} + + status_t TeamDebugInfo::_AddFunction(Function* function) { diff --git a/src/apps/debugger/debug_info/TeamDebugInfo.h b/src/apps/debugger/debug_info/TeamDebugInfo.h index dc04e436e8..c1bf87c402 100644 --- a/src/apps/debugger/debug_info/TeamDebugInfo.h +++ b/src/apps/debugger/debug_info/TeamDebugInfo.h @@ -21,6 +21,7 @@ class DisassembledCode; class FileManager; class FileSourceCode; class Function; +class FunctionID; class FunctionInstance; class ImageDebugInfo; class ImageInfo; @@ -52,15 +53,16 @@ public: DisassembledCode*& _sourceCode); // returns reference - // team is locked status_t AddImageDebugInfo( ImageDebugInfo* imageDebugInfo); void RemoveImageDebugInfo( ImageDebugInfo* imageDebugInfo); + ImageDebugInfo* ImageDebugInfoByName(const char* name) const; Function* FunctionAtSourceLocation(LocatableFile* file, - const SourceLocation& location); + const SourceLocation& location) const; + Function* FunctionByID(FunctionID* functionID) const; private: struct FunctionHashDefinition; diff --git a/src/apps/debugger/gui/team_window/TeamWindow.cpp b/src/apps/debugger/gui/team_window/TeamWindow.cpp index eb41e39622..62511c3621 100644 --- a/src/apps/debugger/gui/team_window/TeamWindow.cpp +++ b/src/apps/debugger/gui/team_window/TeamWindow.cpp @@ -70,7 +70,9 @@ TeamWindow::TeamWindow(::Team* team, Listener* listener) fStepIntoButton(NULL), fStepOutButton(NULL) { + fTeam->Lock(); BString name = fTeam->Name(); + fTeam->Unlock(); if (fTeam->ID() >= 0) name << " (" << fTeam->ID() << ")"; SetTitle(name.String()); diff --git a/src/apps/debugger/ids/FunctionID.cpp b/src/apps/debugger/ids/FunctionID.cpp index b1c4ec19b4..025767dffe 100644 --- a/src/apps/debugger/ids/FunctionID.cpp +++ b/src/apps/debugger/ids/FunctionID.cpp @@ -6,12 +6,29 @@ #include "FunctionID.h" +#include + +#include + #include "StringUtils.h" -FunctionID::FunctionID(const BString& idString) +// #pragma mark - FunctionID + + +FunctionID::FunctionID(const BMessage& archive) : - fIDString(idString) + BArchivable(const_cast(&archive)) +{ + archive.FindString("FunctionID::path", &fPath); + archive.FindString("FunctionID::functionName", &fFunctionName); +} + + +FunctionID::FunctionID(const BString& path, const BString& functionName) + : + fPath(path), + fFunctionName(functionName) { } @@ -21,16 +38,134 @@ FunctionID::~FunctionID() } -bool -FunctionID::operator==(const ObjectID& other) const +status_t +FunctionID::Archive(BMessage* archive, bool deep) const { - const FunctionID* functionID = dynamic_cast(&other); - return functionID != NULL && fIDString == functionID->fIDString; + status_t error = BArchivable::Archive(archive, deep); + if (error != B_OK) + return error; + + error = archive->AddString("FunctionID::path", fPath); + if (error == B_OK) + error = archive->AddString("FunctionID::functionName", fFunctionName); + return error; } uint32 FunctionID::ComputeHashValue() const { - return StringUtils::HashValue(fIDString); + return StringUtils::HashValue(fPath) * 17 + + StringUtils::HashValue(fFunctionName); +} + + +bool +FunctionID::IsValid() const +{ + return !fPath.Length() == 0 && !fFunctionName.Length() == 0; +} + + +// #pragma mark - SourceFunctionID + + +SourceFunctionID::SourceFunctionID(const BMessage& archive) + : + FunctionID(archive) +{ +} + + +SourceFunctionID::SourceFunctionID(const BString& sourceFilePath, + const BString& functionName) + : + FunctionID(sourceFilePath, functionName) +{ +} + + +SourceFunctionID::~SourceFunctionID() +{ +} + + +/*static*/ BArchivable* +SourceFunctionID::Instantiate(BMessage* archive) +{ + if (archive == NULL) + return NULL; + + SourceFunctionID* object = new(std::nothrow) SourceFunctionID(*archive); + if (object == NULL) + return NULL; + + if (!object->IsValid()) { + delete object; + return NULL; + } + + return object; +} + + +bool +SourceFunctionID::operator==(const ObjectID& _other) const +{ + const SourceFunctionID* other = dynamic_cast( + &_other); + return other != NULL && fPath == other->fPath + && fFunctionName == other->fFunctionName; +} + + +// #pragma mark - ImageFunctionID + + +ImageFunctionID::ImageFunctionID(const BMessage& archive) + : + FunctionID(archive) +{ +} + + +ImageFunctionID::ImageFunctionID(const BString& imageName, + const BString& functionName) + : + FunctionID(imageName, functionName) +{ +} + + +ImageFunctionID::~ImageFunctionID() +{ +} + + +/*static*/ BArchivable* +ImageFunctionID::Instantiate(BMessage* archive) +{ + if (archive == NULL) + return NULL; + + ImageFunctionID* object = new(std::nothrow) ImageFunctionID(*archive); + if (object == NULL) + return NULL; + + if (!object->IsValid()) { + delete object; + return NULL; + } + + return object; +} + + +bool +ImageFunctionID::operator==(const ObjectID& _other) const +{ + const ImageFunctionID* other = dynamic_cast( + &_other); + return other != NULL && fPath == other->fPath + && fFunctionName == other->fFunctionName; } diff --git a/src/apps/debugger/ids/FunctionID.h b/src/apps/debugger/ids/FunctionID.h index 82e469a61e..ee5d81cb99 100644 --- a/src/apps/debugger/ids/FunctionID.h +++ b/src/apps/debugger/ids/FunctionID.h @@ -6,23 +6,64 @@ #define FUNCTION_ID_H +#include #include #include "ObjectID.h" -class FunctionID : public ObjectID { +class FunctionID : public ObjectID, public BArchivable { +protected: + FunctionID(const BMessage& archive); + FunctionID(const BString& path, + const BString& functionName); + public: - FunctionID(const BString& idString); virtual ~FunctionID(); - virtual bool operator==(const ObjectID& other) const; + virtual status_t Archive(BMessage* archive, + bool deep = true) const; + + const BString& FunctionName() const { return fFunctionName; } protected: virtual uint32 ComputeHashValue() const; -private: - const BString fIDString; + bool IsValid() const; + +protected: + BString fPath; + BString fFunctionName; +}; + + +class SourceFunctionID : public FunctionID { +public: + SourceFunctionID(const BMessage& archive); + SourceFunctionID(const BString& sourceFilePath, + const BString& functionName); + virtual ~SourceFunctionID(); + + static BArchivable* Instantiate(BMessage* archive); + + const BString& SourceFilePath() const { return fPath; } + + virtual bool operator==(const ObjectID& other) const; +}; + + +class ImageFunctionID : public FunctionID { +public: + ImageFunctionID(const BMessage& archive); + ImageFunctionID(const BString& imageName, + const BString& functionName); + virtual ~ImageFunctionID(); + + static BArchivable* Instantiate(BMessage* archive); + + const BString& ImageName() const { return fPath; } + + virtual bool operator==(const ObjectID& other) const; }; diff --git a/src/apps/debugger/model/Image.h b/src/apps/debugger/model/Image.h index 588557f221..e4882e59d0 100644 --- a/src/apps/debugger/model/Image.h +++ b/src/apps/debugger/model/Image.h @@ -36,7 +36,7 @@ public: Team* GetTeam() const { return fTeam; } image_id ID() const { return fInfo.ImageID(); } - const char* Name() const { return fInfo.Name(); } + const BString& Name() const { return fInfo.Name(); } const ImageInfo& Info() const { return fInfo; } image_type Type() const { return fInfo.Type(); } LocatableFile* ImageFile() const { return fImageFile; } diff --git a/src/apps/debugger/model/ImageInfo.h b/src/apps/debugger/model/ImageInfo.h index a57a0b03b6..2f68021520 100644 --- a/src/apps/debugger/model/ImageInfo.h +++ b/src/apps/debugger/model/ImageInfo.h @@ -31,7 +31,7 @@ public: team_id TeamID() const { return fTeam; } image_id ImageID() const { return fImage; } - const char* Name() const { return fName.String(); } + const BString& Name() const { return fName; } image_type Type() const { return fType; } target_addr_t TextBase() const { return fTextBase; } diff --git a/src/apps/debugger/model/Team.cpp b/src/apps/debugger/model/Team.cpp index 08c588440b..e291c1ead3 100644 --- a/src/apps/debugger/model/Team.cpp +++ b/src/apps/debugger/model/Team.cpp @@ -21,7 +21,6 @@ #include "SpecificImageDebugInfo.h" #include "Statement.h" #include "TeamDebugInfo.h" -#include "UserBreakpoint.h" // #pragma mark - BreakpointByAddressPredicate @@ -58,22 +57,25 @@ Team::Team(team_id teamID, TeamMemory* teamMemory, Architecture* architecture, fArchitecture(architecture), fDebugInfo(debugInfo) { - fDebugInfo->AddReference(); + fDebugInfo->AcquireReference(); } Team::~Team() { + while (UserBreakpoint* userBreakpoint = fUserBreakpoints.RemoveHead()) + userBreakpoint->ReleaseReference(); + for (int32 i = 0; Breakpoint* breakpoint = fBreakpoints.ItemAt(i); i++) - breakpoint->RemoveReference(); + breakpoint->ReleaseReference(); while (Image* image = fImages.RemoveHead()) - image->RemoveReference(); + image->ReleaseReference(); while (Thread* thread = fThreads.RemoveHead()) - thread->RemoveReference(); + thread->ReleaseReference(); - fDebugInfo->RemoveReference(); + fDebugInfo->ReleaseReference(); } @@ -139,7 +141,7 @@ Team::RemoveThread(thread_id threadID) return false; RemoveThread(thread); - thread->RemoveReference(); + thread->ReleaseReference(); return true; } @@ -178,6 +180,9 @@ Team::AddImage(const ImageInfo& imageInfo, LocatableFile* imageFile, return error; } + if (image->Type() == B_APP_IMAGE) + SetName(image->Name()); + fImages.Add(image); _NotifyImageAdded(image); @@ -204,7 +209,7 @@ Team::RemoveImage(image_id imageID) return false; RemoveImage(image); - image->RemoveReference(); + image->ReleaseReference(); return true; } @@ -248,7 +253,7 @@ Team::AddBreakpoint(Breakpoint* breakpoint) if (fBreakpoints.BinaryInsert(breakpoint, &Breakpoint::CompareBreakpoints)) return true; - breakpoint->RemoveReference(); + breakpoint->ReleaseReference(); return false; } @@ -262,7 +267,7 @@ Team::RemoveBreakpoint(Breakpoint* breakpoint) return; fBreakpoints.RemoveItemAt(index); - breakpoint->RemoveReference(); + breakpoint->ReleaseReference(); } @@ -334,12 +339,28 @@ Team::GetBreakpointsForSourceCode(SourceCode* sourceCode, UserBreakpoint* userBreakpoint = userBreakpointInstance->GetUserBreakpoint(); - if (userBreakpoint->GetFunction()->SourceFile() == sourceFile) + if (userBreakpoint->Location().SourceFile() == sourceFile) breakpoints.AddItem(userBreakpoint); } } +void +Team::AddUserBreakpoint(UserBreakpoint* userBreakpoint) +{ + fUserBreakpoints.Add(userBreakpoint); + userBreakpoint->AcquireReference(); +} + + +void +Team::RemoveUserBreakpoint(UserBreakpoint* userBreakpoint) +{ + fUserBreakpoints.Remove(userBreakpoint); + userBreakpoint->ReleaseReference(); +} + + status_t Team::GetStatementAtAddress(target_addr_t address, FunctionInstance*& _function, Statement*& _statement) @@ -436,7 +457,13 @@ printf("Team::GetStatementAtSourceLocation(%p, (%ld, %ld))\n", sourceCode, locat = functionInstance->GetFunctionDebugInfo(); return functionDebugInfo->GetSpecificImageDebugInfo() ->GetStatementAtSourceLocation(functionDebugInfo, location, _statement); +} + +Function* +Team::FunctionByID(FunctionID* functionID) const +{ + return fDebugInfo->FunctionByID(functionID); } diff --git a/src/apps/debugger/model/Team.h b/src/apps/debugger/model/Team.h index d98703eae2..fcb6041671 100644 --- a/src/apps/debugger/model/Team.h +++ b/src/apps/debugger/model/Team.h @@ -15,6 +15,7 @@ #include "TargetAddressRange.h" #include "Thread.h" #include "ThreadInfo.h" +#include "UserBreakpoint.h" // team event types @@ -38,6 +39,7 @@ enum { class Architecture; class Breakpoint; +class Function; class FunctionID; class FunctionInstance; class LocatableFile; @@ -46,7 +48,6 @@ class SourceLocation; class Statement; class TeamDebugInfo; class TeamMemory; -class UserBreakpoint; class Team { @@ -112,6 +113,13 @@ public: BObjectList& breakpoints) const; + void AddUserBreakpoint( + UserBreakpoint* userBreakpoint); + void RemoveUserBreakpoint( + UserBreakpoint* userBreakpoint); + const UserBreakpointList& UserBreakpoints() const + { return fUserBreakpoints; } + status_t GetStatementAtAddress(target_addr_t address, FunctionInstance*& _function, Statement*& _statement); @@ -126,6 +134,8 @@ public: // (any matching statement!), // caller must lock, + Function* FunctionByID(FunctionID* functionID) const; + void AddListener(Listener* listener); void RemoveListener(Listener* listener); @@ -166,6 +176,7 @@ private: ThreadList fThreads; ImageList fImages; BreakpointList fBreakpoints; + UserBreakpointList fUserBreakpoints; ListenerList fListeners; }; diff --git a/src/apps/debugger/model/UserBreakpoint.cpp b/src/apps/debugger/model/UserBreakpoint.cpp index da2420e27a..0fa577931b 100644 --- a/src/apps/debugger/model/UserBreakpoint.cpp +++ b/src/apps/debugger/model/UserBreakpoint.cpp @@ -3,9 +3,73 @@ * Distributed under the terms of the MIT License. */ + #include "UserBreakpoint.h" #include "Function.h" +#include "FunctionID.h" +#include "LocatableFile.h" + + +// #pragma mark - UserBreakpointLocation + + +UserBreakpointLocation::UserBreakpointLocation(FunctionID* functionID, + LocatableFile* sourceFile, const SourceLocation& sourceLocation, + target_addr_t relativeAddress) + : + fFunctionID(functionID), + fSourceFile(sourceFile), + fSourceLocation(sourceLocation), + fRelativeAddress(relativeAddress) +{ + fFunctionID->AcquireReference(); + if (fSourceFile != NULL) + fSourceFile->AcquireReference(); +} + + +UserBreakpointLocation::UserBreakpointLocation( + const UserBreakpointLocation& other) + : + fFunctionID(other.fFunctionID), + fSourceFile(other.fSourceFile), + fSourceLocation(other.fSourceLocation), + fRelativeAddress(other.fRelativeAddress) +{ + fFunctionID->AcquireReference(); + if (fSourceFile != NULL) + fSourceFile->AcquireReference(); +} + + +UserBreakpointLocation::~UserBreakpointLocation() +{ + fFunctionID->ReleaseReference(); + if (fSourceFile != NULL) + fSourceFile->ReleaseReference(); +} + + +UserBreakpointLocation& +UserBreakpointLocation::operator=( + const UserBreakpointLocation& other) +{ + other.fFunctionID->AcquireReference(); + if (other.fSourceFile != NULL) + other.fSourceFile->AcquireReference(); + + fFunctionID->ReleaseReference(); + if (fSourceFile != NULL) + fSourceFile->ReleaseReference(); + + fFunctionID = other.fFunctionID; + fSourceFile = other.fSourceFile; + fSourceLocation = other.fSourceLocation; + fRelativeAddress = other.fRelativeAddress; + + return *this; +} // #pragma mark - UserBreakpointInstance @@ -31,13 +95,12 @@ UserBreakpointInstance::SetBreakpoint(Breakpoint* breakpoint) // #pragma mark - UserBreakpoint -UserBreakpoint::UserBreakpoint(Function* function) +UserBreakpoint::UserBreakpoint(const UserBreakpointLocation& location) : - fFunction(function), + fLocation(location), fValid(false), fEnabled(false) { - fFunction->AcquireReference(); } @@ -47,8 +110,6 @@ UserBreakpoint::~UserBreakpoint() i++) { delete instance; } - - fFunction->ReleaseReference(); } @@ -80,6 +141,13 @@ UserBreakpoint::RemoveInstance(UserBreakpointInstance* instance) } +UserBreakpointInstance* +UserBreakpoint::RemoveInstanceAt(int32 index) +{ + return fInstances.RemoveItemAt(index); +} + + void UserBreakpoint::SetValid(bool valid) { diff --git a/src/apps/debugger/model/UserBreakpoint.h b/src/apps/debugger/model/UserBreakpoint.h index b176580e09..0456f69f0f 100644 --- a/src/apps/debugger/model/UserBreakpoint.h +++ b/src/apps/debugger/model/UserBreakpoint.h @@ -5,18 +5,50 @@ #ifndef USER_BREAKPOINT_H #define USER_BREAKPOINT_H + #include #include #include +#include "SourceLocation.h" #include "Types.h" class Breakpoint; class Function; +class FunctionID; +class LocatableFile; class UserBreakpoint; +class UserBreakpointLocation { +public: + UserBreakpointLocation(FunctionID* functionID, + LocatableFile* sourceFile, + const SourceLocation& sourceLocation, + target_addr_t relativeAddress); + UserBreakpointLocation( + const UserBreakpointLocation& other); + virtual ~UserBreakpointLocation(); + + FunctionID* GetFunctionID() const { return fFunctionID; } + LocatableFile* SourceFile() const { return fSourceFile; } + SourceLocation GetSourceLocation() const + { return fSourceLocation; } + target_addr_t RelativeAddress() const + { return fRelativeAddress; } + + UserBreakpointLocation& operator=( + const UserBreakpointLocation& other); + +private: + FunctionID* fFunctionID; + LocatableFile* fSourceFile; + SourceLocation fSourceLocation; + target_addr_t fRelativeAddress; +}; + + class UserBreakpointInstance : public DoublyLinkedListLinkImpl { public: @@ -41,12 +73,14 @@ private: typedef DoublyLinkedList UserBreakpointInstanceList; -class UserBreakpoint : public Referenceable { +class UserBreakpoint : public Referenceable, + public DoublyLinkedListLinkImpl { public: - UserBreakpoint(Function* function); + UserBreakpoint( + const UserBreakpointLocation& location); ~UserBreakpoint(); - Function* GetFunction() const { return fFunction; } + const UserBreakpointLocation& Location() const { return fLocation; } int32 CountInstances() const; UserBreakpointInstance* InstanceAt(int32 index) const; @@ -56,6 +90,7 @@ public: bool AddInstance(UserBreakpointInstance* instance); void RemoveInstance( UserBreakpointInstance* instance); + UserBreakpointInstance* RemoveInstanceAt(int32 index); bool IsValid() const { return fValid; } void SetValid(bool valid); @@ -69,11 +104,14 @@ private: typedef BObjectList InstanceList; private: - Function* fFunction; + UserBreakpointLocation fLocation; InstanceList fInstances; bool fValid; bool fEnabled; }; +typedef DoublyLinkedList UserBreakpointList; + + #endif // USER_BREAKPOINT_H diff --git a/src/apps/debugger/settings/BreakpointSetting.cpp b/src/apps/debugger/settings/BreakpointSetting.cpp new file mode 100644 index 0000000000..4a738f5627 --- /dev/null +++ b/src/apps/debugger/settings/BreakpointSetting.cpp @@ -0,0 +1,155 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + + +#include "BreakpointSetting.h" + +#include + +#include "ArchivingUtils.h" +#include "FunctionID.h" +#include "LocatableFile.h" +#include "UserBreakpoint.h" + + +BreakpointSetting::BreakpointSetting() + : + fFunctionID(NULL), + fSourceFile(), + fSourceLocation(), + fRelativeAddress(0), + fEnabled(false) +{ +} + + +BreakpointSetting::BreakpointSetting(const BreakpointSetting& other) + : + fFunctionID(other.fFunctionID), + fSourceFile(other.fSourceFile), + fSourceLocation(other.fSourceLocation), + fRelativeAddress(other.fRelativeAddress), + fEnabled(other.fEnabled) +{ + if (fFunctionID != NULL) + fFunctionID->AcquireReference(); +} + + +BreakpointSetting::~BreakpointSetting() +{ + _Unset(); +} + + +status_t +BreakpointSetting::SetTo(const UserBreakpointLocation& location, bool enabled) +{ + _Unset(); + + fFunctionID = location.GetFunctionID(); + if (fFunctionID != NULL) + fFunctionID->AcquireReference(); + + if (LocatableFile* file = location.SourceFile()) + file->GetPath(fSourceFile); + + fSourceLocation = location.GetSourceLocation(); + fRelativeAddress = location.RelativeAddress(); + fEnabled = enabled; + + return B_OK; +} + + +status_t +BreakpointSetting::SetTo(const BMessage& archive) +{ + _Unset(); + + fFunctionID = ArchivingUtils::UnarchiveChild(archive, + "function"); + if (fFunctionID == NULL) + return B_BAD_VALUE; + + archive.FindString("sourceFile", &fSourceFile); + + int32 line; + if (archive.FindInt32("line", &line) != B_OK) + line = -1; + + int32 column; + if (archive.FindInt32("column", &column) != B_OK) + column = -1; + + fSourceLocation = SourceLocation(line, column); + + if (archive.FindUInt64("relativeAddress", &fRelativeAddress) != B_OK) + fRelativeAddress = 0; + + if (archive.FindBool("enabled", &fEnabled) != B_OK) + fEnabled = false; + + return B_OK; +} + + +status_t +BreakpointSetting::WriteTo(BMessage& archive) const +{ + if (fFunctionID == NULL) + return B_BAD_VALUE; + + status_t error; + if ((error = ArchivingUtils::ArchiveChild(fFunctionID, archive, "function")) + != B_OK + || (error = archive.AddString("sourceFile", fSourceFile)) != B_OK + || (error = archive.AddInt32("line", fSourceLocation.Line())) != B_OK + || (error = archive.AddInt32("column", fSourceLocation.Column())) + != B_OK + || (error = archive.AddUInt64("relativeAddress", fRelativeAddress)) + != B_OK + || (error = archive.AddBool("enabled", fEnabled)) != B_OK) { + return error; + } + + return B_OK; +} + + +BreakpointSetting& +BreakpointSetting::operator=(const BreakpointSetting& other) +{ + if (this == &other) + return *this; + + _Unset(); + + fFunctionID = other.fFunctionID; + if (fFunctionID != NULL) + fFunctionID->AcquireReference(); + + fSourceFile = other.fSourceFile; + fSourceLocation = other.fSourceLocation; + fRelativeAddress = other.fRelativeAddress; + fEnabled = other.fEnabled; + + return *this; +} + + +void +BreakpointSetting::_Unset() +{ + if (fFunctionID != NULL) { + fFunctionID->ReleaseReference(); + fFunctionID = NULL; + } + + fSourceFile.Truncate(0); + fSourceLocation = SourceLocation(); + fRelativeAddress = 0; + fEnabled = false; +} diff --git a/src/apps/debugger/settings/BreakpointSetting.h b/src/apps/debugger/settings/BreakpointSetting.h new file mode 100644 index 0000000000..964a0e552f --- /dev/null +++ b/src/apps/debugger/settings/BreakpointSetting.h @@ -0,0 +1,57 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef BREAKPOINT_SETTING_H +#define BREAKPOINT_SETTING_H + + +#include + +#include + +#include "SourceLocation.h" +#include "Types.h" + + +class BMessage; +class FunctionID; +class UserBreakpointLocation; + + +class BreakpointSetting { +public: + BreakpointSetting(); + BreakpointSetting( + const BreakpointSetting& other); + ~BreakpointSetting(); + + status_t SetTo(const UserBreakpointLocation& location, + bool enabled); + status_t SetTo(const BMessage& archive); + status_t WriteTo(BMessage& archive) const; + + FunctionID* GetFunctionID() const { return fFunctionID; } + const BString& SourceFile() const { return fSourceFile; } + SourceLocation GetSourceLocation() const + { return fSourceLocation; } + target_addr_t RelativeAddress() const + { return fRelativeAddress; } + + bool IsEnabled() const { return fEnabled; } + + BreakpointSetting& operator=(const BreakpointSetting& other); + +private: + void _Unset(); + +private: + FunctionID* fFunctionID; + BString fSourceFile; + SourceLocation fSourceLocation; + target_addr_t fRelativeAddress; + bool fEnabled; +}; + + +#endif // BREAKPOINT_SETTING_H diff --git a/src/apps/debugger/settings/SettingsManager.cpp b/src/apps/debugger/settings/SettingsManager.cpp new file mode 100644 index 0000000000..c3a56cc59d --- /dev/null +++ b/src/apps/debugger/settings/SettingsManager.cpp @@ -0,0 +1,207 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + + +#include "SettingsManager.h" + +#include + +#include +#include +#include + +#include +#include + +#include "TeamSettings.h" + + +static const char* const kSettingsDirPath = "Debugger"; +static const char* const kGlobalSettingsName = "Global"; +static const int32 kMaxRecentTeamSettings = 10; + + +SettingsManager::SettingsManager() + : + fLock("settings manager"), + fRecentTeamSettings(kMaxRecentTeamSettings, true) +{ +} + + +SettingsManager::~SettingsManager() +{ + _Unset(); +} + + +status_t +SettingsManager::Init() +{ + // check the lock + status_t error = fLock.InitCheck(); + if (error != B_OK) + return error; + + // get and create our settings directory + if (find_directory(B_USER_SETTINGS_DIRECTORY, &fSettingsPath, true) == B_OK + && fSettingsPath.Append(kSettingsDirPath) == B_OK + && create_directory(fSettingsPath.Path(), 0700) == B_OK + && fSettingsPath.Append(kGlobalSettingsName) == B_OK) { + // load the settings + _LoadSettings(); + } else { + // something went wrong -- clear the path + fSettingsPath.Unset(); + } + + return B_OK; +} + + +status_t +SettingsManager::LoadTeamSettings(const char* teamName, TeamSettings& settings) +{ + AutoLocker locker(fLock); + + int32 index = _TeamSettingsIndex(teamName); + if (index < 0) + return B_ENTRY_NOT_FOUND; + + try { + settings = *fRecentTeamSettings.ItemAt(index); + return B_OK; + } catch (std::bad_alloc) { + return B_NO_MEMORY; + } +} + + +status_t +SettingsManager::SaveTeamSettings(const TeamSettings& _settings) +{ + AutoLocker locker(fLock); + + TeamSettings* settings; + int32 index = _TeamSettingsIndex(_settings.TeamName()); + if (index >= 0) { + settings = fRecentTeamSettings.RemoveItemAt(index); + } else { + settings = new(std::nothrow) TeamSettings; + if (settings == NULL) + return B_NO_MEMORY; + + // enforce recent limit + while (fRecentTeamSettings.CountItems() >= kMaxRecentTeamSettings) + delete fRecentTeamSettings.RemoveItemAt(0); + + } + ObjectDeleter settingsDeleter(settings); + + try { + *settings = _settings; + if (!fRecentTeamSettings.AddItem(settings)) + return B_NO_MEMORY; + settingsDeleter.Detach(); + + return _SaveSettings(); + } catch (std::bad_alloc) { + return B_NO_MEMORY; + } +} + + +void +SettingsManager::_Unset() +{ + fRecentTeamSettings.MakeEmpty(); +} + + +status_t +SettingsManager::_LoadSettings() +{ + _Unset(); + + if (fSettingsPath.Path() == NULL) + return B_ENTRY_NOT_FOUND; + + // read the settings file + BFile file; + status_t error = file.SetTo(fSettingsPath.Path(), B_READ_ONLY); + if (error != B_OK) + return error; + + BMessage archive; + error = archive.Unflatten(&file); + if (error != B_OK) + return error; + + // unarchive the recent team settings + BMessage childArchive; + for (int32 i = 0; archive.FindMessage("teamSettings", i, &childArchive) + == B_OK; i++) { + TeamSettings* settings = new(std::nothrow) TeamSettings; + if (settings == NULL) + return B_NO_MEMORY; + + error = settings->SetTo(childArchive); + if (error != B_OK) { + delete settings; + continue; + } + + if (!fRecentTeamSettings.AddItem(settings)) { + delete settings; + return B_NO_MEMORY; + } + } + + return B_OK; +} + + +status_t +SettingsManager::_SaveSettings() +{ + if (fSettingsPath.Path() == NULL) + return B_ENTRY_NOT_FOUND; + + // archive the recent team settings + BMessage archive; + for (int32 i = 0; TeamSettings* settings = fRecentTeamSettings.ItemAt(i); + i++) { + BMessage childArchive; + status_t error = settings->WriteTo(childArchive); + if (error != B_OK) + return error; + + error = archive.AddMessage("teamSettings", &childArchive); + if (error != B_OK) + return error; + } + + // open the settings file + BFile file; + status_t error = file.SetTo(fSettingsPath.Path(), + B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE); + if (error != B_OK) + return error; + + return archive.Flatten(&file); +} + + +int32 +SettingsManager::_TeamSettingsIndex(const char* teamName) const +{ + for (int32 i = 0; TeamSettings* settings = fRecentTeamSettings.ItemAt(i); + i++) { + if (settings->TeamName() == teamName) + return i; + } + + return -1; +} diff --git a/src/apps/debugger/settings/SettingsManager.h b/src/apps/debugger/settings/SettingsManager.h new file mode 100644 index 0000000000..6dc9465152 --- /dev/null +++ b/src/apps/debugger/settings/SettingsManager.h @@ -0,0 +1,47 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef SETTINGS_MANAGER_H +#define SETTINGS_MANAGER_H + + +#include +#include + +#include + + +class TeamSettings; + + +class SettingsManager { +public: + SettingsManager(); + ~SettingsManager(); + + status_t Init(); + + status_t LoadTeamSettings(const char* teamName, + TeamSettings& settings); + status_t SaveTeamSettings(const TeamSettings& settings); + +private: + typedef BObjectList TeamSettingsList; + +private: + void _Unset(); + + status_t _LoadSettings(); + status_t _SaveSettings(); + + int32 _TeamSettingsIndex(const char* teamName) const; + +private: + BLocker fLock; + BPath fSettingsPath; + TeamSettingsList fRecentTeamSettings; // oldest is first +}; + + +#endif // SETTINGS_MANAGER_H diff --git a/src/apps/debugger/settings/TeamSettings.cpp b/src/apps/debugger/settings/TeamSettings.cpp new file mode 100644 index 0000000000..723cd12f71 --- /dev/null +++ b/src/apps/debugger/settings/TeamSettings.cpp @@ -0,0 +1,177 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + + +#include "TeamSettings.h" + +#include + +#include + +#include + +#include "ArchivingUtils.h" +#include "BreakpointSetting.h" +#include "Team.h" +#include "UserBreakpoint.h" + + +TeamSettings::TeamSettings() +{ +} + + +TeamSettings::TeamSettings(const TeamSettings& other) +{ + try { + *this = other; + } catch (...) { + _Unset(); + throw; + } +} + + +TeamSettings::~TeamSettings() +{ + _Unset(); +} + + +status_t +TeamSettings::SetTo(Team* team) +{ + _Unset(); + + AutoLocker locker(team); + + fTeamName = team->Name(); + + // add breakpoints + for (UserBreakpointList::ConstIterator it + = team->UserBreakpoints().GetIterator(); + UserBreakpoint* breakpoint = it.Next();) { + BreakpointSetting* breakpointSetting + = new(std::nothrow) BreakpointSetting; + if (breakpointSetting == NULL) + return B_NO_MEMORY; + + status_t error = breakpointSetting->SetTo(breakpoint->Location(), + breakpoint->IsEnabled()); + if (error == B_OK && !fBreakpoints.AddItem(breakpointSetting)) + error = B_NO_MEMORY; + if (error != B_OK) { + delete breakpointSetting; + return error; + } + } + + return B_OK; +} + + +status_t +TeamSettings::SetTo(const BMessage& archive) +{ + _Unset(); + + status_t error = archive.FindString("teamName", &fTeamName); + if (error != B_OK) + return error; + + // add breakpoints + BMessage childArchive; + for (int32 i = 0; archive.FindMessage("breakpoints", i, &childArchive) + == B_OK; i++) { + BreakpointSetting* breakpointSetting + = new(std::nothrow) BreakpointSetting; + if (breakpointSetting == NULL) + return B_NO_MEMORY; + + error = breakpointSetting->SetTo(childArchive); + if (error == B_OK && !fBreakpoints.AddItem(breakpointSetting)) + error = B_NO_MEMORY; + if (error != B_OK) { + delete breakpointSetting; + return error; + } + } + + return B_OK; +} + + +status_t +TeamSettings::WriteTo(BMessage& archive) const +{ + status_t error = archive.AddString("teamName", fTeamName); + if (error != B_OK) + return error; + + for (int32 i = 0; BreakpointSetting* breakpoint = fBreakpoints.ItemAt(i); + i++) { + BMessage childArchive; + error = breakpoint->WriteTo(childArchive); + if (error != B_OK) + return error; + + error = archive.AddMessage("breakpoints", &childArchive); + if (error != B_OK) + return error; + } + + return B_OK; +} + + +int32 +TeamSettings::CountBreakpoints() const +{ + return fBreakpoints.CountItems(); +} + + +const BreakpointSetting* +TeamSettings::BreakpointAt(int32 index) const +{ + return fBreakpoints.ItemAt(index); +} + + +TeamSettings& +TeamSettings::operator=(const TeamSettings& other) +{ + if (this == &other) + return *this; + + _Unset(); + + fTeamName = other.fTeamName; + + for (int32 i = 0; BreakpointSetting* breakpoint + = other.fBreakpoints.ItemAt(i); i++) { + BreakpointSetting* clonedBreakpoint + = new BreakpointSetting(*breakpoint); + if (!fBreakpoints.AddItem(clonedBreakpoint)) { + delete clonedBreakpoint; + throw std::bad_alloc(); + } + } + + return *this; +} + + +void +TeamSettings::_Unset() +{ + for (int32 i = 0; BreakpointSetting* breakpoint = fBreakpoints.ItemAt(i); + i++) { + delete breakpoint; + } + fBreakpoints.MakeEmpty(); + + fTeamName.Truncate(0); +} diff --git a/src/apps/debugger/settings/TeamSettings.h b/src/apps/debugger/settings/TeamSettings.h new file mode 100644 index 0000000000..3b66c5e2da --- /dev/null +++ b/src/apps/debugger/settings/TeamSettings.h @@ -0,0 +1,50 @@ +/* + * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef TEAM_SETTINGS_H +#define TEAM_SETTINGS_H + + +#include + +#include + + +class BMessage; +class Team; +class BreakpointSetting; + + +class TeamSettings { +public: + TeamSettings(); + TeamSettings(const TeamSettings& other); + // throws std::bad_alloc + ~TeamSettings(); + + status_t SetTo(Team* team); + status_t SetTo(const BMessage& archive); + status_t WriteTo(BMessage& archive) const; + + const BString& TeamName() const { return fTeamName; } + + int32 CountBreakpoints() const; + const BreakpointSetting* BreakpointAt(int32 index) const; + + TeamSettings& operator=(const TeamSettings& other); + // throws std::bad_alloc + +private: + typedef BObjectList BreakpointList; + +private: + void _Unset(); + +private: + BreakpointList fBreakpoints; + BString fTeamName; +}; + + +#endif // TEAM_SETTINGS_H