xref: /haiku/src/system/kernel/arch/ppc/arch_debug.cpp (revision 37c7d5d83a2372a6971e383411d5bacbeef0ebdc)
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  */
9 
10 
11 #include <arch/debug.h>
12 
13 #include <arch_cpu.h>
14 #include <debug.h>
15 #include <elf.h>
16 #include <kernel.h>
17 #include <kimage.h>
18 #include <thread.h>
19 
20 
21 struct stack_frame {
22 	struct stack_frame	*previous;
23 	addr_t				return_address;
24 };
25 
26 #define NUM_PREVIOUS_LOCATIONS 32
27 
28 extern struct iframe_stack gBootFrameStack;
29 
30 
31 static bool
32 already_visited(uint32 *visited, int32 *_last, int32 *_num, uint32 framePointer)
33 {
34 	int32 last = *_last;
35 	int32 num = *_num;
36 	int32 i;
37 
38 	for (i = 0; i < num; i++) {
39 		if (visited[(NUM_PREVIOUS_LOCATIONS + last - i)
40 				% NUM_PREVIOUS_LOCATIONS] == framePointer) {
41 			return true;
42 		}
43 	}
44 
45 	*_last = last = (last + 1) % NUM_PREVIOUS_LOCATIONS;
46 	visited[last] = framePointer;
47 
48 	if (num < NUM_PREVIOUS_LOCATIONS)
49 		*_num = num + 1;
50 
51 	return false;
52 }
53 
54 
55 static inline stack_frame *
56 get_current_stack_frame()
57 {
58 	stack_frame *frame;
59 	asm volatile("mr %0, %%r1" : "=r"(frame));
60 	return frame;
61 }
62 
63 
64 static status_t
65 get_next_frame(addr_t framePointer, addr_t *next, addr_t *ip)
66 {
67 	stack_frame frame;
68 	if (debug_memcpy(B_CURRENT_TEAM, &frame, (void*)framePointer, sizeof(frame))
69 			!= B_OK) {
70 		return B_BAD_ADDRESS;
71 	}
72 
73 	*ip = frame.return_address;
74 	*next = (addr_t)frame.previous;
75 
76 	return B_OK;
77 }
78 
79 
80 static void
81 print_stack_frame(struct thread *thread, addr_t ip, addr_t framePointer,
82 	addr_t nextFramePointer)
83 {
84 	addr_t diff = nextFramePointer - framePointer;
85 
86 	// kernel space/user space switch
87 	if (diff & 0x80000000)
88 		diff = 0;
89 
90 	// lookup symbol
91 	const char *symbol, *image;
92 	addr_t baseAddress;
93 	bool exactMatch;
94 	status_t status = elf_debug_lookup_symbol_address(ip, &baseAddress, &symbol,
95 		&image, &exactMatch);
96 	if (status != B_OK && !IS_KERNEL_ADDRESS(ip) && thread) {
97 		// try to locate the image in the images loaded into user space
98 		status = image_debug_lookup_user_symbol_address(thread->team, ip,
99 			&baseAddress, &symbol, &image, &exactMatch);
100 	}
101 	if (status == B_OK) {
102 		if (symbol != NULL) {
103 			kprintf("%08lx (+%4ld) %08lx   <%s>:%s + 0x%04lx%s\n", framePointer,
104 				diff, ip, image, symbol, ip - baseAddress,
105 				(exactMatch ? "" : " (nearest)"));
106 		} else {
107 			kprintf("%08lx (+%4ld) %08lx   <%s@%p>:unknown + 0x%04lx\n",
108 				framePointer, diff, ip, image, (void *)baseAddress,
109 				ip - baseAddress);
110 		}
111 	} else
112 		kprintf("%08lx (+%4ld) %08lx\n", framePointer, diff, ip);
113 }
114 
115 
116 static int
117 stack_trace(int argc, char **argv)
118 {
119 	uint32 previousLocations[NUM_PREVIOUS_LOCATIONS];
120 	struct iframe_stack *frameStack;
121 	struct thread *thread;
122 	addr_t framePointer;
123 	int32 i, num = 0, last = 0;
124 
125 	if (argc < 2) {
126 		thread = thread_get_current_thread();
127 		framePointer = (addr_t)get_current_stack_frame();
128 	} else {
129 // TODO: Add support for stack traces of other threads.
130 /*		thread_id id = strtoul(argv[1], NULL, 0);
131 		thread = thread_get_thread_struct_locked(id);
132 		if (thread == NULL) {
133 			kprintf("could not find thread %ld\n", id);
134 			return 0;
135 		}
136 
137 		// read %ebp from the thread's stack stored by a pushad
138 		ebp = thread->arch_info.current_stack.esp[2];
139 
140 		if (id != thread_get_current_thread_id()) {
141 			// switch to the page directory of the new thread to be
142 			// able to follow the stack trace into userland
143 			addr_t newPageDirectory = (addr_t)x86_next_page_directory(
144 				thread_get_current_thread(), thread);
145 
146 			if (newPageDirectory != 0) {
147 				read_cr3(oldPageDirectory);
148 				write_cr3(newPageDirectory);
149 			}
150 		}
151 */
152 kprintf("Stack traces of other threads not supported yet!\n");
153 return 0;
154 	}
155 
156 	// We don't have a thread pointer early in the boot process
157 	if (thread != NULL)
158 		frameStack = &thread->arch_info.iframes;
159 	else
160 		frameStack = &gBootFrameStack;
161 
162 	for (i = 0; i < frameStack->index; i++) {
163 		kprintf("iframe %p (end = %p)\n",
164 			frameStack->frames[i], frameStack->frames[i] + 1);
165 	}
166 
167 	if (thread != NULL) {
168 		kprintf("stack trace for thread 0x%lx \"%s\"\n", thread->id,
169 			thread->name);
170 
171 		kprintf("    kernel stack: %p to %p\n",
172 			(void *)thread->kernel_stack_base,
173 			(void *)(thread->kernel_stack_top));
174 		if (thread->user_stack_base != 0) {
175 			kprintf("      user stack: %p to %p\n",
176 				(void *)thread->user_stack_base,
177 				(void *)(thread->user_stack_base + thread->user_stack_size));
178 		}
179 	}
180 
181 	kprintf("frame            caller     <image>:function + offset\n");
182 
183 	for (;;) {
184 		// see if the frame pointer matches the iframe
185 		struct iframe *frame = NULL;
186 		for (i = 0; i < frameStack->index; i++) {
187 			if (framePointer == (((addr_t)frameStack->frames[i] - 8) & ~0xf)) {
188 				// it's an iframe
189 				frame = frameStack->frames[i];
190 				break;
191 			}
192 		}
193 
194 		if (frame) {
195 			kprintf("iframe at %p\n", frame);
196 			kprintf("   r0 0x%08lx    r1 0x%08lx    r2 0x%08lx    r3 0x%08lx\n",
197 				frame->r0, frame->r1, frame->r2, frame->r3);
198 			kprintf("   r4 0x%08lx    r5 0x%08lx    r6 0x%08lx    r7 0x%08lx\n",
199 				frame->r4, frame->r5, frame->r6, frame->r7);
200 			kprintf("   r8 0x%08lx    r9 0x%08lx   r10 0x%08lx   r11 0x%08lx\n",
201 				frame->r8, frame->r9, frame->r10, frame->r11);
202 			kprintf("  r12 0x%08lx   r13 0x%08lx   r14 0x%08lx   r15 0x%08lx\n",
203 				frame->r12, frame->r13, frame->r14, frame->r15);
204 			kprintf("  r16 0x%08lx   r17 0x%08lx   r18 0x%08lx   r19 0x%08lx\n",
205 				frame->r16, frame->r17, frame->r18, frame->r19);
206 			kprintf("  r20 0x%08lx   r21 0x%08lx   r22 0x%08lx   r23 0x%08lx\n",
207 				frame->r20, frame->r21, frame->r22, frame->r23);
208 			kprintf("  r24 0x%08lx   r25 0x%08lx   r26 0x%08lx   r27 0x%08lx\n",
209 				frame->r24, frame->r25, frame->r26, frame->r27);
210 			kprintf("  r28 0x%08lx   r29 0x%08lx   r30 0x%08lx   r31 0x%08lx\n",
211 				frame->r28, frame->r29, frame->r30, frame->r31);
212 			kprintf("   lr 0x%08lx    cr 0x%08lx   xer 0x%08lx   ctr 0x%08lx\n",
213 				frame->lr, frame->cr, frame->xer, frame->ctr);
214 			kprintf("fpscr 0x%08lx\n", frame->fpscr);
215 			kprintf(" srr0 0x%08lx  srr1 0x%08lx   dar 0x%08lx dsisr 0x%08lx\n",
216 				frame->srr0, frame->srr1, frame->dar, frame->dsisr);
217 			kprintf(" vector: 0x%lx\n", frame->vector);
218 
219 			print_stack_frame(thread, frame->srr0, framePointer, frame->r1);
220  			framePointer = frame->r1;
221 		} else {
222 			addr_t ip, nextFramePointer;
223 
224 			if (get_next_frame(framePointer, &nextFramePointer, &ip) != B_OK) {
225 				kprintf("%08lx -- read fault\n", framePointer);
226 				break;
227 			}
228 
229 			if (ip == 0 || framePointer == 0)
230 				break;
231 
232 			print_stack_frame(thread, ip, framePointer, nextFramePointer);
233 			framePointer = nextFramePointer;
234 		}
235 
236 		if (already_visited(previousLocations, &last, &num, framePointer)) {
237 			kprintf("circular stack frame: %p!\n", (void *)framePointer);
238 			break;
239 		}
240 		if (framePointer == 0)
241 			break;
242 	}
243 
244 /*	if (oldPageDirectory != 0) {
245 		// switch back to the previous page directory to no cause any troubles
246 		write_cr3(oldPageDirectory);
247 	}
248 */
249 
250 	return 0;
251 }
252 
253 
254 
255 // #pragma mark -
256 
257 
258 void
259 arch_debug_save_registers(struct arch_debug_registers* registers)
260 {
261 }
262 
263 
264 void
265 arch_debug_stack_trace(void)
266 {
267 	stack_trace(0, NULL);
268 }
269 
270 
271 bool
272 arch_debug_contains_call(struct thread *thread, const char *symbol,
273 	addr_t start, addr_t end)
274 {
275 	return false;
276 }
277 
278 
279 void *
280 arch_debug_get_caller(void)
281 {
282 	// TODO: implement me
283 	return (void *)&arch_debug_get_caller;
284 }
285 
286 
287 int32
288 arch_debug_get_stack_trace(addr_t* returnAddresses, int32 maxCount,
289 	int32 skipIframes, int32 skipFrames, uint32 flags)
290 {
291 	// TODO: Implement!
292 	return 0;
293 }
294 
295 
296 void*
297 arch_debug_get_interrupt_pc(bool* _isSyscall)
298 {
299 	// TODO: Implement!
300 	return NULL;
301 }
302 
303 
304 void
305 arch_debug_unset_current_thread(void)
306 {
307 	// TODO: Implement!
308 }
309 
310 
311 void
312 arch_debug_call_with_fault_handler(cpu_ent* cpu, jmp_buf jumpBuffer,
313 	void (*function)(void*), void* parameter)
314 {
315 	// TODO: Implement! Most likely in assembly.
316 	longjmp(jumpBuffer, 1);
317 }
318 
319 
320 bool
321 arch_is_debug_variable_defined(const char* variableName)
322 {
323 	// TODO: Implement!
324 	return false;
325 }
326 
327 
328 status_t
329 arch_set_debug_variable(const char* variableName, uint64 value)
330 {
331 	// TODO: Implement!
332 	return B_ENTRY_NOT_FOUND;
333 }
334 
335 
336 status_t
337 arch_get_debug_variable(const char* variableName, uint64* value)
338 {
339 	// TODO: Implement!
340 	return B_ENTRY_NOT_FOUND;
341 }
342 
343 
344 status_t
345 arch_debug_init(kernel_args *args)
346 {
347 	add_debugger_command("where", &stack_trace, "Same as \"sc\"");
348 	add_debugger_command("bt", &stack_trace, "Same as \"sc\" (as in gdb)");
349 	add_debugger_command("sc", &stack_trace, "Stack crawl for current thread");
350 
351 	return B_NO_ERROR;
352 }
353 
354