Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

perf capstone: Move capstone functionality into its own file

Capstone disassembly support was split between disasm.c and
print_insn.c. Move support out of these files into capstone.[ch] and
remove include capstone/capstone.h from those files. As disassembly
routines can fail, make failure the only option without
HAVE_LIBCAPSTONE_SUPPORT. For simplicity's sake, duplicate the
read_symbol utility function.

The intent with moving capstone support into a single file is that
dynamic support, using dlopen for libcapstone, can be added in later
patches. This can potentially always succeed or fail, so relying on
ifdefs isn't sufficient. Using dlopen is a useful option to minimize
the perf tools dependencies and potentially size.

Signed-off-by: Ian Rogers <irogers@google.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Alexandre Ghiti <alexghiti@rivosinc.com>
Cc: Andi Kleen <ak@linux.intel.com>
Cc: Athira Rajeev <atrajeev@linux.ibm.com>
Cc: Bill Wendling <morbo@google.com>
Cc: Charlie Jenkins <charlie@rivosinc.com>
Cc: Collin Funk <collin.funk1@gmail.com>
Cc: Dmitriy Vyukov <dvyukov@google.com>
Cc: Dr. David Alan Gilbert <linux@treblig.org>
Cc: Eric Biggers <ebiggers@kernel.org>
Cc: Haibo Xu <haibo1.xu@intel.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: James Clark <james.clark@linaro.org>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Justin Stitt <justinstitt@google.com>
Cc: Li Huafei <lihuafei1@huawei.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Masami Hiramatsu <mhiramat@kernel.org>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Nathan Chancellor <nathan@kernel.org>
Cc: Nick Desaulniers <nick.desaulniers+lkml@gmail.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Song Liu <song@kernel.org>
Cc: Stephen Brennan <stephen.s.brennan@oracle.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

authored by

Ian Rogers and committed by
Arnaldo Carvalho de Melo
bbb99668 c0b8a55a

+569 -467
-2
tools/perf/builtin-script.c
··· 1225 1225 u8 *inbuf, int inlen, int *lenp, 1226 1226 FILE *fp) 1227 1227 { 1228 - #ifdef HAVE_LIBCAPSTONE_SUPPORT 1229 1228 if (PRINT_FIELD(BRSTACKDISASM)) { 1230 1229 int printed = fprintf_insn_asm(x->machine, x->thread, x->cpumode, x->is64bit, 1231 1230 (uint8_t *)inbuf, inlen, ip, lenp, ··· 1233 1234 if (printed > 0) 1234 1235 return printed; 1235 1236 } 1236 - #endif 1237 1237 return fprintf(fp, "%s", dump_insn(x, ip, inbuf, inlen, lenp)); 1238 1238 } 1239 1239
+1
tools/perf/util/Build
··· 8 8 perf-util-y += block-range.o 9 9 perf-util-y += build-id.o 10 10 perf-util-y += cacheline.o 11 + perf-util-y += capstone.o 11 12 perf-util-y += config.o 12 13 perf-util-y += copyfile.o 13 14 perf-util-y += ctype.o
+536
tools/perf/util/capstone.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + #include "capstone.h" 3 + #include "annotate.h" 4 + #include "addr_location.h" 5 + #include "debug.h" 6 + #include "disasm.h" 7 + #include "dso.h" 8 + #include "machine.h" 9 + #include "map.h" 10 + #include "namespaces.h" 11 + #include "print_insn.h" 12 + #include "symbol.h" 13 + #include "thread.h" 14 + #include <fcntl.h> 15 + #include <string.h> 16 + 17 + #ifdef HAVE_LIBCAPSTONE_SUPPORT 18 + #include <capstone/capstone.h> 19 + #endif 20 + 21 + #ifdef HAVE_LIBCAPSTONE_SUPPORT 22 + static int capstone_init(struct machine *machine, csh *cs_handle, bool is64, 23 + bool disassembler_style) 24 + { 25 + cs_arch arch; 26 + cs_mode mode; 27 + 28 + if (machine__is(machine, "x86_64") && is64) { 29 + arch = CS_ARCH_X86; 30 + mode = CS_MODE_64; 31 + } else if (machine__normalized_is(machine, "x86")) { 32 + arch = CS_ARCH_X86; 33 + mode = CS_MODE_32; 34 + } else if (machine__normalized_is(machine, "arm64")) { 35 + arch = CS_ARCH_ARM64; 36 + mode = CS_MODE_ARM; 37 + } else if (machine__normalized_is(machine, "arm")) { 38 + arch = CS_ARCH_ARM; 39 + mode = CS_MODE_ARM + CS_MODE_V8; 40 + } else if (machine__normalized_is(machine, "s390")) { 41 + arch = CS_ARCH_SYSZ; 42 + mode = CS_MODE_BIG_ENDIAN; 43 + } else { 44 + return -1; 45 + } 46 + 47 + if (cs_open(arch, mode, cs_handle) != CS_ERR_OK) { 48 + pr_warning_once("cs_open failed\n"); 49 + return -1; 50 + } 51 + 52 + if (machine__normalized_is(machine, "x86")) { 53 + /* 54 + * In case of using capstone_init while symbol__disassemble 55 + * setting CS_OPT_SYNTAX_ATT depends if disassembler_style opts 56 + * is set via annotation args 57 + */ 58 + if (disassembler_style) 59 + cs_option(*cs_handle, CS_OPT_SYNTAX, CS_OPT_SYNTAX_ATT); 60 + /* 61 + * Resolving address operands to symbols is implemented 62 + * on x86 by investigating instruction details. 63 + */ 64 + cs_option(*cs_handle, CS_OPT_DETAIL, CS_OPT_ON); 65 + } 66 + 67 + return 0; 68 + } 69 + #endif 70 + 71 + #ifdef HAVE_LIBCAPSTONE_SUPPORT 72 + static size_t print_insn_x86(struct thread *thread, u8 cpumode, cs_insn *insn, 73 + int print_opts, FILE *fp) 74 + { 75 + struct addr_location al; 76 + size_t printed = 0; 77 + 78 + if (insn->detail && insn->detail->x86.op_count == 1) { 79 + cs_x86_op *op = &insn->detail->x86.operands[0]; 80 + 81 + addr_location__init(&al); 82 + if (op->type == X86_OP_IMM && 83 + thread__find_symbol(thread, cpumode, op->imm, &al)) { 84 + printed += fprintf(fp, "%s ", insn[0].mnemonic); 85 + printed += symbol__fprintf_symname_offs(al.sym, &al, fp); 86 + if (print_opts & PRINT_INSN_IMM_HEX) 87 + printed += fprintf(fp, " [%#" PRIx64 "]", op->imm); 88 + addr_location__exit(&al); 89 + return printed; 90 + } 91 + addr_location__exit(&al); 92 + } 93 + 94 + printed += fprintf(fp, "%s %s", insn[0].mnemonic, insn[0].op_str); 95 + return printed; 96 + } 97 + #endif 98 + 99 + 100 + ssize_t capstone__fprintf_insn_asm(struct machine *machine __maybe_unused, 101 + struct thread *thread __maybe_unused, 102 + u8 cpumode __maybe_unused, bool is64bit __maybe_unused, 103 + const uint8_t *code __maybe_unused, 104 + size_t code_size __maybe_unused, 105 + uint64_t ip __maybe_unused, int *lenp __maybe_unused, 106 + int print_opts __maybe_unused, FILE *fp __maybe_unused) 107 + { 108 + #ifdef HAVE_LIBCAPSTONE_SUPPORT 109 + size_t printed; 110 + cs_insn *insn; 111 + csh cs_handle; 112 + size_t count; 113 + int ret; 114 + 115 + /* TODO: Try to initiate capstone only once but need a proper place. */ 116 + ret = capstone_init(machine, &cs_handle, is64bit, true); 117 + if (ret < 0) 118 + return ret; 119 + 120 + count = cs_disasm(cs_handle, code, code_size, ip, 1, &insn); 121 + if (count > 0) { 122 + if (machine__normalized_is(machine, "x86")) 123 + printed = print_insn_x86(thread, cpumode, &insn[0], print_opts, fp); 124 + else 125 + printed = fprintf(fp, "%s %s", insn[0].mnemonic, insn[0].op_str); 126 + if (lenp) 127 + *lenp = insn->size; 128 + cs_free(insn, count); 129 + } else { 130 + printed = -1; 131 + } 132 + 133 + cs_close(&cs_handle); 134 + return printed; 135 + #else 136 + return -1; 137 + #endif 138 + } 139 + 140 + #ifdef HAVE_LIBCAPSTONE_SUPPORT 141 + static int open_capstone_handle(struct annotate_args *args, bool is_64bit, csh *handle) 142 + { 143 + struct annotation_options *opt = args->options; 144 + cs_mode mode = is_64bit ? CS_MODE_64 : CS_MODE_32; 145 + 146 + /* TODO: support more architectures */ 147 + if (!arch__is(args->arch, "x86")) 148 + return -1; 149 + 150 + if (cs_open(CS_ARCH_X86, mode, handle) != CS_ERR_OK) 151 + return -1; 152 + 153 + if (!opt->disassembler_style || 154 + !strcmp(opt->disassembler_style, "att")) 155 + cs_option(*handle, CS_OPT_SYNTAX, CS_OPT_SYNTAX_ATT); 156 + 157 + /* 158 + * Resolving address operands to symbols is implemented 159 + * on x86 by investigating instruction details. 160 + */ 161 + cs_option(*handle, CS_OPT_DETAIL, CS_OPT_ON); 162 + 163 + return 0; 164 + } 165 + #endif 166 + 167 + #ifdef HAVE_LIBCAPSTONE_SUPPORT 168 + static void print_capstone_detail(cs_insn *insn, char *buf, size_t len, 169 + struct annotate_args *args, u64 addr) 170 + { 171 + int i; 172 + struct map *map = args->ms.map; 173 + struct symbol *sym; 174 + 175 + /* TODO: support more architectures */ 176 + if (!arch__is(args->arch, "x86")) 177 + return; 178 + 179 + if (insn->detail == NULL) 180 + return; 181 + 182 + for (i = 0; i < insn->detail->x86.op_count; i++) { 183 + cs_x86_op *op = &insn->detail->x86.operands[i]; 184 + u64 orig_addr; 185 + 186 + if (op->type != X86_OP_MEM) 187 + continue; 188 + 189 + /* only print RIP-based global symbols for now */ 190 + if (op->mem.base != X86_REG_RIP) 191 + continue; 192 + 193 + /* get the target address */ 194 + orig_addr = addr + insn->size + op->mem.disp; 195 + addr = map__objdump_2mem(map, orig_addr); 196 + 197 + if (dso__kernel(map__dso(map))) { 198 + /* 199 + * The kernel maps can be split into sections, let's 200 + * find the map first and the search the symbol. 201 + */ 202 + map = maps__find(map__kmaps(map), addr); 203 + if (map == NULL) 204 + continue; 205 + } 206 + 207 + /* convert it to map-relative address for search */ 208 + addr = map__map_ip(map, addr); 209 + 210 + sym = map__find_symbol(map, addr); 211 + if (sym == NULL) 212 + continue; 213 + 214 + if (addr == sym->start) { 215 + scnprintf(buf, len, "\t# %"PRIx64" <%s>", 216 + orig_addr, sym->name); 217 + } else { 218 + scnprintf(buf, len, "\t# %"PRIx64" <%s+%#"PRIx64">", 219 + orig_addr, sym->name, addr - sym->start); 220 + } 221 + break; 222 + } 223 + } 224 + #endif 225 + 226 + #ifdef HAVE_LIBCAPSTONE_SUPPORT 227 + struct find_file_offset_data { 228 + u64 ip; 229 + u64 offset; 230 + }; 231 + 232 + /* This will be called for each PHDR in an ELF binary */ 233 + static int find_file_offset(u64 start, u64 len, u64 pgoff, void *arg) 234 + { 235 + struct find_file_offset_data *data = arg; 236 + 237 + if (start <= data->ip && data->ip < start + len) { 238 + data->offset = pgoff + data->ip - start; 239 + return 1; 240 + } 241 + return 0; 242 + } 243 + #endif 244 + 245 + #ifdef HAVE_LIBCAPSTONE_SUPPORT 246 + static u8 * 247 + read_symbol(const char *filename, struct map *map, struct symbol *sym, 248 + u64 *len, bool *is_64bit) 249 + { 250 + struct dso *dso = map__dso(map); 251 + struct nscookie nsc; 252 + u64 start = map__rip_2objdump(map, sym->start); 253 + u64 end = map__rip_2objdump(map, sym->end); 254 + int fd, count; 255 + u8 *buf = NULL; 256 + struct find_file_offset_data data = { 257 + .ip = start, 258 + }; 259 + 260 + *is_64bit = false; 261 + 262 + nsinfo__mountns_enter(dso__nsinfo(dso), &nsc); 263 + fd = open(filename, O_RDONLY); 264 + nsinfo__mountns_exit(&nsc); 265 + if (fd < 0) 266 + return NULL; 267 + 268 + if (file__read_maps(fd, /*exe=*/true, find_file_offset, &data, 269 + is_64bit) == 0) 270 + goto err; 271 + 272 + *len = end - start; 273 + buf = malloc(*len); 274 + if (buf == NULL) 275 + goto err; 276 + 277 + count = pread(fd, buf, *len, data.offset); 278 + close(fd); 279 + fd = -1; 280 + 281 + if ((u64)count != *len) 282 + goto err; 283 + 284 + return buf; 285 + 286 + err: 287 + if (fd >= 0) 288 + close(fd); 289 + free(buf); 290 + return NULL; 291 + } 292 + #endif 293 + 294 + int symbol__disassemble_capstone(const char *filename __maybe_unused, 295 + struct symbol *sym __maybe_unused, 296 + struct annotate_args *args __maybe_unused) 297 + { 298 + #ifdef HAVE_LIBCAPSTONE_SUPPORT 299 + struct annotation *notes = symbol__annotation(sym); 300 + struct map *map = args->ms.map; 301 + u64 start = map__rip_2objdump(map, sym->start); 302 + u64 len; 303 + u64 offset; 304 + int i, count, free_count; 305 + bool is_64bit = false; 306 + bool needs_cs_close = false; 307 + u8 *buf = NULL; 308 + csh handle; 309 + cs_insn *insn = NULL; 310 + char disasm_buf[512]; 311 + struct disasm_line *dl; 312 + 313 + if (args->options->objdump_path) 314 + return -1; 315 + 316 + buf = read_symbol(filename, map, sym, &len, &is_64bit); 317 + if (buf == NULL) 318 + return -1; 319 + 320 + /* add the function address and name */ 321 + scnprintf(disasm_buf, sizeof(disasm_buf), "%#"PRIx64" <%s>:", 322 + start, sym->name); 323 + 324 + args->offset = -1; 325 + args->line = disasm_buf; 326 + args->line_nr = 0; 327 + args->fileloc = NULL; 328 + args->ms.sym = sym; 329 + 330 + dl = disasm_line__new(args); 331 + if (dl == NULL) 332 + goto err; 333 + 334 + annotation_line__add(&dl->al, &notes->src->source); 335 + 336 + if (open_capstone_handle(args, is_64bit, &handle) < 0) 337 + goto err; 338 + 339 + needs_cs_close = true; 340 + 341 + free_count = count = cs_disasm(handle, buf, len, start, len, &insn); 342 + for (i = 0, offset = 0; i < count; i++) { 343 + int printed; 344 + 345 + printed = scnprintf(disasm_buf, sizeof(disasm_buf), 346 + " %-7s %s", 347 + insn[i].mnemonic, insn[i].op_str); 348 + print_capstone_detail(&insn[i], disasm_buf + printed, 349 + sizeof(disasm_buf) - printed, args, 350 + start + offset); 351 + 352 + args->offset = offset; 353 + args->line = disasm_buf; 354 + 355 + dl = disasm_line__new(args); 356 + if (dl == NULL) 357 + goto err; 358 + 359 + annotation_line__add(&dl->al, &notes->src->source); 360 + 361 + offset += insn[i].size; 362 + } 363 + 364 + /* It failed in the middle: probably due to unknown instructions */ 365 + if (offset != len) { 366 + struct list_head *list = &notes->src->source; 367 + 368 + /* Discard all lines and fallback to objdump */ 369 + while (!list_empty(list)) { 370 + dl = list_first_entry(list, struct disasm_line, al.node); 371 + 372 + list_del_init(&dl->al.node); 373 + disasm_line__free(dl); 374 + } 375 + count = -1; 376 + } 377 + 378 + out: 379 + if (needs_cs_close) { 380 + cs_close(&handle); 381 + if (free_count > 0) 382 + cs_free(insn, free_count); 383 + } 384 + free(buf); 385 + return count < 0 ? count : 0; 386 + 387 + err: 388 + if (needs_cs_close) { 389 + struct disasm_line *tmp; 390 + 391 + /* 392 + * It probably failed in the middle of the above loop. 393 + * Release any resources it might add. 394 + */ 395 + list_for_each_entry_safe(dl, tmp, &notes->src->source, al.node) { 396 + list_del(&dl->al.node); 397 + disasm_line__free(dl); 398 + } 399 + } 400 + count = -1; 401 + goto out; 402 + #else 403 + return -1; 404 + #endif 405 + } 406 + 407 + int symbol__disassemble_capstone_powerpc(const char *filename __maybe_unused, 408 + struct symbol *sym __maybe_unused, 409 + struct annotate_args *args __maybe_unused) 410 + { 411 + #ifdef HAVE_LIBCAPSTONE_SUPPORT 412 + struct annotation *notes = symbol__annotation(sym); 413 + struct map *map = args->ms.map; 414 + struct dso *dso = map__dso(map); 415 + struct nscookie nsc; 416 + u64 start = map__rip_2objdump(map, sym->start); 417 + u64 end = map__rip_2objdump(map, sym->end); 418 + u64 len = end - start; 419 + u64 offset; 420 + int i, fd, count; 421 + bool is_64bit = false; 422 + bool needs_cs_close = false; 423 + u8 *buf = NULL; 424 + struct find_file_offset_data data = { 425 + .ip = start, 426 + }; 427 + csh handle; 428 + char disasm_buf[512]; 429 + struct disasm_line *dl; 430 + u32 *line; 431 + bool disassembler_style = false; 432 + 433 + if (args->options->objdump_path) 434 + return -1; 435 + 436 + nsinfo__mountns_enter(dso__nsinfo(dso), &nsc); 437 + fd = open(filename, O_RDONLY); 438 + nsinfo__mountns_exit(&nsc); 439 + if (fd < 0) 440 + return -1; 441 + 442 + if (file__read_maps(fd, /*exe=*/true, find_file_offset, &data, 443 + &is_64bit) == 0) 444 + goto err; 445 + 446 + if (!args->options->disassembler_style || 447 + !strcmp(args->options->disassembler_style, "att")) 448 + disassembler_style = true; 449 + 450 + if (capstone_init(maps__machine(args->ms.maps), &handle, is_64bit, disassembler_style) < 0) 451 + goto err; 452 + 453 + needs_cs_close = true; 454 + 455 + buf = malloc(len); 456 + if (buf == NULL) 457 + goto err; 458 + 459 + count = pread(fd, buf, len, data.offset); 460 + close(fd); 461 + fd = -1; 462 + 463 + if ((u64)count != len) 464 + goto err; 465 + 466 + line = (u32 *)buf; 467 + 468 + /* add the function address and name */ 469 + scnprintf(disasm_buf, sizeof(disasm_buf), "%#"PRIx64" <%s>:", 470 + start, sym->name); 471 + 472 + args->offset = -1; 473 + args->line = disasm_buf; 474 + args->line_nr = 0; 475 + args->fileloc = NULL; 476 + args->ms.sym = sym; 477 + 478 + dl = disasm_line__new(args); 479 + if (dl == NULL) 480 + goto err; 481 + 482 + annotation_line__add(&dl->al, &notes->src->source); 483 + 484 + /* 485 + * TODO: enable disassm for powerpc 486 + * count = cs_disasm(handle, buf, len, start, len, &insn); 487 + * 488 + * For now, only binary code is saved in disassembled line 489 + * to be used in "type" and "typeoff" sort keys. Each raw code 490 + * is 32 bit instruction. So use "len/4" to get the number of 491 + * entries. 492 + */ 493 + count = len/4; 494 + 495 + for (i = 0, offset = 0; i < count; i++) { 496 + args->offset = offset; 497 + sprintf(args->line, "%x", line[i]); 498 + 499 + dl = disasm_line__new(args); 500 + if (dl == NULL) 501 + break; 502 + 503 + annotation_line__add(&dl->al, &notes->src->source); 504 + 505 + offset += 4; 506 + } 507 + 508 + /* It failed in the middle */ 509 + if (offset != len) { 510 + struct list_head *list = &notes->src->source; 511 + 512 + /* Discard all lines and fallback to objdump */ 513 + while (!list_empty(list)) { 514 + dl = list_first_entry(list, struct disasm_line, al.node); 515 + 516 + list_del_init(&dl->al.node); 517 + disasm_line__free(dl); 518 + } 519 + count = -1; 520 + } 521 + 522 + out: 523 + if (needs_cs_close) 524 + cs_close(&handle); 525 + free(buf); 526 + return count < 0 ? count : 0; 527 + 528 + err: 529 + if (fd >= 0) 530 + close(fd); 531 + count = -1; 532 + goto out; 533 + #else 534 + return -1; 535 + #endif 536 + }
+24
tools/perf/util/capstone.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + #ifndef __PERF_CAPSTONE_H 3 + #define __PERF_CAPSTONE_H 4 + 5 + #include <stdbool.h> 6 + #include <stdint.h> 7 + #include <stdio.h> 8 + #include <stdlib.h> 9 + #include <linux/types.h> 10 + 11 + struct annotate_args; 12 + struct machine; 13 + struct symbol; 14 + struct thread; 15 + 16 + ssize_t capstone__fprintf_insn_asm(struct machine *machine, struct thread *thread, u8 cpumode, 17 + bool is64bit, const uint8_t *code, size_t code_size, 18 + uint64_t ip, int *lenp, int print_opts, FILE *fp); 19 + int symbol__disassemble_capstone(const char *filename, struct symbol *sym, 20 + struct annotate_args *args); 21 + int symbol__disassemble_capstone_powerpc(const char *filename, struct symbol *sym, 22 + struct annotate_args *args); 23 + 24 + #endif /* __PERF_CAPSTONE_H */
+5 -351
tools/perf/util/disasm.c
··· 14 14 #include "annotate.h" 15 15 #include "annotate-data.h" 16 16 #include "build-id.h" 17 + #include "capstone.h" 17 18 #include "debug.h" 18 19 #include "disasm.h" 19 20 #include "disasm_bpf.h" ··· 1334 1333 return 0; 1335 1334 } 1336 1335 1337 - #ifdef HAVE_LIBCAPSTONE_SUPPORT 1338 - #include <capstone/capstone.h> 1339 - 1340 - int capstone_init(struct machine *machine, csh *cs_handle, bool is64, bool disassembler_style); 1341 - 1342 - static int open_capstone_handle(struct annotate_args *args, bool is_64bit, 1343 - csh *handle) 1344 - { 1345 - struct annotation_options *opt = args->options; 1346 - cs_mode mode = is_64bit ? CS_MODE_64 : CS_MODE_32; 1347 - 1348 - /* TODO: support more architectures */ 1349 - if (!arch__is(args->arch, "x86")) 1350 - return -1; 1351 - 1352 - if (cs_open(CS_ARCH_X86, mode, handle) != CS_ERR_OK) 1353 - return -1; 1354 - 1355 - if (!opt->disassembler_style || 1356 - !strcmp(opt->disassembler_style, "att")) 1357 - cs_option(*handle, CS_OPT_SYNTAX, CS_OPT_SYNTAX_ATT); 1358 - 1359 - /* 1360 - * Resolving address operands to symbols is implemented 1361 - * on x86 by investigating instruction details. 1362 - */ 1363 - cs_option(*handle, CS_OPT_DETAIL, CS_OPT_ON); 1364 - 1365 - return 0; 1366 - } 1367 - #endif 1368 - 1369 - #if defined(HAVE_LIBCAPSTONE_SUPPORT) || defined(HAVE_LIBLLVM_SUPPORT) 1336 + #if defined(HAVE_LIBLLVM_SUPPORT) 1370 1337 struct find_file_offset_data { 1371 1338 u64 ip; 1372 1339 u64 offset; ··· 1399 1430 return NULL; 1400 1431 } 1401 1432 #endif 1402 - 1403 - #if !defined(HAVE_LIBCAPSTONE_SUPPORT) || !defined(HAVE_LIBLLVM_SUPPORT) 1404 - static void symbol__disassembler_missing(const char *disassembler, const char *filename, 1405 - struct symbol *sym) 1406 - { 1407 - pr_debug("The %s disassembler isn't linked in for %s in %s\n", 1408 - disassembler, sym->name, filename); 1409 - } 1410 - #endif 1411 - 1412 - #ifdef HAVE_LIBCAPSTONE_SUPPORT 1413 - static void print_capstone_detail(cs_insn *insn, char *buf, size_t len, 1414 - struct annotate_args *args, u64 addr) 1415 - { 1416 - int i; 1417 - struct map *map = args->ms.map; 1418 - struct symbol *sym; 1419 - 1420 - /* TODO: support more architectures */ 1421 - if (!arch__is(args->arch, "x86")) 1422 - return; 1423 - 1424 - if (insn->detail == NULL) 1425 - return; 1426 - 1427 - for (i = 0; i < insn->detail->x86.op_count; i++) { 1428 - cs_x86_op *op = &insn->detail->x86.operands[i]; 1429 - u64 orig_addr; 1430 - 1431 - if (op->type != X86_OP_MEM) 1432 - continue; 1433 - 1434 - /* only print RIP-based global symbols for now */ 1435 - if (op->mem.base != X86_REG_RIP) 1436 - continue; 1437 - 1438 - /* get the target address */ 1439 - orig_addr = addr + insn->size + op->mem.disp; 1440 - addr = map__objdump_2mem(map, orig_addr); 1441 - 1442 - if (dso__kernel(map__dso(map))) { 1443 - /* 1444 - * The kernel maps can be splitted into sections, 1445 - * let's find the map first and the search the symbol. 1446 - */ 1447 - map = maps__find(map__kmaps(map), addr); 1448 - if (map == NULL) 1449 - continue; 1450 - } 1451 - 1452 - /* convert it to map-relative address for search */ 1453 - addr = map__map_ip(map, addr); 1454 - 1455 - sym = map__find_symbol(map, addr); 1456 - if (sym == NULL) 1457 - continue; 1458 - 1459 - if (addr == sym->start) { 1460 - scnprintf(buf, len, "\t# %"PRIx64" <%s>", 1461 - orig_addr, sym->name); 1462 - } else { 1463 - scnprintf(buf, len, "\t# %"PRIx64" <%s+%#"PRIx64">", 1464 - orig_addr, sym->name, addr - sym->start); 1465 - } 1466 - break; 1467 - } 1468 - } 1469 - 1470 - static int symbol__disassemble_capstone_powerpc(char *filename, struct symbol *sym, 1471 - struct annotate_args *args) 1472 - { 1473 - struct annotation *notes = symbol__annotation(sym); 1474 - struct map *map = args->ms.map; 1475 - struct dso *dso = map__dso(map); 1476 - struct nscookie nsc; 1477 - u64 start = map__rip_2objdump(map, sym->start); 1478 - u64 end = map__rip_2objdump(map, sym->end); 1479 - u64 len = end - start; 1480 - u64 offset; 1481 - int i, fd, count; 1482 - bool is_64bit = false; 1483 - bool needs_cs_close = false; 1484 - u8 *buf = NULL; 1485 - struct find_file_offset_data data = { 1486 - .ip = start, 1487 - }; 1488 - csh handle; 1489 - char disasm_buf[512]; 1490 - struct disasm_line *dl; 1491 - u32 *line; 1492 - bool disassembler_style = false; 1493 - 1494 - if (args->options->objdump_path) 1495 - return -1; 1496 - 1497 - nsinfo__mountns_enter(dso__nsinfo(dso), &nsc); 1498 - fd = open(filename, O_RDONLY); 1499 - nsinfo__mountns_exit(&nsc); 1500 - if (fd < 0) 1501 - return -1; 1502 - 1503 - if (file__read_maps(fd, /*exe=*/true, find_file_offset, &data, 1504 - &is_64bit) == 0) 1505 - goto err; 1506 - 1507 - if (!args->options->disassembler_style || 1508 - !strcmp(args->options->disassembler_style, "att")) 1509 - disassembler_style = true; 1510 - 1511 - if (capstone_init(maps__machine(args->ms.maps), &handle, is_64bit, disassembler_style) < 0) 1512 - goto err; 1513 - 1514 - needs_cs_close = true; 1515 - 1516 - buf = malloc(len); 1517 - if (buf == NULL) 1518 - goto err; 1519 - 1520 - count = pread(fd, buf, len, data.offset); 1521 - close(fd); 1522 - fd = -1; 1523 - 1524 - if ((u64)count != len) 1525 - goto err; 1526 - 1527 - line = (u32 *)buf; 1528 - 1529 - /* add the function address and name */ 1530 - scnprintf(disasm_buf, sizeof(disasm_buf), "%#"PRIx64" <%s>:", 1531 - start, sym->name); 1532 - 1533 - args->offset = -1; 1534 - args->line = disasm_buf; 1535 - args->line_nr = 0; 1536 - args->fileloc = NULL; 1537 - args->ms.sym = sym; 1538 - 1539 - dl = disasm_line__new(args); 1540 - if (dl == NULL) 1541 - goto err; 1542 - 1543 - annotation_line__add(&dl->al, &notes->src->source); 1544 - 1545 - /* 1546 - * TODO: enable disassm for powerpc 1547 - * count = cs_disasm(handle, buf, len, start, len, &insn); 1548 - * 1549 - * For now, only binary code is saved in disassembled line 1550 - * to be used in "type" and "typeoff" sort keys. Each raw code 1551 - * is 32 bit instruction. So use "len/4" to get the number of 1552 - * entries. 1553 - */ 1554 - count = len/4; 1555 - 1556 - for (i = 0, offset = 0; i < count; i++) { 1557 - args->offset = offset; 1558 - sprintf(args->line, "%x", line[i]); 1559 - 1560 - dl = disasm_line__new(args); 1561 - if (dl == NULL) 1562 - break; 1563 - 1564 - annotation_line__add(&dl->al, &notes->src->source); 1565 - 1566 - offset += 4; 1567 - } 1568 - 1569 - /* It failed in the middle */ 1570 - if (offset != len) { 1571 - struct list_head *list = &notes->src->source; 1572 - 1573 - /* Discard all lines and fallback to objdump */ 1574 - while (!list_empty(list)) { 1575 - dl = list_first_entry(list, struct disasm_line, al.node); 1576 - 1577 - list_del_init(&dl->al.node); 1578 - disasm_line__free(dl); 1579 - } 1580 - count = -1; 1581 - } 1582 - 1583 - out: 1584 - if (needs_cs_close) 1585 - cs_close(&handle); 1586 - free(buf); 1587 - return count < 0 ? count : 0; 1588 - 1589 - err: 1590 - if (fd >= 0) 1591 - close(fd); 1592 - count = -1; 1593 - goto out; 1594 - } 1595 - 1596 - static int symbol__disassemble_capstone(char *filename, struct symbol *sym, 1597 - struct annotate_args *args) 1598 - { 1599 - struct annotation *notes = symbol__annotation(sym); 1600 - struct map *map = args->ms.map; 1601 - u64 start = map__rip_2objdump(map, sym->start); 1602 - u64 len; 1603 - u64 offset; 1604 - int i, count, free_count; 1605 - bool is_64bit = false; 1606 - bool needs_cs_close = false; 1607 - u8 *buf = NULL; 1608 - csh handle; 1609 - cs_insn *insn = NULL; 1610 - char disasm_buf[512]; 1611 - struct disasm_line *dl; 1612 - 1613 - if (args->options->objdump_path) 1614 - return -1; 1615 - 1616 - buf = read_symbol(filename, map, sym, &len, &is_64bit); 1617 - if (buf == NULL) 1618 - return -1; 1619 - 1620 - /* add the function address and name */ 1621 - scnprintf(disasm_buf, sizeof(disasm_buf), "%#"PRIx64" <%s>:", 1622 - start, sym->name); 1623 - 1624 - args->offset = -1; 1625 - args->line = disasm_buf; 1626 - args->line_nr = 0; 1627 - args->fileloc = NULL; 1628 - args->ms.sym = sym; 1629 - 1630 - dl = disasm_line__new(args); 1631 - if (dl == NULL) 1632 - goto err; 1633 - 1634 - annotation_line__add(&dl->al, &notes->src->source); 1635 - 1636 - if (open_capstone_handle(args, is_64bit, &handle) < 0) 1637 - goto err; 1638 - 1639 - needs_cs_close = true; 1640 - 1641 - free_count = count = cs_disasm(handle, buf, len, start, len, &insn); 1642 - for (i = 0, offset = 0; i < count; i++) { 1643 - int printed; 1644 - 1645 - printed = scnprintf(disasm_buf, sizeof(disasm_buf), 1646 - " %-7s %s", 1647 - insn[i].mnemonic, insn[i].op_str); 1648 - print_capstone_detail(&insn[i], disasm_buf + printed, 1649 - sizeof(disasm_buf) - printed, args, 1650 - start + offset); 1651 - 1652 - args->offset = offset; 1653 - args->line = disasm_buf; 1654 - 1655 - dl = disasm_line__new(args); 1656 - if (dl == NULL) 1657 - goto err; 1658 - 1659 - annotation_line__add(&dl->al, &notes->src->source); 1660 - 1661 - offset += insn[i].size; 1662 - } 1663 - 1664 - /* It failed in the middle: probably due to unknown instructions */ 1665 - if (offset != len) { 1666 - struct list_head *list = &notes->src->source; 1667 - 1668 - /* Discard all lines and fallback to objdump */ 1669 - while (!list_empty(list)) { 1670 - dl = list_first_entry(list, struct disasm_line, al.node); 1671 - 1672 - list_del_init(&dl->al.node); 1673 - disasm_line__free(dl); 1674 - } 1675 - count = -1; 1676 - } 1677 - 1678 - out: 1679 - if (needs_cs_close) { 1680 - cs_close(&handle); 1681 - if (free_count > 0) 1682 - cs_free(insn, free_count); 1683 - } 1684 - free(buf); 1685 - return count < 0 ? count : 0; 1686 - 1687 - err: 1688 - if (needs_cs_close) { 1689 - struct disasm_line *tmp; 1690 - 1691 - /* 1692 - * It probably failed in the middle of the above loop. 1693 - * Release any resources it might add. 1694 - */ 1695 - list_for_each_entry_safe(dl, tmp, &notes->src->source, al.node) { 1696 - list_del(&dl->al.node); 1697 - disasm_line__free(dl); 1698 - } 1699 - } 1700 - count = -1; 1701 - goto out; 1702 - } 1703 - #else // HAVE_LIBCAPSTONE_SUPPORT 1704 - static int symbol__disassemble_capstone(char *filename, struct symbol *sym, 1705 - struct annotate_args *args __maybe_unused) 1706 - { 1707 - symbol__disassembler_missing("capstone", filename, sym); 1708 - return -1; 1709 - } 1710 - 1711 - static int symbol__disassemble_capstone_powerpc(char *filename, struct symbol *sym, 1712 - struct annotate_args *args __maybe_unused) 1713 - { 1714 - symbol__disassembler_missing("capstone powerpc", filename, sym); 1715 - return -1; 1716 - } 1717 - #endif // HAVE_LIBCAPSTONE_SUPPORT 1718 1433 1719 1434 static int symbol__disassemble_raw(char *filename, struct symbol *sym, 1720 1435 struct annotate_args *args) ··· 1667 2014 return ret; 1668 2015 } 1669 2016 #else // HAVE_LIBLLVM_SUPPORT 1670 - static int symbol__disassemble_llvm(char *filename, struct symbol *sym, 2017 + static int symbol__disassemble_llvm(const char *filename, struct symbol *sym, 1671 2018 struct annotate_args *args __maybe_unused) 1672 2019 { 1673 - symbol__disassembler_missing("LLVM", filename, sym); 2020 + pr_debug("The LLVM disassembler isn't linked in for %s in %s\n", 2021 + sym->name, filename); 1674 2022 return -1; 1675 2023 } 1676 2024 #endif // HAVE_LIBLLVM_SUPPORT
+3 -114
tools/perf/util/print_insn.c
··· 7 7 #include <inttypes.h> 8 8 #include <string.h> 9 9 #include <stdbool.h> 10 + #include "capstone.h" 10 11 #include "debug.h" 11 12 #include "sample.h" 12 13 #include "symbol.h" ··· 30 29 return printed; 31 30 } 32 31 33 - #ifdef HAVE_LIBCAPSTONE_SUPPORT 34 - #include <capstone/capstone.h> 35 - 36 - int capstone_init(struct machine *machine, csh *cs_handle, bool is64, bool disassembler_style); 37 - 38 - int capstone_init(struct machine *machine, csh *cs_handle, bool is64, bool disassembler_style) 39 - { 40 - cs_arch arch; 41 - cs_mode mode; 42 - 43 - if (machine__is(machine, "x86_64") && is64) { 44 - arch = CS_ARCH_X86; 45 - mode = CS_MODE_64; 46 - } else if (machine__normalized_is(machine, "x86")) { 47 - arch = CS_ARCH_X86; 48 - mode = CS_MODE_32; 49 - } else if (machine__normalized_is(machine, "arm64")) { 50 - arch = CS_ARCH_ARM64; 51 - mode = CS_MODE_ARM; 52 - } else if (machine__normalized_is(machine, "arm")) { 53 - arch = CS_ARCH_ARM; 54 - mode = CS_MODE_ARM + CS_MODE_V8; 55 - } else if (machine__normalized_is(machine, "s390")) { 56 - arch = CS_ARCH_SYSZ; 57 - mode = CS_MODE_BIG_ENDIAN; 58 - } else { 59 - return -1; 60 - } 61 - 62 - if (cs_open(arch, mode, cs_handle) != CS_ERR_OK) { 63 - pr_warning_once("cs_open failed\n"); 64 - return -1; 65 - } 66 - 67 - if (machine__normalized_is(machine, "x86")) { 68 - /* 69 - * In case of using capstone_init while symbol__disassemble 70 - * setting CS_OPT_SYNTAX_ATT depends if disassembler_style opts 71 - * is set via annotation args 72 - */ 73 - if (disassembler_style) 74 - cs_option(*cs_handle, CS_OPT_SYNTAX, CS_OPT_SYNTAX_ATT); 75 - /* 76 - * Resolving address operands to symbols is implemented 77 - * on x86 by investigating instruction details. 78 - */ 79 - cs_option(*cs_handle, CS_OPT_DETAIL, CS_OPT_ON); 80 - } 81 - 82 - return 0; 83 - } 84 - 85 - static size_t print_insn_x86(struct thread *thread, u8 cpumode, cs_insn *insn, 86 - int print_opts, FILE *fp) 87 - { 88 - struct addr_location al; 89 - size_t printed = 0; 90 - 91 - if (insn->detail && insn->detail->x86.op_count == 1) { 92 - cs_x86_op *op = &insn->detail->x86.operands[0]; 93 - 94 - addr_location__init(&al); 95 - if (op->type == X86_OP_IMM && 96 - thread__find_symbol(thread, cpumode, op->imm, &al)) { 97 - printed += fprintf(fp, "%s ", insn[0].mnemonic); 98 - printed += symbol__fprintf_symname_offs(al.sym, &al, fp); 99 - if (print_opts & PRINT_INSN_IMM_HEX) 100 - printed += fprintf(fp, " [%#" PRIx64 "]", op->imm); 101 - addr_location__exit(&al); 102 - return printed; 103 - } 104 - addr_location__exit(&al); 105 - } 106 - 107 - printed += fprintf(fp, "%s %s", insn[0].mnemonic, insn[0].op_str); 108 - return printed; 109 - } 110 - 111 32 static bool is64bitip(struct machine *machine, struct addr_location *al) 112 33 { 113 34 const struct dso *dso = al->map ? map__dso(al->map) : NULL; ··· 46 123 bool is64bit, const uint8_t *code, size_t code_size, 47 124 uint64_t ip, int *lenp, int print_opts, FILE *fp) 48 125 { 49 - size_t printed; 50 - cs_insn *insn; 51 - csh cs_handle; 52 - size_t count; 53 - int ret; 54 - 55 - /* TODO: Try to initiate capstone only once but need a proper place. */ 56 - ret = capstone_init(machine, &cs_handle, is64bit, true); 57 - if (ret < 0) 58 - return ret; 59 - 60 - count = cs_disasm(cs_handle, code, code_size, ip, 1, &insn); 61 - if (count > 0) { 62 - if (machine__normalized_is(machine, "x86")) 63 - printed = print_insn_x86(thread, cpumode, &insn[0], print_opts, fp); 64 - else 65 - printed = fprintf(fp, "%s %s", insn[0].mnemonic, insn[0].op_str); 66 - if (lenp) 67 - *lenp = insn->size; 68 - cs_free(insn, count); 69 - } else { 70 - printed = -1; 71 - } 72 - 73 - cs_close(&cs_handle); 74 - return printed; 126 + return capstone__fprintf_insn_asm(machine, thread, cpumode, is64bit, code, code_size, 127 + ip, lenp, print_opts, fp); 75 128 } 76 129 77 130 size_t sample__fprintf_insn_asm(struct perf_sample *sample, struct thread *thread, ··· 65 166 66 167 return printed; 67 168 } 68 - #else 69 - size_t sample__fprintf_insn_asm(struct perf_sample *sample __maybe_unused, 70 - struct thread *thread __maybe_unused, 71 - struct machine *machine __maybe_unused, 72 - FILE *fp __maybe_unused, 73 - struct addr_location *al __maybe_unused) 74 - { 75 - return 0; 76 - } 77 - #endif