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