1 /* 2 * Copyright 2005-2011, Ingo Weinhold, ingo_weinhold@gmx.de. 3 * Copyright 2013, Rene Gollent, rene@gollent.com. 4 * Copyright 2015, Axel Dörfler, axeld@pinc-software.de. 5 * Distributed under the terms of the MIT License. 6 */ 7 8 9 #include <ctype.h> 10 #include <stdio.h> 11 #include <stdlib.h> 12 #include <string.h> 13 #include <strings.h> 14 #include <errno.h> 15 #include <signal.h> 16 17 #include <algorithm> 18 #include <map> 19 #include <string> 20 #include <vector> 21 22 #include <debugger.h> 23 #include <image.h> 24 #include <syscalls.h> 25 26 #include "debug_utils.h" 27 28 #include "Context.h" 29 #include "MemoryReader.h" 30 #include "Syscall.h" 31 #include "TypeHandler.h" 32 33 34 using std::map; 35 using std::string; 36 using std::vector; 37 38 39 struct syscall_stats { 40 bigtime_t time; 41 uint32 count; 42 }; 43 44 45 extern void get_syscalls0(vector<Syscall*> &syscalls); 46 extern void get_syscalls1(vector<Syscall*> &syscalls); 47 extern void get_syscalls2(vector<Syscall*> &syscalls); 48 extern void get_syscalls3(vector<Syscall*> &syscalls); 49 extern void get_syscalls4(vector<Syscall*> &syscalls); 50 extern void get_syscalls5(vector<Syscall*> &syscalls); 51 extern void get_syscalls6(vector<Syscall*> &syscalls); 52 extern void get_syscalls7(vector<Syscall*> &syscalls); 53 extern void get_syscalls8(vector<Syscall*> &syscalls); 54 extern void get_syscalls9(vector<Syscall*> &syscalls); 55 extern void get_syscalls10(vector<Syscall*> &syscalls); 56 extern void get_syscalls11(vector<Syscall*> &syscalls); 57 extern void get_syscalls12(vector<Syscall*> &syscalls); 58 extern void get_syscalls13(vector<Syscall*> &syscalls); 59 extern void get_syscalls14(vector<Syscall*> &syscalls); 60 extern void get_syscalls15(vector<Syscall*> &syscalls); 61 extern void get_syscalls16(vector<Syscall*> &syscalls); 62 extern void get_syscalls17(vector<Syscall*> &syscalls); 63 extern void get_syscalls18(vector<Syscall*> &syscalls); 64 extern void get_syscalls19(vector<Syscall*> &syscalls); 65 66 67 extern const char *__progname; 68 static const char *kCommandName = __progname; 69 70 71 // usage 72 static const char *kUsage = 73 "Usage: %s [ <options> ] [ <thread or team ID> | <executable with args> ]\n" 74 "\n" 75 "Traces the syscalls of a thread or a team. If an executable with\n" 76 "arguments is supplied, it is loaded and it's main thread traced.\n" 77 "\n" 78 "Options:\n" 79 " -a - Don't print syscall arguments.\n" 80 " -c - Record and dump syscall usage statistics.\n" 81 " -C - Same as -c, but also print syscalls as usual.\n" 82 " -d <name> - Filter the types that have their contents retrieved.\n" 83 " <name> is one of: strings, enums, simple, complex or\n" 84 " pointer_values\n" 85 " -f - Fast mode. Syscall arguments contents aren't retrieved.\n" 86 " -h, --help - Print this text.\n" 87 " -i - Print integers in decimal format instead of hexadecimal.\n" 88 " -l - Also trace loading the executable. Only considered when\n" 89 " an executable is provided.\n" 90 " --no-color - Don't colorize output.\n" 91 " -r - Don't print syscall return values.\n" 92 " -s - Also trace all threads spawned by the supplied thread,\n" 93 " respectively the loaded executable's main thread.\n" 94 " -t - Also recursively trace all teams created by a traced\n" 95 " thread or team.\n" 96 " -T - Trace all threads of the supplied or loaded executable's\n" 97 " team. If an ID is supplied, it is interpreted as a team\n" 98 " ID.\n" 99 " -o <file> - directs output into the specified file.\n" 100 " -S - prints output to serial debug line.\n" 101 " -g - turns off signal tracing.\n" 102 ; 103 104 105 // terminal color escape sequences 106 // (http://www.dee.ufcg.edu.br/~rrbrandt/tools/ansi.html) 107 static const char *kTerminalTextNormal = "\33[0m"; 108 static const char *kTerminalTextRed = "\33[31m"; 109 static const char *kTerminalTextMagenta = "\33[35m"; 110 static const char *kTerminalTextBlue = "\33[34m"; 111 112 113 // command line args 114 static int sArgc; 115 static const char *const *sArgv; 116 117 // syscalls 118 static vector<Syscall*> sSyscallVector; 119 static map<string, Syscall*> sSyscallMap; 120 121 // statistics 122 typedef map<string, syscall_stats> StatsMap; 123 static StatsMap sSyscallStats; 124 static bigtime_t sSyscallTime; 125 126 127 struct Team { 128 Team(team_id id) 129 : 130 fID(id), 131 fNubPort(-1) 132 { 133 } 134 135 team_id ID() const 136 { 137 return fID; 138 } 139 140 port_id NubPort() const 141 { 142 return fNubPort; 143 } 144 145 MemoryReader& GetMemoryReader() 146 { 147 return fMemoryReader; 148 } 149 150 status_t InstallDebugger(port_id debuggerPort, bool traceTeam, 151 bool traceChildTeams, bool traceSignal) 152 { 153 fNubPort = install_team_debugger(fID, debuggerPort); 154 if (fNubPort < 0) { 155 fprintf(stderr, "%s: Failed to install team debugger: %s\n", 156 kCommandName, strerror(fNubPort)); 157 return fNubPort; 158 } 159 160 // set team debugging flags 161 int32 teamDebugFlags = (traceTeam ? B_TEAM_DEBUG_POST_SYSCALL : 0) 162 | (traceChildTeams ? B_TEAM_DEBUG_TEAM_CREATION : 0) 163 | (traceSignal ? B_TEAM_DEBUG_SIGNALS : 0); 164 if (set_team_debugging_flags(fNubPort, teamDebugFlags) != B_OK) 165 exit(1); 166 167 return fMemoryReader.Init(fNubPort); 168 } 169 170 private: 171 team_id fID; 172 port_id fNubPort; 173 MemoryReader fMemoryReader; 174 }; 175 176 177 static void 178 print_usage(bool error) 179 { 180 // print usage 181 fprintf((error ? stderr : stdout), kUsage, kCommandName); 182 } 183 184 185 static void 186 print_usage_and_exit(bool error) 187 { 188 print_usage(error); 189 exit(error ? 1 : 0); 190 } 191 192 193 static bool 194 get_id(const char *str, int32 &id) 195 { 196 int32 len = strlen(str); 197 for (int32 i = 0; i < len; i++) { 198 if (!isdigit(str[i])) 199 return false; 200 } 201 202 id = atol(str); 203 return true; 204 } 205 206 207 Syscall * 208 get_syscall(const char *name) 209 { 210 map<string, Syscall *>::const_iterator i = sSyscallMap.find(name); 211 if (i == sSyscallMap.end()) 212 return NULL; 213 214 return i->second; 215 } 216 217 218 static void 219 patch_syscalls() 220 { 221 // instead of having this done here manually we should either add the 222 // patching step to gensyscalls also manually or add metadata to 223 // kernel/syscalls.h and have it parsed automatically 224 extern void patch_ioctl(); 225 226 patch_ioctl(); 227 } 228 229 230 static void 231 init_syscalls() 232 { 233 // init the syscall vector 234 get_syscalls0(sSyscallVector); 235 get_syscalls1(sSyscallVector); 236 get_syscalls2(sSyscallVector); 237 get_syscalls3(sSyscallVector); 238 get_syscalls4(sSyscallVector); 239 get_syscalls5(sSyscallVector); 240 get_syscalls6(sSyscallVector); 241 get_syscalls7(sSyscallVector); 242 get_syscalls8(sSyscallVector); 243 get_syscalls9(sSyscallVector); 244 get_syscalls10(sSyscallVector); 245 get_syscalls11(sSyscallVector); 246 get_syscalls12(sSyscallVector); 247 get_syscalls13(sSyscallVector); 248 get_syscalls14(sSyscallVector); 249 get_syscalls15(sSyscallVector); 250 get_syscalls16(sSyscallVector); 251 get_syscalls17(sSyscallVector); 252 get_syscalls18(sSyscallVector); 253 get_syscalls19(sSyscallVector); 254 255 // init the syscall map 256 int32 count = sSyscallVector.size(); 257 for (int32 i = 0; i < count; i++) { 258 Syscall *syscall = sSyscallVector[i]; 259 sSyscallMap[syscall->Name()] = syscall; 260 } 261 262 patch_syscalls(); 263 } 264 265 266 static void 267 record_syscall_stats(const Syscall& syscall, debug_post_syscall& message) 268 { 269 syscall_stats& stats = sSyscallStats[syscall.Name()]; 270 stats.count++; 271 272 bigtime_t time = message.end_time - message.start_time; 273 stats.time += time; 274 sSyscallTime += time; 275 } 276 277 278 static void 279 print_buffer(FILE *outputFile, char* buffer, int32 length) 280 { 281 // output either to file or serial debug line 282 if (outputFile != NULL) 283 fwrite(buffer, length, 1, outputFile); 284 else 285 _kern_debug_output(buffer); 286 } 287 288 289 static void 290 print_to_string(char **_buffer, int32 *_length, const char *format, ...) 291 { 292 va_list list; 293 va_start(list, format); 294 ssize_t length = vsnprintf(*_buffer, *_length, format, list); 295 va_end(list); 296 297 *_buffer += length; 298 *_length -= length; 299 } 300 301 302 static void 303 print_syscall(FILE *outputFile, Syscall* syscall, debug_post_syscall &message, 304 MemoryReader &memoryReader, bool printArguments, uint32 contentsFlags, 305 bool printReturnValue, bool colorize, bool decimal) 306 { 307 char buffer[4096], *string = buffer; 308 int32 length = (int32)sizeof(buffer); 309 310 Context ctx(syscall, (char *)message.args, memoryReader, 311 contentsFlags, decimal); 312 313 // print syscall name 314 if (colorize) { 315 print_to_string(&string, &length, "[%6ld] %s%s%s(", 316 message.origin.thread, kTerminalTextBlue, syscall->Name().c_str(), 317 kTerminalTextNormal); 318 } else { 319 print_to_string(&string, &length, "[%6ld] %s(", 320 message.origin.thread, syscall->Name().c_str()); 321 } 322 323 // print arguments 324 if (printArguments) { 325 int32 count = syscall->CountParameters(); 326 for (int32 i = 0; i < count; i++) { 327 // get the value 328 Parameter *parameter = syscall->ParameterAt(i); 329 TypeHandler *handler = parameter->Handler(); 330 ::string value = 331 handler->GetParameterValue(ctx, parameter, 332 ctx.GetValue(parameter)); 333 334 print_to_string(&string, &length, (i > 0 ? ", %s" : "%s"), 335 value.c_str()); 336 } 337 } 338 339 print_to_string(&string, &length, ")"); 340 341 // print return value 342 if (printReturnValue) { 343 Type *returnType = syscall->ReturnType(); 344 TypeHandler *handler = returnType->Handler(); 345 ::string value = handler->GetReturnValue(ctx, message.return_value); 346 if (value.length() > 0) { 347 print_to_string(&string, &length, " = %s", value.c_str()); 348 349 // if the return type is status_t or ssize_t, print human-readable 350 // error codes 351 if (returnType->TypeName() == "status_t" 352 || ((returnType->TypeName() == "ssize_t" 353 || returnType->TypeName() == "int") 354 && message.return_value < 0)) { 355 print_to_string(&string, &length, " %s", strerror(message.return_value)); 356 } 357 } 358 } 359 360 if (colorize) { 361 print_to_string(&string, &length, " %s(%lld us)%s\n", kTerminalTextMagenta, 362 message.end_time - message.start_time, kTerminalTextNormal); 363 } else { 364 print_to_string(&string, &length, " (%lld us)\n", 365 message.end_time - message.start_time); 366 } 367 368 //for (int32 i = 0; i < 16; i++) { 369 // if (i % 4 == 0) { 370 // if (i > 0) 371 // printf("\n"); 372 // printf(" "); 373 // } else 374 // printf(" "); 375 // printf("%08lx", message.args[i]); 376 //} 377 //printf("\n"); 378 print_buffer(outputFile, buffer, sizeof(buffer) - length); 379 } 380 381 382 static const char * 383 signal_name(int signal) 384 { 385 if (signal >= 0 && signal < NSIG) 386 return strsignal(signal); 387 388 static char buffer[32]; 389 sprintf(buffer, "%d", signal); 390 return buffer; 391 } 392 393 394 static void 395 print_signal(FILE *outputFile, debug_signal_received &message, 396 bool colorize) 397 { 398 char buffer[4096], *string = buffer; 399 int32 length = (int32)sizeof(buffer); 400 int signalNumber = message.signal; 401 402 // print signal name 403 if (colorize) { 404 print_to_string(&string, &length, "[%6ld] --- %s%s (%s) %s---\n", 405 message.origin.thread, kTerminalTextRed, signal_name(signalNumber), 406 strsignal(signalNumber), kTerminalTextNormal); 407 } else { 408 print_to_string(&string, &length, "[%6ld] --- %s (%s) ---\n", 409 message.origin.thread, signal_name(signalNumber), 410 strsignal(signalNumber)); 411 } 412 413 print_buffer(outputFile, buffer, sizeof(buffer) - length); 414 } 415 416 417 static bool 418 compare_stats_by_time( 419 const std::pair<const std::string*, const syscall_stats*>& a, 420 const std::pair<const std::string*, const syscall_stats*>& b) 421 { 422 return a.second->time > b.second->time; 423 } 424 425 426 static void 427 print_stats(FILE* outputFile) 428 { 429 char buffer[4096], *string = buffer; 430 int32 length = (int32)sizeof(buffer); 431 432 typedef std::vector<std::pair<const std::string*, const syscall_stats*> > 433 StatsRefVector; 434 StatsRefVector calls; 435 StatsMap::const_iterator iterator = sSyscallStats.begin(); 436 for (; iterator != sSyscallStats.end(); iterator++) 437 calls.push_back(std::make_pair(&iterator->first, &iterator->second)); 438 439 // Sort calls by time spent 440 std::sort(calls.begin(), calls.end(), compare_stats_by_time); 441 442 print_to_string(&string, &length, "\n%-6s %-10s %-7s %-10s Syscall\n", 443 "Time %", "Usecs", "Calls", "Usecs/call"); 444 print_to_string(&string, &length, "------ ---------- ------- ---------- " 445 "--------------------\n"); 446 447 StatsRefVector::const_iterator callIterator = calls.begin(); 448 for (; callIterator != calls.end(); callIterator++) { 449 const syscall_stats& stats = *callIterator->second; 450 double percent = stats.time * 100.0 / sSyscallTime; 451 bigtime_t perCall = stats.time / stats.count; 452 453 print_to_string(&string, &length, "%6.2f %10" B_PRIu64 " %7" B_PRIu32 454 " %10" B_PRIu64 " %s\n", percent, stats.time, stats.count, perCall, 455 callIterator->first->c_str()); 456 } 457 458 print_buffer(outputFile, buffer, sizeof(buffer) - length); 459 } 460 461 462 int 463 main(int argc, const char *const *argv) 464 { 465 sArgc = argc; 466 sArgv = argv; 467 468 // parameters 469 const char *const *programArgs = NULL; 470 int32 programArgCount = 0; 471 bool printArguments = true; 472 bool colorize = true; 473 bool stats = false; 474 bool trace = true; 475 uint32 contentsFlags = 0; 476 bool decimalFormat = false; 477 bool fastMode = false; 478 bool traceLoading = false; 479 bool printReturnValues = true; 480 bool traceChildThreads = false; 481 bool traceTeam = false; 482 bool traceChildTeams = false; 483 bool traceSignal = true; 484 bool serialOutput = false; 485 FILE *outputFile = stdout; 486 487 // parse arguments 488 for (int argi = 1; argi < argc; argi++) { 489 const char *arg = argv[argi]; 490 if (arg[0] == '-') { 491 // ToDo: improve option parsing so that ie. "-rsf" would also work 492 if (strcmp(arg, "-h") == 0 || strcmp(arg, "--help") == 0) { 493 print_usage_and_exit(false); 494 } else if (strcmp(arg, "-a") == 0) { 495 printArguments = false; 496 } else if (strcmp(arg, "-c") == 0) { 497 stats = true; 498 trace = false; 499 } else if (strcmp(arg, "-C") == 0) { 500 stats = true; 501 } else if (strcmp(arg, "--no-color") == 0) { 502 colorize = false; 503 } else if (strcmp(arg, "-d") == 0) { 504 const char *what = NULL; 505 506 if (arg[2] == '\0' 507 && argi + 1 < argc && argv[argi + 1][0] != '-') { 508 // next arg is what 509 what = argv[++argi]; 510 } else 511 print_usage_and_exit(true); 512 513 if (strcasecmp(what, "strings") == 0) 514 contentsFlags |= Context::STRINGS; 515 else if (strcasecmp(what, "enums") == 0) 516 contentsFlags |= Context::ENUMERATIONS; 517 else if (strcasecmp(what, "simple") == 0) 518 contentsFlags |= Context::SIMPLE_STRUCTS; 519 else if (strcasecmp(what, "complex") == 0) 520 contentsFlags |= Context::COMPLEX_STRUCTS; 521 else if (strcasecmp(what, "pointer_values") == 0) 522 contentsFlags |= Context::POINTER_VALUES; 523 else { 524 fprintf(stderr, "%s: Unknown content filter `%s'\n", 525 kCommandName, what); 526 exit(1); 527 } 528 } else if (strcmp(arg, "-f") == 0) { 529 fastMode = true; 530 } else if (strcmp(arg, "-i") == 0) { 531 decimalFormat = true; 532 } else if (strcmp(arg, "-l") == 0) { 533 traceLoading = true; 534 } else if (strcmp(arg, "-r") == 0) { 535 printReturnValues = false; 536 } else if (strcmp(arg, "-s") == 0) { 537 traceChildThreads = true; 538 } else if (strcmp(arg, "-t") == 0) { 539 traceChildTeams = true; 540 } else if (strcmp(arg, "-T") == 0) { 541 traceTeam = true; 542 } else if (strcmp(arg, "-g") == 0) { 543 traceSignal = false; 544 } else if (strcmp(arg, "-S") == 0) { 545 serialOutput = true; 546 outputFile = NULL; 547 } else if (strncmp(arg, "-o", 2) == 0) { 548 // read filename 549 const char *filename = NULL; 550 if (arg[2] == '=') { 551 // name follows 552 filename = arg + 3; 553 } else if (arg[2] == '\0' 554 && argi + 1 < argc && argv[argi + 1][0] != '-') { 555 // next arg is name 556 filename = argv[++argi]; 557 } else 558 print_usage_and_exit(true); 559 560 outputFile = fopen(filename, "w+"); 561 if (outputFile == NULL) { 562 fprintf(stderr, "%s: Could not open `%s': %s\n", 563 kCommandName, filename, strerror(errno)); 564 exit(1); 565 } 566 } else { 567 print_usage_and_exit(true); 568 } 569 } else { 570 programArgs = argv + argi; 571 programArgCount = argc - argi; 572 break; 573 } 574 } 575 576 // check parameters 577 if (!programArgs) 578 print_usage_and_exit(true); 579 580 if (fastMode) 581 contentsFlags = 0; 582 else if (contentsFlags == 0) 583 contentsFlags = Context::ALL; 584 585 // initialize our syscalls vector and map 586 init_syscalls(); 587 588 // don't colorize the output, if we don't have a terminal 589 if (outputFile == stdout) 590 colorize = colorize && isatty(STDOUT_FILENO); 591 else if (outputFile) 592 colorize = false; 593 594 // get thread/team to be debugged 595 thread_id threadID = -1; 596 team_id teamID = -1; 597 if (programArgCount > 1 598 || !get_id(*programArgs, (traceTeam ? teamID : threadID))) { 599 // we've been given an executable and need to load it 600 threadID = load_program(programArgs, programArgCount, traceLoading); 601 if (threadID < 0) { 602 fprintf(stderr, "%s: Failed to start `%s': %s\n", kCommandName, 603 programArgs[0], strerror(threadID)); 604 exit(1); 605 } 606 } 607 608 // get the team ID, if we have none yet 609 if (teamID < 0) { 610 thread_info threadInfo; 611 status_t error = get_thread_info(threadID, &threadInfo); 612 if (error != B_OK) { 613 fprintf(stderr, "%s: Failed to get info for thread %" B_PRId32 614 ": %s\n", kCommandName, threadID, strerror(error)); 615 exit(1); 616 } 617 teamID = threadInfo.team; 618 } 619 620 // create a debugger port 621 port_id debuggerPort = create_port(10, "debugger port"); 622 if (debuggerPort < 0) { 623 fprintf(stderr, "%s: Failed to create debugger port: %s\n", 624 kCommandName, strerror(debuggerPort)); 625 exit(1); 626 } 627 628 // install ourselves as the team debugger 629 typedef map<team_id, Team*> TeamMap; 630 TeamMap debuggedTeams; 631 port_id nubPort; 632 633 { 634 Team* team = new Team(teamID); 635 status_t error = team->InstallDebugger(debuggerPort, traceTeam, 636 traceChildTeams, traceSignal); 637 if (error != B_OK) 638 exit(1); 639 640 debuggedTeams[team->ID()] = team; 641 642 nubPort = team->NubPort(); 643 } 644 645 // set thread debugging flags 646 if (threadID >= 0) { 647 int32 threadDebugFlags = 0; 648 if (!traceTeam) { 649 threadDebugFlags = B_THREAD_DEBUG_POST_SYSCALL 650 | (traceChildThreads 651 ? B_THREAD_DEBUG_SYSCALL_TRACE_CHILD_THREADS : 0); 652 } 653 if (set_thread_debugging_flags(nubPort, threadID, threadDebugFlags) 654 != B_OK) { 655 exit(1); 656 } 657 658 // resume the target thread to be sure, it's running 659 resume_thread(threadID); 660 } 661 662 // debug loop 663 while (true) { 664 bool quitLoop = false; 665 int32 code; 666 debug_debugger_message_data message; 667 ssize_t messageSize = read_port(debuggerPort, &code, &message, 668 sizeof(message)); 669 670 if (messageSize < 0) { 671 if (messageSize == B_INTERRUPTED) 672 continue; 673 674 fprintf(stderr, "%s: Reading from debugger port failed: %s\n", 675 kCommandName, strerror(messageSize)); 676 exit(1); 677 } 678 679 switch (code) { 680 case B_DEBUGGER_MESSAGE_POST_SYSCALL: 681 { 682 TeamMap::iterator it = debuggedTeams.find(message.origin.team); 683 if (it == debuggedTeams.end()) 684 break; 685 686 Team* team = it->second; 687 MemoryReader& memoryReader = team->GetMemoryReader(); 688 689 uint32 syscallNumber = message.post_syscall.syscall; 690 if (syscallNumber >= sSyscallVector.size()) { 691 fprintf(stderr, "%s: invalid syscall %" B_PRIu32 " attempted\n", 692 kCommandName, syscallNumber); 693 break; 694 } 695 Syscall* syscall = sSyscallVector[syscallNumber]; 696 697 if (stats) 698 record_syscall_stats(*syscall, message.post_syscall); 699 700 if (trace) { 701 print_syscall(outputFile, syscall, message.post_syscall, 702 memoryReader, printArguments, contentsFlags, 703 printReturnValues, colorize, decimalFormat); 704 } 705 break; 706 } 707 708 case B_DEBUGGER_MESSAGE_SIGNAL_RECEIVED: 709 { 710 if (traceSignal && trace) 711 print_signal(outputFile, message.signal_received, colorize); 712 break; 713 } 714 715 case B_DEBUGGER_MESSAGE_THREAD_DEBUGGED: 716 case B_DEBUGGER_MESSAGE_DEBUGGER_CALL: 717 case B_DEBUGGER_MESSAGE_BREAKPOINT_HIT: 718 case B_DEBUGGER_MESSAGE_WATCHPOINT_HIT: 719 case B_DEBUGGER_MESSAGE_SINGLE_STEP: 720 case B_DEBUGGER_MESSAGE_PRE_SYSCALL: 721 case B_DEBUGGER_MESSAGE_EXCEPTION_OCCURRED: 722 case B_DEBUGGER_MESSAGE_THREAD_CREATED: 723 case B_DEBUGGER_MESSAGE_THREAD_DELETED: 724 case B_DEBUGGER_MESSAGE_IMAGE_CREATED: 725 case B_DEBUGGER_MESSAGE_IMAGE_DELETED: 726 break; 727 728 case B_DEBUGGER_MESSAGE_TEAM_CREATED: 729 { 730 if (!traceChildTeams) 731 break; 732 733 Team* team = new(std::nothrow) Team( 734 message.team_created.new_team); 735 if (team == NULL) { 736 fprintf(stderr, "%s: Out of memory!\n", kCommandName); 737 break; 738 } 739 740 status_t error = team->InstallDebugger(debuggerPort, true, true, 741 traceSignal); 742 if (error != B_OK) { 743 delete team; 744 break; 745 } 746 747 debuggedTeams[team->ID()] = team; 748 break; 749 } 750 751 case B_DEBUGGER_MESSAGE_TEAM_DELETED: 752 { 753 // a debugged team is gone 754 TeamMap::iterator it = debuggedTeams.find(message.origin.team); 755 if (it == debuggedTeams.end()) 756 break; 757 758 Team* team = it->second; 759 debuggedTeams.erase(it); 760 delete team; 761 762 // if all debugged teams are gone, we're done 763 quitLoop = debuggedTeams.empty(); 764 break; 765 } 766 } 767 768 if (quitLoop) 769 break; 770 771 // tell the thread to continue (only when there is a thread and the 772 // message was synchronous) 773 if (message.origin.thread >= 0 && message.origin.nub_port >= 0) { 774 if (continue_thread(message.origin.nub_port, 775 message.origin.thread) != B_OK) { 776 exit(1); 777 } 778 } 779 } 780 781 if (stats) { 782 // Dump recorded statistics 783 print_stats(outputFile); 784 } 785 786 if (outputFile != NULL && outputFile != stdout) 787 fclose(outputFile); 788 789 return 0; 790 } 791