1 /* 2 * Copyright 2008-2009, Ingo Weinhold, ingo_weinhold@gmx.de. 3 * Copyright 2002-2008, Axel Dörfler, axeld@pinc-software.de. 4 * Distributed under the terms of the MIT License. 5 * 6 * Copyright 2001, Travis Geiselbrecht. All rights reserved. 7 * Distributed under the terms of the NewOS License. 8 */ 9 10 /*! This file contains the debugger and debug output facilities */ 11 12 #include "blue_screen.h" 13 14 #include <cpu.h> 15 #include <debug.h> 16 #include <debug_heap.h> 17 #include <debug_paranoia.h> 18 #include <driver_settings.h> 19 #include <frame_buffer_console.h> 20 #include <int.h> 21 #include <kernel.h> 22 #include <ksystem_info.h> 23 #include <smp.h> 24 #include <thread.h> 25 #include <tracing.h> 26 #include <vm.h> 27 28 #include <arch/debug_console.h> 29 #include <arch/debug.h> 30 #include <util/AutoLock.h> 31 #include <util/ring_buffer.h> 32 33 #include <syslog_daemon.h> 34 35 #include <ctype.h> 36 #include <stdarg.h> 37 #include <stdio.h> 38 #include <stdlib.h> 39 #include <string.h> 40 #include <syslog.h> 41 42 #include "debug_builtin_commands.h" 43 #include "debug_commands.h" 44 #include "debug_output_filter.h" 45 #include "debug_variables.h" 46 47 48 static const char* const kKDLPrompt = "kdebug> "; 49 50 extern "C" int kgets(char* buffer, int length); 51 52 void call_modules_hook(bool enter); 53 54 55 int dbg_register_file[B_MAX_CPU_COUNT][14]; 56 /* XXXmpetit -- must be made generic */ 57 58 static debug_page_fault_info sPageFaultInfo; 59 60 static bool sSerialDebugEnabled = true; 61 static bool sSyslogOutputEnabled = true; 62 static bool sBlueScreenEnabled = false; 63 // must always be false on startup 64 static bool sDebugScreenEnabled = false; 65 static bool sBlueScreenOutput = true; 66 static spinlock sSpinlock = B_SPINLOCK_INITIALIZER; 67 static int32 sDebuggerOnCPU = -1; 68 69 static sem_id sSyslogNotify = -1; 70 static struct syslog_message* sSyslogMessage; 71 static struct ring_buffer* sSyslogBuffer; 72 static bool sSyslogDropped = false; 73 74 static const char* sCurrentKernelDebuggerMessage; 75 76 #define DEFAULT_SYSLOG_BUFFER_SIZE 65536 77 #define OUTPUT_BUFFER_SIZE 1024 78 static char sOutputBuffer[OUTPUT_BUFFER_SIZE]; 79 static char sLastOutputBuffer[OUTPUT_BUFFER_SIZE]; 80 static DebugOutputFilter* sDebugOutputFilter = NULL; 81 DefaultDebugOutputFilter gDefaultDebugOutputFilter; 82 83 static void flush_pending_repeats(bool syslogOutput); 84 static void check_pending_repeats(void* data, int iter); 85 86 static int64 sMessageRepeatFirstTime = 0; 87 static int64 sMessageRepeatLastTime = 0; 88 static int32 sMessageRepeatCount = 0; 89 90 static debugger_module_info* sDebuggerModules[8]; 91 static const uint32 kMaxDebuggerModules = sizeof(sDebuggerModules) 92 / sizeof(sDebuggerModules[0]); 93 94 #define LINE_BUFFER_SIZE 1024 95 #define HISTORY_SIZE 16 96 97 static char sLineBuffer[HISTORY_SIZE][LINE_BUFFER_SIZE] = { "", }; 98 static int32 sCurrentLine = 0; 99 100 static debugger_demangle_module_info* sDemangleModule; 101 102 static struct thread* sDebuggedThread; 103 static vint32 sInDebugger = 0; 104 static bool sPreviousDprintfState; 105 static volatile bool sHandOverKDL = false; 106 static vint32 sHandOverKDLToCPU = -1; 107 static bool sCPUTrapped[B_MAX_CPU_COUNT]; 108 109 110 #define distance(a, b) ((a) < (b) ? (b) - (a) : (a) - (b)) 111 112 113 // #pragma mark - DebugOutputFilter 114 115 116 DebugOutputFilter::DebugOutputFilter() 117 { 118 } 119 120 121 DebugOutputFilter::~DebugOutputFilter() 122 { 123 } 124 125 126 void 127 DebugOutputFilter::PrintString(const char* string) 128 { 129 } 130 131 132 void 133 DebugOutputFilter::Print(const char* format, va_list args) 134 { 135 } 136 137 138 void 139 DefaultDebugOutputFilter::PrintString(const char* string) 140 { 141 if (sSerialDebugEnabled) 142 arch_debug_serial_puts(string); 143 if (sBlueScreenEnabled || sDebugScreenEnabled) 144 blue_screen_puts(string); 145 146 for (uint32 i = 0; sSerialDebugEnabled && i < kMaxDebuggerModules; i++) { 147 if (sDebuggerModules[i] && sDebuggerModules[i]->debugger_puts) 148 sDebuggerModules[i]->debugger_puts(string, strlen(string)); 149 } 150 } 151 152 153 void 154 DefaultDebugOutputFilter::Print(const char* format, va_list args) 155 { 156 vsnprintf(sOutputBuffer, OUTPUT_BUFFER_SIZE, format, args); 157 flush_pending_repeats(sInDebugger == 0); 158 PrintString(sOutputBuffer); 159 } 160 161 162 // #pragma mark - 163 164 165 DebugOutputFilter* 166 set_debug_output_filter(DebugOutputFilter* filter) 167 { 168 DebugOutputFilter* oldFilter = sDebugOutputFilter; 169 sDebugOutputFilter = filter; 170 return oldFilter; 171 } 172 173 174 static void 175 kputchar(char c) 176 { 177 if (sSerialDebugEnabled) 178 arch_debug_serial_putchar(c); 179 if (sBlueScreenEnabled || sDebugScreenEnabled) 180 blue_screen_putchar(c); 181 for (uint32 i = 0; sSerialDebugEnabled && i < kMaxDebuggerModules; i++) 182 if (sDebuggerModules[i] && sDebuggerModules[i]->debugger_puts) 183 sDebuggerModules[i]->debugger_puts(&c, sizeof(c)); 184 } 185 186 187 void 188 kputs(const char* s) 189 { 190 if (sDebugOutputFilter != NULL) 191 sDebugOutputFilter->PrintString(s); 192 } 193 194 195 void 196 kputs_unfiltered(const char* s) 197 { 198 gDefaultDebugOutputFilter.PrintString(s); 199 } 200 201 202 static void 203 insert_chars_into_line(char* buffer, int32& position, int32& length, 204 const char* chars, int32 charCount) 205 { 206 // move the following chars to make room for the ones to insert 207 if (position < length) { 208 memmove(buffer + position + charCount, buffer + position, 209 length - position); 210 } 211 212 // insert chars 213 memcpy(buffer + position, chars, charCount); 214 int32 oldPosition = position; 215 position += charCount; 216 length += charCount; 217 218 // print the new chars (and the following ones) 219 kprintf("%.*s", (int)(length - oldPosition), 220 buffer + oldPosition); 221 222 // reposition cursor, if necessary 223 if (position < length) 224 kprintf("\x1b[%ldD", length - position); 225 } 226 227 228 static void 229 insert_char_into_line(char* buffer, int32& position, int32& length, char c) 230 { 231 insert_chars_into_line(buffer, position, length, &c, 1); 232 } 233 234 235 static void 236 remove_char_from_line(char* buffer, int32& position, int32& length) 237 { 238 if (position == length) 239 return; 240 241 length--; 242 243 if (position < length) { 244 // move the subsequent chars 245 memmove(buffer + position, buffer + position + 1, length - position); 246 247 // print the rest of the line again, if necessary 248 for (int32 i = position; i < length; i++) 249 kputchar(buffer[i]); 250 } 251 252 // visually clear the last char 253 kputchar(' '); 254 255 // reposition the cursor 256 kprintf("\x1b[%ldD", length - position + 1); 257 } 258 259 260 class LineEditingHelper { 261 public: 262 virtual ~LineEditingHelper() {} 263 264 virtual void TabCompletion(char* buffer, int32 capacity, int32& position, 265 int32& length) = 0; 266 }; 267 268 269 class CommandLineEditingHelper : public LineEditingHelper { 270 public: 271 CommandLineEditingHelper() 272 { 273 } 274 275 virtual ~CommandLineEditingHelper() {} 276 277 virtual void TabCompletion(char* buffer, int32 capacity, int32& position, 278 int32& length) 279 { 280 // find the first space 281 char tmpChar = buffer[position]; 282 buffer[position] = '\0'; 283 char* firstSpace = strchr(buffer, ' '); 284 buffer[position] = tmpChar; 285 286 bool reprintLine = false; 287 288 if (firstSpace != NULL) { 289 // a complete command -- print its help 290 291 // get the command 292 tmpChar = *firstSpace; 293 *firstSpace = '\0'; 294 bool ambiguous; 295 debugger_command* command = find_debugger_command(buffer, true, ambiguous); 296 *firstSpace = tmpChar; 297 298 if (command != NULL) { 299 kputchar('\n'); 300 print_debugger_command_usage(command->name); 301 } else { 302 if (ambiguous) 303 kprintf("\nambiguous command\n"); 304 else 305 kprintf("\nno such command\n"); 306 } 307 308 reprintLine = true; 309 } else { 310 // a partial command -- look for completions 311 312 // check for possible completions 313 int32 count = 0; 314 int32 longestName = 0; 315 debugger_command* command = NULL; 316 int32 longestCommonPrefix = 0; 317 const char* previousCommandName = NULL; 318 while ((command = next_debugger_command(command, buffer, position)) 319 != NULL) { 320 count++; 321 int32 nameLength = strlen(command->name); 322 longestName = max_c(longestName, nameLength); 323 324 // updated the length of the longest common prefix of the 325 // commands 326 if (count == 1) { 327 longestCommonPrefix = longestName; 328 } else { 329 longestCommonPrefix = min_c(longestCommonPrefix, 330 nameLength); 331 332 for (int32 i = position; i < longestCommonPrefix; i++) { 333 if (previousCommandName[i] != command->name[i]) { 334 longestCommonPrefix = i; 335 break; 336 } 337 } 338 } 339 340 previousCommandName = command->name; 341 } 342 343 if (count == 0) { 344 // no possible completions 345 kprintf("\nno completions\n"); 346 reprintLine = true; 347 } else if (count == 1) { 348 // exactly one completion 349 command = next_debugger_command(NULL, buffer, position); 350 351 // check for sufficient space in the buffer 352 int32 neededSpace = longestName - position + 1; 353 // remainder of the name plus one space 354 // also consider the terminating null char 355 if (length + neededSpace + 1 >= capacity) 356 return; 357 358 insert_chars_into_line(buffer, position, length, 359 command->name + position, longestName - position); 360 insert_char_into_line(buffer, position, length, ' '); 361 } else if (longestCommonPrefix > position) { 362 // multiple possible completions with longer common prefix 363 // -- insert the remainder of the common prefix 364 365 // check for sufficient space in the buffer 366 int32 neededSpace = longestCommonPrefix - position; 367 // also consider the terminating null char 368 if (length + neededSpace + 1 >= capacity) 369 return; 370 371 insert_chars_into_line(buffer, position, length, 372 previousCommandName + position, neededSpace); 373 } else { 374 // multiple possible completions without longer common prefix 375 // -- print them all 376 kprintf("\n"); 377 reprintLine = true; 378 379 int columns = 80 / (longestName + 2); 380 debugger_command* command = NULL; 381 int column = 0; 382 while ((command = next_debugger_command(command, buffer, position)) 383 != NULL) { 384 // spacing 385 if (column > 0 && column % columns == 0) 386 kputchar('\n'); 387 column++; 388 389 kprintf(" %-*s", (int)longestName, command->name); 390 } 391 kputchar('\n'); 392 } 393 } 394 395 // reprint the editing line, if necessary 396 if (reprintLine) { 397 kprintf("%s%.*s", kKDLPrompt, (int)length, buffer); 398 if (position < length) 399 kprintf("\x1b[%ldD", length - position); 400 } 401 } 402 }; 403 404 405 static int 406 read_line(char* buffer, int32 maxLength, 407 LineEditingHelper* editingHelper = NULL) 408 { 409 int32 currentHistoryLine = sCurrentLine; 410 int32 position = 0; 411 int32 length = 0; 412 bool done = false; 413 char c = 0; 414 415 while (!done) { 416 c = kgetc(); 417 418 switch (c) { 419 case '\n': 420 case '\r': 421 buffer[length++] = '\0'; 422 kputchar('\n'); 423 done = true; 424 break; 425 case '\t': 426 { 427 if (editingHelper != NULL) { 428 editingHelper->TabCompletion(buffer, maxLength, 429 position, length); 430 } 431 break; 432 } 433 case 8: // backspace 434 if (position > 0) { 435 kputs("\x1b[1D"); // move to the left one 436 position--; 437 remove_char_from_line(buffer, position, length); 438 } 439 break; 440 case 0x1f & 'K': // CTRL-K -- clear line after current position 441 if (position < length) { 442 // clear chars 443 for (int32 i = position; i < length; i++) 444 kputchar(' '); 445 446 // reposition cursor 447 kprintf("\x1b[%ldD", length - position); 448 449 length = position; 450 } 451 break; 452 case 0x1f & 'L': // CTRL-L -- clear screen 453 if (sBlueScreenOutput) { 454 // All the following needs to be transparent for the 455 // serial debug output. I.e. after clearing the screen 456 // we have to get the on-screen line into the visual state 457 // it should have. 458 459 // clear screen 460 blue_screen_clear_screen(); 461 462 // reprint line 463 buffer[length] = '\0'; 464 blue_screen_puts(kKDLPrompt); 465 blue_screen_puts(buffer); 466 467 // reposition cursor 468 if (position < length) { 469 for (int i = length; i > position; i--) 470 blue_screen_puts("\x1b[1D"); 471 } 472 } 473 break; 474 case 27: // escape sequence 475 c = kgetc(); 476 if (c != '[') { 477 // ignore broken escape sequence 478 break; 479 } 480 c = kgetc(); 481 switch (c) { 482 case 'C': // right arrow 483 if (position < length) { 484 kputs("\x1b[1C"); // move to the right one 485 position++; 486 } 487 break; 488 case 'D': // left arrow 489 if (position > 0) { 490 kputs("\x1b[1D"); // move to the left one 491 position--; 492 } 493 break; 494 case 'A': // up arrow 495 case 'B': // down arrow 496 { 497 int32 historyLine = 0; 498 499 if (c == 'A') { 500 // up arrow 501 historyLine = currentHistoryLine - 1; 502 if (historyLine < 0) 503 historyLine = HISTORY_SIZE - 1; 504 } else { 505 // down arrow 506 if (currentHistoryLine == sCurrentLine) 507 break; 508 509 historyLine = currentHistoryLine + 1; 510 if (historyLine >= HISTORY_SIZE) 511 historyLine = 0; 512 } 513 514 // clear the history again if we're in the current line again 515 // (the buffer we get just is the current line buffer) 516 if (historyLine == sCurrentLine) { 517 sLineBuffer[historyLine][0] = '\0'; 518 } else if (sLineBuffer[historyLine][0] == '\0') { 519 // empty history lines are unused -- so bail out 520 break; 521 } 522 523 // swap the current line with something from the history 524 if (position > 0) 525 kprintf("\x1b[%ldD", position); // move to beginning of line 526 527 strcpy(buffer, sLineBuffer[historyLine]); 528 length = position = strlen(buffer); 529 kprintf("%s\x1b[K", buffer); // print the line and clear the rest 530 currentHistoryLine = historyLine; 531 break; 532 } 533 case '5': // if "5~", it's PAGE UP 534 case '6': // if "6~", it's PAGE DOWN 535 { 536 if (kgetc() != '~') 537 break; 538 539 // PAGE UP: search backward, PAGE DOWN: forward 540 int32 searchDirection = (c == '5' ? -1 : 1); 541 542 bool found = false; 543 int32 historyLine = currentHistoryLine; 544 do { 545 historyLine = (historyLine + searchDirection 546 + HISTORY_SIZE) % HISTORY_SIZE; 547 if (historyLine == sCurrentLine) 548 break; 549 550 if (strncmp(sLineBuffer[historyLine], buffer, 551 position) == 0) { 552 found = true; 553 } 554 } while (!found); 555 556 // bail out, if we've found nothing or hit an empty 557 // (i.e. unused) history line 558 if (!found || strlen(sLineBuffer[historyLine]) == 0) 559 break; 560 561 // found a suitable line -- replace the current buffer 562 // content with it 563 strcpy(buffer, sLineBuffer[historyLine]); 564 length = strlen(buffer); 565 kprintf("%s\x1b[K", buffer + position); 566 // print the line and clear the rest 567 kprintf("\x1b[%ldD", length - position); 568 // reposition cursor 569 currentHistoryLine = historyLine; 570 571 break; 572 } 573 case 'H': // home 574 { 575 if (position > 0) { 576 kprintf("\x1b[%ldD", position); 577 position = 0; 578 } 579 break; 580 } 581 case 'F': // end 582 { 583 if (position < length) { 584 kprintf("\x1b[%ldC", length - position); 585 position = length; 586 } 587 break; 588 } 589 case '3': // if "3~", it's DEL 590 { 591 if (kgetc() != '~') 592 break; 593 594 if (position < length) 595 remove_char_from_line(buffer, position, length); 596 597 break; 598 } 599 default: 600 break; 601 } 602 break; 603 case '$': 604 case '+': 605 if (!sBlueScreenOutput) { 606 /* HACK ALERT!!! 607 * 608 * If we get a $ at the beginning of the line 609 * we assume we are talking with GDB 610 */ 611 if (position == 0) { 612 strcpy(buffer, "gdb"); 613 position = 4; 614 done = true; 615 break; 616 } 617 } 618 /* supposed to fall through */ 619 default: 620 if (isprint(c)) 621 insert_char_into_line(buffer, position, length, c); 622 break; 623 } 624 625 if (length >= maxLength - 2) { 626 buffer[length++] = '\0'; 627 kputchar('\n'); 628 done = true; 629 break; 630 } 631 } 632 633 return length; 634 } 635 636 637 char 638 kgetc(void) 639 { 640 // give the kernel debugger modules a chance first 641 for (uint32 i = 0; i < kMaxDebuggerModules; i++) { 642 if (sDebuggerModules[i] && sDebuggerModules[i]->debugger_getchar) { 643 int getChar = sDebuggerModules[i]->debugger_getchar(); 644 if (getChar >= 0) 645 return (char)getChar; 646 } 647 } 648 649 if (sBlueScreenOutput) 650 return blue_screen_getchar(); 651 652 return arch_debug_serial_getchar(); 653 } 654 655 656 int 657 kgets(char* buffer, int length) 658 { 659 return read_line(buffer, length); 660 } 661 662 663 static void 664 kernel_debugger_loop(void) 665 { 666 int32 previousCPU = sDebuggerOnCPU; 667 sDebuggerOnCPU = smp_get_current_cpu(); 668 669 DebugAllocPool* allocPool = create_debug_alloc_pool(); 670 671 kprintf("Welcome to Kernel Debugging Land...\n"); 672 673 if (struct thread* thread = thread_get_current_thread()) { 674 // set a few temporary debug variables 675 set_debug_variable("_thread", (uint64)(addr_t)thread); 676 set_debug_variable("_threadID", thread->id); 677 set_debug_variable("_team", (uint64)(addr_t)thread->team); 678 if (thread->team != NULL) 679 set_debug_variable("_teamID", thread->team->id); 680 set_debug_variable("_cpu", sDebuggerOnCPU); 681 682 kprintf("Thread %ld \"%s\" running on CPU %ld\n", thread->id, 683 thread->name, sDebuggerOnCPU); 684 } else 685 kprintf("Running on CPU %ld\n", sDebuggerOnCPU); 686 687 int32 continuableLine = -1; 688 // Index of the previous command line, if the command returned 689 // B_KDEBUG_CONT, i.e. asked to be repeatable, -1 otherwise. 690 691 for (;;) { 692 CommandLineEditingHelper editingHelper; 693 kprintf(kKDLPrompt); 694 char* line = sLineBuffer[sCurrentLine]; 695 read_line(line, LINE_BUFFER_SIZE, &editingHelper); 696 697 // check, if the line is empty or whitespace only 698 bool whiteSpaceOnly = true; 699 for (int i = 0 ; line[i] != '\0'; i++) { 700 if (!isspace(line[i])) { 701 whiteSpaceOnly = false; 702 break; 703 } 704 } 705 706 if (whiteSpaceOnly) { 707 if (continuableLine < 0) 708 continue; 709 710 // the previous command can be repeated 711 sCurrentLine = continuableLine; 712 line = sLineBuffer[sCurrentLine]; 713 } 714 715 int rc = evaluate_debug_command(line); 716 717 if (rc == B_KDEBUG_QUIT) { 718 // okay, exit now. 719 break; 720 } 721 722 // If the command is continuable, remember the current line index. 723 continuableLine = (rc == B_KDEBUG_CONT ? sCurrentLine : -1); 724 725 int previousLine = sCurrentLine - 1; 726 if (previousLine < 0) 727 previousLine = HISTORY_SIZE - 1; 728 729 // Only use the next slot in the history, if the entries differ 730 if (strcmp(sLineBuffer[sCurrentLine], sLineBuffer[previousLine])) { 731 if (++sCurrentLine >= HISTORY_SIZE) 732 sCurrentLine = 0; 733 } 734 } 735 736 delete_debug_alloc_pool(allocPool); 737 738 sDebuggerOnCPU = previousCPU; 739 } 740 741 742 static void 743 enter_kernel_debugger(const char* message) 744 { 745 while (atomic_add(&sInDebugger, 1) > 0) { 746 // The debugger is already running, find out where... 747 if (sDebuggerOnCPU == smp_get_current_cpu()) { 748 // We are re-entering the debugger on the same CPU. 749 break; 750 } 751 752 // Some other CPU must have entered the debugger and tried to halt 753 // us. Process ICIs to ensure we get the halt request. Then we are 754 // blocking there until everyone leaves the debugger and we can 755 // try to enter it again. 756 atomic_add(&sInDebugger, -1); 757 smp_intercpu_int_handler(); 758 } 759 760 arch_debug_save_registers(&dbg_register_file[smp_get_current_cpu()][0]); 761 sPreviousDprintfState = set_dprintf_enabled(true); 762 763 if (!gKernelStartup && sDebuggerOnCPU != smp_get_current_cpu() 764 && smp_get_num_cpus() > 1) { 765 // First entry on a MP system, send a halt request to all of the other 766 // CPUs. Should they try to enter the debugger they will be cought in 767 // the loop above. 768 smp_send_broadcast_ici(SMP_MSG_CPU_HALT, 0, 0, 0, NULL, 769 SMP_MSG_FLAG_SYNC); 770 } 771 772 if (sBlueScreenOutput) { 773 if (blue_screen_enter(false) == B_OK) 774 sBlueScreenEnabled = true; 775 } 776 777 sDebugOutputFilter = &gDefaultDebugOutputFilter; 778 779 sDebuggedThread = NULL; 780 781 if (message) 782 kprintf("PANIC: %s\n", message); 783 784 sCurrentKernelDebuggerMessage = message; 785 786 // sort the commands 787 sort_debugger_commands(); 788 789 call_modules_hook(true); 790 } 791 792 793 static void 794 exit_kernel_debugger() 795 { 796 call_modules_hook(false); 797 set_dprintf_enabled(sPreviousDprintfState); 798 799 sDebugOutputFilter = NULL; 800 801 sBlueScreenEnabled = false; 802 if (sDebugScreenEnabled) 803 blue_screen_enter(true); 804 805 atomic_add(&sInDebugger, -1); 806 } 807 808 809 static void 810 hand_over_kernel_debugger() 811 { 812 // Wait until the hand-over is complete. 813 // The other CPU gets our sInDebugger reference and will release it when 814 // done. Note, that there's a small race condition: the other CPU could 815 // hand over to another CPU without us noticing. Since this is only 816 // initiated by the user, it is harmless, though. 817 sHandOverKDL = true; 818 while (sHandOverKDLToCPU >= 0) 819 PAUSE(); 820 } 821 822 823 static int 824 cmd_dump_kdl_message(int argc, char** argv) 825 { 826 if (sCurrentKernelDebuggerMessage) { 827 kputs(sCurrentKernelDebuggerMessage); 828 kputs("\n"); 829 } 830 831 return 0; 832 } 833 834 835 static int 836 cmd_dump_syslog(int argc, char** argv) 837 { 838 if (!sSyslogOutputEnabled) { 839 kprintf("Syslog is not enabled.\n"); 840 return 0; 841 } 842 843 bool currentOnly = false; 844 if (argc > 1) { 845 if (!strcmp(argv[1], "-n")) 846 currentOnly = true; 847 else { 848 print_debugger_command_usage(argv[0]); 849 return 0; 850 } 851 } 852 853 uint32 start = sSyslogBuffer->first; 854 size_t end = start + sSyslogBuffer->in; 855 if (!currentOnly) { 856 // Start the buffer after the current end (we don't really know if 857 // this part has been written to already). 858 start = (start + sSyslogBuffer->in) % sSyslogBuffer->size; 859 end = start + sSyslogBuffer->size; 860 } else if (!ring_buffer_readable(sSyslogBuffer)) { 861 kprintf("Syslog is empty.\n"); 862 return 0; 863 } 864 865 // break it down to lines to make it grep'able 866 867 bool newLine = false; 868 char line[256]; 869 size_t linePos = 0; 870 for (uint32 i = start; i < end; i++) { 871 char c = sSyslogBuffer->buffer[i % sSyslogBuffer->size]; 872 if (c == '\0' || (uint8)c == 0xcc) 873 continue; 874 875 line[linePos++] = c; 876 newLine = false; 877 878 if (c == '\n' || linePos == sizeof(line) - 1) { 879 newLine = c == '\n'; 880 line[linePos] = '\0'; 881 linePos = 0; 882 kprintf(line); 883 } 884 } 885 if (!newLine) 886 kprintf("\n"); 887 888 return 0; 889 } 890 891 892 static int 893 cmd_switch_cpu(int argc, char** argv) 894 { 895 if (argc > 2) { 896 print_debugger_command_usage(argv[0]); 897 return 0; 898 } 899 900 if (argc == 1) { 901 kprintf("running on CPU %ld\n", smp_get_current_cpu()); 902 return 0; 903 } 904 905 int32 newCPU = parse_expression(argv[1]); 906 if (newCPU < 0 || newCPU >= smp_get_num_cpus()) { 907 kprintf("invalid CPU index\n"); 908 return 0; 909 } 910 911 if (newCPU == smp_get_current_cpu()) { 912 kprintf("already running on CPU %ld\n", newCPU); 913 return 0; 914 } 915 916 sHandOverKDLToCPU = newCPU; 917 918 return B_KDEBUG_QUIT; 919 } 920 921 922 static status_t 923 syslog_sender(void* data) 924 { 925 status_t error = B_BAD_PORT_ID; 926 port_id port = -1; 927 bool bufferPending = false; 928 int32 length = 0; 929 930 while (true) { 931 // wait for syslog data to become available 932 acquire_sem(sSyslogNotify); 933 934 sSyslogMessage->when = real_time_clock(); 935 936 if (error == B_BAD_PORT_ID) { 937 // last message couldn't be sent, try to locate the syslog_daemon 938 port = find_port(SYSLOG_PORT_NAME); 939 } 940 941 if (port >= B_OK) { 942 if (!bufferPending) { 943 // we need to have exclusive access to our syslog buffer 944 cpu_status state = disable_interrupts(); 945 acquire_spinlock(&sSpinlock); 946 947 length = ring_buffer_readable(sSyslogBuffer); 948 if (length > (int32)SYSLOG_MAX_MESSAGE_LENGTH) 949 length = SYSLOG_MAX_MESSAGE_LENGTH; 950 951 length = ring_buffer_read(sSyslogBuffer, 952 (uint8*)sSyslogMessage->message, length); 953 if (sSyslogDropped) { 954 // Add drop marker - since parts had to be dropped, it's 955 // guaranteed that we have enough space in the buffer now. 956 ring_buffer_write(sSyslogBuffer, (uint8*)"<DROP>", 6); 957 sSyslogDropped = false; 958 } 959 960 release_spinlock(&sSpinlock); 961 restore_interrupts(state); 962 } 963 964 if (length == 0) { 965 // the buffer we came here for might have been sent already 966 bufferPending = false; 967 continue; 968 } 969 970 error = write_port_etc(port, SYSLOG_MESSAGE, sSyslogMessage, 971 sizeof(struct syslog_message) + length, B_RELATIVE_TIMEOUT, 0); 972 973 if (error < B_OK) { 974 // sending has failed - just wait, maybe it'll work later. 975 bufferPending = true; 976 continue; 977 } 978 979 if (bufferPending) { 980 // we could write the last pending buffer, try to read more 981 // from the syslog ring buffer 982 release_sem_etc(sSyslogNotify, 1, B_DO_NOT_RESCHEDULE); 983 bufferPending = false; 984 } 985 } 986 } 987 988 return 0; 989 } 990 991 992 static void 993 syslog_write(const char* text, int32 length) 994 { 995 bool trunc = false; 996 997 if (sSyslogBuffer == NULL) 998 return; 999 1000 if ((int32)ring_buffer_writable(sSyslogBuffer) < length) { 1001 // truncate data 1002 length = ring_buffer_writable(sSyslogBuffer); 1003 1004 if (length > 8) { 1005 trunc = true; 1006 length -= 8; 1007 } else 1008 sSyslogDropped = true; 1009 } 1010 1011 ring_buffer_write(sSyslogBuffer, (uint8*)text, length); 1012 if (trunc) 1013 ring_buffer_write(sSyslogBuffer, (uint8*)"<TRUNC>", 7); 1014 1015 release_sem_etc(sSyslogNotify, 1, B_DO_NOT_RESCHEDULE); 1016 } 1017 1018 1019 static status_t 1020 syslog_init_post_threads(void) 1021 { 1022 if (!sSyslogOutputEnabled) 1023 return B_OK; 1024 1025 sSyslogNotify = create_sem(0, "syslog data"); 1026 if (sSyslogNotify >= B_OK) { 1027 thread_id thread = spawn_kernel_thread(syslog_sender, "syslog sender", 1028 B_LOW_PRIORITY, NULL); 1029 if (thread >= B_OK && resume_thread(thread) == B_OK) 1030 return B_OK; 1031 } 1032 1033 // initializing kernel syslog service failed -- disable it 1034 1035 sSyslogOutputEnabled = false; 1036 free(sSyslogMessage); 1037 free(sSyslogBuffer); 1038 delete_sem(sSyslogNotify); 1039 1040 return B_ERROR; 1041 } 1042 1043 1044 static status_t 1045 syslog_init(struct kernel_args* args) 1046 { 1047 status_t status; 1048 int32 length = 0; 1049 1050 if (!sSyslogOutputEnabled) 1051 return B_OK; 1052 1053 sSyslogMessage = (syslog_message*)malloc(SYSLOG_MESSAGE_BUFFER_SIZE); 1054 if (sSyslogMessage == NULL) { 1055 status = B_NO_MEMORY; 1056 goto err1; 1057 } 1058 1059 { 1060 size_t bufferSize = DEFAULT_SYSLOG_BUFFER_SIZE; 1061 void* handle = load_driver_settings("kernel"); 1062 if (handle != NULL) { 1063 const char* sizeString = get_driver_parameter(handle, 1064 "syslog_buffer_size", NULL, NULL); 1065 if (sizeString != NULL) { 1066 bufferSize = strtoul(sizeString, NULL, 0); 1067 if (bufferSize > 262144) 1068 bufferSize = 262144; 1069 else if (bufferSize < SYSLOG_MESSAGE_BUFFER_SIZE) 1070 bufferSize = SYSLOG_MESSAGE_BUFFER_SIZE; 1071 } 1072 1073 unload_driver_settings(handle); 1074 } 1075 1076 sSyslogBuffer = create_ring_buffer(bufferSize); 1077 } 1078 if (sSyslogBuffer == NULL) { 1079 status = B_NO_MEMORY; 1080 goto err2; 1081 } 1082 1083 // initialize syslog message 1084 sSyslogMessage->from = 0; 1085 sSyslogMessage->options = LOG_KERN; 1086 sSyslogMessage->priority = LOG_DEBUG; 1087 sSyslogMessage->ident[0] = '\0'; 1088 //strcpy(sSyslogMessage->ident, "KERNEL"); 1089 1090 if (args->debug_output != NULL) 1091 syslog_write((const char*)args->debug_output, args->debug_size); 1092 1093 char revisionBuffer[64]; 1094 length = snprintf(revisionBuffer, sizeof(revisionBuffer), 1095 "Welcome to syslog debug output!\nHaiku revision: %lu\n", 1096 get_haiku_revision()); 1097 syslog_write(revisionBuffer, length); 1098 1099 add_debugger_command_etc("syslog", &cmd_dump_syslog, 1100 "Dumps the syslog buffer.\n", 1101 "[-n]\nDumps the whole syslog buffer, or, if -n is specified, only " 1102 "the part that hasn't been sent yet.\n", 0); 1103 1104 return B_OK; 1105 1106 err2: 1107 free(sSyslogMessage); 1108 err1: 1109 sSyslogOutputEnabled = false; 1110 return status; 1111 } 1112 1113 1114 void 1115 call_modules_hook(bool enter) 1116 { 1117 uint32 index = 0; 1118 while (index < kMaxDebuggerModules && sDebuggerModules[index] != NULL) { 1119 debugger_module_info* module = sDebuggerModules[index]; 1120 1121 if (enter && module->enter_debugger != NULL) 1122 module->enter_debugger(); 1123 else if (!enter && module->exit_debugger != NULL) 1124 module->exit_debugger(); 1125 1126 index++; 1127 } 1128 } 1129 1130 1131 // #pragma mark - private kernel API 1132 1133 1134 bool 1135 debug_screen_output_enabled(void) 1136 { 1137 return sDebugScreenEnabled; 1138 } 1139 1140 1141 void 1142 debug_stop_screen_debug_output(void) 1143 { 1144 sDebugScreenEnabled = false; 1145 } 1146 1147 1148 bool 1149 debug_debugger_running(void) 1150 { 1151 return sDebuggerOnCPU != -1; 1152 } 1153 1154 1155 void 1156 debug_puts(const char* string, int32 length) 1157 { 1158 cpu_status state = disable_interrupts(); 1159 acquire_spinlock(&sSpinlock); 1160 1161 if (length >= OUTPUT_BUFFER_SIZE) 1162 length = OUTPUT_BUFFER_SIZE - 1; 1163 1164 // TODO: Code duplication! Cf. dprintf_args()! 1165 if (length > 1 && string[length - 1] == '\n' 1166 && strncmp(string, sLastOutputBuffer, length) == 0) { 1167 sMessageRepeatCount++; 1168 sMessageRepeatLastTime = system_time(); 1169 if (sMessageRepeatFirstTime == 0) 1170 sMessageRepeatFirstTime = sMessageRepeatLastTime; 1171 } else { 1172 flush_pending_repeats(true); 1173 1174 if (sSerialDebugEnabled) 1175 arch_debug_serial_puts(string); 1176 if (sSyslogOutputEnabled) 1177 syslog_write(string, length); 1178 if (sBlueScreenEnabled || sDebugScreenEnabled) 1179 blue_screen_puts(string); 1180 if (sSerialDebugEnabled) { 1181 for (uint32 i = 0; i < kMaxDebuggerModules; i++) { 1182 if (sDebuggerModules[i] && sDebuggerModules[i]->debugger_puts) 1183 sDebuggerModules[i]->debugger_puts(string, length); 1184 } 1185 } 1186 1187 memcpy(sLastOutputBuffer, string, length); 1188 sLastOutputBuffer[length] = 0; 1189 } 1190 1191 release_spinlock(&sSpinlock); 1192 restore_interrupts(state); 1193 } 1194 1195 1196 void 1197 debug_early_boot_message(const char* string) 1198 { 1199 arch_debug_serial_early_boot_message(string); 1200 } 1201 1202 1203 status_t 1204 debug_init(kernel_args* args) 1205 { 1206 new(&gDefaultDebugOutputFilter) DefaultDebugOutputFilter; 1207 1208 debug_paranoia_init(); 1209 return arch_debug_console_init(args); 1210 } 1211 1212 1213 status_t 1214 debug_init_post_vm(kernel_args* args) 1215 { 1216 add_debugger_command_etc("cpu", &cmd_switch_cpu, 1217 "Switches to another CPU.\n", 1218 "<cpu>\n" 1219 "Switches to CPU with the index <cpu>.\n", 0); 1220 add_debugger_command_etc("message", &cmd_dump_kdl_message, 1221 "Reprint the message printed when entering KDL", 1222 "\n" 1223 "Reprints the message printed when entering KDL.\n", 0); 1224 1225 debug_builtin_commands_init(); 1226 1227 debug_heap_init(); 1228 debug_variables_init(); 1229 frame_buffer_console_init(args); 1230 arch_debug_console_init_settings(args); 1231 tracing_init(); 1232 1233 // get debug settings 1234 void* handle = load_driver_settings("kernel"); 1235 if (handle != NULL) { 1236 sSerialDebugEnabled = get_driver_boolean_parameter(handle, 1237 "serial_debug_output", sSerialDebugEnabled, sSerialDebugEnabled); 1238 sSyslogOutputEnabled = get_driver_boolean_parameter(handle, 1239 "syslog_debug_output", sSyslogOutputEnabled, sSyslogOutputEnabled); 1240 sBlueScreenOutput = get_driver_boolean_parameter(handle, 1241 "bluescreen", true, true); 1242 1243 unload_driver_settings(handle); 1244 } 1245 1246 handle = load_driver_settings(B_SAFEMODE_DRIVER_SETTINGS); 1247 if (handle != NULL) { 1248 sDebugScreenEnabled = get_driver_boolean_parameter(handle, 1249 "debug_screen", false, false); 1250 1251 unload_driver_settings(handle); 1252 } 1253 1254 if ((sBlueScreenOutput || sDebugScreenEnabled) 1255 && blue_screen_init() != B_OK) 1256 sBlueScreenOutput = sDebugScreenEnabled = false; 1257 1258 if (sDebugScreenEnabled) 1259 blue_screen_enter(true); 1260 1261 syslog_init(args); 1262 1263 return arch_debug_init(args); 1264 } 1265 1266 1267 status_t 1268 debug_init_post_modules(struct kernel_args* args) 1269 { 1270 void* cookie; 1271 1272 // check for dupped lines every 10/10 second 1273 register_kernel_daemon(check_pending_repeats, NULL, 10); 1274 1275 syslog_init_post_threads(); 1276 1277 // load kernel debugger addons 1278 1279 static const char* kDemanglePrefix = "debugger/demangle/"; 1280 1281 cookie = open_module_list("debugger"); 1282 uint32 count = 0; 1283 while (count < kMaxDebuggerModules) { 1284 char name[B_FILE_NAME_LENGTH]; 1285 size_t nameLength = sizeof(name); 1286 1287 if (read_next_module_name(cookie, name, &nameLength) != B_OK) 1288 break; 1289 1290 // get demangle module, if any 1291 if (!strncmp(name, kDemanglePrefix, strlen(kDemanglePrefix))) { 1292 if (sDemangleModule == NULL) 1293 get_module(name, (module_info**)&sDemangleModule); 1294 continue; 1295 } 1296 1297 if (get_module(name, (module_info**)&sDebuggerModules[count]) == B_OK) { 1298 dprintf("kernel debugger extension \"%s\": loaded\n", name); 1299 count++; 1300 } else 1301 dprintf("kernel debugger extension \"%s\": failed to load\n", name); 1302 } 1303 close_module_list(cookie); 1304 1305 return frame_buffer_console_init_post_modules(args); 1306 } 1307 1308 1309 void 1310 debug_set_page_fault_info(addr_t faultAddress, addr_t pc, uint32 flags) 1311 { 1312 sPageFaultInfo.fault_address = faultAddress; 1313 sPageFaultInfo.pc = pc; 1314 sPageFaultInfo.flags = flags; 1315 } 1316 1317 1318 debug_page_fault_info* 1319 debug_get_page_fault_info() 1320 { 1321 return &sPageFaultInfo; 1322 } 1323 1324 1325 void 1326 debug_trap_cpu_in_kdl(bool returnIfHandedOver) 1327 { 1328 InterruptsLocker locker; 1329 1330 int cpu = smp_get_current_cpu(); 1331 1332 // return, if we've been called recursively (we call 1333 // smp_intercpu_int_handler() below) 1334 if (sCPUTrapped[cpu]) 1335 return; 1336 1337 sCPUTrapped[cpu] = true; 1338 1339 while (sInDebugger != 0) { 1340 if (sHandOverKDL && sHandOverKDLToCPU == cpu) { 1341 if (returnIfHandedOver) 1342 break; 1343 1344 kernel_debugger(NULL); 1345 } else 1346 smp_intercpu_int_handler(); 1347 } 1348 1349 sCPUTrapped[cpu] = false; 1350 } 1351 1352 1353 // #pragma mark - public API 1354 1355 1356 uint64 1357 parse_expression(const char* expression) 1358 { 1359 uint64 result; 1360 return (evaluate_debug_expression(expression, &result, true) ? result : 0); 1361 } 1362 1363 1364 void 1365 panic(const char* format, ...) 1366 { 1367 va_list args; 1368 char temp[128]; 1369 1370 va_start(args, format); 1371 vsnprintf(temp, sizeof(temp), format, args); 1372 va_end(args); 1373 1374 kernel_debugger(temp); 1375 } 1376 1377 1378 void 1379 kernel_debugger(const char* message) 1380 { 1381 cpu_status state = disable_interrupts(); 1382 1383 while (true) { 1384 if (sHandOverKDLToCPU == smp_get_current_cpu()) { 1385 sHandOverKDLToCPU = -1; 1386 sHandOverKDL = false; 1387 } else 1388 enter_kernel_debugger(message); 1389 1390 kernel_debugger_loop(); 1391 1392 if (sHandOverKDLToCPU < 0) { 1393 exit_kernel_debugger(); 1394 break; 1395 } 1396 1397 hand_over_kernel_debugger(); 1398 1399 debug_trap_cpu_in_kdl(true); 1400 1401 if (sHandOverKDLToCPU != smp_get_current_cpu()) 1402 break; 1403 } 1404 1405 restore_interrupts(state); 1406 } 1407 1408 1409 bool 1410 set_dprintf_enabled(bool newState) 1411 { 1412 bool oldState = sSerialDebugEnabled; 1413 sSerialDebugEnabled = newState; 1414 1415 return oldState; 1416 } 1417 1418 1419 //! Must be called with the sSpinlock held. 1420 static void 1421 flush_pending_repeats(bool syslogOutput) 1422 { 1423 if (sMessageRepeatCount <= 0) 1424 return; 1425 1426 if (sMessageRepeatCount > 1) { 1427 static char temp[40]; 1428 size_t length = snprintf(temp, sizeof(temp), 1429 "Last message repeated %ld times.\n", sMessageRepeatCount); 1430 1431 if (sSerialDebugEnabled) 1432 arch_debug_serial_puts(temp); 1433 if (sSyslogOutputEnabled && syslogOutput) 1434 syslog_write(temp, length); 1435 if (sBlueScreenEnabled || sDebugScreenEnabled) 1436 blue_screen_puts(temp); 1437 if (sSerialDebugEnabled) { 1438 for (uint32 i = 0; i < kMaxDebuggerModules; i++) { 1439 if (sDebuggerModules[i] && sDebuggerModules[i]->debugger_puts) 1440 sDebuggerModules[i]->debugger_puts(temp, length); 1441 } 1442 } 1443 } else { 1444 // if we only have one repeat just reprint the last buffer 1445 size_t length = strlen(sLastOutputBuffer); 1446 1447 if (sSerialDebugEnabled) 1448 arch_debug_serial_puts(sLastOutputBuffer); 1449 if (sSyslogOutputEnabled && syslogOutput) 1450 syslog_write(sLastOutputBuffer, length); 1451 if (sBlueScreenEnabled || sDebugScreenEnabled) 1452 blue_screen_puts(sLastOutputBuffer); 1453 if (sSerialDebugEnabled) { 1454 for (uint32 i = 0; i < kMaxDebuggerModules; i++) { 1455 if (sDebuggerModules[i] && sDebuggerModules[i]->debugger_puts) { 1456 sDebuggerModules[i]->debugger_puts(sLastOutputBuffer, 1457 length); 1458 } 1459 } 1460 } 1461 } 1462 1463 sMessageRepeatFirstTime = 0; 1464 sMessageRepeatCount = 0; 1465 } 1466 1467 1468 static void 1469 check_pending_repeats(void* /*data*/, int /*iteration*/) 1470 { 1471 if (sMessageRepeatCount > 0 1472 && (system_time() - sMessageRepeatLastTime > 1000000 1473 || system_time() - sMessageRepeatFirstTime > 3000000)) { 1474 cpu_status state = disable_interrupts(); 1475 acquire_spinlock(&sSpinlock); 1476 1477 flush_pending_repeats(true); 1478 1479 release_spinlock(&sSpinlock); 1480 restore_interrupts(state); 1481 } 1482 } 1483 1484 1485 static void 1486 dprintf_args(const char* format, va_list args, bool syslogOutput) 1487 { 1488 cpu_status state; 1489 int32 length; 1490 uint32 i; 1491 1492 // ToDo: maybe add a non-interrupt buffer and path that only 1493 // needs to acquire a semaphore instead of needing to disable 1494 // interrupts? 1495 1496 state = disable_interrupts(); 1497 acquire_spinlock(&sSpinlock); 1498 1499 length = vsnprintf(sOutputBuffer, OUTPUT_BUFFER_SIZE, format, args); 1500 1501 if (length >= OUTPUT_BUFFER_SIZE) 1502 length = OUTPUT_BUFFER_SIZE - 1; 1503 1504 if (length > 1 && sOutputBuffer[length - 1] == '\n' 1505 && strncmp(sOutputBuffer, sLastOutputBuffer, length) == 0) { 1506 sMessageRepeatCount++; 1507 sMessageRepeatLastTime = system_time(); 1508 if (sMessageRepeatFirstTime == 0) 1509 sMessageRepeatFirstTime = sMessageRepeatLastTime; 1510 } else { 1511 flush_pending_repeats(syslogOutput); 1512 1513 if (sSerialDebugEnabled) 1514 arch_debug_serial_puts(sOutputBuffer); 1515 if (syslogOutput) 1516 syslog_write(sOutputBuffer, length); 1517 if (sBlueScreenEnabled || sDebugScreenEnabled) 1518 blue_screen_puts(sOutputBuffer); 1519 for (i = 0; sSerialDebugEnabled && i < kMaxDebuggerModules; i++) { 1520 if (sDebuggerModules[i] && sDebuggerModules[i]->debugger_puts) 1521 sDebuggerModules[i]->debugger_puts(sOutputBuffer, length); 1522 } 1523 1524 memcpy(sLastOutputBuffer, sOutputBuffer, length); 1525 sLastOutputBuffer[length] = 0; 1526 } 1527 1528 release_spinlock(&sSpinlock); 1529 restore_interrupts(state); 1530 } 1531 1532 1533 void 1534 dprintf(const char* format, ...) 1535 { 1536 va_list args; 1537 1538 if (!sSerialDebugEnabled && !sSyslogOutputEnabled && !sBlueScreenEnabled) 1539 return; 1540 1541 va_start(args, format); 1542 dprintf_args(format, args, sSyslogOutputEnabled); 1543 va_end(args); 1544 } 1545 1546 1547 void 1548 dprintf_no_syslog(const char* format, ...) 1549 { 1550 va_list args; 1551 1552 if (!sSerialDebugEnabled && !sBlueScreenEnabled) 1553 return; 1554 1555 va_start(args, format); 1556 dprintf_args(format, args, false); 1557 va_end(args); 1558 } 1559 1560 1561 /*! Similar to dprintf() but thought to be used in the kernel 1562 debugger only (it doesn't lock). 1563 */ 1564 void 1565 kprintf(const char* format, ...) 1566 { 1567 if (sDebugOutputFilter != NULL) { 1568 va_list args; 1569 va_start(args, format); 1570 sDebugOutputFilter->Print(format, args); 1571 va_end(args); 1572 } 1573 } 1574 1575 1576 void 1577 kprintf_unfiltered(const char* format, ...) 1578 { 1579 va_list args; 1580 va_start(args, format); 1581 gDefaultDebugOutputFilter.Print(format, args); 1582 va_end(args); 1583 } 1584 1585 1586 const char* 1587 debug_demangle_symbol(const char* symbol, char* buffer, size_t bufferSize, 1588 bool* _isObjectMethod) 1589 { 1590 if (sDemangleModule != NULL && sDemangleModule->demangle_symbol != NULL) { 1591 return sDemangleModule->demangle_symbol(symbol, buffer, bufferSize, 1592 _isObjectMethod); 1593 } 1594 1595 if (_isObjectMethod != NULL) 1596 *_isObjectMethod = false; 1597 1598 return symbol; 1599 } 1600 1601 1602 status_t 1603 debug_get_next_demangled_argument(uint32* _cookie, const char* symbol, 1604 char* name, size_t nameSize, int32* _type, size_t* _argumentLength) 1605 { 1606 if (sDemangleModule != NULL && sDemangleModule->get_next_argument != NULL) { 1607 return sDemangleModule->get_next_argument(_cookie, symbol, name, 1608 nameSize, _type, _argumentLength); 1609 } 1610 1611 return B_NOT_SUPPORTED; 1612 } 1613 1614 1615 struct thread* 1616 debug_set_debugged_thread(struct thread* thread) 1617 { 1618 struct thread* previous = sDebuggedThread; 1619 sDebuggedThread = thread; 1620 return previous; 1621 } 1622 1623 1624 struct thread* 1625 debug_get_debugged_thread() 1626 { 1627 return sDebuggedThread != NULL 1628 ? sDebuggedThread : thread_get_current_thread(); 1629 } 1630 1631 1632 // #pragma mark - 1633 // userland syscalls 1634 1635 1636 void 1637 _user_debug_output(const char* userString) 1638 { 1639 char string[512]; 1640 int32 length; 1641 1642 if (!sSerialDebugEnabled) 1643 return; 1644 1645 if (!IS_USER_ADDRESS(userString)) 1646 return; 1647 1648 do { 1649 length = user_strlcpy(string, userString, sizeof(string)); 1650 debug_puts(string, length); 1651 userString += sizeof(string) - 1; 1652 } while (length >= (ssize_t)sizeof(string)); 1653 } 1654 1655 1656 void 1657 dump_block(const char* buffer, int size, const char* prefix) 1658 { 1659 const int DUMPED_BLOCK_SIZE = 16; 1660 int i; 1661 1662 for (i = 0; i < size;) { 1663 int start = i; 1664 1665 dprintf("%s%04x ", prefix, i); 1666 for (; i < start + DUMPED_BLOCK_SIZE; i++) { 1667 if (!(i % 4)) 1668 dprintf(" "); 1669 1670 if (i >= size) 1671 dprintf(" "); 1672 else 1673 dprintf("%02x", *(unsigned char*)(buffer + i)); 1674 } 1675 dprintf(" "); 1676 1677 for (i = start; i < start + DUMPED_BLOCK_SIZE; i++) { 1678 if (i < size) { 1679 char c = buffer[i]; 1680 1681 if (c < 30) 1682 dprintf("."); 1683 else 1684 dprintf("%c", c); 1685 } else 1686 break; 1687 } 1688 dprintf("\n"); 1689 } 1690 } 1691