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