1 // SPDX-License-Identifier: GPL-2.0 2 #include "capstone.h" 3 4 #include <errno.h> 5 #include <inttypes.h> 6 #include <string.h> 7 8 #include <dlfcn.h> 9 #include <elf.h> 10 #include <fcntl.h> 11 #include <linux/ctype.h> 12 13 #include <capstone/capstone.h> 14 15 #include "addr_location.h" 16 #include "annotate.h" 17 #include "debug.h" 18 #include "disasm.h" 19 #include "dso.h" 20 #include "machine.h" 21 #include "map.h" 22 #include "namespaces.h" 23 #include "print_insn.h" 24 #include "symbol.h" 25 #include "thread.h" 26 27 #if CS_VERSION_MAJOR < 5 28 #define CS_ARCH_RISCV 15 29 #define CS_MODE_RISCV32 1 30 #define CS_MODE_RISCV64 2 31 #define CS_MODE_RISCVC 4 32 #endif 33 34 #ifdef LIBCAPSTONE_DLOPEN 35 static void *perf_cs_dll_handle(void) 36 { 37 static bool dll_handle_init; 38 static void *dll_handle; 39 40 if (!dll_handle_init) { 41 dll_handle_init = true; 42 dll_handle = dlopen("libcapstone.so", RTLD_LAZY); 43 if (!dll_handle) 44 pr_debug("dlopen failed for libcapstone.so\n"); 45 } 46 return dll_handle; 47 } 48 #endif 49 50 static enum cs_err perf_cs_open(enum cs_arch arch, enum cs_mode mode, csh *handle) 51 { 52 #ifndef LIBCAPSTONE_DLOPEN 53 return cs_open(arch, mode, handle); 54 #else 55 static bool fn_init; 56 static enum cs_err (*fn)(enum cs_arch arch, enum cs_mode mode, csh *handle); 57 58 if (!fn_init) { 59 fn = dlsym(perf_cs_dll_handle(), "cs_open"); 60 if (!fn) 61 pr_debug("dlsym failed for cs_open\n"); 62 fn_init = true; 63 } 64 if (!fn) 65 return CS_ERR_HANDLE; 66 return fn(arch, mode, handle); 67 #endif 68 } 69 70 static enum cs_err perf_cs_option(csh handle, enum cs_opt_type type, size_t value) 71 { 72 #ifndef LIBCAPSTONE_DLOPEN 73 return cs_option(handle, type, value); 74 #else 75 static bool fn_init; 76 static enum cs_err (*fn)(csh handle, enum cs_opt_type type, size_t value); 77 78 if (!fn_init) { 79 fn = dlsym(perf_cs_dll_handle(), "cs_option"); 80 if (!fn) 81 pr_debug("dlsym failed for cs_option\n"); 82 fn_init = true; 83 } 84 if (!fn) 85 return CS_ERR_HANDLE; 86 return fn(handle, type, value); 87 #endif 88 } 89 90 static size_t perf_cs_disasm(csh handle, const uint8_t *code, size_t code_size, 91 uint64_t address, size_t count, struct cs_insn **insn) 92 { 93 #ifndef LIBCAPSTONE_DLOPEN 94 return cs_disasm(handle, code, code_size, address, count, insn); 95 #else 96 static bool fn_init; 97 static enum cs_err (*fn)(csh handle, const uint8_t *code, size_t code_size, 98 uint64_t address, size_t count, struct cs_insn **insn); 99 100 if (!fn_init) { 101 fn = dlsym(perf_cs_dll_handle(), "cs_disasm"); 102 if (!fn) 103 pr_debug("dlsym failed for cs_disasm\n"); 104 fn_init = true; 105 } 106 if (!fn) 107 return CS_ERR_HANDLE; 108 return fn(handle, code, code_size, address, count, insn); 109 #endif 110 } 111 112 static void perf_cs_free(struct cs_insn *insn, size_t count) 113 { 114 #ifndef LIBCAPSTONE_DLOPEN 115 cs_free(insn, count); 116 #else 117 static bool fn_init; 118 static void (*fn)(struct cs_insn *insn, size_t count); 119 120 if (!fn_init) { 121 fn = dlsym(perf_cs_dll_handle(), "cs_free"); 122 if (!fn) 123 pr_debug("dlsym failed for cs_free\n"); 124 fn_init = true; 125 } 126 if (!fn) 127 return; 128 fn(insn, count); 129 #endif 130 } 131 132 static enum cs_err perf_cs_close(csh *handle) 133 { 134 #ifndef LIBCAPSTONE_DLOPEN 135 return cs_close(handle); 136 #else 137 static bool fn_init; 138 static enum cs_err (*fn)(csh *handle); 139 140 if (!fn_init) { 141 fn = dlsym(perf_cs_dll_handle(), "cs_close"); 142 if (!fn) 143 pr_debug("dlsym failed for cs_close\n"); 144 fn_init = true; 145 } 146 if (!fn) 147 return CS_ERR_HANDLE; 148 return fn(handle); 149 #endif 150 } 151 152 static bool e_machine_to_capstone(uint16_t e_machine, bool is64, bool is_big_endian, 153 enum cs_arch *arch, enum cs_mode *mode) 154 { 155 *mode = is_big_endian ? CS_MODE_BIG_ENDIAN : CS_MODE_LITTLE_ENDIAN; 156 157 switch (e_machine) { 158 case EM_X86_64: 159 case EM_386: 160 *arch = CS_ARCH_X86; 161 *mode |= is64 ? CS_MODE_64 : CS_MODE_32; 162 return true; 163 case EM_AARCH64: 164 *arch = CS_ARCH_ARM64; 165 *mode |= CS_MODE_ARM; 166 return true; 167 case EM_ARM: 168 *arch = CS_ARCH_ARM; 169 *mode |= CS_MODE_ARM | CS_MODE_V8; 170 return true; 171 case EM_S390: 172 *arch = CS_ARCH_SYSZ; 173 return true; 174 case EM_MIPS: 175 *arch = CS_ARCH_MIPS; 176 *mode |= is64 ? CS_MODE_MIPS64 : CS_MODE_MIPS32; 177 return true; 178 case EM_PPC: 179 *arch = CS_ARCH_PPC; 180 return true; 181 case EM_PPC64: 182 *arch = CS_ARCH_PPC; 183 *mode |= CS_MODE_64; 184 return true; 185 case EM_SPARC: 186 *arch = CS_ARCH_SPARC; 187 return true; 188 case EM_SPARCV9: 189 *arch = CS_ARCH_SPARC; 190 *mode |= CS_MODE_V9; 191 return true; 192 case EM_RISCV: 193 *arch = CS_ARCH_RISCV; 194 *mode |= (is64 ? CS_MODE_RISCV64 : CS_MODE_RISCV32) | CS_MODE_RISCVC; 195 return true; 196 default: 197 return false; 198 } 199 } 200 201 static int capstone_init(uint16_t e_machine, csh *cs_handle, bool is64, bool is_big_endian, 202 bool disassembler_style) 203 { 204 enum cs_arch arch; 205 enum cs_mode mode; 206 207 if (!e_machine_to_capstone(e_machine, is64, is_big_endian, &arch, &mode)) 208 return -1; 209 210 if (perf_cs_open(arch, mode, cs_handle) != CS_ERR_OK) { 211 pr_warning_once("cs_open failed\n"); 212 return -1; 213 } 214 215 if (arch == CS_ARCH_X86) { 216 /* 217 * In case of using capstone_init while symbol__disassemble 218 * setting CS_OPT_SYNTAX_ATT depends if disassembler_style opts 219 * is set via annotation args 220 */ 221 if (disassembler_style) 222 perf_cs_option(*cs_handle, CS_OPT_SYNTAX, CS_OPT_SYNTAX_ATT); 223 /* 224 * Resolving address operands to symbols is implemented 225 * on x86 by investigating instruction details. 226 */ 227 perf_cs_option(*cs_handle, CS_OPT_DETAIL, CS_OPT_ON); 228 } 229 230 return 0; 231 } 232 233 static size_t print_insn_x86(struct thread *thread, u8 cpumode, struct cs_insn *insn, 234 int print_opts, FILE *fp) 235 { 236 struct addr_location al; 237 size_t printed = 0; 238 239 if (insn->detail && insn->detail->x86.op_count == 1) { 240 struct cs_x86_op *op = &insn->detail->x86.operands[0]; 241 242 addr_location__init(&al); 243 if (op->type == X86_OP_IMM && 244 thread__find_symbol(thread, cpumode, op->imm, &al)) { 245 printed += fprintf(fp, "%s ", insn[0].mnemonic); 246 printed += symbol__fprintf_symname_offs(al.sym, &al, fp); 247 if (print_opts & PRINT_INSN_IMM_HEX) 248 printed += fprintf(fp, " [%#" PRIx64 "]", op->imm); 249 addr_location__exit(&al); 250 return printed; 251 } 252 addr_location__exit(&al); 253 } 254 255 printed += fprintf(fp, "%s %s", insn[0].mnemonic, insn[0].op_str); 256 return printed; 257 } 258 259 ssize_t capstone__fprintf_insn_asm(struct machine *machine, struct thread *thread, u8 cpumode, 260 bool is64bit, const uint8_t *code, size_t code_size, uint64_t ip, 261 int *lenp, int print_opts, FILE *fp) 262 { 263 size_t printed; 264 struct cs_insn *insn; 265 csh cs_handle; 266 size_t count; 267 bool is_big_endian = false; 268 uint16_t e_machine = thread__e_machine_endian(thread, machine, 269 /*e_flags=*/NULL, &is_big_endian); 270 int ret; 271 272 /* TODO: Try to initiate capstone only once but need a proper place. */ 273 ret = capstone_init(e_machine, &cs_handle, is64bit, is_big_endian, 274 /*disassembler_style=*/true); 275 if (ret < 0) 276 return ret; 277 278 count = perf_cs_disasm(cs_handle, code, code_size, ip, 1, &insn); 279 if (count > 0) { 280 if (e_machine == EM_X86_64 || e_machine == EM_386) 281 printed = print_insn_x86(thread, cpumode, &insn[0], print_opts, fp); 282 else 283 printed = fprintf(fp, "%s %s", insn[0].mnemonic, insn[0].op_str); 284 if (lenp) 285 *lenp = insn->size; 286 perf_cs_free(insn, count); 287 } else { 288 printed = -1; 289 } 290 291 perf_cs_close(&cs_handle); 292 return printed; 293 } 294 295 static void print_capstone_detail(struct cs_insn *insn, char *buf, size_t len, 296 struct annotate_args *args, u64 addr) 297 { 298 int i; 299 struct map *map = args->ms->map; 300 struct symbol *sym; 301 302 /* TODO: support more architectures */ 303 if (!arch__is_x86(args->arch)) 304 return; 305 306 if (insn->detail == NULL) 307 return; 308 309 for (i = 0; i < insn->detail->x86.op_count; i++) { 310 struct cs_x86_op *op = &insn->detail->x86.operands[i]; 311 u64 orig_addr; 312 struct map *found_map = NULL; 313 314 if (op->type != X86_OP_MEM) 315 continue; 316 317 /* only print RIP-based global symbols for now */ 318 if (op->mem.base != X86_REG_RIP) 319 continue; 320 321 /* get the target address */ 322 orig_addr = addr + insn->size + op->mem.disp; 323 addr = map__objdump_2mem(map, orig_addr); 324 325 if (dso__kernel(map__dso(map))) { 326 /* 327 * The kernel maps can be split into sections, let's 328 * find the map first and then search the symbol. 329 */ 330 found_map = maps__find(map__kmaps(map), addr); 331 if (found_map == NULL) 332 continue; 333 map = found_map; 334 } 335 336 /* convert it to map-relative address for search */ 337 addr = map__map_ip(map, addr); 338 339 sym = map__find_symbol(map, addr); 340 if (sym == NULL) { 341 map__put(found_map); 342 continue; 343 } 344 345 if (addr == sym->start) { 346 scnprintf(buf, len, "\t# %"PRIx64" <%s>", 347 orig_addr, sym->name); 348 } else { 349 scnprintf(buf, len, "\t# %"PRIx64" <%s+%#"PRIx64">", 350 orig_addr, sym->name, addr - sym->start); 351 } 352 map__put(found_map); 353 break; 354 } 355 } 356 357 struct find_file_offset_data { 358 u64 ip; 359 u64 offset; 360 }; 361 362 /* This will be called for each PHDR in an ELF binary */ 363 static int find_file_offset(u64 start, u64 len, u64 pgoff, void *arg) 364 { 365 struct find_file_offset_data *data = arg; 366 367 if (start <= data->ip && data->ip < start + len) { 368 data->offset = pgoff + data->ip - start; 369 return 1; 370 } 371 return 0; 372 } 373 374 int symbol__disassemble_capstone(const char *filename, struct symbol *sym, 375 struct annotate_args *args) 376 { 377 struct annotation *notes = symbol__annotation(sym); 378 struct map *map = args->ms->map; 379 struct dso *dso = map__dso(map); 380 u64 start = map__rip_2objdump(map, sym->start); 381 u64 offset; 382 int i, count, free_count; 383 bool is_64bit = false; 384 bool needs_cs_close = false; 385 /* Malloc-ed buffer containing instructions read from disk. */ 386 u8 *code_buf = NULL; 387 /* Pointer to code to be disassembled. */ 388 const u8 *buf; 389 u64 buf_len; 390 csh handle; 391 struct cs_insn *insn = NULL; 392 char disasm_buf[512]; 393 struct disasm_line *dl; 394 bool disassembler_style = false; 395 uint16_t e_machine = EM_NONE; 396 bool is_big_endian = false; 397 398 if (args->options->objdump_path) 399 return -1; 400 401 buf = dso__read_symbol(dso, filename, map, sym, 402 &code_buf, &buf_len, &is_64bit); 403 if (buf == NULL) 404 return errno; 405 406 /* add the function address and name */ 407 scnprintf(disasm_buf, sizeof(disasm_buf), "%#"PRIx64" <%s>:", 408 start, sym->name); 409 410 args->offset = -1; 411 args->line = disasm_buf; 412 args->line_nr = 0; 413 args->fileloc = NULL; 414 args->ms->sym = sym; 415 416 dl = disasm_line__new(args); 417 if (dl == NULL) 418 goto err; 419 420 annotation_line__add(&dl->al, ¬es->src->source); 421 422 if (!args->options->disassembler_style || 423 !strcmp(args->options->disassembler_style, "att")) 424 disassembler_style = true; 425 426 if (args->ms->thread) { 427 e_machine = thread__e_machine_endian(args->ms->thread, 428 /*machine=*/NULL, 429 /*e_flags=*/NULL, &is_big_endian); 430 } else if (dso) { 431 struct maps *kmaps = (map && dso__kernel(dso)) ? map__kmaps(map) : NULL; 432 struct machine *kmap_machine = kmaps ? maps__machine(kmaps) : NULL; 433 434 e_machine = dso__e_machine_endian(dso, kmap_machine, /*e_flags=*/NULL, 435 &is_big_endian); 436 } 437 if (!e_machine || e_machine == EM_NONE) { 438 e_machine = thread__e_machine_endian(NULL, 439 /*machine=*/NULL, 440 /*e_flags=*/NULL, &is_big_endian); 441 } 442 if (capstone_init(e_machine, &handle, is_64bit, is_big_endian, disassembler_style) < 0) 443 goto err; 444 445 needs_cs_close = true; 446 447 free_count = count = perf_cs_disasm(handle, buf, buf_len, start, buf_len, &insn); 448 for (i = 0, offset = 0; i < count; i++) { 449 int printed; 450 451 printed = scnprintf(disasm_buf, sizeof(disasm_buf), 452 " %-7s %s", 453 insn[i].mnemonic, insn[i].op_str); 454 print_capstone_detail(&insn[i], disasm_buf + printed, 455 sizeof(disasm_buf) - printed, args, 456 start + offset); 457 458 args->offset = offset; 459 args->line = disasm_buf; 460 461 dl = disasm_line__new(args); 462 if (dl == NULL) 463 goto err; 464 465 annotation_line__add(&dl->al, ¬es->src->source); 466 467 offset += insn[i].size; 468 } 469 470 /* It failed in the middle: probably due to unknown instructions */ 471 if (offset != buf_len) { 472 struct list_head *list = ¬es->src->source; 473 474 /* Discard all lines and fallback to objdump */ 475 while (!list_empty(list)) { 476 dl = list_first_entry(list, struct disasm_line, al.node); 477 478 list_del_init(&dl->al.node); 479 disasm_line__free(dl); 480 } 481 count = -1; 482 } 483 484 out: 485 if (needs_cs_close) { 486 perf_cs_close(&handle); 487 if (free_count > 0) 488 perf_cs_free(insn, free_count); 489 } 490 free(code_buf); 491 return count < 0 ? count : 0; 492 493 err: 494 if (needs_cs_close) { 495 struct disasm_line *tmp; 496 497 /* 498 * It probably failed in the middle of the above loop. 499 * Release any resources it might add. 500 */ 501 list_for_each_entry_safe(dl, tmp, ¬es->src->source, al.node) { 502 list_del(&dl->al.node); 503 disasm_line__free(dl); 504 } 505 } 506 count = -1; 507 goto out; 508 } 509 510 int symbol__disassemble_capstone_powerpc(const char *filename __maybe_unused, 511 struct symbol *sym __maybe_unused, 512 struct annotate_args *args __maybe_unused) 513 { 514 struct annotation *notes = symbol__annotation(sym); 515 struct map *map = args->ms->map; 516 struct dso *dso = map__dso(map); 517 struct nscookie nsc; 518 u64 start = map__rip_2objdump(map, sym->start); 519 u64 end = map__rip_2objdump(map, sym->end); 520 u64 len = end - start; 521 u64 offset; 522 int i, fd, count; 523 bool is_64bit = false; 524 bool needs_cs_close = false; 525 u8 *buf = NULL; 526 struct find_file_offset_data data = { 527 .ip = start, 528 }; 529 csh handle; 530 char disasm_buf[512]; 531 struct disasm_line *dl; 532 u32 *line; 533 bool disassembler_style = false; 534 uint16_t e_machine = EM_NONE; 535 bool is_big_endian = false; 536 537 if (args->options->objdump_path) 538 return -1; 539 540 nsinfo__mountns_enter(dso__nsinfo(dso), &nsc); 541 fd = open(filename, O_RDONLY); 542 nsinfo__mountns_exit(&nsc); 543 if (fd < 0) 544 return -1; 545 546 if (file__read_maps(fd, /*exe=*/true, find_file_offset, &data, 547 &is_64bit) == 0) 548 goto err; 549 550 if (!args->options->disassembler_style || 551 !strcmp(args->options->disassembler_style, "att")) 552 disassembler_style = true; 553 554 if (args->ms->thread) { 555 e_machine = thread__e_machine_endian(args->ms->thread, 556 /*machine=*/NULL, 557 /*e_flags=*/NULL, &is_big_endian); 558 } else if (dso) { 559 struct maps *kmaps = (map && dso__kernel(dso)) ? map__kmaps(map) : NULL; 560 struct machine *kmap_machine = kmaps ? maps__machine(kmaps) : NULL; 561 562 e_machine = dso__e_machine_endian(dso, kmap_machine, /*e_flags=*/NULL, 563 &is_big_endian); 564 } 565 if (!e_machine || e_machine == EM_NONE) { 566 e_machine = thread__e_machine_endian(NULL, 567 /*machine=*/NULL, 568 /*e_flags=*/NULL, &is_big_endian); 569 } 570 if (capstone_init(e_machine, &handle, is_64bit, is_big_endian, disassembler_style) < 0) 571 goto err; 572 573 needs_cs_close = true; 574 575 buf = malloc(len); 576 if (buf == NULL) 577 goto err; 578 579 count = pread(fd, buf, len, data.offset); 580 close(fd); 581 fd = -1; 582 583 if ((u64)count != len) 584 goto err; 585 586 line = (u32 *)buf; 587 588 /* add the function address and name */ 589 scnprintf(disasm_buf, sizeof(disasm_buf), "%#"PRIx64" <%s>:", 590 start, sym->name); 591 592 args->offset = -1; 593 args->line = disasm_buf; 594 args->line_nr = 0; 595 args->fileloc = NULL; 596 args->ms->sym = sym; 597 598 dl = disasm_line__new(args); 599 if (dl == NULL) 600 goto err; 601 602 annotation_line__add(&dl->al, ¬es->src->source); 603 604 /* 605 * TODO: enable disassm for powerpc 606 * count = cs_disasm(handle, buf, len, start, len, &insn); 607 * 608 * For now, only binary code is saved in disassembled line 609 * to be used in "type" and "typeoff" sort keys. Each raw code 610 * is 32 bit instruction. So use "len/4" to get the number of 611 * entries. 612 */ 613 count = len/4; 614 615 for (i = 0, offset = 0; i < count; i++) { 616 args->offset = offset; 617 sprintf(args->line, "%x", line[i]); 618 619 dl = disasm_line__new(args); 620 if (dl == NULL) 621 break; 622 623 annotation_line__add(&dl->al, ¬es->src->source); 624 625 offset += 4; 626 } 627 628 /* It failed in the middle */ 629 if (offset != len) { 630 struct list_head *list = ¬es->src->source; 631 632 /* Discard all lines and fallback to objdump */ 633 while (!list_empty(list)) { 634 dl = list_first_entry(list, struct disasm_line, al.node); 635 636 list_del_init(&dl->al.node); 637 disasm_line__free(dl); 638 } 639 count = -1; 640 } 641 642 out: 643 if (needs_cs_close) 644 perf_cs_close(&handle); 645 free(buf); 646 return count < 0 ? count : 0; 647 648 err: 649 if (fd >= 0) 650 close(fd); 651 count = -1; 652 goto out; 653 } 654