Debugger: Split into core library and application.
- Add subfolder src/kits/debugger which contains the debugger's core functionality and lower layers. Correspondingly add headers/private/debugger for shared headers to be used by clients such as the Debugger application and eventual remote_debug_server. Adjust various files to account for differences as a result of the split and moves. - Add libdebugger.so to minimal Jamfile.
This commit is contained in:
@@ -0,0 +1,298 @@
|
||||
/*
|
||||
* Copyright 2009, Ingo Weinhold, [email protected].
|
||||
* Copyright 2013-2016, Rene Gollent, [email protected].
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef TEAM_DEBUGGER_H
|
||||
#define TEAM_DEBUGGER_H
|
||||
|
||||
|
||||
#include <debugger.h>
|
||||
#include <Looper.h>
|
||||
|
||||
#include "Team.h"
|
||||
#include "TeamSettings.h"
|
||||
#include "ThreadHandler.h"
|
||||
#include "UserInterface.h"
|
||||
#include "util/Worker.h"
|
||||
|
||||
|
||||
class DebugEvent;
|
||||
class DebuggerInterface;
|
||||
class DebugReportGenerator;
|
||||
class FileManager;
|
||||
class ImageCreatedEvent;
|
||||
class ImageDebugInfoLoadingState;
|
||||
class ImageDeletedEvent;
|
||||
class PostSyscallEvent;
|
||||
class SettingsManager;
|
||||
class TeamDebugInfo;
|
||||
class TeamDeletedEvent;
|
||||
class TeamExecEvent;
|
||||
class TeamMemoryBlockManager;
|
||||
class Thread;
|
||||
class ThreadCreatedEvent;
|
||||
class ThreadDeletedEvent;
|
||||
class ThreadRenamedEvent;
|
||||
class ThreadPriorityChangedEvent;
|
||||
class WatchpointManager;
|
||||
|
||||
|
||||
class TeamDebugger : public BLooper, private UserInterfaceListener,
|
||||
private JobListener, private Team::Listener {
|
||||
public:
|
||||
class Listener;
|
||||
|
||||
public:
|
||||
TeamDebugger(Listener* listener,
|
||||
UserInterface* userInterface,
|
||||
SettingsManager* settingsManager);
|
||||
~TeamDebugger();
|
||||
|
||||
status_t Init(DebuggerInterface* interface,
|
||||
thread_id threadID, int argc,
|
||||
const char* const* argv,
|
||||
bool stopInMain);
|
||||
|
||||
void Activate();
|
||||
|
||||
team_id TeamID() const { return fTeamID; }
|
||||
|
||||
bool IsPostMortem() const { return fIsPostMortem; }
|
||||
|
||||
int ArgumentCount() const
|
||||
{ return fCommandLineArgc; }
|
||||
const char** Arguments() const
|
||||
{ return fCommandLineArgv; }
|
||||
SettingsManager* GetSettingsManager() const
|
||||
{ return fSettingsManager; }
|
||||
|
||||
virtual void MessageReceived(BMessage* message);
|
||||
|
||||
private:
|
||||
// UserInterfaceListener
|
||||
virtual void FunctionSourceCodeRequested(
|
||||
FunctionInstance* function,
|
||||
bool forceDisassembly = false);
|
||||
virtual void SourceEntryLocateRequested(
|
||||
const char* sourcePath,
|
||||
const char* locatedPath);
|
||||
virtual void SourceEntryInvalidateRequested(
|
||||
LocatableFile* sourceFile);
|
||||
virtual void ImageDebugInfoRequested(Image* image);
|
||||
virtual void ValueNodeValueRequested(CpuState* cpuState,
|
||||
ValueNodeContainer* container,
|
||||
ValueNode* valueNode);
|
||||
virtual void ValueNodeWriteRequested(ValueNode* node,
|
||||
CpuState* state,
|
||||
Value* newValue);
|
||||
virtual void ThreadActionRequested(thread_id threadID,
|
||||
uint32 action, target_addr_t address);
|
||||
|
||||
virtual void SetBreakpointRequested(target_addr_t address,
|
||||
bool enabled, bool hidden = false);
|
||||
virtual void SetBreakpointEnabledRequested(
|
||||
UserBreakpoint* breakpoint,
|
||||
bool enabled);
|
||||
virtual void SetBreakpointConditionRequested(
|
||||
UserBreakpoint* breakpoint,
|
||||
const char* condition);
|
||||
virtual void ClearBreakpointConditionRequested(
|
||||
UserBreakpoint* breakpoint);
|
||||
virtual void ClearBreakpointRequested(target_addr_t address);
|
||||
virtual void ClearBreakpointRequested(
|
||||
UserBreakpoint* breakpoint);
|
||||
|
||||
virtual void SetStopOnImageLoadRequested(bool enabled,
|
||||
bool useImageNames);
|
||||
virtual void AddStopImageNameRequested(
|
||||
const char* name);
|
||||
virtual void RemoveStopImageNameRequested(
|
||||
const char* name);
|
||||
|
||||
virtual void SetDefaultSignalDispositionRequested(
|
||||
int32 disposition);
|
||||
virtual void SetCustomSignalDispositionRequested(
|
||||
int32 signal, int32 disposition);
|
||||
virtual void RemoveCustomSignalDispositionRequested(
|
||||
int32 signal);
|
||||
|
||||
virtual void SetWatchpointRequested(target_addr_t address,
|
||||
uint32 type, int32 length, bool enabled);
|
||||
virtual void SetWatchpointEnabledRequested(
|
||||
Watchpoint *watchpoint, bool enabled);
|
||||
virtual void ClearWatchpointRequested(target_addr_t address);
|
||||
virtual void ClearWatchpointRequested(
|
||||
Watchpoint* breakpoint);
|
||||
|
||||
virtual void InspectRequested(target_addr_t address,
|
||||
TeamMemoryBlock::Listener* listener);
|
||||
virtual void MemoryWriteRequested(target_addr_t address,
|
||||
const void* data, target_size_t size);
|
||||
|
||||
virtual void ExpressionEvaluationRequested(
|
||||
SourceLanguage* language,
|
||||
ExpressionInfo* info,
|
||||
StackFrame* frame = NULL,
|
||||
::Thread* thread = NULL);
|
||||
|
||||
virtual void DebugReportRequested(entry_ref* targetPath);
|
||||
|
||||
virtual void WriteCoreFileRequested(entry_ref* targetPath);
|
||||
|
||||
virtual void TeamRestartRequested();
|
||||
|
||||
virtual bool UserInterfaceQuitRequested(
|
||||
QuitOption quitOption);
|
||||
|
||||
// JobListener
|
||||
virtual void JobStarted(Job* job);
|
||||
virtual void JobDone(Job* job);
|
||||
virtual void JobWaitingForInput(Job* job);
|
||||
virtual void JobFailed(Job* job);
|
||||
virtual void JobAborted(Job* job);
|
||||
|
||||
// Team::Listener
|
||||
virtual void ThreadStateChanged(
|
||||
const ::Team::ThreadEvent& event);
|
||||
virtual void ThreadCpuStateChanged(
|
||||
const ::Team::ThreadEvent& event);
|
||||
virtual void ThreadStackTraceChanged(
|
||||
const ::Team::ThreadEvent& event);
|
||||
virtual void ImageDebugInfoChanged(
|
||||
const ::Team::ImageEvent& event);
|
||||
|
||||
private:
|
||||
struct ImageHandler;
|
||||
struct ImageHandlerHashDefinition;
|
||||
struct ImageInfoPendingThread;
|
||||
struct ImageInfoPendingThreadHashDefinition;
|
||||
|
||||
typedef BOpenHashTable<ImageHandlerHashDefinition> ImageHandlerTable;
|
||||
typedef BOpenHashTable<ImageInfoPendingThreadHashDefinition>
|
||||
ImageInfoPendingThreadTable;
|
||||
|
||||
private:
|
||||
static status_t _DebugEventListenerEntry(void* data);
|
||||
status_t _DebugEventListener();
|
||||
|
||||
void _HandleDebuggerMessage(DebugEvent* event);
|
||||
|
||||
bool _HandleTeamDeleted(
|
||||
TeamDeletedEvent* event);
|
||||
bool _HandleThreadCreated(
|
||||
ThreadCreatedEvent* event);
|
||||
bool _HandleThreadRenamed(
|
||||
ThreadRenamedEvent* event);
|
||||
bool _HandleThreadPriorityChanged(
|
||||
ThreadPriorityChangedEvent* event);
|
||||
bool _HandleThreadDeleted(
|
||||
ThreadDeletedEvent* event);
|
||||
bool _HandleImageCreated(
|
||||
ImageCreatedEvent* event);
|
||||
bool _HandleImageDeleted(
|
||||
ImageDeletedEvent* event);
|
||||
bool _HandlePostSyscall(
|
||||
PostSyscallEvent* event);
|
||||
|
||||
void _PrepareForTeamExec(TeamExecEvent* event);
|
||||
|
||||
void _HandleImageDebugInfoChanged(image_id imageID);
|
||||
void _HandleImageFileChanged(image_id imageID);
|
||||
|
||||
void _HandleSetUserBreakpoint(target_addr_t address,
|
||||
bool enabled, bool hidden);
|
||||
void _HandleSetUserBreakpoint(
|
||||
UserBreakpoint* breakpoint, bool enabled);
|
||||
void _HandleClearUserBreakpoint(
|
||||
target_addr_t address);
|
||||
void _HandleClearUserBreakpoint(
|
||||
UserBreakpoint* breakpoint);
|
||||
|
||||
void _HandleSetWatchpoint(target_addr_t address,
|
||||
uint32 type, int32 length, bool enabled);
|
||||
void _HandleSetWatchpoint(
|
||||
Watchpoint* watchpoint, bool enabled);
|
||||
void _HandleClearWatchpoint( target_addr_t address);
|
||||
void _HandleClearWatchpoint(Watchpoint* watchpoint);
|
||||
|
||||
void _HandleInspectAddress(
|
||||
target_addr_t address,
|
||||
TeamMemoryBlock::Listener* listener);
|
||||
void _HandleWriteMemory(
|
||||
target_addr_t address, void* data,
|
||||
target_size_t size);
|
||||
|
||||
void _HandleEvaluateExpression(
|
||||
SourceLanguage* language,
|
||||
ExpressionInfo* info,
|
||||
StackFrame* frame,
|
||||
::Thread* thread);
|
||||
|
||||
void _HandleWriteCoreFile(const entry_ref& ref);
|
||||
|
||||
status_t _HandleSetArguments(int argc,
|
||||
const char* const* argv);
|
||||
|
||||
void _HandleDebugInfoJobUserInput(
|
||||
ImageDebugInfoLoadingState* state);
|
||||
|
||||
ThreadHandler* _GetThreadHandler(thread_id threadID);
|
||||
|
||||
status_t _AddImage(const ImageInfo& imageInfo,
|
||||
Image** _image = NULL);
|
||||
|
||||
void _LoadSettings();
|
||||
void _SaveSettings();
|
||||
|
||||
void _NotifyUser(const char* title,
|
||||
const char* text,...);
|
||||
|
||||
void _ResetUserBackgroundStatusIfNeeded();
|
||||
// updates user interface to
|
||||
// ready/completed message
|
||||
// for background work status
|
||||
|
||||
private:
|
||||
Listener* fListener;
|
||||
SettingsManager* fSettingsManager;
|
||||
::Team* fTeam;
|
||||
team_id fTeamID;
|
||||
bool fIsPostMortem;
|
||||
ThreadHandlerTable fThreadHandlers;
|
||||
// protected by the team lock
|
||||
ImageHandlerTable* fImageHandlers;
|
||||
ImageInfoPendingThreadTable* fImageInfoPendingThreads;
|
||||
DebuggerInterface* fDebuggerInterface;
|
||||
TeamDebugInfo* fTeamDebugInfo;
|
||||
FileManager* fFileManager;
|
||||
Worker* fWorker;
|
||||
BreakpointManager* fBreakpointManager;
|
||||
WatchpointManager* fWatchpointManager;
|
||||
TeamMemoryBlockManager*
|
||||
fMemoryBlockManager;
|
||||
DebugReportGenerator*
|
||||
fReportGenerator;
|
||||
thread_id fDebugEventListener;
|
||||
UserInterface* fUserInterface;
|
||||
volatile bool fTerminating;
|
||||
bool fKillTeamOnQuit;
|
||||
TeamSettings fTeamSettings;
|
||||
int fCommandLineArgc;
|
||||
const char** fCommandLineArgv;
|
||||
bool fExecPending;
|
||||
};
|
||||
|
||||
|
||||
class TeamDebugger::Listener {
|
||||
public:
|
||||
virtual ~Listener();
|
||||
|
||||
virtual void TeamDebuggerStarted(TeamDebugger* debugger) = 0;
|
||||
virtual void TeamDebuggerRestartRequested(
|
||||
TeamDebugger* debugger) = 0;
|
||||
virtual void TeamDebuggerQuit(TeamDebugger* debugger) = 0;
|
||||
};
|
||||
|
||||
|
||||
#endif // TEAM_DEBUGGER_H
|
||||
@@ -0,0 +1,173 @@
|
||||
/*
|
||||
* Copyright 2009, Ingo Weinhold, [email protected].
|
||||
* Copyright 2014-2016, Rene Gollent, [email protected].
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
#ifndef THREAD_HANDLER_H
|
||||
#define THREAD_HANDLER_H
|
||||
|
||||
|
||||
#include <Referenceable.h>
|
||||
#include <util/OpenHashTable.h>
|
||||
|
||||
#include "Breakpoint.h"
|
||||
#include "ImageDebugInfoProvider.h"
|
||||
#include "model/Thread.h"
|
||||
|
||||
|
||||
class BreakpointHitEvent;
|
||||
class BreakpointManager;
|
||||
class DebugEvent;
|
||||
class DebuggerCallEvent;
|
||||
class DebuggerInterface;
|
||||
class ExceptionOccurredEvent;
|
||||
class ExpressionResult;
|
||||
class ImageDebugInfoJobListener;
|
||||
class JobListener;
|
||||
class SignalReceivedEvent;
|
||||
class SingleStepEvent;
|
||||
class StackFrame;
|
||||
class Statement;
|
||||
class ThreadDebuggedEvent;
|
||||
class WatchpointHitEvent;
|
||||
class Worker;
|
||||
|
||||
|
||||
class ThreadHandler : public BReferenceable, private ImageDebugInfoProvider,
|
||||
private BreakpointClient {
|
||||
public:
|
||||
ThreadHandler(::Thread* thread, Worker* worker,
|
||||
DebuggerInterface* debuggerInterface,
|
||||
JobListener* listener,
|
||||
BreakpointManager* breakpointManager);
|
||||
~ThreadHandler();
|
||||
|
||||
void Init();
|
||||
|
||||
thread_id ThreadID() const { return fThread->ID(); }
|
||||
::Thread* GetThread() const { return fThread; }
|
||||
|
||||
status_t SetBreakpointAndRun(target_addr_t address);
|
||||
// team lock held
|
||||
|
||||
// All Handle*() methods are invoked in team debugger thread,
|
||||
// looper lock held.
|
||||
bool HandleThreadDebugged(
|
||||
ThreadDebuggedEvent* event,
|
||||
const BString& stoppedReason = BString());
|
||||
bool HandleDebuggerCall(
|
||||
DebuggerCallEvent* event);
|
||||
bool HandleBreakpointHit(
|
||||
BreakpointHitEvent* event);
|
||||
bool HandleWatchpointHit(
|
||||
WatchpointHitEvent* event);
|
||||
bool HandleSingleStep(
|
||||
SingleStepEvent* event);
|
||||
bool HandleExceptionOccurred(
|
||||
ExceptionOccurredEvent* event);
|
||||
bool HandleSignalReceived(
|
||||
SignalReceivedEvent* event);
|
||||
|
||||
void HandleThreadAction(uint32 action,
|
||||
target_addr_t address);
|
||||
|
||||
void HandleThreadStateChanged();
|
||||
void HandleCpuStateChanged();
|
||||
void HandleStackTraceChanged();
|
||||
|
||||
private:
|
||||
friend class ExpressionEvaluationListener;
|
||||
|
||||
private:
|
||||
// ImageDebugInfoProvider
|
||||
virtual status_t GetImageDebugInfo(Image* image,
|
||||
ImageDebugInfo*& _info);
|
||||
|
||||
bool _HandleThreadStopped(CpuState* cpuState,
|
||||
uint32 stoppedReason,
|
||||
const BString& stoppedReasonInfo
|
||||
= BString());
|
||||
|
||||
bool _HandleSetAddress(CpuState* cpuState,
|
||||
target_addr_t address);
|
||||
|
||||
void _SetThreadState(uint32 state,
|
||||
CpuState* cpuState, uint32 stoppedReason,
|
||||
const BString& stoppedReasonInfo);
|
||||
|
||||
Statement* _GetStatementAtInstructionPointer(
|
||||
StackFrame* frame);
|
||||
|
||||
void _StepFallback();
|
||||
bool _DoStepOver(CpuState* cpuState);
|
||||
|
||||
status_t _InstallTemporaryBreakpoint(
|
||||
target_addr_t address);
|
||||
void _UninstallTemporaryBreakpoint();
|
||||
void _ClearContinuationState();
|
||||
void _RunThread(target_addr_t instructionPointer);
|
||||
void _SingleStepThread(
|
||||
target_addr_t instructionPointer);
|
||||
|
||||
bool _HandleBreakpointConditionIfNeeded(
|
||||
CpuState* cpuState);
|
||||
void _HandleBreakpointConditionEvaluated(
|
||||
ExpressionResult* value);
|
||||
bool _CheckStopCondition();
|
||||
|
||||
bool _HandleBreakpointHitStep(CpuState* cpuState);
|
||||
bool _HandleSingleStepStep(CpuState* cpuState);
|
||||
|
||||
bool _HasExitedFrame(target_addr_t framePointer)
|
||||
const;
|
||||
|
||||
private:
|
||||
::Thread* fThread;
|
||||
Worker* fWorker;
|
||||
DebuggerInterface* fDebuggerInterface;
|
||||
JobListener* fJobListener;
|
||||
BreakpointManager* fBreakpointManager;
|
||||
uint32 fStepMode;
|
||||
Statement* fStepStatement;
|
||||
target_addr_t fBreakpointAddress;
|
||||
target_addr_t fSteppedOverFunctionAddress;
|
||||
target_addr_t fPreviousInstructionPointer;
|
||||
target_addr_t fPreviousFrameAddress;
|
||||
bool fSingleStepping;
|
||||
sem_id fConditionWaitSem;
|
||||
ExpressionResult* fConditionResult;
|
||||
|
||||
public:
|
||||
ThreadHandler* fNext;
|
||||
};
|
||||
|
||||
|
||||
struct ThreadHandlerHashDefinition {
|
||||
typedef thread_id KeyType;
|
||||
typedef ThreadHandler ValueType;
|
||||
|
||||
size_t HashKey(thread_id key) const
|
||||
{
|
||||
return (size_t)key;
|
||||
}
|
||||
|
||||
size_t Hash(const ThreadHandler* value) const
|
||||
{
|
||||
return HashKey(value->ThreadID());
|
||||
}
|
||||
|
||||
bool Compare(thread_id key, ThreadHandler* value) const
|
||||
{
|
||||
return value->ThreadID() == key;
|
||||
}
|
||||
|
||||
ThreadHandler*& GetLink(ThreadHandler* value) const
|
||||
{
|
||||
return value->fNext;
|
||||
}
|
||||
};
|
||||
|
||||
typedef BOpenHashTable<ThreadHandlerHashDefinition> ThreadHandlerTable;
|
||||
|
||||
|
||||
#endif // THREAD_HANDLER_H
|
||||
Reference in New Issue
Block a user