xref: /haiku/src/system/kernel/arch/arm/arch_debug.cpp (revision caed67a8cba83913b9c21ac2b06ebc6bd1cb3111)
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 
29 extern struct iframe_stack gBootFrameStack;
30 
31 
32 static bool
33 already_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 
56 static status_t
57 get_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 
70 static status_t
71 lookup_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 
96 static void
97 set_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 
105 template<typename Type>
106 static Type
107 read_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 
120 static status_t
121 print_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 
284 static void
285 print_stack_frame(Thread* thread, addr_t ip, addr_t calleeFp, addr_t fp,
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 = fp - calleeFp;
296 
297 	// kernel space/user space switch
298 	if (calleeFp > fp)
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 				fp, 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 
336 static int
337 stack_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 
449 void
450 arch_debug_save_registers(struct arch_debug_registers* registers)
451 {
452 }
453 
454 
455 bool
456 arch_debug_contains_call(Thread *thread, const char *symbol,
457 	addr_t start, addr_t end)
458 {
459 	return false;
460 }
461 
462 
463 void
464 arch_debug_stack_trace(void)
465 {
466 	stack_trace(0, NULL);
467 }
468 
469 
470 int32
471 arch_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 
479 void*
480 arch_debug_get_interrupt_pc(bool* _isSyscall)
481 {
482 	// TODO: Implement!
483 	return NULL;
484 }
485 
486 
487 bool
488 arch_is_debug_variable_defined(const char* variableName)
489 {
490 	// TODO: Implement!
491 	return false;
492 }
493 
494 
495 status_t
496 arch_set_debug_variable(const char* variableName, uint64 value)
497 {
498 	// TODO: Implement!
499 	return B_ENTRY_NOT_FOUND;
500 }
501 
502 
503 status_t
504 arch_get_debug_variable(const char* variableName, uint64* value)
505 {
506 	// TODO: Implement!
507 	return B_ENTRY_NOT_FOUND;
508 }
509 
510 
511 status_t
512 arch_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 
524 void
525 arch_debug_unset_current_thread(void)
526 {
527 	// TODO: Implement!
528 }
529 
530 
531 ssize_t
532 arch_debug_gdb_get_registers(char* buffer, size_t bufferSize)
533 {
534 	// TODO: Implement!
535 	return B_NOT_SUPPORTED;
536 }
537