* 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
This commit is contained in:
Ingo Weinhold
2009-07-24 02:35:30 +00:00
parent 79a9dc4460
commit 2bf55b39a5
27 changed files with 1480 additions and 67 deletions
+175 -7
View File
@@ -12,6 +12,9 @@
#include <AutoLocker.h>
#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<BLocker> installLocker(fLock);
AutoLocker<Team> teamLocker(fTeam);
// remove obsolete user breakpoint instances
BObjectList<Breakpoint> 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<UserBreakpointInstance> 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)
{
+5 -4
View File
@@ -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
+16 -1
View File
@@ -3,6 +3,7 @@
* Distributed under the terms of the MIT License.
*/
#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
@@ -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;
}
+7
View File
@@ -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
+1
View File
@@ -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',
+137 -7
View File
@@ -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<BLooper> 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<ImageHandler> 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<Image> 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<FunctionID> 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<LocatableFile> 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<UserBreakpoint> 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,...)
{
+10 -1
View File
@@ -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;
@@ -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());
}
@@ -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
@@ -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;
+57 -1
View File
@@ -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<SourceFileEntry> {
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<Function> 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<SourceFunctionID*>(functionID)) {
// get the source file
LocatableFile* file = fFileManager->GetSourceFile(
sourceFunctionID->SourceFilePath());
if (file == NULL)
return NULL;
Reference<LocatableFile> fileReference(file, true);
if (SourceFileEntry* entry = fSourceFiles->Lookup(file))
return entry->FunctionByName(functionID->FunctionName());
return NULL;
}
ImageFunctionID* imageFunctionID
= dynamic_cast<ImageFunctionID*>(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)
{
+4 -2
View File
@@ -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;
@@ -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());
+142 -7
View File
@@ -6,12 +6,29 @@
#include "FunctionID.h"
#include <new>
#include <Message.h>
#include "StringUtils.h"
FunctionID::FunctionID(const BString& idString)
// #pragma mark - FunctionID
FunctionID::FunctionID(const BMessage& archive)
:
fIDString(idString)
BArchivable(const_cast<BMessage*>(&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<const FunctionID*>(&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<const SourceFunctionID*>(
&_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<const ImageFunctionID*>(
&_other);
return other != NULL && fPath == other->fPath
&& fFunctionName == other->fFunctionName;
}
+46 -5
View File
@@ -6,23 +6,64 @@
#define FUNCTION_ID_H
#include <Archivable.h>
#include <String.h>
#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;
};
+1 -1
View File
@@ -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; }
+1 -1
View File
@@ -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; }
+38 -11
View File
@@ -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);
}
+12 -1
View File
@@ -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<UserBreakpoint>& 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;
};
+73 -5
View File
@@ -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)
{
+42 -4
View File
@@ -5,18 +5,50 @@
#ifndef USER_BREAKPOINT_H
#define USER_BREAKPOINT_H
#include <ObjectList.h>
#include <Referenceable.h>
#include <util/DoublyLinkedList.h>
#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<UserBreakpointInstance> {
public:
@@ -41,12 +73,14 @@ private:
typedef DoublyLinkedList<UserBreakpointInstance> UserBreakpointInstanceList;
class UserBreakpoint : public Referenceable {
class UserBreakpoint : public Referenceable,
public DoublyLinkedListLinkImpl<UserBreakpoint> {
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<UserBreakpointInstance> InstanceList;
private:
Function* fFunction;
UserBreakpointLocation fLocation;
InstanceList fInstances;
bool fValid;
bool fEnabled;
};
typedef DoublyLinkedList<UserBreakpoint> UserBreakpointList;
#endif // USER_BREAKPOINT_H
@@ -0,0 +1,155 @@
/*
* Copyright 2009, Ingo Weinhold, [email protected].
* Distributed under the terms of the MIT License.
*/
#include "BreakpointSetting.h"
#include <Message.h>
#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<FunctionID>(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;
}
@@ -0,0 +1,57 @@
/*
* Copyright 2009, Ingo Weinhold, [email protected].
* Distributed under the terms of the MIT License.
*/
#ifndef BREAKPOINT_SETTING_H
#define BREAKPOINT_SETTING_H
#include <String.h>
#include <ObjectList.h>
#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
@@ -0,0 +1,207 @@
/*
* Copyright 2009, Ingo Weinhold, [email protected].
* Distributed under the terms of the MIT License.
*/
#include "SettingsManager.h"
#include <new>
#include <Directory.h>
#include <File.h>
#include <FindDirectory.h>
#include <AutoDeleter.h>
#include <AutoLocker.h>
#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<BLocker> 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<BLocker> 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<TeamSettings> 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;
}
@@ -0,0 +1,47 @@
/*
* Copyright 2009, Ingo Weinhold, [email protected].
* Distributed under the terms of the MIT License.
*/
#ifndef SETTINGS_MANAGER_H
#define SETTINGS_MANAGER_H
#include <Locker.h>
#include <Path.h>
#include <ObjectList.h>
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<TeamSettings> 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
+177
View File
@@ -0,0 +1,177 @@
/*
* Copyright 2009, Ingo Weinhold, [email protected].
* Distributed under the terms of the MIT License.
*/
#include "TeamSettings.h"
#include <new>
#include <Message.h>
#include <AutoLocker.h>
#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<Team> 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);
}
+50
View File
@@ -0,0 +1,50 @@
/*
* Copyright 2009, Ingo Weinhold, [email protected].
* Distributed under the terms of the MIT License.
*/
#ifndef TEAM_SETTINGS_H
#define TEAM_SETTINGS_H
#include <String.h>
#include <ObjectList.h>
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<BreakpointSetting> BreakpointList;
private:
void _Unset();
private:
BreakpointList fBreakpoints;
BString fTeamName;
};
#endif // TEAM_SETTINGS_H