xref: /haiku/src/system/kernel/arch/x86/arch_debug.cpp (revision 746cac055adc6ac3308c7bc2d29040fb95689cc9)
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 	if (status == B_OK) {
103 		*_symbolName = debug_demangle(*_symbolName);
104 	}
105 
106 	return status;
107 }
108 
109 
110 static void
111 print_stack_frame(struct thread *thread, addr_t eip, addr_t ebp, addr_t nextEbp,
112 	int32 callIndex)
113 {
114 	const char *symbol, *image;
115 	addr_t baseAddress;
116 	bool exactMatch;
117 	status_t status;
118 	addr_t diff;
119 
120 	diff = nextEbp - ebp;
121 
122 	// kernel space/user space switch
123 	if (diff & 0x80000000)
124 		diff = 0;
125 
126 	status = lookup_symbol(thread, eip, &baseAddress, &symbol, &image,
127 		&exactMatch);
128 
129 	kprintf("%2ld %08lx (+%4ld) %08lx", callIndex, ebp, diff, eip);
130 
131 	if (status == B_OK) {
132 		if (symbol != NULL) {
133 			kprintf("   <%s>:%s + 0x%04lx%s\n", image, symbol,
134 				eip - baseAddress, exactMatch ? "" : " (nearest)");
135 		} else {
136 			kprintf("   <%s@%p>:unknown + 0x%04lx\n", image,
137 				(void *)baseAddress, eip - baseAddress);
138 		}
139 	} else {
140 		vm_area *area = NULL;
141 		if (thread->team->address_space != NULL)
142 			area = vm_area_lookup(thread->team->address_space, eip);
143 		if (area != NULL) {
144 			kprintf("   %ld:%s@%p + %#lx\n", area->id, area->name, (void *)area->base,
145 				eip - area->base);
146 		} else
147 			kprintf("\n");
148 	}
149 }
150 
151 
152 static void
153 print_iframe(struct iframe *frame)
154 {
155 	bool isUser = IFRAME_IS_USER(frame);
156 	kprintf("%s iframe at %p (end = %p)\n", isUser ? "user" : "kernel", frame,
157 		isUser ? (uint32*)(frame + 1) : &frame->user_esp);
158 
159 	kprintf(" eax 0x%-9lx    ebx 0x%-9lx     ecx 0x%-9lx  edx 0x%lx\n",
160 		frame->eax, frame->ebx, frame->ecx, frame->edx);
161 	kprintf(" esi 0x%-9lx    edi 0x%-9lx     ebp 0x%-9lx  esp 0x%lx\n",
162 		frame->esi, frame->edi, frame->ebp, frame->esp);
163 	kprintf(" eip 0x%-9lx eflags 0x%-9lx", frame->eip, frame->flags);
164 	if (isUser) {
165 		// from user space
166 		kprintf("user esp 0x%lx", frame->user_esp);
167 	}
168 	kprintf("\n");
169 	kprintf(" vector: 0x%lx, error code: 0x%lx\n", frame->vector,
170 		frame->error_code);
171 }
172 
173 
174 static void
175 setup_for_thread(char *arg, struct thread **_thread, uint32 *_ebp,
176 	uint32 *_oldPageDirectory)
177 {
178 	struct thread *thread = NULL;
179 
180 	if (arg != NULL) {
181 		thread_id id = strtoul(arg, NULL, 0);
182 		thread = thread_get_thread_struct_locked(id);
183 		if (thread == NULL) {
184 			kprintf("could not find thread %ld\n", id);
185 			return;
186 		}
187 
188 		if (id != thread_get_current_thread_id()) {
189 			// switch to the page directory of the new thread to be
190 			// able to follow the stack trace into userland
191 			addr_t newPageDirectory = (addr_t)x86_next_page_directory(
192 				thread_get_current_thread(), thread);
193 
194 			if (newPageDirectory != 0) {
195 				read_cr3(*_oldPageDirectory);
196 				write_cr3(newPageDirectory);
197 			}
198 
199 			// read %ebp from the thread's stack stored by a pushad
200 			*_ebp = thread->arch_info.current_stack.esp[2];
201 		} else
202 			thread = NULL;
203 	}
204 
205 	if (thread == NULL) {
206 		// if we don't have a thread yet, we want the current one
207 		// (ebp has been set by the caller for this case already)
208 		thread = thread_get_current_thread();
209 	}
210 
211 	*_thread = thread;
212 }
213 
214 static bool
215 is_double_fault_stack_address(int32 cpu, addr_t address)
216 {
217 	size_t size;
218 	addr_t bottom = (addr_t)x86_get_double_fault_stack(cpu, &size);
219 	return address >= bottom && address < bottom + size;
220 }
221 
222 
223 static bool
224 is_kernel_stack_address(struct thread* thread, addr_t address)
225 {
226 	// We don't have a thread pointer in the early boot process, but then we are
227 	// on the kernel stack for sure.
228 	if (thread == NULL)
229 		return IS_KERNEL_ADDRESS(address);
230 
231 	return address >= thread->kernel_stack_base
232 			&& address < thread->kernel_stack_top
233 		|| thread->cpu != NULL
234 			&& is_double_fault_stack_address(thread->cpu->cpu_num, address);
235 }
236 
237 
238 static bool
239 is_iframe(struct thread* thread, addr_t frame)
240 {
241 	if (!is_kernel_stack_address(thread, frame))
242 		return false;
243 
244 	addr_t previousFrame = *(addr_t*)frame;
245 	return ((previousFrame & ~IFRAME_TYPE_MASK) == 0 && previousFrame != 0);
246 }
247 
248 
249 static struct iframe *
250 find_previous_iframe(struct thread *thread, addr_t frame)
251 {
252 	// iterate backwards through the stack frames, until we hit an iframe
253 	while (is_kernel_stack_address(thread, frame)) {
254 		if (is_iframe(thread, frame))
255 			return (struct iframe*)frame;
256 
257 		frame = *(addr_t*)frame;
258 	}
259 
260 	return NULL;
261 }
262 
263 
264 static struct iframe*
265 get_previous_iframe(struct thread* thread, struct iframe* frame)
266 {
267 	if (frame == NULL)
268 		return NULL;
269 
270 	return find_previous_iframe(thread, frame->ebp);
271 }
272 
273 
274 static struct iframe*
275 get_current_iframe(struct thread* thread)
276 {
277 	if (thread == thread_get_current_thread())
278 		return i386_get_current_iframe();
279 
280 	addr_t ebp = thread->arch_info.current_stack.esp[2];
281 		// NOTE: This doesn't work, if the thread is running (on another CPU).
282 	return find_previous_iframe(thread, ebp);
283 }
284 
285 
286 uint32*
287 find_debug_variable(const char* variableName, bool& settable)
288 {
289 	struct iframe* frame = get_current_iframe(debug_get_debugged_thread());
290 	if (frame == NULL)
291 		return NULL;
292 
293 	settable = false;
294 
295 	if (strcmp(variableName, "gs") == 0) {
296 		return &frame->gs;
297 	} else if (strcmp(variableName, "fs") == 0) {
298 		return &frame->fs;
299 	} else if (strcmp(variableName, "es") == 0) {
300 		return &frame->es;
301 	} else if (strcmp(variableName, "ds") == 0) {
302 		return &frame->ds;
303 	} else if (strcmp(variableName, "cs") == 0) {
304 		return &frame->cs;
305 	} else if (strcmp(variableName, "edi") == 0) {
306 		settable = true;
307 		return &frame->edi;
308 	} else if (strcmp(variableName, "esi") == 0) {
309 		settable = true;
310 		return &frame->esi;
311 	} else if (strcmp(variableName, "ebp") == 0) {
312 		settable = true;
313 		return &frame->ebp;
314 	} else if (strcmp(variableName, "esp") == 0) {
315 		settable = true;
316 		return &frame->esp;
317 	} else if (strcmp(variableName, "ebx") == 0) {
318 		settable = true;
319 		return &frame->ebx;
320 	} else if (strcmp(variableName, "edx") == 0) {
321 		settable = true;
322 		return &frame->edx;
323 	} else if (strcmp(variableName, "ecx") == 0) {
324 		settable = true;
325 		return &frame->ecx;
326 	} else if (strcmp(variableName, "eax") == 0) {
327 		settable = true;
328 		return &frame->eax;
329 	} else if (strcmp(variableName, "orig_eax") == 0) {
330 		settable = true;
331 		return &frame->orig_eax;
332 	} else if (strcmp(variableName, "orig_edx") == 0) {
333 		settable = true;
334 		return &frame->orig_edx;
335 	} else if (strcmp(variableName, "eip") == 0) {
336 		settable = true;
337 		return &frame->eip;
338 	} else if (strcmp(variableName, "eflags") == 0) {
339 		settable = true;
340 		return &frame->flags;
341 	}
342 
343 	if (IFRAME_IS_USER(frame)) {
344 		if (strcmp(variableName, "user_esp") == 0) {
345 			settable = true;
346 			return &frame->user_esp;
347 		} else if (strcmp(variableName, "user_ss") == 0) {
348 			return &frame->user_ss;
349 		}
350 	}
351 
352 	return NULL;
353 }
354 
355 
356 static int
357 stack_trace(int argc, char **argv)
358 {
359 	static const char* usage = "usage: %s [ <thread id> ]\n"
360 		"Prints a stack trace for the current, respectively the specified\n"
361 		"thread.\n"
362 		"  <thread id>  -  The ID of the thread for which to print the stack\n"
363 		"                  trace.\n";
364 	if (argc > 2 || argc == 2 && strcmp(argv[1], "--help") == 0) {
365 		kprintf(usage, argv[0]);
366 		return 0;
367 	}
368 
369 	uint32 previousLocations[NUM_PREVIOUS_LOCATIONS];
370 	struct thread *thread = NULL;
371 	addr_t oldPageDirectory = 0;
372 	uint32 ebp = x86_read_ebp();
373 	int32 num = 0, last = 0;
374 
375 	setup_for_thread(argc == 2 ? argv[1] : NULL, &thread, &ebp,
376 		&oldPageDirectory);
377 
378 	if (thread != NULL) {
379 		kprintf("stack trace for thread %ld \"%s\"\n", thread->id,
380 			thread->name);
381 
382 		kprintf("    kernel stack: %p to %p\n",
383 			(void *)thread->kernel_stack_base,
384 			(void *)(thread->kernel_stack_top));
385 		if (thread->user_stack_base != 0) {
386 			kprintf("      user stack: %p to %p\n",
387 				(void *)thread->user_stack_base,
388 				(void *)(thread->user_stack_base + thread->user_stack_size));
389 		}
390 	}
391 
392 	kprintf("frame            caller     <image>:function + offset\n");
393 
394 	bool onKernelStack = true;
395 
396 	for (int32 callIndex = 0;; callIndex++) {
397 		onKernelStack = onKernelStack
398 			&& is_kernel_stack_address(thread, ebp);
399 
400 		if (onKernelStack && is_iframe(thread, ebp)) {
401 			struct iframe *frame = (struct iframe *)ebp;
402 
403 			print_iframe(frame);
404 			print_stack_frame(thread, frame->eip, ebp, frame->ebp, callIndex);
405 
406  			ebp = frame->ebp;
407 		} else {
408 			addr_t eip, nextEbp;
409 
410 			if (get_next_frame(ebp, &nextEbp, &eip) != B_OK) {
411 				kprintf("%08lx -- read fault\n", ebp);
412 				break;
413 			}
414 
415 			if (eip == 0 || ebp == 0)
416 				break;
417 
418 			print_stack_frame(thread, eip, ebp, nextEbp, callIndex);
419 			ebp = nextEbp;
420 		}
421 
422 		if (already_visited(previousLocations, &last, &num, ebp)) {
423 			kprintf("circular stack frame: %p!\n", (void *)ebp);
424 			break;
425 		}
426 		if (ebp == 0)
427 			break;
428 	}
429 
430 	if (oldPageDirectory != 0) {
431 		// switch back to the previous page directory to no cause any troubles
432 		write_cr3(oldPageDirectory);
433 	}
434 
435 	return 0;
436 }
437 
438 
439 static void
440 print_call(struct thread *thread, addr_t eip, addr_t ebp, addr_t nextEbp,
441 	int32 argCount)
442 {
443 	const char *symbol, *image;
444 	addr_t baseAddress;
445 	bool exactMatch;
446 	status_t status;
447 
448 	status = lookup_symbol(thread, eip, &baseAddress, &symbol, &image,
449 		&exactMatch);
450 
451 	kprintf("%08lx %08lx", ebp, eip);
452 
453 	if (status == B_OK) {
454 		if (symbol != NULL) {
455 			kprintf("   <%s>:%s%s", image, symbol,
456 				exactMatch ? "" : " (nearest)");
457 		} else {
458 			kprintf("   <%s@%p>:unknown + 0x%04lx", image,
459 				(void *)baseAddress, eip - baseAddress);
460 		}
461 	} else {
462 		vm_area *area = NULL;
463 		if (thread->team->address_space != NULL)
464 			area = vm_area_lookup(thread->team->address_space, eip);
465 		if (area != NULL) {
466 			kprintf("   %ld:%s@%p + %#lx", area->id, area->name,
467 				(void *)area->base, eip - area->base);
468 		}
469 	}
470 
471 	int32 *arg = (int32 *)(nextEbp + 8);
472 	kprintf("(");
473 
474 	for (int32 i = 0; i < argCount; i++) {
475 		if (i > 0)
476 			kprintf(", ");
477 		kprintf("%#lx", *arg);
478 		if (*arg > -0x10000 && *arg < 0x10000)
479 			kprintf(" (%ld)", *arg);
480 
481 		char name[8];
482 		snprintf(name, sizeof(name), "_arg%ld", i + 1);
483 		set_debug_variable(name, *(uint32 *)arg);
484 
485 		arg++;
486 	}
487 
488 	kprintf(")\n");
489 
490 	set_debug_variable("_frame", nextEbp);
491 }
492 
493 
494 static int
495 show_call(int argc, char **argv)
496 {
497 	static const char* usage
498 		= "usage: %s [ <thread id> ] <call index> [ -<arg count> ]\n"
499 		"Prints a function call with parameters of the current, respectively\n"
500 		"the specified thread.\n"
501 		"  <thread id>   -  The ID of the thread for which to print the call.\n"
502 		"  <call index>  -  The index of the call in the stack trace.\n"
503 		"  <arg count>   -  The number of call arguments to print.\n";
504 	if (argc == 2 && strcmp(argv[1], "--help") == 0) {
505 		kprintf(usage, argv[0]);
506 		return 0;
507 	}
508 
509 	struct thread *thread = NULL;
510 	addr_t oldPageDirectory = 0;
511 	addr_t ebp = x86_read_ebp();
512 	int32 argCount = 0;
513 
514 	if (argc >= 2 && argv[argc - 1][0] == '-') {
515 		argCount = strtoul(argv[argc - 1] + 1, NULL, 0);
516 		if (argCount < 0 || argCount > 16) {
517 			kprintf("Invalid argument count \"%ld\".\n", argCount);
518 			return 0;
519 		}
520 		argc--;
521 	}
522 
523 	if (argc < 2 || argc > 3) {
524 		kprintf(usage, argv[0]);
525 		return 0;
526 	}
527 
528 	setup_for_thread(argc == 3 ? argv[1] : NULL, &thread, &ebp,
529 		&oldPageDirectory);
530 
531 	int32 callIndex = strtoul(argv[argc == 3 ? 2 : 1], NULL, 0);
532 
533 	if (thread != NULL)
534 		kprintf("thread %ld, %s\n", thread->id, thread->name);
535 
536 	bool onKernelStack = true;
537 
538 	for (int32 index = 0; index <= callIndex; index++) {
539 		onKernelStack = onKernelStack
540 			&& is_kernel_stack_address(thread, ebp);
541 
542 		if (onKernelStack && is_iframe(thread, ebp)) {
543 			struct iframe *frame = (struct iframe *)ebp;
544 
545 			if (index == callIndex)
546 				print_call(thread, frame->eip, ebp, frame->ebp, argCount);
547 
548  			ebp = frame->ebp;
549 		} else {
550 			addr_t eip, nextEbp;
551 
552 			if (get_next_frame(ebp, &nextEbp, &eip) != B_OK) {
553 				kprintf("%08lx -- read fault\n", ebp);
554 				break;
555 			}
556 
557 			if (eip == 0 || ebp == 0)
558 				break;
559 
560 			if (index == callIndex)
561 				print_call(thread, eip, ebp, nextEbp, argCount);
562 
563 			ebp = nextEbp;
564 		}
565 
566 		if (ebp == 0)
567 			break;
568 	}
569 
570 	if (oldPageDirectory != 0) {
571 		// switch back to the previous page directory to not cause any troubles
572 		write_cr3(oldPageDirectory);
573 	}
574 
575 	return 0;
576 }
577 
578 
579 static int
580 dump_iframes(int argc, char **argv)
581 {
582 	static const char* usage = "usage: %s [ <thread id> ]\n"
583 		"Prints the iframe stack for the current, respectively the specified\n"
584 		"thread.\n"
585 		"  <thread id>  -  The ID of the thread for which to print the iframe\n"
586 		"                  stack.\n";
587 	if (argc == 2 && strcmp(argv[1], "--help") == 0) {
588 		kprintf(usage, argv[0]);
589 		return 0;
590 	}
591 
592 	struct thread *thread = NULL;
593 
594 	if (argc < 2) {
595 		thread = thread_get_current_thread();
596 	} else if (argc == 2) {
597 		thread_id id = strtoul(argv[1], NULL, 0);
598 		thread = thread_get_thread_struct_locked(id);
599 		if (thread == NULL) {
600 			kprintf("could not find thread %ld\n", id);
601 			return 0;
602 		}
603 	} else if (argc > 2) {
604 		kprintf(usage, argv[0]);
605 		return 0;
606 	}
607 
608 	if (thread != NULL)
609 		kprintf("iframes for thread %ld \"%s\"\n", thread->id, thread->name);
610 
611 	struct iframe* frame = find_previous_iframe(thread, x86_read_ebp());
612 	while (frame != NULL) {
613 		print_iframe(frame);
614 		frame = get_previous_iframe(thread, frame);
615 	}
616 
617 	return 0;
618 }
619 
620 
621 static bool
622 is_calling(struct thread *thread, addr_t eip, const char *pattern,
623 	addr_t start, addr_t end)
624 {
625 	if (pattern == NULL)
626 		return eip >= start && eip < end;
627 
628 	const char *symbol;
629 	if (lookup_symbol(thread, eip, NULL, &symbol, NULL, NULL) != B_OK)
630 		return false;
631 
632 	return strstr(symbol, pattern);
633 }
634 
635 
636 static int
637 cmd_in_context(int argc, char** argv)
638 {
639 	if (argc != 2) {
640 		print_debugger_command_usage(argv[0]);
641 		return 0;
642 	}
643 
644 	// get the thread ID
645 	const char* commandLine = argv[1];
646 	char threadIDString[16];
647 	if (parse_next_debug_command_argument(&commandLine, threadIDString,
648 			sizeof(threadIDString)) != B_OK) {
649 		kprintf("Failed to parse thread ID.\n");
650 		return 0;
651 	}
652 
653 	if (commandLine == NULL) {
654 		print_debugger_command_usage(argv[0]);
655 		return 0;
656 	}
657 
658 	uint64 threadID;
659 	if (!evaluate_debug_expression(threadIDString, &threadID, false))
660 		return 0;
661 
662 	// get the thread
663 	struct thread* thread = thread_get_thread_struct_locked(threadID);
664 	if (thread == NULL) {
665 		kprintf("Could not find thread with ID \"%s\".\n", threadIDString);
666 		return 0;
667 	}
668 
669 	// switch the page directory, if necessary
670 	addr_t oldPageDirectory = 0;
671 	if (thread != thread_get_current_thread()) {
672 		addr_t newPageDirectory = (addr_t)x86_next_page_directory(
673 			thread_get_current_thread(), thread);
674 
675 		if (newPageDirectory != 0) {
676 			read_cr3(oldPageDirectory);
677 			write_cr3(newPageDirectory);
678 		}
679 	}
680 
681 	struct thread* previousThread = debug_set_debugged_thread(thread);
682 
683 	// execute the command
684 	evaluate_debug_command(commandLine);
685 
686 	debug_set_debugged_thread(previousThread);
687 
688 	// reset the page directory
689 	if (oldPageDirectory)
690 		write_cr3(oldPageDirectory);
691 
692 	return 0;
693 }
694 
695 
696 //	#pragma mark -
697 
698 
699 bool
700 arch_debug_contains_call(struct thread *thread, const char *symbol,
701 	addr_t start, addr_t end)
702 {
703 	addr_t ebp;
704 	if (thread == thread_get_current_thread())
705 		ebp = x86_read_ebp();
706 	else
707 		ebp = thread->arch_info.current_stack.esp[2];
708 
709 	for (;;) {
710 		if (!is_kernel_stack_address(thread, ebp))
711 			break;
712 
713 		if (is_iframe(thread, ebp)) {
714 			struct iframe *frame = (struct iframe *)ebp;
715 
716 			if (is_calling(thread, frame->eip, symbol, start, end))
717 				return true;
718 
719  			ebp = frame->ebp;
720 		} else {
721 			addr_t eip, nextEbp;
722 
723 			if (get_next_frame(ebp, &nextEbp, &eip) != B_OK
724 				|| eip == 0 || ebp == 0)
725 				break;
726 
727 			if (is_calling(thread, eip, symbol, start, end))
728 				return true;
729 
730 			ebp = nextEbp;
731 		}
732 
733 		if (ebp == 0)
734 			break;
735 	}
736 
737 	return false;
738 }
739 
740 
741 void *
742 arch_debug_get_caller(void)
743 {
744 	struct stack_frame *frame = (struct stack_frame *)x86_read_ebp();
745 	return (void *)frame->previous->return_address;
746 }
747 
748 
749 int32
750 arch_debug_get_stack_trace(addr_t* returnAddresses, int32 maxCount,
751 	int32 skipFrames, bool userOnly)
752 {
753 	// always skip our own frame
754 	skipFrames++;
755 
756 	struct thread* thread = thread_get_current_thread();
757 	int32 count = 0;
758 	addr_t ebp = x86_read_ebp();
759 	bool onKernelStack = true;
760 
761 	while (ebp != 0 && count < maxCount) {
762 		onKernelStack = onKernelStack
763 			&& is_kernel_stack_address(thread, ebp);
764 
765 		addr_t eip;
766 		addr_t nextEbp;
767 
768 		if (onKernelStack && is_iframe(thread, ebp)) {
769 			struct iframe *frame = (struct iframe*)ebp;
770 			eip = frame->eip;
771  			nextEbp = frame->ebp;
772 		} else {
773 			if (get_next_frame(ebp, &nextEbp, &eip) != B_OK)
774 				break;
775 		}
776 
777 		if (skipFrames <= 0 && (!userOnly || IS_USER_ADDRESS(ebp)))
778 			returnAddresses[count++] = eip;
779 		else
780 			skipFrames--;
781 
782 		ebp = nextEbp;
783 	}
784 
785 	return count;
786 }
787 
788 
789 /*!	Returns the program counter of the currently debugged (respectively this)
790 	thread where the innermost interrupts happened. Returns \c NULL, if there's
791 	none or a problem occurred retrieving it.
792 */
793 void*
794 arch_debug_get_interrupt_pc()
795 {
796 	struct iframe* frame = get_current_iframe(debug_get_debugged_thread());
797 	if (frame == NULL)
798 		return NULL;
799 
800 	return (void*)(addr_t)frame->eip;
801 }
802 
803 
804 bool
805 arch_is_debug_variable_defined(const char* variableName)
806 {
807 	bool settable;
808 	return find_debug_variable(variableName, settable);
809 }
810 
811 
812 status_t
813 arch_set_debug_variable(const char* variableName, uint64 value)
814 {
815 	bool settable;
816 	uint32* variable = find_debug_variable(variableName, settable);
817 	if (variable == NULL)
818 		return B_ENTRY_NOT_FOUND;
819 
820 	if (!settable)
821 		return B_NOT_ALLOWED;
822 
823 	*variable = (uint32)value;
824 	return B_OK;
825 }
826 
827 
828 status_t
829 arch_get_debug_variable(const char* variableName, uint64* value)
830 {
831 	bool settable;
832 	uint32* variable = find_debug_variable(variableName, settable);
833 	if (variable == NULL)
834 		return B_ENTRY_NOT_FOUND;
835 
836 	*value = *variable;
837 	return B_OK;
838 }
839 
840 
841 status_t
842 arch_debug_init(kernel_args *args)
843 {
844 	// at this stage, the debugger command system is alive
845 
846 	add_debugger_command("where", &stack_trace, "Same as \"sc\"");
847 	add_debugger_command("bt", &stack_trace, "Same as \"sc\" (as in gdb)");
848 	add_debugger_command("sc", &stack_trace,
849 		"Stack crawl for current thread (or any other)");
850 	add_debugger_command("iframe", &dump_iframes,
851 		"Dump iframes for the specified thread");
852 	add_debugger_command("call", &show_call, "Show call with arguments");
853 	add_debugger_command_etc("in_context", &cmd_in_context,
854 		"Executes a command in the context of a given thread",
855 		"<thread ID> <command> ...\n"
856 		"Executes a command in the context of a given thread.\n",
857 		B_KDEBUG_DONT_PARSE_ARGUMENTS);
858 
859 	return B_NO_ERROR;
860 }
861 
862