xref: /haiku/src/kits/debugger/target_host_interface/TargetHostInterface.cpp (revision 05fc1277c47440dc36134816d70e5723c99cfcd2)
1fce4895dSRene Gollent /*
2fce4895dSRene Gollent  * Copyright 2016, Rene Gollent, rene@gollent.com.
3fce4895dSRene Gollent  * Distributed under the terms of the MIT License.
4fce4895dSRene Gollent  */
5fce4895dSRene Gollent 
6fce4895dSRene Gollent #include "TargetHostInterface.h"
7fce4895dSRene Gollent 
8fce4895dSRene Gollent #include <stdio.h>
9fce4895dSRene Gollent 
10fce4895dSRene Gollent #include <AutoLocker.h>
11fce4895dSRene Gollent 
12fce4895dSRene Gollent #include "DebuggerInterface.h"
13fce4895dSRene Gollent #include "MessageCodes.h"
14fce4895dSRene Gollent #include "TeamDebugger.h"
15fce4895dSRene Gollent 
16fce4895dSRene Gollent 
17fce4895dSRene Gollent // #pragma mark - TeamDebuggerOptions
18fce4895dSRene Gollent 
19fce4895dSRene Gollent 
TeamDebuggerOptions()20fce4895dSRene Gollent TeamDebuggerOptions::TeamDebuggerOptions()
21fce4895dSRene Gollent 	:
22fce4895dSRene Gollent 	requestType(TEAM_DEBUGGER_REQUEST_UNKNOWN),
23fce4895dSRene Gollent 	commandLineArgc(0),
24fce4895dSRene Gollent 	commandLineArgv(NULL),
25fce4895dSRene Gollent 	team(-1),
26fce4895dSRene Gollent 	thread(-1),
27fce4895dSRene Gollent 	settingsManager(NULL),
28fce4895dSRene Gollent 	userInterface(NULL),
29fce4895dSRene Gollent 	coreFilePath(NULL)
30fce4895dSRene Gollent {
31fce4895dSRene Gollent }
32fce4895dSRene Gollent 
33fce4895dSRene Gollent 
34fce4895dSRene Gollent // #pragma mark - TargetHostInterface
35fce4895dSRene Gollent 
36fce4895dSRene Gollent 
TargetHostInterface()37fce4895dSRene Gollent TargetHostInterface::TargetHostInterface()
38fce4895dSRene Gollent 	:
39fce4895dSRene Gollent 	BLooper(),
40fce4895dSRene Gollent 	fListeners(),
41fce4895dSRene Gollent 	fTeamDebuggers(20, false)
42fce4895dSRene Gollent {
43fce4895dSRene Gollent }
44fce4895dSRene Gollent 
45fce4895dSRene Gollent 
~TargetHostInterface()46fce4895dSRene Gollent TargetHostInterface::~TargetHostInterface()
47fce4895dSRene Gollent {
48fce4895dSRene Gollent 	for (ListenerList::Iterator it = fListeners.GetIterator();
49fce4895dSRene Gollent 			Listener* listener = it.Next();) {
50fce4895dSRene Gollent 		listener->TargetHostInterfaceQuit(this);
51fce4895dSRene Gollent 	}
52fce4895dSRene Gollent }
53fce4895dSRene Gollent 
54fce4895dSRene Gollent 
55fce4895dSRene Gollent status_t
StartTeamDebugger(const TeamDebuggerOptions & options)56fce4895dSRene Gollent TargetHostInterface::StartTeamDebugger(const TeamDebuggerOptions& options)
57fce4895dSRene Gollent {
58fce4895dSRene Gollent 	// we only want to stop in main for teams we're responsible for
59fce4895dSRene Gollent 	// creating ourselves.
60fce4895dSRene Gollent 	bool stopInMain = options.requestType == TEAM_DEBUGGER_REQUEST_CREATE;
61fce4895dSRene Gollent 	team_id team = options.team;
62fce4895dSRene Gollent 	thread_id thread = options.thread;
63fce4895dSRene Gollent 
64fce4895dSRene Gollent 	AutoLocker<TargetHostInterface> interfaceLocker(this);
65fce4895dSRene Gollent 	if (options.requestType == TEAM_DEBUGGER_REQUEST_CREATE) {
66fce4895dSRene Gollent 		status_t error = CreateTeam(options.commandLineArgc,
67fce4895dSRene Gollent 			options.commandLineArgv, team);
68fce4895dSRene Gollent 		if (error != B_OK)
69fce4895dSRene Gollent 			return error;
70fce4895dSRene Gollent 		thread = team;
71fce4895dSRene Gollent 	}
72fce4895dSRene Gollent 
73fce4895dSRene Gollent 	if (options.requestType != TEAM_DEBUGGER_REQUEST_LOAD_CORE) {
74fce4895dSRene Gollent 
75fce4895dSRene Gollent 		if (team < 0 && thread < 0)
76fce4895dSRene Gollent 			return B_BAD_VALUE;
77fce4895dSRene Gollent 
78fce4895dSRene Gollent 		if (team < 0) {
79fce4895dSRene Gollent 			status_t error = FindTeamByThread(thread, team);
80fce4895dSRene Gollent 			if (error != B_OK)
81fce4895dSRene Gollent 				return error;
82fce4895dSRene Gollent 		}
83fce4895dSRene Gollent 
84fce4895dSRene Gollent 		TeamDebugger* debugger = FindTeamDebugger(team);
85fce4895dSRene Gollent 		if (debugger != NULL) {
86fce4895dSRene Gollent 			debugger->Activate();
87fce4895dSRene Gollent 			return B_OK;
88fce4895dSRene Gollent 		}
89fce4895dSRene Gollent 	}
90fce4895dSRene Gollent 
91fce4895dSRene Gollent 	return _StartTeamDebugger(team, options, stopInMain);
92fce4895dSRene Gollent }
93fce4895dSRene Gollent 
94fce4895dSRene Gollent 
95fce4895dSRene Gollent int32
CountTeamDebuggers() const96fce4895dSRene Gollent TargetHostInterface::CountTeamDebuggers() const
97fce4895dSRene Gollent {
98fce4895dSRene Gollent 	return fTeamDebuggers.CountItems();
99fce4895dSRene Gollent }
100fce4895dSRene Gollent 
101fce4895dSRene Gollent 
102fce4895dSRene Gollent TeamDebugger*
TeamDebuggerAt(int32 index) const103fce4895dSRene Gollent TargetHostInterface::TeamDebuggerAt(int32 index) const
104fce4895dSRene Gollent {
105fce4895dSRene Gollent 	return fTeamDebuggers.ItemAt(index);
106fce4895dSRene Gollent }
107fce4895dSRene Gollent 
108fce4895dSRene Gollent 
109fce4895dSRene Gollent TeamDebugger*
FindTeamDebugger(team_id team) const110fce4895dSRene Gollent TargetHostInterface::FindTeamDebugger(team_id team) const
111fce4895dSRene Gollent {
112fce4895dSRene Gollent 	for (int32 i = 0; i < fTeamDebuggers.CountItems(); i++) {
113fce4895dSRene Gollent 		TeamDebugger* debugger = fTeamDebuggers.ItemAt(i);
114fce4895dSRene Gollent 		if (debugger->TeamID() == team && !debugger->IsPostMortem())
115fce4895dSRene Gollent 			return debugger;
116fce4895dSRene Gollent 	}
117fce4895dSRene Gollent 
118fce4895dSRene Gollent 	return NULL;
119fce4895dSRene Gollent }
120fce4895dSRene Gollent 
121fce4895dSRene Gollent 
122fce4895dSRene Gollent status_t
AddTeamDebugger(TeamDebugger * debugger)123fce4895dSRene Gollent TargetHostInterface::AddTeamDebugger(TeamDebugger* debugger)
124fce4895dSRene Gollent {
125fce4895dSRene Gollent 	if (!fTeamDebuggers.BinaryInsert(debugger, &_CompareDebuggers))
126fce4895dSRene Gollent 		return B_NO_MEMORY;
127fce4895dSRene Gollent 
128fce4895dSRene Gollent 	return B_OK;
129fce4895dSRene Gollent }
130fce4895dSRene Gollent 
131fce4895dSRene Gollent 
132fce4895dSRene Gollent void
RemoveTeamDebugger(TeamDebugger * debugger)133fce4895dSRene Gollent TargetHostInterface::RemoveTeamDebugger(TeamDebugger* debugger)
134fce4895dSRene Gollent {
135fce4895dSRene Gollent 	for (int32 i = 0; i < fTeamDebuggers.CountItems(); i++) {
136fce4895dSRene Gollent 		if (fTeamDebuggers.ItemAt(i) == debugger) {
137fce4895dSRene Gollent 			fTeamDebuggers.RemoveItemAt(i);
138fce4895dSRene Gollent 			break;
139fce4895dSRene Gollent 		}
140fce4895dSRene Gollent 	}
141fce4895dSRene Gollent }
142fce4895dSRene Gollent 
143fce4895dSRene Gollent 
144fce4895dSRene Gollent void
AddListener(Listener * listener)145fce4895dSRene Gollent TargetHostInterface::AddListener(Listener* listener)
146fce4895dSRene Gollent {
147fce4895dSRene Gollent 	AutoLocker<TargetHostInterface> interfaceLocker(this);
148fce4895dSRene Gollent 	fListeners.Add(listener);
149fce4895dSRene Gollent }
150fce4895dSRene Gollent 
151fce4895dSRene Gollent 
152fce4895dSRene Gollent void
RemoveListener(Listener * listener)153fce4895dSRene Gollent TargetHostInterface::RemoveListener(Listener* listener)
154fce4895dSRene Gollent {
155fce4895dSRene Gollent 	AutoLocker<TargetHostInterface> interfaceLocker(this);
156fce4895dSRene Gollent 	fListeners.Remove(listener);
157fce4895dSRene Gollent }
158fce4895dSRene Gollent 
159fce4895dSRene Gollent 
160fce4895dSRene Gollent void
Quit()161fce4895dSRene Gollent TargetHostInterface::Quit()
162fce4895dSRene Gollent {
163fce4895dSRene Gollent 	if (fTeamDebuggers.CountItems() == 0)
164fce4895dSRene Gollent 		BLooper::Quit();
165fce4895dSRene Gollent }
166fce4895dSRene Gollent 
167fce4895dSRene Gollent 
168fce4895dSRene Gollent void
MessageReceived(BMessage * message)169fce4895dSRene Gollent TargetHostInterface::MessageReceived(BMessage* message)
170fce4895dSRene Gollent {
171fce4895dSRene Gollent 	switch (message->what) {
172fce4895dSRene Gollent 	case MSG_TEAM_DEBUGGER_QUIT:
173fce4895dSRene Gollent 	{
174fce4895dSRene Gollent 		thread_id thread;
175fce4895dSRene Gollent 		if (message->FindInt32("thread", &thread) == B_OK)
176fce4895dSRene Gollent 			wait_for_thread(thread, NULL);
177fce4895dSRene Gollent 		break;
178fce4895dSRene Gollent 	}
179fce4895dSRene Gollent 	case MSG_TEAM_RESTART_REQUESTED:
180fce4895dSRene Gollent 	{
181fce4895dSRene Gollent 		int32 teamID;
182fce4895dSRene Gollent 		if (message->FindInt32("team", &teamID) != B_OK)
183fce4895dSRene Gollent 			break;
184fce4895dSRene Gollent 
185fce4895dSRene Gollent 		TeamDebugger* debugger = FindTeamDebugger(teamID);
186fce4895dSRene Gollent 
187*05fc1277SRene Gollent 		UserInterface* userInterface = debugger->GetUserInterface()->Clone();
188*05fc1277SRene Gollent 		if (userInterface == NULL)
189*05fc1277SRene Gollent 			break;
190*05fc1277SRene Gollent 
191*05fc1277SRene Gollent 		BReference<UserInterface> userInterfaceReference(userInterface, true);
192*05fc1277SRene Gollent 
193fce4895dSRene Gollent 		TeamDebuggerOptions options;
194*05fc1277SRene Gollent 		options.requestType = TEAM_DEBUGGER_REQUEST_CREATE;
195fce4895dSRene Gollent 		options.commandLineArgc = debugger->ArgumentCount();
196fce4895dSRene Gollent 		options.commandLineArgv = debugger->Arguments();
197fce4895dSRene Gollent 		options.settingsManager = debugger->GetSettingsManager();
198*05fc1277SRene Gollent 		options.userInterface = userInterface;
199fce4895dSRene Gollent 		status_t result = StartTeamDebugger(options);
200*05fc1277SRene Gollent 		if (result == B_OK) {
201*05fc1277SRene Gollent 			userInterfaceReference.Detach();
202fce4895dSRene Gollent 			debugger->PostMessage(B_QUIT_REQUESTED);
203*05fc1277SRene Gollent 		}
204fce4895dSRene Gollent 		break;
205fce4895dSRene Gollent 	}
206fce4895dSRene Gollent 	default:
207fce4895dSRene Gollent 		BLooper::MessageReceived(message);
208fce4895dSRene Gollent 		break;
209fce4895dSRene Gollent 	}
210fce4895dSRene Gollent }
211fce4895dSRene Gollent 
212fce4895dSRene Gollent 
213fce4895dSRene Gollent void
TeamDebuggerStarted(TeamDebugger * debugger)214fce4895dSRene Gollent TargetHostInterface::TeamDebuggerStarted(TeamDebugger* debugger)
215fce4895dSRene Gollent {
216fce4895dSRene Gollent 	AutoLocker<TargetHostInterface> locker(this);
217fce4895dSRene Gollent 	AddTeamDebugger(debugger);
218fce4895dSRene Gollent 	_NotifyTeamDebuggerStarted(debugger);
219fce4895dSRene Gollent }
220fce4895dSRene Gollent 
221fce4895dSRene Gollent 
222fce4895dSRene Gollent void
TeamDebuggerRestartRequested(TeamDebugger * debugger)223fce4895dSRene Gollent TargetHostInterface::TeamDebuggerRestartRequested(TeamDebugger* debugger)
224fce4895dSRene Gollent {
225fce4895dSRene Gollent 	BMessage message(MSG_TEAM_RESTART_REQUESTED);
226fce4895dSRene Gollent 	message.AddInt32("team", debugger->TeamID());
227fce4895dSRene Gollent 	PostMessage(&message);
228fce4895dSRene Gollent }
229fce4895dSRene Gollent 
230fce4895dSRene Gollent 
231fce4895dSRene Gollent void
TeamDebuggerQuit(TeamDebugger * debugger)232fce4895dSRene Gollent TargetHostInterface::TeamDebuggerQuit(TeamDebugger* debugger)
233fce4895dSRene Gollent {
234fce4895dSRene Gollent 	AutoLocker<TargetHostInterface> interfaceLocker(this);
235fce4895dSRene Gollent 	RemoveTeamDebugger(debugger);
236fce4895dSRene Gollent 
237fce4895dSRene Gollent 	if (debugger->Thread() >= 0) {
238fce4895dSRene Gollent 		_NotifyTeamDebuggerQuit(debugger);
239fce4895dSRene Gollent 		BMessage message(MSG_TEAM_DEBUGGER_QUIT);
240fce4895dSRene Gollent 		message.AddInt32("thread", debugger->Thread());
241fce4895dSRene Gollent 		PostMessage(&message);
242fce4895dSRene Gollent 	}
243fce4895dSRene Gollent }
244fce4895dSRene Gollent 
245fce4895dSRene Gollent 
246fce4895dSRene Gollent status_t
_StartTeamDebugger(team_id teamID,const TeamDebuggerOptions & options,bool stopInMain)247fce4895dSRene Gollent TargetHostInterface::_StartTeamDebugger(team_id teamID,
248fce4895dSRene Gollent 	const TeamDebuggerOptions& options, bool stopInMain)
249fce4895dSRene Gollent {
250fce4895dSRene Gollent 	UserInterface* userInterface = options.userInterface;
251fce4895dSRene Gollent 	if (userInterface == NULL) {
252fce4895dSRene Gollent 		fprintf(stderr, "Error: Requested team debugger start without "
253fce4895dSRene Gollent 			"valid user interface!\n");
254fce4895dSRene Gollent 		return B_BAD_VALUE;
255fce4895dSRene Gollent 	}
256fce4895dSRene Gollent 
257fce4895dSRene Gollent 	thread_id threadID = options.thread;
258fce4895dSRene Gollent 	if (options.commandLineArgv != NULL)
259fce4895dSRene Gollent 		threadID = teamID;
260fce4895dSRene Gollent 
261fce4895dSRene Gollent 	DebuggerInterface* interface = NULL;
262fce4895dSRene Gollent 	TeamDebugger* debugger = NULL;
263fce4895dSRene Gollent 	status_t error = B_OK;
264fce4895dSRene Gollent 	if (options.requestType != TEAM_DEBUGGER_REQUEST_LOAD_CORE) {
265fce4895dSRene Gollent 		error = Attach(teamID, options.thread, interface);
266fce4895dSRene Gollent 		if (error != B_OK) {
267fce4895dSRene Gollent 			fprintf(stderr, "Error: Failed to attach to team %" B_PRId32
268fce4895dSRene Gollent 				": %s!\n", teamID, strerror(error));
269fce4895dSRene Gollent 			return error;
270fce4895dSRene Gollent 		}
271fce4895dSRene Gollent 	} else {
272fce4895dSRene Gollent 		error = LoadCore(options.coreFilePath, interface, threadID);
273fce4895dSRene Gollent 		if (error != B_OK) {
274fce4895dSRene Gollent 			fprintf(stderr, "Error: Failed to load core file '%s': %s!\n",
275fce4895dSRene Gollent 				options.coreFilePath, strerror(error));
276fce4895dSRene Gollent 			return error;
277fce4895dSRene Gollent 		}
278fce4895dSRene Gollent 	}
279fce4895dSRene Gollent 
280fce4895dSRene Gollent 	BReference<DebuggerInterface> debuggerInterfaceReference(interface,
281fce4895dSRene Gollent 		true);
282fce4895dSRene Gollent 	debugger = new(std::nothrow) TeamDebugger(this, userInterface,
283fce4895dSRene Gollent 		options.settingsManager);
284fce4895dSRene Gollent 	if (debugger != NULL) {
285fce4895dSRene Gollent 		error = debugger->Init(interface, threadID,
286fce4895dSRene Gollent 			options.commandLineArgc, options.commandLineArgv, stopInMain);
287fce4895dSRene Gollent 	}
288fce4895dSRene Gollent 
289fce4895dSRene Gollent 	if (error != B_OK) {
290fce4895dSRene Gollent 		printf("Error: debugger for team %" B_PRId32 " on interface %s failed"
291fce4895dSRene Gollent 			" to init: %s!\n", interface->TeamID(), Name(), strerror(error));
292fce4895dSRene Gollent 		delete debugger;
293fce4895dSRene Gollent 		debugger = NULL;
294fce4895dSRene Gollent 	} else {
295fce4895dSRene Gollent 		printf("debugger for team %" B_PRId32 " on interface %s created and"
296fce4895dSRene Gollent 			" initialized successfully!\n", interface->TeamID(), Name());
297fce4895dSRene Gollent 	}
298fce4895dSRene Gollent 
299fce4895dSRene Gollent 	return error;
300fce4895dSRene Gollent }
301fce4895dSRene Gollent 
302fce4895dSRene Gollent 
303fce4895dSRene Gollent void
_NotifyTeamDebuggerStarted(TeamDebugger * debugger)304fce4895dSRene Gollent TargetHostInterface::_NotifyTeamDebuggerStarted(TeamDebugger* debugger)
305fce4895dSRene Gollent {
306fce4895dSRene Gollent 	for (ListenerList::Iterator it = fListeners.GetIterator();
307fce4895dSRene Gollent 			Listener* listener = it.Next();) {
308fce4895dSRene Gollent 		listener->TeamDebuggerStarted(debugger);
309fce4895dSRene Gollent 	}
310fce4895dSRene Gollent }
311fce4895dSRene Gollent 
312fce4895dSRene Gollent 
313fce4895dSRene Gollent void
_NotifyTeamDebuggerQuit(TeamDebugger * debugger)314fce4895dSRene Gollent TargetHostInterface::_NotifyTeamDebuggerQuit(TeamDebugger* debugger)
315fce4895dSRene Gollent {
316fce4895dSRene Gollent 	for (ListenerList::Iterator it = fListeners.GetIterator();
317fce4895dSRene Gollent 			Listener* listener = it.Next();) {
318fce4895dSRene Gollent 		listener->TeamDebuggerQuit(debugger);
319fce4895dSRene Gollent 	}
320fce4895dSRene Gollent }
321fce4895dSRene Gollent 
322fce4895dSRene Gollent 
323fce4895dSRene Gollent /*static*/ int
_CompareDebuggers(const TeamDebugger * a,const TeamDebugger * b)324fce4895dSRene Gollent TargetHostInterface::_CompareDebuggers(const TeamDebugger* a,
325fce4895dSRene Gollent 	const TeamDebugger* b)
326fce4895dSRene Gollent {
327fce4895dSRene Gollent 	return a->TeamID() < b->TeamID() ? -1 : 1;
328fce4895dSRene Gollent }
329fce4895dSRene Gollent 
330fce4895dSRene Gollent 
331fce4895dSRene Gollent // #pragma mark - TargetHostInterface::Listener
332fce4895dSRene Gollent 
333fce4895dSRene Gollent 
~Listener()334fce4895dSRene Gollent TargetHostInterface::Listener::~Listener()
335fce4895dSRene Gollent {
336fce4895dSRene Gollent }
337fce4895dSRene Gollent 
338fce4895dSRene Gollent 
339fce4895dSRene Gollent void
TeamDebuggerStarted(TeamDebugger * debugger)340fce4895dSRene Gollent TargetHostInterface::Listener::TeamDebuggerStarted(TeamDebugger* debugger)
341fce4895dSRene Gollent {
342fce4895dSRene Gollent }
343fce4895dSRene Gollent 
344fce4895dSRene Gollent 
345fce4895dSRene Gollent void
TeamDebuggerQuit(TeamDebugger * debugger)346fce4895dSRene Gollent TargetHostInterface::Listener::TeamDebuggerQuit(TeamDebugger* debugger)
347fce4895dSRene Gollent {
348fce4895dSRene Gollent }
349fce4895dSRene Gollent 
350fce4895dSRene Gollent 
351fce4895dSRene Gollent void
TargetHostInterfaceQuit(TargetHostInterface * interface)352fce4895dSRene Gollent TargetHostInterface::Listener::TargetHostInterfaceQuit(
353fce4895dSRene Gollent 	TargetHostInterface* interface)
354fce4895dSRene Gollent {
355fce4895dSRene Gollent }
356