xref: /haiku/src/system/kernel/arch/arm/arch_debug.cpp (revision b2a7fcb4045ff77189f7431fde83e16e21258736)
1 /*
2  * Copyright 2003-2009, 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 
22 struct stack_frame {
23 	struct stack_frame	*previous;
24 	addr_t				return_address;
25 };
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 framePointer)
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] == framePointer) {
42 			return true;
43 		}
44 	}
45 
46 	*_last = last = (last + 1) % NUM_PREVIOUS_LOCATIONS;
47 	visited[last] = framePointer;
48 
49 	if (num < NUM_PREVIOUS_LOCATIONS)
50 		*_num = num + 1;
51 
52 	return false;
53 }
54 
55 
56 static inline stack_frame *
57 get_current_stack_frame()
58 {
59 	stack_frame *frame;
60 	asm volatile("move.l %%fp,%0" : "=r"(frame));
61 	return frame;
62 }
63 
64 
65 static status_t
66 get_next_frame(addr_t framePointer, addr_t *next, addr_t *ip)
67 {
68 	struct thread *thread = thread_get_current_thread();
69 	addr_t oldFaultHandler = thread->fault_handler;
70 
71 	// set fault handler, so that we can safely access user stacks
72 	if (thread) {
73 		if (m68k_set_fault_handler(&thread->fault_handler, (addr_t)&&error))
74 			goto error;
75 	}
76 
77 	*ip = ((struct stack_frame *)framePointer)->return_address;
78 	*next = (addr_t)((struct stack_frame *)framePointer)->previous;
79 
80 	if (thread)
81 		thread->fault_handler = oldFaultHandler;
82 	return B_OK;
83 
84 error:
85 	thread->fault_handler = oldFaultHandler;
86 	return B_BAD_ADDRESS;
87 }
88 
89 
90 static void
91 print_stack_frame(struct thread *thread, addr_t ip, addr_t framePointer,
92 	addr_t nextFramePointer)
93 {
94 	addr_t diff = nextFramePointer - framePointer;
95 
96 	// kernel space/user space switch
97 	if (diff & 0x80000000)
98 		diff = 0;
99 
100 	// lookup symbol
101 	const char *symbol, *image;
102 	addr_t baseAddress;
103 	bool exactMatch;
104 	status_t status = elf_debug_lookup_symbol_address(ip, &baseAddress, &symbol,
105 		&image, &exactMatch);
106 	if (status != B_OK && !IS_KERNEL_ADDRESS(ip) && thread) {
107 		// try to locate the image in the images loaded into user space
108 		status = image_debug_lookup_user_symbol_address(thread->team, ip,
109 			&baseAddress, &symbol, &image, &exactMatch);
110 	}
111 	if (status == B_OK) {
112 		if (symbol != NULL) {
113 			kprintf("%08lx (+%4ld) %08lx   <%s>:%s + 0x%04lx%s\n", framePointer,
114 				diff, ip, image, symbol, ip - baseAddress,
115 				(exactMatch ? "" : " (nearest)"));
116 		} else {
117 			kprintf("%08lx (+%4ld) %08lx   <%s@%p>:unknown + 0x%04lx\n",
118 				framePointer, diff, ip, image, (void *)baseAddress,
119 				ip - baseAddress);
120 		}
121 	} else
122 		kprintf("%08lx (+%4ld) %08lx\n", framePointer, diff, ip);
123 }
124 
125 
126 static int
127 stack_trace(int argc, char **argv)
128 {
129 	uint32 previousLocations[NUM_PREVIOUS_LOCATIONS];
130 	struct iframe_stack *frameStack;
131 	struct thread *thread;
132 	addr_t framePointer;
133 	int32 i, num = 0, last = 0;
134 
135 	if (argc < 2) {
136 		thread = thread_get_current_thread();
137 		framePointer = (addr_t)get_current_stack_frame();
138 	} else {
139 kprintf("Stack traces of other threads not supported yet!\n");
140 return 0;
141 	}
142 
143 	// We don't have a thread pointer early in the boot process
144 	if (thread != NULL)
145 		frameStack = &thread->arch_info.iframes;
146 	else
147 		frameStack = &gBootFrameStack;
148 
149 	for (i = 0; i < frameStack->index; i++) {
150 		kprintf("iframe %p (end = %p)\n",
151 			frameStack->frames[i], frameStack->frames[i] + 1);
152 	}
153 
154 	if (thread != NULL) {
155 		kprintf("stack trace for thread 0x%lx \"%s\"\n", thread->id,
156 			thread->name);
157 
158 		kprintf("    kernel stack: %p to %p\n",
159 			(void *)thread->kernel_stack_base,
160 			(void *)(thread->kernel_stack_top));
161 		if (thread->user_stack_base != 0) {
162 			kprintf("      user stack: %p to %p\n",
163 				(void *)thread->user_stack_base,
164 				(void *)(thread->user_stack_base + thread->user_stack_size));
165 		}
166 	}
167 
168 	kprintf("frame            caller     <image>:function + offset\n");
169 
170 	for (;;) {
171 		// see if the frame pointer matches the iframe
172 		struct iframe *frame = NULL;
173 		for (i = 0; i < frameStack->index; i++) {
174 			if (framePointer == (addr_t)frameStack->frames[i]) {
175 				// it's an iframe
176 				frame = frameStack->frames[i];
177 				break;
178 			}
179 		}
180 
181 		if (frame) {
182 			kprintf("iframe at %p\n", frame);
183 			kprintf("   d0 0x%08lx    d1 0x%08lx    d2 0x%08lx    d3 0x%08lx\n",
184 				frame->d[0], frame->d[1], frame->d[2], frame->d[3]);
185 			kprintf("   d4 0x%08lx    d5 0x%08lx    d6 0x%08lx    d7 0x%08lx\n",
186 				frame->d[4], frame->d[5], frame->d[6], frame->d[7]);
187 			kprintf("   a0 0x%08lx    a1 0x%08lx    a2 0x%08lx    a3 0x%08lx\n",
188 				frame->a[0], frame->a[1], frame->a[2], frame->a[3]);
189 			kprintf("   a4 0x%08lx    a5 0x%08lx    a6 0x%08lx    a7 0x%08lx (sp)\n",
190 #warning M68K: a7 in iframe ??
191 				frame->a[4], frame->a[5], frame->a[6], -1L);
192 			kprintf("   pc 0x%08lx        sr 0x%04x\n",
193 				frame->cpu.pc, frame->cpu.sr);
194 #warning M68K: missing regs
195 
196 			print_stack_frame(thread, frame->cpu.pc, framePointer, frame->a[6]);
197  			framePointer = frame->a[6];
198 		} else {
199 			addr_t ip, nextFramePointer;
200 
201 			if (get_next_frame(framePointer, &nextFramePointer, &ip) != B_OK) {
202 				kprintf("%08lx -- read fault\n", framePointer);
203 				break;
204 			}
205 
206 			if (ip == 0 || framePointer == 0)
207 				break;
208 
209 			print_stack_frame(thread, ip, framePointer, nextFramePointer);
210 			framePointer = nextFramePointer;
211 		}
212 
213 		if (already_visited(previousLocations, &last, &num, framePointer)) {
214 			kprintf("circular stack frame: %p!\n", (void *)framePointer);
215 			break;
216 		}
217 		if (framePointer == 0)
218 			break;
219 	}
220 
221 
222 	return 0;
223 }
224 
225 */
226 
227 // #pragma mark -
228 
229 
230 void
231 arch_debug_save_registers(int *regs)
232 {
233 }
234 
235 
236 bool
237 arch_debug_contains_call(struct thread *thread, const char *symbol,
238 	addr_t start, addr_t end)
239 {
240 	return false;
241 }
242 
243 
244 void
245 arch_debug_stack_trace(void)
246 {
247 }
248 
249 
250 void *
251 arch_debug_get_caller(void)
252 {
253 #warning ARM:IMPLEMENT
254 	// TODO: implement me
255 	//return __builtin_frame_address(1);
256 //	struct stack_frame *frame;
257 	//frame = __builtin_frame_address(0);
258 //	frame = get_current_stack_frame();
259 //	return (void *)frame->previous->return_address;
260 	return NULL;
261 }
262 
263 
264 /*!	Captures a stack trace (the return addresses) of the current thread.
265 	\param returnAddresses The array the return address shall be written to.
266 	\param maxCount The maximum number of return addresses to be captured.
267 	\param skipIframes The number of interrupt frames that shall be skipped. If
268 		greater than 0, \a skipFrames is ignored.
269 	\param skipFrames The number of stack frames that shall be skipped.
270 	\param userOnly If \c true, only userland return addresses are captured.
271 	\return The number of return addresses written to the given array.
272 */
273 int32
274 arch_debug_get_stack_trace(addr_t* returnAddresses, int32 maxCount,
275 	int32 skipIframes, int32 skipFrames, bool userOnly)
276 {
277 /*	struct iframe_stack *frameStack;
278 	addr_t framePointer;
279 	int32 count = 0;
280 	int32 i, num = 0, last = 0;
281 
282 	// Keep skipping normal stack frames until we've skipped the iframes we're
283 	// supposed to skip.
284 	if (skipIframes > 0) {
285 		skipFrames = INT_MAX;
286 	} else {
287 		// always skip our own frame
288 		skipFrames++;
289 	}
290 
291 	struct thread* thread = thread_get_current_thread();
292 	framePointer = (addr_t)get_current_stack_frame();
293 
294 	// We don't have a thread pointer early in the boot process
295 	if (thread != NULL)
296 		frameStack = &thread->arch_info.iframes;
297 	else
298 		frameStack = &gBootFrameStack;
299 
300 	while (framePointer != 0 && count < maxCount) {
301 		// see if the frame pointer matches the iframe
302 		struct iframe *frame = NULL;
303 		for (i = 0; i < frameStack->index; i++) {
304 			if (framePointer == (addr_t)frameStack->frames[i]) {
305 				// it's an iframe
306 				frame = frameStack->frames[i];
307 				break;
308 			}
309 		}
310 
311 		addr_t ip;
312 		addr_t nextFrame;
313 
314 		if (frame) {
315 			ip = frame->cpu.pc;
316  			nextFrame = frame->a[6];
317 
318 			if (skipIframes > 0) {
319 				if (--skipIframes == 0)
320 					skipFrames = 0;
321 			}
322 		} else {
323 			if (get_next_frame(framePointer, &nextFrame, &ip) != B_OK)
324 				break;
325 		}
326 
327 		if (skipFrames <= 0 && (!userOnly || IS_USER_ADDRESS(framePointer)))
328 			returnAddresses[count++] = ip;
329 		else
330 			skipFrames--;
331 
332 		framePointer = nextFrame;
333 	}
334 
335 	return count;*/
336 #warning ARM:IMPLEMENT
337 
338 	return 0;
339 }
340 
341 
342 void*
343 arch_debug_get_interrupt_pc(bool* _isSyscall)
344 {
345 	// TODO: Implement!
346 	return NULL;
347 }
348 
349 
350 bool
351 arch_is_debug_variable_defined(const char* variableName)
352 {
353 	// TODO: Implement!
354 	return false;
355 }
356 
357 
358 status_t
359 arch_set_debug_variable(const char* variableName, uint64 value)
360 {
361 	// TODO: Implement!
362 	return B_ENTRY_NOT_FOUND;
363 }
364 
365 
366 status_t
367 arch_get_debug_variable(const char* variableName, uint64* value)
368 {
369 	// TODO: Implement!
370 	return B_ENTRY_NOT_FOUND;
371 }
372 
373 
374 status_t
375 arch_debug_init(kernel_args *args)
376 {
377 //	add_debugger_command("where", &stack_trace, "Same as \"sc\"");
378 //	add_debugger_command("bt", &stack_trace, "Same as \"sc\" (as in gdb)");
379 //	add_debugger_command("sc", &stack_trace, "Stack crawl for current thread");
380 #warning ARM:IMPLEMENT
381 
382 	return B_NO_ERROR;
383 }
384 
385 
386 void
387 arch_debug_call_with_fault_handler(cpu_ent* cpu, jmp_buf jumpBuffer,
388 	void (*function)(void*), void* parameter)
389 {
390 	// TODO: Implement! Most likely in assembly.
391 	longjmp(jumpBuffer, 1);
392 }
393 
394 
395 void
396 arch_debug_unset_current_thread(void)
397 {
398 	// TODO: Implement!
399 }
400 
401 
402