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>
9 * Ithamar R. Adema <ithamar@upgrade-android.com>
14 #include <arch/debug.h>
18 #include <debug_heap.h>
23 #include <vm/vm_types.h>
24 #include <vm/VMAddressSpace.h>
25 #include <vm/VMArea.h>
27 #define NUM_PREVIOUS_LOCATIONS 32
29 extern struct iframe_stack gBootFrameStack
;
33 already_visited(uint32
*visited
, int32
*_last
, int32
*_num
, uint32 fp
)
39 for (i
= 0; i
< num
; i
++) {
40 if (visited
[(NUM_PREVIOUS_LOCATIONS
+ last
- i
)
41 % NUM_PREVIOUS_LOCATIONS
] == fp
) {
46 *_last
= last
= (last
+ 1) % NUM_PREVIOUS_LOCATIONS
;
49 if (num
< NUM_PREVIOUS_LOCATIONS
)
57 get_next_frame(addr_t fp
, addr_t
*next
, addr_t
*ip
)
60 addr_t _fp
= *(((addr_t
*)fp
) -3);
61 addr_t _sp
= *(((addr_t
*)fp
) -2);
62 addr_t _lr
= *(((addr_t
*)fp
) -1);
63 addr_t _pc
= *(((addr_t
*)fp
) -0);
65 *ip
= (_fp
!= 0) ? _lr
: _pc
;
76 lookup_symbol(Thread
* thread
, addr_t address
, addr_t
* _baseAddress
,
77 const char** _symbolName
, const char** _imageName
, bool* _exactMatch
)
79 status_t status
= B_ENTRY_NOT_FOUND
;
81 if (IS_KERNEL_ADDRESS(address
)) {
83 status
= elf_debug_lookup_symbol_address(address
, _baseAddress
,
84 _symbolName
, _imageName
, _exactMatch
);
85 } else if (thread
!= NULL
&& thread
->team
!= NULL
) {
86 // try a lookup using the userland runtime loader structures
87 status
= elf_debug_lookup_user_symbol_address(thread
->team
, address
,
88 _baseAddress
, _symbolName
, _imageName
, _exactMatch
);
91 // try to locate the image in the images loaded into user space
92 status
= image_debug_lookup_user_symbol_address(thread
->team
,
93 address
, _baseAddress
, _symbolName
, _imageName
, _exactMatch
);
102 set_debug_argument_variable(int32 index
, uint64 value
)
105 snprintf(name
, sizeof(name
), "_arg%ld", index
);
106 set_debug_variable(name
, value
);
110 template<typename Type
>
112 read_function_argument_value(void* argument
, bool& _valueKnown
)
115 if (debug_memcpy(B_CURRENT_TEAM
, &value
, argument
, sizeof(Type
)) == B_OK
) {
126 print_demangled_call(const char* image
, const char* symbol
, addr_t args
,
127 bool noObjectMethod
, bool addDebugVariables
)
129 static const size_t kBufferSize
= 256;
130 char* buffer
= (char*)debug_malloc(kBufferSize
);
135 const char* name
= debug_demangle_symbol(symbol
, buffer
, kBufferSize
,
142 uint32
* arg
= (uint32
*)args
;
145 isObjectMethod
= false;
146 if (isObjectMethod
) {
147 const char* lastName
= strrchr(name
, ':') - 1;
148 int namespaceLength
= lastName
- name
;
151 if (debug_memcpy(B_CURRENT_TEAM
, &argValue
, arg
, 4) == B_OK
) {
152 kprintf("<%s> %.*s<\33[32m%#" B_PRIx32
"\33[0m>%s", image
,
153 namespaceLength
, name
, argValue
, lastName
);
155 kprintf("<%s> %.*s<???>%s", image
, namespaceLength
, name
, lastName
);
157 if (addDebugVariables
)
158 set_debug_variable("_this", argValue
);
161 kprintf("<%s> %s", image
, name
);
168 while (debug_get_next_demangled_argument(&cookie
, symbol
, buffer
,
169 kBufferSize
, &type
, &length
) == B_OK
) {
173 // retrieve value and type identifier
176 bool valueKnown
= false;
180 value
= read_function_argument_value
<int64
>(arg
, valueKnown
);
182 kprintf("int64: \33[34m%Ld\33[0m", value
);
185 value
= read_function_argument_value
<int32
>(arg
, valueKnown
);
187 kprintf("int32: \33[34m%ld\33[0m", (int32
)value
);
190 value
= read_function_argument_value
<int16
>(arg
, valueKnown
);
192 kprintf("int16: \33[34m%d\33[0m", (int16
)value
);
195 value
= read_function_argument_value
<int8
>(arg
, valueKnown
);
197 kprintf("int8: \33[34m%d\33[0m", (int8
)value
);
200 value
= read_function_argument_value
<uint64
>(arg
, valueKnown
);
202 kprintf("uint64: \33[34m%#Lx\33[0m", value
);
203 if (value
< 0x100000)
204 kprintf(" (\33[34m%Lu\33[0m)", value
);
208 value
= read_function_argument_value
<uint32
>(arg
, valueKnown
);
210 kprintf("uint32: \33[34m%#lx\33[0m", (uint32
)value
);
211 if (value
< 0x100000)
212 kprintf(" (\33[34m%lu\33[0m)", (uint32
)value
);
216 value
= read_function_argument_value
<uint16
>(arg
, valueKnown
);
218 kprintf("uint16: \33[34m%#x\33[0m (\33[34m%u\33[0m)",
219 (uint16
)value
, (uint16
)value
);
223 value
= read_function_argument_value
<uint8
>(arg
, valueKnown
);
225 kprintf("uint8: \33[34m%#x\33[0m (\33[34m%u\33[0m)",
226 (uint8
)value
, (uint8
)value
);
230 value
= read_function_argument_value
<uint8
>(arg
, valueKnown
);
232 kprintf("\33[34m%s\33[0m", value
? "true" : "false");
236 kprintf("%s: ", buffer
);
239 value
= read_function_argument_value
<uint32
>(arg
,
243 && (type
== B_POINTER_TYPE
|| type
== B_REF_TYPE
))
246 kprintf("\33[34m%#lx\33[0m", (uint32
)value
);
253 value
= read_function_argument_value
<uint64
>(arg
,
259 kprintf("\33[34m%#Lx\33[0m", value
);
266 if (valueKnown
&& type
== B_STRING_TYPE
) {
268 kprintf(" \33[31m\"<NULL>\"\33[0m");
269 else if (debug_strlcpy(B_CURRENT_TEAM
, buffer
, (char*)(addr_t
)value
,
270 kBufferSize
) < B_OK
) {
271 kprintf(" \33[31m\"<???>\"\33[0m");
273 kprintf(" \33[36m\"%s\"\33[0m", buffer
);
276 if (addDebugVariables
)
277 set_debug_argument_variable(i
, value
);
278 arg
= (uint32
*)((uint8
*)arg
+ length
);
290 print_stack_frame(Thread
*thread
, addr_t ip
, addr_t fp
, addr_t next
,
291 int32 callIndex
, bool demangle
)
302 // MSB set = kernel space/user space switch
303 if (diff
& ~((addr_t
)-1 >> 1))
306 status
= lookup_symbol(thread
, ip
, &baseAddress
, &symbol
, &image
,
309 kprintf("%2" B_PRId32
" %0*lx (+%4ld) %0*lx ", callIndex
,
310 B_PRINTF_POINTER_WIDTH
, fp
, diff
, B_PRINTF_POINTER_WIDTH
, ip
);
312 if (status
== B_OK
) {
313 if (exactMatch
&& demangle
) {
314 status
= print_demangled_call(image
, symbol
,
318 if (!exactMatch
|| !demangle
|| status
!= B_OK
) {
319 if (symbol
!= NULL
) {
320 kprintf("<%s> %s%s", image
, symbol
,
321 exactMatch
? "" : " (nearest)");
323 kprintf("<%s@%p> <unknown>", image
, (void*)baseAddress
);
326 kprintf(" + %#04lx\n", ip
- baseAddress
);
329 if (thread
!= NULL
&& thread
->team
!= NULL
330 && thread
->team
->address_space
!= NULL
) {
331 area
= thread
->team
->address_space
->LookupArea(ip
);
334 kprintf("%" B_PRId32
":%s@%p + %#lx\n", area
->id
, area
->name
,
335 (void*)area
->Base(), ip
- area
->Base());
342 stack_trace(int argc
, char **argv
)
344 static const char* usage
= "usage: %s [-d] [ <thread id> ]\n"
345 "Prints a stack trace for the current, respectively the specified\n"
347 " -d - Disables the demangling of the symbols.\n"
348 " <thread id> - The ID of the thread for which to print the stack\n"
350 bool demangle
= true;
351 int32 threadIndex
= 1;
352 if (argc
> 1 && !strcmp(argv
[1], "-d")) {
357 if (argc
> threadIndex
+ 1
358 || (argc
== 2 && strcmp(argv
[1], "--help") == 0)) {
359 kprintf(usage
, argv
[0]);
363 addr_t previousLocations
[NUM_PREVIOUS_LOCATIONS
];
364 Thread
* thread
= NULL
;
365 phys_addr_t oldPageDirectory
= 0;
366 addr_t fp
= arm_get_fp();
367 int32 num
= 0, last
= 0;
368 struct iframe_stack
*frameStack
;
370 // We don't have a thread pointer early in the boot process
372 frameStack
= &thread
->arch_info
.iframes
;
374 frameStack
= &gBootFrameStack
;
377 for (i
= 0; i
< frameStack
->index
; i
++) {
378 kprintf("iframe %p (end = %p)\n",
379 frameStack
->frames
[i
], frameStack
->frames
[i
] + 1);
382 if (thread
!= NULL
) {
383 kprintf("stack trace for thread 0x%lx \"%s\"\n", thread
->id
,
386 kprintf(" kernel stack: %p to %p\n",
387 (void *)thread
->kernel_stack_base
,
388 (void *)(thread
->kernel_stack_top
));
389 if (thread
->user_stack_base
!= 0) {
390 kprintf(" user stack: %p to %p\n",
391 (void *)thread
->user_stack_base
,
392 (void *)(thread
->user_stack_base
+ thread
->user_stack_size
));
396 kprintf("frame caller <image>:function + offset\n");
398 for (int32 callIndex
= 0;; callIndex
++) {
399 // see if the frame pointer matches the iframe
400 struct iframe
*frame
= NULL
;
401 for (i
= 0; i
< frameStack
->index
; i
++) {
402 if (fp
== (addr_t
)frameStack
->frames
[i
]) {
404 frame
= frameStack
->frames
[i
];
410 kprintf("iframe at %p\n", frame
);
411 kprintf(" r0 0x%08lx r1 0x%08lx r2 0x%08lx r3 0x%08lx\n",
412 frame
->r0
, frame
->r1
, frame
->r2
, frame
->r3
);
413 kprintf(" r4 0x%08lx r5 0x%08lx r6 0x%08lx r7 0x%08lx\n",
414 frame
->r4
, frame
->r5
, frame
->r6
, frame
->r7
);
415 kprintf(" r8 0x%08lx r9 0x%08lx r10 0x%08lx r11 0x%08lx\n",
416 frame
->r8
, frame
->r9
, frame
->r10
, frame
->r11
);
417 kprintf(" r12 0x%08lx sp 0x%08lx lr 0x%08lx pc 0x%08lx\n",
418 frame
->r12
, frame
->svc_sp
, frame
->svc_lr
, frame
->pc
);
421 print_stack_frame(thread
, frame
->pc
, frame
->svc_sp
, frame
->svc_lr
, callIndex
, demangle
);
425 if (get_next_frame(fp
, &next
, &ip
) != B_OK
) {
426 kprintf("%08lx -- read fault\n", fp
);
430 if (ip
== 0 || fp
== 0)
433 print_stack_frame(thread
, ip
, fp
, next
, callIndex
, demangle
);
437 if (already_visited(previousLocations
, &last
, &num
, fp
)) {
438 kprintf("circular stack frame: %p!\n", (void *)fp
);
453 arch_debug_save_registers(struct arch_debug_registers
* registers
)
459 arch_debug_contains_call(Thread
*thread
, const char *symbol
,
460 addr_t start
, addr_t end
)
467 arch_debug_stack_trace(void)
469 stack_trace(0, NULL
);
474 arch_debug_get_caller(void)
476 /* Return the thread id as the kernel (for example the lock code) actually
477 gets a somewhat valid indication of the caller back. */
478 return (void*) thread_get_current_thread_id();
483 arch_debug_get_stack_trace(addr_t
* returnAddresses
, int32 maxCount
,
484 int32 skipIframes
, int32 skipFrames
, uint32 flags
)
492 arch_debug_get_interrupt_pc(bool* _isSyscall
)
500 arch_is_debug_variable_defined(const char* variableName
)
508 arch_set_debug_variable(const char* variableName
, uint64 value
)
511 return B_ENTRY_NOT_FOUND
;
516 arch_get_debug_variable(const char* variableName
, uint64
* value
)
519 return B_ENTRY_NOT_FOUND
;
524 arch_debug_init(kernel_args
*args
)
526 add_debugger_command("where", &stack_trace
, "Same as \"sc\"");
527 add_debugger_command("bt", &stack_trace
, "Same as \"sc\" (as in gdb)");
528 add_debugger_command("sc", &stack_trace
, "Stack crawl for current thread");
534 /* arch_debug_call_with_fault_handler is in arch_asm.S */
537 arch_debug_unset_current_thread(void)
544 arch_debug_gdb_get_registers(char* buffer
, size_t bufferSize
)
547 return B_NOT_SUPPORTED
;