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