btrfs: Attempt to fix GCC2 build.
[haiku.git] / src / system / kernel / arch / arm / arch_debug.cpp
blob1832ca2962833a1a0f804a3019ef2230f5029bdb
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 * Ithamar R. Adema <ithamar@upgrade-android.com>
14 #include <arch/debug.h>
16 #include <arch_cpu.h>
17 #include <debug.h>
18 #include <debug_heap.h>
19 #include <elf.h>
20 #include <kernel.h>
21 #include <kimage.h>
22 #include <thread.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;
32 static bool
33 already_visited(uint32 *visited, int32 *_last, int32 *_num, uint32 fp)
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] == fp) {
42 return true;
46 *_last = last = (last + 1) % NUM_PREVIOUS_LOCATIONS;
47 visited[last] = fp;
49 if (num < NUM_PREVIOUS_LOCATIONS)
50 *_num = num + 1;
52 return false;
56 static status_t
57 get_next_frame(addr_t fp, addr_t *next, addr_t *ip)
59 if (fp != 0) {
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;
66 *next = _fp;
68 return B_OK;
71 return B_BAD_VALUE;
75 static status_t
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)) {
82 // a kernel symbol
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);
90 if (status != B_OK) {
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);
97 return status;
101 static void
102 set_debug_argument_variable(int32 index, uint64 value)
104 char name[8];
105 snprintf(name, sizeof(name), "_arg%ld", index);
106 set_debug_variable(name, value);
110 template<typename Type>
111 static Type
112 read_function_argument_value(void* argument, bool& _valueKnown)
114 Type value;
115 if (debug_memcpy(B_CURRENT_TEAM, &value, argument, sizeof(Type)) == B_OK) {
116 _valueKnown = true;
117 return value;
120 _valueKnown = false;
121 return 0;
125 static status_t
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);
131 if (buffer == NULL)
132 return B_NO_MEMORY;
134 bool isObjectMethod;
135 const char* name = debug_demangle_symbol(symbol, buffer, kBufferSize,
136 &isObjectMethod);
137 if (name == NULL) {
138 debug_free(buffer);
139 return B_ERROR;
142 uint32* arg = (uint32*)args;
144 if (noObjectMethod)
145 isObjectMethod = false;
146 if (isObjectMethod) {
147 const char* lastName = strrchr(name, ':') - 1;
148 int namespaceLength = lastName - name;
150 uint32 argValue = 0;
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);
154 } else
155 kprintf("<%s> %.*s<???>%s", image, namespaceLength, name, lastName);
157 if (addDebugVariables)
158 set_debug_variable("_this", argValue);
159 arg++;
160 } else
161 kprintf("<%s> %s", image, name);
163 kprintf("(");
165 size_t length;
166 int32 type, i = 0;
167 uint32 cookie = 0;
168 while (debug_get_next_demangled_argument(&cookie, symbol, buffer,
169 kBufferSize, &type, &length) == B_OK) {
170 if (i++ > 0)
171 kprintf(", ");
173 // retrieve value and type identifier
175 uint64 value;
176 bool valueKnown = false;
178 switch (type) {
179 case B_INT64_TYPE:
180 value = read_function_argument_value<int64>(arg, valueKnown);
181 if (valueKnown)
182 kprintf("int64: \33[34m%Ld\33[0m", value);
183 break;
184 case B_INT32_TYPE:
185 value = read_function_argument_value<int32>(arg, valueKnown);
186 if (valueKnown)
187 kprintf("int32: \33[34m%ld\33[0m", (int32)value);
188 break;
189 case B_INT16_TYPE:
190 value = read_function_argument_value<int16>(arg, valueKnown);
191 if (valueKnown)
192 kprintf("int16: \33[34m%d\33[0m", (int16)value);
193 break;
194 case B_INT8_TYPE:
195 value = read_function_argument_value<int8>(arg, valueKnown);
196 if (valueKnown)
197 kprintf("int8: \33[34m%d\33[0m", (int8)value);
198 break;
199 case B_UINT64_TYPE:
200 value = read_function_argument_value<uint64>(arg, valueKnown);
201 if (valueKnown) {
202 kprintf("uint64: \33[34m%#Lx\33[0m", value);
203 if (value < 0x100000)
204 kprintf(" (\33[34m%Lu\33[0m)", value);
206 break;
207 case B_UINT32_TYPE:
208 value = read_function_argument_value<uint32>(arg, valueKnown);
209 if (valueKnown) {
210 kprintf("uint32: \33[34m%#lx\33[0m", (uint32)value);
211 if (value < 0x100000)
212 kprintf(" (\33[34m%lu\33[0m)", (uint32)value);
214 break;
215 case B_UINT16_TYPE:
216 value = read_function_argument_value<uint16>(arg, valueKnown);
217 if (valueKnown) {
218 kprintf("uint16: \33[34m%#x\33[0m (\33[34m%u\33[0m)",
219 (uint16)value, (uint16)value);
221 break;
222 case B_UINT8_TYPE:
223 value = read_function_argument_value<uint8>(arg, valueKnown);
224 if (valueKnown) {
225 kprintf("uint8: \33[34m%#x\33[0m (\33[34m%u\33[0m)",
226 (uint8)value, (uint8)value);
228 break;
229 case B_BOOL_TYPE:
230 value = read_function_argument_value<uint8>(arg, valueKnown);
231 if (valueKnown)
232 kprintf("\33[34m%s\33[0m", value ? "true" : "false");
233 break;
234 default:
235 if (buffer[0])
236 kprintf("%s: ", buffer);
238 if (length == 4) {
239 value = read_function_argument_value<uint32>(arg,
240 valueKnown);
241 if (valueKnown) {
242 if (value == 0
243 && (type == B_POINTER_TYPE || type == B_REF_TYPE))
244 kprintf("NULL");
245 else
246 kprintf("\33[34m%#lx\33[0m", (uint32)value);
248 break;
252 if (length == 8) {
253 value = read_function_argument_value<uint64>(arg,
254 valueKnown);
255 } else
256 value = (uint64)arg;
258 if (valueKnown)
259 kprintf("\33[34m%#Lx\33[0m", value);
260 break;
263 if (!valueKnown)
264 kprintf("???");
266 if (valueKnown && type == B_STRING_TYPE) {
267 if (value == 0)
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");
272 } else
273 kprintf(" \33[36m\"%s\"\33[0m", buffer);
276 if (addDebugVariables)
277 set_debug_argument_variable(i, value);
278 arg = (uint32*)((uint8*)arg + length);
281 debug_free(buffer);
283 kprintf(")");
284 return B_OK;
289 static void
290 print_stack_frame(Thread *thread, addr_t ip, addr_t fp, addr_t next,
291 int32 callIndex, bool demangle)
293 const char* symbol;
294 const char* image;
295 addr_t baseAddress;
296 bool exactMatch;
297 status_t status;
298 addr_t diff;
300 diff = next - fp;
302 // MSB set = kernel space/user space switch
303 if (diff & ~((addr_t)-1 >> 1))
304 diff = 0;
306 status = lookup_symbol(thread, ip, &baseAddress, &symbol, &image,
307 &exactMatch);
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,
315 next, false, false);
318 if (!exactMatch || !demangle || status != B_OK) {
319 if (symbol != NULL) {
320 kprintf("<%s> %s%s", image, symbol,
321 exactMatch ? "" : " (nearest)");
322 } else
323 kprintf("<%s@%p> <unknown>", image, (void*)baseAddress);
326 kprintf(" + %#04lx\n", ip - baseAddress);
327 } else {
328 VMArea *area = NULL;
329 if (thread != NULL && thread->team != NULL
330 && thread->team->address_space != NULL) {
331 area = thread->team->address_space->LookupArea(ip);
333 if (area != NULL) {
334 kprintf("%" B_PRId32 ":%s@%p + %#lx\n", area->id, area->name,
335 (void*)area->Base(), ip - area->Base());
336 } else
337 kprintf("\n");
341 static int
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"
346 "thread.\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"
349 " trace.\n";
350 bool demangle = true;
351 int32 threadIndex = 1;
352 if (argc > 1 && !strcmp(argv[1], "-d")) {
353 demangle = false;
354 threadIndex++;
357 if (argc > threadIndex + 1
358 || (argc == 2 && strcmp(argv[1], "--help") == 0)) {
359 kprintf(usage, argv[0]);
360 return 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
371 if (thread != NULL)
372 frameStack = &thread->arch_info.iframes;
373 else
374 frameStack = &gBootFrameStack;
376 int32 i;
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,
384 thread->name);
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]) {
403 // it's an iframe
404 frame = frameStack->frames[i];
405 break;
409 if (frame) {
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);
420 fp = frame->svc_sp;
421 print_stack_frame(thread, frame->pc, frame->svc_sp, frame->svc_lr, callIndex, demangle);
422 } else {
423 addr_t ip, next;
425 if (get_next_frame(fp, &next, &ip) != B_OK) {
426 kprintf("%08lx -- read fault\n", fp);
427 break;
430 if (ip == 0 || fp == 0)
431 break;
433 print_stack_frame(thread, ip, fp, next, callIndex, demangle);
434 fp = next;
437 if (already_visited(previousLocations, &last, &num, fp)) {
438 kprintf("circular stack frame: %p!\n", (void *)fp);
439 break;
441 if (fp == 0)
442 break;
445 return 0;
449 // #pragma mark -
452 void
453 arch_debug_save_registers(struct arch_debug_registers* registers)
458 bool
459 arch_debug_contains_call(Thread *thread, const char *symbol,
460 addr_t start, addr_t end)
462 return false;
466 void
467 arch_debug_stack_trace(void)
469 stack_trace(0, NULL);
473 void *
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();
482 int32
483 arch_debug_get_stack_trace(addr_t* returnAddresses, int32 maxCount,
484 int32 skipIframes, int32 skipFrames, uint32 flags)
486 // TODO: Implement!
487 return 0;
491 void*
492 arch_debug_get_interrupt_pc(bool* _isSyscall)
494 // TODO: Implement!
495 return NULL;
499 bool
500 arch_is_debug_variable_defined(const char* variableName)
502 // TODO: Implement!
503 return false;
507 status_t
508 arch_set_debug_variable(const char* variableName, uint64 value)
510 // TODO: Implement!
511 return B_ENTRY_NOT_FOUND;
515 status_t
516 arch_get_debug_variable(const char* variableName, uint64* value)
518 // TODO: Implement!
519 return B_ENTRY_NOT_FOUND;
523 status_t
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");
530 return B_NO_ERROR;
534 /* arch_debug_call_with_fault_handler is in arch_asm.S */
536 void
537 arch_debug_unset_current_thread(void)
539 // TODO: Implement!
543 ssize_t
544 arch_debug_gdb_get_registers(char* buffer, size_t bufferSize)
546 // TODO: Implement!
547 return B_NOT_SUPPORTED;