1 /* 2 * Copyright 2019-2020, Haiku, Inc. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Adrien Destugues <pulkomandy@pulkomandy.tk> 7 */ 8 9 10 #include <arch/debug.h> 11 #include <vm/VMAddressSpace.h> 12 #include <vm/VMArea.h> 13 #include <elf.h> 14 #include <kimage.h> 15 #include <arch/generic/user_memory.h> 16 #include <AutoDeleterDrivers.h> 17 18 19 kernel_args *sKernelArgs; 20 bool sInitCalled = false; 21 22 23 extern "C" void SVecRet(); 24 extern "C" void SVecURet(); 25 26 void WriteRegisters(iframe* frame); 27 28 29 static void 30 WriteImage(preloaded_image* _image) 31 { 32 preloaded_elf64_image* image = (preloaded_elf64_image*)_image; 33 dprintf("image %p\n", image); 34 dprintf("image \"%s\"\n", (char*)image->name); 35 dprintf(" text: 0x%" B_PRIxADDR " - 0x%" B_PRIxADDR ",%" 36 B_PRIdSSIZE "\n", image->text_region.start, 37 image->text_region.start + image->text_region.size, 38 image->text_region.delta); 39 dprintf(" data: 0x%" B_PRIxADDR " - 0x%" B_PRIxADDR ", %" 40 B_PRIdSSIZE "\n", image->data_region.start, 41 image->data_region.start + image->data_region.size, 42 image->data_region.delta); 43 } 44 45 46 static void 47 WriteImages() 48 { 49 WriteImage(sKernelArgs->kernel_image); 50 51 preloaded_image* image = sKernelArgs->preloaded_images; 52 while (image != NULL) { 53 WriteImage(image); 54 image = image->next; 55 } 56 } 57 58 59 static bool 60 AddressInImage(preloaded_image* _image, addr_t adr) 61 { 62 preloaded_elf64_image* image = (preloaded_elf64_image*)_image; 63 if (adr >= image->text_region.start 64 && adr < image->text_region.start + image->text_region.size) { 65 return true; 66 } 67 68 if (adr >= image->data_region.start 69 && adr < image->data_region.start + image->data_region.size) { 70 return true; 71 } 72 73 return false; 74 } 75 76 77 static bool 78 SymbolAt(preloaded_image* _image, addr_t adr, const char **name, ssize_t *ofs) 79 { 80 preloaded_elf64_image* image = (preloaded_elf64_image*)_image; 81 adr -= image->text_region.delta; 82 for (uint32 i = 0; i < image->num_debug_symbols; i++) { 83 Elf64_Sym& sym = image->debug_symbols[i]; 84 if (sym.st_shndx != STN_UNDEF && adr >= sym.st_value 85 && adr < sym.st_value + sym.st_size) { 86 if (name != NULL) 87 *name = &image->debug_string_table[sym.st_name]; 88 if (ofs != NULL) 89 *ofs = adr - sym.st_value; 90 return true; 91 } 92 } 93 return false; 94 } 95 96 97 static preloaded_image* 98 FindImage(addr_t adr) 99 { 100 if (AddressInImage(sKernelArgs->kernel_image, adr)) 101 return sKernelArgs->kernel_image; 102 103 preloaded_image* image = sKernelArgs->preloaded_images; 104 while (image != NULL) { 105 if (AddressInImage(image, adr)) 106 return image; 107 image = image->next; 108 } 109 110 return NULL; 111 } 112 113 114 static VMArea* 115 FindArea(addr_t adr) 116 { 117 if (IS_KERNEL_ADDRESS(adr)) { 118 VMAddressSpacePutter addrSpace(VMAddressSpace::GetKernel()); 119 return addrSpace->LookupArea(adr); 120 } 121 if (IS_USER_ADDRESS(adr)) { 122 VMAddressSpacePutter addrSpace(VMAddressSpace::GetCurrent()); 123 return addrSpace->LookupArea(adr); 124 } 125 return NULL; 126 } 127 128 129 static VMArea* 130 FindAreaEx(Thread* thread, addr_t adr) 131 { 132 if (IS_KERNEL_ADDRESS(adr)) { 133 return VMAddressSpace::Kernel()->LookupArea(adr); 134 } 135 if (IS_USER_ADDRESS(adr)) { 136 return thread->team->address_space->LookupArea(adr); 137 } 138 return NULL; 139 } 140 141 142 static status_t 143 lookup_symbol(Thread* thread, addr_t address, addr_t* _baseAddress, 144 const char** _symbolName, const char** _imageName, bool* _exactMatch) 145 { 146 status_t status = B_ENTRY_NOT_FOUND; 147 148 if (IS_KERNEL_ADDRESS(address)) { 149 // a kernel symbol 150 status = elf_debug_lookup_symbol_address(address, _baseAddress, 151 _symbolName, _imageName, _exactMatch); 152 } else if (true && thread != NULL && thread->team != NULL) { 153 // try a lookup using the userland runtime loader structures 154 status = elf_debug_lookup_user_symbol_address(thread->team, address, 155 _baseAddress, _symbolName, _imageName, _exactMatch); 156 157 if (status != B_OK) { 158 // try to locate the image in the images loaded into user space 159 status = image_debug_lookup_user_symbol_address(thread->team, 160 address, _baseAddress, _symbolName, _imageName, _exactMatch); 161 } 162 } 163 164 return status; 165 } 166 167 168 void 169 WritePCBoot(addr_t pc) 170 { 171 preloaded_image* image = FindImage(pc); 172 if (image != NULL) { 173 const char *name; 174 ssize_t ofs; 175 if (SymbolAt(image, pc, &name, &ofs)) { 176 dprintf("<%s> %s + %" B_PRIdSSIZE, (char*)image->name, name, ofs); 177 return; 178 } 179 dprintf("<%s> 0x%" B_PRIxADDR, (char*)image->name, 180 pc - ((preloaded_elf64_image*)image)->text_region.delta); 181 return; 182 } 183 /* 184 VMArea* area = FindArea(pc); 185 if (area != NULL) { 186 dprintf("<%s> 0x%" B_PRIxADDR, area->name, pc - area->Base()); 187 return; 188 } 189 */ 190 dprintf("0x%" B_PRIxADDR, pc); 191 } 192 193 194 static void 195 WritePCEx(Thread* thread, addr_t pc) 196 { 197 dprintf("0x%" B_PRIxADDR " ", pc); 198 if (!sInitCalled) { 199 WritePCBoot(pc); return; 200 } 201 202 addr_t baseAddress; 203 const char* symbolName; 204 const char* imageName; 205 bool exactMatch; 206 if (lookup_symbol(thread, pc, &baseAddress, 207 &symbolName, &imageName, &exactMatch) >= B_OK) { 208 if (symbolName != NULL) { 209 dprintf("<%s> %s + %" B_PRIdSSIZE, imageName, symbolName, 210 pc - baseAddress); 211 return; 212 } 213 dprintf("<%s> 0x%" B_PRIxADDR, imageName, pc - baseAddress); 214 return; 215 } 216 217 VMArea* area = FindAreaEx(thread, pc); 218 if (area != NULL) { 219 dprintf("<%s> 0x%" B_PRIxADDR, area->name, pc - area->Base()); 220 return; 221 } 222 223 dprintf("0x%" B_PRIxADDR, pc); 224 } 225 226 227 void WritePC(addr_t pc) 228 { 229 WritePCEx(thread_get_current_thread(), pc); 230 } 231 232 233 static status_t 234 arch_debug_memcpy(void* dst, const void* src, size_t size) 235 { 236 if (debug_debugger_running()) 237 return debug_memcpy(B_CURRENT_TEAM, dst, src, size); 238 239 return user_memcpy(dst, src, size); 240 } 241 242 243 static void 244 DumpMemory(uint64* adr, size_t len) 245 { 246 while (len > 0) { 247 if ((addr_t)adr % 0x10 == 0) 248 dprintf(" %08" B_PRIxADDR " ", (addr_t)adr); 249 uint64 val; 250 if (arch_debug_memcpy(&val, adr++, sizeof(val)) < B_OK) { 251 dprintf(" ????????????????"); 252 } else { 253 dprintf(" %016" B_PRIx64, val); 254 } 255 if ((addr_t)adr % 0x10 == 0) 256 dprintf("\n"); 257 len -= 8; 258 } 259 if ((addr_t)adr % 0x10 != 0) 260 dprintf("\n"); 261 } 262 263 264 static void 265 DoStackTraceEx(Thread* thread, addr_t fp, addr_t pc) 266 { 267 dprintf("Stack:\n"); 268 dprintf("FP: 0x%" B_PRIxADDR, fp); 269 if (pc != 0) { 270 dprintf(", PC: "); WritePCEx(thread, pc); 271 } 272 dprintf("\n"); 273 addr_t oldFp = fp; 274 int i = 0; 275 while (fp != 0 && i < 1000) { 276 if ((pc >= (addr_t)&strcpy && pc < (addr_t)&strcpy + 32) 277 || (pc >= (addr_t)&memset && pc < (addr_t)&memset + 34) 278 || (pc >= (addr_t)&memcpy && pc < (addr_t)&memcpy + 186)) { 279 if (arch_debug_memcpy(&fp, (uint64*)fp - 1, sizeof(pc)) < B_OK) 280 break; 281 pc = 0; 282 } else { 283 if (arch_debug_memcpy(&pc, (uint64*)fp - 1, sizeof(pc)) < B_OK) 284 break; 285 if (arch_debug_memcpy(&fp, (uint64*)fp - 2, sizeof(pc)) < B_OK) 286 break; 287 } 288 dprintf("FP: 0x%" B_PRIxADDR, fp); 289 dprintf(", PC: "); WritePCEx(thread, pc); 290 dprintf("\n"); 291 292 if (pc == (addr_t)&SVecRet || pc == (addr_t)&SVecURet) { 293 WriteTrapInfo((iframe*)fp - 1); 294 } 295 /* 296 if (IS_KERNEL_ADDRESS(oldFp) != IS_KERNEL_ADDRESS(fp)) 297 oldFp = fp; 298 else if (fp != 0) 299 DumpMemory((uint64*)oldFp, (addr_t)fp - (addr_t)oldFp); 300 */ 301 oldFp = fp; 302 i++; 303 } 304 } 305 306 307 void 308 DoStackTrace(addr_t fp, addr_t pc) 309 { 310 DoStackTraceEx(thread_get_current_thread(), fp, pc); 311 } 312 313 314 static int 315 stack_trace(int argc, char **argv) 316 { 317 if (argc >= 2) { 318 thread_id id = strtoul(argv[1], NULL, 0); 319 Thread* thread = Thread::GetDebug(id); 320 if (thread == NULL) { 321 kprintf("could not find thread %" B_PRId32 "\n", id); 322 return 0; 323 } 324 uint64 oldSatp = Satp(); 325 SetSatp(thread->arch_info.context.satp); 326 DebuggedThreadSetter threadSetter(thread); 327 DoStackTraceEx(thread, thread->arch_info.context.s[0], thread->arch_info.context.ra); 328 SetSatp(oldSatp); 329 return 0; 330 } 331 DoStackTrace(Fp(), 0); 332 return 0; 333 } 334 335 336 void 337 arch_debug_stack_trace(void) 338 { 339 DoStackTrace(Fp(), 0); 340 } 341 342 343 bool 344 arch_debug_contains_call(Thread *thread, const char *symbol, 345 addr_t start, addr_t end) 346 { 347 return false; 348 } 349 350 351 void * 352 arch_debug_get_caller(void) 353 { 354 return NULL; 355 } 356 357 358 void 359 arch_debug_save_registers(struct arch_debug_registers* registers) 360 { 361 } 362 363 364 static void __attribute__((naked)) 365 HandleFault() 366 { 367 asm volatile("ld a0, 0(sp)"); 368 asm volatile("li a1, 1"); 369 asm volatile("call longjmp"); 370 } 371 372 373 void 374 arch_debug_call_with_fault_handler(cpu_ent* cpu, jmp_buf jumpBuffer, 375 void (*function)(void*), void* parameter) 376 { 377 cpu->fault_handler = (addr_t)&HandleFault; 378 cpu->fault_handler_stack_pointer = (addr_t)&jumpBuffer; 379 function(parameter); 380 } 381 382 383 bool 384 arch_is_debug_variable_defined(const char* variableName) 385 { 386 // TODO: Implement! 387 return false; 388 } 389 390 391 status_t 392 arch_set_debug_variable(const char* variableName, uint64 value) 393 { 394 // TODO: Implement! 395 return B_ENTRY_NOT_FOUND; 396 } 397 398 399 status_t 400 arch_get_debug_variable(const char* variableName, uint64* value) 401 { 402 // TODO: Implement! 403 return B_ENTRY_NOT_FOUND; 404 } 405 406 407 int32 408 arch_debug_get_stack_trace(addr_t* returnAddresses, int32 maxCount, 409 int32 skipIframes, int32 skipFrames, uint32 flags) 410 { 411 return 0; 412 } 413 414 415 ssize_t 416 arch_debug_gdb_get_registers(char* buffer, size_t bufferSize) 417 { 418 // TODO: Implement! 419 return B_NOT_SUPPORTED; 420 } 421 422 423 void* 424 arch_debug_get_interrupt_pc(bool* _isSyscall) 425 { 426 // TODO: Implement! 427 return NULL; 428 } 429 430 431 void 432 arch_debug_unset_current_thread(void) 433 { 434 // TODO: Implement! 435 } 436 437 438 status_t 439 arch_debug_init_early(kernel_args *args) 440 { 441 dprintf("arch_debug_init_early()\n"); 442 sKernelArgs = args; 443 WriteImages(); 444 return B_OK; 445 } 446 447 448 status_t 449 arch_debug_init(kernel_args *args) 450 { 451 sInitCalled = true; 452 453 add_debugger_command("where", &stack_trace, "Same as \"sc\""); 454 add_debugger_command("bt", &stack_trace, "Same as \"sc\" (as in gdb)"); 455 add_debugger_command("sc", &stack_trace, "Stack crawl for current thread"); 456 457 return B_OK; 458 } 459