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