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