| 1 | |
| 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 | NULL, &is_big_endian);
|
| 270 | int ret;
|
| 271 |
|
| 272 |
|
| 273 | ret = capstone_init(e_machine, &cs_handle, is64bit, is_big_endian,
|
| 274 | 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 |
|
| 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 |
|
| 318 | if (op->mem.base != X86_REG_RIP)
|
| 319 | continue;
|
| 320 |
|
| 321 |
|
| 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 |
|
| 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 |
|
| 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 |
|
| 386 | u8 *code_buf = NULL;
|
| 387 |
|
| 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 |
|
| 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 | NULL,
|
| 429 | 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, NULL,
|
| 435 | &is_big_endian);
|
| 436 | }
|
| 437 | if (!e_machine || e_machine == EM_NONE) {
|
| 438 | e_machine = thread__e_machine_endian(NULL,
|
| 439 | NULL,
|
| 440 | 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 |
|
| 471 | if (offset != buf_len) {
|
| 472 | struct list_head *list = ¬es->src->source;
|
| 473 |
|
| 474 |
|
| 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, 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 | NULL,
|
| 557 | 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, NULL,
|
| 563 | &is_big_endian);
|
| 564 | }
|
| 565 | if (!e_machine || e_machine == EM_NONE) {
|
| 566 | e_machine = thread__e_machine_endian(NULL,
|
| 567 | NULL,
|
| 568 | 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 |
|
| 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 |
|
| 629 | if (offset != len) {
|
| 630 | struct list_head *list = ¬es->src->source;
|
| 631 |
|
| 632 |
|
| 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 | }
|