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