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