1/*
2 * Copyright 2003-2011, Haiku Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 * 		Axel D��rfler <axeld@pinc-software.de>
7 * 		Ingo Weinhold <bonefish@cs.tu-berlin.de>
8 * 		Fran��ois Revol <revol@free.fr>
9 *		Ithamar R. Adema <ithamar@upgrade-android.com>
10 *
11 */
12
13
14#include <arch/debug.h>
15
16#include <arch_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_types.h>
24#include <vm/VMAddressSpace.h>
25#include <vm/VMArea.h>
26
27#define NUM_PREVIOUS_LOCATIONS 32
28
29extern struct iframe_stack gBootFrameStack;
30
31
32static bool
33already_visited(addr_t *visited, int32 *_last, int32 *_num, addr_t fp)
34{
35	int32 last = *_last;
36	int32 num = *_num;
37	int32 i;
38
39	for (i = 0; i < num; i++) {
40		if (visited[(NUM_PREVIOUS_LOCATIONS + last - i)
41				% NUM_PREVIOUS_LOCATIONS] == fp) {
42			return true;
43		}
44	}
45
46	*_last = last = (last + 1) % NUM_PREVIOUS_LOCATIONS;
47	visited[last] = fp;
48
49	if (num < NUM_PREVIOUS_LOCATIONS)
50		*_num = num + 1;
51
52	return false;
53}
54
55
56static status_t
57get_next_frame(addr_t fp, addr_t *next, addr_t *ip)
58{
59	if (fp != 0) {
60		*ip   = *(((addr_t*)fp) - 0);
61		*next = *(((addr_t*)fp) - 1);
62
63		return B_OK;
64	}
65
66	return B_BAD_VALUE;
67}
68
69
70static status_t
71lookup_symbol(Thread* thread, addr_t address, addr_t* _baseAddress,
72	const char** _symbolName, const char** _imageName, bool* _exactMatch)
73{
74	status_t status = B_ENTRY_NOT_FOUND;
75
76	if (IS_KERNEL_ADDRESS(address)) {
77		// a kernel symbol
78		status = elf_debug_lookup_symbol_address(address, _baseAddress,
79			_symbolName, _imageName, _exactMatch);
80	} else if (thread != NULL && thread->team != NULL) {
81		// try a lookup using the userland runtime loader structures
82		status = elf_debug_lookup_user_symbol_address(thread->team, address,
83			_baseAddress, _symbolName, _imageName, _exactMatch);
84
85		if (status != B_OK) {
86			// try to locate the image in the images loaded into user space
87			status = image_debug_lookup_user_symbol_address(thread->team,
88				address, _baseAddress, _symbolName, _imageName, _exactMatch);
89		}
90	}
91
92	return status;
93}
94
95
96static void
97set_debug_argument_variable(int32 index, uint64 value)
98{
99	char name[8];
100	snprintf(name, sizeof(name), "_arg%" B_PRId32, index);
101	set_debug_variable(name, value);
102}
103
104
105template<typename Type>
106static Type
107read_function_argument_value(void* argument, bool& _valueKnown)
108{
109	Type value;
110	if (debug_memcpy(B_CURRENT_TEAM, &value, argument, sizeof(Type)) == B_OK) {
111		_valueKnown = true;
112		return value;
113	}
114
115	_valueKnown = false;
116	return 0;
117}
118
119
120static status_t
121print_demangled_call(const char* image, const char* symbol, addr_t args,
122	bool noObjectMethod, bool addDebugVariables)
123{
124	static const size_t kBufferSize = 256;
125	char* buffer = (char*)debug_malloc(kBufferSize);
126	if (buffer == NULL)
127		return B_NO_MEMORY;
128
129	bool isObjectMethod;
130	const char* name = debug_demangle_symbol(symbol, buffer, kBufferSize,
131		&isObjectMethod);
132	if (name == NULL) {
133		debug_free(buffer);
134		return B_ERROR;
135	}
136
137	uint32* arg = (uint32*)args;
138
139	if (noObjectMethod)
140		isObjectMethod = false;
141	if (isObjectMethod) {
142		const char* lastName = strrchr(name, ':') - 1;
143		int namespaceLength = lastName - name;
144
145		uint32 argValue = 0;
146		if (debug_memcpy(B_CURRENT_TEAM, &argValue, arg, 4) == B_OK) {
147			kprintf("<%s> %.*s<\33[32m%#" B_PRIx32 "\33[0m>%s", image,
148				namespaceLength, name, argValue, lastName);
149		} else
150			kprintf("<%s> %.*s<\?\?\?>%s", image, namespaceLength, name, lastName);
151
152		if (addDebugVariables)
153			set_debug_variable("_this", argValue);
154		arg++;
155	} else
156		kprintf("<%s> %s", image, name);
157
158	kprintf("(");
159
160	size_t length;
161	int32 type, i = 0;
162	uint32 cookie = 0;
163	while (debug_get_next_demangled_argument(&cookie, symbol, buffer,
164			kBufferSize, &type, &length) == B_OK) {
165		if (i++ > 0)
166			kprintf(", ");
167
168		// retrieve value and type identifier
169
170		uint64 value;
171		bool valueKnown = false;
172
173		switch (type) {
174			case B_INT64_TYPE:
175				value = read_function_argument_value<int64>(arg, valueKnown);
176				if (valueKnown)
177					kprintf("int64: \33[34m%lld\33[0m", value);
178				break;
179			case B_INT32_TYPE:
180				value = read_function_argument_value<int32>(arg, valueKnown);
181				if (valueKnown)
182					kprintf("int32: \33[34m%" B_PRId32 "\33[0m", (int32)value);
183				break;
184			case B_INT16_TYPE:
185				value = read_function_argument_value<int16>(arg, valueKnown);
186				if (valueKnown)
187					kprintf("int16: \33[34m%d\33[0m", (int16)value);
188				break;
189			case B_INT8_TYPE:
190				value = read_function_argument_value<int8>(arg, valueKnown);
191				if (valueKnown)
192					kprintf("int8: \33[34m%d\33[0m", (int8)value);
193				break;
194			case B_UINT64_TYPE:
195				value = read_function_argument_value<uint64>(arg, valueKnown);
196				if (valueKnown) {
197					kprintf("uint64: \33[34m%#Lx\33[0m", value);
198					if (value < 0x100000)
199						kprintf(" (\33[34m%Lu\33[0m)", value);
200				}
201				break;
202			case B_UINT32_TYPE:
203				value = read_function_argument_value<uint32>(arg, valueKnown);
204				if (valueKnown) {
205					kprintf("uint32: \33[34m%#" B_PRIx32 "\33[0m", (uint32)value);
206					if (value < 0x100000)
207						kprintf(" (\33[34m%" B_PRIu32 "\33[0m)", (uint32)value);
208				}
209				break;
210			case B_UINT16_TYPE:
211				value = read_function_argument_value<uint16>(arg, valueKnown);
212				if (valueKnown) {
213					kprintf("uint16: \33[34m%#x\33[0m (\33[34m%u\33[0m)",
214						(uint16)value, (uint16)value);
215				}
216				break;
217			case B_UINT8_TYPE:
218				value = read_function_argument_value<uint8>(arg, valueKnown);
219				if (valueKnown) {
220					kprintf("uint8: \33[34m%#x\33[0m (\33[34m%u\33[0m)",
221						(uint8)value, (uint8)value);
222				}
223				break;
224			case B_BOOL_TYPE:
225				value = read_function_argument_value<uint8>(arg, valueKnown);
226				if (valueKnown)
227					kprintf("\33[34m%s\33[0m", value ? "true" : "false");
228				break;
229			default:
230				if (buffer[0])
231					kprintf("%s: ", buffer);
232
233				if (length == 4) {
234					value = read_function_argument_value<uint32>(arg,
235						valueKnown);
236					if (valueKnown) {
237						if (value == 0
238							&& (type == B_POINTER_TYPE || type == B_REF_TYPE))
239							kprintf("NULL");
240						else
241							kprintf("\33[34m%#" B_PRIx32 "\33[0m", (uint32)value);
242					}
243					break;
244				}
245
246
247				if (length == 8) {
248					value = read_function_argument_value<uint64>(arg,
249						valueKnown);
250				} else
251					value = (uint64)arg;
252
253				if (valueKnown)
254					kprintf("\33[34m%#Lx\33[0m", value);
255				break;
256		}
257
258		if (!valueKnown)
259			kprintf("???");
260
261		if (valueKnown && type == B_STRING_TYPE) {
262			if (value == 0)
263				kprintf(" \33[31m\"<NULL>\"\33[0m");
264			else if (debug_strlcpy(B_CURRENT_TEAM, buffer, (char*)(addr_t)value,
265					kBufferSize) < B_OK) {
266				kprintf(" \33[31m\"<\?\?\?>\"\33[0m");
267			} else
268				kprintf(" \33[36m\"%s\"\33[0m", buffer);
269		}
270
271		if (addDebugVariables)
272			set_debug_argument_variable(i, value);
273		arg = (uint32*)((uint8*)arg + length);
274	}
275
276	debug_free(buffer);
277
278	kprintf(")");
279	return B_OK;
280}
281
282
283
284static void
285print_stack_frame(Thread *thread, addr_t ip, addr_t fp, addr_t next,
286	int32 callIndex, bool demangle)
287{
288	const char* symbol;
289	const char* image;
290	addr_t baseAddress;
291	bool exactMatch;
292	status_t status;
293	addr_t diff;
294
295	diff = next - fp;
296
297	// MSB set = kernel space/user space switch
298	if (diff & ~((addr_t)-1 >> 1))
299		diff = 0;
300
301	status = lookup_symbol(thread, ip, &baseAddress, &symbol, &image,
302		&exactMatch);
303
304	kprintf("%2" B_PRId32 " %0*lx (+%4ld) %0*lx   ", callIndex,
305		B_PRINTF_POINTER_WIDTH, fp, diff, B_PRINTF_POINTER_WIDTH, ip);
306
307	if (status == B_OK) {
308		if (exactMatch && demangle) {
309			status = print_demangled_call(image, symbol,
310				next, false, false);
311		}
312
313		if (!exactMatch || !demangle || status != B_OK) {
314			if (symbol != NULL) {
315				kprintf("<%s> %s%s", image, symbol,
316					exactMatch ? "" : " (nearest)");
317			} else
318				kprintf("<%s@%p> <unknown>", image, (void*)baseAddress);
319		}
320
321		kprintf(" + %#04lx\n", ip - baseAddress);
322	} else {
323		VMArea *area = NULL;
324		if (thread != NULL && thread->team != NULL
325			&& thread->team->address_space != NULL) {
326			area = thread->team->address_space->LookupArea(ip);
327		}
328		if (area != NULL) {
329			kprintf("%" B_PRId32 ":%s@%p + %#lx\n", area->id, area->name,
330				(void*)area->Base(), ip - area->Base());
331		} else
332			kprintf("\n");
333	}
334}
335
336static int
337stack_trace(int argc, char **argv)
338{
339	static const char* usage = "usage: %s [-d] [ <thread id> ]\n"
340		"Prints a stack trace for the current, respectively the specified\n"
341		"thread.\n"
342		"  -d           -  Disables the demangling of the symbols.\n"
343		"  <thread id>  -  The ID of the thread for which to print the stack\n"
344		"                  trace.\n";
345	bool demangle = true;
346	int32 threadIndex = 1;
347	if (argc > 1 && !strcmp(argv[1], "-d")) {
348		demangle = false;
349		threadIndex++;
350	}
351
352	if (argc > threadIndex + 1
353		|| (argc == 2 && strcmp(argv[1], "--help") == 0)) {
354		kprintf(usage, argv[0]);
355		return 0;
356	}
357
358	addr_t previousLocations[NUM_PREVIOUS_LOCATIONS];
359	Thread* thread = thread_get_current_thread();
360	phys_addr_t oldPageDirectory = 0;
361	addr_t fp = arm_get_fp();
362	int32 num = 0, last = 0;
363	struct iframe_stack *frameStack;
364
365	// We don't have a thread pointer early in the boot process
366	if (thread != NULL)
367		frameStack = &thread->arch_info.iframes;
368	else
369		frameStack = &gBootFrameStack;
370
371	int32 i;
372	for (i = 0; i < frameStack->index; i++) {
373		kprintf("iframe %p (end = %p)\n",
374			frameStack->frames[i], frameStack->frames[i] + 1);
375	}
376
377	if (thread != NULL) {
378		kprintf("stack trace for thread 0x%" B_PRIx32 " \"%s\"\n", thread->id,
379			thread->name);
380
381		kprintf("    kernel stack: %p to %p\n",
382			(void *)thread->kernel_stack_base,
383			(void *)(thread->kernel_stack_top));
384		if (thread->user_stack_base != 0) {
385			kprintf("      user stack: %p to %p\n",
386				(void *)thread->user_stack_base,
387				(void *)(thread->user_stack_base + thread->user_stack_size));
388		}
389	}
390
391	kprintf("frame            caller     <image>:function + offset\n");
392
393	for (int32 callIndex = 0;; callIndex++) {
394		// see if the frame pointer matches the iframe
395		struct iframe *frame = NULL;
396		for (i = 0; i < frameStack->index; i++) {
397			if (fp == (addr_t)frameStack->frames[i]) {
398				// it's an iframe
399				frame = frameStack->frames[i];
400				break;
401			}
402		}
403
404		if (frame) {
405			kprintf("iframe at %p\n", frame);
406			kprintf("   R00 0x%08x    R01 0x%08x    R02 0x%08x    R03 0x%08x\n",
407				frame->r0, frame->r1, frame->r2, frame->r3);
408			kprintf("   R04 0x%08x    R05 0x%08x    R06 0x%08x    R07 0x%08x\n",
409				frame->r4, frame->r5, frame->r6, frame->r7);
410			kprintf("   R08 0x%08x    R09 0x%08x    R10 0x%08x    R11 0x%08x\n",
411				frame->r8, frame->r9, frame->r10, frame->r11);
412			kprintf("   R12 0x%08x    SPs 0x%08x    LRs 0x%08x    PC  0x%08x\n",
413				frame->r12, frame->svc_sp, frame->svc_lr, frame->pc);
414			kprintf("                     SPu 0x%08x    LRu 0x%08x   SPSR 0x%08x\n",
415				frame->usr_sp, frame->usr_lr, frame->spsr);
416
417			print_stack_frame(thread, frame->pc, fp, frame->r11, callIndex, demangle);
418			fp = frame->r11;
419		} else {
420			addr_t ip, next;
421
422			if (get_next_frame(fp, &next, &ip) != B_OK) {
423				kprintf("%08lx -- read fault\n", fp);
424				break;
425			}
426
427			if (ip == 0 || fp == 0)
428				break;
429
430			print_stack_frame(thread, ip, fp, next, callIndex, demangle);
431			fp = next;
432		}
433
434		if (already_visited(previousLocations, &last, &num, fp)) {
435			kprintf("circular stack frame: %p!\n", (void *)fp);
436			break;
437		}
438		if (fp == 0)
439			break;
440	}
441
442	return 0;
443}
444
445
446// #pragma mark -
447
448
449void
450arch_debug_save_registers(struct arch_debug_registers* registers)
451{
452}
453
454
455bool
456arch_debug_contains_call(Thread *thread, const char *symbol,
457	addr_t start, addr_t end)
458{
459	return false;
460}
461
462
463void
464arch_debug_stack_trace(void)
465{
466	stack_trace(0, NULL);
467}
468
469
470int32
471arch_debug_get_stack_trace(addr_t* returnAddresses, int32 maxCount,
472	int32 skipIframes, int32 skipFrames, uint32 flags)
473{
474	// TODO: Implement!
475	return 0;
476}
477
478
479void*
480arch_debug_get_interrupt_pc(bool* _isSyscall)
481{
482	// TODO: Implement!
483	return NULL;
484}
485
486
487bool
488arch_is_debug_variable_defined(const char* variableName)
489{
490	// TODO: Implement!
491	return false;
492}
493
494
495status_t
496arch_set_debug_variable(const char* variableName, uint64 value)
497{
498	// TODO: Implement!
499	return B_ENTRY_NOT_FOUND;
500}
501
502
503status_t
504arch_get_debug_variable(const char* variableName, uint64* value)
505{
506	// TODO: Implement!
507	return B_ENTRY_NOT_FOUND;
508}
509
510
511status_t
512arch_debug_init(kernel_args *args)
513{
514	add_debugger_command("where", &stack_trace, "Same as \"sc\"");
515	add_debugger_command("bt", &stack_trace, "Same as \"sc\" (as in gdb)");
516	add_debugger_command("sc", &stack_trace, "Stack crawl for current thread");
517
518	return B_NO_ERROR;
519}
520
521
522/* arch_debug_call_with_fault_handler is in arch_asm.S */
523
524void
525arch_debug_unset_current_thread(void)
526{
527	// TODO: Implement!
528}
529
530
531ssize_t
532arch_debug_gdb_get_registers(char* buffer, size_t bufferSize)
533{
534	// TODO: Implement!
535	return B_NOT_SUPPORTED;
536}
537