xref: /haiku/src/system/kernel/arch/x86/arch_debug.cpp (revision 23eafdaf313f2e756170f6a543205311a4d9bc96)
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 (user_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 void
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;
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 }
372 
373 
374 static bool
375 is_double_fault_stack_address(int32 cpu, addr_t address)
376 {
377 	size_t size;
378 	addr_t bottom = (addr_t)x86_get_double_fault_stack(cpu, &size);
379 	return address >= bottom && address < bottom + size;
380 }
381 
382 
383 static bool
384 is_kernel_stack_address(struct thread* thread, addr_t address)
385 {
386 	// We don't have a thread pointer in the early boot process, but then we are
387 	// on the kernel stack for sure.
388 	if (thread == NULL)
389 		return IS_KERNEL_ADDRESS(address);
390 
391 	return (address >= thread->kernel_stack_base
392 			&& address < thread->kernel_stack_top)
393 		|| (thread->cpu != NULL
394 			&& is_double_fault_stack_address(thread->cpu->cpu_num, address));
395 }
396 
397 
398 static bool
399 is_iframe(struct thread* thread, addr_t frame)
400 {
401 	if (!is_kernel_stack_address(thread, frame))
402 		return false;
403 
404 	addr_t previousFrame = *(addr_t*)frame;
405 	return ((previousFrame & ~IFRAME_TYPE_MASK) == 0 && previousFrame != 0);
406 }
407 
408 
409 static struct iframe *
410 find_previous_iframe(struct thread *thread, addr_t frame)
411 {
412 	// iterate backwards through the stack frames, until we hit an iframe
413 	while (is_kernel_stack_address(thread, frame)) {
414 		if (is_iframe(thread, frame))
415 			return (struct iframe*)frame;
416 
417 		frame = *(addr_t*)frame;
418 	}
419 
420 	return NULL;
421 }
422 
423 
424 static struct iframe*
425 get_previous_iframe(struct thread* thread, struct iframe* frame)
426 {
427 	if (frame == NULL)
428 		return NULL;
429 
430 	return find_previous_iframe(thread, frame->ebp);
431 }
432 
433 
434 static struct iframe*
435 get_current_iframe(struct thread* thread)
436 {
437 	if (thread == thread_get_current_thread())
438 		return i386_get_current_iframe();
439 
440 	addr_t ebp = thread->arch_info.current_stack.esp[2];
441 		// NOTE: This doesn't work, if the thread is running (on another CPU).
442 	return find_previous_iframe(thread, ebp);
443 }
444 
445 
446 uint32*
447 find_debug_variable(const char* variableName, bool& settable)
448 {
449 	struct iframe* frame = get_current_iframe(debug_get_debugged_thread());
450 	if (frame == NULL)
451 		return NULL;
452 
453 	settable = false;
454 
455 	if (strcmp(variableName, "gs") == 0) {
456 		return &frame->gs;
457 	} else if (strcmp(variableName, "fs") == 0) {
458 		return &frame->fs;
459 	} else if (strcmp(variableName, "es") == 0) {
460 		return &frame->es;
461 	} else if (strcmp(variableName, "ds") == 0) {
462 		return &frame->ds;
463 	} else if (strcmp(variableName, "cs") == 0) {
464 		return &frame->cs;
465 	} else if (strcmp(variableName, "edi") == 0) {
466 		settable = true;
467 		return &frame->edi;
468 	} else if (strcmp(variableName, "esi") == 0) {
469 		settable = true;
470 		return &frame->esi;
471 	} else if (strcmp(variableName, "ebp") == 0) {
472 		settable = true;
473 		return &frame->ebp;
474 	} else if (strcmp(variableName, "esp") == 0) {
475 		settable = true;
476 		return &frame->esp;
477 	} else if (strcmp(variableName, "ebx") == 0) {
478 		settable = true;
479 		return &frame->ebx;
480 	} else if (strcmp(variableName, "edx") == 0) {
481 		settable = true;
482 		return &frame->edx;
483 	} else if (strcmp(variableName, "ecx") == 0) {
484 		settable = true;
485 		return &frame->ecx;
486 	} else if (strcmp(variableName, "eax") == 0) {
487 		settable = true;
488 		return &frame->eax;
489 	} else if (strcmp(variableName, "orig_eax") == 0) {
490 		settable = true;
491 		return &frame->orig_eax;
492 	} else if (strcmp(variableName, "orig_edx") == 0) {
493 		settable = true;
494 		return &frame->orig_edx;
495 	} else if (strcmp(variableName, "eip") == 0) {
496 		settable = true;
497 		return &frame->eip;
498 	} else if (strcmp(variableName, "eflags") == 0) {
499 		settable = true;
500 		return &frame->flags;
501 	}
502 
503 	if (IFRAME_IS_USER(frame)) {
504 		if (strcmp(variableName, "user_esp") == 0) {
505 			settable = true;
506 			return &frame->user_esp;
507 		} else if (strcmp(variableName, "user_ss") == 0) {
508 			return &frame->user_ss;
509 		}
510 	}
511 
512 	return NULL;
513 }
514 
515 
516 static int
517 stack_trace(int argc, char **argv)
518 {
519 	static const char* usage = "usage: %s [-d] [ <thread id> ]\n"
520 		"Prints a stack trace for the current, respectively the specified\n"
521 		"thread.\n"
522 		"  -d           -  Disables the demangling of the symbols.\n"
523 		"  <thread id>  -  The ID of the thread for which to print the stack\n"
524 		"                  trace.\n";
525 	bool demangle = true;
526 	int32 threadIndex = 1;
527 	if (argc > 1 && !strcmp(argv[1], "-d")) {
528 		demangle = false;
529 		threadIndex++;
530 	}
531 
532 	if (argc > threadIndex + 1
533 		|| (argc == 2 && strcmp(argv[1], "--help") == 0)) {
534 		kprintf(usage, argv[0]);
535 		return 0;
536 	}
537 
538 	uint32 previousLocations[NUM_PREVIOUS_LOCATIONS];
539 	struct thread *thread = NULL;
540 	addr_t oldPageDirectory = 0;
541 	uint32 ebp = x86_read_ebp();
542 	int32 num = 0, last = 0;
543 
544 	setup_for_thread(argc == threadIndex + 1 ? argv[threadIndex] : NULL,
545 		&thread, &ebp, &oldPageDirectory);
546 
547 	if (thread != NULL) {
548 		kprintf("stack trace for thread %ld \"%s\"\n", thread->id,
549 			thread->name);
550 
551 		kprintf("    kernel stack: %p to %p\n",
552 			(void *)thread->kernel_stack_base,
553 			(void *)(thread->kernel_stack_top));
554 		if (thread->user_stack_base != 0) {
555 			kprintf("      user stack: %p to %p\n",
556 				(void *)thread->user_stack_base,
557 				(void *)(thread->user_stack_base + thread->user_stack_size));
558 		}
559 	}
560 
561 	kprintf("frame               caller     <image>:function + offset\n");
562 
563 	bool onKernelStack = true;
564 
565 	for (int32 callIndex = 0;; callIndex++) {
566 		onKernelStack = onKernelStack
567 			&& is_kernel_stack_address(thread, ebp);
568 
569 		if (onKernelStack && is_iframe(thread, ebp)) {
570 			struct iframe *frame = (struct iframe *)ebp;
571 
572 			print_iframe(frame);
573 			print_stack_frame(thread, frame->eip, ebp, frame->ebp, callIndex,
574 				demangle);
575 
576  			ebp = frame->ebp;
577 		} else {
578 			addr_t eip, nextEbp;
579 
580 			if (get_next_frame_debugger(ebp, &nextEbp, &eip) != B_OK) {
581 				kprintf("%08lx -- read fault\n", ebp);
582 				break;
583 			}
584 
585 			if (eip == 0 || ebp == 0)
586 				break;
587 
588 			print_stack_frame(thread, eip, ebp, nextEbp, callIndex, demangle);
589 			ebp = nextEbp;
590 		}
591 
592 		if (already_visited(previousLocations, &last, &num, ebp)) {
593 			kprintf("circular stack frame: %p!\n", (void *)ebp);
594 			break;
595 		}
596 		if (ebp == 0)
597 			break;
598 	}
599 
600 	if (oldPageDirectory != 0) {
601 		// switch back to the previous page directory to no cause any troubles
602 		write_cr3(oldPageDirectory);
603 	}
604 
605 	return 0;
606 }
607 
608 
609 static void
610 print_call(struct thread *thread, addr_t eip, addr_t ebp, addr_t nextEbp,
611 	int32 argCount)
612 {
613 	const char *symbol, *image;
614 	addr_t baseAddress;
615 	bool exactMatch;
616 	status_t status;
617 	bool demangled = false;
618 	int32 *arg = (int32 *)(nextEbp + 8);
619 
620 	status = lookup_symbol(thread, eip, &baseAddress, &symbol, &image,
621 		&exactMatch);
622 
623 	kprintf("%08lx %08lx   ", ebp, eip);
624 
625 	if (status == B_OK) {
626 		if (symbol != NULL) {
627 			if (exactMatch && (argCount == 0 || argCount == -1)) {
628 				status = print_demangled_call(image, symbol, (addr_t)arg,
629 					argCount == -1, true);
630 				if (status == B_OK)
631 					demangled = true;
632 			}
633 			if (!demangled) {
634 				kprintf("<%s>:%s%s", image, symbol,
635 					exactMatch ? "" : " (nearest)");
636 			}
637 		} else {
638 			kprintf("<%s@%p>:unknown + 0x%04lx", image,
639 				(void *)baseAddress, eip - baseAddress);
640 		}
641 	} else {
642 		vm_area *area = NULL;
643 		if (thread->team->address_space != NULL)
644 			area = vm_area_lookup(thread->team->address_space, eip);
645 		if (area != NULL) {
646 			kprintf("%ld:%s@%p + %#lx", area->id, area->name,
647 				(void *)area->base, eip - area->base);
648 		}
649 	}
650 
651 	if (!demangled) {
652 		kprintf("(");
653 
654 		for (int32 i = 0; i < argCount; i++) {
655 			if (i > 0)
656 				kprintf(", ");
657 			kprintf("%#lx", *arg);
658 			if (*arg > -0x10000 && *arg < 0x10000)
659 				kprintf(" (%ld)", *arg);
660 
661 			set_debug_argument_variable(i + 1, *(uint32 *)arg);
662 			arg++;
663 		}
664 
665 		kprintf(")\n");
666 	} else
667 		kprintf("\n");
668 
669 	set_debug_variable("_frame", nextEbp);
670 }
671 
672 
673 static int
674 show_call(int argc, char **argv)
675 {
676 	static const char* usage
677 		= "usage: %s [ <thread id> ] <call index> [ -<arg count> ]\n"
678 		"Prints a function call with parameters of the current, respectively\n"
679 		"the specified thread.\n"
680 		"  <thread id>   -  The ID of the thread for which to print the call.\n"
681 		"  <call index>  -  The index of the call in the stack trace.\n"
682 		"  <arg count>   -  The number of call arguments to print (use 'c' to\n"
683 		"                   force the C++ demangler to use class methods,\n"
684 		"                   use 'd' to disable demangling).\n";
685 	if (argc == 2 && strcmp(argv[1], "--help") == 0) {
686 		kprintf(usage, argv[0]);
687 		return 0;
688 	}
689 
690 	struct thread *thread = NULL;
691 	addr_t oldPageDirectory = 0;
692 	addr_t ebp = x86_read_ebp();
693 	int32 argCount = 0;
694 
695 	if (argc >= 2 && argv[argc - 1][0] == '-') {
696 		if (argv[argc - 1][1] == 'c')
697 			argCount = -1;
698 		else if (argv[argc - 1][1] == 'd')
699 			argCount = -2;
700 		else
701 			argCount = strtoul(argv[argc - 1] + 1, NULL, 0);
702 
703 		if (argCount < -2 || argCount > 16) {
704 			kprintf("Invalid argument count \"%ld\".\n", argCount);
705 			return 0;
706 		}
707 		argc--;
708 	}
709 
710 	if (argc < 2 || argc > 3) {
711 		kprintf(usage, argv[0]);
712 		return 0;
713 	}
714 
715 	setup_for_thread(argc == 3 ? argv[1] : NULL, &thread, &ebp,
716 		&oldPageDirectory);
717 
718 	int32 callIndex = strtoul(argv[argc == 3 ? 2 : 1], NULL, 0);
719 
720 	if (thread != NULL)
721 		kprintf("thread %ld, %s\n", thread->id, thread->name);
722 
723 	bool onKernelStack = true;
724 
725 	for (int32 index = 0; index <= callIndex; index++) {
726 		onKernelStack = onKernelStack
727 			&& is_kernel_stack_address(thread, ebp);
728 
729 		if (onKernelStack && is_iframe(thread, ebp)) {
730 			struct iframe *frame = (struct iframe *)ebp;
731 
732 			if (index == callIndex)
733 				print_call(thread, frame->eip, ebp, frame->ebp, argCount);
734 
735  			ebp = frame->ebp;
736 		} else {
737 			addr_t eip, nextEbp;
738 
739 			if (get_next_frame_debugger(ebp, &nextEbp, &eip) != B_OK) {
740 				kprintf("%08lx -- read fault\n", ebp);
741 				break;
742 			}
743 
744 			if (eip == 0 || ebp == 0)
745 				break;
746 
747 			if (index == callIndex)
748 				print_call(thread, eip, ebp, nextEbp, argCount);
749 
750 			ebp = nextEbp;
751 		}
752 
753 		if (ebp == 0)
754 			break;
755 	}
756 
757 	if (oldPageDirectory != 0) {
758 		// switch back to the previous page directory to not cause any troubles
759 		write_cr3(oldPageDirectory);
760 	}
761 
762 	return 0;
763 }
764 
765 
766 static int
767 dump_iframes(int argc, char **argv)
768 {
769 	static const char* usage = "usage: %s [ <thread id> ]\n"
770 		"Prints the iframe stack for the current, respectively the specified\n"
771 		"thread.\n"
772 		"  <thread id>  -  The ID of the thread for which to print the iframe\n"
773 		"                  stack.\n";
774 	if (argc == 2 && strcmp(argv[1], "--help") == 0) {
775 		kprintf(usage, argv[0]);
776 		return 0;
777 	}
778 
779 	struct thread *thread = NULL;
780 
781 	if (argc < 2) {
782 		thread = thread_get_current_thread();
783 	} else if (argc == 2) {
784 		thread_id id = strtoul(argv[1], NULL, 0);
785 		thread = thread_get_thread_struct_locked(id);
786 		if (thread == NULL) {
787 			kprintf("could not find thread %ld\n", id);
788 			return 0;
789 		}
790 	} else if (argc > 2) {
791 		kprintf(usage, argv[0]);
792 		return 0;
793 	}
794 
795 	if (thread != NULL)
796 		kprintf("iframes for thread %ld \"%s\"\n", thread->id, thread->name);
797 
798 	struct iframe* frame = find_previous_iframe(thread, x86_read_ebp());
799 	while (frame != NULL) {
800 		print_iframe(frame);
801 		frame = get_previous_iframe(thread, frame);
802 	}
803 
804 	return 0;
805 }
806 
807 
808 static bool
809 is_calling(struct thread *thread, addr_t eip, const char *pattern,
810 	addr_t start, addr_t end)
811 {
812 	if (pattern == NULL)
813 		return eip >= start && eip < end;
814 
815 	const char *symbol;
816 	if (lookup_symbol(thread, eip, NULL, &symbol, NULL, NULL) != B_OK)
817 		return false;
818 
819 	return strstr(symbol, pattern);
820 }
821 
822 
823 static int
824 cmd_in_context(int argc, char** argv)
825 {
826 	if (argc != 2) {
827 		print_debugger_command_usage(argv[0]);
828 		return 0;
829 	}
830 
831 	// get the thread ID
832 	const char* commandLine = argv[1];
833 	char threadIDString[16];
834 	if (parse_next_debug_command_argument(&commandLine, threadIDString,
835 			sizeof(threadIDString)) != B_OK) {
836 		kprintf("Failed to parse thread ID.\n");
837 		return 0;
838 	}
839 
840 	if (commandLine == NULL) {
841 		print_debugger_command_usage(argv[0]);
842 		return 0;
843 	}
844 
845 	uint64 threadID;
846 	if (!evaluate_debug_expression(threadIDString, &threadID, false))
847 		return 0;
848 
849 	// get the thread
850 	struct thread* thread = thread_get_thread_struct_locked(threadID);
851 	if (thread == NULL) {
852 		kprintf("Could not find thread with ID \"%s\".\n", threadIDString);
853 		return 0;
854 	}
855 
856 	// switch the page directory, if necessary
857 	addr_t oldPageDirectory = 0;
858 	if (thread != thread_get_current_thread()) {
859 		addr_t newPageDirectory = (addr_t)x86_next_page_directory(
860 			thread_get_current_thread(), thread);
861 
862 		if (newPageDirectory != 0) {
863 			read_cr3(oldPageDirectory);
864 			write_cr3(newPageDirectory);
865 		}
866 	}
867 
868 	struct thread* previousThread = debug_set_debugged_thread(thread);
869 
870 	// execute the command
871 	evaluate_debug_command(commandLine);
872 
873 	debug_set_debugged_thread(previousThread);
874 
875 	// reset the page directory
876 	if (oldPageDirectory)
877 		write_cr3(oldPageDirectory);
878 
879 	return 0;
880 }
881 
882 
883 //	#pragma mark -
884 
885 
886 bool
887 arch_debug_contains_call(struct thread *thread, const char *symbol,
888 	addr_t start, addr_t end)
889 {
890 	addr_t ebp;
891 	if (thread == thread_get_current_thread())
892 		ebp = x86_read_ebp();
893 	else
894 		ebp = thread->arch_info.current_stack.esp[2];
895 
896 	for (;;) {
897 		if (!is_kernel_stack_address(thread, ebp))
898 			break;
899 
900 		if (is_iframe(thread, ebp)) {
901 			struct iframe *frame = (struct iframe *)ebp;
902 
903 			if (is_calling(thread, frame->eip, symbol, start, end))
904 				return true;
905 
906  			ebp = frame->ebp;
907 		} else {
908 			addr_t eip, nextEbp;
909 
910 			if (get_next_frame_no_debugger(ebp, &nextEbp, &eip) != B_OK
911 				|| eip == 0 || ebp == 0)
912 				break;
913 
914 			if (is_calling(thread, eip, symbol, start, end))
915 				return true;
916 
917 			ebp = nextEbp;
918 		}
919 
920 		if (ebp == 0)
921 			break;
922 	}
923 
924 	return false;
925 }
926 
927 
928 void *
929 arch_debug_get_caller(void)
930 {
931 	struct stack_frame *frame = (struct stack_frame *)x86_read_ebp();
932 	return (void *)frame->previous->return_address;
933 }
934 
935 
936 /*!	Captures a stack trace (the return addresses) of the current thread.
937 	\param returnAddresses The array the return address shall be written to.
938 	\param maxCount The maximum number of return addresses to be captured.
939 	\param skipIframes The number of interrupt frames that shall be skipped. If
940 		greater than 0, \a skipFrames is ignored.
941 	\param skipFrames The number of stack frames that shall be skipped.
942 	\param userOnly If \c true, only userland return addresses are captured.
943 	\return The number of return addresses written to the given array.
944 */
945 int32
946 arch_debug_get_stack_trace(addr_t* returnAddresses, int32 maxCount,
947 	int32 skipIframes, int32 skipFrames, bool userOnly)
948 {
949 	// Keep skipping normal stack frames until we've skipped the iframes we're
950 	// supposed to skip.
951 	if (skipIframes > 0) {
952 		skipFrames = INT_MAX;
953 	} else {
954 		// always skip our own frame
955 		skipFrames++;
956 	}
957 
958 	struct thread* thread = thread_get_current_thread();
959 	int32 count = 0;
960 	addr_t ebp = x86_read_ebp();
961 	bool onKernelStack = true;
962 
963 	while (ebp != 0 && count < maxCount) {
964 		onKernelStack = onKernelStack
965 			&& is_kernel_stack_address(thread, ebp);
966 
967 		addr_t eip;
968 		addr_t nextEbp;
969 
970 		if (onKernelStack && is_iframe(thread, ebp)) {
971 			struct iframe *frame = (struct iframe*)ebp;
972 			eip = frame->eip;
973  			nextEbp = frame->ebp;
974 
975 			if (skipIframes > 0) {
976 				if (--skipIframes == 0)
977 					skipFrames = 0;
978 			}
979 		} else {
980 			if (get_next_frame_no_debugger(ebp, &nextEbp, &eip) != B_OK)
981 				break;
982 		}
983 
984 		if (skipFrames <= 0 && (!userOnly || IS_USER_ADDRESS(ebp)))
985 			returnAddresses[count++] = eip;
986 		else
987 			skipFrames--;
988 
989 		ebp = nextEbp;
990 	}
991 
992 	return count;
993 }
994 
995 
996 /*!	Returns the program counter of the currently debugged (respectively this)
997 	thread where the innermost interrupts happened. \a _isSyscall, if specified,
998 	is set to whether this interrupt frame was created by a syscall. Returns
999 	\c NULL, if there's no such frame or a problem occurred retrieving it;
1000 	\a _isSyscall won't be set in this case.
1001 */
1002 void*
1003 arch_debug_get_interrupt_pc(bool* _isSyscall)
1004 {
1005 	struct iframe* frame = get_current_iframe(debug_get_debugged_thread());
1006 	if (frame == NULL)
1007 		return NULL;
1008 
1009 	if (_isSyscall != NULL)
1010 		*_isSyscall = frame->vector == 99;
1011 
1012 	return (void*)(addr_t)frame->eip;
1013 }
1014 
1015 
1016 /*!	Sets the current thread to \c NULL.
1017 	Invoked in the kernel debugger only.
1018 */
1019 void
1020 arch_debug_unset_current_thread(void)
1021 {
1022 	write_dr3(NULL);
1023 }
1024 
1025 
1026 bool
1027 arch_is_debug_variable_defined(const char* variableName)
1028 {
1029 	bool settable;
1030 	return find_debug_variable(variableName, settable);
1031 }
1032 
1033 
1034 status_t
1035 arch_set_debug_variable(const char* variableName, uint64 value)
1036 {
1037 	bool settable;
1038 	uint32* variable = find_debug_variable(variableName, settable);
1039 	if (variable == NULL)
1040 		return B_ENTRY_NOT_FOUND;
1041 
1042 	if (!settable)
1043 		return B_NOT_ALLOWED;
1044 
1045 	*variable = (uint32)value;
1046 	return B_OK;
1047 }
1048 
1049 
1050 status_t
1051 arch_get_debug_variable(const char* variableName, uint64* value)
1052 {
1053 	bool settable;
1054 	uint32* variable = find_debug_variable(variableName, settable);
1055 	if (variable == NULL)
1056 		return B_ENTRY_NOT_FOUND;
1057 
1058 	*value = *variable;
1059 	return B_OK;
1060 }
1061 
1062 
1063 status_t
1064 arch_debug_init(kernel_args *args)
1065 {
1066 	// at this stage, the debugger command system is alive
1067 
1068 	add_debugger_command("where", &stack_trace, "Same as \"sc\"");
1069 	add_debugger_command("bt", &stack_trace, "Same as \"sc\" (as in gdb)");
1070 	add_debugger_command("sc", &stack_trace,
1071 		"Stack crawl for current thread (or any other)");
1072 	add_debugger_command("iframe", &dump_iframes,
1073 		"Dump iframes for the specified thread");
1074 	add_debugger_command("call", &show_call, "Show call with arguments");
1075 	add_debugger_command_etc("in_context", &cmd_in_context,
1076 		"Executes a command in the context of a given thread",
1077 		"<thread ID> <command> ...\n"
1078 		"Executes a command in the context of a given thread.\n",
1079 		B_KDEBUG_DONT_PARSE_ARGUMENTS);
1080 
1081 	return B_NO_ERROR;
1082 }
1083 
1084