117721Speter/*
217721Speter * Copyright 2019-2022 Haiku, Inc. All Rights Reserved.
317721Speter * Distributed under the terms of the MIT License.
417721Speter */
517721Speter
617721Speter
717721Speter#include <arch/debug.h>
817721Speter
917721Speter#include <arch_cpu.h>
1017721Speter#include <debug.h>
1117721Speter#include <debug_heap.h>
1217721Speter#include <elf.h>
1317721Speter#include <kernel.h>
1417721Speter#include <kimage.h>
1517721Speter#include <thread.h>
1617721Speter#include <vm/vm_types.h>
1717721Speter#include <vm/VMAddressSpace.h>
1817721Speter#include <vm/VMArea.h>
1917721Speter
2017721Speter#define NUM_PREVIOUS_LOCATIONS 32
2117721Speter
2217721Speterextern struct iframe_stack gBootFrameStack;
2317721Speter
2417721Speter
2517721Speterstatic bool
2617721Speteralready_visited(addr_t* visited, int32* _last, int32* _num, addr_t fp)
2717721Speter{
2817721Speter	int32 last = *_last;
2917721Speter	int32 num = *_num;
3017721Speter
3117721Speter	for (int32 i = 0; i < num; i++) {
3217721Speter		if (visited[(NUM_PREVIOUS_LOCATIONS + last - i)
3317721Speter				% NUM_PREVIOUS_LOCATIONS] == fp) {
3417721Speter			return true;
3517721Speter		}
3617721Speter	}
3717721Speter
3817721Speter	*_last = last = (last + 1) % NUM_PREVIOUS_LOCATIONS;
3917721Speter	visited[last] = fp;
4017721Speter
4117721Speter	if (num < NUM_PREVIOUS_LOCATIONS)
4217721Speter		*_num = num + 1;
4317721Speter
4417721Speter	return false;
4517721Speter}
4617721Speter
4717721Speter
4817721Speterstatic status_t
4917721Speterget_next_frame(addr_t fp, addr_t *next, addr_t *ip)
5017721Speter{
5117721Speter	if (fp != 0) {
5217721Speter		*ip   = ((addr_t*)fp)[1];
5317721Speter		*next = ((addr_t*)fp)[0];
5417721Speter
5517721Speter		return B_OK;
5617721Speter	}
5717721Speter
5817721Speter	return B_BAD_VALUE;
5917721Speter}
6017721Speter
6117721Speter
6217721Speterstatic status_t
6317721Speterlookup_symbol(Thread* thread, addr_t address, addr_t* _baseAddress,
6417721Speter	const char** _symbolName, const char** _imageName, bool* _exactMatch)
6517721Speter{
6617721Speter	status_t status = B_ENTRY_NOT_FOUND;
6717721Speter
6817721Speter	if (address >= KERNEL_BASE) {
6917721Speter		// a kernel symbol
7017721Speter		status = elf_debug_lookup_symbol_address(address, _baseAddress,
7117721Speter			_symbolName, _imageName, _exactMatch);
7217721Speter	} else if (thread != NULL && thread->team != NULL) {
7317721Speter		// try a lookup using the userland runtime loader structures
7417721Speter		status = elf_debug_lookup_user_symbol_address(thread->team, address,
7517721Speter			_baseAddress, _symbolName, _imageName, _exactMatch);
7617721Speter
7717721Speter		if (status != B_OK) {
7817721Speter			// try to locate the image in the images loaded into user space
7917721Speter			status = image_debug_lookup_user_symbol_address(thread->team,
8017721Speter				address, _baseAddress, _symbolName, _imageName, _exactMatch);
8117721Speter		}
8217721Speter	}
8317721Speter
8417721Speter	return status;
8517721Speter}
8617721Speter
8717721Speter
8817721Speterstatic void
8917721Speterset_debug_argument_variable(int32 index, uint64 value)
9017721Speter{
9117721Speter	char name[8];
9217721Speter	snprintf(name, sizeof(name), "_arg%" B_PRId32, index);
9317721Speter	set_debug_variable(name, value);
9417721Speter}
9517721Speter
9617721Speter
9717721Spetertemplate<typename Type>
9817721Speterstatic Type
9917721Speterread_function_argument_value(void* argument, bool& _valueKnown)
10017721Speter{
10117721Speter	Type value;
10217721Speter	if (debug_memcpy(B_CURRENT_TEAM, &value, argument, sizeof(Type)) == B_OK) {
10317721Speter		_valueKnown = true;
10417721Speter		return value;
10517721Speter	}
10617721Speter
10717721Speter	_valueKnown = false;
10817721Speter	return 0;
10917721Speter}
11017721Speter
11117721Speter
11217721Speterstatic status_t
11317721Speterprint_demangled_call(const char* image, const char* symbol, addr_t args,
11417721Speter	bool noObjectMethod, bool addDebugVariables)
11517721Speter{
11617721Speter	static const size_t kBufferSize = 256;
11717721Speter	char* buffer = (char*)debug_malloc(kBufferSize);
11817721Speter	if (buffer == NULL)
11917721Speter		return B_NO_MEMORY;
12017721Speter
12117721Speter	bool isObjectMethod;
12217721Speter	const char* name = debug_demangle_symbol(symbol, buffer, kBufferSize,
12317721Speter		&isObjectMethod);
12417721Speter	if (name == NULL) {
12517721Speter		debug_free(buffer);
12617721Speter		return B_ERROR;
12717721Speter	}
12817721Speter
12917721Speter	uint32* arg = (uint32*)args;
13017721Speter
13117721Speter	if (noObjectMethod)
13217721Speter		isObjectMethod = false;
13317721Speter	if (isObjectMethod) {
13417721Speter		const char* lastName = strrchr(name, ':') - 1;
13517721Speter		int namespaceLength = lastName - name;
13617721Speter
13717721Speter		uint32 argValue = 0;
13817721Speter		if (debug_memcpy(B_CURRENT_TEAM, &argValue, arg, 4) == B_OK) {
13917721Speter			kprintf("<%s> %.*s<\33[32m%#" B_PRIx32 "\33[0m>%s", image,
14017721Speter				namespaceLength, name, argValue, lastName);
14117721Speter		} else
14217721Speter			kprintf("<%s> %.*s<\?\?\?>%s", image, namespaceLength, name, lastName);
14317721Speter
14417721Speter		if (addDebugVariables)
14517721Speter			set_debug_variable("_this", argValue);
14617721Speter		arg++;
14717721Speter	} else
14817721Speter		kprintf("<%s> %s", image, name);
14917721Speter
15017721Speter	kprintf("(");
15117721Speter
15217721Speter	size_t length;
15317721Speter	int32 type, i = 0;
15417721Speter	uint32 cookie = 0;
15517721Speter	while (debug_get_next_demangled_argument(&cookie, symbol, buffer,
15617721Speter			kBufferSize, &type, &length) == B_OK) {
15717721Speter		if (i++ > 0)
15817721Speter			kprintf(", ");
15917721Speter
16017721Speter		// retrieve value and type identifier
16117721Speter
16217721Speter		uint64 value;
16317721Speter		bool valueKnown = false;
16417721Speter
16517721Speter		switch (type) {
16617721Speter			case B_INT64_TYPE:
16717721Speter				value = read_function_argument_value<int64>(arg, valueKnown);
16817721Speter				if (valueKnown)
16917721Speter					kprintf("int64: \33[34m%" B_PRId64 "\33[0m", value);
17017721Speter				break;
17117721Speter			case B_INT32_TYPE:
17217721Speter				value = read_function_argument_value<int32>(arg, valueKnown);
17317721Speter				if (valueKnown)
17417721Speter					kprintf("int32: \33[34m%" B_PRId32 "\33[0m", (int32)value);
17517721Speter				break;
17617721Speter			case B_INT16_TYPE:
17717721Speter				value = read_function_argument_value<int16>(arg, valueKnown);
17817721Speter				if (valueKnown)
17917721Speter					kprintf("int16: \33[34m%d\33[0m", (int16)value);
18017721Speter				break;
18117721Speter			case B_INT8_TYPE:
18217721Speter				value = read_function_argument_value<int8>(arg, valueKnown);
18317721Speter				if (valueKnown)
18417721Speter					kprintf("int8: \33[34m%d\33[0m", (int8)value);
18517721Speter				break;
18617721Speter			case B_UINT64_TYPE:
18717721Speter				value = read_function_argument_value<uint64>(arg, valueKnown);
18817721Speter				if (valueKnown) {
18917721Speter					kprintf("uint64: \33[34m%#" B_PRIx64 "\33[0m", value);
19017721Speter					if (value < 0x100000)
19117721Speter						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
275static void
276print_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
327static int
328stack_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
431void
432arch_debug_save_registers(struct arch_debug_registers* registers)
433{
434}
435
436
437bool
438arch_debug_contains_call(Thread *thread, const char *symbol,
439	addr_t start, addr_t end)
440{
441	return false;
442}
443
444
445void
446arch_debug_stack_trace(void)
447{
448	stack_trace(0, NULL);
449}
450
451
452int32
453arch_debug_get_stack_trace(addr_t* returnAddresses, int32 maxCount,
454	int32 skipIframes, int32 skipFrames, uint32 flags)
455{
456	return 0;
457}
458
459
460void*
461arch_debug_get_interrupt_pc(bool* _isSyscall)
462{
463	return NULL;
464}
465
466
467bool
468arch_is_debug_variable_defined(const char* variableName)
469{
470	return false;
471}
472
473
474status_t
475arch_set_debug_variable(const char* variableName, uint64 value)
476{
477	return B_ENTRY_NOT_FOUND;
478}
479
480
481status_t
482arch_get_debug_variable(const char* variableName, uint64* value)
483{
484	return B_ENTRY_NOT_FOUND;
485}
486
487
488status_t
489arch_debug_init(kernel_args *args)
490{
491	add_debugger_command("where", &stack_trace, "Same as \"sc\"");
492	add_debugger_command("bt", &stack_trace, "Same as \"sc\" (as in gdb)");
493	add_debugger_command("sc", &stack_trace, "Stack crawl for current thread");
494
495	return B_NO_ERROR;
496}
497
498
499void
500arch_debug_unset_current_thread(void)
501{
502}
503
504
505ssize_t
506arch_debug_gdb_get_registers(char* buffer, size_t bufferSize)
507{
508	return B_NOT_SUPPORTED;
509}
510