From nobody Sat Nov 23 20:19:48 2024 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id EEDE513AA38; Mon, 11 Nov 2024 15:17:57 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731338278; cv=none; b=mlxatlax50U/LECelLmQUGCGvMXh5Nt/GN8aObp8Z4hroHHmhCxv+3FrnT/Uwts8tlIXmFzqmGk5QsIIUeIVFi8i9WAZkkODG+qwhXaVVe+ex2QqIfVhZYZWbog7tWKHnUUWT1vcmTwj+eeQcgRqNRGnKl68QxGGu6CCEpX+KLk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731338278; c=relaxed/simple; bh=8XlzRzF1gBkUhM/gWdpfw1FaK3At+clEa03vKUZgw0k=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Q1NtPyjEdIicGjqvcUYuiDx4QHyK1gHTeKwKpVsBPE3MNQrfj3iy80wtQjN9zb45X0WkRtg+zBytVgMaJJ54/n5Lekg6RJYXM/1eZwTIKXF/jmBCHuuo7RD+YBFdgfoCObRQ+g5SWYzFQ/ZuKVIAGq9RQ22zsz8SEOIEY2ayHMg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=GlYTYeqy; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="GlYTYeqy" Received: by smtp.kernel.org (Postfix) with ESMTPSA id DE928C4CECF; Mon, 11 Nov 2024 15:17:50 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1731338277; bh=8XlzRzF1gBkUhM/gWdpfw1FaK3At+clEa03vKUZgw0k=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=GlYTYeqyM0uFGmV/dXm/dw0DDiMVK2IwFZV9Eox3wEHL7B0QUnK2kFccpmTk1rsKs QU09N4Z+GCs2NchSAki050uqReHnk0K/RxwhVrwH4l9gIOwFPJ9dvldLznqOwJRMFB +5pnrtPJz05/aOK/Mc19P6BWMYpQUoaxs/rbNIoSlcnZ7GE3n6Je0L5IsycRj3Rwoc F5nI7p+PUYQWospP00PIbtPKWcNsV0OTqHfxZvbglOT2+ItKvd/smTtK9M/llcadeW mWfmNlFez9lgBmx5RO/JaWyQbkxx4UdrO6tdBp46YrdYa1ydTwiT7s0O60Yhf5n3Tj LfZtpDRAMn/fQ== From: Arnaldo Carvalho de Melo To: Namhyung Kim Cc: Ingo Molnar , Thomas Gleixner , Jiri Olsa , Ian Rogers , Adrian Hunter , Kan Liang , Clark Williams , linux-kernel@vger.kernel.org, linux-perf-users@vger.kernel.org, Arnaldo Carvalho de Melo , Athira Rajeev , "Steinar H. Gunderson" Subject: [PATCH 1/3] perf disasm: Introduce symbol__disassemble_objdump() Date: Mon, 11 Nov 2024 12:17:32 -0300 Message-ID: <20241111151734.1018476-2-acme@kernel.org> X-Mailer: git-send-email 2.47.0 In-Reply-To: <20241111151734.1018476-1-acme@kernel.org> References: <20241111151734.1018476-1-acme@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Arnaldo Carvalho de Melo With the first disassemble method in perf, the parsing of objdump output, just like we have for llvm and capstone. This paves the way to allow the user to specify what disassemblers are preferred and to also to at some point allow building without the objdump method. Cc: Adrian Hunter Cc: Athira Rajeev Cc: Ian Rogers Cc: Jiri Olsa Cc: Kan Liang Cc: Namhyung Kim Cc: Steinar H. Gunderson Signed-off-by: Arnaldo Carvalho de Melo Acked-by: Ian Rogers --- tools/perf/util/disasm.c | 168 ++++++++++++++++++++------------------- 1 file changed, 88 insertions(+), 80 deletions(-) diff --git a/tools/perf/util/disasm.c b/tools/perf/util/disasm.c index a525b80b934fdb5f..36cf61602c17fe69 100644 --- a/tools/perf/util/disasm.c +++ b/tools/perf/util/disasm.c @@ -2045,17 +2045,14 @@ static char *expand_tabs(char *line, char **storage= , size_t *storage_len) return new_line; } =20 -int symbol__disassemble(struct symbol *sym, struct annotate_args *args) +static int symbol__disassemble_objdump(const char *filename, struct symbol= *sym, + struct annotate_args *args) { struct annotation_options *opts =3D &annotate_opts; struct map *map =3D args->ms.map; struct dso *dso =3D map__dso(map); char *command; FILE *file; - char symfs_filename[PATH_MAX]; - struct kcore_extract kce; - bool delete_extract =3D false; - bool decomp =3D false; int lineno =3D 0; char *fileloc =3D NULL; int nline; @@ -2070,77 +2067,7 @@ int symbol__disassemble(struct symbol *sym, struct a= nnotate_args *args) NULL, }; struct child_process objdump_process; - int err =3D dso__disassemble_filename(dso, symfs_filename, sizeof(symfs_f= ilename)); - - if (err) - return err; - - pr_debug("%s: filename=3D%s, sym=3D%s, start=3D%#" PRIx64 ", end=3D%#" PR= Ix64 "\n", __func__, - symfs_filename, sym->name, map__unmap_ip(map, sym->start), - map__unmap_ip(map, sym->end)); - - pr_debug("annotating [%p] %30s : [%p] %30s\n", - dso, dso__long_name(dso), sym, sym->name); - - if (dso__binary_type(dso) =3D=3D DSO_BINARY_TYPE__BPF_PROG_INFO) { - return symbol__disassemble_bpf(sym, args); - } else if (dso__binary_type(dso) =3D=3D DSO_BINARY_TYPE__BPF_IMAGE) { - return symbol__disassemble_bpf_image(sym, args); - } else if (dso__binary_type(dso) =3D=3D DSO_BINARY_TYPE__NOT_FOUND) { - return -1; - } else if (dso__is_kcore(dso)) { - kce.kcore_filename =3D symfs_filename; - kce.addr =3D map__rip_2objdump(map, sym->start); - kce.offs =3D sym->start; - kce.len =3D sym->end - sym->start; - if (!kcore_extract__create(&kce)) { - delete_extract =3D true; - strlcpy(symfs_filename, kce.extract_filename, - sizeof(symfs_filename)); - } - } else if (dso__needs_decompress(dso)) { - char tmp[KMOD_DECOMP_LEN]; - - if (dso__decompress_kmodule_path(dso, symfs_filename, - tmp, sizeof(tmp)) < 0) - return -1; - - decomp =3D true; - strcpy(symfs_filename, tmp); - } - - /* - * For powerpc data type profiling, use the dso__data_read_offset - * to read raw instruction directly and interpret the binary code - * to understand instructions and register fields. For sort keys as - * type and typeoff, disassemble to mnemonic notation is - * not required in case of powerpc. - */ - if (arch__is(args->arch, "powerpc")) { - extern const char *sort_order; - - if (sort_order && !strstr(sort_order, "sym")) { - err =3D symbol__disassemble_raw(symfs_filename, sym, args); - if (err =3D=3D 0) - goto out_remove_tmp; -#ifdef HAVE_LIBCAPSTONE_SUPPORT - err =3D symbol__disassemble_capstone_powerpc(symfs_filename, sym, args); - if (err =3D=3D 0) - goto out_remove_tmp; -#endif - } - } - -#ifdef HAVE_LIBLLVM_SUPPORT - err =3D symbol__disassemble_llvm(symfs_filename, sym, args); - if (err =3D=3D 0) - goto out_remove_tmp; -#endif -#ifdef HAVE_LIBCAPSTONE_SUPPORT - err =3D symbol__disassemble_capstone(symfs_filename, sym, args); - if (err =3D=3D 0) - goto out_remove_tmp; -#endif + int err; =20 err =3D asprintf(&command, "%s %s%s --start-address=3D0x%016" PRIx64 @@ -2163,13 +2090,13 @@ int symbol__disassemble(struct symbol *sym, struct = annotate_args *args) =20 if (err < 0) { pr_err("Failure allocating memory for the command to run\n"); - goto out_remove_tmp; + return err; } =20 pr_debug("Executing: %s\n", command); =20 objdump_argv[2] =3D command; - objdump_argv[4] =3D symfs_filename; + objdump_argv[4] =3D filename; =20 /* Create a pipe to read from for stdout */ memset(&objdump_process, 0, sizeof(objdump_process)); @@ -2207,8 +2134,8 @@ int symbol__disassemble(struct symbol *sym, struct an= notate_args *args) break; =20 /* Skip lines containing "filename:" */ - match =3D strstr(line, symfs_filename); - if (match && match[strlen(symfs_filename)] =3D=3D ':') + match =3D strstr(line, filename); + if (match && match[strlen(filename)] =3D=3D ':') continue; =20 expanded_line =3D strim(line); @@ -2253,6 +2180,87 @@ int symbol__disassemble(struct symbol *sym, struct a= nnotate_args *args) =20 out_free_command: free(command); + return err; +} + +int symbol__disassemble(struct symbol *sym, struct annotate_args *args) +{ + struct map *map =3D args->ms.map; + struct dso *dso =3D map__dso(map); + char symfs_filename[PATH_MAX]; + bool delete_extract =3D false; + struct kcore_extract kce; + bool decomp =3D false; + int err =3D dso__disassemble_filename(dso, symfs_filename, sizeof(symfs_f= ilename)); + + if (err) + return err; + + pr_debug("%s: filename=3D%s, sym=3D%s, start=3D%#" PRIx64 ", end=3D%#" PR= Ix64 "\n", __func__, + symfs_filename, sym->name, map__unmap_ip(map, sym->start), + map__unmap_ip(map, sym->end)); + + pr_debug("annotating [%p] %30s : [%p] %30s\n", dso, dso__long_name(dso), = sym, sym->name); + + if (dso__binary_type(dso) =3D=3D DSO_BINARY_TYPE__BPF_PROG_INFO) { + return symbol__disassemble_bpf(sym, args); + } else if (dso__binary_type(dso) =3D=3D DSO_BINARY_TYPE__BPF_IMAGE) { + return symbol__disassemble_bpf_image(sym, args); + } else if (dso__binary_type(dso) =3D=3D DSO_BINARY_TYPE__NOT_FOUND) { + return -1; + } else if (dso__is_kcore(dso)) { + kce.addr =3D map__rip_2objdump(map, sym->start); + kce.kcore_filename =3D symfs_filename; + kce.len =3D sym->end - sym->start; + kce.offs =3D sym->start; + + if (!kcore_extract__create(&kce)) { + delete_extract =3D true; + strlcpy(symfs_filename, kce.extract_filename, sizeof(symfs_filename)); + } + } else if (dso__needs_decompress(dso)) { + char tmp[KMOD_DECOMP_LEN]; + + if (dso__decompress_kmodule_path(dso, symfs_filename, tmp, sizeof(tmp)) = < 0) + return -1; + + decomp =3D true; + strcpy(symfs_filename, tmp); + } + + /* + * For powerpc data type profiling, use the dso__data_read_offset to + * read raw instruction directly and interpret the binary code to + * understand instructions and register fields. For sort keys as type + * and typeoff, disassemble to mnemonic notation is not required in + * case of powerpc. + */ + if (arch__is(args->arch, "powerpc")) { + extern const char *sort_order; + + if (sort_order && !strstr(sort_order, "sym")) { + err =3D symbol__disassemble_raw(symfs_filename, sym, args); + if (err =3D=3D 0) + goto out_remove_tmp; +#ifdef HAVE_LIBCAPSTONE_SUPPORT + err =3D symbol__disassemble_capstone_powerpc(symfs_filename, sym, args); + if (err =3D=3D 0) + goto out_remove_tmp; +#endif + } + } + +#ifdef HAVE_LIBLLVM_SUPPORT + err =3D symbol__disassemble_llvm(symfs_filename, sym, args); + if (err =3D=3D 0) + goto out_remove_tmp; +#endif +#ifdef HAVE_LIBCAPSTONE_SUPPORT + err =3D symbol__disassemble_capstone(symfs_filename, sym, args); + if (err =3D=3D 0) + goto out_remove_tmp; +#endif + err =3D symbol__disassemble_objdump(symfs_filename, sym, args); =20 out_remove_tmp: if (decomp) --=20 2.47.0 From nobody Sat Nov 23 20:19:48 2024 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id CF8101A254E; Mon, 11 Nov 2024 15:18:03 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731338283; cv=none; b=lCStw3ttWN8OWwuZPKlVTuobXQlWpSlPDeKGtfBjS7a0trgUMgHtSA0I35R58kIBVUpOtTc5t0Ta1V6gfG3XuLrAs1x52qVKPMoTrD1KwO0OOYQkQDCqdZPfZfiLlgBB16EaGZ4FIem8+LD1Q3lCnKGVddfG0RdGCoGjjJg7Fso= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731338283; c=relaxed/simple; bh=j/Cv6gy4XfZef1hgbCcWDH10UFHhy5vRK/6BCYY/VdM=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=ls1SMszliniRDN8QjlPPwDNaztskt9W5OGlexxAdKW6hhO5WKmMK/rkCPOLJQplzpQkPgRIpzromKcDxJfiV9PRQvKgABsz3PIhNYMJYuugwkDZvpu+nuB3KvZ2H9+nBSygyv1yeThZ4ID7aspg6NMtkjdUIbVuOErpziwLsmX4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=P9ESR5xv; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="P9ESR5xv" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 0C67CC4CED7; Mon, 11 Nov 2024 15:17:57 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1731338283; bh=j/Cv6gy4XfZef1hgbCcWDH10UFHhy5vRK/6BCYY/VdM=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=P9ESR5xvS3j05PXYeDvnfMJca8TckRfABFEQVplaxrOUaZtm54ZBbWr07lHolBubM nSZk/DpLO8+fivMRJ3xv7I3ITz64aiOtCIMzcYZsE0EE+IzkSJxtK633Sp88JmXG/D GTkHNiEBfNYvp0uGxGnP/SPsyf0xlJKouUl/X2ZVqXkabhVEUb+fbWAT0npTdmQmra sg6ja1hANBC1xAfghUdCpTUANx52mCnHXVk7NdhyaE49SVDqHrA7+AWieegZkhdPZl bKHIuSFEkeAa6cmtINuaSVUbJUc5h/7duW5UlA/b4wvcHgATTtb3fGMBD95hdjrw1K u+Mj/UAvHttnQ== From: Arnaldo Carvalho de Melo To: Namhyung Kim Cc: Ingo Molnar , Thomas Gleixner , Jiri Olsa , Ian Rogers , Adrian Hunter , Kan Liang , Clark Williams , linux-kernel@vger.kernel.org, linux-perf-users@vger.kernel.org, Arnaldo Carvalho de Melo , Athira Rajeev , "Steinar H. Gunderson" Subject: [PATCH 2/3] perf disasm: Define stubs for the LLVM and capstone disassemblers Date: Mon, 11 Nov 2024 12:17:33 -0300 Message-ID: <20241111151734.1018476-3-acme@kernel.org> X-Mailer: git-send-email 2.47.0 In-Reply-To: <20241111151734.1018476-1-acme@kernel.org> References: <20241111151734.1018476-1-acme@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Arnaldo Carvalho de Melo This reduces the number of ifdefs in the main symbol__disassemble() method and paves the way for allowing the user to configure the disassemblers of preference. Cc: Adrian Hunter Cc: Athira Rajeev Cc: Ian Rogers Cc: Jiri Olsa Cc: Kan Liang Cc: Namhyung Kim Cc: Steinar H. Gunderson Signed-off-by: Arnaldo Carvalho de Melo Acked-by: Ian Rogers Tested-by: Aditya Bodkhe > --- tools/perf/util/disasm.c | 40 ++++++++++++++++++++++++++++++++-------- 1 file changed, 32 insertions(+), 8 deletions(-) diff --git a/tools/perf/util/disasm.c b/tools/perf/util/disasm.c index 36cf61602c17fe69..83df1da20a7b16cd 100644 --- a/tools/perf/util/disasm.c +++ b/tools/perf/util/disasm.c @@ -1422,6 +1422,13 @@ read_symbol(const char *filename, struct map *map, s= truct symbol *sym, free(buf); return NULL; } +#else // defined(HAVE_LIBCAPSTONE_SUPPORT) || defined(HAVE_LIBLLVM_SUPPORT) +static void symbol__disassembler_missing(const char *disassembler, const c= har *filename, + struct symbol *sym) +{ + pr_debug("The %s disassembler isn't linked in for %s in %s\n", + disassembler, sym->name, filename); +} #endif =20 #ifdef HAVE_LIBCAPSTONE_SUPPORT @@ -1715,7 +1722,20 @@ static int symbol__disassemble_capstone(char *filena= me, struct symbol *sym, count =3D -1; goto out; } -#endif +#else // HAVE_LIBCAPSTONE_SUPPORT +static int symbol__disassemble_capstone(char *filename, struct symbol *sym, + struct annotate_args *args) + symbol__disassembler_missing("capstone", filename, sym); + return -1; +} + +static int symbol__disassemble_capstone_powerpc(char *filename, struct sym= bol *sym, + struct annotate_args *args __maybe_unused) +{ + symbol__disassembler_missing("capstone powerpc", filename, sym); + return -1; +} +#endif // HAVE_LIBCAPSTONE_SUPPORT =20 static int symbol__disassemble_raw(char *filename, struct symbol *sym, struct annotate_args *args) @@ -1983,7 +2003,14 @@ static int symbol__disassemble_llvm(char *filename, = struct symbol *sym, free(line_storage); return ret; } -#endif +#else // HAVE_LIBLLVM_SUPPORT +static int symbol__disassemble_llvm(char *filename, struct symbol *sym, + struct annotate_args *args __maybe_unused) +{ + symbol__disassembler_missing("LLVM", filename, sym); + return -1; +} +#endif // HAVE_LIBLLVM_SUPPORT =20 /* * Possibly create a new version of line with tabs expanded. Returns the @@ -2242,24 +2269,21 @@ int symbol__disassemble(struct symbol *sym, struct = annotate_args *args) err =3D symbol__disassemble_raw(symfs_filename, sym, args); if (err =3D=3D 0) goto out_remove_tmp; -#ifdef HAVE_LIBCAPSTONE_SUPPORT + err =3D symbol__disassemble_capstone_powerpc(symfs_filename, sym, args); if (err =3D=3D 0) goto out_remove_tmp; -#endif } } =20 -#ifdef HAVE_LIBLLVM_SUPPORT err =3D symbol__disassemble_llvm(symfs_filename, sym, args); if (err =3D=3D 0) goto out_remove_tmp; -#endif -#ifdef HAVE_LIBCAPSTONE_SUPPORT + err =3D symbol__disassemble_capstone(symfs_filename, sym, args); if (err =3D=3D 0) goto out_remove_tmp; -#endif + err =3D symbol__disassemble_objdump(symfs_filename, sym, args); =20 out_remove_tmp: --=20 2.47.0 From nobody Sat Nov 23 20:19:48 2024 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id F036F1494BB; Mon, 11 Nov 2024 15:18:09 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731338290; cv=none; b=sPrmSyJ0a+YIq47R6YbClQ7zRjFmWFxGi+SVCiJ8+Pgu/AbVADCQ1dM0MCMJa4dUYSff5SukOYVK+Z7pftfNaYwTUBZuqFxRKdnzfrEUta4JgshSqLIujWP//UfUL7nlDHo6icqi6uBpaErgn3L3bPquGU+4yrL/WoOxrXJMI4k= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1731338290; c=relaxed/simple; bh=MHF5Vv8F3/QBbWu7HpNpjeJfgl9O8zj//WncFSQ9bhc=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=LG/gu8GGh3Z3Psgn23Utp/DI1kona9lCugxsJVIsfZN3hmNXzMoOX/ruEgfgOvcMmyEkLLLDhU5PA1q2cH4vXa2fIF1xZ+QH52aURySPeAAFoVHj52aUfSkBQ0luZ0IlwW3kNvALykLNr/wd1W1pK5fJWmAJPRM+efJ98GEc6Uc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=a0+JvYQQ; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="a0+JvYQQ" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 0AFA3C4CECF; Mon, 11 Nov 2024 15:18:03 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1731338289; bh=MHF5Vv8F3/QBbWu7HpNpjeJfgl9O8zj//WncFSQ9bhc=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=a0+JvYQQTUQC1hz4Asnaid3GC0gr8Ve9Dgqt/t9BBAT4l9uGyDtoSkp9ZfTUwAh8L i3rIHVXXwrpw3HbEq5eTlnYJm1vRsKPn55OXXcpnbbTJNA4bAZnN6K0qAfwbFm83f2 8n5gNgITM1yMMwhRS3SWDXMgaUaBagI5t5vq+7NbDG+BGKTzXOvmB8wj8s/KRw2kEk IdoT0a0GSYPSRL79zOuSzKolCUeUlqNh94wWwRfvMZzKilKduNRUb/ZJT0sNLZTBgZ jHB1B3NEIJVdIyntfp0VGU/K69RMBEG7gz7FvA7qYx3i92dILaFbkyPnAvymNP2CSo Aa/ALSfvIEMRg== From: Arnaldo Carvalho de Melo To: Namhyung Kim Cc: Ingo Molnar , Thomas Gleixner , Jiri Olsa , Ian Rogers , Adrian Hunter , Kan Liang , Clark Williams , linux-kernel@vger.kernel.org, linux-perf-users@vger.kernel.org, Arnaldo Carvalho de Melo , Athira Rajeev , "Steinar H. Gunderson" Subject: [PATCH 3/3] perf disasm: Allow configuring what disassemblers to use Date: Mon, 11 Nov 2024 12:17:34 -0300 Message-ID: <20241111151734.1018476-4-acme@kernel.org> X-Mailer: git-send-email 2.47.0 In-Reply-To: <20241111151734.1018476-1-acme@kernel.org> References: <20241111151734.1018476-1-acme@kernel.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Arnaldo Carvalho de Melo The perf tools annotation code used for a long time parsing the output of binutils's objdump (or its reimplementations, like llvm's) to then parse and augment it with samples, allow navigation, etc. More recently disassemblers from the capstone and llvm (libraries, not parsing the output of tools using those libraries to mimic binutils's objdump output) were introduced. So when all those methods are available, there is a static preference for a series of attempts of disassembling a binary, with the 'llvm, capstone, objdump' sequence being hard coded. This patch allows users to change that sequence, specifying via a 'perf config' 'annotate.disassemblers' entry which and in what order disassemblers should be attempted. As alluded to in the comments in the source code of this series, this flexibility is useful for users and developers alike, elliminating the requirement to rebuild the tool with some specific set of libraries to see how the output of disassembling would be for one of these methods. root@x1:~# rm -f ~/.perfconfig root@x1:~# perf annotate -v --stdio2 update_load_avg symbol__disassemble: filename=3D/usr/lib/debug/lib/modules/6.11.4-201.fc40.x86_64/vmlinux, sym=3Dupdate_load_avg, start=3D0xffffffffb6148fe0, en> annotating [0x6ff7170] /usr/lib/debug/lib/modules/6.11.4-201.fc40.x86_64/vmlinux : [0x7407ca0] update_load_avg Disassembled with llvm annotate.disassemblers=3Dllvm,capstone,objdump Samples: 66 of event 'cpu_atom/cycles/P', 10000 Hz, Event count (approx.): 5185444, [percent: local period] update_load_avg() /usr/lib/debug/lib/modules/6.11.4-201.fc40.x86_64/vmlinux Percent 0xffffffff81148fe0 : 1.61 pushq %r15 pushq %r14 1.00 pushq %r13 movl %edx,%r13d 1.90 pushq %r12 pushq %rbp movq %rsi,%rbp pushq %rbx movq %rdi,%rbx subq $0x18,%rsp 15.14 movl 0x1a4(%rdi),%eax root@x1:~# perf config annotate.disassemblers=3Dcapstone root@x1:~# cat ~/.perfconfig # this file is auto-generated. [annotate] disassemblers =3D capstone root@x1:~# root@x1:~# perf annotate -v --stdio2 update_load_avg Disassembled with capstone annotate.disassemblers=3Dcapstone Samples: 66 of event 'cpu_atom/cycles/P', 10000 Hz, Event count (approx.): 5185444, [percent: local period] update_load_avg() /usr/lib/debug/lib/modules/6.11.4-201.fc40.x86_64/vmlinux Percent 0xffffffff81148fe0 : 1.61 pushq %r15 pushq %r14 1.00 pushq %r13 movl %edx,%r13d 1.90 pushq %r12 pushq %rbp movq %rsi,%rbp pushq %rbx movq %rdi,%rbx subq $0x18,%rsp 15.14 movl 0x1a4(%rdi),%eax root@x1:~# perf config annotate.disassemblers=3Dobjdump,capstone root@x1:~# perf config annotate.disassemblers annotate.disassemblers=3Dobjdump,capstone root@x1:~# cat ~/.perfconfig # this file is auto-generated. [annotate] disassemblers =3D objdump,capstone root@x1:~# perf annotate -v --stdio2 update_load_avg Executing: objdump --start-address=3D0xffffffff81148fe0 \ --stop-address=3D0xffffffff811497aa \ -d --no-show-raw-insn -S -C "$1" Disassembled with objdump annotate.disassemblers=3Dobjdump,capstone Samples: 66 of event 'cpu_atom/cycles/P', 10000 Hz, Event count (approx.): 5185444, [percent: local period] update_load_avg() /usr/lib/debug/lib/modules/6.11.4-201.fc40.x86_64/vmlinux Percent Disassembly of section .text: ffffffff81148fe0 : #define DO_ATTACH 0x4 ffffffff81148fe0 : #define DO_ATTACH 0x4 #define DO_DETACH 0x8 /* Update task and its cfs_rq load average */ static inline void update_load_avg(struct cfs_rq *cfs_rq, struct sched_entity *se, int flags) { 1.61 push %r15 push %r14 1.00 push %r13 mov %edx,%r13d 1.90 push %r12 push %rbp mov %rsi,%rbp push %rbx mov %rdi,%rbx sub $0x18,%rsp } /* rq->task_clock normalized against any time this cfs_rq has spent throttled */ static inline u64 cfs_rq_clock_pelt(struct cfs_rq *cfs_rq) { if (unlikely(cfs_rq->throttle_count)) 15.14 mov 0x1a4(%rdi),%eax root@x1:~# After adding a way to select the disassembler from the command line a 'perf test' comparing the output of the various diassemblers should be introduced, to test these codebases. Cc: Adrian Hunter Cc: Athira Rajeev Cc: Ian Rogers Cc: Jiri Olsa Cc: Kan Liang Cc: Namhyung Kim Cc: Steinar H. Gunderson Signed-off-by: Arnaldo Carvalho de Melo Acked-by: Ian Rogers --- tools/perf/Documentation/perf-config.txt | 13 ++++ tools/perf/util/annotate.c | 6 ++ tools/perf/util/annotate.h | 6 ++ tools/perf/util/disasm.c | 77 ++++++++++++++++++++++-- 4 files changed, 96 insertions(+), 6 deletions(-) diff --git a/tools/perf/Documentation/perf-config.txt b/tools/perf/Document= ation/perf-config.txt index 379f9d7a8ab11a02..1f668d4724e3749a 100644 --- a/tools/perf/Documentation/perf-config.txt +++ b/tools/perf/Documentation/perf-config.txt @@ -247,6 +247,19 @@ annotate.*:: These are in control of addresses, jump function, source code in lines of assembly code from a specific program. =20 + annotate.disassemblers:: + Choose the disassembler to use: "objdump", "llvm", "capstone", + if not specified it will first try, if available, the "llvm" one, + then, if it fails, "capstone", and finally the original "objdump" + based one. + + Choosing a different one is useful when handling some feature that + is known to be best support at some point by one of the options, + to compare the output when in doubt about some bug, etc. + + This can be a list, in order of preference, the first one that works + finishes the process. + annotate.addr2line:: addr2line binary to use for file names and line numbers. =20 diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index b1d98da79be8b2b0..32e15c9f53f3c0a3 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -2116,6 +2116,12 @@ static int annotation__config(const char *var, const= char *value, void *data) opt->offset_level =3D ANNOTATION__MAX_OFFSET_LEVEL; else if (opt->offset_level < ANNOTATION__MIN_OFFSET_LEVEL) opt->offset_level =3D ANNOTATION__MIN_OFFSET_LEVEL; + } else if (!strcmp(var, "annotate.disassemblers")) { + opt->disassemblers_str =3D strdup(value); + if (!opt->disassemblers_str) { + pr_err("Not enough memory for annotate.disassemblers\n"); + return -1; + } } else if (!strcmp(var, "annotate.hide_src_code")) { opt->hide_src_code =3D perf_config_bool("hide_src_code", value); } else if (!strcmp(var, "annotate.jump_arrows")) { diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index 8b9e05a1932f2f9e..194a05cbc506e4da 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -34,6 +34,9 @@ struct annotated_data_type; #define ANNOTATION__BR_CNTR_WIDTH 30 #define ANNOTATION_DUMMY_LEN 256 =20 +// llvm, capstone, objdump +#define MAX_DISASSEMBLERS 3 + struct annotation_options { bool hide_src_code, use_offset, @@ -49,11 +52,14 @@ struct annotation_options { annotate_src, full_addr; u8 offset_level; + u8 nr_disassemblers; int min_pcnt; int max_lines; int context; char *objdump_path; char *disassembler_style; + const char *disassemblers_str; + const char *disassemblers[MAX_DISASSEMBLERS]; const char *prefix; const char *prefix_strip; unsigned int percent_type; diff --git a/tools/perf/util/disasm.c b/tools/perf/util/disasm.c index 83df1da20a7b16cd..df6c172c9c7f86d9 100644 --- a/tools/perf/util/disasm.c +++ b/tools/perf/util/disasm.c @@ -2210,13 +2210,65 @@ static int symbol__disassemble_objdump(const char *= filename, struct symbol *sym, return err; } =20 +static int annotation_options__init_disassemblers(struct annotation_option= s *options) +{ + char *disassembler; + + if (options->disassemblers_str =3D=3D NULL) { + const char *default_disassemblers_str =3D +#ifdef HAVE_LIBLLVM_SUPPORT + "llvm," +#endif +#ifdef HAVE_LIBCAPSTONE_SUPPORT + "capstone," +#endif + "objdump"; + + options->disassemblers_str =3D strdup(default_disassemblers_str); + if (!options->disassemblers_str) + goto out_enomem; + } + + disassembler =3D strdup(options->disassemblers_str); + if (disassembler =3D=3D NULL) + goto out_enomem; + + while (1) { + char *comma =3D strchr(disassembler, ','); + + if (comma !=3D NULL) + *comma =3D '\0'; + + options->disassemblers[options->nr_disassemblers++] =3D strim(disassembl= er); + + if (comma =3D=3D NULL) + break; + + disassembler =3D comma + 1; + + if (options->nr_disassemblers >=3D MAX_DISASSEMBLERS) { + pr_debug("annotate.disassemblers can have at most %d entries, ignoring = \"%s\"\n", + MAX_DISASSEMBLERS, disassembler); + break; + } + } + + return 0; + +out_enomem: + pr_err("Not enough memory for annotate.disassemblers\n"); + return -1; +} + int symbol__disassemble(struct symbol *sym, struct annotate_args *args) { + struct annotation_options *options =3D args->options; struct map *map =3D args->ms.map; struct dso *dso =3D map__dso(map); char symfs_filename[PATH_MAX]; bool delete_extract =3D false; struct kcore_extract kce; + const char *disassembler; bool decomp =3D false; int err =3D dso__disassemble_filename(dso, symfs_filename, sizeof(symfs_f= ilename)); =20 @@ -2276,16 +2328,29 @@ int symbol__disassemble(struct symbol *sym, struct = annotate_args *args) } } =20 - err =3D symbol__disassemble_llvm(symfs_filename, sym, args); - if (err =3D=3D 0) + err =3D annotation_options__init_disassemblers(options); + if (err) goto out_remove_tmp; =20 - err =3D symbol__disassemble_capstone(symfs_filename, sym, args); - if (err =3D=3D 0) - goto out_remove_tmp; + err =3D -1; =20 - err =3D symbol__disassemble_objdump(symfs_filename, sym, args); + for (int i =3D 0; i < options->nr_disassemblers && err !=3D 0; ++i) { + disassembler =3D options->disassemblers[i]; =20 + if (!strcmp(disassembler, "llvm")) + err =3D symbol__disassemble_llvm(symfs_filename, sym, args); + else if (!strcmp(disassembler, "capstone")) + err =3D symbol__disassemble_capstone(symfs_filename, sym, args); + else if (!strcmp(disassembler, "objdump")) + err =3D symbol__disassemble_objdump(symfs_filename, sym, args); + else + pr_debug("Unknown disassembler %s, skipping...\n", disassembler); + } + + if (err =3D=3D 0) { + pr_debug("Disassembled with %s\nannotate.disassemblers=3D%s\n", + disassembler, options->disassemblers_str); + } out_remove_tmp: if (decomp) unlink(symfs_filename); --=20 2.47.0