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