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 */
10
11
12#include <arch/debug.h>
13
14#include <arch_cpu.h>
15#include <debug.h>
16#include <elf.h>
17#include <kernel.h>
18#include <kimage.h>
19#include <thread.h>
20
21
22struct stack_frame {
23	struct stack_frame	*previous;
24	addr_t				return_address;
25};
26
27#define NUM_PREVIOUS_LOCATIONS 32
28
29extern struct iframe_stack gBootFrameStack;
30
31
32/*
33static bool
34already_visited(uint32 *visited, int32 *_last, int32 *_num, uint32 framePointer)
35{
36	int32 last = *_last;
37	int32 num = *_num;
38	int32 i;
39
40	for (i = 0; i < num; i++) {
41		if (visited[(NUM_PREVIOUS_LOCATIONS + last - i)
42				% NUM_PREVIOUS_LOCATIONS] == framePointer) {
43			return true;
44		}
45	}
46
47	*_last = last = (last + 1) % NUM_PREVIOUS_LOCATIONS;
48	visited[last] = framePointer;
49
50	if (num < NUM_PREVIOUS_LOCATIONS)
51		*_num = num + 1;
52
53	return false;
54}
55
56
57static inline stack_frame *
58get_current_stack_frame()
59{
60	stack_frame *frame;
61	asm volatile("move.l %%fp,%0" : "=r"(frame));
62	return frame;
63}
64
65
66static status_t
67get_next_frame(addr_t framePointer, addr_t *next, addr_t *ip)
68{
69	Thread *thread = thread_get_current_thread();
70	addr_t oldFaultHandler = thread->fault_handler;
71
72	// set fault handler, so that we can safely access user stacks
73	if (thread) {
74		if (m68k_set_fault_handler(&thread->fault_handler, (addr_t)&&error))
75			goto error;
76	}
77
78	*ip = ((struct stack_frame *)framePointer)->return_address;
79	*next = (addr_t)((struct stack_frame *)framePointer)->previous;
80
81	if (thread)
82		thread->fault_handler = oldFaultHandler;
83	return B_OK;
84
85error:
86	thread->fault_handler = oldFaultHandler;
87	return B_BAD_ADDRESS;
88}
89
90
91static void
92print_stack_frame(Thread *thread, addr_t ip, addr_t framePointer,
93	addr_t nextFramePointer)
94{
95	addr_t diff = nextFramePointer - framePointer;
96
97	// kernel space/user space switch
98	if (diff & 0x80000000)
99		diff = 0;
100
101	// lookup symbol
102	const char *symbol, *image;
103	addr_t baseAddress;
104	bool exactMatch;
105	status_t status = elf_debug_lookup_symbol_address(ip, &baseAddress, &symbol,
106		&image, &exactMatch);
107	if (status != B_OK && !IS_KERNEL_ADDRESS(ip) && thread) {
108		// try to locate the image in the images loaded into user space
109		status = image_debug_lookup_user_symbol_address(thread->team, ip,
110			&baseAddress, &symbol, &image, &exactMatch);
111	}
112	if (status == B_OK) {
113		if (symbol != NULL) {
114			kprintf("%08lx (+%4ld) %08lx   <%s>:%s + 0x%04lx%s\n", framePointer,
115				diff, ip, image, symbol, ip - baseAddress,
116				(exactMatch ? "" : " (nearest)"));
117		} else {
118			kprintf("%08lx (+%4ld) %08lx   <%s@%p>:unknown + 0x%04lx\n",
119				framePointer, diff, ip, image, (void *)baseAddress,
120				ip - baseAddress);
121		}
122	} else
123		kprintf("%08lx (+%4ld) %08lx\n", framePointer, diff, ip);
124}
125
126
127static int
128stack_trace(int argc, char **argv)
129{
130	uint32 previousLocations[NUM_PREVIOUS_LOCATIONS];
131	struct iframe_stack *frameStack;
132	Thread *thread;
133	addr_t framePointer;
134	int32 i, num = 0, last = 0;
135
136	if (argc < 2) {
137		thread = thread_get_current_thread();
138		framePointer = (addr_t)get_current_stack_frame();
139	} else {
140kprintf("Stack traces of other threads not supported yet!\n");
141return 0;
142	}
143
144	// We don't have a thread pointer early in the boot process
145	if (thread != NULL)
146		frameStack = &thread->arch_info.iframes;
147	else
148		frameStack = &gBootFrameStack;
149
150	for (i = 0; i < frameStack->index; i++) {
151		kprintf("iframe %p (end = %p)\n",
152			frameStack->frames[i], frameStack->frames[i] + 1);
153	}
154
155	if (thread != NULL) {
156		kprintf("stack trace for thread 0x%lx \"%s\"\n", thread->id,
157			thread->name);
158
159		kprintf("    kernel stack: %p to %p\n",
160			(void *)thread->kernel_stack_base,
161			(void *)(thread->kernel_stack_top));
162		if (thread->user_stack_base != 0) {
163			kprintf("      user stack: %p to %p\n",
164				(void *)thread->user_stack_base,
165				(void *)(thread->user_stack_base + thread->user_stack_size));
166		}
167	}
168
169	kprintf("frame            caller     <image>:function + offset\n");
170
171	for (;;) {
172		// see if the frame pointer matches the iframe
173		struct iframe *frame = NULL;
174		for (i = 0; i < frameStack->index; i++) {
175			if (framePointer == (addr_t)frameStack->frames[i]) {
176				// it's an iframe
177				frame = frameStack->frames[i];
178				break;
179			}
180		}
181
182		if (frame) {
183			kprintf("iframe at %p\n", frame);
184			kprintf("   d0 0x%08lx    d1 0x%08lx    d2 0x%08lx    d3 0x%08lx\n",
185				frame->d[0], frame->d[1], frame->d[2], frame->d[3]);
186			kprintf("   d4 0x%08lx    d5 0x%08lx    d6 0x%08lx    d7 0x%08lx\n",
187				frame->d[4], frame->d[5], frame->d[6], frame->d[7]);
188			kprintf("   a0 0x%08lx    a1 0x%08lx    a2 0x%08lx    a3 0x%08lx\n",
189				frame->a[0], frame->a[1], frame->a[2], frame->a[3]);
190			kprintf("   a4 0x%08lx    a5 0x%08lx    a6 0x%08lx    a7 0x%08lx (sp)\n",
191#warning M68K: a7 in iframe ??
192				frame->a[4], frame->a[5], frame->a[6], -1L);
193			kprintf("   pc 0x%08lx        sr 0x%04x\n",
194				frame->cpu.pc, frame->cpu.sr);
195#warning M68K: missing regs
196
197			print_stack_frame(thread, frame->cpu.pc, framePointer, frame->a[6]);
198 			framePointer = frame->a[6];
199		} else {
200			addr_t ip, nextFramePointer;
201
202			if (get_next_frame(framePointer, &nextFramePointer, &ip) != B_OK) {
203				kprintf("%08lx -- read fault\n", framePointer);
204				break;
205			}
206
207			if (ip == 0 || framePointer == 0)
208				break;
209
210			print_stack_frame(thread, ip, framePointer, nextFramePointer);
211			framePointer = nextFramePointer;
212		}
213
214		if (already_visited(previousLocations, &last, &num, framePointer)) {
215			kprintf("circular stack frame: %p!\n", (void *)framePointer);
216			break;
217		}
218		if (framePointer == 0)
219			break;
220	}
221
222
223	return 0;
224}
225
226*/
227
228// #pragma mark -
229
230
231void
232arch_debug_save_registers(struct arch_debug_registers* registers)
233{
234}
235
236
237bool
238arch_debug_contains_call(Thread *thread, const char *symbol,
239	addr_t start, addr_t end)
240{
241	return false;
242}
243
244
245void
246arch_debug_stack_trace(void)
247{
248}
249
250
251void *
252arch_debug_get_caller(void)
253{
254	/* Return the thread id as the kernel (for example the lock code) actually
255	   gets a somewhat valid indication of the caller back. */
256	return (void*) thread_get_current_thread_id();
257}
258
259
260int32
261arch_debug_get_stack_trace(addr_t* returnAddresses, int32 maxCount,
262	int32 skipIframes, int32 skipFrames, uint32 flags)
263{
264#warning ARM:IMPLEMENT
265
266	return 0;
267}
268
269
270void*
271arch_debug_get_interrupt_pc(bool* _isSyscall)
272{
273	// TODO: Implement!
274	return NULL;
275}
276
277
278bool
279arch_is_debug_variable_defined(const char* variableName)
280{
281	// TODO: Implement!
282	return false;
283}
284
285
286status_t
287arch_set_debug_variable(const char* variableName, uint64 value)
288{
289	// TODO: Implement!
290	return B_ENTRY_NOT_FOUND;
291}
292
293
294status_t
295arch_get_debug_variable(const char* variableName, uint64* value)
296{
297	// TODO: Implement!
298	return B_ENTRY_NOT_FOUND;
299}
300
301
302status_t
303arch_debug_init(kernel_args *args)
304{
305//	add_debugger_command("where", &stack_trace, "Same as \"sc\"");
306//	add_debugger_command("bt", &stack_trace, "Same as \"sc\" (as in gdb)");
307//	add_debugger_command("sc", &stack_trace, "Stack crawl for current thread");
308#warning ARM:IMPLEMENT
309
310	return B_NO_ERROR;
311}
312
313
314/* arch_debug_call_with_fault_handler is in arch_asm.S */
315
316void
317arch_debug_unset_current_thread(void)
318{
319	// TODO: Implement!
320}
321
322
323ssize_t
324arch_debug_gdb_get_registers(char* buffer, size_t bufferSize)
325{
326	// TODO: Implement!
327	return B_NOT_SUPPORTED;
328}
329