lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <Z5FwusFZ_bYlu6aK@google.com>
Date: Wed, 22 Jan 2025 14:27:06 -0800
From: Namhyung Kim <namhyung@...nel.org>
To: Ian Rogers <irogers@...gle.com>
Cc: Peter Zijlstra <peterz@...radead.org>, Ingo Molnar <mingo@...hat.com>,
	Arnaldo Carvalho de Melo <acme@...nel.org>,
	Mark Rutland <mark.rutland@....com>,
	Alexander Shishkin <alexander.shishkin@...ux.intel.com>,
	Jiri Olsa <jolsa@...nel.org>,
	Adrian Hunter <adrian.hunter@...el.com>,
	Kan Liang <kan.liang@...ux.intel.com>,
	Nathan Chancellor <nathan@...nel.org>,
	Nick Desaulniers <ndesaulniers@...gle.com>,
	Bill Wendling <morbo@...gle.com>,
	Justin Stitt <justinstitt@...gle.com>,
	"Steinar H. Gunderson" <sesse@...gle.com>,
	Charlie Jenkins <charlie@...osinc.com>,
	Changbin Du <changbin.du@...wei.com>,
	"Masami Hiramatsu (Google)" <mhiramat@...nel.org>,
	James Clark <james.clark@...aro.org>,
	Kajol Jain <kjain@...ux.ibm.com>,
	Athira Rajeev <atrajeev@...ux.vnet.ibm.com>,
	Li Huafei <lihuafei1@...wei.com>,
	Dmitry Vyukov <dvyukov@...gle.com>, Andi Kleen <ak@...ux.intel.com>,
	linux-kernel@...r.kernel.org, linux-perf-users@...r.kernel.org,
	llvm@...ts.linux.dev
Subject: Re: [PATCH v1 4/5] perf capstone: Support for dlopen-ing
 libcapstone.so

Hi Ian,

On Mon, Jan 20, 2025 at 09:32:07AM -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.

I think reverse engineering the types is fragile.  Can we simply change
to dlopen if libcapstone is available?

Thanks,
Namhyung

> 
> Signed-off-by: Ian Rogers <irogers@...gle.com>
> ---
>  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>
>  #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;
> +	};
> +};
> +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
> +}
> +
> +static enum cs_err perf_cs_option(csh handle, enum cs_opt_type type, size_t value)
> +{
> +#ifdef HAVE_LIBCAPSTONE_SUPPORT
> +	return cs_option(handle, type, value);
> +#else
> +	static bool fn_init;
> +	static enum cs_err (*fn)(csh handle, enum cs_opt_type type, size_t value);
> +
> +	if (!fn_init) {
> +		fn = dlsym(perf_cs_dll_handle(), "cs_option");
> +		if (!fn)
> +			pr_debug("dlsym failed for cs_option\n");
> +		fn_init = true;
> +	}
> +	if (!fn)
> +		return CS_ERR_HANDLE;
> +	return fn(handle, type, value);
> +#endif
> +}
> +
> +static size_t perf_cs_disasm(csh handle, const uint8_t *code, size_t code_size,
> +			uint64_t address, size_t count, struct cs_insn **insn)
> +{
> +#ifdef HAVE_LIBCAPSTONE_SUPPORT
> +	return cs_disasm(handle, code, code_size, address, count, insn);
> +#else
> +	static bool fn_init;
> +	static enum cs_err (*fn)(csh handle, const uint8_t *code, size_t code_size,
> +				 uint64_t address, size_t count, struct cs_insn **insn);
> +
> +	if (!fn_init) {
> +		fn = dlsym(perf_cs_dll_handle(), "cs_disasm");
> +		if (!fn)
> +			pr_debug("dlsym failed for cs_disasm\n");
> +		fn_init = true;
> +	}
> +	if (!fn)
> +		return CS_ERR_HANDLE;
> +	return fn(handle, code, code_size, address, count, insn);
>  #endif
> +}
>  
> +static void perf_cs_free(struct cs_insn *insn, size_t count)
> +{
>  #ifdef HAVE_LIBCAPSTONE_SUPPORT
> +	cs_free(insn, count);
> +#else
> +	static bool fn_init;
> +	static void (*fn)(struct cs_insn *insn, size_t count);
> +
> +	if (!fn_init) {
> +		fn = dlsym(perf_cs_dll_handle(), "cs_free");
> +		if (!fn)
> +			pr_debug("dlsym failed for cs_free\n");
> +		fn_init = true;
> +	}
> +	if (!fn)
> +		return;
> +	fn(insn, count);
> +#endif
> +}
> +
> +static enum cs_err perf_cs_close(csh *handle)
> +{
> +#ifdef HAVE_LIBCAPSTONE_SUPPORT
> +	return cs_close(handle);
> +#else
> +	static bool fn_init;
> +	static enum cs_err (*fn)(csh *handle);
> +
> +	if (!fn_init) {
> +		fn = dlsym(perf_cs_dll_handle(), "cs_close");
> +		if (!fn)
> +			pr_debug("dlsym failed for cs_close\n");
> +		fn_init = true;
> +	}
> +	if (!fn)
> +		return CS_ERR_HANDLE;
> +	return fn(handle);
> +#endif
> +}
> +
>  static int capstone_init(struct machine *machine, csh *cs_handle, bool is64,
>  			 bool disassembler_style)
>  {
> -	cs_arch arch;
> -	cs_mode mode;
> +	enum cs_arch arch;
> +	enum cs_mode mode;
>  
>  	if (machine__is(machine, "x86_64") && is64) {
>  		arch = CS_ARCH_X86;
> @@ -44,7 +274,7 @@ static int capstone_init(struct machine *machine, csh *cs_handle, bool is64,
>  		return -1;
>  	}
>  
> -	if (cs_open(arch, mode, cs_handle) != CS_ERR_OK) {
> +	if (perf_cs_open(arch, mode, cs_handle) != CS_ERR_OK) {
>  		pr_warning_once("cs_open failed\n");
>  		return -1;
>  	}
> @@ -56,27 +286,25 @@ static int capstone_init(struct machine *machine, csh *cs_handle, bool is64,
>  		 * is set via annotation args
>  		 */
>  		if (disassembler_style)
> -			cs_option(*cs_handle, CS_OPT_SYNTAX, CS_OPT_SYNTAX_ATT);
> +			perf_cs_option(*cs_handle, CS_OPT_SYNTAX, CS_OPT_SYNTAX_ATT);
>  		/*
>  		 * Resolving address operands to symbols is implemented
>  		 * on x86 by investigating instruction details.
>  		 */
> -		cs_option(*cs_handle, CS_OPT_DETAIL, CS_OPT_ON);
> +		perf_cs_option(*cs_handle, CS_OPT_DETAIL, CS_OPT_ON);
>  	}
>  
>  	return 0;
>  }
> -#endif
>  
> -#ifdef HAVE_LIBCAPSTONE_SUPPORT
> -static size_t print_insn_x86(struct thread *thread, u8 cpumode, cs_insn *insn,
> +static size_t print_insn_x86(struct thread *thread, u8 cpumode, struct cs_insn *insn,
>  			     int print_opts, FILE *fp)
>  {
>  	struct addr_location al;
>  	size_t printed = 0;
>  
>  	if (insn->detail && insn->detail->x86.op_count == 1) {
> -		cs_x86_op *op = &insn->detail->x86.operands[0];
> +		struct cs_x86_op *op = &insn->detail->x86.operands[0];
>  
>  		addr_location__init(&al);
>  		if (op->type == X86_OP_IMM &&
> @@ -94,7 +322,6 @@ static size_t print_insn_x86(struct thread *thread, u8 cpumode, cs_insn *insn,
>  	printed += fprintf(fp, "%s %s", insn[0].mnemonic, insn[0].op_str);
>  	return printed;
>  }
> -#endif
>  
>  
>  ssize_t capstone__fprintf_insn_asm(struct machine *machine __maybe_unused,
> @@ -105,9 +332,8 @@ ssize_t capstone__fprintf_insn_asm(struct machine *machine __maybe_unused,
>  				   uint64_t ip __maybe_unused, int *lenp __maybe_unused,
>  				   int print_opts __maybe_unused, FILE *fp __maybe_unused)
>  {
> -#ifdef HAVE_LIBCAPSTONE_SUPPORT
>  	size_t printed;
> -	cs_insn *insn;
> +	struct cs_insn *insn;
>  	csh cs_handle;
>  	size_t count;
>  	int ret;
> @@ -117,7 +343,7 @@ ssize_t capstone__fprintf_insn_asm(struct machine *machine __maybe_unused,
>  	if (ret < 0)
>  		return ret;
>  
> -	count = cs_disasm(cs_handle, code, code_size, ip, 1, &insn);
> +	count = perf_cs_disasm(cs_handle, code, code_size, ip, 1, &insn);
>  	if (count > 0) {
>  		if (machine__normalized_is(machine, "x86"))
>  			printed = print_insn_x86(thread, cpumode, &insn[0], print_opts, fp);
> @@ -125,20 +351,16 @@ ssize_t capstone__fprintf_insn_asm(struct machine *machine __maybe_unused,
>  			printed = fprintf(fp, "%s %s", insn[0].mnemonic, insn[0].op_str);
>  		if (lenp)
>  			*lenp = insn->size;
> -		cs_free(insn, count);
> +		perf_cs_free(insn, count);
>  	} else {
>  		printed = -1;
>  	}
>  
> -	cs_close(&cs_handle);
> +	perf_cs_close(&cs_handle);
>  	return printed;
> -#else
> -	return -1;
> -#endif
>  }
>  
> -#ifdef HAVE_LIBCAPSTONE_SUPPORT
> -static void print_capstone_detail(cs_insn *insn, char *buf, size_t len,
> +static void print_capstone_detail(struct cs_insn *insn, char *buf, size_t len,
>  				  struct annotate_args *args, u64 addr)
>  {
>  	int i;
> @@ -153,7 +375,7 @@ static void print_capstone_detail(cs_insn *insn, char *buf, size_t len,
>  		return;
>  
>  	for (i = 0; i < insn->detail->x86.op_count; i++) {
> -		cs_x86_op *op = &insn->detail->x86.operands[i];
> +		struct cs_x86_op *op = &insn->detail->x86.operands[i];
>  		u64 orig_addr;
>  
>  		if (op->type != X86_OP_MEM)
> @@ -194,9 +416,7 @@ static void print_capstone_detail(cs_insn *insn, char *buf, size_t len,
>  		break;
>  	}
>  }
> -#endif
>  
> -#ifdef HAVE_LIBCAPSTONE_SUPPORT
>  struct find_file_offset_data {
>  	u64 ip;
>  	u64 offset;
> @@ -213,9 +433,7 @@ static int find_file_offset(u64 start, u64 len, u64 pgoff, void *arg)
>  	}
>  	return 0;
>  }
> -#endif
>  
> -#ifdef HAVE_LIBCAPSTONE_SUPPORT
>  static u8 *
>  read_symbol(const char *filename, struct map *map, struct symbol *sym,
>  	    u64 *len, bool *is_64bit)
> @@ -262,13 +480,11 @@ read_symbol(const char *filename, struct map *map, struct symbol *sym,
>  	free(buf);
>  	return NULL;
>  }
> -#endif
>  
>  int symbol__disassemble_capstone(const char *filename __maybe_unused,
>  				 struct symbol *sym __maybe_unused,
>  				 struct annotate_args *args __maybe_unused)
>  {
> -#ifdef HAVE_LIBCAPSTONE_SUPPORT
>  	struct annotation *notes = symbol__annotation(sym);
>  	struct map *map = args->ms.map;
>  	u64 start = map__rip_2objdump(map, sym->start);
> @@ -279,7 +495,7 @@ int symbol__disassemble_capstone(const char *filename __maybe_unused,
>  	bool needs_cs_close = false;
>  	u8 *buf = NULL;
>  	csh handle;
> -	cs_insn *insn = NULL;
> +	struct cs_insn *insn = NULL;
>  	char disasm_buf[512];
>  	struct disasm_line *dl;
>  	bool disassembler_style = false;
> @@ -316,7 +532,7 @@ int symbol__disassemble_capstone(const char *filename __maybe_unused,
>  
>  	needs_cs_close = true;
>  
> -	free_count = count = cs_disasm(handle, buf, len, start, len, &insn);
> +	free_count = count = perf_cs_disasm(handle, buf, len, start, len, &insn);
>  	for (i = 0, offset = 0; i < count; i++) {
>  		int printed;
>  
> @@ -355,9 +571,9 @@ int symbol__disassemble_capstone(const char *filename __maybe_unused,
>  
>  out:
>  	if (needs_cs_close) {
> -		cs_close(&handle);
> +		perf_cs_close(&handle);
>  		if (free_count > 0)
> -			cs_free(insn, free_count);
> +			perf_cs_free(insn, free_count);
>  	}
>  	free(buf);
>  	return count < 0 ? count : 0;
> @@ -377,16 +593,12 @@ int symbol__disassemble_capstone(const char *filename __maybe_unused,
>  	}
>  	count = -1;
>  	goto out;
> -#else
> -	return -1;
> -#endif
>  }
>  
>  int symbol__disassemble_capstone_powerpc(const char *filename __maybe_unused,
>  					 struct symbol *sym __maybe_unused,
>  					 struct annotate_args *args __maybe_unused)
>  {
> -#ifdef HAVE_LIBCAPSTONE_SUPPORT
>  	struct annotation *notes = symbol__annotation(sym);
>  	struct map *map = args->ms.map;
>  	struct dso *dso = map__dso(map);
> @@ -499,7 +711,7 @@ int symbol__disassemble_capstone_powerpc(const char *filename __maybe_unused,
>  
>  out:
>  	if (needs_cs_close)
> -		cs_close(&handle);
> +		perf_cs_close(&handle);
>  	free(buf);
>  	return count < 0 ? count : 0;
>  
> @@ -508,7 +720,4 @@ int symbol__disassemble_capstone_powerpc(const char *filename __maybe_unused,
>  		close(fd);
>  	count = -1;
>  	goto out;
> -#else
> -	return -1;
> -#endif
>  }
> -- 
> 2.48.0.rc2.279.g1de40edade-goog
> 

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ