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