xref: /haiku/src/system/kernel/debug/debug.cpp (revision b2c7de82305294ddf7dd438eecf63f281ef33eba)
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