root/src/kits/debugger/controllers/TeamDebugger.cpp
/*
 * Copyright 2009-2012, Ingo Weinhold, ingo_weinhold@gmx.de.
 * Copyright 2010-2017, Rene Gollent, rene@gollent.com.
 * Distributed under the terms of the MIT License.
 */


#include "controllers/TeamDebugger.h"

#include <stdarg.h>
#include <stdio.h>

#include <new>

#include <Entry.h>
#include <InterfaceDefs.h>
#include <Message.h>
#include <StringList.h>

#include <AutoDeleter.h>
#include <AutoLocker.h>

#include "debug_utils.h"
#include "syscall_numbers.h"

#include "Architecture.h"
#include "BreakpointManager.h"
#include "BreakpointSetting.h"
#include "CpuState.h"
#include "DebugEvent.h"
#include "DebuggerInterface.h"
#include "DebugReportGenerator.h"
#include "ExpressionInfo.h"
#include "FileManager.h"
#include "Function.h"
#include "FunctionID.h"
#include "ImageDebugInfo.h"
#include "ImageDebugInfoLoadingState.h"
#include "ImageDebugLoadingStateHandler.h"
#include "ImageDebugLoadingStateHandlerRoster.h"
#include "Jobs.h"
#include "LocatableFile.h"
#include "MessageCodes.h"
#include "NoOpSettingsManager.h"
#include "SettingsManager.h"
#include "SourceCode.h"
#include "SourceLanguage.h"
#include "SpecificImageDebugInfo.h"
#include "SpecificImageDebugInfoLoadingState.h"
#include "StackFrame.h"
#include "StackFrameValues.h"
#include "Statement.h"
#include "SymbolInfo.h"
#include "TeamDebugInfo.h"
#include "TeamInfo.h"
#include "TeamMemoryBlock.h"
#include "TeamMemoryBlockManager.h"
#include "TeamSettings.h"
#include "TeamSignalSettings.h"
#include "TeamUiSettings.h"
#include "Tracing.h"
#include "ValueNode.h"
#include "ValueNodeContainer.h"
#include "Variable.h"
#include "WatchpointManager.h"


// #pragma mark - ImageHandler


struct TeamDebugger::ImageHandler : public BReferenceable,
        private LocatableFile::Listener {
public:
        ImageHandler(TeamDebugger* teamDebugger, Image* image)
                :
                fTeamDebugger(teamDebugger),
                fImage(image)
        {
                fImage->AcquireReference();
                if (fImage->ImageFile() != NULL)
                        fImage->ImageFile()->AddListener(this);
        }

        ~ImageHandler()
        {
                if (fImage->ImageFile() != NULL)
                        fImage->ImageFile()->RemoveListener(this);
                fImage->ReleaseReference();
        }

        Image* GetImage() const
        {
                return fImage;
        }

        image_id ImageID() const
        {
                return fImage->ID();
        }

private:
        // LocatableFile::Listener
        virtual void LocatableFileChanged(LocatableFile* file)
        {
                BMessage message(MSG_IMAGE_FILE_CHANGED);
                message.AddInt32("image", fImage->ID());
                fTeamDebugger->PostMessage(&message);
        }

private:
        TeamDebugger*   fTeamDebugger;
        Image*                  fImage;

public:
        ImageHandler*   fNext;
};


// #pragma mark - ImageHandlerHashDefinition


struct TeamDebugger::ImageHandlerHashDefinition {
        typedef image_id                KeyType;
        typedef ImageHandler    ValueType;

        size_t HashKey(image_id key) const
        {
                return (size_t)key;
        }

        size_t Hash(const ImageHandler* value) const
        {
                return HashKey(value->ImageID());
        }

        bool Compare(image_id key, const ImageHandler* value) const
        {
                return value->ImageID() == key;
        }

        ImageHandler*& GetLink(ImageHandler* value) const
        {
                return value->fNext;
        }
};


// #pragma mark - ImageInfoPendingThread


struct TeamDebugger::ImageInfoPendingThread {
public:
        ImageInfoPendingThread(image_id image, thread_id thread)
                :
                fImage(image),
                fThread(thread)
        {
        }

        ~ImageInfoPendingThread()
        {
        }

        image_id ImageID() const
        {
                return fImage;
        }

        thread_id ThreadID() const
        {
                return fThread;
        }

private:
        image_id                                fImage;
        thread_id                               fThread;

public:
        ImageInfoPendingThread* fNext;
};


// #pragma mark - ImageHandlerHashDefinition


struct TeamDebugger::ImageInfoPendingThreadHashDefinition {
        typedef image_id                                KeyType;
        typedef ImageInfoPendingThread  ValueType;

        size_t HashKey(image_id key) const
        {
                return (size_t)key;
        }

        size_t Hash(const ImageInfoPendingThread* value) const
        {
                return HashKey(value->ImageID());
        }

        bool Compare(image_id key, const ImageInfoPendingThread* value) const
        {
                return value->ImageID() == key;
        }

        ImageInfoPendingThread*& GetLink(ImageInfoPendingThread* value) const
        {
                return value->fNext;
        }
};


// #pragma mark - TeamDebugger


TeamDebugger::TeamDebugger(Listener* listener, UserInterface* userInterface,
        SettingsManager* settingsManager)
        :
        BLooper("team debugger"),
        fListener(listener),
        fSettingsManager(settingsManager),
        fTeam(NULL),
        fTeamID(-1),
        fIsPostMortem(false),
        fImageHandlers(NULL),
        fImageInfoPendingThreads(NULL),
        fDebuggerInterface(NULL),
        fFileManager(NULL),
        fWorker(NULL),
        fBreakpointManager(NULL),
        fWatchpointManager(NULL),
        fMemoryBlockManager(NULL),
        fReportGenerator(NULL),
        fDebugEventListener(-1),
        fUserInterface(userInterface),
        fTerminating(false),
        fKillTeamOnQuit(false),
        fCommandLineArgc(0),
        fCommandLineArgv(NULL),
        fExecPending(false)
{
        fUserInterface->AcquireReference();
}


TeamDebugger::~TeamDebugger()
{
        if (fTeam != NULL)
                _SaveSettings();

        AutoLocker<BLooper> locker(this);

        fTerminating = true;

        if (fDebuggerInterface != NULL) {
                fDebuggerInterface->Close(fKillTeamOnQuit);
                fDebuggerInterface->ReleaseReference();
        }

        if (fWorker != NULL)
                fWorker->ShutDown();

        locker.Unlock();

        if (fDebugEventListener >= 0)
                wait_for_thread(fDebugEventListener, NULL);

        // terminate UI
        if (fUserInterface != NULL) {
                fUserInterface->Terminate();
                fUserInterface->ReleaseReference();
        }

        ThreadHandler* threadHandler = fThreadHandlers.Clear(true);
        while (threadHandler != NULL) {
                ThreadHandler* next = threadHandler->fNext;
                threadHandler->ReleaseReference();
                threadHandler = next;
        }

        if (fImageHandlers != NULL) {
                ImageHandler* imageHandler = fImageHandlers->Clear(true);
                while (imageHandler != NULL) {
                        ImageHandler* next = imageHandler->fNext;
                        imageHandler->ReleaseReference();
                        imageHandler = next;
                }
        }

        delete fImageHandlers;

        if (fImageInfoPendingThreads != NULL) {
                ImageInfoPendingThread* thread = fImageInfoPendingThreads->Clear(true);
                while (thread != NULL) {
                        ImageInfoPendingThread* next = thread->fNext;
                        delete thread;
                        thread = next;
                }
        }

        if (fReportGenerator != NULL) {
                fReportGenerator->Lock();
                fReportGenerator->Quit();
        }

        delete fWorker;

        delete fImageInfoPendingThreads;

        delete fBreakpointManager;
        delete fWatchpointManager;
        delete fMemoryBlockManager;
        delete fTeam;
        delete fFileManager;

        for (int i = 0; i < fCommandLineArgc; i++) {
                if (fCommandLineArgv[i] != NULL)
                        free(const_cast<char*>(fCommandLineArgv[i]));
        }

        delete [] fCommandLineArgv;

        fListener->TeamDebuggerQuit(this);
}


status_t
TeamDebugger::Init(DebuggerInterface* interface, thread_id threadID, int argc,
        const char* const* argv, bool stopInMain)
{
        bool targetIsLocal = true;
                // TODO: Support non-local targets!

        // the first thing we want to do when running
        PostMessage(MSG_LOAD_SETTINGS);

        status_t error = _HandleSetArguments(argc, argv);
        if (error != B_OK)
                return error;

        if (fSettingsManager == NULL) {
                // if we have not been provided with a settings manager,
                // simply use the no-op manager by default.
                fSettingsManager = new(std::nothrow) NoOpSettingsManager;
                if (fSettingsManager == NULL)
                        return B_NO_MEMORY;
        }

        fDebuggerInterface = interface;
        fDebuggerInterface->AcquireReference();
        fTeamID = interface->TeamID();
        fIsPostMortem = interface->IsPostMortem();


        // create file manager
        fFileManager = new(std::nothrow) FileManager;
        if (fFileManager == NULL)
                return B_NO_MEMORY;

        error = fFileManager->Init(targetIsLocal);
        if (error != B_OK)
                return error;

        // create team debug info
        TeamDebugInfo* teamDebugInfo = new(std::nothrow) TeamDebugInfo(
                fDebuggerInterface, fDebuggerInterface->GetArchitecture(),
                fFileManager);
        if (teamDebugInfo == NULL)
                return B_NO_MEMORY;
        BReference<TeamDebugInfo> teamDebugInfoReference(teamDebugInfo, true);

        error = teamDebugInfo->Init();
        if (error != B_OK)
                return error;

        // check whether the team exists at all
        TeamInfo teamInfo;
        error = fDebuggerInterface->GetTeamInfo(teamInfo);
        if (error != B_OK)
                return error;

        // create a team object
        fTeam = new(std::nothrow) ::Team(fTeamID, fDebuggerInterface,
                fDebuggerInterface->GetArchitecture(), teamDebugInfo,
                teamDebugInfo);
        if (fTeam == NULL)
                return B_NO_MEMORY;

        error = fTeam->Init();
        if (error != B_OK)
                return error;
        fTeam->SetName(teamInfo.Arguments());
                // TODO: Set a better name!

        fTeam->AddListener(this);

        // init thread handler table
        error = fThreadHandlers.Init();
        if (error != B_OK)
                return error;

        // create image handler table
        fImageHandlers = new(std::nothrow) ImageHandlerTable;
        if (fImageHandlers == NULL)
                return B_NO_MEMORY;

        error = fImageHandlers->Init();
        if (error != B_OK)
                return error;

        fImageInfoPendingThreads = new(std::nothrow) ImageInfoPendingThreadTable;
        if (fImageInfoPendingThreads == NULL)
                return B_NO_MEMORY;

        // create our worker
        fWorker = new(std::nothrow) Worker;
        if (fWorker == NULL)
                return B_NO_MEMORY;

        error = fWorker->Init();
        if (error != B_OK)
                return error;

        // create the breakpoint manager
        fBreakpointManager = new(std::nothrow) BreakpointManager(fTeam,
                fDebuggerInterface);
        if (fBreakpointManager == NULL)
                return B_NO_MEMORY;

        error = fBreakpointManager->Init();
        if (error != B_OK)
                return error;

        // create the watchpoint manager
        fWatchpointManager = new(std::nothrow) WatchpointManager(fTeam,
                fDebuggerInterface);
        if (fWatchpointManager == NULL)
                return B_NO_MEMORY;

        error = fWatchpointManager->Init();
        if (error != B_OK)
                return error;

        // create the memory block manager
        fMemoryBlockManager = new(std::nothrow) TeamMemoryBlockManager();
        if (fMemoryBlockManager == NULL)
                return B_NO_MEMORY;

        error = fMemoryBlockManager->Init();
        if (error != B_OK)
                return error;

        // create the debug report generator
        fReportGenerator = new(std::nothrow) DebugReportGenerator(fTeam, this,
                fDebuggerInterface);
        if (fReportGenerator == NULL)
                return B_NO_MEMORY;

        error = fReportGenerator->Init();
        if (error != B_OK)
                return error;

        // set team debugging flags
        fDebuggerInterface->SetTeamDebuggingFlags(
                B_TEAM_DEBUG_THREADS | B_TEAM_DEBUG_IMAGES
                        | B_TEAM_DEBUG_POST_SYSCALL | B_TEAM_DEBUG_SIGNALS
                        | B_TEAM_DEBUG_TEAM_CREATION);

        // get the initial state of the team
        AutoLocker< ::Team> teamLocker(fTeam);

        ThreadHandler* mainThreadHandler = NULL;
        {
                BObjectList<ThreadInfo, true> threadInfos(20);
                status_t error = fDebuggerInterface->GetThreadInfos(threadInfos);
                for (int32 i = 0; ThreadInfo* info = threadInfos.ItemAt(i); i++) {
                        ::Thread* thread;
                        error = fTeam->AddThread(*info, &thread);
                        if (error != B_OK)
                                return error;

                        ThreadHandler* handler = new(std::nothrow) ThreadHandler(thread,
                                fWorker, fDebuggerInterface, this, fBreakpointManager);
                        if (handler == NULL)
                                return B_NO_MEMORY;

                        fThreadHandlers.Insert(handler);

                        if (thread->IsMainThread())
                                mainThreadHandler = handler;

                        handler->Init();
                }
        }

        Image* appImage = NULL;
        {
                BObjectList<ImageInfo, true> imageInfos(20);
                status_t error = fDebuggerInterface->GetImageInfos(imageInfos);
                for (int32 i = 0; ImageInfo* info = imageInfos.ItemAt(i); i++) {
                        Image* image;
                        error = _AddImage(*info, &image);
                        if (error != B_OK)
                                return error;
                        if (image->Type() == B_APP_IMAGE)
                                appImage = image;

                        ImageDebugInfoRequested(image);
                }
        }

        // create the debug event listener (for live debugging only)
        if (!fDebuggerInterface->IsPostMortem()) {
                char buffer[128];
                snprintf(buffer, sizeof(buffer), "team %" B_PRId32 " debug listener",
                        fTeamID);
                fDebugEventListener = spawn_thread(_DebugEventListenerEntry, buffer,
                        B_NORMAL_PRIORITY, this);
                if (fDebugEventListener < 0)
                        return fDebugEventListener;

                resume_thread(fDebugEventListener);
        }

        // run looper
        thread_id looperThread = Run();
        if (looperThread < 0)
                return looperThread;

        // init the UI
        error = fUserInterface->Init(fTeam, this);
        if (error != B_OK) {
                ERROR("Error: Failed to init the UI: %s\n", strerror(error));
                return error;
        }

        // if requested, stop the given thread
        if (threadID >= 0 && !fDebuggerInterface->IsPostMortem()) {
                if (stopInMain) {
                        SymbolInfo symbolInfo;
                        if (appImage != NULL && mainThreadHandler != NULL
                                && fDebuggerInterface->GetSymbolInfo(
                                        fTeam->ID(), appImage->ID(), "main", B_SYMBOL_TYPE_TEXT,
                                        symbolInfo) == B_OK) {
                                mainThreadHandler->SetBreakpointAndRun(symbolInfo.Address());
                        }
                } else {
                        debug_thread(threadID);
                                // TODO: Superfluous, if the thread is already stopped.
                }
        }

        fListener->TeamDebuggerStarted(this);

        return B_OK;
}


void
TeamDebugger::Activate()
{
        fUserInterface->Show();
}


void
TeamDebugger::MessageReceived(BMessage* message)
{
        switch (message->what) {
                case MSG_THREAD_RUN:
                case MSG_THREAD_SET_ADDRESS:
                case MSG_THREAD_STOP:
                case MSG_THREAD_STEP_OVER:
                case MSG_THREAD_STEP_INTO:
                case MSG_THREAD_STEP_OUT:
                {
                        int32 threadID;
                        target_addr_t address;
                        if (message->FindInt32("thread", &threadID) != B_OK)
                                break;

                        if (message->FindUInt64("address", &address) != B_OK)
                                address = 0;

                        if (ThreadHandler* handler = _GetThreadHandler(threadID)) {
                                handler->HandleThreadAction(message->what, address);
                                handler->ReleaseReference();
                        }
                        break;
                }

                case MSG_SET_BREAKPOINT:
                case MSG_CLEAR_BREAKPOINT:
                {
                        UserBreakpoint* breakpoint = NULL;
                        BReference<UserBreakpoint> breakpointReference;
                        uint64 address = 0;

                        if (message->FindPointer("breakpoint", (void**)&breakpoint)
                                == B_OK) {
                                breakpointReference.SetTo(breakpoint, true);
                        } else if (message->FindUInt64("address", &address) != B_OK)
                                break;

                        if (message->what == MSG_SET_BREAKPOINT) {
                                bool enabled;
                                if (message->FindBool("enabled", &enabled) != B_OK)
                                        enabled = true;

                                bool hidden;
                                if (message->FindBool("hidden", &hidden) != B_OK)
                                        hidden = false;

                                if (breakpoint != NULL)
                                        _HandleSetUserBreakpoint(breakpoint, enabled);
                                else
                                        _HandleSetUserBreakpoint(address, enabled, hidden);
                        } else {
                                if (breakpoint != NULL)
                                        _HandleClearUserBreakpoint(breakpoint);
                                else
                                        _HandleClearUserBreakpoint(address);
                        }

                        break;
                }

                case MSG_SET_BREAKPOINT_CONDITION:
                {
                        UserBreakpoint* breakpoint = NULL;
                        BReference<UserBreakpoint> breakpointReference;
                        if (message->FindPointer("breakpoint", (void**)&breakpoint)
                                != B_OK) {
                                break;
                        }

                        breakpointReference.SetTo(breakpoint, true);

                        const char* condition;
                        if (message->FindString("condition", &condition) != B_OK)
                                break;

                        AutoLocker< ::Team> teamLocker(fTeam);
                        breakpoint->SetCondition(condition);
                        fTeam->NotifyUserBreakpointChanged(breakpoint);

                        break;
                }

                case MSG_CLEAR_BREAKPOINT_CONDITION:
                {
                        UserBreakpoint* breakpoint = NULL;
                        BReference<UserBreakpoint> breakpointReference;
                        if (message->FindPointer("breakpoint", (void**)&breakpoint)
                                != B_OK)
                                break;

                        breakpointReference.SetTo(breakpoint, true);

                        AutoLocker< ::Team> teamLocker(fTeam);
                        breakpoint->SetCondition(NULL);
                        fTeam->NotifyUserBreakpointChanged(breakpoint);

                        break;
                }

                case MSG_STOP_ON_IMAGE_LOAD:
                {
                        bool enabled;
                        bool useNames;
                        if (message->FindBool("enabled", &enabled) != B_OK)
                                break;

                        if (message->FindBool("useNames", &useNames) != B_OK)
                                break;

                        AutoLocker< ::Team> teamLocker(fTeam);
                        fTeam->SetStopOnImageLoad(enabled, useNames);
                        break;
                }

                case MSG_ADD_STOP_IMAGE_NAME:
                {
                        BString imageName;
                        if (message->FindString("name", &imageName) != B_OK)
                                break;

                        AutoLocker< ::Team> teamLocker(fTeam);
                        fTeam->AddStopImageName(imageName);
                        break;
                }

                case MSG_REMOVE_STOP_IMAGE_NAME:
                {
                        BString imageName;
                        if (message->FindString("name", &imageName) != B_OK)
                                break;

                        AutoLocker< ::Team> teamLocker(fTeam);
                        fTeam->RemoveStopImageName(imageName);
                        break;
                }

                case MSG_SET_DEFAULT_SIGNAL_DISPOSITION:
                {
                        int32 disposition;
                        if (message->FindInt32("disposition", &disposition) != B_OK)
                                break;

                        AutoLocker< ::Team> teamLocker(fTeam);
                        fTeam->SetDefaultSignalDisposition(disposition);
                        break;
                }

                case MSG_SET_CUSTOM_SIGNAL_DISPOSITION:
                {
                        int32 signal;
                        int32 disposition;
                        if (message->FindInt32("signal", &signal) != B_OK
                                || message->FindInt32("disposition", &disposition) != B_OK) {
                                break;
                        }

                        AutoLocker< ::Team> teamLocker(fTeam);
                        fTeam->SetCustomSignalDisposition(signal, disposition);
                        break;
                }

                case MSG_REMOVE_CUSTOM_SIGNAL_DISPOSITION:
                {
                        int32 signal;
                        if (message->FindInt32("signal", &signal) != B_OK)
                                break;

                        AutoLocker< ::Team> teamLocker(fTeam);
                        fTeam->RemoveCustomSignalDisposition(signal);
                        break;
                }

                case MSG_SET_WATCHPOINT:
                case MSG_CLEAR_WATCHPOINT:
                {
                        Watchpoint* watchpoint = NULL;
                        BReference<Watchpoint> watchpointReference;
                        uint64 address = 0;
                        uint32 type = 0;
                        int32 length = 0;

                        if (message->FindPointer("watchpoint", (void**)&watchpoint)
                                        == B_OK) {
                                watchpointReference.SetTo(watchpoint, true);
                        } else if (message->FindUInt64("address", &address) != B_OK)
                                break;

                        if (message->what == MSG_SET_WATCHPOINT) {
                                if (watchpoint == NULL && (message->FindUInt32("type", &type)
                                                        != B_OK
                                                || message->FindInt32("length", &length) != B_OK)) {
                                        break;
                                }

                                bool enabled;
                                if (message->FindBool("enabled", &enabled) != B_OK)
                                        enabled = true;

                                if (watchpoint != NULL)
                                        _HandleSetWatchpoint(watchpoint, enabled);
                                else
                                        _HandleSetWatchpoint(address, type, length, enabled);
                        } else {
                                if (watchpoint != NULL)
                                        _HandleClearWatchpoint(watchpoint);
                                else
                                        _HandleClearWatchpoint(address);
                        }

                        break;
                }

                case MSG_INSPECT_ADDRESS:
                {
                        TeamMemoryBlock::Listener* listener;
                        if (message->FindPointer("listener",
                                reinterpret_cast<void **>(&listener)) != B_OK) {
                                break;
                        }

                        target_addr_t address;
                        if (message->FindUInt64("address",
                                &address) == B_OK) {
                                _HandleInspectAddress(address, listener);
                        }
                        break;
                }

                case MSG_WRITE_TARGET_MEMORY:
                {
                        target_addr_t address;
                        if (message->FindUInt64("address", &address) != B_OK)
                                break;

                        void* data;
                        if (message->FindPointer("data", &data) != B_OK)
                                break;

                        target_size_t size;
                        if (message->FindUInt64("size", &size) != B_OK)
                                break;

                        _HandleWriteMemory(address, data, size);
                        break;
                }

                case MSG_EVALUATE_EXPRESSION:
                {
                        SourceLanguage* language;
                        if (message->FindPointer("language",
                                reinterpret_cast<void**>(&language)) != B_OK) {
                                break;
                        }

                        // ExpressionEvaluationRequested() acquires a reference
                        // to both the language and the expression info on our behalf.
                        BReference<SourceLanguage> reference(language, true);

                        ExpressionInfo* info;
                        if (message->FindPointer("info",
                                reinterpret_cast<void**>(&info)) != B_OK) {
                                break;
                        }

                        BReference<ExpressionInfo> infoReference(info, true);

                        StackFrame* frame;
                        if (message->FindPointer("frame",
                                reinterpret_cast<void**>(&frame)) != B_OK) {
                                // the stack frame isn't needed, unless variable
                                // evaluation is desired.
                                frame = NULL;
                        }

                        ::Thread* thread;
                        if (message->FindPointer("thread",
                                reinterpret_cast<void**>(&thread)) != B_OK) {
                                // the thread isn't needed, unless variable
                                // evaluation is desired.
                                thread = NULL;
                        }

                        _HandleEvaluateExpression(language, info, frame, thread);
                        break;
                }

                case MSG_GENERATE_DEBUG_REPORT:
                {
                        fReportGenerator->PostMessage(message);
                        break;
                }

                case MSG_WRITE_CORE_FILE:
                {
                        entry_ref ref;
                        if (message->FindRef("target", &ref) != B_OK)
                                break;

                        _HandleWriteCoreFile(ref);
                        break;
                }

                case MSG_THREAD_STATE_CHANGED:
                {
                        int32 threadID;
                        if (message->FindInt32("thread", &threadID) != B_OK)
                                break;

                        if (ThreadHandler* handler = _GetThreadHandler(threadID)) {
                                handler->HandleThreadStateChanged();
                                handler->ReleaseReference();
                        }
                        break;
                }
                case MSG_THREAD_CPU_STATE_CHANGED:
                {
                        int32 threadID;
                        if (message->FindInt32("thread", &threadID) != B_OK)
                                break;

                        if (ThreadHandler* handler = _GetThreadHandler(threadID)) {
                                handler->HandleCpuStateChanged();
                                handler->ReleaseReference();
                        }
                        break;
                }
                case MSG_THREAD_STACK_TRACE_CHANGED:
                {
                        int32 threadID;
                        if (message->FindInt32("thread", &threadID) != B_OK)
                                break;

                        if (ThreadHandler* handler = _GetThreadHandler(threadID)) {
                                handler->HandleStackTraceChanged();
                                handler->ReleaseReference();
                        }
                        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;
                        if (message->FindInt32("image", &imageID) != B_OK)
                                break;

                        _HandleImageFileChanged(imageID);
                        break;
                }

                case MSG_DEBUGGER_EVENT:
                {
                        DebugEvent* event;
                        if (message->FindPointer("event", (void**)&event) != B_OK)
                                break;

                        _HandleDebuggerMessage(event);
                        delete event;
                        break;
                }

                case MSG_LOAD_SETTINGS:
                        _LoadSettings();
                        Activate();
                        break;

                case MSG_TEAM_RESTART_REQUESTED:
                {
                        if (fCommandLineArgc == 0)
                                break;

                        _SaveSettings();
                        fListener->TeamDebuggerRestartRequested(this);
                        break;
                }

                case MSG_DEBUG_INFO_NEEDS_USER_INPUT:
                {
                        Job* job;
                        ImageDebugInfoLoadingState* state;
                        if (message->FindPointer("job", (void**)&job) != B_OK)
                                break;
                        if (message->FindPointer("state", (void**)&state) != B_OK)
                                break;

                        _HandleDebugInfoJobUserInput(state);
                        fWorker->ResumeJob(job);
                        break;
                }

                case MSG_RESET_USER_BACKGROUND_STATUS:
                {
                        fUserInterface->NotifyBackgroundWorkStatus("Ready.");
                        break;
                }

                default:
                        BLooper::MessageReceived(message);
                        break;
        }
}


void
TeamDebugger::SourceEntryLocateRequested(const char* sourcePath,
        const char* locatedPath)
{
        AutoLocker<FileManager> locker(fFileManager);
        fFileManager->SourceEntryLocated(sourcePath, locatedPath);
}


void
TeamDebugger::SourceEntryInvalidateRequested(LocatableFile* sourceFile)
{
        AutoLocker< ::Team> locker(fTeam);

        fTeam->DebugInfo()->ClearSourceCode(sourceFile);
}


void
TeamDebugger::FunctionSourceCodeRequested(FunctionInstance* functionInstance,
        bool forceDisassembly)
{
        Function* function = functionInstance->GetFunction();

        // mark loading
        AutoLocker< ::Team> locker(fTeam);

        if (forceDisassembly && functionInstance->SourceCodeState()
                        != FUNCTION_SOURCE_NOT_LOADED) {
                return;
        } else if (!forceDisassembly && function->SourceCodeState()
                        == FUNCTION_SOURCE_LOADED) {
                return;
        }

        functionInstance->SetSourceCode(NULL, FUNCTION_SOURCE_LOADING);

        bool loadForFunction = false;
        if (!forceDisassembly && (function->SourceCodeState()
                                == FUNCTION_SOURCE_NOT_LOADED
                        || function->SourceCodeState() == FUNCTION_SOURCE_SUPPRESSED)) {
                loadForFunction = true;
                function->SetSourceCode(NULL, FUNCTION_SOURCE_LOADING);
        }

        locker.Unlock();

        // schedule the job
        if (fWorker->ScheduleJob(
                        new(std::nothrow) LoadSourceCodeJob(fDebuggerInterface,
                                fDebuggerInterface->GetArchitecture(), fTeam, functionInstance,
                                        loadForFunction),
                        this) != B_OK) {
                // scheduling failed -- mark unavailable
                locker.Lock();
                function->SetSourceCode(NULL, FUNCTION_SOURCE_UNAVAILABLE);
                locker.Unlock();
        }
}


void
TeamDebugger::ImageDebugInfoRequested(Image* image)
{
        LoadImageDebugInfoJob::ScheduleIfNecessary(fWorker, image, this);
}


void
TeamDebugger::ValueNodeValueRequested(CpuState* cpuState,
        ValueNodeContainer* container, ValueNode* valueNode)
{
        AutoLocker<ValueNodeContainer> containerLocker(container);
        if (valueNode->Container() != container)
                return;

        // check whether a job is already in progress
        AutoLocker<Worker> workerLocker(fWorker);
        SimpleJobKey jobKey(valueNode, JOB_TYPE_RESOLVE_VALUE_NODE_VALUE);
        if (fWorker->GetJob(jobKey) != NULL)
                return;
        workerLocker.Unlock();

        // schedule the job
        status_t error = fWorker->ScheduleJob(
                new(std::nothrow) ResolveValueNodeValueJob(fDebuggerInterface,
                        fDebuggerInterface->GetArchitecture(), cpuState,
                        fTeam->GetTeamTypeInformation(), container,     valueNode), this);
        if (error != B_OK) {
                // scheduling failed -- set the value to invalid
                valueNode->SetLocationAndValue(NULL, NULL, error);
        }
}

void
TeamDebugger::ValueNodeWriteRequested(ValueNode* node, CpuState* state,
        Value* newValue)
{
        // schedule the job
        status_t error = fWorker->ScheduleJob(
                new(std::nothrow) WriteValueNodeValueJob(fDebuggerInterface,
                        fDebuggerInterface->GetArchitecture(), state,
                        fTeam->GetTeamTypeInformation(), node, newValue), this);
        if (error != B_OK) {
                BString message;
                message.SetToFormat("Request to write new value for variable %s "
                        "failed: %s.\n", node->Name().String(), strerror(error));
                fUserInterface->NotifyUser("Error", message.String(),
                        USER_NOTIFICATION_ERROR);
        }
}


void
TeamDebugger::ThreadActionRequested(thread_id threadID,
        uint32 action, target_addr_t address)
{
        BMessage message(action);
        message.AddInt32("thread", threadID);
        message.AddUInt64("address", address);
        PostMessage(&message);
}


void
TeamDebugger::SetBreakpointRequested(target_addr_t address, bool enabled,
        bool hidden)
{
        BMessage message(MSG_SET_BREAKPOINT);
        message.AddUInt64("address", (uint64)address);
        message.AddBool("enabled", enabled);
        message.AddBool("hidden", hidden);
        PostMessage(&message);
}


void
TeamDebugger::SetBreakpointEnabledRequested(UserBreakpoint* breakpoint,
        bool enabled)
{
        BMessage message(MSG_SET_BREAKPOINT);
        BReference<UserBreakpoint> breakpointReference(breakpoint);
        if (message.AddPointer("breakpoint", breakpoint) == B_OK
                && message.AddBool("enabled", enabled) == B_OK
                && PostMessage(&message) == B_OK) {
                breakpointReference.Detach();
        }
}


void
TeamDebugger::SetBreakpointConditionRequested(UserBreakpoint* breakpoint,
        const char* condition)
{
        BMessage message(MSG_SET_BREAKPOINT_CONDITION);
        BReference<UserBreakpoint> breakpointReference(breakpoint);
        if (message.AddPointer("breakpoint", breakpoint) == B_OK
                && message.AddString("condition", condition) == B_OK
                && PostMessage(&message) == B_OK) {
                breakpointReference.Detach();
        }
}


void
TeamDebugger::ClearBreakpointConditionRequested(UserBreakpoint* breakpoint)
{
        BMessage message(MSG_CLEAR_BREAKPOINT_CONDITION);
        BReference<UserBreakpoint> breakpointReference(breakpoint);
        if (message.AddPointer("breakpoint", breakpoint) == B_OK
                && PostMessage(&message) == B_OK) {
                breakpointReference.Detach();
        }
}


void
TeamDebugger::ClearBreakpointRequested(target_addr_t address)
{
        BMessage message(MSG_CLEAR_BREAKPOINT);
        message.AddUInt64("address", (uint64)address);
        PostMessage(&message);
}


void
TeamDebugger::SetStopOnImageLoadRequested(bool enabled, bool useImageNames)
{
        BMessage message(MSG_STOP_ON_IMAGE_LOAD);
        message.AddBool("enabled", enabled);
        message.AddBool("useNames", useImageNames);
        PostMessage(&message);
}


void
TeamDebugger::AddStopImageNameRequested(const char* name)
{
        BMessage message(MSG_ADD_STOP_IMAGE_NAME);
        message.AddString("name", name);
        PostMessage(&message);
}


void
TeamDebugger::RemoveStopImageNameRequested(const char* name)
{
        BMessage message(MSG_REMOVE_STOP_IMAGE_NAME);
        message.AddString("name", name);
        PostMessage(&message);
}


void
TeamDebugger::SetDefaultSignalDispositionRequested(int32 disposition)
{
        BMessage message(MSG_SET_DEFAULT_SIGNAL_DISPOSITION);
        message.AddInt32("disposition", disposition);
        PostMessage(&message);
}


void
TeamDebugger::SetCustomSignalDispositionRequested(int32 signal,
        int32 disposition)
{
        BMessage message(MSG_SET_CUSTOM_SIGNAL_DISPOSITION);
        message.AddInt32("signal", signal);
        message.AddInt32("disposition", disposition);
        PostMessage(&message);
}


void
TeamDebugger::RemoveCustomSignalDispositionRequested(int32 signal)
{
        BMessage message(MSG_REMOVE_CUSTOM_SIGNAL_DISPOSITION);
        message.AddInt32("signal", signal);
        PostMessage(&message);
}


void
TeamDebugger::ClearBreakpointRequested(UserBreakpoint* breakpoint)
{
        BMessage message(MSG_CLEAR_BREAKPOINT);
        BReference<UserBreakpoint> breakpointReference(breakpoint);
        if (message.AddPointer("breakpoint", breakpoint) == B_OK
                && PostMessage(&message) == B_OK) {
                breakpointReference.Detach();
        }
}


void
TeamDebugger::SetWatchpointRequested(target_addr_t address, uint32 type,
        int32 length, bool enabled)
{
        BMessage message(MSG_SET_WATCHPOINT);
        message.AddUInt64("address", (uint64)address);
        message.AddUInt32("type", type);
        message.AddInt32("length", length);
        message.AddBool("enabled", enabled);
        PostMessage(&message);
}


void
TeamDebugger::SetWatchpointEnabledRequested(Watchpoint* watchpoint,
        bool enabled)
{
        BMessage message(MSG_SET_WATCHPOINT);
        BReference<Watchpoint> watchpointReference(watchpoint);
        if (message.AddPointer("watchpoint", watchpoint) == B_OK
                && message.AddBool("enabled", enabled) == B_OK
                && PostMessage(&message) == B_OK) {
                watchpointReference.Detach();
        }
}


void
TeamDebugger::ClearWatchpointRequested(target_addr_t address)
{
        BMessage message(MSG_CLEAR_WATCHPOINT);
        message.AddUInt64("address", (uint64)address);
        PostMessage(&message);
}


void
TeamDebugger::ClearWatchpointRequested(Watchpoint* watchpoint)
{
        BMessage message(MSG_CLEAR_WATCHPOINT);
        BReference<Watchpoint> watchpointReference(watchpoint);
        if (message.AddPointer("watchpoint", watchpoint) == B_OK
                && PostMessage(&message) == B_OK) {
                watchpointReference.Detach();
        }
}


void
TeamDebugger::InspectRequested(target_addr_t address,
        TeamMemoryBlock::Listener *listener)
{
        BMessage message(MSG_INSPECT_ADDRESS);
        message.AddUInt64("address", address);
        message.AddPointer("listener", listener);
        PostMessage(&message);
}


void
TeamDebugger::MemoryWriteRequested(target_addr_t address, const void* data,
        target_size_t size)
{
        BMessage message(MSG_WRITE_TARGET_MEMORY);
        message.AddUInt64("address", address);
        message.AddPointer("data", data);
        message.AddUInt64("size", size);
        PostMessage(&message);
}


void
TeamDebugger::ExpressionEvaluationRequested(SourceLanguage* language,
        ExpressionInfo* info, StackFrame* frame, ::Thread* thread)
{
        BMessage message(MSG_EVALUATE_EXPRESSION);
        message.AddPointer("language", language);
        message.AddPointer("info", info);
        if (frame != NULL)
                message.AddPointer("frame", frame);
        if (thread != NULL)
                message.AddPointer("thread", thread);

        BReference<SourceLanguage> languageReference(language);
        BReference<ExpressionInfo> infoReference(info);
        if (PostMessage(&message) == B_OK) {
                languageReference.Detach();
                infoReference.Detach();
        }
}


void
TeamDebugger::DebugReportRequested(entry_ref* targetPath)
{
        BMessage message(MSG_GENERATE_DEBUG_REPORT);
        message.AddRef("target", targetPath);
        PostMessage(&message);
}


void
TeamDebugger::WriteCoreFileRequested(entry_ref* targetPath)
{
        BMessage message(MSG_WRITE_CORE_FILE);
        message.AddRef("target", targetPath);
        PostMessage(&message);
}


void
TeamDebugger::TeamRestartRequested()
{
        PostMessage(MSG_TEAM_RESTART_REQUESTED);
}


bool
TeamDebugger::UserInterfaceQuitRequested(QuitOption quitOption)
{
        bool askUser = false;
        switch (quitOption) {
                case QUIT_OPTION_ASK_USER:
                        askUser = true;
                        break;

                case QUIT_OPTION_ASK_KILL_TEAM:
                        fKillTeamOnQuit = true;
                        break;

                case QUIT_OPTION_ASK_RESUME_TEAM:
                        break;
        }

        if (askUser) {
                AutoLocker< ::Team> locker(fTeam);
                BString name(fTeam->Name());
                locker.Unlock();

                BString message;
                message << "What shall be done about the debugged team '";
                message << name;
                message << "'?";

                name.Remove(0, name.FindLast('/') + 1);

                BString killLabel("Kill ");
                killLabel << name;

                BString resumeLabel("Resume ");
                resumeLabel << name;

                int32 choice = fUserInterface->SynchronouslyAskUser("Quit Debugger",
                        message, killLabel, "Cancel", resumeLabel);

                switch (choice) {
                        case 0:
                                fKillTeamOnQuit = true;
                                break;
                        case 1:
                        case -1:
                                return false;
                        case 2:
                                // Detach from the team and resume and stopped threads.
                                break;
                }
        }

        PostMessage(B_QUIT_REQUESTED);

        return true;
}


void
TeamDebugger::JobStarted(Job* job)
{
        BString description(job->GetDescription());
        if (!description.IsEmpty()) {
                description.Append(B_UTF8_ELLIPSIS);
                fUserInterface->NotifyBackgroundWorkStatus(description.String());
        }
}


void
TeamDebugger::JobDone(Job* job)
{
        TRACE_JOBS("TeamDebugger::JobDone(%p)\n", job);
        _ResetUserBackgroundStatusIfNeeded();
}


void
TeamDebugger::JobWaitingForInput(Job* job)
{
        LoadImageDebugInfoJob* infoJob = dynamic_cast<LoadImageDebugInfoJob*>(job);

        if (infoJob == NULL)
                return;

        BMessage message(MSG_DEBUG_INFO_NEEDS_USER_INPUT);
        message.AddPointer("job", infoJob);
        message.AddPointer("state", infoJob->GetLoadingState());
        PostMessage(&message);
}


void
TeamDebugger::JobFailed(Job* job)
{
        TRACE_JOBS("TeamDebugger::JobFailed(%p)\n", job);
        // TODO: notify user
        _ResetUserBackgroundStatusIfNeeded();
}


void
TeamDebugger::JobAborted(Job* job)
{
        TRACE_JOBS("TeamDebugger::JobAborted(%p)\n", job);
        // TODO: For a stack frame source loader thread we should reset the
        // loading state! Asynchronously due to locking order.
        _ResetUserBackgroundStatusIfNeeded();
}


void
TeamDebugger::ThreadStateChanged(const ::Team::ThreadEvent& event)
{
        BMessage message(MSG_THREAD_STATE_CHANGED);
        message.AddInt32("thread", event.GetThread()->ID());
        PostMessage(&message);
}


void
TeamDebugger::ThreadCpuStateChanged(const ::Team::ThreadEvent& event)
{
        BMessage message(MSG_THREAD_CPU_STATE_CHANGED);
        message.AddInt32("thread", event.GetThread()->ID());
        PostMessage(&message);
}


void
TeamDebugger::ThreadStackTraceChanged(const ::Team::ThreadEvent& event)
{
        BMessage message(MSG_THREAD_STACK_TRACE_CHANGED);
        message.AddInt32("thread", event.GetThread()->ID());
        PostMessage(&message);
}


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)
{
        return ((TeamDebugger*)data)->_DebugEventListener();
}


status_t
TeamDebugger::_DebugEventListener()
{
        while (!fTerminating) {
                // get the next event
                DebugEvent* event;
                status_t error = fDebuggerInterface->GetNextDebugEvent(event);
                if (error != B_OK)
                        break;
                                // TODO: Error handling!

                if (event->Team() != fTeamID) {
                        TRACE_EVENTS("TeamDebugger for team %" B_PRId32 ": received event "
                                "from team %" B_PRId32 "!\n", fTeamID, event->Team());
                        continue;
                }

                BMessage message(MSG_DEBUGGER_EVENT);
                if (message.AddPointer("event", event) != B_OK
                        || PostMessage(&message) != B_OK) {
                        // TODO: Continue thread if necessary!
                        delete event;
                }
        }

        return B_OK;
}


void
TeamDebugger::_HandleDebuggerMessage(DebugEvent* event)
{
        TRACE_EVENTS("TeamDebugger::_HandleDebuggerMessage(): %" B_PRId32 "\n",
                event->EventType());

        bool handled = false;

        ThreadHandler* handler = _GetThreadHandler(event->Thread());
        BReference<ThreadHandler> handlerReference(handler, true);

        switch (event->EventType()) {
                case B_DEBUGGER_MESSAGE_THREAD_DEBUGGED:
                        TRACE_EVENTS("B_DEBUGGER_MESSAGE_THREAD_DEBUGGED: thread: %"
                                B_PRId32 "\n", event->Thread());

                        if (handler != NULL) {
                                handled = handler->HandleThreadDebugged(
                                        dynamic_cast<ThreadDebuggedEvent*>(event));
                        }
                        break;
                case B_DEBUGGER_MESSAGE_DEBUGGER_CALL:
                        TRACE_EVENTS("B_DEBUGGER_MESSAGE_DEBUGGER_CALL: thread: %" B_PRId32
                                "\n", event->Thread());

                        if (handler != NULL) {
                                handled = handler->HandleDebuggerCall(
                                        dynamic_cast<DebuggerCallEvent*>(event));
                        }
                        break;
                case B_DEBUGGER_MESSAGE_BREAKPOINT_HIT:
                        TRACE_EVENTS("B_DEBUGGER_MESSAGE_BREAKPOINT_HIT: thread: %" B_PRId32
                                "\n", event->Thread());

                        if (handler != NULL) {
                                handled = handler->HandleBreakpointHit(
                                        dynamic_cast<BreakpointHitEvent*>(event));
                        }
                        break;
                case B_DEBUGGER_MESSAGE_WATCHPOINT_HIT:
                        TRACE_EVENTS("B_DEBUGGER_MESSAGE_WATCHPOINT_HIT: thread: %" B_PRId32
                                "\n", event->Thread());

                        if (handler != NULL) {
                                handled = handler->HandleWatchpointHit(
                                        dynamic_cast<WatchpointHitEvent*>(event));
                        }
                        break;
                case B_DEBUGGER_MESSAGE_SINGLE_STEP:
                        TRACE_EVENTS("B_DEBUGGER_MESSAGE_SINGLE_STEP: thread: %" B_PRId32
                                "\n", event->Thread());

                        if (handler != NULL) {
                                handled = handler->HandleSingleStep(
                                        dynamic_cast<SingleStepEvent*>(event));
                        }
                        break;
                case B_DEBUGGER_MESSAGE_EXCEPTION_OCCURRED:
                        TRACE_EVENTS("B_DEBUGGER_MESSAGE_EXCEPTION_OCCURRED: thread: %"
                                B_PRId32 "\n", event->Thread());

                        if (handler != NULL) {
                                handled = handler->HandleExceptionOccurred(
                                        dynamic_cast<ExceptionOccurredEvent*>(event));
                        }
                        break;
//              case B_DEBUGGER_MESSAGE_TEAM_CREATED:
//printf("B_DEBUGGER_MESSAGE_TEAM_CREATED: team: %ld\n", message.team_created.new_team);
//                      break;
                case B_DEBUGGER_MESSAGE_TEAM_DELETED:
                {
                        TRACE_EVENTS("B_DEBUGGER_MESSAGE_TEAM_DELETED: team: %" B_PRId32
                                "\n", event->Team());
                        TeamDeletedEvent* teamEvent
                                = dynamic_cast<TeamDeletedEvent*>(event);
                        handled = _HandleTeamDeleted(teamEvent);
                        break;
                }
                case B_DEBUGGER_MESSAGE_TEAM_EXEC:
                {
                        TRACE_EVENTS("B_DEBUGGER_MESSAGE_TEAM_EXEC: team: %" B_PRId32 "\n",
                                event->Team());

                        TeamExecEvent* teamEvent
                                = dynamic_cast<TeamExecEvent*>(event);
                        _PrepareForTeamExec(teamEvent);
                        break;
                }
                case B_DEBUGGER_MESSAGE_THREAD_CREATED:
                {
                        ThreadCreatedEvent* threadEvent
                                = dynamic_cast<ThreadCreatedEvent*>(event);
                        TRACE_EVENTS("B_DEBUGGER_MESSAGE_THREAD_CREATED: thread: %" B_PRId32
                                "\n", threadEvent->NewThread());
                        handled = _HandleThreadCreated(threadEvent);
                        break;
                }
                case DEBUGGER_MESSAGE_THREAD_RENAMED:
                {
                        ThreadRenamedEvent* threadEvent
                                = dynamic_cast<ThreadRenamedEvent*>(event);
                        TRACE_EVENTS("DEBUGGER_MESSAGE_THREAD_RENAMED: thread: %" B_PRId32
                                " (\"%s\")\n",
                                threadEvent->RenamedThread(), threadEvent->NewName());
                        handled = _HandleThreadRenamed(threadEvent);
                        break;
                }
                case DEBUGGER_MESSAGE_THREAD_PRIORITY_CHANGED:
                {
                        ThreadPriorityChangedEvent* threadEvent
                                = dynamic_cast<ThreadPriorityChangedEvent*>(event);
                        TRACE_EVENTS("B_DEBUGGER_MESSAGE_THREAD_PRIORITY_CHANGED: thread:"
                                " %" B_PRId32 "\n", threadEvent->ChangedThread());
                        handled = _HandleThreadPriorityChanged(threadEvent);
                        break;
                }
                case B_DEBUGGER_MESSAGE_THREAD_DELETED:
                        TRACE_EVENTS("B_DEBUGGER_MESSAGE_THREAD_DELETED: thread: %" B_PRId32
                                "\n", event->Thread());
                        handled = _HandleThreadDeleted(
                                dynamic_cast<ThreadDeletedEvent*>(event));
                        break;
                case B_DEBUGGER_MESSAGE_IMAGE_CREATED:
                {
                        ImageCreatedEvent* imageEvent
                                = dynamic_cast<ImageCreatedEvent*>(event);
                        TRACE_EVENTS("B_DEBUGGER_MESSAGE_IMAGE_CREATED: image: \"%s\" "
                                "(%" B_PRId32 ")\n", imageEvent->GetImageInfo().Name().String(),
                                imageEvent->GetImageInfo().ImageID());
                        handled = _HandleImageCreated(imageEvent);
                        break;
                }
                case B_DEBUGGER_MESSAGE_IMAGE_DELETED:
                {
                        ImageDeletedEvent* imageEvent
                                = dynamic_cast<ImageDeletedEvent*>(event);
                        TRACE_EVENTS("B_DEBUGGER_MESSAGE_IMAGE_DELETED: image: \"%s\" "
                                "(%" B_PRId32 ")\n", imageEvent->GetImageInfo().Name().String(),
                                imageEvent->GetImageInfo().ImageID());
                        handled = _HandleImageDeleted(imageEvent);
                        break;
                }
                case B_DEBUGGER_MESSAGE_POST_SYSCALL:
                {
                        PostSyscallEvent* postSyscallEvent
                                = dynamic_cast<PostSyscallEvent*>(event);
                        TRACE_EVENTS("B_DEBUGGER_MESSAGE_POST_SYSCALL: syscall: %"
                                B_PRIu32 "\n", postSyscallEvent->GetSyscallInfo().Syscall());
                        handled = _HandlePostSyscall(postSyscallEvent);

                        // if a thread was blocked in a syscall when we requested to
                        // stop it for debugging, then that request will interrupt
                        // said call, and the post syscall event will be all we get
                        // in response. Consequently, we need to treat this case as
                        // equivalent to having received a thread debugged event.
                        AutoLocker< ::Team> teamLocker(fTeam);
                        ::Thread* thread = fTeam->ThreadByID(event->Thread());
                        if (handler != NULL && thread != NULL
                                && thread->StopRequestPending()) {
                                handled = handler->HandleThreadDebugged(NULL);
                        }
                        break;
                }
                case B_DEBUGGER_MESSAGE_SIGNAL_RECEIVED:
                {
                        TRACE_EVENTS("B_DEBUGGER_MESSAGE_SIGNAL_RECEIVED: thread: %"
                                B_PRId32 "\n", event->Thread());

                        if (handler != NULL) {
                                handled = handler->HandleSignalReceived(
                                        dynamic_cast<SignalReceivedEvent*>(event));
                        }
                        break;
                }
                case B_DEBUGGER_MESSAGE_PRE_SYSCALL:
                case B_DEBUGGER_MESSAGE_PROFILER_UPDATE:
                case B_DEBUGGER_MESSAGE_HANDED_OVER:
                        // not interested
                        break;
                default:
                        WARNING("TeamDebugger for team %" B_PRId32 ": unknown event type: "
                                "%" B_PRId32 "\n", fTeamID, event->EventType());
                        break;
        }

        if (!handled && event->ThreadStopped())
                fDebuggerInterface->ContinueThread(event->Thread());
}


bool
TeamDebugger::_HandleTeamDeleted(TeamDeletedEvent* event)
{
        char message[64];
        fDebuggerInterface->Close(false);

        snprintf(message, sizeof(message), "Team %" B_PRId32 " has terminated. ",
                event->Team());

        int32 result = fUserInterface->SynchronouslyAskUser("Team terminated",
                message, "Do nothing", "Quit", fCommandLineArgc != 0
                        ? "Restart team" : NULL);

        switch (result) {
                case 1:
                case -1:
                {
                        PostMessage(B_QUIT_REQUESTED);
                        break;
                }
                case 2:
                {
                        _SaveSettings();
                        fListener->TeamDebuggerRestartRequested(this);
                        break;
                }
                default:
                        break;
        }

        return true;
}


bool
TeamDebugger::_HandleThreadCreated(ThreadCreatedEvent* event)
{
        AutoLocker< ::Team> locker(fTeam);

        ThreadInfo info;
        status_t error = fDebuggerInterface->GetThreadInfo(event->NewThread(),
                info);
        if (error == B_OK) {
                ::Thread* thread;
                fTeam->AddThread(info, &thread);

                ThreadHandler* handler = new(std::nothrow) ThreadHandler(thread,
                        fWorker, fDebuggerInterface, this, fBreakpointManager);
                if (handler != NULL) {
                        fThreadHandlers.Insert(handler);
                        handler->Init();
                }
        }

        return false;
}


bool
TeamDebugger::_HandleThreadRenamed(ThreadRenamedEvent* event)
{
        AutoLocker< ::Team> locker(fTeam);

        ::Thread* thread = fTeam->ThreadByID(event->RenamedThread());

        if (thread != NULL)
                thread->SetName(event->NewName());

        return false;
}


bool
TeamDebugger::_HandleThreadPriorityChanged(ThreadPriorityChangedEvent*)
{
        // TODO: implement once we actually track thread priorities

        return false;
}


bool
TeamDebugger::_HandleThreadDeleted(ThreadDeletedEvent* event)
{
        AutoLocker< ::Team> locker(fTeam);
        if (ThreadHandler* handler = fThreadHandlers.Lookup(event->Thread())) {
                fThreadHandlers.Remove(handler);
                handler->ReleaseReference();
        }
        fTeam->RemoveThread(event->Thread());
        return false;
}


bool
TeamDebugger::_HandleImageCreated(ImageCreatedEvent* event)
{
        AutoLocker< ::Team> locker(fTeam);
        _AddImage(event->GetImageInfo());

        ImageInfoPendingThread* info = new(std::nothrow) ImageInfoPendingThread(
                event->GetImageInfo().ImageID(), event->Thread());
        if (info == NULL)
                return false;

        fImageInfoPendingThreads->Insert(info);
        return true;
}


bool
TeamDebugger::_HandleImageDeleted(ImageDeletedEvent* event)
{
        AutoLocker< ::Team> locker(fTeam);
        fTeam->RemoveImage(event->GetImageInfo().ImageID());

        ImageHandler* imageHandler = fImageHandlers->Lookup(
                event->GetImageInfo().ImageID());
        if (imageHandler == NULL)
                return false;

        fImageHandlers->Remove(imageHandler);
        BReference<ImageHandler> imageHandlerReference(imageHandler, true);
        locker.Unlock();

        // remove breakpoints in the image
        fBreakpointManager->RemoveImageBreakpoints(imageHandler->GetImage());

        return false;
}


bool
TeamDebugger::_HandlePostSyscall(PostSyscallEvent* event)
{
        const SyscallInfo& info = event->GetSyscallInfo();

        switch (info.Syscall()) {
                case SYSCALL_WRITE:
                {
                        if ((ssize_t)info.ReturnValue() <= 0)
                                break;

                        int32 fd;
                        target_addr_t address;
                        size_t size;
                        // TODO: decoding the syscall arguments should probably be
                        // factored out into an Architecture method of its own, since
                        // there's no guarantee the target architecture has the same
                        // endianness as the host. This could re-use the syscall
                        // argument parser that strace uses, though that would need to
                        // be adapted to handle the aforementioned endian differences.
                        // This works for x86{-64} for now though.
                        if (fTeam->GetArchitecture()->AddressSize() == 4) {
                                const uint32* args = (const uint32*)info.Arguments();
                                fd = args[0];
                                address = args[3];
                                size = args[4];
                        } else {
                                const uint64* args = (const uint64*)info.Arguments();
                                fd = args[0];
                                address = args[2];
                                size = args[3];
                        }

                        if (fd == 1 || fd == 2) {
                                BString data;

                                ssize_t result = fDebuggerInterface->ReadMemoryString(
                                        address, size, data);
                                if (result >= 0)
                                        fTeam->NotifyConsoleOutputReceived(fd, data);
                        }
                        break;
                }
                case SYSCALL_WRITEV:
                {
                        // TODO: handle
                }
                default:
                        break;
        }

        return false;
}


void
TeamDebugger::_PrepareForTeamExec(TeamExecEvent* event)
{
        // NB: must be called with team lock held.

        _SaveSettings();

        // when notified of exec, we need to clear out data related
        // to the old team.
        const ImageList& images = fTeam->Images();

        for (ImageList::ConstIterator it = images.GetIterator();
                        Image* image = it.Next();) {
                fBreakpointManager->RemoveImageBreakpoints(image);
        }

        BObjectList<UserBreakpoint> breakpointsToRemove(20);
        const UserBreakpointList& breakpoints = fTeam->UserBreakpoints();
        for (UserBreakpointList::ConstIterator it = breakpoints.GetIterator();
                        UserBreakpoint* breakpoint = it.Next();) {
                breakpointsToRemove.AddItem(breakpoint);
                breakpoint->AcquireReference();
        }

        for (int32 i = 0; i < breakpointsToRemove.CountItems(); i++) {
                UserBreakpoint* breakpoint = breakpointsToRemove.ItemAt(i);
                fTeam->RemoveUserBreakpoint(breakpoint);
                fTeam->NotifyUserBreakpointChanged(breakpoint);
                breakpoint->ReleaseReference();
        }

        fTeam->ClearImages();
        fTeam->ClearSignalDispositionMappings();
        fExecPending = true;
}


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();
        BReference<Image> imageReference(image);
        image_debug_info_state state = image->ImageDebugInfoState();

        bool handlePostExecSetup = fExecPending && image->Type() == B_APP_IMAGE
                && state != IMAGE_DEBUG_INFO_LOADING;
        // this needs to be done first so that breakpoints are loaded.
        // otherwise, UpdateImageBreakpoints() won't find the appropriate
        // UserBreakpoints to create/install instances for.
        if (handlePostExecSetup) {
                fTeam->SetName(image->Name());
                _LoadSettings();
                fExecPending = false;
        }

        locker.Unlock();

        if (state == IMAGE_DEBUG_INFO_LOADED
                || state == IMAGE_DEBUG_INFO_UNAVAILABLE) {

                // update breakpoints in the image
                fBreakpointManager->UpdateImageBreakpoints(image);

                ImageInfoPendingThread* thread =  fImageInfoPendingThreads
                        ->Lookup(imageID);
                if (thread != NULL) {
                        fImageInfoPendingThreads->Remove(thread);
                        ObjectDeleter<ImageInfoPendingThread> threadDeleter(thread);
                        locker.Lock();
                        ThreadHandler* handler = _GetThreadHandler(thread->ThreadID());
                        BReference<ThreadHandler> handlerReference(handler, true);
                        if (fTeam->StopOnImageLoad()) {

                                bool stop = true;
                                const BString& imageName = image->Name();
                                // only match on the image filename itself
                                const char* rawImageName = imageName.String()
                                        + imageName.FindLast('/') + 1;
                                if (fTeam->StopImageNameListEnabled()) {
                                        const BStringList& nameList = fTeam->StopImageNames();
                                        stop = nameList.HasString(rawImageName);
                                }

                                if (stop && handler != NULL) {
                                        BString stopReason;
                                        stopReason.SetToFormat("Image '%s' loaded.",
                                                rawImageName);
                                        locker.Unlock();

                                        if (handler->HandleThreadDebugged(NULL, stopReason))
                                                return;
                                } else
                                        locker.Unlock();
                        } else if (handlePostExecSetup) {
                                // in the case of an exec(), we can't stop in main() until
                                // the new app image has been loaded, so we know where to
                                // set the main breakpoint at.
                                SymbolInfo symbolInfo;
                                if (fDebuggerInterface->GetSymbolInfo(fTeam->ID(), image->ID(),
                                                "main", B_SYMBOL_TYPE_TEXT, symbolInfo) == B_OK) {
                                        handler->SetBreakpointAndRun(symbolInfo.Address());
                                }
                        } else {
                                locker.Unlock();
                                fDebuggerInterface->ContinueThread(thread->ThreadID());
                        }
                }
        }
}


void
TeamDebugger::_HandleImageFileChanged(image_id imageID)
{
        TRACE_IMAGES("TeamDebugger::_HandleImageFileChanged(%" B_PRId32 ")\n",
                imageID);
// TODO: Reload the debug info!
}


void
TeamDebugger::_HandleSetUserBreakpoint(target_addr_t address, bool enabled,
        bool hidden)
{
        TRACE_CONTROL("TeamDebugger::_HandleSetUserBreakpoint(%#" B_PRIx64
                ", %d, %d)\n", address, enabled, hidden);

        // check whether there already is a breakpoint
        AutoLocker< ::Team> locker(fTeam);

        Breakpoint* breakpoint = fTeam->BreakpointAtAddress(address);
        UserBreakpoint* userBreakpoint = NULL;
        if (breakpoint != NULL && breakpoint->FirstUserBreakpoint() != NULL)
                userBreakpoint = breakpoint->FirstUserBreakpoint()->GetUserBreakpoint();
        BReference<UserBreakpoint> userBreakpointReference(userBreakpoint);

        if (userBreakpoint == NULL) {
                TRACE_CONTROL("  no breakpoint yet\n");

                // get the function at the address
                Image* image = fTeam->ImageByAddress(address);

                TRACE_CONTROL("  image: %p\n", image);

                if (image == NULL)
                        return;
                ImageDebugInfo* imageDebugInfo = image->GetImageDebugInfo();

                TRACE_CONTROL("  image debug info: %p\n", imageDebugInfo);

                if (imageDebugInfo == NULL)
                        return;
                        // TODO: Handle this case by loading the debug info, if possible!
                FunctionInstance* functionInstance
                        = imageDebugInfo->FunctionAtAddress(address);

                TRACE_CONTROL("  function instance: %p\n", functionInstance);

                if (functionInstance == NULL)
                        return;
                Function* function = functionInstance->GetFunction();

                TRACE_CONTROL("  function: %p\n", function);

                // get the source location for the address
                FunctionDebugInfo* functionDebugInfo
                        = functionInstance->GetFunctionDebugInfo();
                SourceLocation sourceLocation;
                Statement* breakpointStatement = NULL;
                if (functionDebugInfo->GetSpecificImageDebugInfo()->GetStatement(
                                functionDebugInfo, address, breakpointStatement) != B_OK) {
                        return;
                }

                sourceLocation = breakpointStatement->StartSourceLocation();
                breakpointStatement->ReleaseReference();

                target_addr_t relativeAddress = address - functionInstance->Address();

                TRACE_CONTROL("  relative address: %#" B_PRIx64 ", source location: "
                        "(%" B_PRId32 ", %" B_PRId32 ")\n", relativeAddress,
                        sourceLocation.Line(), sourceLocation.Column());

                // get function id
                FunctionID* functionID = functionInstance->GetFunctionID();
                if (functionID == NULL)
                        return;
                BReference<FunctionID> functionIDReference(functionID, true);

                // create the user breakpoint
                userBreakpoint = new(std::nothrow) UserBreakpoint(
                        UserBreakpointLocation(functionID, function->SourceFile(),
                                sourceLocation, relativeAddress));
                if (userBreakpoint == NULL)
                        return;
                userBreakpointReference.SetTo(userBreakpoint, true);

                userBreakpoint->SetHidden(hidden);

                TRACE_CONTROL("  created user breakpoint: %p\n", userBreakpoint);

                // iterate through all function instances and create
                // UserBreakpointInstances
                for (FunctionInstanceList::ConstIterator it
                                        = function->Instances().GetIterator();
                                FunctionInstance* instance = it.Next();) {
                        TRACE_CONTROL("  function instance %p: range: %#" B_PRIx64 " - %#"
                                B_PRIx64 "\n", instance, instance->Address(),
                                instance->Address() + instance->Size());

                        // get the breakpoint address for the instance
                        target_addr_t instanceAddress = 0;
                        if (instance == functionInstance) {
                                instanceAddress = address;
                        } else if (functionInstance->SourceFile() != NULL) {
                                // We have a source file, so get the address for the source
                                // location.
                                Statement* statement = NULL;
                                functionDebugInfo = instance->GetFunctionDebugInfo();
                                functionDebugInfo->GetSpecificImageDebugInfo()
                                        ->GetStatementAtSourceLocation(functionDebugInfo,
                                                sourceLocation, statement);
                                if (statement != NULL) {
                                        instanceAddress = statement->CoveringAddressRange().Start();
                                                // TODO: What about BreakpointAllowed()?
                                        statement->ReleaseReference();
                                }
                        }

                        TRACE_CONTROL("    breakpoint address using source info: %" B_PRIx64
                                "\n", instanceAddress);

                        if (instanceAddress == 0) {
                                // No source file (or we failed getting the statement), so try
                                // to use the same relative address.
                                if (relativeAddress > instance->Size())
                                        continue;
                                instanceAddress = instance->Address() + relativeAddress;
                        }

                        TRACE_CONTROL("    final breakpoint address: %" B_PRIx64 "\n",
                                instanceAddress);

                        UserBreakpointInstance* breakpointInstance = new(std::nothrow)
                                UserBreakpointInstance(userBreakpoint, instanceAddress);
                        if (breakpointInstance == NULL
                                || !userBreakpoint->AddInstance(breakpointInstance)) {
                                delete breakpointInstance;
                                return;
                        }

                        TRACE_CONTROL("  breakpoint instance: %p\n", breakpointInstance);
                }
        }

        locker.Unlock();

        _HandleSetUserBreakpoint(userBreakpoint, enabled);
}


void
TeamDebugger::_HandleSetUserBreakpoint(UserBreakpoint* breakpoint, bool enabled)
{
        status_t error = fBreakpointManager->InstallUserBreakpoint(breakpoint,
                enabled);
        if (error != B_OK) {
                _NotifyUser("Install Breakpoint", "Failed to install breakpoint: %s",
                        strerror(error));
        }
}


void
TeamDebugger::_HandleClearUserBreakpoint(target_addr_t address)
{
        TRACE_CONTROL("TeamDebugger::_HandleClearUserBreakpoint(%#" B_PRIx64 ")\n",
                address);

        AutoLocker< ::Team> locker(fTeam);

        Breakpoint* breakpoint = fTeam->BreakpointAtAddress(address);
        if (breakpoint == NULL || breakpoint->FirstUserBreakpoint() == NULL)
                return;
        UserBreakpoint* userBreakpoint
                = breakpoint->FirstUserBreakpoint()->GetUserBreakpoint();
        BReference<UserBreakpoint> userBreakpointReference(userBreakpoint);

        locker.Unlock();

        _HandleClearUserBreakpoint(userBreakpoint);
}


void
TeamDebugger::_HandleClearUserBreakpoint(UserBreakpoint* breakpoint)
{
        fBreakpointManager->UninstallUserBreakpoint(breakpoint);
}


void
TeamDebugger::_HandleSetWatchpoint(target_addr_t address, uint32 type,
        int32 length, bool enabled)
{
        Watchpoint* watchpoint = new(std::nothrow) Watchpoint(address, type,
                length);

        if (watchpoint == NULL)
                return;
        BReference<Watchpoint> watchpointRef(watchpoint, true);

        _HandleSetWatchpoint(watchpoint, enabled);
}


void
TeamDebugger::_HandleSetWatchpoint(Watchpoint* watchpoint, bool enabled)
{
        status_t error = fWatchpointManager->InstallWatchpoint(watchpoint,
                enabled);
        if (error != B_OK) {
                _NotifyUser("Install Watchpoint", "Failed to install watchpoint: %s",
                        strerror(error));
        }
}


void
TeamDebugger::_HandleClearWatchpoint(target_addr_t address)
{
        TRACE_CONTROL("TeamDebugger::_HandleClearWatchpoint(%#" B_PRIx64 ")\n",
                address);

        AutoLocker< ::Team> locker(fTeam);

        Watchpoint* watchpoint = fTeam->WatchpointAtAddress(address);
        if (watchpoint == NULL)
                return;
        BReference<Watchpoint> watchpointReference(watchpoint);

        locker.Unlock();

        _HandleClearWatchpoint(watchpoint);
}


void
TeamDebugger::_HandleClearWatchpoint(Watchpoint* watchpoint)
{
        fWatchpointManager->UninstallWatchpoint(watchpoint);
}


void
TeamDebugger::_HandleInspectAddress(target_addr_t address,
        TeamMemoryBlock::Listener* listener)
{
        TRACE_CONTROL("TeamDebugger::_HandleInspectAddress(%" B_PRIx64 ", %p)\n",
                address, listener);

        TeamMemoryBlock* memoryBlock = fMemoryBlockManager
                ->GetMemoryBlock(address);

        if (memoryBlock == NULL) {
                _NotifyUser("Inspect Address", "Failed to allocate memory block");
                return;
        }

        if (!memoryBlock->IsValid()) {
                AutoLocker< ::Team> teamLocker(fTeam);

                if (!memoryBlock->HasListener(listener))
                        memoryBlock->AddListener(listener);

                TeamMemory* memory = fTeam->GetTeamMemory();
                // schedule the job
                status_t result;
                if ((result = fWorker->ScheduleJob(
                        new(std::nothrow) RetrieveMemoryBlockJob(fTeam, memory,
                                memoryBlock),
                        this)) != B_OK) {

                        memoryBlock->NotifyDataRetrieved(result);
                        memoryBlock->ReleaseReference();

                        _NotifyUser("Inspect Address", "Failed to retrieve memory data: %s",
                                strerror(result));
                }
        } else
                memoryBlock->NotifyDataRetrieved();

}


void
TeamDebugger::_HandleWriteMemory(target_addr_t address, void* data,
        target_size_t size)
{
        TRACE_CONTROL("TeamDebugger::_HandleWriteTargetMemory(%" B_PRIx64 ", %p, "
                "%" B_PRIu64 ")\n", address, data, size);

        AutoLocker< ::Team> teamLocker(fTeam);
        TeamMemory* memory = fTeam->GetTeamMemory();
        // schedule the job
        status_t result;
        if ((result = fWorker->ScheduleJob(
                new(std::nothrow) WriteMemoryJob(fTeam, memory, address, data, size),
                this)) != B_OK) {
                _NotifyUser("Write Memory", "Failed to write memory data: %s",
                        strerror(result));
        }
}


void
TeamDebugger::_HandleEvaluateExpression(SourceLanguage* language,
        ExpressionInfo* info, StackFrame* frame, ::Thread* thread)
{
        status_t result = fWorker->ScheduleJob(
                new(std::nothrow) ExpressionEvaluationJob(fTeam, fDebuggerInterface,
                        language, info, frame, thread));
        if (result != B_OK) {
                _NotifyUser("Evaluate Expression", "Failed to evaluate expression: %s",
                        strerror(result));
        }
}


void
TeamDebugger::_HandleWriteCoreFile(const entry_ref& targetPath)
{
        status_t result = fWorker->ScheduleJob(
                new(std::nothrow) WriteCoreFileJob(fTeam, fDebuggerInterface,
                        targetPath));
        if (result != B_OK) {
                _NotifyUser("Write Core File", "Failed to write core file: %s",
                        strerror(result));
        }
}


status_t
TeamDebugger::_HandleSetArguments(int argc, const char* const* argv)
{
        fCommandLineArgc = argc;
        fCommandLineArgv = new(std::nothrow) const char*[argc];
        if (fCommandLineArgv == NULL)
                return B_NO_MEMORY;

        memset(const_cast<char **>(fCommandLineArgv), 0, sizeof(char*) * argc);

        for (int i = 0; i < argc; i++) {
                fCommandLineArgv[i] = strdup(argv[i]);
                if (fCommandLineArgv[i] == NULL)
                        return B_NO_MEMORY;
        }

        return B_OK;
}


void
TeamDebugger::_HandleDebugInfoJobUserInput(ImageDebugInfoLoadingState* state)
{
        SpecificImageDebugInfoLoadingState* specificState
                = state->GetSpecificDebugInfoLoadingState();

        ImageDebugLoadingStateHandler* handler;
        if (ImageDebugLoadingStateHandlerRoster::Default()
                        ->FindStateHandler(specificState, handler) != B_OK) {
                TRACE_JOBS("TeamDebugger::_HandleDebugInfoJobUserInput(): "
                        "Failed to find appropriate information handler, aborting.");
                return;
        }

        handler->HandleState(specificState, fUserInterface);
}


ThreadHandler*
TeamDebugger::_GetThreadHandler(thread_id threadID)
{
        AutoLocker< ::Team> locker(fTeam);

        ThreadHandler* handler = fThreadHandlers.Lookup(threadID);
        if (handler != NULL)
                handler->AcquireReference();
        return handler;
}


status_t
TeamDebugger::_AddImage(const ImageInfo& imageInfo, Image** _image)
{
        LocatableFile* file = NULL;
        if (strchr(imageInfo.Name(), '/') != NULL)
                file = fFileManager->GetTargetFile(imageInfo.Name());
        BReference<LocatableFile> imageFileReference(file, true);

        Image* image;
        status_t error = fTeam->AddImage(imageInfo, file, &image);
        if (error != B_OK)
                return error;

        ImageDebugInfoRequested(image);

        ImageHandler* imageHandler = new(std::nothrow) ImageHandler(this, image);
        if (imageHandler != NULL)
                fImageHandlers->Insert(imageHandler);

        if (_image != NULL)
                *_image = image;

        return B_OK;
}


void
TeamDebugger::_LoadSettings()
{
        // get the team name
        AutoLocker< ::Team> locker(fTeam);
        BString teamName = fTeam->Name();
        locker.Unlock();

        // load the settings
        if (fSettingsManager->LoadTeamSettings(teamName, fTeamSettings) != B_OK)
                return;

        // create the saved breakpoints
        for (int32 i = 0; const BreakpointSetting* breakpointSetting
                        = fTeamSettings.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;
                }
                BReference<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;
                BReference<UserBreakpoint> breakpointReference(breakpoint, true);

                breakpoint->SetHidden(breakpointSetting->IsHidden());
                breakpoint->SetCondition(breakpointSetting->Condition());

                // install it
                fBreakpointManager->InstallUserBreakpoint(breakpoint,
                        breakpointSetting->IsEnabled());
        }

        fFileManager->LoadLocationMappings(fTeamSettings.FileManagerSettings());

        const TeamUiSettings* uiSettings = fTeamSettings.UiSettingFor(
                fUserInterface->ID());
        if (uiSettings != NULL)
                        fUserInterface->LoadSettings(uiSettings);

        const TeamSignalSettings* signalSettings = fTeamSettings.SignalSettings();
        if (signalSettings != NULL) {
                fTeam->SetDefaultSignalDisposition(
                        signalSettings->DefaultSignalDisposition());

                int32 signal;
                int32 disposition;
                for (int32 i = 0; i < signalSettings->CountCustomSignalDispositions();
                        i++) {
                        if (signalSettings->GetCustomSignalDispositionAt(i, signal,
                                disposition) == B_OK) {
                                fTeam->SetCustomSignalDisposition(signal, disposition);
                        }
                }
        }
}


void
TeamDebugger::_SaveSettings()
{
        // get the settings
        AutoLocker< ::Team> locker(fTeam);
        TeamSettings settings;
        if (settings.SetTo(fTeam) != B_OK)
                return;

        TeamUiSettings* uiSettings = NULL;
        if (fUserInterface->SaveSettings(uiSettings) != B_OK)
                return;
        if (uiSettings != NULL)
                settings.AddUiSettings(uiSettings);

        // preserve the UI settings from our cached copy.
        for (int32 i = 0; i < fTeamSettings.CountUiSettings(); i++) {
                const TeamUiSettings* oldUiSettings = fTeamSettings.UiSettingAt(i);
                if (strcmp(oldUiSettings->ID(), fUserInterface->ID()) != 0) {
                        TeamUiSettings* clonedSettings = oldUiSettings->Clone();
                        if (clonedSettings != NULL)
                                settings.AddUiSettings(clonedSettings);
                }
        }

        fFileManager->SaveLocationMappings(settings.FileManagerSettings());
        locker.Unlock();

        // save the settings
        fSettingsManager->SaveTeamSettings(settings);
}


void
TeamDebugger::_NotifyUser(const char* title, const char* text,...)
{
        // print the message
        char buffer[1024];
        va_list args;
        va_start(args, text);
        vsnprintf(buffer, sizeof(buffer), text, args);
        va_end(args);

        // notify the user
        fUserInterface->NotifyUser(title, buffer, USER_NOTIFICATION_WARNING);
}


void
TeamDebugger::_ResetUserBackgroundStatusIfNeeded()
{
        if (!fTerminating && !fWorker->HasPendingJobs())
                PostMessage(MSG_RESET_USER_BACKGROUND_STATUS);
}


// #pragma mark - Listener


TeamDebugger::Listener::~Listener()
{
}