1c6897b28SRene Gollent/*
2c6897b28SRene Gollent * Copyright 2016, Rene Gollent, rene@gollent.com.
3c6897b28SRene Gollent * Distributed under the terms of the MIT License.
4c6897b28SRene Gollent */
5c6897b28SRene Gollent
6c6897b28SRene Gollent#include "TargetHostInterface.h"
7c6897b28SRene Gollent
8a1afac4dSRene Gollent#include <stdio.h>
9a1afac4dSRene Gollent
10a1afac4dSRene Gollent#include <AutoLocker.h>
11a1afac4dSRene Gollent
12a1afac4dSRene Gollent#include "DebuggerInterface.h"
13a1afac4dSRene Gollent#include "MessageCodes.h"
147442abd1SRene Gollent#include "TeamDebugger.h"
157442abd1SRene Gollent
167442abd1SRene Gollent
17a1afac4dSRene Gollent// #pragma mark - TeamDebuggerOptions
18a1afac4dSRene Gollent
19a1afac4dSRene Gollent
20a1afac4dSRene GollentTeamDebuggerOptions::TeamDebuggerOptions()
21a1afac4dSRene Gollent	:
222c4195e8SRene Gollent	requestType(TEAM_DEBUGGER_REQUEST_UNKNOWN),
23a1afac4dSRene Gollent	commandLineArgc(0),
24a1afac4dSRene Gollent	commandLineArgv(NULL),
25a1afac4dSRene Gollent	team(-1),
26a1afac4dSRene Gollent	thread(-1),
27a1afac4dSRene Gollent	settingsManager(NULL),
282c4195e8SRene Gollent	userInterface(NULL),
292c4195e8SRene Gollent	coreFilePath(NULL)
30a1afac4dSRene Gollent{
31a1afac4dSRene Gollent}
32a1afac4dSRene Gollent
33a1afac4dSRene Gollent
34a1afac4dSRene Gollent// #pragma mark - TargetHostInterface
35a1afac4dSRene Gollent
36a1afac4dSRene Gollent
377442abd1SRene GollentTargetHostInterface::TargetHostInterface()
387442abd1SRene Gollent	:
39a1afac4dSRene Gollent	BLooper(),
405bb138f7SRene Gollent	fListeners(),
417442abd1SRene Gollent	fTeamDebuggers(20, false)
427442abd1SRene Gollent{
437442abd1SRene Gollent}
44c6897b28SRene Gollent
45c6897b28SRene Gollent
46c6897b28SRene GollentTargetHostInterface::~TargetHostInterface()
47c6897b28SRene Gollent{
485bb138f7SRene Gollent	for (ListenerList::Iterator it = fListeners.GetIterator();
495bb138f7SRene Gollent			Listener* listener = it.Next();) {
505bb138f7SRene Gollent		listener->TargetHostInterfaceQuit(this);
515bb138f7SRene Gollent	}
52c6897b28SRene Gollent}
53c6897b28SRene Gollent
54c6897b28SRene Gollent
55a1afac4dSRene Gollentstatus_t
56a1afac4dSRene GollentTargetHostInterface::StartTeamDebugger(const TeamDebuggerOptions& options)
57c6897b28SRene Gollent{
58a1afac4dSRene Gollent	// we only want to stop in main for teams we're responsible for
59a1afac4dSRene Gollent	// creating ourselves.
602c4195e8SRene Gollent	bool stopInMain = options.requestType == TEAM_DEBUGGER_REQUEST_CREATE;
61a1afac4dSRene Gollent	team_id team = options.team;
62a1afac4dSRene Gollent	thread_id thread = options.thread;
63a1afac4dSRene Gollent
64a1afac4dSRene Gollent	AutoLocker<TargetHostInterface> interfaceLocker(this);
652c4195e8SRene Gollent	if (options.requestType == TEAM_DEBUGGER_REQUEST_CREATE) {
66a1afac4dSRene Gollent		status_t error = CreateTeam(options.commandLineArgc,
67a1afac4dSRene Gollent			options.commandLineArgv, team);
68a1afac4dSRene Gollent		if (error != B_OK)
69a1afac4dSRene Gollent			return error;
70a1afac4dSRene Gollent		thread = team;
71a1afac4dSRene Gollent	}
72a1afac4dSRene Gollent
732c4195e8SRene Gollent	if (options.requestType != TEAM_DEBUGGER_REQUEST_LOAD_CORE) {
74a1afac4dSRene Gollent
752c4195e8SRene Gollent		if (team < 0 && thread < 0)
762c4195e8SRene Gollent			return B_BAD_VALUE;
77a1afac4dSRene Gollent
782c4195e8SRene Gollent		if (team < 0) {
792c4195e8SRene Gollent			status_t error = FindTeamByThread(thread, team);
802c4195e8SRene Gollent			if (error != B_OK)
812c4195e8SRene Gollent				return error;
822c4195e8SRene Gollent		}
832c4195e8SRene Gollent
842c4195e8SRene Gollent		TeamDebugger* debugger = FindTeamDebugger(team);
852c4195e8SRene Gollent		if (debugger != NULL) {
862c4195e8SRene Gollent			debugger->Activate();
872c4195e8SRene Gollent			return B_OK;
882c4195e8SRene Gollent		}
89a1afac4dSRene Gollent	}
90a1afac4dSRene Gollent
91a1afac4dSRene Gollent	return _StartTeamDebugger(team, options, stopInMain);
92c6897b28SRene Gollent}
937442abd1SRene Gollent
947442abd1SRene Gollent
957442abd1SRene Gollentint32
967442abd1SRene GollentTargetHostInterface::CountTeamDebuggers() const
977442abd1SRene Gollent{
987442abd1SRene Gollent	return fTeamDebuggers.CountItems();
997442abd1SRene Gollent}
1007442abd1SRene Gollent
1017442abd1SRene Gollent
1027442abd1SRene GollentTeamDebugger*
1037442abd1SRene GollentTargetHostInterface::TeamDebuggerAt(int32 index) const
1047442abd1SRene Gollent{
1057442abd1SRene Gollent	return fTeamDebuggers.ItemAt(index);
1067442abd1SRene Gollent}
1077442abd1SRene Gollent
1087442abd1SRene Gollent
1097442abd1SRene GollentTeamDebugger*
1107442abd1SRene GollentTargetHostInterface::FindTeamDebugger(team_id team) const
1117442abd1SRene Gollent{
11261f0bf59SRene Gollent	for (int32 i = 0; i < fTeamDebuggers.CountItems(); i++) {
11361f0bf59SRene Gollent		TeamDebugger* debugger = fTeamDebuggers.ItemAt(i);
11461f0bf59SRene Gollent		if (debugger->TeamID() == team && !debugger->IsPostMortem())
11561f0bf59SRene Gollent			return debugger;
11661f0bf59SRene Gollent	}
11761f0bf59SRene Gollent
11861f0bf59SRene Gollent	return NULL;
1197442abd1SRene Gollent}
1207442abd1SRene Gollent
1217442abd1SRene Gollent
1227442abd1SRene Gollentstatus_t
1237442abd1SRene GollentTargetHostInterface::AddTeamDebugger(TeamDebugger* debugger)
1247442abd1SRene Gollent{
1257442abd1SRene Gollent	if (!fTeamDebuggers.BinaryInsert(debugger, &_CompareDebuggers))
1267442abd1SRene Gollent		return B_NO_MEMORY;
1277442abd1SRene Gollent
1287442abd1SRene Gollent	return B_OK;
1297442abd1SRene Gollent}
1307442abd1SRene Gollent
1317442abd1SRene Gollent
1327442abd1SRene Gollentvoid
1337442abd1SRene GollentTargetHostInterface::RemoveTeamDebugger(TeamDebugger* debugger)
1347442abd1SRene Gollent{
13561f0bf59SRene Gollent	for (int32 i = 0; i < fTeamDebuggers.CountItems(); i++) {
13661f0bf59SRene Gollent		if (fTeamDebuggers.ItemAt(i) == debugger) {
13761f0bf59SRene Gollent			fTeamDebuggers.RemoveItemAt(i);
13861f0bf59SRene Gollent			break;
13961f0bf59SRene Gollent		}
14061f0bf59SRene Gollent	}
1417442abd1SRene Gollent}
1427442abd1SRene Gollent
1437442abd1SRene Gollent
1445bb138f7SRene Gollentvoid
1455bb138f7SRene GollentTargetHostInterface::AddListener(Listener* listener)
1465bb138f7SRene Gollent{
1475bb138f7SRene Gollent	AutoLocker<TargetHostInterface> interfaceLocker(this);
1485bb138f7SRene Gollent	fListeners.Add(listener);
1495bb138f7SRene Gollent}
1505bb138f7SRene Gollent
1515bb138f7SRene Gollent
1525bb138f7SRene Gollentvoid
1535bb138f7SRene GollentTargetHostInterface::RemoveListener(Listener* listener)
1545bb138f7SRene Gollent{
1555bb138f7SRene Gollent	AutoLocker<TargetHostInterface> interfaceLocker(this);
1565bb138f7SRene Gollent	fListeners.Remove(listener);
1575bb138f7SRene Gollent}
1585bb138f7SRene Gollent
1595bb138f7SRene Gollent
160a1afac4dSRene Gollentvoid
161a1afac4dSRene GollentTargetHostInterface::Quit()
162a1afac4dSRene Gollent{
163a1afac4dSRene Gollent	if (fTeamDebuggers.CountItems() == 0)
164a1afac4dSRene Gollent		BLooper::Quit();
165a1afac4dSRene Gollent}
166a1afac4dSRene Gollent
167a1afac4dSRene Gollent
168a1afac4dSRene Gollentvoid
169a1afac4dSRene GollentTargetHostInterface::MessageReceived(BMessage* message)
170a1afac4dSRene Gollent{
171a1afac4dSRene Gollent	switch (message->what) {
172a1afac4dSRene Gollent	case MSG_TEAM_DEBUGGER_QUIT:
173a1afac4dSRene Gollent	{
174a1afac4dSRene Gollent		thread_id thread;
175a1afac4dSRene Gollent		if (message->FindInt32("thread", &thread) == B_OK)
176a1afac4dSRene Gollent			wait_for_thread(thread, NULL);
177a1afac4dSRene Gollent		break;
178a1afac4dSRene Gollent	}
179a1afac4dSRene Gollent	case MSG_TEAM_RESTART_REQUESTED:
180a1afac4dSRene Gollent	{
181a1afac4dSRene Gollent		int32 teamID;
182a1afac4dSRene Gollent		if (message->FindInt32("team", &teamID) != B_OK)
183a1afac4dSRene Gollent			break;
184a1afac4dSRene Gollent
185a1afac4dSRene Gollent		TeamDebugger* debugger = FindTeamDebugger(teamID);
186a1afac4dSRene Gollent
18705fc1277SRene Gollent		UserInterface* userInterface = debugger->GetUserInterface()->Clone();
18805fc1277SRene Gollent		if (userInterface == NULL)
18905fc1277SRene Gollent			break;
19005fc1277SRene Gollent
19105fc1277SRene Gollent		BReference<UserInterface> userInterfaceReference(userInterface, true);
19205fc1277SRene Gollent
193a1afac4dSRene Gollent		TeamDebuggerOptions options;
19405fc1277SRene Gollent		options.requestType = TEAM_DEBUGGER_REQUEST_CREATE;
195a1afac4dSRene Gollent		options.commandLineArgc = debugger->ArgumentCount();
196a1afac4dSRene Gollent		options.commandLineArgv = debugger->Arguments();
197a1afac4dSRene Gollent		options.settingsManager = debugger->GetSettingsManager();
19805fc1277SRene Gollent		options.userInterface = userInterface;
199a1afac4dSRene Gollent		status_t result = StartTeamDebugger(options);
20005fc1277SRene Gollent		if (result == B_OK) {
20105fc1277SRene Gollent			userInterfaceReference.Detach();
202a1afac4dSRene Gollent			debugger->PostMessage(B_QUIT_REQUESTED);
20305fc1277SRene Gollent		}
204a1afac4dSRene Gollent		break;
205a1afac4dSRene Gollent	}
206a1afac4dSRene Gollent	default:
207a1afac4dSRene Gollent		BLooper::MessageReceived(message);
208a1afac4dSRene Gollent		break;
209a1afac4dSRene Gollent	}
210a1afac4dSRene Gollent}
211a1afac4dSRene Gollent
212a1afac4dSRene Gollent
213a1afac4dSRene Gollentvoid
214a1afac4dSRene GollentTargetHostInterface::TeamDebuggerStarted(TeamDebugger* debugger)
215a1afac4dSRene Gollent{
216a1afac4dSRene Gollent	AutoLocker<TargetHostInterface> locker(this);
217a1afac4dSRene Gollent	AddTeamDebugger(debugger);
2185bb138f7SRene Gollent	_NotifyTeamDebuggerStarted(debugger);
219a1afac4dSRene Gollent}
220a1afac4dSRene Gollent
221a1afac4dSRene Gollent
222a1afac4dSRene Gollentvoid
223a1afac4dSRene GollentTargetHostInterface::TeamDebuggerRestartRequested(TeamDebugger* debugger)
224a1afac4dSRene Gollent{
225a1afac4dSRene Gollent	BMessage message(MSG_TEAM_RESTART_REQUESTED);
226a1afac4dSRene Gollent	message.AddInt32("team", debugger->TeamID());
227a1afac4dSRene Gollent	PostMessage(&message);
228a1afac4dSRene Gollent}
229a1afac4dSRene Gollent
230a1afac4dSRene Gollent
231a1afac4dSRene Gollentvoid
232a1afac4dSRene GollentTargetHostInterface::TeamDebuggerQuit(TeamDebugger* debugger)
233a1afac4dSRene Gollent{
234a1afac4dSRene Gollent	AutoLocker<TargetHostInterface> interfaceLocker(this);
235a1afac4dSRene Gollent	RemoveTeamDebugger(debugger);
236a1afac4dSRene Gollent
237a1afac4dSRene Gollent	if (debugger->Thread() >= 0) {
2385bb138f7SRene Gollent		_NotifyTeamDebuggerQuit(debugger);
239a1afac4dSRene Gollent		BMessage message(MSG_TEAM_DEBUGGER_QUIT);
240a1afac4dSRene Gollent		message.AddInt32("thread", debugger->Thread());
241a1afac4dSRene Gollent		PostMessage(&message);
242a1afac4dSRene Gollent	}
243a1afac4dSRene Gollent}
244a1afac4dSRene Gollent
245a1afac4dSRene Gollent
246a1afac4dSRene Gollentstatus_t
247a1afac4dSRene GollentTargetHostInterface::_StartTeamDebugger(team_id teamID,
248a1afac4dSRene Gollent	const TeamDebuggerOptions& options, bool stopInMain)
249a1afac4dSRene Gollent{
250a1afac4dSRene Gollent	UserInterface* userInterface = options.userInterface;
251a1afac4dSRene Gollent	if (userInterface == NULL) {
252880a6464SRene Gollent		fprintf(stderr, "Error: Requested team debugger start without "
253880a6464SRene Gollent			"valid user interface!\n");
254880a6464SRene Gollent		return B_BAD_VALUE;
255a1afac4dSRene Gollent	}
256a1afac4dSRene Gollent
257a1afac4dSRene Gollent	thread_id threadID = options.thread;
258a1afac4dSRene Gollent	if (options.commandLineArgv != NULL)
259a1afac4dSRene Gollent		threadID = teamID;
260a1afac4dSRene Gollent
261a1afac4dSRene Gollent	DebuggerInterface* interface = NULL;
262a1afac4dSRene Gollent	TeamDebugger* debugger = NULL;
2632c4195e8SRene Gollent	status_t error = B_OK;
2642c4195e8SRene Gollent	if (options.requestType != TEAM_DEBUGGER_REQUEST_LOAD_CORE) {
2652c4195e8SRene Gollent		error = Attach(teamID, options.thread, interface);
2662c4195e8SRene Gollent		if (error != B_OK) {
2672c4195e8SRene Gollent			fprintf(stderr, "Error: Failed to attach to team %" B_PRId32
2682c4195e8SRene Gollent				": %s!\n", teamID, strerror(error));
2692c4195e8SRene Gollent			return error;
2702c4195e8SRene Gollent		}
2712c4195e8SRene Gollent	} else {
2722c4195e8SRene Gollent		error = LoadCore(options.coreFilePath, interface, threadID);
2732c4195e8SRene Gollent		if (error != B_OK) {
2742c4195e8SRene Gollent			fprintf(stderr, "Error: Failed to load core file '%s': %s!\n",
2752c4195e8SRene Gollent				options.coreFilePath, strerror(error));
2762c4195e8SRene Gollent			return error;
2772c4195e8SRene Gollent		}
278a1afac4dSRene Gollent	}
279a1afac4dSRene Gollent
280a1afac4dSRene Gollent	BReference<DebuggerInterface> debuggerInterfaceReference(interface,
281a1afac4dSRene Gollent		true);
282a1afac4dSRene Gollent	debugger = new(std::nothrow) TeamDebugger(this, userInterface,
283a1afac4dSRene Gollent		options.settingsManager);
284a1afac4dSRene Gollent	if (debugger != NULL) {
285a1afac4dSRene Gollent		error = debugger->Init(interface, threadID,
286a1afac4dSRene Gollent			options.commandLineArgc, options.commandLineArgv, stopInMain);
287a1afac4dSRene Gollent	}
288a1afac4dSRene Gollent
289a1afac4dSRene Gollent	if (error != B_OK) {
290a1afac4dSRene Gollent		printf("Error: debugger for team %" B_PRId32 " on interface %s failed"
291a1afac4dSRene Gollent			" to init: %s!\n", interface->TeamID(), Name(), strerror(error));
292a1afac4dSRene Gollent		delete debugger;
293a1afac4dSRene Gollent		debugger = NULL;
294a1afac4dSRene Gollent	} else {
295a1afac4dSRene Gollent		printf("debugger for team %" B_PRId32 " on interface %s created and"
296a1afac4dSRene Gollent			" initialized successfully!\n", interface->TeamID(), Name());
297a1afac4dSRene Gollent	}
298a1afac4dSRene Gollent
299a1afac4dSRene Gollent	return error;
300a1afac4dSRene Gollent}
301a1afac4dSRene Gollent
302a1afac4dSRene Gollent
3035bb138f7SRene Gollentvoid
3045bb138f7SRene GollentTargetHostInterface::_NotifyTeamDebuggerStarted(TeamDebugger* debugger)
3055bb138f7SRene Gollent{
3065bb138f7SRene Gollent	for (ListenerList::Iterator it = fListeners.GetIterator();
3075bb138f7SRene Gollent			Listener* listener = it.Next();) {
3085bb138f7SRene Gollent		listener->TeamDebuggerStarted(debugger);
3095bb138f7SRene Gollent	}
3105bb138f7SRene Gollent}
3115bb138f7SRene Gollent
3125bb138f7SRene Gollent
3135bb138f7SRene Gollentvoid
3145bb138f7SRene GollentTargetHostInterface::_NotifyTeamDebuggerQuit(TeamDebugger* debugger)
3155bb138f7SRene Gollent{
3165bb138f7SRene Gollent	for (ListenerList::Iterator it = fListeners.GetIterator();
3175bb138f7SRene Gollent			Listener* listener = it.Next();) {
3185bb138f7SRene Gollent		listener->TeamDebuggerQuit(debugger);
3195bb138f7SRene Gollent	}
3205bb138f7SRene Gollent}
3215bb138f7SRene Gollent
3225bb138f7SRene Gollent
3237442abd1SRene Gollent/*static*/ int
3247442abd1SRene GollentTargetHostInterface::_CompareDebuggers(const TeamDebugger* a,
3257442abd1SRene Gollent	const TeamDebugger* b)
3267442abd1SRene Gollent{
3277442abd1SRene Gollent	return a->TeamID() < b->TeamID() ? -1 : 1;
3287442abd1SRene Gollent}
3297442abd1SRene Gollent
3307442abd1SRene Gollent
3315bb138f7SRene Gollent// #pragma mark - TargetHostInterface::Listener
3325bb138f7SRene Gollent
3335bb138f7SRene Gollent
3345bb138f7SRene GollentTargetHostInterface::Listener::~Listener()
3355bb138f7SRene Gollent{
3365bb138f7SRene Gollent}
3375bb138f7SRene Gollent
3385bb138f7SRene Gollent
3395bb138f7SRene Gollentvoid
3405bb138f7SRene GollentTargetHostInterface::Listener::TeamDebuggerStarted(TeamDebugger* debugger)
3415bb138f7SRene Gollent{
3425bb138f7SRene Gollent}
3435bb138f7SRene Gollent
3445bb138f7SRene Gollent
3455bb138f7SRene Gollentvoid
3465bb138f7SRene GollentTargetHostInterface::Listener::TeamDebuggerQuit(TeamDebugger* debugger)
3475bb138f7SRene Gollent{
3485bb138f7SRene Gollent}
3495bb138f7SRene Gollent
3505bb138f7SRene Gollent
3515bb138f7SRene Gollentvoid
3525bb138f7SRene GollentTargetHostInterface::Listener::TargetHostInterfaceQuit(
3535bb138f7SRene Gollent	TargetHostInterface* interface)
3545bb138f7SRene Gollent{
3555bb138f7SRene Gollent}
356