xref: /haiku/src/system/kernel/arch/x86/arch_debug.cpp (revision c9ad965c81b08802fed0827fd1dd16f45297928a)
1 /*
2  * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
3  * Copyright 2002-2008, Axel Dörfler, axeld@pinc-software.de.
4  * Distributed under the terms of the MIT License.
5  *
6  * Copyright 2001, Travis Geiselbrecht. All rights reserved.
7  * Distributed under the terms of the NewOS License.
8  */
9 
10 
11 #include <arch/debug.h>
12 
13 #include <stdio.h>
14 #include <stdlib.h>
15 
16 #include <cpu.h>
17 #include <debug.h>
18 #include <debug_heap.h>
19 #include <elf.h>
20 #include <kernel.h>
21 #include <kimage.h>
22 #include <thread.h>
23 #include <vm.h>
24 #include <vm_types.h>
25 
26 #include <arch_cpu.h>
27 
28 
29 struct stack_frame {
30 	struct stack_frame	*previous;
31 	addr_t				return_address;
32 };
33 
34 #define NUM_PREVIOUS_LOCATIONS 32
35 
36 
37 static bool
38 already_visited(uint32 *visited, int32 *_last, int32 *_num, uint32 ebp)
39 {
40 	int32 last = *_last;
41 	int32 num = *_num;
42 	int32 i;
43 
44 	for (i = 0; i < num; i++) {
45 		if (visited[(NUM_PREVIOUS_LOCATIONS + last - i) % NUM_PREVIOUS_LOCATIONS] == ebp)
46 			return true;
47 	}
48 
49 	*_last = last = (last + 1) % NUM_PREVIOUS_LOCATIONS;
50 	visited[last] = ebp;
51 
52 	if (num < NUM_PREVIOUS_LOCATIONS)
53 		*_num = num + 1;
54 
55 	return false;
56 }
57 
58 
59 /*!	Safe to be called only from outside the debugger.
60 */
61 static status_t
62 get_next_frame_no_debugger(addr_t ebp, addr_t *_next, addr_t *_eip)
63 {
64 	// TODO: Do this more efficiently in assembly.
65 	stack_frame frame;
66 	if (user_memcpy(&frame, (void*)ebp, sizeof(frame)) != B_OK)
67 		return B_BAD_ADDRESS;
68 
69 	*_eip = frame.return_address;
70 	*_next = (addr_t)frame.previous;
71 
72 	return B_OK;
73 }
74 
75 
76 /*!	Safe to be called only from inside the debugger.
77 */
78 static status_t
79 get_next_frame_debugger(addr_t ebp, addr_t *_next, addr_t *_eip)
80 {
81 	stack_frame frame;
82 	if (debug_memcpy(&frame, (void*)ebp, sizeof(frame)) != B_OK)
83 		return B_BAD_ADDRESS;
84 
85 	*_eip = frame.return_address;
86 	*_next = (addr_t)frame.previous;
87 
88 	return B_OK;
89 }
90 
91 
92 static status_t
93 lookup_symbol(struct thread* thread, addr_t address, addr_t *_baseAddress,
94 	const char **_symbolName, const char **_imageName, bool *_exactMatch)
95 {
96 	status_t status = B_ENTRY_NOT_FOUND;
97 
98 	if (IS_KERNEL_ADDRESS(address)) {
99 		// a kernel symbol
100 		status = elf_debug_lookup_symbol_address(address, _baseAddress,
101 			_symbolName, _imageName, _exactMatch);
102 	} else if (thread != NULL && thread->team != NULL) {
103 		// try a lookup using the userland runtime loader structures
104 		status = elf_debug_lookup_user_symbol_address(thread->team, address,
105 			_baseAddress, _symbolName, _imageName, _exactMatch);
106 
107 		if (status != B_OK) {
108 			// try to locate the image in the images loaded into user space
109 			status = image_debug_lookup_user_symbol_address(thread->team,
110 				address, _baseAddress, _symbolName, _imageName, _exactMatch);
111 		}
112 	}
113 
114 	return status;
115 }
116 
117 
118 static void
119 set_debug_argument_variable(int32 index, uint64 value)
120 {
121 	char name[8];
122 	snprintf(name, sizeof(name), "_arg%ld", index);
123 	set_debug_variable(name, value);
124 }
125 
126 
127 static status_t
128 print_demangled_call(const char* image, const char* symbol, addr_t args,
129 	bool noObjectMethod, bool addDebugVariables)
130 {
131 	static const size_t kBufferSize = 256;
132 	char* buffer = (char*)debug_malloc(kBufferSize);
133 	if (buffer == NULL)
134 		return B_NO_MEMORY;
135 
136 	bool isObjectMethod;
137 	const char* name = debug_demangle_symbol(symbol, buffer, kBufferSize,
138 		&isObjectMethod);
139 	if (name == NULL) {
140 		debug_free(buffer);
141 		return B_ERROR;
142 	}
143 
144 	uint32* arg = (uint32*)args;
145 
146 	if (noObjectMethod)
147 		isObjectMethod = false;
148 	if (isObjectMethod) {
149 		const char* lastName = strrchr(name, ':') - 1;
150 		int namespaceLength = lastName - name;
151 
152 		kprintf("<%s> %.*s<\33[32m%p\33[0m>%s", image, namespaceLength, name,
153 			*(uint32 **)arg, lastName);
154 		if (addDebugVariables)
155 			set_debug_variable("_this", *(uint32 *)arg);
156 		arg++;
157 	} else
158 		kprintf("<%s> %s", image, name);
159 
160 	kprintf("(");
161 
162 	size_t length;
163 	int32 type, i = 0;
164 	uint32 cookie = 0;
165 	while (debug_get_next_demangled_argument(&cookie, symbol, buffer,
166 			kBufferSize, &type, &length) == B_OK) {
167 		if (i++ > 0)
168 			kprintf(", ");
169 
170 		// retrieve value and type identifier
171 
172 		uint64 value;
173 
174 		switch (type) {
175 			case B_INT64_TYPE:
176 				value = *(int64*)arg;
177 				kprintf("int64: \33[34m%Ld\33[0m", value);
178 				break;
179 			case B_INT32_TYPE:
180 				value = *(int32*)arg;
181 				kprintf("int32: \33[34m%ld\33[0m", (int32)value);
182 				break;
183 			case B_INT16_TYPE:
184 				value = *(int16*)arg;
185 				kprintf("int16: \33[34m%d\33[0m", (int16)value);
186 				break;
187 			case B_INT8_TYPE:
188 				value = *(int8*)arg;
189 				kprintf("int8: \33[34m%d\33[0m", (int8)value);
190 				break;
191 			case B_UINT64_TYPE:
192 				value = *(uint64*)arg;
193 				kprintf("uint64: \33[34m%#Lx\33[0m", value);
194 				if (value < 0x100000)
195 					kprintf(" (\33[34m%Lu\33[0m)", value);
196 				break;
197 			case B_UINT32_TYPE:
198 				value = *(uint32*)arg;
199 				kprintf("uint32: \33[34m%#lx\33[0m", (uint32)value);
200 				if (value < 0x100000)
201 					kprintf(" (\33[34m%lu\33[0m)", (uint32)value);
202 				break;
203 			case B_UINT16_TYPE:
204 				value = *(uint16*)arg;
205 				kprintf("uint16: \33[34m%#x\33[0m (\33[34m%u\33[0m)",
206 					(uint16)value, (uint16)value);
207 				break;
208 			case B_UINT8_TYPE:
209 				value = *(uint8*)arg;
210 				kprintf("uint8: \33[34m%#x\33[0m (\33[34m%u\33[0m)",
211 					(uint8)value, (uint8)value);
212 				break;
213 			case B_BOOL_TYPE:
214 				value = *(uint8*)arg;
215 				kprintf("\33[34m%s\33[0m", value ? "true" : "false");
216 				break;
217 			default:
218 				if (buffer[0])
219 					kprintf("%s: ", buffer);
220 
221 				if (length == 4) {
222 					value = *(uint32*)arg;
223 					if (value == 0
224 						&& (type == B_POINTER_TYPE || type == B_REF_TYPE))
225 						kprintf("NULL");
226 					else
227 						kprintf("\33[34m%#lx\33[0m", (uint32)value);
228 					break;
229 				}
230 
231 				if (length == 8)
232 					value = *(uint64*)arg;
233 				else
234 					value = (uint64)arg;
235 				kprintf("\33[34m%#Lx\33[0m", value);
236 				break;
237 		}
238 
239 		if (type == B_STRING_TYPE) {
240 			if (value == 0)
241 				kprintf(" \33[31m\"<NULL>\"\33[0m");
242 			else if (debug_strlcpy(buffer, (char*)value, kBufferSize) < B_OK)
243 				kprintf(" \33[31m\"<???>\"\33[0m");
244 			else
245 				kprintf(" \33[36m\"%s\"\33[0m", buffer);
246 		}
247 
248 		if (addDebugVariables)
249 			set_debug_argument_variable(i, value);
250 		arg = (uint32*)((uint8*)arg + length);
251 	}
252 
253 	debug_free(buffer);
254 
255 	kprintf(")");
256 	return B_OK;
257 }
258 
259 
260 static void
261 print_stack_frame(struct thread *thread, addr_t eip, addr_t ebp, addr_t nextEbp,
262 	int32 callIndex, bool demangle)
263 {
264 	const char *symbol, *image;
265 	addr_t baseAddress;
266 	bool exactMatch;
267 	status_t status;
268 	addr_t diff;
269 
270 	diff = nextEbp - ebp;
271 
272 	// kernel space/user space switch
273 	if (diff & 0x80000000)
274 		diff = 0;
275 
276 	status = lookup_symbol(thread, eip, &baseAddress, &symbol, &image,
277 		&exactMatch);
278 
279 	kprintf("%2ld %08lx (+%4ld) %08lx   ", callIndex, ebp, diff, eip);
280 
281 	if (status == B_OK) {
282 		if (exactMatch && demangle) {
283 			status = print_demangled_call(image, symbol, nextEbp + 8, false,
284 				false);
285 		}
286 
287 		if (!exactMatch || !demangle || status != B_OK) {
288 			if (symbol != NULL) {
289 				kprintf("<%s>:%s%s", image, symbol,
290 					exactMatch ? "" : " (nearest)");
291 			} else
292 				kprintf("<%s@%p>:unknown", image, (void *)baseAddress);
293 		}
294 
295 		kprintf(" + 0x%04lx\n", eip - baseAddress);
296 	} else {
297 		vm_area *area = NULL;
298 		if (thread != NULL && thread->team != NULL
299 			&& thread->team->address_space != NULL) {
300 			area = vm_area_lookup(thread->team->address_space, eip);
301 		}
302 		if (area != NULL) {
303 			kprintf("%ld:%s@%p + %#lx\n", area->id, area->name,
304 				(void*)area->base, eip - area->base);
305 		} else
306 			kprintf("\n");
307 	}
308 }
309 
310 
311 static void
312 print_iframe(struct iframe *frame)
313 {
314 	bool isUser = IFRAME_IS_USER(frame);
315 	kprintf("%s iframe at %p (end = %p)\n", isUser ? "user" : "kernel", frame,
316 		isUser ? (uint32*)(frame + 1) : &frame->user_esp);
317 
318 	kprintf(" eax 0x%-9lx    ebx 0x%-9lx     ecx 0x%-9lx  edx 0x%lx\n",
319 		frame->eax, frame->ebx, frame->ecx, frame->edx);
320 	kprintf(" esi 0x%-9lx    edi 0x%-9lx     ebp 0x%-9lx  esp 0x%lx\n",
321 		frame->esi, frame->edi, frame->ebp, frame->esp);
322 	kprintf(" eip 0x%-9lx eflags 0x%-9lx", frame->eip, frame->flags);
323 	if (isUser) {
324 		// from user space
325 		kprintf("user esp 0x%lx", frame->user_esp);
326 	}
327 	kprintf("\n");
328 	kprintf(" vector: 0x%lx, error code: 0x%lx\n", frame->vector,
329 		frame->error_code);
330 }
331 
332 
333 static bool
334 setup_for_thread(char *arg, struct thread **_thread, uint32 *_ebp,
335 	uint32 *_oldPageDirectory)
336 {
337 	struct thread *thread = NULL;
338 
339 	if (arg != NULL) {
340 		thread_id id = strtoul(arg, NULL, 0);
341 		thread = thread_get_thread_struct_locked(id);
342 		if (thread == NULL) {
343 			kprintf("could not find thread %ld\n", id);
344 			return false;
345 		}
346 
347 		if (id != thread_get_current_thread_id()) {
348 			// switch to the page directory of the new thread to be
349 			// able to follow the stack trace into userland
350 			addr_t newPageDirectory = (addr_t)x86_next_page_directory(
351 				thread_get_current_thread(), thread);
352 
353 			if (newPageDirectory != 0) {
354 				read_cr3(*_oldPageDirectory);
355 				write_cr3(newPageDirectory);
356 			}
357 
358 			// read %ebp from the thread's stack stored by a pushad
359 			*_ebp = thread->arch_info.current_stack.esp[2];
360 		} else
361 			thread = NULL;
362 	}
363 
364 	if (thread == NULL) {
365 		// if we don't have a thread yet, we want the current one
366 		// (ebp has been set by the caller for this case already)
367 		thread = thread_get_current_thread();
368 	}
369 
370 	*_thread = thread;
371 	return true;
372 }
373 
374 
375 static bool
376 is_double_fault_stack_address(int32 cpu, addr_t address)
377 {
378 	size_t size;
379 	addr_t bottom = (addr_t)x86_get_double_fault_stack(cpu, &size);
380 	return address >= bottom && address < bottom + size;
381 }
382 
383 
384 static bool
385 is_kernel_stack_address(struct thread* thread, addr_t address)
386 {
387 	// We don't have a thread pointer in the early boot process, but then we are
388 	// on the kernel stack for sure.
389 	if (thread == NULL)
390 		return IS_KERNEL_ADDRESS(address);
391 
392 	return (address >= thread->kernel_stack_base
393 			&& address < thread->kernel_stack_top)
394 		|| (thread->cpu != NULL
395 			&& is_double_fault_stack_address(thread->cpu->cpu_num, address));
396 }
397 
398 
399 static bool
400 is_iframe(struct thread* thread, addr_t frame)
401 {
402 	if (!is_kernel_stack_address(thread, frame))
403 		return false;
404 
405 	addr_t previousFrame = *(addr_t*)frame;
406 	return ((previousFrame & ~IFRAME_TYPE_MASK) == 0 && previousFrame != 0);
407 }
408 
409 
410 static struct iframe *
411 find_previous_iframe(struct thread *thread, addr_t frame)
412 {
413 	// iterate backwards through the stack frames, until we hit an iframe
414 	while (is_kernel_stack_address(thread, frame)) {
415 		if (is_iframe(thread, frame))
416 			return (struct iframe*)frame;
417 
418 		frame = *(addr_t*)frame;
419 	}
420 
421 	return NULL;
422 }
423 
424 
425 static struct iframe*
426 get_previous_iframe(struct thread* thread, struct iframe* frame)
427 {
428 	if (frame == NULL)
429 		return NULL;
430 
431 	return find_previous_iframe(thread, frame->ebp);
432 }
433 
434 
435 static struct iframe*
436 get_current_iframe(struct thread* thread)
437 {
438 	if (thread == thread_get_current_thread())
439 		return i386_get_current_iframe();
440 
441 	addr_t ebp = thread->arch_info.current_stack.esp[2];
442 		// NOTE: This doesn't work, if the thread is running (on another CPU).
443 	return find_previous_iframe(thread, ebp);
444 }
445 
446 
447 uint32*
448 find_debug_variable(const char* variableName, bool& settable)
449 {
450 	struct iframe* frame = get_current_iframe(debug_get_debugged_thread());
451 	if (frame == NULL)
452 		return NULL;
453 
454 	settable = false;
455 
456 	if (strcmp(variableName, "gs") == 0) {
457 		return &frame->gs;
458 	} else if (strcmp(variableName, "fs") == 0) {
459 		return &frame->fs;
460 	} else if (strcmp(variableName, "es") == 0) {
461 		return &frame->es;
462 	} else if (strcmp(variableName, "ds") == 0) {
463 		return &frame->ds;
464 	} else if (strcmp(variableName, "cs") == 0) {
465 		return &frame->cs;
466 	} else if (strcmp(variableName, "edi") == 0) {
467 		settable = true;
468 		return &frame->edi;
469 	} else if (strcmp(variableName, "esi") == 0) {
470 		settable = true;
471 		return &frame->esi;
472 	} else if (strcmp(variableName, "ebp") == 0) {
473 		settable = true;
474 		return &frame->ebp;
475 	} else if (strcmp(variableName, "esp") == 0) {
476 		settable = true;
477 		return &frame->esp;
478 	} else if (strcmp(variableName, "ebx") == 0) {
479 		settable = true;
480 		return &frame->ebx;
481 	} else if (strcmp(variableName, "edx") == 0) {
482 		settable = true;
483 		return &frame->edx;
484 	} else if (strcmp(variableName, "ecx") == 0) {
485 		settable = true;
486 		return &frame->ecx;
487 	} else if (strcmp(variableName, "eax") == 0) {
488 		settable = true;
489 		return &frame->eax;
490 	} else if (strcmp(variableName, "orig_eax") == 0) {
491 		settable = true;
492 		return &frame->orig_eax;
493 	} else if (strcmp(variableName, "orig_edx") == 0) {
494 		settable = true;
495 		return &frame->orig_edx;
496 	} else if (strcmp(variableName, "eip") == 0) {
497 		settable = true;
498 		return &frame->eip;
499 	} else if (strcmp(variableName, "eflags") == 0) {
500 		settable = true;
501 		return &frame->flags;
502 	}
503 
504 	if (IFRAME_IS_USER(frame)) {
505 		if (strcmp(variableName, "user_esp") == 0) {
506 			settable = true;
507 			return &frame->user_esp;
508 		} else if (strcmp(variableName, "user_ss") == 0) {
509 			return &frame->user_ss;
510 		}
511 	}
512 
513 	return NULL;
514 }
515 
516 
517 static int
518 stack_trace(int argc, char **argv)
519 {
520 	static const char* usage = "usage: %s [-d] [ <thread id> ]\n"
521 		"Prints a stack trace for the current, respectively the specified\n"
522 		"thread.\n"
523 		"  -d           -  Disables the demangling of the symbols.\n"
524 		"  <thread id>  -  The ID of the thread for which to print the stack\n"
525 		"                  trace.\n";
526 	bool demangle = true;
527 	int32 threadIndex = 1;
528 	if (argc > 1 && !strcmp(argv[1], "-d")) {
529 		demangle = false;
530 		threadIndex++;
531 	}
532 
533 	if (argc > threadIndex + 1
534 		|| (argc == 2 && strcmp(argv[1], "--help") == 0)) {
535 		kprintf(usage, argv[0]);
536 		return 0;
537 	}
538 
539 	uint32 previousLocations[NUM_PREVIOUS_LOCATIONS];
540 	struct thread *thread = NULL;
541 	addr_t oldPageDirectory = 0;
542 	uint32 ebp = x86_read_ebp();
543 	int32 num = 0, last = 0;
544 
545 	if (!setup_for_thread(argc == threadIndex + 1 ? argv[threadIndex] : NULL,
546 			&thread, &ebp, &oldPageDirectory))
547 		return 0;
548 
549 	if (thread != NULL) {
550 		kprintf("stack trace for thread %ld \"%s\"\n", thread->id,
551 			thread->name);
552 
553 		kprintf("    kernel stack: %p to %p\n",
554 			(void *)thread->kernel_stack_base,
555 			(void *)(thread->kernel_stack_top));
556 		if (thread->user_stack_base != 0) {
557 			kprintf("      user stack: %p to %p\n",
558 				(void *)thread->user_stack_base,
559 				(void *)(thread->user_stack_base + thread->user_stack_size));
560 		}
561 	}
562 
563 	kprintf("frame               caller     <image>:function + offset\n");
564 
565 	bool onKernelStack = true;
566 
567 	for (int32 callIndex = 0;; callIndex++) {
568 		onKernelStack = onKernelStack
569 			&& is_kernel_stack_address(thread, ebp);
570 
571 		if (onKernelStack && is_iframe(thread, ebp)) {
572 			struct iframe *frame = (struct iframe *)ebp;
573 
574 			print_iframe(frame);
575 			print_stack_frame(thread, frame->eip, ebp, frame->ebp, callIndex,
576 				demangle);
577 
578  			ebp = frame->ebp;
579 		} else {
580 			addr_t eip, nextEbp;
581 
582 			if (get_next_frame_debugger(ebp, &nextEbp, &eip) != B_OK) {
583 				kprintf("%08lx -- read fault\n", ebp);
584 				break;
585 			}
586 
587 			if (eip == 0 || ebp == 0)
588 				break;
589 
590 			print_stack_frame(thread, eip, ebp, nextEbp, callIndex, demangle);
591 			ebp = nextEbp;
592 		}
593 
594 		if (already_visited(previousLocations, &last, &num, ebp)) {
595 			kprintf("circular stack frame: %p!\n", (void *)ebp);
596 			break;
597 		}
598 		if (ebp == 0)
599 			break;
600 	}
601 
602 	if (oldPageDirectory != 0) {
603 		// switch back to the previous page directory to no cause any troubles
604 		write_cr3(oldPageDirectory);
605 	}
606 
607 	return 0;
608 }
609 
610 
611 static void
612 print_call(struct thread *thread, addr_t eip, addr_t ebp, addr_t nextEbp,
613 	int32 argCount)
614 {
615 	const char *symbol, *image;
616 	addr_t baseAddress;
617 	bool exactMatch;
618 	status_t status;
619 	bool demangled = false;
620 	int32 *arg = (int32 *)(nextEbp + 8);
621 
622 	status = lookup_symbol(thread, eip, &baseAddress, &symbol, &image,
623 		&exactMatch);
624 
625 	kprintf("%08lx %08lx   ", ebp, eip);
626 
627 	if (status == B_OK) {
628 		if (symbol != NULL) {
629 			if (exactMatch && (argCount == 0 || argCount == -1)) {
630 				status = print_demangled_call(image, symbol, (addr_t)arg,
631 					argCount == -1, true);
632 				if (status == B_OK)
633 					demangled = true;
634 			}
635 			if (!demangled) {
636 				kprintf("<%s>:%s%s", image, symbol,
637 					exactMatch ? "" : " (nearest)");
638 			}
639 		} else {
640 			kprintf("<%s@%p>:unknown + 0x%04lx", image,
641 				(void *)baseAddress, eip - baseAddress);
642 		}
643 	} else {
644 		vm_area *area = NULL;
645 		if (thread->team->address_space != NULL)
646 			area = vm_area_lookup(thread->team->address_space, eip);
647 		if (area != NULL) {
648 			kprintf("%ld:%s@%p + %#lx", area->id, area->name,
649 				(void *)area->base, eip - area->base);
650 		}
651 	}
652 
653 	if (!demangled) {
654 		kprintf("(");
655 
656 		for (int32 i = 0; i < argCount; i++) {
657 			if (i > 0)
658 				kprintf(", ");
659 			kprintf("%#lx", *arg);
660 			if (*arg > -0x10000 && *arg < 0x10000)
661 				kprintf(" (%ld)", *arg);
662 
663 			set_debug_argument_variable(i + 1, *(uint32 *)arg);
664 			arg++;
665 		}
666 
667 		kprintf(")\n");
668 	} else
669 		kprintf("\n");
670 
671 	set_debug_variable("_frame", nextEbp);
672 }
673 
674 
675 static int
676 show_call(int argc, char **argv)
677 {
678 	static const char* usage
679 		= "usage: %s [ <thread id> ] <call index> [ -<arg count> ]\n"
680 		"Prints a function call with parameters of the current, respectively\n"
681 		"the specified thread.\n"
682 		"  <thread id>   -  The ID of the thread for which to print the call.\n"
683 		"  <call index>  -  The index of the call in the stack trace.\n"
684 		"  <arg count>   -  The number of call arguments to print (use 'c' to\n"
685 		"                   force the C++ demangler to use class methods,\n"
686 		"                   use 'd' to disable demangling).\n";
687 	if (argc == 2 && strcmp(argv[1], "--help") == 0) {
688 		kprintf(usage, argv[0]);
689 		return 0;
690 	}
691 
692 	struct thread *thread = NULL;
693 	addr_t oldPageDirectory = 0;
694 	addr_t ebp = x86_read_ebp();
695 	int32 argCount = 0;
696 
697 	if (argc >= 2 && argv[argc - 1][0] == '-') {
698 		if (argv[argc - 1][1] == 'c')
699 			argCount = -1;
700 		else if (argv[argc - 1][1] == 'd')
701 			argCount = -2;
702 		else
703 			argCount = strtoul(argv[argc - 1] + 1, NULL, 0);
704 
705 		if (argCount < -2 || argCount > 16) {
706 			kprintf("Invalid argument count \"%ld\".\n", argCount);
707 			return 0;
708 		}
709 		argc--;
710 	}
711 
712 	if (argc < 2 || argc > 3) {
713 		kprintf(usage, argv[0]);
714 		return 0;
715 	}
716 
717 	if (!setup_for_thread(argc == 3 ? argv[1] : NULL, &thread, &ebp,
718 			&oldPageDirectory))
719 		return 0;
720 
721 	int32 callIndex = strtoul(argv[argc == 3 ? 2 : 1], NULL, 0);
722 
723 	if (thread != NULL)
724 		kprintf("thread %ld, %s\n", thread->id, thread->name);
725 
726 	bool onKernelStack = true;
727 
728 	for (int32 index = 0; index <= callIndex; index++) {
729 		onKernelStack = onKernelStack
730 			&& is_kernel_stack_address(thread, ebp);
731 
732 		if (onKernelStack && is_iframe(thread, ebp)) {
733 			struct iframe *frame = (struct iframe *)ebp;
734 
735 			if (index == callIndex)
736 				print_call(thread, frame->eip, ebp, frame->ebp, argCount);
737 
738  			ebp = frame->ebp;
739 		} else {
740 			addr_t eip, nextEbp;
741 
742 			if (get_next_frame_debugger(ebp, &nextEbp, &eip) != B_OK) {
743 				kprintf("%08lx -- read fault\n", ebp);
744 				break;
745 			}
746 
747 			if (eip == 0 || ebp == 0)
748 				break;
749 
750 			if (index == callIndex)
751 				print_call(thread, eip, ebp, nextEbp, argCount);
752 
753 			ebp = nextEbp;
754 		}
755 
756 		if (ebp == 0)
757 			break;
758 	}
759 
760 	if (oldPageDirectory != 0) {
761 		// switch back to the previous page directory to not cause any troubles
762 		write_cr3(oldPageDirectory);
763 	}
764 
765 	return 0;
766 }
767 
768 
769 static int
770 dump_iframes(int argc, char **argv)
771 {
772 	static const char* usage = "usage: %s [ <thread id> ]\n"
773 		"Prints the iframe stack for the current, respectively the specified\n"
774 		"thread.\n"
775 		"  <thread id>  -  The ID of the thread for which to print the iframe\n"
776 		"                  stack.\n";
777 	if (argc == 2 && strcmp(argv[1], "--help") == 0) {
778 		kprintf(usage, argv[0]);
779 		return 0;
780 	}
781 
782 	struct thread *thread = NULL;
783 
784 	if (argc < 2) {
785 		thread = thread_get_current_thread();
786 	} else if (argc == 2) {
787 		thread_id id = strtoul(argv[1], NULL, 0);
788 		thread = thread_get_thread_struct_locked(id);
789 		if (thread == NULL) {
790 			kprintf("could not find thread %ld\n", id);
791 			return 0;
792 		}
793 	} else if (argc > 2) {
794 		kprintf(usage, argv[0]);
795 		return 0;
796 	}
797 
798 	if (thread != NULL)
799 		kprintf("iframes for thread %ld \"%s\"\n", thread->id, thread->name);
800 
801 	struct iframe* frame = find_previous_iframe(thread, x86_read_ebp());
802 	while (frame != NULL) {
803 		print_iframe(frame);
804 		frame = get_previous_iframe(thread, frame);
805 	}
806 
807 	return 0;
808 }
809 
810 
811 static bool
812 is_calling(struct thread *thread, addr_t eip, const char *pattern,
813 	addr_t start, addr_t end)
814 {
815 	if (pattern == NULL)
816 		return eip >= start && eip < end;
817 
818 	const char *symbol;
819 	if (lookup_symbol(thread, eip, NULL, &symbol, NULL, NULL) != B_OK)
820 		return false;
821 
822 	return strstr(symbol, pattern);
823 }
824 
825 
826 static int
827 cmd_in_context(int argc, char** argv)
828 {
829 	if (argc != 2) {
830 		print_debugger_command_usage(argv[0]);
831 		return 0;
832 	}
833 
834 	// get the thread ID
835 	const char* commandLine = argv[1];
836 	char threadIDString[16];
837 	if (parse_next_debug_command_argument(&commandLine, threadIDString,
838 			sizeof(threadIDString)) != B_OK) {
839 		kprintf("Failed to parse thread ID.\n");
840 		return 0;
841 	}
842 
843 	if (commandLine == NULL) {
844 		print_debugger_command_usage(argv[0]);
845 		return 0;
846 	}
847 
848 	uint64 threadID;
849 	if (!evaluate_debug_expression(threadIDString, &threadID, false))
850 		return 0;
851 
852 	// get the thread
853 	struct thread* thread = thread_get_thread_struct_locked(threadID);
854 	if (thread == NULL) {
855 		kprintf("Could not find thread with ID \"%s\".\n", threadIDString);
856 		return 0;
857 	}
858 
859 	// switch the page directory, if necessary
860 	addr_t oldPageDirectory = 0;
861 	if (thread != thread_get_current_thread()) {
862 		addr_t newPageDirectory = (addr_t)x86_next_page_directory(
863 			thread_get_current_thread(), thread);
864 
865 		if (newPageDirectory != 0) {
866 			read_cr3(oldPageDirectory);
867 			write_cr3(newPageDirectory);
868 		}
869 	}
870 
871 	struct thread* previousThread = debug_set_debugged_thread(thread);
872 
873 	// execute the command
874 	evaluate_debug_command(commandLine);
875 
876 	debug_set_debugged_thread(previousThread);
877 
878 	// reset the page directory
879 	if (oldPageDirectory)
880 		write_cr3(oldPageDirectory);
881 
882 	return 0;
883 }
884 
885 
886 //	#pragma mark -
887 
888 
889 void
890 arch_debug_stack_trace(void)
891 {
892 	stack_trace(0, NULL);
893 }
894 
895 
896 bool
897 arch_debug_contains_call(struct thread *thread, const char *symbol,
898 	addr_t start, addr_t end)
899 {
900 	addr_t ebp;
901 	if (thread == thread_get_current_thread())
902 		ebp = x86_read_ebp();
903 	else
904 		ebp = thread->arch_info.current_stack.esp[2];
905 
906 	for (;;) {
907 		if (!is_kernel_stack_address(thread, ebp))
908 			break;
909 
910 		if (is_iframe(thread, ebp)) {
911 			struct iframe *frame = (struct iframe *)ebp;
912 
913 			if (is_calling(thread, frame->eip, symbol, start, end))
914 				return true;
915 
916  			ebp = frame->ebp;
917 		} else {
918 			addr_t eip, nextEbp;
919 
920 			if (get_next_frame_no_debugger(ebp, &nextEbp, &eip) != B_OK
921 				|| eip == 0 || ebp == 0)
922 				break;
923 
924 			if (is_calling(thread, eip, symbol, start, end))
925 				return true;
926 
927 			ebp = nextEbp;
928 		}
929 
930 		if (ebp == 0)
931 			break;
932 	}
933 
934 	return false;
935 }
936 
937 
938 void *
939 arch_debug_get_caller(void)
940 {
941 	struct stack_frame *frame = (struct stack_frame *)x86_read_ebp();
942 	return (void *)frame->previous->return_address;
943 }
944 
945 
946 /*!	Captures a stack trace (the return addresses) of the current thread.
947 	\param returnAddresses The array the return address shall be written to.
948 	\param maxCount The maximum number of return addresses to be captured.
949 	\param skipIframes The number of interrupt frames that shall be skipped. If
950 		greater than 0, \a skipFrames is ignored.
951 	\param skipFrames The number of stack frames that shall be skipped.
952 	\param userOnly If \c true, only userland return addresses are captured.
953 	\return The number of return addresses written to the given array.
954 */
955 int32
956 arch_debug_get_stack_trace(addr_t* returnAddresses, int32 maxCount,
957 	int32 skipIframes, int32 skipFrames, bool userOnly)
958 {
959 	// Keep skipping normal stack frames until we've skipped the iframes we're
960 	// supposed to skip.
961 	if (skipIframes > 0) {
962 		skipFrames = INT_MAX;
963 	} else {
964 		// always skip our own frame
965 		skipFrames++;
966 	}
967 
968 	struct thread* thread = thread_get_current_thread();
969 	int32 count = 0;
970 	addr_t ebp = x86_read_ebp();
971 	bool onKernelStack = true;
972 
973 	while (ebp != 0 && count < maxCount) {
974 		onKernelStack = onKernelStack
975 			&& is_kernel_stack_address(thread, ebp);
976 
977 		addr_t eip;
978 		addr_t nextEbp;
979 
980 		if (onKernelStack && is_iframe(thread, ebp)) {
981 			struct iframe *frame = (struct iframe*)ebp;
982 			eip = frame->eip;
983  			nextEbp = frame->ebp;
984 
985 			if (skipIframes > 0) {
986 				if (--skipIframes == 0)
987 					skipFrames = 0;
988 			}
989 		} else {
990 			if (get_next_frame_no_debugger(ebp, &nextEbp, &eip) != B_OK)
991 				break;
992 		}
993 
994 		if (skipFrames <= 0 && (!userOnly || IS_USER_ADDRESS(ebp)))
995 			returnAddresses[count++] = eip;
996 		else
997 			skipFrames--;
998 
999 		ebp = nextEbp;
1000 	}
1001 
1002 	return count;
1003 }
1004 
1005 
1006 /*!	Returns the program counter of the currently debugged (respectively this)
1007 	thread where the innermost interrupts happened. \a _isSyscall, if specified,
1008 	is set to whether this interrupt frame was created by a syscall. Returns
1009 	\c NULL, if there's no such frame or a problem occurred retrieving it;
1010 	\a _isSyscall won't be set in this case.
1011 */
1012 void*
1013 arch_debug_get_interrupt_pc(bool* _isSyscall)
1014 {
1015 	struct iframe* frame = get_current_iframe(debug_get_debugged_thread());
1016 	if (frame == NULL)
1017 		return NULL;
1018 
1019 	if (_isSyscall != NULL)
1020 		*_isSyscall = frame->vector == 99;
1021 
1022 	return (void*)(addr_t)frame->eip;
1023 }
1024 
1025 
1026 /*!	Sets the current thread to \c NULL.
1027 	Invoked in the kernel debugger only.
1028 */
1029 void
1030 arch_debug_unset_current_thread(void)
1031 {
1032 	write_dr3(NULL);
1033 }
1034 
1035 
1036 bool
1037 arch_is_debug_variable_defined(const char* variableName)
1038 {
1039 	bool settable;
1040 	return find_debug_variable(variableName, settable);
1041 }
1042 
1043 
1044 status_t
1045 arch_set_debug_variable(const char* variableName, uint64 value)
1046 {
1047 	bool settable;
1048 	uint32* variable = find_debug_variable(variableName, settable);
1049 	if (variable == NULL)
1050 		return B_ENTRY_NOT_FOUND;
1051 
1052 	if (!settable)
1053 		return B_NOT_ALLOWED;
1054 
1055 	*variable = (uint32)value;
1056 	return B_OK;
1057 }
1058 
1059 
1060 status_t
1061 arch_get_debug_variable(const char* variableName, uint64* value)
1062 {
1063 	bool settable;
1064 	uint32* variable = find_debug_variable(variableName, settable);
1065 	if (variable == NULL)
1066 		return B_ENTRY_NOT_FOUND;
1067 
1068 	*value = *variable;
1069 	return B_OK;
1070 }
1071 
1072 
1073 status_t
1074 arch_debug_init(kernel_args *args)
1075 {
1076 	// at this stage, the debugger command system is alive
1077 
1078 	add_debugger_command("where", &stack_trace, "Same as \"sc\"");
1079 	add_debugger_command("bt", &stack_trace, "Same as \"sc\" (as in gdb)");
1080 	add_debugger_command("sc", &stack_trace,
1081 		"Stack crawl for current thread (or any other)");
1082 	add_debugger_command("iframe", &dump_iframes,
1083 		"Dump iframes for the specified thread");
1084 	add_debugger_command("call", &show_call, "Show call with arguments");
1085 	add_debugger_command_etc("in_context", &cmd_in_context,
1086 		"Executes a command in the context of a given thread",
1087 		"<thread ID> <command> ...\n"
1088 		"Executes a command in the context of a given thread.\n",
1089 		B_KDEBUG_DONT_PARSE_ARGUMENTS);
1090 
1091 	return B_NO_ERROR;
1092 }
1093 
1094