* 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:
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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',
|
||||
|
||||
|
||||
@@ -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,...)
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user