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