vfs: check userland buffers before reading them.
[haiku.git] / src / system / kernel / arch / m68k / arch_debug.cpp
blobeaa3819d418b315bcfecbfb2e40e3da0b4d1fddc
1 /*
2 * Copyright 2003-2011, Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
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 */
12 #include <arch/debug.h>
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>
22 struct stack_frame {
23 struct stack_frame *previous;
24 addr_t return_address;
27 #define NUM_PREVIOUS_LOCATIONS 32
29 extern struct iframe_stack gBootFrameStack;
32 static bool
33 already_visited(uint32 *visited, int32 *_last, int32 *_num, uint32 framePointer)
35 int32 last = *_last;
36 int32 num = *_num;
37 int32 i;
39 for (i = 0; i < num; i++) {
40 if (visited[(NUM_PREVIOUS_LOCATIONS + last - i)
41 % NUM_PREVIOUS_LOCATIONS] == framePointer) {
42 return true;
46 *_last = last = (last + 1) % NUM_PREVIOUS_LOCATIONS;
47 visited[last] = framePointer;
49 if (num < NUM_PREVIOUS_LOCATIONS)
50 *_num = num + 1;
52 return false;
56 static inline stack_frame *
57 get_current_stack_frame()
59 stack_frame *frame;
60 asm volatile("move.l %%fp,%0" : "=r"(frame));
61 return frame;
65 static status_t
66 get_next_frame(addr_t framePointer, addr_t *next, addr_t *ip)
68 stack_frame frame;
69 if (debug_memcpy(B_CURRENT_TEAM, &frame, (void*)framePointer, sizeof(frame))
70 != B_OK) {
71 return B_BAD_ADDRESS;
74 *ip = frame.return_address;
75 *next = (addr_t)frame.previous;
77 return B_OK;
81 static void
82 print_stack_frame(Thread *thread, addr_t ip, addr_t framePointer,
83 addr_t nextFramePointer)
85 addr_t diff = nextFramePointer - framePointer;
87 // kernel space/user space switch
88 if (diff & 0x80000000)
89 diff = 0;
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);
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);
112 } else
113 kprintf("%08lx (+%4ld) %08lx\n", framePointer, diff, ip);
117 static int
118 stack_trace(int argc, char **argv)
120 uint32 previousLocations[NUM_PREVIOUS_LOCATIONS];
121 struct iframe_stack *frameStack;
122 Thread *thread;
123 addr_t framePointer;
124 int32 i, num = 0, last = 0;
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::GetDebug(id);
133 if (thread == NULL) {
134 kprintf("could not find thread %ld\n", id);
135 return 0;
138 // read %ebp from the thread's stack stored by a pushad
139 ebp = thread->arch_info.current_stack.esp[2];
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);
147 if (newPageDirectory != 0) {
148 read_cr3(oldPageDirectory);
149 write_cr3(newPageDirectory);
153 kprintf("Stack traces of other threads not supported yet!\n");
154 return 0;
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;
163 for (i = 0; i < frameStack->index; i++) {
164 kprintf("iframe %p (end = %p)\n",
165 frameStack->frames[i], frameStack->frames[i] + 1);
168 if (thread != NULL) {
169 kprintf("stack trace for thread 0x%lx \"%s\"\n", thread->id,
170 thread->name);
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));
182 kprintf("frame caller <image>:function + offset\n");
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;
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]*/);
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
213 print_stack_frame(thread, frame->cpu.pc, framePointer, frame->a[6]);
214 framePointer = frame->a[6];
215 } else {
216 addr_t ip, nextFramePointer;
218 if (get_next_frame(framePointer, &nextFramePointer, &ip) != B_OK) {
219 kprintf("%08lx -- read fault\n", framePointer);
220 break;
223 if (ip == 0 || framePointer == 0)
224 break;
226 print_stack_frame(thread, ip, framePointer, nextFramePointer);
227 framePointer = nextFramePointer;
230 if (already_visited(previousLocations, &last, &num, framePointer)) {
231 kprintf("circular stack frame: %p!\n", (void *)framePointer);
232 break;
234 if (framePointer == 0)
235 break;
238 /* if (oldPageDirectory != 0) {
239 // switch back to the previous page directory to no cause any troubles
240 write_cr3(oldPageDirectory);
244 return 0;
249 // #pragma mark -
252 void
253 arch_debug_save_registers(struct arch_debug_registers* registers)
258 void
259 arch_debug_stack_trace(void)
264 bool
265 arch_debug_contains_call(Thread *thread, const char *symbol,
266 addr_t start, addr_t end)
268 return false;
272 void *
273 arch_debug_get_caller(void)
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;
284 int32
285 arch_debug_get_stack_trace(addr_t* returnAddresses, int32 maxCount,
286 int32 skipIframes, int32 skipFrames, uint32 flags)
288 struct iframe_stack *frameStack;
289 addr_t framePointer;
290 int32 count = 0;
291 int32 i, num = 0, last = 0;
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;
298 Thread* thread = thread_get_current_thread();
299 framePointer = (addr_t)get_current_stack_frame();
300 bool onKernelStack = true;
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;
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;
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;
324 addr_t ip;
325 addr_t nextFrame;
327 if (frame) {
328 ip = frame->cpu.pc;
329 nextFrame = frame->a[6];
331 if (skipIframes > 0) {
332 if (--skipIframes == 0)
333 skipFrames = 0;
335 } else {
336 if (get_next_frame(framePointer, &nextFrame, &ip) != B_OK)
337 break;
340 if (skipFrames <= 0
341 && ((flags & STACK_TRACE_KERNEL) != 0 || onKernelStack)) {
342 returnAddresses[count++] = ip;
343 } else
344 skipFrames--;
346 framePointer = nextFrame;
349 return count;
353 void*
354 arch_debug_get_interrupt_pc(bool* _isSyscall)
356 // TODO: Implement!
357 return NULL;
361 void
362 arch_debug_unset_current_thread(void)
364 // TODO: Implement!
368 void
369 arch_debug_call_with_fault_handler(cpu_ent* cpu, jmp_buf jumpBuffer,
370 void (*function)(void*), void* parameter)
372 // TODO: Implement! Most likely in assembly.
373 longjmp(jumpBuffer, 1);
377 bool
378 arch_is_debug_variable_defined(const char* variableName)
380 // TODO: Implement!
381 return false;
385 status_t
386 arch_set_debug_variable(const char* variableName, uint64 value)
388 // TODO: Implement!
389 return B_ENTRY_NOT_FOUND;
393 status_t
394 arch_get_debug_variable(const char* variableName, uint64* value)
396 // TODO: Implement!
397 return B_ENTRY_NOT_FOUND;
401 ssize_t
402 arch_debug_gdb_get_registers(char* buffer, size_t bufferSize)
404 // TODO: Implement!
405 return B_NOT_SUPPORTED;
409 status_t
410 arch_debug_init(kernel_args *args)
412 add_debugger_command("where", &stack_trace, "Same as \"sc\"");
413 add_debugger_command("bt", &stack_trace, "Same as \"sc\" (as in gdb)");
414 add_debugger_command("sc", &stack_trace, "Stack crawl for current thread");
416 return B_NO_ERROR;