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 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 37 TargetHostInterface::TargetHostInterface() 38 : 39 BLooper(), 40 fListeners(), 41 fTeamDebuggers(20, false) 42 { 43 } 44 45 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 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 96 TargetHostInterface::CountTeamDebuggers() const 97 { 98 return fTeamDebuggers.CountItems(); 99 } 100 101 102 TeamDebugger* 103 TargetHostInterface::TeamDebuggerAt(int32 index) const 104 { 105 return fTeamDebuggers.ItemAt(index); 106 } 107 108 109 TeamDebugger* 110 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 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 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 145 TargetHostInterface::AddListener(Listener* listener) 146 { 147 AutoLocker<TargetHostInterface> interfaceLocker(this); 148 fListeners.Add(listener); 149 } 150 151 152 void 153 TargetHostInterface::RemoveListener(Listener* listener) 154 { 155 AutoLocker<TargetHostInterface> interfaceLocker(this); 156 fListeners.Remove(listener); 157 } 158 159 160 void 161 TargetHostInterface::Quit() 162 { 163 if (fTeamDebuggers.CountItems() == 0) 164 BLooper::Quit(); 165 } 166 167 168 void 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 214 TargetHostInterface::TeamDebuggerStarted(TeamDebugger* debugger) 215 { 216 AutoLocker<TargetHostInterface> locker(this); 217 AddTeamDebugger(debugger); 218 _NotifyTeamDebuggerStarted(debugger); 219 } 220 221 222 void 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 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 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 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 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 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 334 TargetHostInterface::Listener::~Listener() 335 { 336 } 337 338 339 void 340 TargetHostInterface::Listener::TeamDebuggerStarted(TeamDebugger* debugger) 341 { 342 } 343 344 345 void 346 TargetHostInterface::Listener::TeamDebuggerQuit(TeamDebugger* debugger) 347 { 348 } 349 350 351 void 352 TargetHostInterface::Listener::TargetHostInterfaceQuit( 353 TargetHostInterface* interface) 354 { 355 } 356