2 * Copyright 2003-2011, Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
6 * Axel Dörfler <axeld@pinc-software.de>
7 * Ingo Weinhold <bonefish@cs.tu-berlin.de>
8 * François Revol <revol@free.fr>
12 #include <arch/debug.h>
23 struct stack_frame
*previous
;
24 addr_t return_address
;
27 #define NUM_PREVIOUS_LOCATIONS 32
29 extern struct iframe_stack gBootFrameStack
;
33 already_visited(uint32
*visited
, int32
*_last
, int32
*_num
, uint32 framePointer
)
39 for (i
= 0; i
< num
; i
++) {
40 if (visited
[(NUM_PREVIOUS_LOCATIONS
+ last
- i
)
41 % NUM_PREVIOUS_LOCATIONS
] == framePointer
) {
46 *_last
= last
= (last
+ 1) % NUM_PREVIOUS_LOCATIONS
;
47 visited
[last
] = framePointer
;
49 if (num
< NUM_PREVIOUS_LOCATIONS
)
56 static inline stack_frame
*
57 get_current_stack_frame()
60 asm volatile("move.l %%fp,%0" : "=r"(frame
));
66 get_next_frame(addr_t framePointer
, addr_t
*next
, addr_t
*ip
)
69 if (debug_memcpy(B_CURRENT_TEAM
, &frame
, (void*)framePointer
, sizeof(frame
))
74 *ip
= frame
.return_address
;
75 *next
= (addr_t
)frame
.previous
;
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)
92 const char *symbol
, *image
;
95 status_t status
= elf_debug_lookup_symbol_address(ip
, &baseAddress
, &symbol
,
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)"));
108 kprintf("%08lx (+%4ld) %08lx <%s@%p>:unknown + 0x%04lx\n",
109 framePointer
, diff
, ip
, image
, (void *)baseAddress
,
113 kprintf("%08lx (+%4ld) %08lx\n", framePointer
, diff
, ip
);
118 stack_trace(int argc
, char **argv
)
120 uint32 previousLocations
[NUM_PREVIOUS_LOCATIONS
];
121 struct iframe_stack
*frameStack
;
124 int32 i
, num
= 0, last
= 0;
127 thread
= thread_get_current_thread();
128 framePointer
= (addr_t
)get_current_stack_frame();
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);
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");
157 // We don't have a thread pointer early in the boot process
159 frameStack
= &thread
->arch_info
.iframes
;
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
,
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");
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
]) {
190 frame
= frameStack
->frames
[i
];
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];
216 addr_t ip
, nextFramePointer
;
218 if (get_next_frame(framePointer
, &nextFramePointer
, &ip
) != B_OK
) {
219 kprintf("%08lx -- read fault\n", framePointer
);
223 if (ip
== 0 || framePointer
== 0)
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
);
234 if (framePointer
== 0)
238 /* if (oldPageDirectory != 0) {
239 // switch back to the previous page directory to no cause any troubles
240 write_cr3(oldPageDirectory);
253 arch_debug_save_registers(struct arch_debug_registers
* registers
)
259 arch_debug_stack_trace(void)
265 arch_debug_contains_call(Thread
*thread
, const char *symbol
,
266 addr_t start
, addr_t end
)
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
;
285 arch_debug_get_stack_trace(addr_t
* returnAddresses
, int32 maxCount
,
286 int32 skipIframes
, int32 skipFrames
, uint32 flags
)
288 struct iframe_stack
*frameStack
;
291 int32 i
, num
= 0, last
= 0;
293 // Keep skipping normal stack frames until we've skipped the iframes we're
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
304 frameStack
= &thread
->arch_info
.iframes
;
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)
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
]) {
319 frame
= frameStack
->frames
[i
];
329 nextFrame
= frame
->a
[6];
331 if (skipIframes
> 0) {
332 if (--skipIframes
== 0)
336 if (get_next_frame(framePointer
, &nextFrame
, &ip
) != B_OK
)
341 && ((flags
& STACK_TRACE_KERNEL
) != 0 || onKernelStack
)) {
342 returnAddresses
[count
++] = ip
;
346 framePointer
= nextFrame
;
354 arch_debug_get_interrupt_pc(bool* _isSyscall
)
362 arch_debug_unset_current_thread(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);
378 arch_is_debug_variable_defined(const char* variableName
)
386 arch_set_debug_variable(const char* variableName
, uint64 value
)
389 return B_ENTRY_NOT_FOUND
;
394 arch_get_debug_variable(const char* variableName
, uint64
* value
)
397 return B_ENTRY_NOT_FOUND
;
402 arch_debug_gdb_get_registers(char* buffer
, size_t bufferSize
)
405 return B_NOT_SUPPORTED
;
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");