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