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