117721Speter/* 217721Speter * Copyright 2019-2022 Haiku, Inc. All Rights Reserved. 317721Speter * Distributed under the terms of the MIT License. 417721Speter */ 517721Speter 617721Speter 717721Speter#include <arch/debug.h> 817721Speter 917721Speter#include <arch_cpu.h> 1017721Speter#include <debug.h> 1117721Speter#include <debug_heap.h> 1217721Speter#include <elf.h> 1317721Speter#include <kernel.h> 1417721Speter#include <kimage.h> 1517721Speter#include <thread.h> 1617721Speter#include <vm/vm_types.h> 1717721Speter#include <vm/VMAddressSpace.h> 1817721Speter#include <vm/VMArea.h> 1917721Speter 2017721Speter#define NUM_PREVIOUS_LOCATIONS 32 2117721Speter 2217721Speterextern struct iframe_stack gBootFrameStack; 2317721Speter 2417721Speter 2517721Speterstatic bool 2617721Speteralready_visited(addr_t* visited, int32* _last, int32* _num, addr_t fp) 2717721Speter{ 2817721Speter int32 last = *_last; 2917721Speter int32 num = *_num; 3017721Speter 3117721Speter for (int32 i = 0; i < num; i++) { 3217721Speter if (visited[(NUM_PREVIOUS_LOCATIONS + last - i) 3317721Speter % NUM_PREVIOUS_LOCATIONS] == fp) { 3417721Speter return true; 3517721Speter } 3617721Speter } 3717721Speter 3817721Speter *_last = last = (last + 1) % NUM_PREVIOUS_LOCATIONS; 3917721Speter visited[last] = fp; 4017721Speter 4117721Speter if (num < NUM_PREVIOUS_LOCATIONS) 4217721Speter *_num = num + 1; 4317721Speter 4417721Speter return false; 4517721Speter} 4617721Speter 4717721Speter 4817721Speterstatic status_t 4917721Speterget_next_frame(addr_t fp, addr_t *next, addr_t *ip) 5017721Speter{ 5117721Speter if (fp != 0) { 5217721Speter *ip = ((addr_t*)fp)[1]; 5317721Speter *next = ((addr_t*)fp)[0]; 5417721Speter 5517721Speter return B_OK; 5617721Speter } 5717721Speter 5817721Speter return B_BAD_VALUE; 5917721Speter} 6017721Speter 6117721Speter 6217721Speterstatic status_t 6317721Speterlookup_symbol(Thread* thread, addr_t address, addr_t* _baseAddress, 6417721Speter const char** _symbolName, const char** _imageName, bool* _exactMatch) 6517721Speter{ 6617721Speter status_t status = B_ENTRY_NOT_FOUND; 6717721Speter 6817721Speter if (address >= KERNEL_BASE) { 6917721Speter // a kernel symbol 7017721Speter status = elf_debug_lookup_symbol_address(address, _baseAddress, 7117721Speter _symbolName, _imageName, _exactMatch); 7217721Speter } else if (thread != NULL && thread->team != NULL) { 7317721Speter // try a lookup using the userland runtime loader structures 7417721Speter status = elf_debug_lookup_user_symbol_address(thread->team, address, 7517721Speter _baseAddress, _symbolName, _imageName, _exactMatch); 7617721Speter 7717721Speter if (status != B_OK) { 7817721Speter // try to locate the image in the images loaded into user space 7917721Speter status = image_debug_lookup_user_symbol_address(thread->team, 8017721Speter address, _baseAddress, _symbolName, _imageName, _exactMatch); 8117721Speter } 8217721Speter } 8317721Speter 8417721Speter return status; 8517721Speter} 8617721Speter 8717721Speter 8817721Speterstatic void 8917721Speterset_debug_argument_variable(int32 index, uint64 value) 9017721Speter{ 9117721Speter char name[8]; 9217721Speter snprintf(name, sizeof(name), "_arg%" B_PRId32, index); 9317721Speter set_debug_variable(name, value); 9417721Speter} 9517721Speter 9617721Speter 9717721Spetertemplate<typename Type> 9817721Speterstatic Type 9917721Speterread_function_argument_value(void* argument, bool& _valueKnown) 10017721Speter{ 10117721Speter Type value; 10217721Speter if (debug_memcpy(B_CURRENT_TEAM, &value, argument, sizeof(Type)) == B_OK) { 10317721Speter _valueKnown = true; 10417721Speter return value; 10517721Speter } 10617721Speter 10717721Speter _valueKnown = false; 10817721Speter return 0; 10917721Speter} 11017721Speter 11117721Speter 11217721Speterstatic status_t 11317721Speterprint_demangled_call(const char* image, const char* symbol, addr_t args, 11417721Speter bool noObjectMethod, bool addDebugVariables) 11517721Speter{ 11617721Speter static const size_t kBufferSize = 256; 11717721Speter char* buffer = (char*)debug_malloc(kBufferSize); 11817721Speter if (buffer == NULL) 11917721Speter return B_NO_MEMORY; 12017721Speter 12117721Speter bool isObjectMethod; 12217721Speter const char* name = debug_demangle_symbol(symbol, buffer, kBufferSize, 12317721Speter &isObjectMethod); 12417721Speter if (name == NULL) { 12517721Speter debug_free(buffer); 12617721Speter return B_ERROR; 12717721Speter } 12817721Speter 12917721Speter uint32* arg = (uint32*)args; 13017721Speter 13117721Speter if (noObjectMethod) 13217721Speter isObjectMethod = false; 13317721Speter if (isObjectMethod) { 13417721Speter const char* lastName = strrchr(name, ':') - 1; 13517721Speter int namespaceLength = lastName - name; 13617721Speter 13717721Speter uint32 argValue = 0; 13817721Speter if (debug_memcpy(B_CURRENT_TEAM, &argValue, arg, 4) == B_OK) { 13917721Speter kprintf("<%s> %.*s<\33[32m%#" B_PRIx32 "\33[0m>%s", image, 14017721Speter namespaceLength, name, argValue, lastName); 14117721Speter } else 14217721Speter kprintf("<%s> %.*s<\?\?\?>%s", image, namespaceLength, name, lastName); 14317721Speter 14417721Speter if (addDebugVariables) 14517721Speter set_debug_variable("_this", argValue); 14617721Speter arg++; 14717721Speter } else 14817721Speter kprintf("<%s> %s", image, name); 14917721Speter 15017721Speter kprintf("("); 15117721Speter 15217721Speter size_t length; 15317721Speter int32 type, i = 0; 15417721Speter uint32 cookie = 0; 15517721Speter while (debug_get_next_demangled_argument(&cookie, symbol, buffer, 15617721Speter kBufferSize, &type, &length) == B_OK) { 15717721Speter if (i++ > 0) 15817721Speter kprintf(", "); 15917721Speter 16017721Speter // retrieve value and type identifier 16117721Speter 16217721Speter uint64 value; 16317721Speter bool valueKnown = false; 16417721Speter 16517721Speter switch (type) { 16617721Speter case B_INT64_TYPE: 16717721Speter value = read_function_argument_value<int64>(arg, valueKnown); 16817721Speter if (valueKnown) 16917721Speter kprintf("int64: \33[34m%" B_PRId64 "\33[0m", value); 17017721Speter break; 17117721Speter case B_INT32_TYPE: 17217721Speter value = read_function_argument_value<int32>(arg, valueKnown); 17317721Speter if (valueKnown) 17417721Speter kprintf("int32: \33[34m%" B_PRId32 "\33[0m", (int32)value); 17517721Speter break; 17617721Speter case B_INT16_TYPE: 17717721Speter value = read_function_argument_value<int16>(arg, valueKnown); 17817721Speter if (valueKnown) 17917721Speter kprintf("int16: \33[34m%d\33[0m", (int16)value); 18017721Speter break; 18117721Speter case B_INT8_TYPE: 18217721Speter value = read_function_argument_value<int8>(arg, valueKnown); 18317721Speter if (valueKnown) 18417721Speter kprintf("int8: \33[34m%d\33[0m", (int8)value); 18517721Speter break; 18617721Speter case B_UINT64_TYPE: 18717721Speter value = read_function_argument_value<uint64>(arg, valueKnown); 18817721Speter if (valueKnown) { 18917721Speter kprintf("uint64: \33[34m%#" B_PRIx64 "\33[0m", value); 19017721Speter if (value < 0x100000) 19117721Speter kprintf(" (\33[34m%" B_PRIu64 "\33[0m)", value); 192 } 193 break; 194 case B_UINT32_TYPE: 195 value = read_function_argument_value<uint32>(arg, valueKnown); 196 if (valueKnown) { 197 kprintf("uint32: \33[34m%#" B_PRIx32 "\33[0m", (uint32)value); 198 if (value < 0x100000) 199 kprintf(" (\33[34m%" B_PRIu32 "\33[0m)", (uint32)value); 200 } 201 break; 202 case B_UINT16_TYPE: 203 value = read_function_argument_value<uint16>(arg, valueKnown); 204 if (valueKnown) { 205 kprintf("uint16: \33[34m%#x\33[0m (\33[34m%u\33[0m)", 206 (uint16)value, (uint16)value); 207 } 208 break; 209 case B_UINT8_TYPE: 210 value = read_function_argument_value<uint8>(arg, valueKnown); 211 if (valueKnown) { 212 kprintf("uint8: \33[34m%#x\33[0m (\33[34m%u\33[0m)", 213 (uint8)value, (uint8)value); 214 } 215 break; 216 case B_BOOL_TYPE: 217 value = read_function_argument_value<uint8>(arg, valueKnown); 218 if (valueKnown) 219 kprintf("\33[34m%s\33[0m", value ? "true" : "false"); 220 break; 221 default: 222 if (buffer[0]) 223 kprintf("%s: ", buffer); 224 225 if (length == 4) { 226 value = read_function_argument_value<uint32>(arg, 227 valueKnown); 228 if (valueKnown) { 229 if (value == 0 230 && (type == B_POINTER_TYPE || type == B_REF_TYPE)) 231 kprintf("NULL"); 232 else 233 kprintf("\33[34m%#" B_PRIx32 "\33[0m", (uint32)value); 234 } 235 break; 236 } 237 238 239 if (length == 8) { 240 value = read_function_argument_value<uint64>(arg, 241 valueKnown); 242 } else 243 value = (uint64)arg; 244 245 if (valueKnown) 246 kprintf("\33[34m%#" B_PRIx64 "\33[0m", value); 247 break; 248 } 249 250 if (!valueKnown) 251 kprintf("???"); 252 253 if (valueKnown && type == B_STRING_TYPE) { 254 if (value == 0) 255 kprintf(" \33[31m\"<NULL>\"\33[0m"); 256 else if (debug_strlcpy(B_CURRENT_TEAM, buffer, (char*)(addr_t)value, 257 kBufferSize) < B_OK) { 258 kprintf(" \33[31m\"<\?\?\?>\"\33[0m"); 259 } else 260 kprintf(" \33[36m\"%s\"\33[0m", buffer); 261 } 262 263 if (addDebugVariables) 264 set_debug_argument_variable(i, value); 265 arg = (uint32*)((uint8*)arg + length); 266 } 267 268 debug_free(buffer); 269 270 kprintf(")"); 271 return B_OK; 272} 273 274 275static void 276print_stack_frame(Thread *thread, addr_t ip, addr_t fp, addr_t next, 277 int32 callIndex, bool demangle) 278{ 279 const char* symbol; 280 const char* image; 281 addr_t baseAddress; 282 bool exactMatch; 283 status_t status; 284 addr_t diff; 285 286 diff = next - fp; 287 288 // MSB set = kernel space/user space switch 289 if (diff & ~((addr_t)-1 >> 1)) 290 diff = 0; 291 292 status = lookup_symbol(thread, ip, &baseAddress, &symbol, &image, 293 &exactMatch); 294 295 kprintf("%2" B_PRId32 " %0*lx (+%4ld) %0*lx ", callIndex, 296 B_PRINTF_POINTER_WIDTH, fp, diff, B_PRINTF_POINTER_WIDTH, ip); 297 298 if (status == B_OK) { 299 if (exactMatch && demangle) { 300 status = print_demangled_call(image, symbol, 301 next, false, false); 302 } 303 304 if (!exactMatch || !demangle || status != B_OK) { 305 if (symbol != NULL) { 306 kprintf("<%s> %s%s", image, symbol, 307 exactMatch ? "" : " (nearest)"); 308 } else 309 kprintf("<%s@%p> <unknown>", image, (void*)baseAddress); 310 } 311 312 kprintf(" + %#04lx\n", ip - baseAddress); 313 } else { 314 VMArea *area = NULL; 315 if (thread != NULL && thread->team != NULL 316 && thread->team->address_space != NULL) { 317 area = thread->team->address_space->LookupArea(ip); 318 } 319 if (area != NULL) { 320 kprintf("%" B_PRId32 ":%s@%p + %#lx\n", area->id, area->name, 321 (void*)area->Base(), ip - area->Base()); 322 } else 323 kprintf("\n"); 324 } 325} 326 327static int 328stack_trace(int argc, char **argv) 329{ 330 static const char* usage = "usage: %s [-d] [ <thread id> ]\n" 331 "Prints a stack trace for the current, respectively the specified\n" 332 "thread.\n" 333 " -d - Disables the demangling of the symbols.\n" 334 " <thread id> - The ID of the thread for which to print the stack\n" 335 " trace.\n"; 336 bool demangle = true; 337 int32 threadIndex = 1; 338 if (argc > 1 && !strcmp(argv[1], "-d")) { 339 demangle = false; 340 threadIndex++; 341 } 342 343 if (argc > threadIndex + 1 344 || (argc == 2 && strcmp(argv[1], "--help") == 0)) { 345 kprintf(usage, argv[0]); 346 return 0; 347 } 348 349 addr_t previousLocations[NUM_PREVIOUS_LOCATIONS]; 350 Thread* thread = thread_get_current_thread(); 351 addr_t fp = arm64_get_fp(); 352 int32 num = 0, last = 0; 353 struct iframe_stack *frameStack; 354 355 // We don't have a thread pointer early in the boot process 356 if (thread != NULL) 357 frameStack = &thread->arch_info.iframes; 358 else 359 frameStack = &gBootFrameStack; 360 361 int32 i; 362 for (i = 0; i < frameStack->index; i++) { 363 kprintf("iframe %p (end = %p)\n", 364 frameStack->frames[i], frameStack->frames[i] + 1); 365 } 366 367 if (thread != NULL) { 368 kprintf("stack trace for thread 0x%" B_PRIx32 " \"%s\"\n", thread->id, 369 thread->name); 370 371 kprintf(" kernel stack: %p to %p\n", 372 (void *)thread->kernel_stack_base, 373 (void *)(thread->kernel_stack_top)); 374 if (thread->user_stack_base != 0) { 375 kprintf(" user stack: %p to %p\n", 376 (void *)thread->user_stack_base, 377 (void *)(thread->user_stack_base + thread->user_stack_size)); 378 } 379 } 380 381 kprintf("frame caller <image>:function + offset\n"); 382 383 for (int32 callIndex = 0;; callIndex++) { 384 // see if the frame pointer matches the iframe 385 struct iframe *frame = NULL; 386 for (i = 0; i < frameStack->index; i++) { 387 if (fp == (addr_t)frameStack->frames[i]) { 388 // it's an iframe 389 frame = frameStack->frames[i]; 390 break; 391 } 392 } 393 394 if (frame) { 395 kprintf("iframe at %p\n", frame); 396 dprintf("ELR=%016lx SPSR=%016lx\n", frame->elr, frame->spsr); 397 dprintf("LR =%016lx SP =%016lx FP =%016lx\n", frame->lr, frame->sp, frame->fp); 398 dprintf("ESR=%016lx FAR =%016lx\n", frame->esr, frame->far); 399 print_stack_frame(thread, frame->elr, fp, frame->fp, callIndex, demangle); 400 fp = frame->fp; 401 } else { 402 addr_t ip, next; 403 404 if (get_next_frame(fp, &next, &ip) != B_OK) { 405 kprintf("%08lx -- read fault\n", fp); 406 break; 407 } 408 409 if (ip == 0 || fp == 0) 410 break; 411 412 print_stack_frame(thread, ip, fp, next, callIndex, demangle); 413 fp = next; 414 } 415 416 if (already_visited(previousLocations, &last, &num, fp)) { 417 kprintf("circular stack frame: %p!\n", (void *)fp); 418 break; 419 } 420 if (fp == 0) 421 break; 422 } 423 424 return 0; 425} 426 427 428// #pragma mark - 429 430 431void 432arch_debug_save_registers(struct arch_debug_registers* registers) 433{ 434} 435 436 437bool 438arch_debug_contains_call(Thread *thread, const char *symbol, 439 addr_t start, addr_t end) 440{ 441 return false; 442} 443 444 445void 446arch_debug_stack_trace(void) 447{ 448 stack_trace(0, NULL); 449} 450 451 452int32 453arch_debug_get_stack_trace(addr_t* returnAddresses, int32 maxCount, 454 int32 skipIframes, int32 skipFrames, uint32 flags) 455{ 456 return 0; 457} 458 459 460void* 461arch_debug_get_interrupt_pc(bool* _isSyscall) 462{ 463 return NULL; 464} 465 466 467bool 468arch_is_debug_variable_defined(const char* variableName) 469{ 470 return false; 471} 472 473 474status_t 475arch_set_debug_variable(const char* variableName, uint64 value) 476{ 477 return B_ENTRY_NOT_FOUND; 478} 479 480 481status_t 482arch_get_debug_variable(const char* variableName, uint64* value) 483{ 484 return B_ENTRY_NOT_FOUND; 485} 486 487 488status_t 489arch_debug_init(kernel_args *args) 490{ 491 add_debugger_command("where", &stack_trace, "Same as \"sc\""); 492 add_debugger_command("bt", &stack_trace, "Same as \"sc\" (as in gdb)"); 493 add_debugger_command("sc", &stack_trace, "Stack crawl for current thread"); 494 495 return B_NO_ERROR; 496} 497 498 499void 500arch_debug_unset_current_thread(void) 501{ 502} 503 504 505ssize_t 506arch_debug_gdb_get_registers(char* buffer, size_t bufferSize) 507{ 508 return B_NOT_SUPPORTED; 509} 510