diff --git a/contrib/plugins/bap-tracing/bap-frames b/contrib/plugins/bap-tracing/bap-frames index de612ffce48cb..ff649e49c84fd 160000 --- a/contrib/plugins/bap-tracing/bap-frames +++ b/contrib/plugins/bap-tracing/bap-frames @@ -1 +1 @@ -Subproject commit de612ffce48cb93f7a462f8b0ab28f2884adec0b +Subproject commit ff649e49c84fd6017e9bf5847cd00304652033f5 diff --git a/contrib/plugins/bap-tracing/meson.build b/contrib/plugins/bap-tracing/meson.build index 743282e703b3f..4c431d281215b 100644 --- a/contrib/plugins/bap-tracing/meson.build +++ b/contrib/plugins/bap-tracing/meson.build @@ -46,6 +46,7 @@ bap_tracing_src = files( 'frame_buffer.c', 'tracing.c', 'trace_meta.c', + 'trace_riscv.c', ) if host_os == 'windows' diff --git a/contrib/plugins/bap-tracing/trace_meta.c b/contrib/plugins/bap-tracing/trace_meta.c index 4f15265435bee..53554fe1463c0 100644 --- a/contrib/plugins/bap-tracing/trace_meta.c +++ b/contrib/plugins/bap-tracing/trace_meta.c @@ -9,6 +9,7 @@ #include "frame.piqi.pb-c-patched.h" #include "trace_consts.h" #include "trace_meta.h" +#include "trace_riscv.h" #define MD5LEN 16 @@ -169,6 +170,9 @@ void write_meta(WLOCKED FILE *file, char **plugin_argv, size_t plugin_argc) { char *host = g_strdup(g_get_host_name()); meta.host = host; + char *isa = riscv_isa_from_elf(bin_path ? bin_path : arg_bin_path); + meta.isa = isa; + size_t msg_size = meta_frame__get_packed_size(&meta); uint8_t *packed_buffer = g_malloc0(msg_size); uint64_t packed_size = meta_frame__pack(&meta, packed_buffer); @@ -189,6 +193,7 @@ void write_meta(WLOCKED FILE *file, char **plugin_argv, size_t plugin_argc) { g_free(user); g_free(host); + g_free(isa); g_free(arg_bin_path); } diff --git a/contrib/plugins/bap-tracing/trace_riscv.c b/contrib/plugins/bap-tracing/trace_riscv.c new file mode 100644 index 0000000000000..5683512538fe7 --- /dev/null +++ b/contrib/plugins/bap-tracing/trace_riscv.c @@ -0,0 +1,204 @@ +// SPDX-FileCopyrightText: 2025 Rot127 +// SPDX-License-Identifier: GPL-2.0-only + +#include "trace_riscv.h" + +#include +#include +#include +#include +#include + +#define TAG_RISCV_ARCH 5 +#define RISCV_ATTR_VENDOR "riscv" + +/* + * A 64-bit value needs at most ceil(64/7) = 10 bytes in ULEB128. + * Any sequence requiring more bytes cannot fit in uint64_t. + */ +#define ULEB128_MAX_BYTES 10 + +/* + * Decode one ULEB128 integer from buf[0..buf_len). + * Sets *out_bytes to the number of bytes consumed, or 0 on failure + * (buffer too short mid-sequence, or value exceeds 64 bits). + */ +static uint64_t uleb128_read(const uint8_t *buf, size_t buf_len, + size_t *out_bytes) { + uint64_t result = 0; + for (size_t i = 0; i < buf_len && i < ULEB128_MAX_BYTES; i++) { + uint8_t b = buf[i]; + uint8_t data = b & 0x7f; + uint32_t shift = 7 * (uint32_t)i; + /* + * At i=9 (shift=63), bit 0 of data maps to bit 63 of result. + * Bits 1-6 of data would map to bits 64-69: overflow. + */ + if (shift == 63 && (data & 0x7e)) { + if (out_bytes) { + *out_bytes = 0; + } + return 0; + } + result |= (uint64_t)data << shift; + if (!(b & 0x80)) { + if (out_bytes) { + *out_bytes = i + 1; + } + return result; + } + } + /* Buffer exhausted mid-sequence, or 10th byte still had continuation. */ + if (out_bytes) { + *out_bytes = 0; + } + return 0; +} + +/* + * Parse the .riscv.attributes section data and return a copy of the + * Tag_RISCV_arch string, or NULL if not found. + * + * Format (GNU/ARM ELF attribute ABI, adopted by RISC-V): + * 'A' (1 byte, format version) + * [vendor sub-section]: + * sub_size (4 bytes LE, includes itself) + * vendor_name (null-terminated) + * [file sub-sub-section, tag = 1]: + * tag (1 byte) + * ssz (4 bytes LE, includes tag byte + itself + content) + * [attribute pairs: ULEB128 tag, then value] + * + * Tag parity convention: odd tags have NTBS values, even have ULEB128 int. + */ +static char *parse_riscv_attrs(const uint8_t *data, size_t size) { + if (size < 1 || data[0] != 'A') { + return NULL; + } + + size_t voff = 1; + while (voff + 5 <= size) { + uint32_t sub_size; + memcpy(&sub_size, data + voff, 4); + if (sub_size < 5 || voff + sub_size > size) { + break; + } + + const char *vendor = (const char *)(data + voff + 4); + size_t vendor_len = strnlen(vendor, sub_size - 4) + 1; + + if (!strcmp(vendor, RISCV_ATTR_VENDOR)) { + size_t soff = voff + 4 + vendor_len; + size_t vend = voff + sub_size; + + while (soff + 5 <= vend) { + uint8_t sub_tag = data[soff]; + uint32_t ssz; + memcpy(&ssz, data + soff + 1, 4); + size_t attr_end = soff + ssz; + + if (sub_tag == 1 /* Tag_File */ && attr_end <= vend) { + size_t p = soff + 5; + while (p < attr_end) { + size_t tlen; + uint64_t tag = uleb128_read(data + p, attr_end - p, + &tlen); + if (!tlen) { + break; + } + p += tlen; + if (p >= attr_end) { + break; + } + if (tag == TAG_RISCV_ARCH) { + return g_strdup((const char *)(data + p)); + } + /* Skip value: odd tags are NTBS, even are ULEB128. */ + if (tag & 1) { + p += strnlen((const char *)(data + p), + attr_end - p) + 1; + } else { + size_t skip; + uleb128_read(data + p, attr_end - p, &skip); + if (!skip) { + break; + } + p += skip; + } + } + } + soff = attr_end; + } + } + voff += sub_size; + } + return NULL; +} + +/* + * Expand to a function read_attrs_section that reads the ELF section + * header table using SHDR_T (Elf32_Shdr or Elf64_Shdr) and shoff of type + * OFF_T (Elf32_Off or Elf64_Off), finds the SHT_RISCV_ATTRIBUTES section, + * and delegates to parse_riscv_attrs. + */ +#define DEFINE_READ_ATTRS_SECTION(BITS, SHDR_T, OFF_T) \ +static char *read_attrs_section##BITS(FILE *f, uint16_t shnum, OFF_T shoff) { \ + SHDR_T *shdrs = g_malloc(shnum * sizeof(SHDR_T)); \ + if (fseeko(f, (off_t)(shoff), SEEK_SET) < 0 || \ + fread(shdrs, sizeof(SHDR_T), shnum, f) != shnum) { \ + g_free(shdrs); \ + return NULL; \ + } \ + char *isa = NULL; \ + for (int i = 0; i < shnum && !isa; i++) { \ + if (shdrs[i].sh_type != SHT_RISCV_ATTRIBUTES) { \ + continue; \ + } \ + uint8_t *buf = g_malloc(shdrs[i].sh_size); \ + if (fseeko(f, (off_t)(shdrs[i].sh_offset), SEEK_SET) >= 0 && \ + fread(buf, 1, shdrs[i].sh_size, f) == shdrs[i].sh_size) { \ + isa = parse_riscv_attrs(buf, shdrs[i].sh_size); \ + } \ + g_free(buf); \ + } \ + g_free(shdrs); \ + return isa; \ +} + +DEFINE_READ_ATTRS_SECTION(32, Elf32_Shdr, Elf32_Off) +DEFINE_READ_ATTRS_SECTION(64, Elf64_Shdr, Elf64_Off) + +char *riscv_isa_from_elf(const char *path) { + FILE *f = fopen(path, "rb"); + if (!f) { + return NULL; + } + + unsigned char ident[EI_NIDENT]; + if (fread(ident, 1, EI_NIDENT, f) != EI_NIDENT || + ident[EI_MAG0] != ELFMAG0 || ident[EI_MAG1] != ELFMAG1 || + ident[EI_MAG2] != ELFMAG2 || ident[EI_MAG3] != ELFMAG3) { + fclose(f); + return NULL; + } + + rewind(f); + char *isa = NULL; + + if (ident[EI_CLASS] == ELFCLASS32) { + Elf32_Ehdr ehdr; + if (fread(&ehdr, sizeof(ehdr), 1, f) == 1 && + ehdr.e_machine == EM_RISCV) { + isa = read_attrs_section32(f, ehdr.e_shnum, ehdr.e_shoff); + } + } else if (ident[EI_CLASS] == ELFCLASS64) { + Elf64_Ehdr ehdr; + if (fread(&ehdr, sizeof(ehdr), 1, f) == 1 && + ehdr.e_machine == EM_RISCV) { + isa = read_attrs_section64(f, ehdr.e_shnum, ehdr.e_shoff); + } + } + + fclose(f); + return isa; +} diff --git a/contrib/plugins/bap-tracing/trace_riscv.h b/contrib/plugins/bap-tracing/trace_riscv.h new file mode 100644 index 0000000000000..3d49dfbf67b83 --- /dev/null +++ b/contrib/plugins/bap-tracing/trace_riscv.h @@ -0,0 +1,20 @@ +// SPDX-FileCopyrightText: 2025 Rot127 +// SPDX-License-Identifier: GPL-2.0-only + +#ifndef BAP_TRACE_RISCV_H +#define BAP_TRACE_RISCV_H + +/** + * \brief Read the RISC-V ISA string from a binary's ELF attributes section. + * + * Parses the SHT_RISCV_ATTRIBUTES section of the ELF binary at \p path, + * locates the "riscv" vendor sub-section, and returns the value of + * Tag_RISCV_arch (tag 5) verbatim as a newly-allocated string. + * + * \param path Path to the ELF binary. + * \return Heap-allocated ISA string (caller must g_free), or NULL if the + * binary is not a RISC-V ELF or the attributes section is absent. + */ +char *riscv_isa_from_elf(const char *path); + +#endif diff --git a/contrib/plugins/bap-tracing/tracing.h b/contrib/plugins/bap-tracing/tracing.h index f39509e2fc3f8..e54bca99b9c13 100644 --- a/contrib/plugins/bap-tracing/tracing.h +++ b/contrib/plugins/bap-tracing/tracing.h @@ -105,6 +105,8 @@ static struct arch_enum_entry arch_map[] = { {.name = "sm83", .arch = frame_arch_sm83, .machine = 0}, {.name = "hexagon", .arch = frame_arch_hexagon, .machine = 0}, {.name = "tricore", .arch = frame_arch_tricore, .machine = frame_mach_tricore_162}, + {.name = "riscv32", .arch = frame_arch_riscv, .machine = frame_mach_riscv32}, + {.name = "riscv64", .arch = frame_arch_riscv, .machine = frame_mach_riscv64}, {.name = NULL, .arch = frame_arch_last, .machine = 0}, };