[PATCH v2] tools: perf: tests: Fix code reading for riscv
Ian Rogers
irogers at google.com
Tue Dec 17 16:18:32 PST 2024
On Tue, Dec 17, 2024 at 3:52 PM Charlie Jenkins <charlie at rivosinc.com> wrote:
>
> After binutils commit e43d876 which was first included in binutils 2.41,
> riscv no longer supports dumping in the middle of instructions. Increase
> the objdump window by 2-bytes to ensure that any instruction that sits
> on the boundary of the specified stop-address is not cut in half.
>
> Signed-off-by: Charlie Jenkins <charlie at rivosinc.com>
Reviewed-by: Ian Rogers <irogers at google.com>
> ---
> A binutils patch has been sent as well to fix this in objdump [1].
>
> Link:
> https://sourceware.org/pipermail/binutils/2024-December/138139.html [1]
> ---
> Changes in v2:
> - Do objdump version detection at runtime (Ian)
> - Link to v1: https://lore.kernel.org/r/20241216-perf_fix_riscv_obj_reading-v1-0-b75962660a9b@rivosinc.com
> ---
> tools/perf/tests/code-reading.c | 84 ++++++++++++++++++++++++++++++++++++++++-
> 1 file changed, 83 insertions(+), 1 deletion(-)
>
> diff --git a/tools/perf/tests/code-reading.c b/tools/perf/tests/code-reading.c
> index 27c82cfb7e7de42284bf5af9cf7594a3a963052e..7e24d10a543ac18ac2be70b829d088874e0edfd5 100644
> --- a/tools/perf/tests/code-reading.c
> +++ b/tools/perf/tests/code-reading.c
> @@ -1,5 +1,6 @@
> // SPDX-License-Identifier: GPL-2.0
> #include <errno.h>
> +#include <linux/kconfig.h>
> #include <linux/kernel.h>
> #include <linux/types.h>
> #include <inttypes.h>
> @@ -176,6 +177,66 @@ static int read_objdump_output(FILE *f, void *buf, size_t *len, u64 start_addr)
> return err;
> }
>
> +/*
> + * Only gets GNU objdump version. Returns 0 for llvm-objdump.
> + */
> +static int objdump_version(void)
> +{
> + size_t line_len;
> + char cmd[PATH_MAX * 2];
> + char *line = NULL;
> + const char *fmt;
> + FILE *f;
> + int ret;
> +
> + int version_tmp, version_num = 0;
> + char *version = 0, *token;
> +
> + fmt = "%s --version";
> + ret = snprintf(cmd, sizeof(cmd), fmt, test_objdump_path);
> + if (ret <= 0 || (size_t)ret >= sizeof(cmd))
> + return -1;
> + /* Ignore objdump errors */
> + strcat(cmd, " 2>/dev/null");
> + f = popen(cmd, "r");
> + if (!f) {
> + pr_debug("popen failed\n");
> + return -1;
> + }
> + /* Get first line of objdump --version output */
> + ret = getline(&line, &line_len, f);
> + pclose(f);
> + if (ret < 0) {
> + pr_debug("getline failed\n");
> + return -1;
> + }
> +
> + token = strsep(&line, " ");
> + if (token != NULL && !strcmp(token, "GNU")) {
> + // version is last part of first line of objdump --version output.
> + while ((token = strsep(&line, " ")))
> + version = token;
> +
> + // Convert version into a format we can compare with
> + token = strsep(&version, ".");
> + version_num = atoi(token);
> + if (version_num)
> + version_num *= 10000;
> +
> + token = strsep(&version, ".");
> + version_tmp = atoi(token);
> + if (token)
> + version_num += version_tmp * 100;
> +
> + token = strsep(&version, ".");
> + version_tmp = atoi(token);
> + if (token)
> + version_num += version_tmp;
> + }
> +
> + return version_num;
> +}
> +
> static int read_via_objdump(const char *filename, u64 addr, void *buf,
> size_t len)
> {
> @@ -183,9 +244,30 @@ static int read_via_objdump(const char *filename, u64 addr, void *buf,
> const char *fmt;
> FILE *f;
> int ret;
> + u64 stop_address = addr + len;
> +
> + if (IS_ENABLED(__riscv)) {
Not sure if there is a consistency issue here. Elsewhere we're just
using ifdef, such as:
https://git.kernel.org/pub/scm/linux/kernel/git/perf/perf-tools-next.git/tree/tools/perf/util/include/dwarf-regs.h?h=perf-tools-next#n69
Thanks,
Ian
> + int version = objdump_version();
> +
> + /* Default to this workaround if version parsing fails */
> + if (version < 0 || version > 24100) {
> + /*
> + * Starting at riscv objdump version 2.41, dumping in
> + * the middle of an instruction is not supported. riscv
> + * instructions are aligned along 2-byte intervals and
> + * can be either 2-bytes or 4-bytes. This makes it
> + * possible that the stop-address lands in the middle of
> + * a 4-byte instruction. Increase the stop_address by
> + * two to ensure an instruction is not cut in half, but
> + * leave the len as-is so only the expected number of
> + * bytes are collected.
> + */
> + stop_address += 2;
> + }
> + }
>
> fmt = "%s -z -d --start-address=0x%"PRIx64" --stop-address=0x%"PRIx64" %s";
> - ret = snprintf(cmd, sizeof(cmd), fmt, test_objdump_path, addr, addr + len,
> + ret = snprintf(cmd, sizeof(cmd), fmt, test_objdump_path, addr, stop_address,
> filename);
> if (ret <= 0 || (size_t)ret >= sizeof(cmd))
> return -1;
>
> ---
> base-commit: fac04efc5c793dccbd07e2d59af9f90b7fc0dca4
> change-id: 20241213-perf_fix_riscv_obj_reading-cabf02be3c85
> --
> - Charlie
>
More information about the linux-riscv
mailing list