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

Configure Feed

Select the types of activity you want to include in your feed.

perf capstone: Support for dlopen-ing libcapstone.so

If perf is built with LIBCAPSTONE_DLOPEN=1, support dlopen-ing
libcapstone.so and then calling the necessary functions by looking them
up using dlsym.

The types come from capstone.h which means the libcapstone feature check
needs to pass, and NO_CAPSTONE=1 hasn't been defined. This will cause
the definition of HAVE_LIBCAPSTONE_SUPPORT.

Earlier versions of this code tried to declare the necessary
capstone.h constants and structs, but they weren't stable and caused
breakages across libcapstone releases.

Signed-off-by: Ian Rogers <irogers@google.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.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: 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: 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>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

authored by

Ian Rogers and committed by
Arnaldo Carvalho de Melo
b5c9bcde 169343cc

+179 -42
+6 -2
tools/perf/Makefile.config
··· 1078 1078 $(call feature_check,libcapstone) 1079 1079 ifeq ($(feature-libcapstone), 1) 1080 1080 CFLAGS += -DHAVE_LIBCAPSTONE_SUPPORT $(LIBCAPSTONE_CFLAGS) 1081 - LDFLAGS += $(LICAPSTONE_LDFLAGS) 1082 - EXTLIBS += -lcapstone 1081 + ifdef LIBCAPSTONE_DLOPEN 1082 + CFLAGS += -DLIBCAPSTONE_DLOPEN 1083 + else 1084 + LDFLAGS += $(LIBCAPSTONE_LDFLAGS) 1085 + EXTLIBS += -lcapstone 1086 + endif 1083 1087 $(call detected,CONFIG_LIBCAPSTONE) 1084 1088 else 1085 1089 msg := $(warning No libcapstone found, disables disasm engine support for 'perf script', please install libcapstone-dev/capstone-devel);
+2
tools/perf/tests/make
··· 85 85 make_libunwind := LIBUNWIND=1 86 86 make_no_backtrace := NO_BACKTRACE=1 87 87 make_no_libcapstone := NO_CAPSTONE=1 88 + make_libcapstone_dlopen := LIBCAPSTONE_DLOPEN=1 88 89 make_no_libnuma := NO_LIBNUMA=1 89 90 make_no_libbionic := NO_LIBBIONIC=1 90 91 make_no_libbpf := NO_LIBBPF=1 ··· 160 159 run += make_no_libdw_dwarf_unwind 161 160 run += make_no_backtrace 162 161 run += make_no_libcapstone 162 + run += make_libcapstone_dlopen 163 163 run += make_no_libnuma 164 164 run += make_no_libbionic 165 165 run += make_no_libbpf
+1 -1
tools/perf/util/Build
··· 11 11 perf-util-y += block-range.o 12 12 perf-util-y += build-id.o 13 13 perf-util-y += cacheline.o 14 - perf-util-y += capstone.o 14 + perf-util-$(CONFIG_LIBCAPSTONE) += capstone.o 15 15 perf-util-y += config.o 16 16 perf-util-y += copyfile.o 17 17 perf-util-y += ctype.o
+137 -39
tools/perf/util/capstone.c
··· 11 11 #include "print_insn.h" 12 12 #include "symbol.h" 13 13 #include "thread.h" 14 + #include <dlfcn.h> 14 15 #include <errno.h> 15 16 #include <fcntl.h> 17 + #include <inttypes.h> 16 18 #include <string.h> 17 19 18 - #ifdef HAVE_LIBCAPSTONE_SUPPORT 19 20 #include <capstone/capstone.h> 21 + 22 + #ifdef LIBCAPSTONE_DLOPEN 23 + static void *perf_cs_dll_handle(void) 24 + { 25 + static bool dll_handle_init; 26 + static void *dll_handle; 27 + 28 + if (!dll_handle_init) { 29 + dll_handle_init = true; 30 + dll_handle = dlopen("libcapstone.so", RTLD_LAZY); 31 + if (!dll_handle) 32 + pr_debug("dlopen failed for libcapstone.so\n"); 33 + } 34 + return dll_handle; 35 + } 20 36 #endif 21 37 22 - #ifdef HAVE_LIBCAPSTONE_SUPPORT 38 + static enum cs_err perf_cs_open(enum cs_arch arch, enum cs_mode mode, csh *handle) 39 + { 40 + #ifndef LIBCAPSTONE_DLOPEN 41 + return cs_open(arch, mode, handle); 42 + #else 43 + static bool fn_init; 44 + static enum cs_err (*fn)(enum cs_arch arch, enum cs_mode mode, csh *handle); 45 + 46 + if (!fn_init) { 47 + fn = dlsym(perf_cs_dll_handle(), "cs_open"); 48 + if (!fn) 49 + pr_debug("dlsym failed for cs_open\n"); 50 + fn_init = true; 51 + } 52 + if (!fn) 53 + return CS_ERR_HANDLE; 54 + return fn(arch, mode, handle); 55 + #endif 56 + } 57 + 58 + static enum cs_err perf_cs_option(csh handle, enum cs_opt_type type, size_t value) 59 + { 60 + #ifndef LIBCAPSTONE_DLOPEN 61 + return cs_option(handle, type, value); 62 + #else 63 + static bool fn_init; 64 + static enum cs_err (*fn)(csh handle, enum cs_opt_type type, size_t value); 65 + 66 + if (!fn_init) { 67 + fn = dlsym(perf_cs_dll_handle(), "cs_option"); 68 + if (!fn) 69 + pr_debug("dlsym failed for cs_option\n"); 70 + fn_init = true; 71 + } 72 + if (!fn) 73 + return CS_ERR_HANDLE; 74 + return fn(handle, type, value); 75 + #endif 76 + } 77 + 78 + static size_t perf_cs_disasm(csh handle, const uint8_t *code, size_t code_size, 79 + uint64_t address, size_t count, struct cs_insn **insn) 80 + { 81 + #ifndef LIBCAPSTONE_DLOPEN 82 + return cs_disasm(handle, code, code_size, address, count, insn); 83 + #else 84 + static bool fn_init; 85 + static enum cs_err (*fn)(csh handle, const uint8_t *code, size_t code_size, 86 + uint64_t address, size_t count, struct cs_insn **insn); 87 + 88 + if (!fn_init) { 89 + fn = dlsym(perf_cs_dll_handle(), "cs_disasm"); 90 + if (!fn) 91 + pr_debug("dlsym failed for cs_disasm\n"); 92 + fn_init = true; 93 + } 94 + if (!fn) 95 + return CS_ERR_HANDLE; 96 + return fn(handle, code, code_size, address, count, insn); 97 + #endif 98 + } 99 + 100 + static void perf_cs_free(struct cs_insn *insn, size_t count) 101 + { 102 + #ifndef LIBCAPSTONE_DLOPEN 103 + cs_free(insn, count); 104 + #else 105 + static bool fn_init; 106 + static void (*fn)(struct cs_insn *insn, size_t count); 107 + 108 + if (!fn_init) { 109 + fn = dlsym(perf_cs_dll_handle(), "cs_free"); 110 + if (!fn) 111 + pr_debug("dlsym failed for cs_free\n"); 112 + fn_init = true; 113 + } 114 + if (!fn) 115 + return; 116 + fn(insn, count); 117 + #endif 118 + } 119 + 120 + static enum cs_err perf_cs_close(csh *handle) 121 + { 122 + #ifndef LIBCAPSTONE_DLOPEN 123 + return cs_close(handle); 124 + #else 125 + static bool fn_init; 126 + static enum cs_err (*fn)(csh *handle); 127 + 128 + if (!fn_init) { 129 + fn = dlsym(perf_cs_dll_handle(), "cs_close"); 130 + if (!fn) 131 + pr_debug("dlsym failed for cs_close\n"); 132 + fn_init = true; 133 + } 134 + if (!fn) 135 + return CS_ERR_HANDLE; 136 + return fn(handle); 137 + #endif 138 + } 139 + 23 140 static int capstone_init(struct machine *machine, csh *cs_handle, bool is64, 24 141 bool disassembler_style) 25 142 { 26 - cs_arch arch; 27 - cs_mode mode; 143 + enum cs_arch arch; 144 + enum cs_mode mode; 28 145 29 146 if (machine__is(machine, "x86_64") && is64) { 30 147 arch = CS_ARCH_X86; ··· 162 45 return -1; 163 46 } 164 47 165 - if (cs_open(arch, mode, cs_handle) != CS_ERR_OK) { 48 + if (perf_cs_open(arch, mode, cs_handle) != CS_ERR_OK) { 166 49 pr_warning_once("cs_open failed\n"); 167 50 return -1; 168 51 } ··· 174 57 * is set via annotation args 175 58 */ 176 59 if (disassembler_style) 177 - cs_option(*cs_handle, CS_OPT_SYNTAX, CS_OPT_SYNTAX_ATT); 60 + perf_cs_option(*cs_handle, CS_OPT_SYNTAX, CS_OPT_SYNTAX_ATT); 178 61 /* 179 62 * Resolving address operands to symbols is implemented 180 63 * on x86 by investigating instruction details. 181 64 */ 182 - cs_option(*cs_handle, CS_OPT_DETAIL, CS_OPT_ON); 65 + perf_cs_option(*cs_handle, CS_OPT_DETAIL, CS_OPT_ON); 183 66 } 184 67 185 68 return 0; 186 69 } 187 - #endif 188 70 189 - #ifdef HAVE_LIBCAPSTONE_SUPPORT 190 - static size_t print_insn_x86(struct thread *thread, u8 cpumode, cs_insn *insn, 71 + static size_t print_insn_x86(struct thread *thread, u8 cpumode, struct cs_insn *insn, 191 72 int print_opts, FILE *fp) 192 73 { 193 74 struct addr_location al; 194 75 size_t printed = 0; 195 76 196 77 if (insn->detail && insn->detail->x86.op_count == 1) { 197 - cs_x86_op *op = &insn->detail->x86.operands[0]; 78 + struct cs_x86_op *op = &insn->detail->x86.operands[0]; 198 79 199 80 addr_location__init(&al); 200 81 if (op->type == X86_OP_IMM && ··· 210 95 printed += fprintf(fp, "%s %s", insn[0].mnemonic, insn[0].op_str); 211 96 return printed; 212 97 } 213 - #endif 214 98 215 99 216 100 ssize_t capstone__fprintf_insn_asm(struct machine *machine __maybe_unused, ··· 220 106 uint64_t ip __maybe_unused, int *lenp __maybe_unused, 221 107 int print_opts __maybe_unused, FILE *fp __maybe_unused) 222 108 { 223 - #ifdef HAVE_LIBCAPSTONE_SUPPORT 224 109 size_t printed; 225 - cs_insn *insn; 110 + struct cs_insn *insn; 226 111 csh cs_handle; 227 112 size_t count; 228 113 int ret; ··· 231 118 if (ret < 0) 232 119 return ret; 233 120 234 - count = cs_disasm(cs_handle, code, code_size, ip, 1, &insn); 121 + count = perf_cs_disasm(cs_handle, code, code_size, ip, 1, &insn); 235 122 if (count > 0) { 236 123 if (machine__normalized_is(machine, "x86")) 237 124 printed = print_insn_x86(thread, cpumode, &insn[0], print_opts, fp); ··· 239 126 printed = fprintf(fp, "%s %s", insn[0].mnemonic, insn[0].op_str); 240 127 if (lenp) 241 128 *lenp = insn->size; 242 - cs_free(insn, count); 129 + perf_cs_free(insn, count); 243 130 } else { 244 131 printed = -1; 245 132 } 246 133 247 - cs_close(&cs_handle); 134 + perf_cs_close(&cs_handle); 248 135 return printed; 249 - #else 250 - return -1; 251 - #endif 252 136 } 253 137 254 - #ifdef HAVE_LIBCAPSTONE_SUPPORT 255 - static void print_capstone_detail(cs_insn *insn, char *buf, size_t len, 138 + static void print_capstone_detail(struct cs_insn *insn, char *buf, size_t len, 256 139 struct annotate_args *args, u64 addr) 257 140 { 258 141 int i; ··· 263 154 return; 264 155 265 156 for (i = 0; i < insn->detail->x86.op_count; i++) { 266 - cs_x86_op *op = &insn->detail->x86.operands[i]; 157 + struct cs_x86_op *op = &insn->detail->x86.operands[i]; 267 158 u64 orig_addr; 268 159 269 160 if (op->type != X86_OP_MEM) ··· 304 195 break; 305 196 } 306 197 } 307 - #endif 308 198 309 - #ifdef HAVE_LIBCAPSTONE_SUPPORT 310 199 struct find_file_offset_data { 311 200 u64 ip; 312 201 u64 offset; ··· 321 214 } 322 215 return 0; 323 216 } 324 - #endif 325 217 326 218 int symbol__disassemble_capstone(const char *filename __maybe_unused, 327 219 struct symbol *sym __maybe_unused, 328 220 struct annotate_args *args __maybe_unused) 329 221 { 330 - #ifdef HAVE_LIBCAPSTONE_SUPPORT 331 222 struct annotation *notes = symbol__annotation(sym); 332 223 struct map *map = args->ms->map; 333 224 struct dso *dso = map__dso(map); ··· 340 235 const u8 *buf; 341 236 u64 buf_len; 342 237 csh handle; 343 - cs_insn *insn = NULL; 238 + struct cs_insn *insn = NULL; 344 239 char disasm_buf[512]; 345 240 struct disasm_line *dl; 346 241 bool disassembler_style = false; ··· 379 274 380 275 needs_cs_close = true; 381 276 382 - free_count = count = cs_disasm(handle, buf, buf_len, start, buf_len, &insn); 277 + free_count = count = perf_cs_disasm(handle, buf, buf_len, start, buf_len, &insn); 383 278 for (i = 0, offset = 0; i < count; i++) { 384 279 int printed; 385 280 ··· 418 313 419 314 out: 420 315 if (needs_cs_close) { 421 - cs_close(&handle); 316 + perf_cs_close(&handle); 422 317 if (free_count > 0) 423 - cs_free(insn, free_count); 318 + perf_cs_free(insn, free_count); 424 319 } 425 320 free(code_buf); 426 321 return count < 0 ? count : 0; ··· 440 335 } 441 336 count = -1; 442 337 goto out; 443 - #else 444 - return -1; 445 - #endif 446 338 } 447 339 448 340 int symbol__disassemble_capstone_powerpc(const char *filename __maybe_unused, 449 341 struct symbol *sym __maybe_unused, 450 342 struct annotate_args *args __maybe_unused) 451 343 { 452 - #ifdef HAVE_LIBCAPSTONE_SUPPORT 453 344 struct annotation *notes = symbol__annotation(sym); 454 345 struct map *map = args->ms->map; 455 346 struct dso *dso = map__dso(map); ··· 559 458 560 459 out: 561 460 if (needs_cs_close) 562 - cs_close(&handle); 461 + perf_cs_close(&handle); 563 462 free(buf); 564 463 return count < 0 ? count : 0; 565 464 ··· 568 467 close(fd); 569 468 count = -1; 570 469 goto out; 571 - #else 572 - return -1; 573 - #endif 574 470 }
+33
tools/perf/util/capstone.h
··· 6 6 #include <stdint.h> 7 7 #include <stdio.h> 8 8 #include <stdlib.h> 9 + #include <linux/compiler.h> 9 10 #include <linux/types.h> 10 11 11 12 struct annotate_args; ··· 14 13 struct symbol; 15 14 struct thread; 16 15 16 + #ifdef HAVE_LIBCAPSTONE_SUPPORT 17 17 ssize_t capstone__fprintf_insn_asm(struct machine *machine, struct thread *thread, u8 cpumode, 18 18 bool is64bit, const uint8_t *code, size_t code_size, 19 19 uint64_t ip, int *lenp, int print_opts, FILE *fp); ··· 22 20 struct annotate_args *args); 23 21 int symbol__disassemble_capstone_powerpc(const char *filename, struct symbol *sym, 24 22 struct annotate_args *args); 23 + 24 + #else /* !HAVE_LIBCAPSTONE_SUPPORT */ 25 + static inline ssize_t capstone__fprintf_insn_asm(struct machine *machine __maybe_unused, 26 + struct thread *thread __maybe_unused, 27 + u8 cpumode __maybe_unused, 28 + bool is64bit __maybe_unused, 29 + const uint8_t *code __maybe_unused, 30 + size_t code_size __maybe_unused, 31 + uint64_t ip __maybe_unused, 32 + int *lenp __maybe_unused, 33 + int print_opts __maybe_unused, 34 + FILE *fp __maybe_unused) 35 + { 36 + return -1; 37 + } 38 + 39 + static inline int symbol__disassemble_capstone(const char *filename __maybe_unused, 40 + struct symbol *sym __maybe_unused, 41 + struct annotate_args *args __maybe_unused) 42 + { 43 + return -1; 44 + } 45 + 46 + static inline int symbol__disassemble_capstone_powerpc(const char *filename __maybe_unused, 47 + struct symbol *sym __maybe_unused, 48 + struct annotate_args *args __maybe_unused) 49 + { 50 + return -1; 51 + } 52 + 53 + #endif /* HAVE_LIBCAPSTONE_SUPPORT */ 25 54 26 55 #endif /* __PERF_CAPSTONE_H */