1d316037cSAxel Dörfler/*
24535495dSIngo Weinhold * Copyright 2009-2011, Ingo Weinhold, ingo_weinhold@gmx.de.
3758962ecSAxel Dörfler * Copyright 2002-2008, Axel D��rfler, axeld@pinc-software.de.
4bcb07a31SAlex Smith * Copyright 2012, Alex Smith, alex@alex-smith.me.uk.
5d316037cSAxel Dörfler * Distributed under the terms of the MIT License.
6d316037cSAxel Dörfler *
7d316037cSAxel Dörfler * Copyright 2001, Travis Geiselbrecht. All rights reserved.
8d316037cSAxel Dörfler * Distributed under the terms of the NewOS License.
9d316037cSAxel Dörfler */
10d316037cSAxel Dörfler
11d316037cSAxel Dörfler
12e6dc7903SAxel Dörfler#include <arch/debug.h>
13e6dc7903SAxel Dörfler
1408f2fdacSAxel Dörfler#include <stdio.h>
15e6dc7903SAxel Dörfler#include <stdlib.h>
16e6dc7903SAxel Dörfler
179536ec02SIngo Weinhold#include <ByteOrder.h>
1845bd7bb3SIngo Weinhold#include <TypeConstants.h>
1945bd7bb3SIngo Weinhold
20bca3215fSIngo Weinhold#include <cpu.h>
2152a38012Sejakowatz#include <debug.h>
22813d6a74SIngo Weinhold#include <debug_heap.h>
235ca8da7aSAxel Dörfler#include <elf.h>
24c5eb28a3SAxel Dörfler#include <kernel.h>
25c5eb28a3SAxel Dörfler#include <kimage.h>
26c5eb28a3SAxel Dörfler#include <thread.h>
27e50cf876SIngo Weinhold#include <vm/vm.h>
28e50cf876SIngo Weinhold#include <vm/vm_types.h>
29e50cf876SIngo Weinhold#include <vm/VMAddressSpace.h>
30f34a1dd5SIngo Weinhold#include <vm/VMArea.h>
313ae4fa63SAxel Dörfler
325ca8da7aSAxel Dörfler
336d352d08SAxel Dörflerstruct stack_frame {
34bcb07a31SAlex Smith	stack_frame*	previous;
35bcb07a31SAlex Smith	addr_t			return_address;
366d352d08SAxel Dörfler};
376d352d08SAxel Dörfler
386d352d08SAxel Dörfler#define NUM_PREVIOUS_LOCATIONS 32
3940cc0ebdSAxel Dörfler
4040cc0ebdSAxel Dörfler
41b2ef1767SJulian Harnathstatic bool is_kernel_stack_address(Thread* thread, addr_t address);
42b2ef1767SJulian Harnath
43b2ef1767SJulian Harnath
4440cc0ebdSAxel Dörflerstatic bool
45bcb07a31SAlex Smithalready_visited(addr_t* visited, int32* _last, int32* _num, addr_t bp)
4640cc0ebdSAxel Dörfler{
4740cc0ebdSAxel Dörfler	int32 last = *_last;
4840cc0ebdSAxel Dörfler	int32 num = *_num;
4940cc0ebdSAxel Dörfler	int32 i;
5040cc0ebdSAxel Dörfler
5140cc0ebdSAxel Dörfler	for (i = 0; i < num; i++) {
52bcb07a31SAlex Smith		if (visited[(NUM_PREVIOUS_LOCATIONS + last - i) % NUM_PREVIOUS_LOCATIONS] == bp)
5340cc0ebdSAxel Dörfler			return true;
5440cc0ebdSAxel Dörfler	}
5540cc0ebdSAxel Dörfler
5640cc0ebdSAxel Dörfler	*_last = last = (last + 1) % NUM_PREVIOUS_LOCATIONS;
57bcb07a31SAlex Smith	visited[last] = bp;
5840cc0ebdSAxel Dörfler
5940cc0ebdSAxel Dörfler	if (num < NUM_PREVIOUS_LOCATIONS)
6040cc0ebdSAxel Dörfler		*_num = num + 1;
6140cc0ebdSAxel Dörfler
6240cc0ebdSAxel Dörfler	return false;
6340cc0ebdSAxel Dörfler}
6440cc0ebdSAxel Dörfler
6540cc0ebdSAxel Dörfler
66ea2abd11SIngo Weinhold/*!	Safe to be called only from outside the debugger.
67ea2abd11SIngo Weinhold*/
688733b731SAxel Dörflerstatic status_t
69337c4ccfSMichael Lotzget_next_frame_no_debugger(addr_t bp, addr_t* _next, addr_t* _ip,
70b2ef1767SJulian Harnath	bool onKernelStack, Thread* thread)
718733b731SAxel Dörfler{
72ea2abd11SIngo Weinhold	// TODO: Do this more efficiently in assembly.
73ea2abd11SIngo Weinhold	stack_frame frame;
74b2ef1767SJulian Harnath	if (onKernelStack
753a3d6c4aSAugustin Cavalier			&& is_kernel_stack_address(thread, bp + sizeof(frame) - 1)) {
76337c4ccfSMichael Lotz		memcpy(&frame, (void*)bp, sizeof(frame));
773a3d6c4aSAugustin Cavalier	} else if (!IS_USER_ADDRESS(bp)
783a3d6c4aSAugustin Cavalier			|| user_memcpy(&frame, (void*)bp, sizeof(frame)) != B_OK) {
79ea2abd11SIngo Weinhold		return B_BAD_ADDRESS;
803a3d6c4aSAugustin Cavalier	}
81ea2abd11SIngo Weinhold
82bcb07a31SAlex Smith	*_ip = frame.return_address;
83ea2abd11SIngo Weinhold	*_next = (addr_t)frame.previous;
84ea2abd11SIngo Weinhold
858733b731SAxel Dörfler	return B_OK;
86ea2abd11SIngo Weinhold}
87ea2abd11SIngo Weinhold
88ea2abd11SIngo Weinhold
89ea2abd11SIngo Weinhold/*!	Safe to be called only from inside the debugger.
90ea2abd11SIngo Weinhold*/
91ea2abd11SIngo Weinholdstatic status_t
92bcb07a31SAlex Smithget_next_frame_debugger(addr_t bp, addr_t* _next, addr_t* _ip)
93ea2abd11SIngo Weinhold{
94ea2abd11SIngo Weinhold	stack_frame frame;
95bcb07a31SAlex Smith	if (debug_memcpy(B_CURRENT_TEAM, &frame, (void*)bp, sizeof(frame)) != B_OK)
96ea2abd11SIngo Weinhold		return B_BAD_ADDRESS;
97ea2abd11SIngo Weinhold
98bcb07a31SAlex Smith	*_ip = frame.return_address;
99ea2abd11SIngo Weinhold	*_next = (addr_t)frame.previous;
1008733b731SAxel Dörfler
101ea2abd11SIngo Weinhold	return B_OK;
1028733b731SAxel Dörfler}
1038733b731SAxel Dörfler
1048733b731SAxel Dörfler
1052477bce5SIngo Weinholdstatic status_t
106bcb07a31SAlex Smithlookup_symbol(Thread* thread, addr_t address, addr_t* _baseAddress,
107bcb07a31SAlex Smith	const char** _symbolName, const char** _imageName, bool* _exactMatch)
1082477bce5SIngo Weinhold{
1092477bce5SIngo Weinhold	status_t status = B_ENTRY_NOT_FOUND;
1102477bce5SIngo Weinhold
1112477bce5SIngo Weinhold	if (IS_KERNEL_ADDRESS(address)) {
1122477bce5SIngo Weinhold		// a kernel symbol
1132477bce5SIngo Weinhold		status = elf_debug_lookup_symbol_address(address, _baseAddress,
1142477bce5SIngo Weinhold			_symbolName, _imageName, _exactMatch);
1152477bce5SIngo Weinhold	} else if (thread != NULL && thread->team != NULL) {
1162477bce5SIngo Weinhold		// try a lookup using the userland runtime loader structures
1172477bce5SIngo Weinhold		status = elf_debug_lookup_user_symbol_address(thread->team, address,
1182477bce5SIngo Weinhold			_baseAddress, _symbolName, _imageName, _exactMatch);
1192477bce5SIngo Weinhold
1202477bce5SIngo Weinhold		if (status != B_OK) {
1212477bce5SIngo Weinhold			// try to locate the image in the images loaded into user space
1222477bce5SIngo Weinhold			status = image_debug_lookup_user_symbol_address(thread->team,
1232477bce5SIngo Weinhold				address, _baseAddress, _symbolName, _imageName, _exactMatch);
1242477bce5SIngo Weinhold		}
1252477bce5SIngo Weinhold	}
1262477bce5SIngo Weinhold
1272477bce5SIngo Weinhold	return status;
1282477bce5SIngo Weinhold}
1292477bce5SIngo Weinhold
1302477bce5SIngo Weinhold
131bcb07a31SAlex Smith#ifndef __x86_64__
132bcb07a31SAlex Smith
133bcb07a31SAlex Smith
1341fdc8a49SAxel Dörflerstatic void
1351fdc8a49SAxel Dörflerset_debug_argument_variable(int32 index, uint64 value)
1361fdc8a49SAxel Dörfler{
1371fdc8a49SAxel Dörfler	char name[8];
1381fdc8a49SAxel Dörfler	snprintf(name, sizeof(name), "_arg%ld", index);
1391fdc8a49SAxel Dörfler	set_debug_variable(name, value);
1401fdc8a49SAxel Dörfler}
1411fdc8a49SAxel Dörfler
1421fdc8a49SAxel Dörfler
143c3676b54SIngo Weinholdtemplate<typename Type>
144c3676b54SIngo Weinholdstatic Type
145c3676b54SIngo Weinholdread_function_argument_value(void* argument, bool& _valueKnown)
146c3676b54SIngo Weinhold{
147c3676b54SIngo Weinhold	Type value;
148c3676b54SIngo Weinhold	if (debug_memcpy(B_CURRENT_TEAM, &value, argument, sizeof(Type)) == B_OK) {
149c3676b54SIngo Weinhold		_valueKnown = true;
150c3676b54SIngo Weinhold		return value;
151c3676b54SIngo Weinhold	}
152c3676b54SIngo Weinhold
153c3676b54SIngo Weinhold	_valueKnown = false;
154c3676b54SIngo Weinhold	return 0;
155c3676b54SIngo Weinhold}
156c3676b54SIngo Weinhold
157c3676b54SIngo Weinhold
1581fdc8a49SAxel Dörflerstatic status_t
1591fdc8a49SAxel Dörflerprint_demangled_call(const char* image, const char* symbol, addr_t args,
1601fdc8a49SAxel Dörfler	bool noObjectMethod, bool addDebugVariables)
1611fdc8a49SAxel Dörfler{
162813d6a74SIngo Weinhold	static const size_t kBufferSize = 256;
163813d6a74SIngo Weinhold	char* buffer = (char*)debug_malloc(kBufferSize);
164813d6a74SIngo Weinhold	if (buffer == NULL)
165813d6a74SIngo Weinhold		return B_NO_MEMORY;
166813d6a74SIngo Weinhold
1671fdc8a49SAxel Dörfler	bool isObjectMethod;
168813d6a74SIngo Weinhold	const char* name = debug_demangle_symbol(symbol, buffer, kBufferSize,
1691fdc8a49SAxel Dörfler		&isObjectMethod);
170813d6a74SIngo Weinhold	if (name == NULL) {
171813d6a74SIngo Weinhold		debug_free(buffer);
1721fdc8a49SAxel Dörfler		return B_ERROR;
173813d6a74SIngo Weinhold	}
1741fdc8a49SAxel Dörfler
1751fdc8a49SAxel Dörfler	uint32* arg = (uint32*)args;
1761fdc8a49SAxel Dörfler
1771fdc8a49SAxel Dörfler	if (noObjectMethod)
1781fdc8a49SAxel Dörfler		isObjectMethod = false;
1791fdc8a49SAxel Dörfler	if (isObjectMethod) {
1801fdc8a49SAxel Dörfler		const char* lastName = strrchr(name, ':') - 1;
1811fdc8a49SAxel Dörfler		int namespaceLength = lastName - name;
1821fdc8a49SAxel Dörfler
183c3676b54SIngo Weinhold		uint32 argValue = 0;
184c3676b54SIngo Weinhold		if (debug_memcpy(B_CURRENT_TEAM, &argValue, arg, 4) == B_OK) {
185c3676b54SIngo Weinhold			kprintf("<%s> %.*s<\33[32m%#" B_PRIx32 "\33[0m>%s", image,
186c3676b54SIngo Weinhold				namespaceLength, name, argValue, lastName);
187c3676b54SIngo Weinhold		} else
18820f6556bSAugustin Cavalier			kprintf("<%s> %.*s<\?\?\?>%s", image, namespaceLength, name, lastName);
189c3676b54SIngo Weinhold
1901fdc8a49SAxel Dörfler		if (addDebugVariables)
191c3676b54SIngo Weinhold			set_debug_variable("_this", argValue);
1921fdc8a49SAxel Dörfler		arg++;
1931fdc8a49SAxel Dörfler	} else
1941fdc8a49SAxel Dörfler		kprintf("<%s> %s", image, name);
1951fdc8a49SAxel Dörfler
1961fdc8a49SAxel Dörfler	kprintf("(");
1971fdc8a49SAxel Dörfler
1981fdc8a49SAxel Dörfler	size_t length;
1991fdc8a49SAxel Dörfler	int32 type, i = 0;
2001fdc8a49SAxel Dörfler	uint32 cookie = 0;
2011fdc8a49SAxel Dörfler	while (debug_get_next_demangled_argument(&cookie, symbol, buffer,
202813d6a74SIngo Weinhold			kBufferSize, &type, &length) == B_OK) {
2031fdc8a49SAxel Dörfler		if (i++ > 0)
2041fdc8a49SAxel Dörfler			kprintf(", ");
2051fdc8a49SAxel Dörfler
2061fdc8a49SAxel Dörfler		// retrieve value and type identifier
2071fdc8a49SAxel Dörfler
2081fdc8a49SAxel Dörfler		uint64 value;
209c3676b54SIngo Weinhold		bool valueKnown = false;
2101fdc8a49SAxel Dörfler
2111fdc8a49SAxel Dörfler		switch (type) {
2121fdc8a49SAxel Dörfler			case B_INT64_TYPE:
213c3676b54SIngo Weinhold				value = read_function_argument_value<int64>(arg, valueKnown);
214c3676b54SIngo Weinhold				if (valueKnown)
215c3676b54SIngo Weinhold					kprintf("int64: \33[34m%Ld\33[0m", value);
2161fdc8a49SAxel Dörfler				break;
2171fdc8a49SAxel Dörfler			case B_INT32_TYPE:
218c3676b54SIngo Weinhold				value = read_function_argument_value<int32>(arg, valueKnown);
219c3676b54SIngo Weinhold				if (valueKnown)
220c3676b54SIngo Weinhold					kprintf("int32: \33[34m%ld\33[0m", (int32)value);
2211fdc8a49SAxel Dörfler				break;
2221fdc8a49SAxel Dörfler			case B_INT16_TYPE:
223c3676b54SIngo Weinhold				value = read_function_argument_value<int16>(arg, valueKnown);
224c3676b54SIngo Weinhold				if (valueKnown)
225c3676b54SIngo Weinhold					kprintf("int16: \33[34m%d\33[0m", (int16)value);
2261fdc8a49SAxel Dörfler				break;
2271fdc8a49SAxel Dörfler			case B_INT8_TYPE:
228c3676b54SIngo Weinhold				value = read_function_argument_value<int8>(arg, valueKnown);
229c3676b54SIngo Weinhold				if (valueKnown)
230c3676b54SIngo Weinhold					kprintf("int8: \33[34m%d\33[0m", (int8)value);
2311fdc8a49SAxel Dörfler				break;
2321fdc8a49SAxel Dörfler			case B_UINT64_TYPE:
233c3676b54SIngo Weinhold				value = read_function_argument_value<uint64>(arg, valueKnown);
234c3676b54SIngo Weinhold				if (valueKnown) {
235c3676b54SIngo Weinhold					kprintf("uint64: \33[34m%#Lx\33[0m", value);
236c3676b54SIngo Weinhold					if (value < 0x100000)
237c3676b54SIngo Weinhold						kprintf(" (\33[34m%Lu\33[0m)", value);
238c3676b54SIngo Weinhold				}
2391fdc8a49SAxel Dörfler				break;
2401fdc8a49SAxel Dörfler			case B_UINT32_TYPE:
241c3676b54SIngo Weinhold				value = read_function_argument_value<uint32>(arg, valueKnown);
242c3676b54SIngo Weinhold				if (valueKnown) {
243c3676b54SIngo Weinhold					kprintf("uint32: \33[34m%#lx\33[0m", (uint32)value);
244c3676b54SIngo Weinhold					if (value < 0x100000)
245c3676b54SIngo Weinhold						kprintf(" (\33[34m%lu\33[0m)", (uint32)value);
246c3676b54SIngo Weinhold				}
2471fdc8a49SAxel Dörfler				break;
2481fdc8a49SAxel Dörfler			case B_UINT16_TYPE:
249c3676b54SIngo Weinhold				value = read_function_argument_value<uint16>(arg, valueKnown);
250c3676b54SIngo Weinhold				if (valueKnown) {
251c3676b54SIngo Weinhold					kprintf("uint16: \33[34m%#x\33[0m (\33[34m%u\33[0m)",
252c3676b54SIngo Weinhold						(uint16)value, (uint16)value);
253c3676b54SIngo Weinhold				}
2541fdc8a49SAxel Dörfler				break;
2551fdc8a49SAxel Dörfler			case B_UINT8_TYPE:
256c3676b54SIngo Weinhold				value = read_function_argument_value<uint8>(arg, valueKnown);
257c3676b54SIngo Weinhold				if (valueKnown) {
258c3676b54SIngo Weinhold					kprintf("uint8: \33[34m%#x\33[0m (\33[34m%u\33[0m)",
259c3676b54SIngo Weinhold						(uint8)value, (uint8)value);
260c3676b54SIngo Weinhold				}
2611fdc8a49SAxel Dörfler				break;
2621fdc8a49SAxel Dörfler			case B_BOOL_TYPE:
263c3676b54SIngo Weinhold				value = read_function_argument_value<uint8>(arg, valueKnown);
264c3676b54SIngo Weinhold				if (valueKnown)
265c3676b54SIngo Weinhold					kprintf("\33[34m%s\33[0m", value ? "true" : "false");
2661fdc8a49SAxel Dörfler				break;
2671fdc8a49SAxel Dörfler			default:
2687927ebb6SIngo Weinhold				if (buffer[0])
2697927ebb6SIngo Weinhold					kprintf("%s: ", buffer);
2701fdc8a49SAxel Dörfler
2711fdc8a49SAxel Dörfler				if (length == 4) {
272c3676b54SIngo Weinhold					value = read_function_argument_value<uint32>(arg,
273c3676b54SIngo Weinhold						valueKnown);
274c3676b54SIngo Weinhold					if (valueKnown) {
275c3676b54SIngo Weinhold						if (value == 0
276c3676b54SIngo Weinhold							&& (type == B_POINTER_TYPE || type == B_REF_TYPE))
277c3676b54SIngo Weinhold							kprintf("NULL");
278c3676b54SIngo Weinhold						else
279c3676b54SIngo Weinhold							kprintf("\33[34m%#lx\33[0m", (uint32)value);
280c3676b54SIngo Weinhold					}
2811fdc8a49SAxel Dörfler					break;
2821fdc8a49SAxel Dörfler				}
2831fdc8a49SAxel Dörfler
284c3676b54SIngo Weinhold
285c3676b54SIngo Weinhold				if (length == 8) {
286c3676b54SIngo Weinhold					value = read_function_argument_value<uint64>(arg,
287c3676b54SIngo Weinhold						valueKnown);
288c3676b54SIngo Weinhold				} else
2891fdc8a49SAxel Dörfler					value = (uint64)arg;
290c3676b54SIngo Weinhold
291c3676b54SIngo Weinhold				if (valueKnown)
292c3676b54SIngo Weinhold					kprintf("\33[34m%#Lx\33[0m", value);
2931fdc8a49SAxel Dörfler				break;
2941fdc8a49SAxel Dörfler		}
2951fdc8a49SAxel Dörfler
296c3676b54SIngo Weinhold		if (!valueKnown)
297c3676b54SIngo Weinhold			kprintf("???");
298c3676b54SIngo Weinhold
299c3676b54SIngo Weinhold		if (valueKnown && type == B_STRING_TYPE) {
3003a5a6775SAxel Dörfler			if (value == 0)
3013a5a6775SAxel Dörfler				kprintf(" \33[31m\"<NULL>\"\33[0m");
302e468e31fSIngo Weinhold			else if (debug_strlcpy(B_CURRENT_TEAM, buffer, (char*)(addr_t)value,
303c3676b54SIngo Weinhold					kBufferSize) < B_OK) {
30420f6556bSAugustin Cavalier				kprintf(" \33[31m\"<\?\?\?>\"\33[0m");
305c3676b54SIngo Weinhold			} else
3063a5a6775SAxel Dörfler				kprintf(" \33[36m\"%s\"\33[0m", buffer);
30797ba3fb3SAxel Dörfler		}
3081fdc8a49SAxel Dörfler
3091fdc8a49SAxel Dörfler		if (addDebugVariables)
3101fdc8a49SAxel Dörfler			set_debug_argument_variable(i, value);
3111fdc8a49SAxel Dörfler		arg = (uint32*)((uint8*)arg + length);
3121fdc8a49SAxel Dörfler	}
3131fdc8a49SAxel Dörfler
314813d6a74SIngo Weinhold	debug_free(buffer);
315813d6a74SIngo Weinhold
3161fdc8a49SAxel Dörfler	kprintf(")");
3171fdc8a49SAxel Dörfler	return B_OK;
3181fdc8a49SAxel Dörfler}
3191fdc8a49SAxel Dörfler
3201fdc8a49SAxel Dörfler
321bcb07a31SAlex Smith#else	// __x86_64__
322bcb07a31SAlex Smith
323bcb07a31SAlex Smith
324bcb07a31SAlex Smithstatic status_t
325bcb07a31SAlex Smithprint_demangled_call(const char* image, const char* symbol, addr_t args,
326bcb07a31SAlex Smith	bool noObjectMethod, bool addDebugVariables)
327bcb07a31SAlex Smith{
328bcb07a31SAlex Smith	// Since x86_64 uses registers rather than the stack for the first 6
329bcb07a31SAlex Smith	// arguments we cannot use the same method as x86 to read the function
330bcb07a31SAlex Smith	// arguments. Maybe we need DWARF support in the kernel debugger. For now
331bcb07a31SAlex Smith	// just print out the function signature without the argument values.
332bcb07a31SAlex Smith
3335afce632SAlex Smith	static const size_t kBufferSize = 256;
3345afce632SAlex Smith	char* buffer = (char*)debug_malloc(kBufferSize);
3355afce632SAlex Smith	if (buffer == NULL)
3365afce632SAlex Smith		return B_NO_MEMORY;
3375afce632SAlex Smith
3385afce632SAlex Smith	bool isObjectMethod;
3395afce632SAlex Smith	const char* name = debug_demangle_symbol(symbol, buffer, kBufferSize,
3405afce632SAlex Smith		&isObjectMethod);
3415afce632SAlex Smith	if (name == NULL) {
3425afce632SAlex Smith		debug_free(buffer);
3435afce632SAlex Smith		return B_ERROR;
3445afce632SAlex Smith	}
3455afce632SAlex Smith
3465afce632SAlex Smith	kprintf("<%s> %s(", image, name);
3475afce632SAlex Smith
3485afce632SAlex Smith	size_t length;
3495afce632SAlex Smith	int32 type, i = 0;
3505afce632SAlex Smith	uint32 cookie = 0;
3515afce632SAlex Smith	while (debug_get_next_demangled_argument(&cookie, symbol, buffer,
3525afce632SAlex Smith			kBufferSize, &type, &length) == B_OK) {
3535afce632SAlex Smith		if (i++ > 0)
3545afce632SAlex Smith			kprintf(", ");
3555afce632SAlex Smith
3565afce632SAlex Smith		if (buffer[0])
3575afce632SAlex Smith			kprintf("%s", buffer);
3585afce632SAlex Smith		else
3595afce632SAlex Smith			kprintf("???");
3605afce632SAlex Smith	}
3615afce632SAlex Smith
3625afce632SAlex Smith	debug_free(buffer);
3635afce632SAlex Smith
3645afce632SAlex Smith	kprintf(")");
3655afce632SAlex Smith	return B_OK;
366bcb07a31SAlex Smith}
367bcb07a31SAlex Smith
368bcb07a31SAlex Smith
369bcb07a31SAlex Smith#endif	// __x86_64__
370bcb07a31SAlex Smith
371bcb07a31SAlex Smith
372c5eb28a3SAxel Dörflerstatic void
373bcb07a31SAlex Smithprint_stack_frame(Thread* thread, addr_t ip, addr_t bp, addr_t nextBp,
3741fdc8a49SAxel Dörfler	int32 callIndex, bool demangle)
375c5eb28a3SAxel Dörfler{
376bcb07a31SAlex Smith	const char* symbol;
377bcb07a31SAlex Smith	const char* image;
378c5eb28a3SAxel Dörfler	addr_t baseAddress;
379c5eb28a3SAxel Dörfler	bool exactMatch;
380513403d4SAugustin Cavalier	status_t status;
381c5eb28a3SAxel Dörfler	addr_t diff;
382c5eb28a3SAxel Dörfler
383bcb07a31SAlex Smith	diff = nextBp - bp;
384c5eb28a3SAxel Dörfler
385bcb07a31SAlex Smith	// MSB set = kernel space/user space switch
386bcb07a31SAlex Smith	if (diff & ~((addr_t)-1 >> 1))
387c5eb28a3SAxel Dörfler		diff = 0;
388c5eb28a3SAxel Dörfler
389bcb07a31SAlex Smith	status = lookup_symbol(thread, ip, &baseAddress, &symbol, &image,
3902477bce5SIngo Weinhold		&exactMatch);
391f4748003SAxel Dörfler
392bcb07a31SAlex Smith	kprintf("%2" B_PRId32 " %0*lx (+%4ld) %0*lx   ", callIndex,
393bcb07a31SAlex Smith		B_PRINTF_POINTER_WIDTH, bp, diff, B_PRINTF_POINTER_WIDTH, ip);
394f39acd67SAxel Dörfler
395c5eb28a3SAxel Dörfler	if (status == B_OK) {
3961fdc8a49SAxel Dörfler		if (exactMatch && demangle) {
397bcb07a31SAlex Smith			status = print_demangled_call(image, symbol,
398bcb07a31SAlex Smith				nextBp + sizeof(stack_frame), false, false);
399c5eb28a3SAxel Dörfler		}
4001fdc8a49SAxel Dörfler
4011fdc8a49SAxel Dörfler		if (!exactMatch || !demangle || status != B_OK) {
4021fdc8a49SAxel Dörfler			if (symbol != NULL) {
4035afce632SAlex Smith				kprintf("<%s> %s%s", image, symbol,
4041fdc8a49SAxel Dörfler					exactMatch ? "" : " (nearest)");
4051fdc8a49SAxel Dörfler			} else
4065afce632SAlex Smith				kprintf("<%s@%p> <unknown>", image, (void*)baseAddress);
4071fdc8a49SAxel Dörfler		}
4081fdc8a49SAxel Dörfler
409bcb07a31SAlex Smith		kprintf(" + %#04lx\n", ip - baseAddress);
410f39acd67SAxel Dörfler	} else {
411a99eb6b5SIngo Weinhold		VMArea *area = NULL;
412ea2abd11SIngo Weinhold		if (thread != NULL && thread->team != NULL
413ea2abd11SIngo Weinhold			&& thread->team->address_space != NULL) {
414bcb07a31SAlex Smith			area = thread->team->address_space->LookupArea(ip);
415ea2abd11SIngo Weinhold		}
416f39acd67SAxel Dörfler		if (area != NULL) {
417bcb07a31SAlex Smith			kprintf("%" B_PRId32 ":%s@%p + %#lx\n", area->id, area->name,
418bcb07a31SAlex Smith				(void*)area->Base(), ip - area->Base());
419f39acd67SAxel Dörfler		} else
420f39acd67SAxel Dörfler			kprintf("\n");
421f39acd67SAxel Dörfler	}
422c5eb28a3SAxel Dörfler}
423c5eb28a3SAxel Dörfler
424c5eb28a3SAxel Dörfler
42599085d67SAxel Dörflerstatic void
426bcb07a31SAlex Smithprint_iframe(iframe* frame)
42799085d67SAxel Dörfler{
4285ccf1db3SIngo Weinhold	bool isUser = IFRAME_IS_USER(frame);
429bcb07a31SAlex Smith
430bcb07a31SAlex Smith#ifdef __x86_64__
431bcb07a31SAlex Smith	kprintf("%s iframe at %p (end = %p)\n", isUser ? "user" : "kernel", frame,
432bcb07a31SAlex Smith		frame + 1);
433bcb07a31SAlex Smith
434bcb07a31SAlex Smith	kprintf(" rax %#-18lx    rbx %#-18lx    rcx %#lx\n", frame->ax,
435bcb07a31SAlex Smith		frame->bx, frame->cx);
436bcb07a31SAlex Smith	kprintf(" rdx %#-18lx    rsi %#-18lx    rdi %#lx\n", frame->dx,
437bcb07a31SAlex Smith		frame->si, frame->di);
438bcb07a31SAlex Smith	kprintf(" rbp %#-18lx     r8 %#-18lx     r9 %#lx\n", frame->bp,
439bcb07a31SAlex Smith		frame->r8, frame->r9);
440bcb07a31SAlex Smith	kprintf(" r10 %#-18lx    r11 %#-18lx    r12 %#lx\n", frame->r10,
441bcb07a31SAlex Smith		frame->r11, frame->r12);
442bcb07a31SAlex Smith	kprintf(" r13 %#-18lx    r14 %#-18lx    r15 %#lx\n", frame->r13,
443bcb07a31SAlex Smith		frame->r14, frame->r15);
444bcb07a31SAlex Smith	kprintf(" rip %#-18lx    rsp %#-18lx rflags %#lx\n", frame->ip,
445bcb07a31SAlex Smith		frame->sp, frame->flags);
446bcb07a31SAlex Smith#else
4475ccf1db3SIngo Weinhold	kprintf("%s iframe at %p (end = %p)\n", isUser ? "user" : "kernel", frame,
448bcb07a31SAlex Smith		isUser ? (void*)(frame + 1) : (void*)&frame->user_sp);
44999085d67SAxel Dörfler
450bcb07a31SAlex Smith	kprintf(" eax %#-10lx    ebx %#-10lx     ecx %#-10lx  edx %#lx\n",
451b5c9d24aSAlex Smith		frame->ax, frame->bx, frame->cx, frame->dx);
452bcb07a31SAlex Smith	kprintf(" esi %#-10lx    edi %#-10lx     ebp %#-10lx  esp %#lx\n",
453b5c9d24aSAlex Smith		frame->si, frame->di, frame->bp, frame->sp);
454bcb07a31SAlex Smith	kprintf(" eip %#-10lx eflags %#-10lx", frame->ip, frame->flags);
4555ccf1db3SIngo Weinhold	if (isUser) {
45699085d67SAxel Dörfler		// from user space
457bcb07a31SAlex Smith		kprintf("user esp %#lx", frame->user_sp);
45899085d67SAxel Dörfler	}
45999085d67SAxel Dörfler	kprintf("\n");
460bcb07a31SAlex Smith#endif
461bcb07a31SAlex Smith
462bcb07a31SAlex Smith	kprintf(" vector: %#lx, error code: %#lx\n", frame->vector,
463f4748003SAxel Dörfler		frame->error_code);
46499085d67SAxel Dörfler}
46599085d67SAxel Dörfler
46699085d67SAxel Dörfler
467e7baaab3SAxel Dörflerstatic bool
468bcb07a31SAlex Smithsetup_for_thread(char* arg, Thread** _thread, addr_t* _bp,
469bcb07a31SAlex Smith	phys_addr_t* _oldPageDirectory)
4705ca8da7aSAxel Dörfler{
471bcb07a31SAlex Smith	Thread* thread = NULL;
4725ca8da7aSAxel Dörfler
473f4748003SAxel Dörfler	if (arg != NULL) {
474f4748003SAxel Dörfler		thread_id id = strtoul(arg, NULL, 0);
47524df6592SIngo Weinhold		thread = Thread::GetDebug(id);
476d6c32d2bSAxel Dörfler		if (thread == NULL) {
477bcb07a31SAlex Smith			kprintf("could not find thread %" B_PRId32 "\n", id);
478e7baaab3SAxel Dörfler			return false;
479d6c32d2bSAxel Dörfler		}
480d6c32d2bSAxel Dörfler
4817b7c38a2SAxel Dörfler		if (id != thread_get_current_thread_id()) {
4827b7c38a2SAxel Dörfler			// switch to the page directory of the new thread to be
4837b7c38a2SAxel Dörfler			// able to follow the stack trace into userland
484bcb07a31SAlex Smith			phys_addr_t newPageDirectory = x86_next_page_directory(
4857b7c38a2SAxel Dörfler				thread_get_current_thread(), thread);
4867b7c38a2SAxel Dörfler
4877b7c38a2SAxel Dörfler			if (newPageDirectory != 0) {
4884e8fbfb2SAlex Smith				*_oldPageDirectory = x86_read_cr3();
4894e8fbfb2SAlex Smith				x86_write_cr3(newPageDirectory);
4907b7c38a2SAxel Dörfler			}
49199085d67SAxel Dörfler
492cfefeee3SIngo Weinhold			if (thread->state == B_THREAD_RUNNING) {
493cfefeee3SIngo Weinhold				// The thread is currently running on another CPU.
494cfefeee3SIngo Weinhold				if (thread->cpu == NULL)
495cfefeee3SIngo Weinhold					return false;
496cfefeee3SIngo Weinhold				arch_debug_registers* registers = debug_get_debug_registers(
497cfefeee3SIngo Weinhold					thread->cpu->cpu_num);
498cfefeee3SIngo Weinhold				if (registers == NULL)
499cfefeee3SIngo Weinhold					return false;
500bcb07a31SAlex Smith				*_bp = registers->bp;
501cfefeee3SIngo Weinhold			} else {
502bcb07a31SAlex Smith				// Read frame pointer from the thread's stack.
503bcb07a31SAlex Smith				*_bp = thread->arch_info.GetFramePointer();
504cfefeee3SIngo Weinhold			}
50599085d67SAxel Dörfler		} else
5068ac552e4SAxel Dörfler			thread = NULL;
50799085d67SAxel Dörfler	}
50899085d67SAxel Dörfler
50999085d67SAxel Dörfler	if (thread == NULL) {
51099085d67SAxel Dörfler		// if we don't have a thread yet, we want the current one
511f4748003SAxel Dörfler		// (ebp has been set by the caller for this case already)
51299085d67SAxel Dörfler		thread = thread_get_current_thread();
5135ca8da7aSAxel Dörfler	}
5145ca8da7aSAxel Dörfler
515f4748003SAxel Dörfler	*_thread = thread;
516e7baaab3SAxel Dörfler	return true;
517f4748003SAxel Dörfler}
518f4748003SAxel Dörfler
519ea2abd11SIngo Weinhold
520bca3215fSIngo Weinholdstatic bool
521bca3215fSIngo Weinholdis_double_fault_stack_address(int32 cpu, addr_t address)
522bca3215fSIngo Weinhold{
523bca3215fSIngo Weinhold	size_t size;
524bca3215fSIngo Weinhold	addr_t bottom = (addr_t)x86_get_double_fault_stack(cpu, &size);
525bca3215fSIngo Weinhold	return address >= bottom && address < bottom + size;
526bca3215fSIngo Weinhold}
527bca3215fSIngo Weinhold
528f4748003SAxel Dörfler
52934b3b26bSIngo Weinholdstatic bool
5304535495dSIngo Weinholdis_kernel_stack_address(Thread* thread, addr_t address)
53134b3b26bSIngo Weinhold{
53234b3b26bSIngo Weinhold	// We don't have a thread pointer in the early boot process, but then we are
53334b3b26bSIngo Weinhold	// on the kernel stack for sure.
53434b3b26bSIngo Weinhold	if (thread == NULL)
53534b3b26bSIngo Weinhold		return IS_KERNEL_ADDRESS(address);
53634b3b26bSIngo Weinhold
537fe30b74fSIngo Weinhold	// Also in the early boot process we might have a thread structure, but it
538fe30b74fSIngo Weinhold	// might not have its kernel stack attributes set yet.
539fe30b74fSIngo Weinhold	if (thread->kernel_stack_top == 0)
540fe30b74fSIngo Weinhold		return IS_KERNEL_ADDRESS(address);
541fe30b74fSIngo Weinhold
542c33667d4SMichael Lotz	return (address >= thread->kernel_stack_base
543c33667d4SMichael Lotz			&& address < thread->kernel_stack_top)
544c33667d4SMichael Lotz		|| (thread->cpu != NULL
545c33667d4SMichael Lotz			&& is_double_fault_stack_address(thread->cpu->cpu_num, address));
54634b3b26bSIngo Weinhold}
54734b3b26bSIngo Weinhold
54834b3b26bSIngo Weinhold
54934b3b26bSIngo Weinholdstatic bool
5504535495dSIngo Weinholdis_iframe(Thread* thread, addr_t frame)
55134b3b26bSIngo Weinhold{
5521111ffc5SIngo Weinhold	if (!is_kernel_stack_address(thread, frame))
5531111ffc5SIngo Weinhold		return false;
5541111ffc5SIngo Weinhold
5551111ffc5SIngo Weinhold	addr_t previousFrame = *(addr_t*)frame;
55615feb603SAlex Smith	return ((previousFrame & ~(addr_t)IFRAME_TYPE_MASK) == 0
55715feb603SAlex Smith		&& previousFrame != 0);
55834b3b26bSIngo Weinhold}
55934b3b26bSIngo Weinhold
56034b3b26bSIngo Weinhold
561bcb07a31SAlex Smithstatic iframe*
562bcb07a31SAlex Smithfind_previous_iframe(Thread* thread, addr_t frame)
56334b3b26bSIngo Weinhold{
56434b3b26bSIngo Weinhold	// iterate backwards through the stack frames, until we hit an iframe
56534b3b26bSIngo Weinhold	while (is_kernel_stack_address(thread, frame)) {
56634b3b26bSIngo Weinhold		if (is_iframe(thread, frame))
567bcb07a31SAlex Smith			return (iframe*)frame;
56834b3b26bSIngo Weinhold
56934b3b26bSIngo Weinhold		frame = *(addr_t*)frame;