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