On Fri, Jan 24, 2025 at 2:22 PM Namhyung Kim <namhyung@xxxxxxxxxx> wrote: > > On Wed, Jan 22, 2025 at 09:42:56AM -0800, Ian Rogers wrote: > > If perf wasn't built against libcapstone, no HAVE_LIBCAPSTONE_SUPPORT, > > support dlopen-ing libcapstone.so and then calling the necessary > > functions by looking them up using dlsym. Reverse engineer the types > > in the API using pahole, adding only what's used in the perf code or > > necessary for the sake of struct size and alignment. > > > > Signed-off-by: Ian Rogers <irogers@xxxxxxxxxx> > > --- > > tools/perf/util/capstone.c | 287 ++++++++++++++++++++++++++++++++----- > > 1 file changed, 248 insertions(+), 39 deletions(-) > > > > diff --git a/tools/perf/util/capstone.c b/tools/perf/util/capstone.c > > index c9845e4d8781..8d65c7a55a8b 100644 > > --- a/tools/perf/util/capstone.c > > +++ b/tools/perf/util/capstone.c > > @@ -11,19 +11,249 @@ > > #include "print_insn.h" > > #include "symbol.h" > > #include "thread.h" > > +#include <dlfcn.h> > > #include <fcntl.h> > > +#include <inttypes.h> > > These two can go under #else (!HAVE_LIBCAPSTONE_SUPPORT). Ack. > > #include <string.h> > > > > #ifdef HAVE_LIBCAPSTONE_SUPPORT > > #include <capstone/capstone.h> > > +#else > > +typedef size_t csh; > > +enum cs_arch { > > + CS_ARCH_ARM = 0, > > + CS_ARCH_ARM64 = 1, > > + CS_ARCH_X86 = 3, > > + CS_ARCH_SYSZ = 6, > > +}; > > +enum cs_mode { > > + CS_MODE_ARM = 0, > > + CS_MODE_32 = 1 << 2, > > + CS_MODE_64 = 1 << 3, > > + CS_MODE_V8 = 1 << 6, > > + CS_MODE_BIG_ENDIAN = 1 << 31, > > +}; > > +enum cs_opt_type { > > + CS_OPT_SYNTAX = 1, > > + CS_OPT_DETAIL = 2, > > +}; > > +enum cs_opt_value { > > + CS_OPT_SYNTAX_ATT = 2, > > + CS_OPT_ON = 3, > > +}; > > +enum cs_err { > > + CS_ERR_OK = 0, > > + CS_ERR_HANDLE = 3, > > +}; > > +enum x86_op_type { > > + X86_OP_IMM = 2, > > + X86_OP_MEM = 3, > > +}; > > +enum x86_reg { > > + X86_REG_RIP = 41, > > +}; > > +typedef int32_t x86_avx_bcast; > > +struct x86_op_mem { > > + enum x86_reg segment; > > + enum x86_reg base; > > + enum x86_reg index; > > + int scale; > > + int64_t disp; > > +}; > > + > > +struct cs_x86_op { > > + enum x86_op_type type; > > + union { > > + enum x86_reg reg; > > + int64_t imm; > > + struct x86_op_mem mem; > > + }; > > + uint8_t size; > > + uint8_t access; > > + x86_avx_bcast avx_bcast; > > + bool avx_zero_opmask; > > +}; > > +struct cs_x86_encoding { > > + uint8_t modrm_offset; > > + uint8_t disp_offset; > > + uint8_t disp_size; > > + uint8_t imm_offset; > > + uint8_t imm_size; > > +}; > > +typedef int32_t x86_xop_cc; > > +typedef int32_t x86_sse_cc; > > +typedef int32_t x86_avx_cc; > > +typedef int32_t x86_avx_rm; > > +struct cs_x86 { > > + uint8_t prefix[4]; > > + uint8_t opcode[4]; > > + uint8_t rex; > > + uint8_t addr_size; > > + uint8_t modrm; > > + uint8_t sib; > > + int64_t disp; > > + enum x86_reg sib_index; > > + int8_t sib_scale; > > + enum x86_reg sib_base; > > + x86_xop_cc xop_cc; > > + x86_sse_cc sse_cc; > > + x86_avx_cc avx_cc; > > + bool avx_sae; > > + x86_avx_rm avx_rm; > > + union { > > + uint64_t eflags; > > + uint64_t fpu_flags; > > + }; > > + uint8_t op_count; > > + struct cs_x86_op operands[8]; > > + struct cs_x86_encoding encoding; > > +}; > > +struct cs_detail { > > + uint16_t regs_read[12]; > > + uint8_t regs_read_count; > > + uint16_t regs_write[20]; > > + uint8_t regs_write_count; > > + uint8_t groups[8]; > > + uint8_t groups_count; > > + > > + union { > > + struct cs_x86 x86; > > + }; > > +}; > > As discussed, let's remove the detail part. I kind of feel there should be a #warning in that case. I'd rather leave it as is and not have a build warning. > > +struct cs_insn { > > + unsigned int id; > > + uint64_t address; > > + uint16_t size; > > + uint8_t bytes[16]; > > + char mnemonic[32]; > > + char op_str[160]; > > + struct cs_detail *detail; > > +}; > > +#endif > > + > > +#ifndef HAVE_LIBCAPSTONE_SUPPORT > > +static void *perf_cs_dll_handle(void) > > +{ > > + static bool dll_handle_init; > > + static void *dll_handle; > > + > > + if (!dll_handle_init) { > > + dll_handle_init = true; > > + dll_handle = dlopen("libcapstone.so", RTLD_LAZY); > > + if (!dll_handle) > > + pr_debug("dlopen failed for libcapstone.so\n"); > > + } > > + return dll_handle; > > +} > > +#endif > > + > > +static enum cs_err perf_cs_open(enum cs_arch arch, enum cs_mode mode, csh *handle) > > +{ > > +#ifdef HAVE_LIBCAPSTONE_SUPPORT > > + return cs_open(arch, mode, handle); > > +#else > > + static bool fn_init; > > + static enum cs_err (*fn)(enum cs_arch arch, enum cs_mode mode, csh *handle); > > + > > + if (!fn_init) { > > + fn = dlsym(perf_cs_dll_handle(), "cs_open"); > > + if (!fn) > > + pr_debug("dlsym failed for cs_open\n"); > > + fn_init = true; > > + } > > + if (!fn) > > + return CS_ERR_HANDLE; > > + return fn(arch, mode, handle); > > +#endif > > +} > > I think it's better to organize the code with less #ifdef's. I think this reduces readability - 100s of lines where it isn't clear there is something conditional going on, or losing the fact a function is a shim. More details in: https://lore.kernel.org/lkml/CAP-5=fV0w9tLFr7xYHFUH=UUq+tr+o5EYUik0d74rMWa9=Qi+A@xxxxxxxxxxxxxx/ Thanks, Ian