⛏️ index : haiku.git

/*
 * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
 * Copyright 2013-2016, Rene Gollent, rene@gollent.com.
 * 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; }
			UserInterface*		GetUserInterface() const
									{ return fUserInterface; }

	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