From nobody Mon Feb 9 13:01:05 2026 Received: from mail-pg1-f201.google.com (mail-pg1-f201.google.com [209.85.215.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 88C271B3940 for ; Thu, 19 Dec 2024 21:07:53 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.215.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734642475; cv=none; b=ulbH0zfyIUYuxPTG56sbUzidKWPqz1fhWWD2WglQKUwYXfbuW2E3SOGO4Bs71dCJJFfViWRV3EzmKZxKvlhFiaS0KvEzZzKl9dkpNHsTCFKyrVpTI8kVH+HLfIdWD5dDKFjLKkmbuqIYlUFSasy26bWEbyuBNH0h2cN3cMoTPGU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734642475; c=relaxed/simple; bh=2R588xAUPDj6AGGdbWW5NwsrdeGB6AGfvMfJGS/jZx4=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=cT28vJ/ALEET5X+Rg/hx3c5wZa/zUDxUrX49nXO+/GG9pVic2PgHBRuV+Qrl7Ez8Hcqh/ImOhLm2ze3/2BtZJHcU0ha4Cm63vwuvkp/jmKt6BV8LB5p3LgoaUcdyb0SMes7wQ+LG3MqeNk0pUGDv9f5WxcgqdHUcSF913fSc1RE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--samitolvanen.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=SKLeCniX; arc=none smtp.client-ip=209.85.215.201 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--samitolvanen.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="SKLeCniX" Received: by mail-pg1-f201.google.com with SMTP id 41be03b00d2f7-7eb0a32fc5aso760887a12.2 for ; Thu, 19 Dec 2024 13:07:53 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1734642473; x=1735247273; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=9ZKqBqF0DF83RqL6Z7Kl1Azm4e26cplxVnocDMKcEpM=; b=SKLeCniXvb2yQ0Fdz2LmlC1o9CZtLjroh1xslzndC1B6ZO5BHgP/Ho5CgXek76vZ2b OD97AadC07aytoxcOXHhl4gACQ4reSXc3x4s9rQ37OMFqLpYEfNCsfgrnhLO9+J7SBMM UF/RhKhfdykvnYyLU1iNR2CIzBLnQimQwMsfS9HPCD+axrheRT/kSZy/4EJ/3rJqr3h4 kRM7Yzu6YdeoDYLyglwFbe/ifz22fE2hAIVWXHy8sdqOR1ZdDqQrN8yJoRBk2+1yrF1o ZplfzIFf6nTfLS9YTsj+EUvZnhXmtFdIoOwI9tXjFdQzJeR/zu/IWKBpgIDV9pgrEeeJ hlOQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1734642473; x=1735247273; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=9ZKqBqF0DF83RqL6Z7Kl1Azm4e26cplxVnocDMKcEpM=; b=EyZBJz6RdZv7FHi7dHhozprRRAJTTut9zgQU6ygS0qOJatHfqajGVDLxqxE+bc526+ YsfmAuk5h9g3uEFqro+zTNNRWDa7hwW0xOQzTpMV4Qmg8I5NSMzmIi4DSXaVFj+FVNDU OnwnoXCBQTgMAaAI7cXeZAKTFJd9G8eZMXY2PiToRerI1G75nYGM/+qkdpMt9UqhBIcQ d2NmH78lnEEuK86KJ8UW+52zxghigr1JkAxIw66xMlT3Q9y3flhIHoCUnQZP+HQ9x76x onuV8AalRxCTtKwlK4IMWcpMAN24EBeipWo/7nMaMJI2IWXnZwDuAxw1c5OAY4qQ92ab oWHA== X-Forwarded-Encrypted: i=1; AJvYcCV7pw+qbdM6YPYI5sr+w57gNdVw4RP5O3YaNToiSmW3ZQ0uHv/831Qp+w7lxRBihhh4xcQGMAkp6uUWJyg=@vger.kernel.org X-Gm-Message-State: AOJu0Yx2Ny+fIo/KxzMh99iMZuyqDrJMwm84a7vq72o3WPVVAq1uVLNO LTz9wuMNdxvGFvo3vz/17mtpsayklu41+ynNfTN7+JO4nOR6McTmTDf0I+I9tZzvQwCaV+Wnjvf ZT41D0iaw7lzCmwrYv1ar5AqZLQ== X-Google-Smtp-Source: AGHT+IFJL1RxKDsXqgL3DtW3U3Mg12nOMMsALjKCxJoLk2AfQs+nAGL4RT7NPJBEKhNqLd9TxR4yhgD2XdmpXwA7f04= X-Received: from pfaw12.prod.google.com ([2002:a05:6a00:ab8c:b0:728:e1a0:2e73]) (user=samitolvanen job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6a21:32a5:b0:1e1:bf3d:a191 with SMTP id adf61e73a8af0-1e5e080c805mr805679637.33.1734642472902; Thu, 19 Dec 2024 13:07:52 -0800 (PST) Date: Thu, 19 Dec 2024 21:07:38 +0000 In-Reply-To: <20241219210736.2990838-20-samitolvanen@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20241219210736.2990838-20-samitolvanen@google.com> X-Developer-Key: i=samitolvanen@google.com; a=openpgp; fpr=35CCFB63B283D6D3AEB783944CB5F6848BBC56EE X-Developer-Signature: v=1; a=openpgp-sha256; l=15516; i=samitolvanen@google.com; h=from:subject; bh=2R588xAUPDj6AGGdbWW5NwsrdeGB6AGfvMfJGS/jZx4=; b=owGbwMvMwCEWxa662nLh8irG02pJDOkp3ZIcV3h0Zfm/L/9fNo3V0e+nxN62Y/H3lgju/3ZRh YnBu2FTRykLgxgHg6yYIkvL19Vbd393Sn31uUgCZg4rE8gQBi5OAZiIognDX7nJqQ9mr6/fcerf tRtSp/zPycqzS1ds1kysV97/6EWneBojw3vNu9ZeV8srVu/tfXHJreha7pJvGoGzrd8nHu+/Mml 1MicA X-Mailer: git-send-email 2.47.1.613.gc27f4b7a9f-goog Message-ID: <20241219210736.2990838-21-samitolvanen@google.com> Subject: [PATCH v7 01/18] tools: Add gendwarfksyms From: Sami Tolvanen To: Masahiro Yamada , Luis Chamberlain , Miguel Ojeda , Greg Kroah-Hartman Cc: Matthew Maurer , Alex Gaynor , Gary Guo , Petr Pavlu , Daniel Gomez , Neal Gompa , Hector Martin , Janne Grunau , Miroslav Benes , Asahi Linux , Sedat Dilek , linux-kbuild@vger.kernel.org, linux-kernel@vger.kernel.org, linux-modules@vger.kernel.org, rust-for-linux@vger.kernel.org, Sami Tolvanen Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add a basic DWARF parser, which uses libdw to traverse the debugging information in an object file and looks for functions and variables. In follow-up patches, this will be expanded to produce symbol versions for CONFIG_MODVERSIONS from DWARF. Signed-off-by: Sami Tolvanen Reviewed-by: Petr Pavlu --- MAINTAINERS | 7 ++ kernel/module/Kconfig | 8 ++ scripts/Makefile | 1 + scripts/gendwarfksyms/.gitignore | 2 + scripts/gendwarfksyms/Makefile | 8 ++ scripts/gendwarfksyms/dwarf.c | 166 ++++++++++++++++++++++++++ scripts/gendwarfksyms/gendwarfksyms.c | 126 +++++++++++++++++++ scripts/gendwarfksyms/gendwarfksyms.h | 95 +++++++++++++++ scripts/gendwarfksyms/symbols.c | 96 +++++++++++++++ 9 files changed, 509 insertions(+) create mode 100644 scripts/gendwarfksyms/.gitignore create mode 100644 scripts/gendwarfksyms/Makefile create mode 100644 scripts/gendwarfksyms/dwarf.c create mode 100644 scripts/gendwarfksyms/gendwarfksyms.c create mode 100644 scripts/gendwarfksyms/gendwarfksyms.h create mode 100644 scripts/gendwarfksyms/symbols.c diff --git a/MAINTAINERS b/MAINTAINERS index baf0eeb9a355..35bb18834b39 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9550,6 +9550,13 @@ W: https://linuxtv.org T: git git://linuxtv.org/media.git F: drivers/media/radio/radio-gemtek* =20 +GENDWARFKSYMS +M: Sami Tolvanen +L: linux-modules@vger.kernel.org +L: linux-kbuild@vger.kernel.org +S: Maintained +F: scripts/gendwarfksyms/ + GENERIC ARCHITECTURE TOPOLOGY M: Sudeep Holla L: linux-kernel@vger.kernel.org diff --git a/kernel/module/Kconfig b/kernel/module/Kconfig index 7b329057997a..4637f063d0fc 100644 --- a/kernel/module/Kconfig +++ b/kernel/module/Kconfig @@ -169,6 +169,14 @@ config MODVERSIONS make them incompatible with the kernel you are running. If unsure, say N. =20 +config GENDWARFKSYMS + bool "gendwarfksyms (from debugging information)" + depends on DEBUG_INFO + # Requires full debugging information, split DWARF not supported. + depends on !DEBUG_INFO_REDUCED && !DEBUG_INFO_SPLIT + # Requires ELF object files. + depends on !LTO + config ASM_MODVERSIONS bool default HAVE_ASM_MODVERSIONS && MODVERSIONS diff --git a/scripts/Makefile b/scripts/Makefile index 6bcda4b9d054..d7fec46d38c0 100644 --- a/scripts/Makefile +++ b/scripts/Makefile @@ -54,6 +54,7 @@ targets +=3D module.lds =20 subdir-$(CONFIG_GCC_PLUGINS) +=3D gcc-plugins subdir-$(CONFIG_MODVERSIONS) +=3D genksyms +subdir-$(CONFIG_GENDWARFKSYMS) +=3D gendwarfksyms subdir-$(CONFIG_SECURITY_SELINUX) +=3D selinux subdir-$(CONFIG_SECURITY_IPE) +=3D ipe =20 diff --git a/scripts/gendwarfksyms/.gitignore b/scripts/gendwarfksyms/.giti= gnore new file mode 100644 index 000000000000..0927f8d3cd96 --- /dev/null +++ b/scripts/gendwarfksyms/.gitignore @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0 +/gendwarfksyms diff --git a/scripts/gendwarfksyms/Makefile b/scripts/gendwarfksyms/Makefile new file mode 100644 index 000000000000..9f8fec4fd39b --- /dev/null +++ b/scripts/gendwarfksyms/Makefile @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: GPL-2.0 +hostprogs-always-y +=3D gendwarfksyms + +gendwarfksyms-objs +=3D gendwarfksyms.o +gendwarfksyms-objs +=3D dwarf.o +gendwarfksyms-objs +=3D symbols.o + +HOSTLDLIBS_gendwarfksyms :=3D -ldw -lelf diff --git a/scripts/gendwarfksyms/dwarf.c b/scripts/gendwarfksyms/dwarf.c new file mode 100644 index 000000000000..81df3e2ad3ae --- /dev/null +++ b/scripts/gendwarfksyms/dwarf.c @@ -0,0 +1,166 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2024 Google LLC + */ + +#include "gendwarfksyms.h" + +static bool get_ref_die_attr(Dwarf_Die *die, unsigned int id, Dwarf_Die *v= alue) +{ + Dwarf_Attribute da; + + /* dwarf_formref_die returns a pointer instead of an error value. */ + return dwarf_attr(die, id, &da) && dwarf_formref_die(&da, value); +} + +#define DEFINE_GET_STRING_ATTR(attr) \ + static const char *get_##attr##_attr(Dwarf_Die *die) \ + { \ + Dwarf_Attribute da; \ + if (dwarf_attr(die, DW_AT_##attr, &da)) \ + return dwarf_formstring(&da); \ + return NULL; \ + } + +DEFINE_GET_STRING_ATTR(name) +DEFINE_GET_STRING_ATTR(linkage_name) + +static const char *get_symbol_name(Dwarf_Die *die) +{ + const char *name; + + /* rustc uses DW_AT_linkage_name for exported symbols */ + name =3D get_linkage_name_attr(die); + if (!name) + name =3D get_name_attr(die); + + return name; +} + +static bool match_export_symbol(struct state *state, Dwarf_Die *die) +{ + Dwarf_Die *source =3D die; + Dwarf_Die origin; + + /* If the DIE has an abstract origin, use it for type information. */ + if (get_ref_die_attr(die, DW_AT_abstract_origin, &origin)) + source =3D &origin; + + state->sym =3D symbol_get(get_symbol_name(die)); + + /* Look up using the origin name if there are no matches. */ + if (!state->sym && source !=3D die) + state->sym =3D symbol_get(get_symbol_name(source)); + + state->die =3D *source; + return !!state->sym; +} + +/* + * Type string processing + */ +static void process(const char *s) +{ + s =3D s ?: ""; + + if (dump_dies) + fputs(s, stderr); +} + +bool match_all(Dwarf_Die *die) +{ + return true; +} + +int process_die_container(struct state *state, Dwarf_Die *die, + die_callback_t func, die_match_callback_t match) +{ + Dwarf_Die current; + int res; + + res =3D checkp(dwarf_child(die, ¤t)); + while (!res) { + if (match(¤t)) { + /* <0 =3D error, 0 =3D continue, >0 =3D stop */ + res =3D checkp(func(state, ¤t)); + if (res) + return res; + } + + res =3D checkp(dwarf_siblingof(¤t, ¤t)); + } + + return 0; +} + +/* + * Exported symbol processing + */ +static void process_symbol(struct state *state, Dwarf_Die *die, + die_callback_t process_func) +{ + debug("%s", state->sym->name); + check(process_func(state, die)); + if (dump_dies) + fputs("\n", stderr); +} + +static int __process_subprogram(struct state *state, Dwarf_Die *die) +{ + process("subprogram"); + return 0; +} + +static void process_subprogram(struct state *state, Dwarf_Die *die) +{ + process_symbol(state, die, __process_subprogram); +} + +static int __process_variable(struct state *state, Dwarf_Die *die) +{ + process("variable "); + return 0; +} + +static void process_variable(struct state *state, Dwarf_Die *die) +{ + process_symbol(state, die, __process_variable); +} + +static int process_exported_symbols(struct state *unused, Dwarf_Die *die) +{ + int tag =3D dwarf_tag(die); + + switch (tag) { + /* Possible containers of exported symbols */ + case DW_TAG_namespace: + case DW_TAG_class_type: + case DW_TAG_structure_type: + return check(process_die_container( + NULL, die, process_exported_symbols, match_all)); + + /* Possible exported symbols */ + case DW_TAG_subprogram: + case DW_TAG_variable: { + struct state state; + + if (!match_export_symbol(&state, die)) + return 0; + + if (tag =3D=3D DW_TAG_subprogram) + process_subprogram(&state, &state.die); + else + process_variable(&state, &state.die); + + return 0; + } + default: + return 0; + } +} + +void process_cu(Dwarf_Die *cudie) +{ + check(process_die_container(NULL, cudie, process_exported_symbols, + match_all)); +} diff --git a/scripts/gendwarfksyms/gendwarfksyms.c b/scripts/gendwarfksyms/= gendwarfksyms.c new file mode 100644 index 000000000000..f84fa98fcbdb --- /dev/null +++ b/scripts/gendwarfksyms/gendwarfksyms.c @@ -0,0 +1,126 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2024 Google LLC + */ + +#include +#include +#include +#include +#include +#include +#include "gendwarfksyms.h" + +/* + * Options + */ + +/* Print debugging information to stderr */ +int debug; +/* Dump DIE contents */ +int dump_dies; + +static void usage(void) +{ + fputs("Usage: gendwarfksyms [options] elf-object-file ... < symbol-list\n= \n" + "Options:\n" + " -d, --debug Print debugging information\n" + " --dump-dies Dump DWARF DIE contents\n" + " -h, --help Print this message\n" + "\n", + stderr); +} + +static int process_module(Dwfl_Module *mod, void **userdata, const char *n= ame, + Dwarf_Addr base, void *arg) +{ + Dwarf_Addr dwbias; + Dwarf_Die cudie; + Dwarf_CU *cu =3D NULL; + Dwarf *dbg; + int res; + + debug("%s", name); + dbg =3D dwfl_module_getdwarf(mod, &dwbias); + + do { + res =3D dwarf_get_units(dbg, cu, &cu, NULL, NULL, &cudie, NULL); + if (res < 0) + error("dwarf_get_units failed: no debugging information?"); + if (res =3D=3D 1) + break; /* No more units */ + + process_cu(&cudie); + } while (cu); + + return DWARF_CB_OK; +} + +static const Dwfl_Callbacks callbacks =3D { + .section_address =3D dwfl_offline_section_address, + .find_debuginfo =3D dwfl_standard_find_debuginfo, +}; + +int main(int argc, char **argv) +{ + unsigned int n; + int opt; + + struct option opts[] =3D { { "debug", 0, NULL, 'd' }, + { "dump-dies", 0, &dump_dies, 1 }, + { "help", 0, NULL, 'h' }, + { 0, 0, NULL, 0 } }; + + while ((opt =3D getopt_long(argc, argv, "dh", opts, NULL)) !=3D EOF) { + switch (opt) { + case 0: + break; + case 'd': + debug =3D 1; + break; + case 'h': + usage(); + return 0; + default: + usage(); + return 1; + } + } + + if (optind >=3D argc) { + usage(); + error("no input files?"); + } + + symbol_read_exports(stdin); + + for (n =3D optind; n < argc; n++) { + Dwfl *dwfl; + int fd; + + fd =3D open(argv[n], O_RDONLY); + if (fd =3D=3D -1) + error("open failed for '%s': %s", argv[n], + strerror(errno)); + + dwfl =3D dwfl_begin(&callbacks); + if (!dwfl) + error("dwfl_begin failed for '%s': %s", argv[n], + dwarf_errmsg(-1)); + + if (!dwfl_report_offline(dwfl, argv[n], argv[n], fd)) + error("dwfl_report_offline failed for '%s': %s", + argv[n], dwarf_errmsg(-1)); + + dwfl_report_end(dwfl, NULL, NULL); + + if (dwfl_getmodules(dwfl, &process_module, NULL, 0)) + error("dwfl_getmodules failed for '%s'", argv[n]); + + dwfl_end(dwfl); + } + + symbol_free(); + + return 0; +} diff --git a/scripts/gendwarfksyms/gendwarfksyms.h b/scripts/gendwarfksyms/= gendwarfksyms.h new file mode 100644 index 000000000000..5c8288c71fdd --- /dev/null +++ b/scripts/gendwarfksyms/gendwarfksyms.h @@ -0,0 +1,95 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2024 Google LLC + */ + +#include +#include +#include +#include +#include + +#include +#include +#include + +#ifndef __GENDWARFKSYMS_H +#define __GENDWARFKSYMS_H + +/* + * Options -- in gendwarfksyms.c + */ +extern int debug; +extern int dump_dies; + +/* + * Output helpers + */ +#define __PREFIX "gendwarfksyms: " +#define __println(prefix, format, ...) \ + fprintf(stderr, prefix __PREFIX "%s: " format "\n", __func__, \ + ##__VA_ARGS__) + +#define debug(format, ...) \ + do { \ + if (debug) \ + __println("", format, ##__VA_ARGS__); \ + } while (0) + +#define warn(format, ...) __println("warning: ", format, ##__VA_ARGS__) +#define error(format, ...) \ + do { \ + __println("error: ", format, ##__VA_ARGS__); \ + exit(1); \ + } while (0) + +/* + * Error handling helpers + */ +#define __check(expr, test) \ + ({ \ + int __res =3D expr; \ + if (test) \ + error("`%s` failed: %d", #expr, __res); \ + __res; \ + }) + +/* Error =3D=3D non-zero values */ +#define check(expr) __check(expr, __res) +/* Error =3D=3D negative values */ +#define checkp(expr) __check(expr, __res < 0) + +/* + * symbols.c + */ + +struct symbol { + const char *name; + struct hlist_node name_hash; +}; + +typedef void (*symbol_callback_t)(struct symbol *, void *arg); + +void symbol_read_exports(FILE *file); +struct symbol *symbol_get(const char *name); +void symbol_free(void); + +/* + * dwarf.c + */ + +struct state { + struct symbol *sym; + Dwarf_Die die; +}; + +typedef int (*die_callback_t)(struct state *state, Dwarf_Die *die); +typedef bool (*die_match_callback_t)(Dwarf_Die *die); +bool match_all(Dwarf_Die *die); + +int process_die_container(struct state *state, Dwarf_Die *die, + die_callback_t func, die_match_callback_t match); + +void process_cu(Dwarf_Die *cudie); + +#endif /* __GENDWARFKSYMS_H */ diff --git a/scripts/gendwarfksyms/symbols.c b/scripts/gendwarfksyms/symbol= s.c new file mode 100644 index 000000000000..7adf2ed9b89b --- /dev/null +++ b/scripts/gendwarfksyms/symbols.c @@ -0,0 +1,96 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2024 Google LLC + */ + +#include "gendwarfksyms.h" + +#define SYMBOL_HASH_BITS 12 +static HASHTABLE_DEFINE(symbol_names, 1 << SYMBOL_HASH_BITS); + +static unsigned int for_each(const char *name, symbol_callback_t func, + void *data) +{ + struct hlist_node *tmp; + struct symbol *match; + + if (!name || !*name) + return 0; + + hash_for_each_possible_safe(symbol_names, match, tmp, name_hash, + hash_str(name)) { + if (strcmp(match->name, name)) + continue; + + if (func) + func(match, data); + + return 1; + } + + return 0; +} + +static bool is_exported(const char *name) +{ + return for_each(name, NULL, NULL) > 0; +} + +void symbol_read_exports(FILE *file) +{ + struct symbol *sym; + char *line =3D NULL; + char *name =3D NULL; + size_t size =3D 0; + int nsym =3D 0; + + while (getline(&line, &size, file) > 0) { + if (sscanf(line, "%ms\n", &name) !=3D 1) + error("malformed input line: %s", line); + + if (is_exported(name)) { + /* Ignore duplicates */ + free(name); + continue; + } + + sym =3D xcalloc(1, sizeof(struct symbol)); + sym->name =3D name; + + hash_add(symbol_names, &sym->name_hash, hash_str(sym->name)); + ++nsym; + + debug("%s", sym->name); + } + + free(line); + debug("%d exported symbols", nsym); +} + +static void get_symbol(struct symbol *sym, void *arg) +{ + struct symbol **res =3D arg; + + *res =3D sym; +} + +struct symbol *symbol_get(const char *name) +{ + struct symbol *sym =3D NULL; + + for_each(name, get_symbol, &sym); + return sym; +} + +void symbol_free(void) +{ + struct hlist_node *tmp; + struct symbol *sym; + + hash_for_each_safe(symbol_names, sym, tmp, name_hash) { + free((void *)sym->name); + free(sym); + } + + hash_init(symbol_names); +} --=20 2.47.1.613.gc27f4b7a9f-goog From nobody Mon Feb 9 13:01:05 2026 Received: from mail-pf1-f202.google.com (mail-pf1-f202.google.com [209.85.210.202]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 274791BEF71 for ; Thu, 19 Dec 2024 21:07:55 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.202 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734642478; cv=none; b=T5OddPtlkxB0YgguEtEJhbXhapqsDUkdsYV+/O3oO/5EFO33lf8ETf53dl1XJanKtuSx6PDGPEsxZBRtE+QuWarDvi1RAnbFZ08iF7UdkKRBqU1R9DPPghk/CzNSxughtl0lKXoHo8BZMzUO8U8zR0ShU7zNUC0Gt799n5YWmIE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734642478; c=relaxed/simple; bh=t4OeKtmQMhXTGshkqVqY9wv+YyO0JXvhiaWxn9DmKAo=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=pX3XCE5opMHuX4ExYqVbs+Vz9oe182egotiyNwavkfgrKNf0JVN+0GM/Jq07k0FM0gQSxyD3BIbhRfAjoJU2D91j2i+cfbV44Xehj+nPtKRja9nHdQgc2xj/eL/8CnnGS1w4ZZzafilIMvDvGScQf4N3g9vGtfc+ljUvHTmSll4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--samitolvanen.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=X4RuCyA5; arc=none smtp.client-ip=209.85.210.202 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--samitolvanen.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="X4RuCyA5" Received: by mail-pf1-f202.google.com with SMTP id d2e1a72fcca58-728cd4fd607so1144651b3a.0 for ; Thu, 19 Dec 2024 13:07:55 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1734642474; x=1735247274; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=aaIPQcS3RU8IiH3sIpb5Pan8w7W30JBzIeQFaarlfbM=; b=X4RuCyA5rRAKOTAElVlOtzYGMhWRoA+M0tEtgrZcCJ7m+i0MdlfK2iHsAVbtcR0VxG eHrbuNTCFRXjfW9lcxqKKxLXlhEtq0up15N5mcofBJ6MYXzeuQnHv5wCHG9A71e7NngH +SqWRe7vjlUMtGuSBB8sV4fezG5RQ1Gz26RcP826WBXVZiI8eQzoklnlo1yGwWPx9NXR YxCJ3+sQazK3ndkMHs5a17PtKQK3J1lVhwsONxy8cVAZsEvKKabz7RhRAyz7XmlaGZNB 3+vXmZ1d4UejWc77pwZjL5qL8+bOYct2gVZ06e1JjD+cv+1MR+YdnYwJ3AxHzXY0JpRg 8Lvg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1734642474; x=1735247274; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=aaIPQcS3RU8IiH3sIpb5Pan8w7W30JBzIeQFaarlfbM=; b=tOoBEjAFCGAYRUJODH+7okLGwzrF9zmlHpnOfyJkpbPknjubHyhjvxxOz35HEXb4ei S8u/Y+vn8dBff5vwZwKMEbjl9CiJEp+5mOdZuWsmKgFytxMAOhi8tcNRWo81kS9S9AKw 9m3AxzH/ebL7s2autYtN/elCNGFsXIyeoxRzKO5Xd8/L15fbNEWNesmucAtKRDqH8vni Zo6Tf4u0DLWMOKBg86vsn/w7S8ownyyj8CQ4ulFd4a8j+hv5HHUYGkmb4rYHd9UKd5A5 MVJ1Ox+hKZ87y8zHSlxAqgGio1NzrDBjIiZ9qpjwjB8vSuFkrDwde83UJtBI0Kgu+R1k dAEA== X-Forwarded-Encrypted: i=1; AJvYcCVSlP/ICGsLJv+jQhCzYWyqSf07PWDEWsVGfeKWtYUJF29bntD5QDWwtxkmDVvNKSADVSXLs64naXsV9Tc=@vger.kernel.org X-Gm-Message-State: AOJu0YwKfhHZSggkG+g839yTkpcMOkGBC7rZOwTApEZO8JY8Pfo8a4LG Ff6ePR3Iw94b0aJTp4VJj3A2rHxcbbdtqkzylX5wjFYPSEtE0YZNzCLA6mx/CW1dZAl480Iqme6 205L6jYx6qa0mU+p8sxsr7zzwPQ== X-Google-Smtp-Source: AGHT+IGRpSgOPRPZNpyl27Of4ttBmlmnJE0YmNtoWb3t4dJHVI+bEy+3Qz33iUQMEmIb2tBllePsJuTn/0jfn3MEXGg= X-Received: from pfbct27.prod.google.com ([2002:a05:6a00:f9b:b0:72a:a111:742a]) (user=samitolvanen job=prod-delivery.src-stubby-dispatcher) by 2002:aa7:888c:0:b0:725:f212:12e5 with SMTP id d2e1a72fcca58-72abded14e5mr298842b3a.24.1734642474367; Thu, 19 Dec 2024 13:07:54 -0800 (PST) Date: Thu, 19 Dec 2024 21:07:39 +0000 In-Reply-To: <20241219210736.2990838-20-samitolvanen@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20241219210736.2990838-20-samitolvanen@google.com> X-Developer-Key: i=samitolvanen@google.com; a=openpgp; fpr=35CCFB63B283D6D3AEB783944CB5F6848BBC56EE X-Developer-Signature: v=1; a=openpgp-sha256; l=7404; i=samitolvanen@google.com; h=from:subject; bh=t4OeKtmQMhXTGshkqVqY9wv+YyO0JXvhiaWxn9DmKAo=; b=owGbwMvMwCEWxa662nLh8irG02pJDOkp3ZKvXdzWCx1TOvh2Nf/fKjaxX/OsdbXX7Lr+9uFko bf3aicVd5SyMIhxMMiKKbK0fF29dfd3p9RXn4skYOawMoEMYeDiFICJuPMw/Pdlvb/uQRgrW+DR x3NTWY47XX8W3bR9porMHBtO21+qjnsY/sccyzcQzOF40S8xe7WSS6bD4pCA4mCuqbOiFlcxciV 9ZAUA X-Mailer: git-send-email 2.47.1.613.gc27f4b7a9f-goog Message-ID: <20241219210736.2990838-22-samitolvanen@google.com> Subject: [PATCH v7 02/18] gendwarfksyms: Add address matching From: Sami Tolvanen To: Masahiro Yamada , Luis Chamberlain , Miguel Ojeda , Greg Kroah-Hartman Cc: Matthew Maurer , Alex Gaynor , Gary Guo , Petr Pavlu , Daniel Gomez , Neal Gompa , Hector Martin , Janne Grunau , Miroslav Benes , Asahi Linux , Sedat Dilek , linux-kbuild@vger.kernel.org, linux-kernel@vger.kernel.org, linux-modules@vger.kernel.org, rust-for-linux@vger.kernel.org, Sami Tolvanen Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" The compiler may choose not to emit type information in DWARF for all aliases, but it's possible for each alias to be exported separately. To ensure we find type information for the aliases as well, read {section, address} tuples from the symbol table and match symbols also by address. Signed-off-by: Sami Tolvanen Reviewed-by: Petr Pavlu --- scripts/gendwarfksyms/gendwarfksyms.c | 2 + scripts/gendwarfksyms/gendwarfksyms.h | 13 ++ scripts/gendwarfksyms/symbols.c | 163 ++++++++++++++++++++++++++ 3 files changed, 178 insertions(+) diff --git a/scripts/gendwarfksyms/gendwarfksyms.c b/scripts/gendwarfksyms/= gendwarfksyms.c index f84fa98fcbdb..1763234b6329 100644 --- a/scripts/gendwarfksyms/gendwarfksyms.c +++ b/scripts/gendwarfksyms/gendwarfksyms.c @@ -103,6 +103,8 @@ int main(int argc, char **argv) error("open failed for '%s': %s", argv[n], strerror(errno)); =20 + symbol_read_symtab(fd); + dwfl =3D dwfl_begin(&callbacks); if (!dwfl) error("dwfl_begin failed for '%s': %s", argv[n], diff --git a/scripts/gendwarfksyms/gendwarfksyms.h b/scripts/gendwarfksyms/= gendwarfksyms.h index 5c8288c71fdd..cb9fd78a58da 100644 --- a/scripts/gendwarfksyms/gendwarfksyms.h +++ b/scripts/gendwarfksyms/gendwarfksyms.h @@ -63,14 +63,27 @@ extern int dump_dies; * symbols.c */ =20 +static inline unsigned int addr_hash(uintptr_t addr) +{ + return hash_ptr((const void *)addr); +} + +struct symbol_addr { + uint32_t section; + Elf64_Addr address; +}; + struct symbol { const char *name; + struct symbol_addr addr; + struct hlist_node addr_hash; struct hlist_node name_hash; }; =20 typedef void (*symbol_callback_t)(struct symbol *, void *arg); =20 void symbol_read_exports(FILE *file); +void symbol_read_symtab(int fd); struct symbol *symbol_get(const char *name); void symbol_free(void); =20 diff --git a/scripts/gendwarfksyms/symbols.c b/scripts/gendwarfksyms/symbol= s.c index 7adf2ed9b89b..98febb524dd5 100644 --- a/scripts/gendwarfksyms/symbols.c +++ b/scripts/gendwarfksyms/symbols.c @@ -6,8 +6,39 @@ #include "gendwarfksyms.h" =20 #define SYMBOL_HASH_BITS 12 + +/* struct symbol_addr -> struct symbol */ +static HASHTABLE_DEFINE(symbol_addrs, 1 << SYMBOL_HASH_BITS); +/* name -> struct symbol */ static HASHTABLE_DEFINE(symbol_names, 1 << SYMBOL_HASH_BITS); =20 +static inline unsigned int symbol_addr_hash(const struct symbol_addr *addr) +{ + return hash_32(addr->section ^ addr_hash(addr->address)); +} + +static unsigned int __for_each_addr(struct symbol *sym, symbol_callback_t = func, + void *data) +{ + struct hlist_node *tmp; + struct symbol *match =3D NULL; + unsigned int processed =3D 0; + + hash_for_each_possible_safe(symbol_addrs, match, tmp, addr_hash, + symbol_addr_hash(&sym->addr)) { + if (match =3D=3D sym) + continue; /* Already processed */ + + if (match->addr.section =3D=3D sym->addr.section && + match->addr.address =3D=3D sym->addr.address) { + func(match, data); + ++processed; + } + } + + return processed; +} + static unsigned int for_each(const char *name, symbol_callback_t func, void *data) { @@ -22,9 +53,13 @@ static unsigned int for_each(const char *name, symbol_ca= llback_t func, if (strcmp(match->name, name)) continue; =20 + /* Call func for the match, and all address matches */ if (func) func(match, data); =20 + if (match->addr.section !=3D SHN_UNDEF) + return __for_each_addr(match, func, data) + 1; + return 1; } =20 @@ -56,6 +91,7 @@ void symbol_read_exports(FILE *file) =20 sym =3D xcalloc(1, sizeof(struct symbol)); sym->name =3D name; + sym->addr.section =3D SHN_UNDEF; =20 hash_add(symbol_names, &sym->name_hash, hash_str(sym->name)); ++nsym; @@ -82,6 +118,132 @@ struct symbol *symbol_get(const char *name) return sym; } =20 +typedef void (*elf_symbol_callback_t)(const char *name, GElf_Sym *sym, + Elf32_Word xndx, void *arg); + +static void elf_for_each_global(int fd, elf_symbol_callback_t func, void *= arg) +{ + size_t sym_size; + GElf_Shdr shdr_mem; + GElf_Shdr *shdr; + Elf_Data *xndx_data =3D NULL; + Elf_Scn *scn; + Elf *elf; + + if (elf_version(EV_CURRENT) !=3D EV_CURRENT) + error("elf_version failed: %s", elf_errmsg(-1)); + + elf =3D elf_begin(fd, ELF_C_READ_MMAP, NULL); + if (!elf) + error("elf_begin failed: %s", elf_errmsg(-1)); + + scn =3D elf_nextscn(elf, NULL); + + while (scn) { + shdr =3D gelf_getshdr(scn, &shdr_mem); + if (!shdr) + error("gelf_getshdr failed: %s", elf_errmsg(-1)); + + if (shdr->sh_type =3D=3D SHT_SYMTAB_SHNDX) { + xndx_data =3D elf_getdata(scn, NULL); + if (!xndx_data) + error("elf_getdata failed: %s", elf_errmsg(-1)); + break; + } + + scn =3D elf_nextscn(elf, scn); + } + + sym_size =3D gelf_fsize(elf, ELF_T_SYM, 1, EV_CURRENT); + scn =3D elf_nextscn(elf, NULL); + + while (scn) { + shdr =3D gelf_getshdr(scn, &shdr_mem); + if (!shdr) + error("gelf_getshdr failed: %s", elf_errmsg(-1)); + + if (shdr->sh_type =3D=3D SHT_SYMTAB) { + unsigned int nsyms; + unsigned int n; + Elf_Data *data =3D elf_getdata(scn, NULL); + + if (!data) + error("elf_getdata failed: %s", elf_errmsg(-1)); + + if (shdr->sh_entsize !=3D sym_size) + error("expected sh_entsize (%lu) to be %zu", + shdr->sh_entsize, sym_size); + + nsyms =3D shdr->sh_size / shdr->sh_entsize; + + for (n =3D 1; n < nsyms; ++n) { + const char *name =3D NULL; + Elf32_Word xndx =3D 0; + GElf_Sym sym_mem; + GElf_Sym *sym; + + sym =3D gelf_getsymshndx(data, xndx_data, n, + &sym_mem, &xndx); + if (!sym) + error("gelf_getsymshndx failed: %s", + elf_errmsg(-1)); + + if (GELF_ST_BIND(sym->st_info) =3D=3D STB_LOCAL) + continue; + + if (sym->st_shndx !=3D SHN_XINDEX) + xndx =3D sym->st_shndx; + + name =3D elf_strptr(elf, shdr->sh_link, + sym->st_name); + if (!name) + error("elf_strptr failed: %s", + elf_errmsg(-1)); + + /* Skip empty symbol names */ + if (*name) + func(name, sym, xndx, arg); + } + } + + scn =3D elf_nextscn(elf, scn); + } + + check(elf_end(elf)); +} + +static void set_symbol_addr(struct symbol *sym, void *arg) +{ + struct symbol_addr *addr =3D arg; + + if (sym->addr.section =3D=3D SHN_UNDEF) { + sym->addr =3D *addr; + hash_add(symbol_addrs, &sym->addr_hash, + symbol_addr_hash(&sym->addr)); + + debug("%s -> { %u, %lx }", sym->name, sym->addr.section, + sym->addr.address); + } else if (sym->addr.section !=3D addr->section || + sym->addr.address !=3D addr->address) { + warn("multiple addresses for symbol %s?", sym->name); + } +} + +static void elf_set_symbol_addr(const char *name, GElf_Sym *sym, + Elf32_Word xndx, void *arg) +{ + struct symbol_addr addr =3D { .section =3D xndx, .address =3D sym->st_val= ue }; + + /* Set addresses for exported symbols */ + if (addr.section !=3D SHN_UNDEF) + for_each(name, set_symbol_addr, &addr); +} + +void symbol_read_symtab(int fd) +{ + elf_for_each_global(fd, elf_set_symbol_addr, NULL); +} + void symbol_free(void) { struct hlist_node *tmp; @@ -92,5 +254,6 @@ void symbol_free(void) free(sym); } =20 + hash_init(symbol_addrs); hash_init(symbol_names); } --=20 2.47.1.613.gc27f4b7a9f-goog From nobody Mon Feb 9 13:01:05 2026 Received: from mail-pj1-f73.google.com (mail-pj1-f73.google.com [209.85.216.73]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 842951C5F1E for ; Thu, 19 Dec 2024 21:07:56 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.216.73 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734642478; cv=none; b=gEFw1byTCs6xpajan1/I851jFs4bqvabJPvnWnim7pCO5qxWCZgLqMXLSsSkK3OEtKznE5LH7X2Qk3dqfwfI0BYP4VZ0lttrFG2nHFhpK3msuh4w8n5ZKSM9IbSRu5vgCM5hrgvl3CKNoqu884XaFSJ34ujhLCh9uXpyY6atGZE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734642478; c=relaxed/simple; bh=bbCvhhmVnhtTYpDrJYZHLEm7Ii+2fqEhxzWaIoSVp4g=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=TeKcuJ2XXSGBXhhn4p1DZV6SkTMv59R7bYXZNd8ve9QVauWNYHFfSk8kX5FaCVmOvEJmRHfqFIY4O1yrMdeNNNCy5yhTIp3dihx5w2SR4cRyvpaO0lZisSwu9JuZBYSRn+ODyfcHswn7i3c/ATpkbeiolh7Jt/0+Cngfu4kW6zU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--samitolvanen.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=JeRuArBE; arc=none smtp.client-ip=209.85.216.73 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--samitolvanen.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="JeRuArBE" Received: by mail-pj1-f73.google.com with SMTP id 98e67ed59e1d1-2ef91d5c863so1136527a91.2 for ; Thu, 19 Dec 2024 13:07:56 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1734642476; x=1735247276; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=iqmGG67x42YJFJgNp9m9MGLgkL+XEQeNfXKJAnh+SAA=; b=JeRuArBEogAyU34vC9HtTHwrJHx5u1RL7XqRP4DzNZDKbpLa6jWNZ1zw7KwqLDA23O LVhS5GMWzOvavLmBuzo/zYYLyy+zNoja3X8ZuekN1kHC6YRycDphvJvAzsFFuR0vPENq JuNVAZwMPGudJ9cn+0Jtoe64ozMruOXhuREywnoAAO3y3bpdLXZA6VdVqUlYg8Xma9cq Nc6UNWa71BtZJSgLe+o34V5pRGRX/tCsNvTslIgL2J10MXNlzW2lO4YzzUhJ9759VP2C iHrdb9Kt0XRhZgmCcuDiLzm0a972hxcQ8NmRVH115qRwbaAXq3pmyJzbox/n2vTgvWBg z7BQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1734642476; x=1735247276; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=iqmGG67x42YJFJgNp9m9MGLgkL+XEQeNfXKJAnh+SAA=; b=wXs6B7hquql8TdxIDo3/jqM8gvCSyvvsZmRqTarY9FgSbr5kHiCZdTywaKd+1T0+Mw B2wb/5B/Zpg61/XIl9uiZMjn3f+54HtNDA5XO3bUxxMWUY10Zw8uq+HsN18MVqEcZIv5 NgkFH7fna/GYleLBu8JfBuMGIEmJw3cRQ8RBB/CKzh1tXdMPfC0v64BZG0dEMdcldQ+g i6epP1VJv1tZYz2uk+Yp3TU8fOONbSikde3FeaMhtIZspIzE17rc3FsUuSVbpqesa1rE BnoaKPOJ7gRJUq/OXwf88TnSZUb6QMbIh0/P5mHcRhrY2aT9JGF7acJlxpzP+uGh+BP0 tB/w== X-Forwarded-Encrypted: i=1; AJvYcCWcEKeeTadSzF2RsxTPFJa1kv3tv8QfnJZ0H5Bzbse6SRjgkM7xQaGnQxLJQ9jgR+KapGSEEoLbTmpQFPQ=@vger.kernel.org X-Gm-Message-State: AOJu0Ywi7d4nVvpYKn9LT5RZ69XQddo+n6PhcK1PZSspFbf+UTK2ecge 4KRyUh19HA1gnlpqG6gnOf1ScZu7gywVpcvvRbBRY/4ceyDiPo5bh4smhun7w/TkSo+F71SthEy otswSCQDxzKTs3Xzxgi6sQXv6vA== X-Google-Smtp-Source: AGHT+IE+QiqHOl9N3U1IZLotZi74BCW+jOyId5tadxS/AlzJ429isHN0f1j0ynJltMkWByvG7g6oYhH80nrxkRm4n7Y= X-Received: from pjyd8.prod.google.com ([2002:a17:90a:dfc8:b0:2ea:7d73:294e]) (user=samitolvanen job=prod-delivery.src-stubby-dispatcher) by 2002:a17:90b:5202:b0:2ee:d186:fe48 with SMTP id 98e67ed59e1d1-2f452ec6a53mr608686a91.28.1734642476006; Thu, 19 Dec 2024 13:07:56 -0800 (PST) Date: Thu, 19 Dec 2024 21:07:40 +0000 In-Reply-To: <20241219210736.2990838-20-samitolvanen@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20241219210736.2990838-20-samitolvanen@google.com> X-Developer-Key: i=samitolvanen@google.com; a=openpgp; fpr=35CCFB63B283D6D3AEB783944CB5F6848BBC56EE X-Developer-Signature: v=1; a=openpgp-sha256; l=5405; i=samitolvanen@google.com; h=from:subject; bh=bbCvhhmVnhtTYpDrJYZHLEm7Ii+2fqEhxzWaIoSVp4g=; b=owGbwMvMwCEWxa662nLh8irG02pJDOkp3VKTOfLeOSXc/yAtcG3KRvG375YYlxx89vqYa396Q 3azF9fhjlIWBjEOBlkxRZaWr6u37v7ulPrqc5EEzBxWJpAhDFycAjAR72OMDCvE51ZIaKnWdc3W qMs7KDKrcTPrj5Wt3ofNrzw82bQ6wZCR4bZbsZexvmW7rsxemRXuNjP/7+A9I/8tPm+zPnNBgcc XVgA= X-Mailer: git-send-email 2.47.1.613.gc27f4b7a9f-goog Message-ID: <20241219210736.2990838-23-samitolvanen@google.com> Subject: [PATCH v7 03/18] gendwarfksyms: Expand base_type From: Sami Tolvanen To: Masahiro Yamada , Luis Chamberlain , Miguel Ojeda , Greg Kroah-Hartman Cc: Matthew Maurer , Alex Gaynor , Gary Guo , Petr Pavlu , Daniel Gomez , Neal Gompa , Hector Martin , Janne Grunau , Miroslav Benes , Asahi Linux , Sedat Dilek , linux-kbuild@vger.kernel.org, linux-kernel@vger.kernel.org, linux-modules@vger.kernel.org, rust-for-linux@vger.kernel.org, Sami Tolvanen Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Start making gendwarfksyms more useful by adding support for expanding DW_TAG_base_type types and basic DWARF attributes. Example: $ echo loops_per_jiffy | \ scripts/gendwarfksyms/gendwarfksyms \ --debug --dump-dies vmlinux.o ... gendwarfksyms: process_symbol: loops_per_jiffy variable base_type unsigned long byte_size(8) encoding(7) ... Signed-off-by: Sami Tolvanen Reviewed-by: Petr Pavlu --- scripts/gendwarfksyms/dwarf.c | 160 ++++++++++++++++++++++++++++++++++ 1 file changed, 160 insertions(+) diff --git a/scripts/gendwarfksyms/dwarf.c b/scripts/gendwarfksyms/dwarf.c index 81df3e2ad3ae..74e75b8ec891 100644 --- a/scripts/gendwarfksyms/dwarf.c +++ b/scripts/gendwarfksyms/dwarf.c @@ -3,8 +3,21 @@ * Copyright (C) 2024 Google LLC */ =20 +#include +#include #include "gendwarfksyms.h" =20 +#define DEFINE_GET_ATTR(attr, type) \ + static bool get_##attr##_attr(Dwarf_Die *die, unsigned int id, \ + type *value) \ + { \ + Dwarf_Attribute da; \ + return dwarf_attr(die, id, &da) && \ + !dwarf_form##attr(&da, value); \ + } + +DEFINE_GET_ATTR(udata, Dwarf_Word) + static bool get_ref_die_attr(Dwarf_Die *die, unsigned int id, Dwarf_Die *v= alue) { Dwarf_Attribute da; @@ -67,6 +80,109 @@ static void process(const char *s) fputs(s, stderr); } =20 +#define MAX_FMT_BUFFER_SIZE 128 + +static void process_fmt(const char *fmt, ...) +{ + char buf[MAX_FMT_BUFFER_SIZE]; + va_list args; + + va_start(args, fmt); + + if (checkp(vsnprintf(buf, sizeof(buf), fmt, args)) >=3D sizeof(buf)) + error("vsnprintf overflow: increase MAX_FMT_BUFFER_SIZE"); + + process(buf); + va_end(args); +} + +#define MAX_FQN_SIZE 64 + +/* Get a fully qualified name from DWARF scopes */ +static char *get_fqn(Dwarf_Die *die) +{ + const char *list[MAX_FQN_SIZE]; + Dwarf_Die *scopes =3D NULL; + bool has_name =3D false; + char *fqn =3D NULL; + char *p; + int count =3D 0; + int len =3D 0; + int res; + int i; + + res =3D checkp(dwarf_getscopes_die(die, &scopes)); + if (!res) { + list[count] =3D get_name_attr(die); + + if (!list[count]) + return NULL; + + len +=3D strlen(list[count]); + count++; + + goto done; + } + + for (i =3D res - 1; i >=3D 0 && count < MAX_FQN_SIZE; i--) { + if (dwarf_tag(&scopes[i]) =3D=3D DW_TAG_compile_unit) + continue; + + list[count] =3D get_name_attr(&scopes[i]); + + if (list[count]) { + has_name =3D true; + } else { + list[count] =3D ""; + has_name =3D false; + } + + len +=3D strlen(list[count]); + count++; + + if (i > 0) { + list[count++] =3D "::"; + len +=3D 2; + } + } + + free(scopes); + + if (count =3D=3D MAX_FQN_SIZE) + warn("increase MAX_FQN_SIZE: reached the maximum"); + + /* Consider the DIE unnamed if the last scope doesn't have a name */ + if (!has_name) + return NULL; +done: + fqn =3D xmalloc(len + 1); + *fqn =3D '\0'; + + p =3D fqn; + for (i =3D 0; i < count; i++) + p =3D stpcpy(p, list[i]); + + return fqn; +} + +static void process_fqn(Dwarf_Die *die) +{ + process(" "); + process(get_fqn(die) ?: ""); +} + +#define DEFINE_PROCESS_UDATA_ATTRIBUTE(attribute) = \ + static void process_##attribute##_attr(Dwarf_Die *die) \ + { \ + Dwarf_Word value; \ + if (get_udata_attr(die, DW_AT_##attribute, &value)) \ + process_fmt(" " #attribute "(%" PRIu64 ")", value); \ + } + +DEFINE_PROCESS_UDATA_ATTRIBUTE(alignment) +DEFINE_PROCESS_UDATA_ATTRIBUTE(byte_size) +DEFINE_PROCESS_UDATA_ATTRIBUTE(encoding) + bool match_all(Dwarf_Die *die) { return true; @@ -93,6 +209,49 @@ int process_die_container(struct state *state, Dwarf_Di= e *die, return 0; } =20 +static int process_type(struct state *state, Dwarf_Die *die); + +static void process_type_attr(struct state *state, Dwarf_Die *die) +{ + Dwarf_Die type; + + if (get_ref_die_attr(die, DW_AT_type, &type)) { + check(process_type(state, &type)); + return; + } + + /* Compilers can omit DW_AT_type -- print out 'void' to clarify */ + process("base_type void"); +} + +static void process_base_type(struct state *state, Dwarf_Die *die) +{ + process("base_type"); + process_fqn(die); + process_byte_size_attr(die); + process_encoding_attr(die); + process_alignment_attr(die); +} + +#define PROCESS_TYPE(type) \ + case DW_TAG_##type##_type: \ + process_##type##_type(state, die); \ + break; + +static int process_type(struct state *state, Dwarf_Die *die) +{ + int tag =3D dwarf_tag(die); + + switch (tag) { + PROCESS_TYPE(base) + default: + debug("unimplemented type: %x", tag); + break; + } + + return 0; +} + /* * Exported symbol processing */ @@ -119,6 +278,7 @@ static void process_subprogram(struct state *state, Dwa= rf_Die *die) static int __process_variable(struct state *state, Dwarf_Die *die) { process("variable "); + process_type_attr(state, die); return 0; } =20 --=20 2.47.1.613.gc27f4b7a9f-goog From nobody Mon Feb 9 13:01:05 2026 Received: from mail-pf1-f202.google.com (mail-pf1-f202.google.com [209.85.210.202]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id D220C1BEF81 for ; Thu, 19 Dec 2024 21:07:57 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.202 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734642481; cv=none; b=OCt2f7YXSDx0zhTGdIy4rgPMS4GLY9Vp3mxX3UYkKt8ToGNaBsuKX18sxWr7LEa4tIlLGC3RqNmDbD8wm/T15b1x/efxkmA+8TE5gB98lp6ONU4ednYHqsyWF36Rpgx8TPKvL7lb0HkwWGWib7WYvMgN/qYHyR4NDL0EKFNzt5k= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734642481; c=relaxed/simple; bh=ojPHM4TdRJoPL09uxHNafq3Z6qYR3Fl2hZHkfw7C90s=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=SSe4UrxXEh6/qHDvDTtWO1/KCvCnzrz6pznJvfE2Brc6BocOZUSXCurYUaLMQu4rlXhmU5n5eyX+LFFcu6Aq6oP9UZbS/lnl9Nja13UptZjiRKEN5zQ1f1oMQxrk7DRVxoyGk5E899TdAOG9tAzz2fX/hyH5aJpkrQtQPUBPPpw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--samitolvanen.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=R8G0boFv; arc=none smtp.client-ip=209.85.210.202 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--samitolvanen.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="R8G0boFv" Received: by mail-pf1-f202.google.com with SMTP id d2e1a72fcca58-726047a4bd1so1775935b3a.3 for ; Thu, 19 Dec 2024 13:07:57 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1734642477; x=1735247277; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=sZeTEVoU9eMu65xvxr+TzfCvkY1WGDct1gC44nB7igY=; b=R8G0boFvEqyQxy2jYMTzjPOXtarL2WT6cAxHkIF+Y3B4bAG8sniTlyVQY5t8GzEnOb V1mKR4HAHQwS2aoO4+msYAWD2t8E5zYPuHdu1L0Qs4EWUmfGZ7lW2YXRM1kZi8xW5jqb 9mFjJXqNUEam4N+HgKh6LPy9eS0whLOW8bQFw4nke2AjIA6EnJSWiDyIy+BUWkAYGzQ6 Q8IC5ArIw4Wd30oJhteDp7iHc819qhmH7PSkEHlsn/CK59nb43STcKMav4VHxEZsjBPi ZUB8ZeYAkkhimn7M6p8ikiBgopVq2yFC/JPebAtlCZCh2qAmx9avHcZzNoNokzV78GV2 yEDw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1734642477; x=1735247277; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=sZeTEVoU9eMu65xvxr+TzfCvkY1WGDct1gC44nB7igY=; b=lyQ+Vhlkeg5QItmJPgu2F9kJCp7aD4Zeg5iuNHKH8csu+1IiNUx/iTjL7tixb4N+sf O9cUleCT1Q3AphZLMRVi/riNx6wk4XIdGwdLGGdvGdJCc05HS+HXZBy2L/LGVdyidbbm WVz3thZuTMgue1BJzbjrHCQNY0VIeguu1CWB4yr9dffFFobXdROh6iuMQSxJHQPgLi3i Xs0tygeuv2tM+49Emli+HgGIUtpjlJ/QNxPGwzBjkRULkFA5QGZR6MjYPoAJmv6PWG5R BDUJQktZt6zUPOMAHwhsyHf3j1Whnw+O1+PzFeaNgUljuRsceMQxwU6/L5FndT/7xDqg fVfA== X-Forwarded-Encrypted: i=1; AJvYcCWtnCyg/DTMgiSJvw5gjzd+ydaAIhKclRuyDKNH7rcH2emjnAlOq8SuwC2lPEjLSfVqi8bzPl1QSg7d3JA=@vger.kernel.org X-Gm-Message-State: AOJu0YzmiMYyoqcAsgXf9Kg7pNAnmCb01DzmgW43f9jRAmcN+uIixTcU xJ3u+ZKSF4YxM5lK/vdv2m0TlUTcl77B8BPZWRUNi0TzDwoT6MGvmXuA1EaPrVEzV9HuW+iQmb8 bkeZxS33vS08mUFJhD5MWdVg7LA== X-Google-Smtp-Source: AGHT+IH2yVOIxDOfFhNUksJYr+R7sAFJ9w+dsz4GakGwGDv4Cl/xUUow3RZ0UbkILOHU3rexcNwxwHJftIU+tQ4Js4g= X-Received: from pfbct11.prod.google.com ([2002:a05:6a00:f8b:b0:725:ceac:b484]) (user=samitolvanen job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6a00:a91:b0:726:c23f:4e5c with SMTP id d2e1a72fcca58-72abdd20f88mr268222b3a.1.1734642477322; Thu, 19 Dec 2024 13:07:57 -0800 (PST) Date: Thu, 19 Dec 2024 21:07:41 +0000 In-Reply-To: <20241219210736.2990838-20-samitolvanen@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20241219210736.2990838-20-samitolvanen@google.com> X-Developer-Key: i=samitolvanen@google.com; a=openpgp; fpr=35CCFB63B283D6D3AEB783944CB5F6848BBC56EE X-Developer-Signature: v=1; a=openpgp-sha256; l=15460; i=samitolvanen@google.com; h=from:subject; bh=ojPHM4TdRJoPL09uxHNafq3Z6qYR3Fl2hZHkfw7C90s=; b=owGbwMvMwCEWxa662nLh8irG02pJDOkp3VJPEktf7s+4Jfl6wwRLtkVSS/k2F3pNF16+SKngg FWzhUxZRykLgxgHg6yYIkvL19Vbd393Sn31uUgCZg4rE8gQBi5OAZjI6f8Mf0Wc+b7OMN96h91g 2983n2WO3ou83231fI+odn6u1P6UfZ8Z/md/0T8Y2zqrp4OhJfls0yytUBYjqYT7U9+8E37Mssj oNScA X-Mailer: git-send-email 2.47.1.613.gc27f4b7a9f-goog Message-ID: <20241219210736.2990838-24-samitolvanen@google.com> Subject: [PATCH v7 04/18] gendwarfksyms: Add a cache for processed DIEs From: Sami Tolvanen To: Masahiro Yamada , Luis Chamberlain , Miguel Ojeda , Greg Kroah-Hartman Cc: Matthew Maurer , Alex Gaynor , Gary Guo , Petr Pavlu , Daniel Gomez , Neal Gompa , Hector Martin , Janne Grunau , Miroslav Benes , Asahi Linux , Sedat Dilek , linux-kbuild@vger.kernel.org, linux-kernel@vger.kernel.org, linux-modules@vger.kernel.org, rust-for-linux@vger.kernel.org, Sami Tolvanen Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Basic types in DWARF repeat frequently and traversing the DIEs using libdw is relatively slow. Add a simple hashtable based cache for the processed DIEs. Signed-off-by: Sami Tolvanen Reviewed-by: Petr Pavlu --- scripts/gendwarfksyms/Makefile | 1 + scripts/gendwarfksyms/die.c | 143 ++++++++++++++++++++++++++ scripts/gendwarfksyms/dwarf.c | 136 +++++++++++++++++------- scripts/gendwarfksyms/gendwarfksyms.c | 6 ++ scripts/gendwarfksyms/gendwarfksyms.h | 63 +++++++++++- 5 files changed, 308 insertions(+), 41 deletions(-) create mode 100644 scripts/gendwarfksyms/die.c diff --git a/scripts/gendwarfksyms/Makefile b/scripts/gendwarfksyms/Makefile index 9f8fec4fd39b..c0d4ce50fc27 100644 --- a/scripts/gendwarfksyms/Makefile +++ b/scripts/gendwarfksyms/Makefile @@ -2,6 +2,7 @@ hostprogs-always-y +=3D gendwarfksyms =20 gendwarfksyms-objs +=3D gendwarfksyms.o +gendwarfksyms-objs +=3D die.o gendwarfksyms-objs +=3D dwarf.o gendwarfksyms-objs +=3D symbols.o =20 diff --git a/scripts/gendwarfksyms/die.c b/scripts/gendwarfksyms/die.c new file mode 100644 index 000000000000..b7d900c6a9c8 --- /dev/null +++ b/scripts/gendwarfksyms/die.c @@ -0,0 +1,143 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2024 Google LLC + */ + +#include +#include "gendwarfksyms.h" + +#define DIE_HASH_BITS 15 + +/* {die->addr, state} -> struct die * */ +static HASHTABLE_DEFINE(die_map, 1 << DIE_HASH_BITS); + +static unsigned int map_hits; +static unsigned int map_misses; + +static inline unsigned int die_hash(uintptr_t addr, enum die_state state) +{ + return hash_32(addr_hash(addr) ^ (unsigned int)state); +} + +static void init_die(struct die *cd) +{ + cd->state =3D DIE_INCOMPLETE; + cd->fqn =3D NULL; + cd->tag =3D -1; + cd->addr =3D 0; + INIT_LIST_HEAD(&cd->fragments); +} + +static struct die *create_die(Dwarf_Die *die, enum die_state state) +{ + struct die *cd; + + cd =3D xmalloc(sizeof(struct die)); + init_die(cd); + cd->addr =3D (uintptr_t)die->addr; + + hash_add(die_map, &cd->hash, die_hash(cd->addr, state)); + return cd; +} + +int __die_map_get(uintptr_t addr, enum die_state state, struct die **res) +{ + struct die *cd; + + hash_for_each_possible(die_map, cd, hash, die_hash(addr, state)) { + if (cd->addr =3D=3D addr && cd->state =3D=3D state) { + *res =3D cd; + return 0; + } + } + + return -1; +} + +struct die *die_map_get(Dwarf_Die *die, enum die_state state) +{ + struct die *cd; + + if (__die_map_get((uintptr_t)die->addr, state, &cd) =3D=3D 0) { + map_hits++; + return cd; + } + + map_misses++; + return create_die(die, state); +} + +static void reset_die(struct die *cd) +{ + struct die_fragment *tmp; + struct die_fragment *df; + + list_for_each_entry_safe(df, tmp, &cd->fragments, list) { + if (df->type =3D=3D FRAGMENT_STRING) + free(df->data.str); + free(df); + } + + if (cd->fqn && *cd->fqn) + free(cd->fqn); + init_die(cd); +} + +void die_map_free(void) +{ + struct hlist_node *tmp; + unsigned int stats[DIE_LAST + 1]; + struct die *cd; + int i; + + memset(stats, 0, sizeof(stats)); + + hash_for_each_safe(die_map, cd, tmp, hash) { + stats[cd->state]++; + reset_die(cd); + free(cd); + } + hash_init(die_map); + + if (map_hits + map_misses > 0) + debug("hits %u, misses %u (hit rate %.02f%%)", map_hits, + map_misses, + (100.0f * map_hits) / (map_hits + map_misses)); + + for (i =3D 0; i <=3D DIE_LAST; i++) + debug("%s: %u entries", die_state_name(i), stats[i]); +} + +static struct die_fragment *append_item(struct die *cd) +{ + struct die_fragment *df; + + df =3D xmalloc(sizeof(struct die_fragment)); + df->type =3D FRAGMENT_EMPTY; + list_add_tail(&df->list, &cd->fragments); + return df; +} + +void die_map_add_string(struct die *cd, const char *str) +{ + struct die_fragment *df; + + if (!cd) + return; + + df =3D append_item(cd); + df->data.str =3D xstrdup(str); + df->type =3D FRAGMENT_STRING; +} + +void die_map_add_die(struct die *cd, struct die *child) +{ + struct die_fragment *df; + + if (!cd) + return; + + df =3D append_item(cd); + df->data.addr =3D child->addr; + df->type =3D FRAGMENT_DIE; +} diff --git a/scripts/gendwarfksyms/dwarf.c b/scripts/gendwarfksyms/dwarf.c index 74e75b8ec891..f40e23a547da 100644 --- a/scripts/gendwarfksyms/dwarf.c +++ b/scripts/gendwarfksyms/dwarf.c @@ -72,17 +72,19 @@ static bool match_export_symbol(struct state *state, Dw= arf_Die *die) /* * Type string processing */ -static void process(const char *s) +static void process(struct die *cache, const char *s) { s =3D s ?: ""; =20 if (dump_dies) fputs(s, stderr); + + die_map_add_string(cache, s); } =20 #define MAX_FMT_BUFFER_SIZE 128 =20 -static void process_fmt(const char *fmt, ...) +static void process_fmt(struct die *cache, const char *fmt, ...) { char buf[MAX_FMT_BUFFER_SIZE]; va_list args; @@ -92,7 +94,7 @@ static void process_fmt(const char *fmt, ...) if (checkp(vsnprintf(buf, sizeof(buf), fmt, args)) >=3D sizeof(buf)) error("vsnprintf overflow: increase MAX_FMT_BUFFER_SIZE"); =20 - process(buf); + process(cache, buf); va_end(args); } =20 @@ -165,18 +167,28 @@ static char *get_fqn(Dwarf_Die *die) return fqn; } =20 -static void process_fqn(Dwarf_Die *die) +static void update_fqn(struct die *cache, Dwarf_Die *die) +{ + if (!cache->fqn) + cache->fqn =3D get_fqn(die) ?: ""; +} + +static void process_fqn(struct die *cache, Dwarf_Die *die) { - process(" "); - process(get_fqn(die) ?: ""); + update_fqn(cache, die); + if (*cache->fqn) + process(cache, " "); + process(cache, cache->fqn); } =20 -#define DEFINE_PROCESS_UDATA_ATTRIBUTE(attribute) = \ - static void process_##attribute##_attr(Dwarf_Die *die) \ - { \ - Dwarf_Word value; \ - if (get_udata_attr(die, DW_AT_##attribute, &value)) \ - process_fmt(" " #attribute "(%" PRIu64 ")", value); \ +#define DEFINE_PROCESS_UDATA_ATTRIBUTE(attribute) = \ + static void process_##attribute##_attr(struct die *cache, \ + Dwarf_Die *die) \ + { \ + Dwarf_Word value; \ + if (get_udata_attr(die, DW_AT_##attribute, &value)) \ + process_fmt(cache, " " #attribute "(%" PRIu64 ")", \ + value); \ } =20 DEFINE_PROCESS_UDATA_ATTRIBUTE(alignment) @@ -188,8 +200,9 @@ bool match_all(Dwarf_Die *die) return true; } =20 -int process_die_container(struct state *state, Dwarf_Die *die, - die_callback_t func, die_match_callback_t match) +int process_die_container(struct state *state, struct die *cache, + Dwarf_Die *die, die_callback_t func, + die_match_callback_t match) { Dwarf_Die current; int res; @@ -198,7 +211,7 @@ int process_die_container(struct state *state, Dwarf_Di= e *die, while (!res) { if (match(¤t)) { /* <0 =3D error, 0 =3D continue, >0 =3D stop */ - res =3D checkp(func(state, ¤t)); + res =3D checkp(func(state, cache, ¤t)); if (res) return res; } @@ -209,39 +222,78 @@ int process_die_container(struct state *state, Dwarf_= Die *die, return 0; } =20 -static int process_type(struct state *state, Dwarf_Die *die); +static int process_type(struct state *state, struct die *parent, + Dwarf_Die *die); =20 -static void process_type_attr(struct state *state, Dwarf_Die *die) +static void process_type_attr(struct state *state, struct die *cache, + Dwarf_Die *die) { Dwarf_Die type; =20 if (get_ref_die_attr(die, DW_AT_type, &type)) { - check(process_type(state, &type)); + check(process_type(state, cache, &type)); return; } =20 /* Compilers can omit DW_AT_type -- print out 'void' to clarify */ - process("base_type void"); + process(cache, "base_type void"); +} + +static void process_base_type(struct state *state, struct die *cache, + Dwarf_Die *die) +{ + process(cache, "base_type"); + process_fqn(cache, die); + process_byte_size_attr(cache, die); + process_encoding_attr(cache, die); + process_alignment_attr(cache, die); } =20 -static void process_base_type(struct state *state, Dwarf_Die *die) +static void process_cached(struct state *state, struct die *cache, + Dwarf_Die *die) { - process("base_type"); - process_fqn(die); - process_byte_size_attr(die); - process_encoding_attr(die); - process_alignment_attr(die); + struct die_fragment *df; + Dwarf_Die child; + + list_for_each_entry(df, &cache->fragments, list) { + switch (df->type) { + case FRAGMENT_STRING: + process(NULL, df->data.str); + break; + case FRAGMENT_DIE: + if (!dwarf_die_addr_die(dwarf_cu_getdwarf(die->cu), + (void *)df->data.addr, &child)) + error("dwarf_die_addr_die failed"); + check(process_type(state, NULL, &child)); + break; + default: + error("empty die_fragment"); + } + } } =20 -#define PROCESS_TYPE(type) \ - case DW_TAG_##type##_type: \ - process_##type##_type(state, die); \ +#define PROCESS_TYPE(type) \ + case DW_TAG_##type##_type: \ + process_##type##_type(state, cache, die); \ break; =20 -static int process_type(struct state *state, Dwarf_Die *die) +static int process_type(struct state *state, struct die *parent, Dwarf_Die= *die) { + struct die *cache; int tag =3D dwarf_tag(die); =20 + /* + * If we have the DIE already cached, use it instead of walking + * through DWARF. + */ + cache =3D die_map_get(die, DIE_COMPLETE); + + if (cache->state =3D=3D DIE_COMPLETE) { + process_cached(state, cache, die); + die_map_add_die(parent, cache); + return 0; + } + switch (tag) { PROCESS_TYPE(base) default: @@ -249,6 +301,11 @@ static int process_type(struct state *state, Dwarf_Die= *die) break; } =20 + /* Update cache state and append to the parent (if any) */ + cache->tag =3D tag; + cache->state =3D DIE_COMPLETE; + die_map_add_die(parent, cache); + return 0; } =20 @@ -259,14 +316,15 @@ static void process_symbol(struct state *state, Dwarf= _Die *die, die_callback_t process_func) { debug("%s", state->sym->name); - check(process_func(state, die)); + check(process_func(state, NULL, die)); if (dump_dies) fputs("\n", stderr); } =20 -static int __process_subprogram(struct state *state, Dwarf_Die *die) +static int __process_subprogram(struct state *state, struct die *cache, + Dwarf_Die *die) { - process("subprogram"); + process(cache, "subprogram"); return 0; } =20 @@ -275,10 +333,11 @@ static void process_subprogram(struct state *state, D= warf_Die *die) process_symbol(state, die, __process_subprogram); } =20 -static int __process_variable(struct state *state, Dwarf_Die *die) +static int __process_variable(struct state *state, struct die *cache, + Dwarf_Die *die) { - process("variable "); - process_type_attr(state, die); + process(cache, "variable "); + process_type_attr(state, cache, die); return 0; } =20 @@ -287,7 +346,8 @@ static void process_variable(struct state *state, Dwarf= _Die *die) process_symbol(state, die, __process_variable); } =20 -static int process_exported_symbols(struct state *unused, Dwarf_Die *die) +static int process_exported_symbols(struct state *unused, struct die *cach= e, + Dwarf_Die *die) { int tag =3D dwarf_tag(die); =20 @@ -297,7 +357,7 @@ static int process_exported_symbols(struct state *unuse= d, Dwarf_Die *die) case DW_TAG_class_type: case DW_TAG_structure_type: return check(process_die_container( - NULL, die, process_exported_symbols, match_all)); + NULL, cache, die, process_exported_symbols, match_all)); =20 /* Possible exported symbols */ case DW_TAG_subprogram: @@ -321,6 +381,6 @@ static int process_exported_symbols(struct state *unuse= d, Dwarf_Die *die) =20 void process_cu(Dwarf_Die *cudie) { - check(process_die_container(NULL, cudie, process_exported_symbols, + check(process_die_container(NULL, NULL, cudie, process_exported_symbols, match_all)); } diff --git a/scripts/gendwarfksyms/gendwarfksyms.c b/scripts/gendwarfksyms/= gendwarfksyms.c index 1763234b6329..7552fde495ef 100644 --- a/scripts/gendwarfksyms/gendwarfksyms.c +++ b/scripts/gendwarfksyms/gendwarfksyms.c @@ -43,6 +43,10 @@ static int process_module(Dwfl_Module *mod, void **userd= ata, const char *name, debug("%s", name); dbg =3D dwfl_module_getdwarf(mod, &dwbias); =20 + /* + * Look for exported symbols in each CU, follow the DIE tree, and add + * the entries to die_map. + */ do { res =3D dwarf_get_units(dbg, cu, &cu, NULL, NULL, &cudie, NULL); if (res < 0) @@ -53,6 +57,8 @@ static int process_module(Dwfl_Module *mod, void **userda= ta, const char *name, process_cu(&cudie); } while (cu); =20 + die_map_free(); + return DWARF_CB_OK; } =20 diff --git a/scripts/gendwarfksyms/gendwarfksyms.h b/scripts/gendwarfksyms/= gendwarfksyms.h index cb9fd78a58da..601f877bc8ca 100644 --- a/scripts/gendwarfksyms/gendwarfksyms.h +++ b/scripts/gendwarfksyms/gendwarfksyms.h @@ -87,6 +87,61 @@ void symbol_read_symtab(int fd); struct symbol *symbol_get(const char *name); void symbol_free(void); =20 +/* + * die.c + */ + +enum die_state { + DIE_INCOMPLETE, + DIE_COMPLETE, + DIE_LAST =3D DIE_COMPLETE +}; + +enum die_fragment_type { + FRAGMENT_EMPTY, + FRAGMENT_STRING, + FRAGMENT_DIE +}; + +struct die_fragment { + enum die_fragment_type type; + union { + char *str; + uintptr_t addr; + } data; + struct list_head list; +}; + +#define CASE_CONST_TO_STR(name) \ + case name: \ + return #name; + +static inline const char *die_state_name(enum die_state state) +{ + switch (state) { + CASE_CONST_TO_STR(DIE_INCOMPLETE) + CASE_CONST_TO_STR(DIE_COMPLETE) + } + + error("unexpected die_state: %d", state); +} + +struct die { + enum die_state state; + char *fqn; + int tag; + uintptr_t addr; + struct list_head fragments; + struct hlist_node hash; +}; + +int __die_map_get(uintptr_t addr, enum die_state state, struct die **res); +struct die *die_map_get(Dwarf_Die *die, enum die_state state); +void die_map_add_string(struct die *pd, const char *str); +void die_map_add_linebreak(struct die *pd, int linebreak); +void die_map_add_die(struct die *pd, struct die *child); +void die_map_free(void); + /* * dwarf.c */ @@ -96,12 +151,14 @@ struct state { Dwarf_Die die; }; =20 -typedef int (*die_callback_t)(struct state *state, Dwarf_Die *die); +typedef int (*die_callback_t)(struct state *state, struct die *cache, + Dwarf_Die *die); typedef bool (*die_match_callback_t)(Dwarf_Die *die); bool match_all(Dwarf_Die *die); =20 -int process_die_container(struct state *state, Dwarf_Die *die, - die_callback_t func, die_match_callback_t match); +int process_die_container(struct state *state, struct die *cache, + Dwarf_Die *die, die_callback_t func, + die_match_callback_t match); =20 void process_cu(Dwarf_Die *cudie); =20 --=20 2.47.1.613.gc27f4b7a9f-goog From nobody Mon Feb 9 13:01:05 2026 Received: from mail-pg1-f201.google.com (mail-pg1-f201.google.com [209.85.215.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 963D91DC985 for ; Thu, 19 Dec 2024 21:07:59 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.215.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734642481; cv=none; b=n54TXaZWKyxtpuZMu7mtrwPkY/HP7xz1GR7Y/vlP/VKsZtjJBg3hgD2xk/8yaXkhbY2NTsjqdknaHsQlHa+yS9WaWxh75Dy+0iyd13j4b+pttqcS+q5zMfj4X0e0zss7XLS0yOijpArp4f8B3cuOf/ylzMs9FPOI+nlUiCl4JJI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734642481; c=relaxed/simple; bh=buSElSaAFhyQbPke8FFMFfz7pZ/egR8VAABZIjgNK0o=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=qQfXqRZWi6vCRb0+CzTdAtjiGSlZoBcIInbi2As8iJkY/WDDZ52VyrpvvozQ54gTYRVn6cDvKqTP8dR69GbXkD55/DGTvAP3cKbo8FpP6b2/+8XcOnsCOhO1aPmtgEo1NRJIbaoXM2iX/KktuSNavEoz0swghwp6W/wm+TMRWDA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--samitolvanen.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=EEkcF17I; arc=none smtp.client-ip=209.85.215.201 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--samitolvanen.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="EEkcF17I" Received: by mail-pg1-f201.google.com with SMTP id 41be03b00d2f7-7fcca85ffdaso677296a12.3 for ; Thu, 19 Dec 2024 13:07:59 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1734642479; x=1735247279; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=KlBM+UoVMiu/aVYEb5JmNGVezBYswW2Sh9t+S0cH6qM=; b=EEkcF17IC1aOeabAs4L3QThYNjHT8dxXfzDU16fcAD5l7XHtE+twva2K0VKnRK1I8J sy/gdYn4LogWIDrqueVbprDktv9XROA+RaALEaj1iZCUdzKmhIAUOueE35dtHixjSDnt +SI8xSMveoqWG/eMWkzDrw7YL5Q+9rGekftKymo3nlRqnNLUAgdckPWqDtBxyOsDf2qo KXReUnNTbN34Bz93NuG9HGPP3ToVedKgqSO5RYxXlp2I7SmsEsnv0L5/kqPOuXdJg7Xu NLAamjCSYnacn7QpLs7DGdlkxbLzEHCHJ/4UVCSpL0QOveZ0PIpac+m5g0AGpEKxPiJJ ekTw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1734642479; x=1735247279; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=KlBM+UoVMiu/aVYEb5JmNGVezBYswW2Sh9t+S0cH6qM=; b=xRCkm5RMiOGbuZE/Jz+Cs+5w+9+KcSD+ZA9WMZVOVW8pLmyG2etSdZ0aK95EKnB3Ge 3JcoD8YTr4Ni16vQrygWLjjF1Nn3YqlhFxgVvPZgPnWL72zVOBizJCkfGUwD0QZnOSGk OweLX0epUuQ0wWSu9ieW8t8y95hR8uXSBctE1UiEVm1Vr0FoqCSkzgwotu7mEO+lzuZp SNn/PhYr3nijbruBfr14dhRHsUrtaGB51kskHKlFGtoiVZu8yp6+bAfii5ZjP6W1BU3N Bm6i6XDVzRxGzSCfUqFS7ClWJzBNFRwCMZt9ln/L9E7jCMwH7EgNFksKCXDYPBSqDjDj iWsQ== X-Forwarded-Encrypted: i=1; AJvYcCWZUZ+ZYN+TpUhRDzePw+ufFPTin9EmSXQKYU0h2GBDhjn8KJTR6uDMyzMgxRAlLRESpXmfNul2MV0CniU=@vger.kernel.org X-Gm-Message-State: AOJu0YwitvLbKnEHBQjMuPVea58KsUWq3RR7LbOzuLHGDHuoecIdNOpo CezxQPs/ugyHuE0zrA2UADs5PaAkYKjgwGNFTHPbOvklhlGhnyoT9dfCVP69phAVbHMgNPpgoER vY4OoIjOXu0MRQPIUQ8+M7JKl/g== X-Google-Smtp-Source: AGHT+IFSfZWkVsUgeZM2+bv/bDQNUAw6E73pPO8hwFTzmQfKGqBteuj8Emcx7y5sX8zEMa48boCkXnaWJG2J+Q06KzE= X-Received: from pjbqd7.prod.google.com ([2002:a17:90b:3cc7:b0:2e5:5ffc:1c36]) (user=samitolvanen job=prod-delivery.src-stubby-dispatcher) by 2002:a17:90a:c2c7:b0:2ef:19d0:2261 with SMTP id 98e67ed59e1d1-2f452e1c111mr791881a91.16.1734642479012; Thu, 19 Dec 2024 13:07:59 -0800 (PST) Date: Thu, 19 Dec 2024 21:07:42 +0000 In-Reply-To: <20241219210736.2990838-20-samitolvanen@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20241219210736.2990838-20-samitolvanen@google.com> X-Developer-Key: i=samitolvanen@google.com; a=openpgp; fpr=35CCFB63B283D6D3AEB783944CB5F6848BBC56EE X-Developer-Signature: v=1; a=openpgp-sha256; l=5425; i=samitolvanen@google.com; h=from:subject; bh=buSElSaAFhyQbPke8FFMFfz7pZ/egR8VAABZIjgNK0o=; b=owGbwMvMwCEWxa662nLh8irG02pJDOkp3dJ8nn9PBZ0rjTx1O9HBga1z5zED9WbDKO7DEimzN XdKxyzrKGVhEONgkBVTZGn5unrr7u9Oqa8+F0nAzGFlAhnCwMUpABNZrcfIcNh6W1ew/JGnZqsy 0tNPP2Qq5Nz5JvLeYhtXpoRzJ6c+XcTwT9f8F7PCtkrlV092JF9/E5N091jD5TRtDY5d65v6ikS aeQA= X-Mailer: git-send-email 2.47.1.613.gc27f4b7a9f-goog Message-ID: <20241219210736.2990838-25-samitolvanen@google.com> Subject: [PATCH v7 05/18] gendwarfksyms: Expand type modifiers and typedefs From: Sami Tolvanen To: Masahiro Yamada , Luis Chamberlain , Miguel Ojeda , Greg Kroah-Hartman Cc: Matthew Maurer , Alex Gaynor , Gary Guo , Petr Pavlu , Daniel Gomez , Neal Gompa , Hector Martin , Janne Grunau , Miroslav Benes , Asahi Linux , Sedat Dilek , linux-kbuild@vger.kernel.org, linux-kernel@vger.kernel.org, linux-modules@vger.kernel.org, rust-for-linux@vger.kernel.org, Sami Tolvanen Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add support for expanding DWARF type modifiers, such as pointers, const values etc., and typedefs. These types all have DW_AT_type attribute pointing to the underlying type, and thus produce similar output. Also add linebreaks and indentation to debugging output to make it more readable. Signed-off-by: Sami Tolvanen Reviewed-by: Petr Pavlu --- scripts/gendwarfksyms/die.c | 12 +++++ scripts/gendwarfksyms/dwarf.c | 67 +++++++++++++++++++++++++++ scripts/gendwarfksyms/gendwarfksyms.h | 5 ++ 3 files changed, 84 insertions(+) diff --git a/scripts/gendwarfksyms/die.c b/scripts/gendwarfksyms/die.c index b7d900c6a9c8..0d70e02d02b5 100644 --- a/scripts/gendwarfksyms/die.c +++ b/scripts/gendwarfksyms/die.c @@ -130,6 +130,18 @@ void die_map_add_string(struct die *cd, const char *st= r) df->type =3D FRAGMENT_STRING; } =20 +void die_map_add_linebreak(struct die *cd, int linebreak) +{ + struct die_fragment *df; + + if (!cd) + return; + + df =3D append_item(cd); + df->data.linebreak =3D linebreak; + df->type =3D FRAGMENT_LINEBREAK; +} + void die_map_add_die(struct die *cd, struct die *child) { struct die_fragment *df; diff --git a/scripts/gendwarfksyms/dwarf.c b/scripts/gendwarfksyms/dwarf.c index f40e23a547da..3e08a32b7b16 100644 --- a/scripts/gendwarfksyms/dwarf.c +++ b/scripts/gendwarfksyms/dwarf.c @@ -7,6 +7,17 @@ #include #include "gendwarfksyms.h" =20 +static bool do_linebreak; +static int indentation_level; + +/* Line breaks and indentation for pretty-printing */ +static void process_linebreak(struct die *cache, int n) +{ + indentation_level +=3D n; + do_linebreak =3D true; + die_map_add_linebreak(cache, n); +} + #define DEFINE_GET_ATTR(attr, type) \ static bool get_##attr##_attr(Dwarf_Die *die, unsigned int id, \ type *value) \ @@ -76,6 +87,12 @@ static void process(struct die *cache, const char *s) { s =3D s ?: ""; =20 + if (dump_dies && do_linebreak) { + fputs("\n", stderr); + for (int i =3D 0; i < indentation_level; i++) + fputs(" ", stderr); + do_linebreak =3D false; + } if (dump_dies) fputs(s, stderr); =20 @@ -239,6 +256,40 @@ static void process_type_attr(struct state *state, str= uct die *cache, process(cache, "base_type void"); } =20 +/* Container types with DW_AT_type */ +static void __process_type(struct state *state, struct die *cache, + Dwarf_Die *die, const char *type) +{ + process(cache, type); + process_fqn(cache, die); + process(cache, " {"); + process_linebreak(cache, 1); + process_type_attr(state, cache, die); + process_linebreak(cache, -1); + process(cache, "}"); + process_byte_size_attr(cache, die); + process_alignment_attr(cache, die); +} + +#define DEFINE_PROCESS_TYPE(type) = \ + static void process_##type##_type(struct state *state, \ + struct die *cache, Dwarf_Die *die) \ + { \ + __process_type(state, cache, die, #type "_type"); \ + } + +DEFINE_PROCESS_TYPE(atomic) +DEFINE_PROCESS_TYPE(const) +DEFINE_PROCESS_TYPE(immutable) +DEFINE_PROCESS_TYPE(packed) +DEFINE_PROCESS_TYPE(pointer) +DEFINE_PROCESS_TYPE(reference) +DEFINE_PROCESS_TYPE(restrict) +DEFINE_PROCESS_TYPE(rvalue_reference) +DEFINE_PROCESS_TYPE(shared) +DEFINE_PROCESS_TYPE(volatile) +DEFINE_PROCESS_TYPE(typedef) + static void process_base_type(struct state *state, struct die *cache, Dwarf_Die *die) { @@ -260,6 +311,9 @@ static void process_cached(struct state *state, struct = die *cache, case FRAGMENT_STRING: process(NULL, df->data.str); break; + case FRAGMENT_LINEBREAK: + process_linebreak(NULL, df->data.linebreak); + break; case FRAGMENT_DIE: if (!dwarf_die_addr_die(dwarf_cu_getdwarf(die->cu), (void *)df->data.addr, &child)) @@ -295,7 +349,20 @@ static int process_type(struct state *state, struct di= e *parent, Dwarf_Die *die) } =20 switch (tag) { + /* Type modifiers */ + PROCESS_TYPE(atomic) + PROCESS_TYPE(const) + PROCESS_TYPE(immutable) + PROCESS_TYPE(packed) + PROCESS_TYPE(pointer) + PROCESS_TYPE(reference) + PROCESS_TYPE(restrict) + PROCESS_TYPE(rvalue_reference) + PROCESS_TYPE(shared) + PROCESS_TYPE(volatile) + /* Other types */ PROCESS_TYPE(base) + PROCESS_TYPE(typedef) default: debug("unimplemented type: %x", tag); break; diff --git a/scripts/gendwarfksyms/gendwarfksyms.h b/scripts/gendwarfksyms/= gendwarfksyms.h index 601f877bc8ca..832d05b4fc1c 100644 --- a/scripts/gendwarfksyms/gendwarfksyms.h +++ b/scripts/gendwarfksyms/gendwarfksyms.h @@ -59,6 +59,9 @@ extern int dump_dies; /* Error =3D=3D negative values */ #define checkp(expr) __check(expr, __res < 0) =20 +/* Consistent aliases (DW_TAG__type) for DWARF tags */ +#define DW_TAG_typedef_type DW_TAG_typedef + /* * symbols.c */ @@ -100,6 +103,7 @@ enum die_state { enum die_fragment_type { FRAGMENT_EMPTY, FRAGMENT_STRING, + FRAGMENT_LINEBREAK, FRAGMENT_DIE }; =20 @@ -107,6 +111,7 @@ struct die_fragment { enum die_fragment_type type; union { char *str; + int linebreak; uintptr_t addr; } data; struct list_head list; --=20 2.47.1.613.gc27f4b7a9f-goog From nobody Mon Feb 9 13:01:05 2026 Received: from mail-pg1-f202.google.com (mail-pg1-f202.google.com [209.85.215.202]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 22BE01E9B39 for ; Thu, 19 Dec 2024 21:08:01 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.215.202 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734642482; cv=none; b=CcU51fltu0M0WNetEHUwm2B+r+varZqcUshPpoBBYk8OD5oagrf+4S6D1/xUCwoK30ibi/MRWPDnYt/noKYSXv6Lw4BDOW4z8IxT8JeeWe8eZkcgkcAppVxsu3rrSUGhTz3K8ifbW5oS9omGQS3JrmFVq3+m/nGPu7eXpggcrcE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734642482; c=relaxed/simple; bh=yrWG/DLfaIaAG3roJ/5utp+xwkOJf1qHLLIwHK3efLM=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=NUvPTFP2V96ndAlxNWu1YBuKgKEWVnGJcUTI9u6TGll321A1Lye+imlOl6i3YL26X1mJLwFBqq9L6VE+6ypluDlkB8LmRRKB8QIcaQUBjgXDbQvRxM2xXujm9JxdHarKgPkV8IXLeOEBJpC61uSt6l3AIq08Te76HeXV84V/Mak= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--samitolvanen.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=wjFr1nVt; arc=none smtp.client-ip=209.85.215.202 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--samitolvanen.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="wjFr1nVt" Received: by mail-pg1-f202.google.com with SMTP id 41be03b00d2f7-7eb0a32fc5aso760984a12.2 for ; Thu, 19 Dec 2024 13:08:01 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1734642480; x=1735247280; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=FPHPHvsctuc5VzYf3oHMp0UrUbKfYCtMAQllWUKFUVU=; b=wjFr1nVtncfs4uZM0MGJ5JLqv3O+VmtTwRpr61vkTN3I1NuKsj/J9+oqmuWdP6P9k5 EKB4/R9nKiCbfAg9sm/o4VgdcVWtImAO+GL10wIFiKrUGYYW6PNrNnU7vY4Yot2wColD XK5Iz0UD3kvnKvdCOnBgVrLQseFcmKysWhTCwFvwC7XP5x/mKqAeG1aa2tQDPJGio0TJ oJBzj4Ar8mB16w/G4TYNxEl3nZYH9EZxIUTI+GNK04RtB9y80ZBsJKEslzhPColQ9et5 BuVukhWHCBJa57Sa3ky6hRe9j7ElxV3XOU71yu4n6Brjy8eAylnzu+SPfzRfBqTGRpl8 wRBg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1734642480; x=1735247280; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=FPHPHvsctuc5VzYf3oHMp0UrUbKfYCtMAQllWUKFUVU=; b=Gb6xq20LgVyE2z6PLYij0QyWhI2UL6xnJ5M8CpUOrY9SgJCrVOeOcOjterJgIFIgEN AJSGqKINknntxgJ7B1QICLhqFgEt8vXShv85Vm8+veC8bmKLHSCDIKK/5tFgrT6QgoN3 LDhjtjt8aa+OGmxMzbM/3QkgA4uQC4k5zS88XGjPsFjsAen+4fi5l0Osd7HmN7cXs8yQ zTCOBB0zeJFFCm8HkrIatmE/Aq8TCA3mObo2Zj/w/MUiV52Lgw9hkW0V7Yn8JKwu62wb /yWIClV4SKCX5d9iqCKHFDPRvEWRR9xuMyDo9WJ/JSp1szESxTF/bQ57WduIZd8QfAmO rq7A== X-Forwarded-Encrypted: i=1; AJvYcCUJc5B7615N48yvOSZAXbATPAibiqj3H8t1n2mM49+V1qN0NbrE9GQxYWitrSpLZ+y+l3TRWYGJ7MrWCnA=@vger.kernel.org X-Gm-Message-State: AOJu0YyKyAmuU1TH/wYZc3rbvvAFEgzoiZW5nqHlCcUnmrY+A8MFhU9F Yv49l9Qll8j9x0bcuRRKLcOu9EHNbgqfTbeD+3hbc3x1aEjDT6V78Ff5NQKole6LSuV+kQzf3Fp b49wblyBEhxqI9dbmBGvY4wez7Q== X-Google-Smtp-Source: AGHT+IFYCaPz9QbyJkzupiDNzS+0gKY6yj2ENaZGGGMbhbVCqclKJfeKJrrvON74WvgtKdmMMO0b1eaIO/DnhNkwtDY= X-Received: from pjbtb3.prod.google.com ([2002:a17:90b:53c3:b0:2ef:6fb0:55fb]) (user=samitolvanen job=prod-delivery.src-stubby-dispatcher) by 2002:a17:90b:2d4c:b0:2ee:c2b5:97a0 with SMTP id 98e67ed59e1d1-2f452ec290emr651742a91.25.1734642480608; Thu, 19 Dec 2024 13:08:00 -0800 (PST) Date: Thu, 19 Dec 2024 21:07:43 +0000 In-Reply-To: <20241219210736.2990838-20-samitolvanen@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20241219210736.2990838-20-samitolvanen@google.com> X-Developer-Key: i=samitolvanen@google.com; a=openpgp; fpr=35CCFB63B283D6D3AEB783944CB5F6848BBC56EE X-Developer-Signature: v=1; a=openpgp-sha256; l=5759; i=samitolvanen@google.com; h=from:subject; bh=yrWG/DLfaIaAG3roJ/5utp+xwkOJf1qHLLIwHK3efLM=; b=owGbwMvMwCEWxa662nLh8irG02pJDOkp3dLXypfvOnnVWfZ8SmhR2tXsyecXqs/a8KIlPa6Te fLxoJJjHaUsDGIcDLJiiiwtX1dv3f3dKfXV5yIJmDmsTCBDGLg4BWAii1gZ/qeKrjj4y/+h1T/r izPN7FYsCTq0P/Zv5Z6O0zv39rDO0N3K8If/29Wt2wv8eD35gm41/rzzUdH3eN3irK5Ed96wPXF GykwA X-Mailer: git-send-email 2.47.1.613.gc27f4b7a9f-goog Message-ID: <20241219210736.2990838-26-samitolvanen@google.com> Subject: [PATCH v7 06/18] gendwarfksyms: Expand subroutine_type From: Sami Tolvanen To: Masahiro Yamada , Luis Chamberlain , Miguel Ojeda , Greg Kroah-Hartman Cc: Matthew Maurer , Alex Gaynor , Gary Guo , Petr Pavlu , Daniel Gomez , Neal Gompa , Hector Martin , Janne Grunau , Miroslav Benes , Asahi Linux , Sedat Dilek , linux-kbuild@vger.kernel.org, linux-kernel@vger.kernel.org, linux-modules@vger.kernel.org, rust-for-linux@vger.kernel.org, Sami Tolvanen Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add support for expanding DW_TAG_subroutine_type and the parameters in DW_TAG_formal_parameter. Use this to also expand subprograms. Example output with --dump-dies: subprogram ( formal_parameter pointer_type { const_type { base_type char byte_size(1) encoding(6) } } ) -> base_type unsigned long byte_size(8) encoding(7) Signed-off-by: Sami Tolvanen Reviewed-by: Petr Pavlu --- scripts/gendwarfksyms/dwarf.c | 84 ++++++++++++++++++++++++++- scripts/gendwarfksyms/gendwarfksyms.h | 4 ++ 2 files changed, 85 insertions(+), 3 deletions(-) diff --git a/scripts/gendwarfksyms/dwarf.c b/scripts/gendwarfksyms/dwarf.c index 3e08a32b7b16..7d8a4eb6c387 100644 --- a/scripts/gendwarfksyms/dwarf.c +++ b/scripts/gendwarfksyms/dwarf.c @@ -212,6 +212,15 @@ DEFINE_PROCESS_UDATA_ATTRIBUTE(alignment) DEFINE_PROCESS_UDATA_ATTRIBUTE(byte_size) DEFINE_PROCESS_UDATA_ATTRIBUTE(encoding) =20 +/* Match functions -- die_match_callback_t */ +#define DEFINE_MATCH(type) \ + static bool match_##type##_type(Dwarf_Die *die) \ + { \ + return dwarf_tag(die) =3D=3D DW_TAG_##type##_type; \ + } + +DEFINE_MATCH(formal_parameter) + bool match_all(Dwarf_Die *die) { return true; @@ -224,19 +233,28 @@ int process_die_container(struct state *state, struct= die *cache, Dwarf_Die current; int res; =20 + /* Track the first item in lists. */ + if (state) + state->first_list_item =3D true; + res =3D checkp(dwarf_child(die, ¤t)); while (!res) { if (match(¤t)) { /* <0 =3D error, 0 =3D continue, >0 =3D stop */ res =3D checkp(func(state, cache, ¤t)); if (res) - return res; + goto out; } =20 res =3D checkp(dwarf_siblingof(¤t, ¤t)); } =20 - return 0; + res =3D 0; +out: + if (state) + state->first_list_item =3D false; + + return res; } =20 static int process_type(struct state *state, struct die *parent, @@ -256,6 +274,40 @@ static void process_type_attr(struct state *state, str= uct die *cache, process(cache, "base_type void"); } =20 +static void process_list_comma(struct state *state, struct die *cache) +{ + if (state->first_list_item) { + state->first_list_item =3D false; + } else { + process(cache, " ,"); + process_linebreak(cache, 0); + } +} + +/* Comma-separated with DW_AT_type */ +static void __process_list_type(struct state *state, struct die *cache, + Dwarf_Die *die, const char *type) +{ + const char *name =3D get_name_attr(die); + + process_list_comma(state, cache); + process(cache, type); + process_type_attr(state, cache, die); + if (name) { + process(cache, " "); + process(cache, name); + } +} + +#define DEFINE_PROCESS_LIST_TYPE(type) = \ + static void process_##type##_type(struct state *state, \ + struct die *cache, Dwarf_Die *die) \ + { \ + __process_list_type(state, cache, die, #type " "); \ + } + +DEFINE_PROCESS_LIST_TYPE(formal_parameter) + /* Container types with DW_AT_type */ static void __process_type(struct state *state, struct die *cache, Dwarf_Die *die, const char *type) @@ -290,6 +342,29 @@ DEFINE_PROCESS_TYPE(shared) DEFINE_PROCESS_TYPE(volatile) DEFINE_PROCESS_TYPE(typedef) =20 +static void __process_subroutine_type(struct state *state, struct die *cac= he, + Dwarf_Die *die, const char *type) +{ + process(cache, type); + process(cache, " ("); + process_linebreak(cache, 1); + /* Parameters */ + check(process_die_container(state, cache, die, process_type, + match_formal_parameter_type)); + process_linebreak(cache, -1); + process(cache, ")"); + process_linebreak(cache, 0); + /* Return type */ + process(cache, "-> "); + process_type_attr(state, cache, die); +} + +static void process_subroutine_type(struct state *state, struct die *cache, + Dwarf_Die *die) +{ + __process_subroutine_type(state, cache, die, "subroutine_type"); +} + static void process_base_type(struct state *state, struct die *cache, Dwarf_Die *die) { @@ -360,8 +435,11 @@ static int process_type(struct state *state, struct di= e *parent, Dwarf_Die *die) PROCESS_TYPE(rvalue_reference) PROCESS_TYPE(shared) PROCESS_TYPE(volatile) + /* Subtypes */ + PROCESS_TYPE(formal_parameter) /* Other types */ PROCESS_TYPE(base) + PROCESS_TYPE(subroutine) PROCESS_TYPE(typedef) default: debug("unimplemented type: %x", tag); @@ -391,7 +469,7 @@ static void process_symbol(struct state *state, Dwarf_D= ie *die, static int __process_subprogram(struct state *state, struct die *cache, Dwarf_Die *die) { - process(cache, "subprogram"); + __process_subroutine_type(state, cache, die, "subprogram"); return 0; } =20 diff --git a/scripts/gendwarfksyms/gendwarfksyms.h b/scripts/gendwarfksyms/= gendwarfksyms.h index 832d05b4fc1c..0746a36f4924 100644 --- a/scripts/gendwarfksyms/gendwarfksyms.h +++ b/scripts/gendwarfksyms/gendwarfksyms.h @@ -60,6 +60,7 @@ extern int dump_dies; #define checkp(expr) __check(expr, __res < 0) =20 /* Consistent aliases (DW_TAG__type) for DWARF tags */ +#define DW_TAG_formal_parameter_type DW_TAG_formal_parameter #define DW_TAG_typedef_type DW_TAG_typedef =20 /* @@ -154,6 +155,9 @@ void die_map_free(void); struct state { struct symbol *sym; Dwarf_Die die; + + /* List expansion */ + bool first_list_item; }; =20 typedef int (*die_callback_t)(struct state *state, struct die *cache, --=20 2.47.1.613.gc27f4b7a9f-goog From nobody Mon Feb 9 13:01:05 2026 Received: from mail-pl1-f201.google.com (mail-pl1-f201.google.com [209.85.214.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 143B21F192A for ; Thu, 19 Dec 2024 21:08:02 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734642484; cv=none; b=qZNvn/iMmpPd+nnRBr5cltLXk5o35CB/JK2ClQSPGGgwpBbo3kYfxTjKx+DpL78361tuz6fsYlJsf+zOQIObJjR01R4uEdI8VJKuMEJx4wXq9g31UAnRrPNwD4ZbfXKsDTcKqgzpGuY9ozLfb5np7HbYKaaNO4NnMT23ea9b/JM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734642484; c=relaxed/simple; bh=V88Ux5YpLtipLnwT7oAorrJvHrfCrHoGnWDZa7njhBA=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=aGtxJ5HM8xAB+JXXJ3V9ZA6Tr3If9kRK4Kr0Jjt0NiU+sq2CEA0DR/Q6bVeFs/JAC/g4ZRqJN75H7j0XliLcMnjtHIOVJ/hlugprnXAaGswwkk+HYAy438aIRGNoL0y1kpfl1xhLk/SJcFQ5V5CHUVnOnDPttgeiznbOzzoSRjw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--samitolvanen.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=SNRaDN42; arc=none smtp.client-ip=209.85.214.201 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--samitolvanen.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="SNRaDN42" Received: by mail-pl1-f201.google.com with SMTP id d9443c01a7336-2167141e00eso11249905ad.2 for ; Thu, 19 Dec 2024 13:08:02 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1734642482; x=1735247282; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=12wMWYmdUy+3imKc/VOk9UykTDeV6/VQokbuwTAWfVw=; b=SNRaDN42AjnZ0RJlXamPKfrgzp83iOyx5fdEAaKCevNY15riTlG7Oyr2go5bWuqjp0 oqUPxO/q3cZKnZeoxb69PpRq5bM6NCwHsOCZSryMz/PvloTrvygM7Vr9HZRZK7y4Xwf4 +W0AE7Kv2oRdtg6Y856vR3DVYMgcy7oTJqsX2elPpEniK7SebNAeQpyb9B3ARzN4nATC 75kBc4mtjH6xnEy6rp2YjVw1bTxRJPvld17uN3miGA6ddlU0rA+Q8MzC7EMlgdf/8IZL bHFfC6MzwPa9cDFY+xgxnd4s9gE/6GY8rxSFJiuiqpe5wJwQB1wYEcbN6gpAH3JWgsU3 omjg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1734642482; x=1735247282; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=12wMWYmdUy+3imKc/VOk9UykTDeV6/VQokbuwTAWfVw=; b=bavP4VtiO9rMa/krVk775PtRiwnXb7tYxaz1uMT+34dCPFCPcNMwh0TgpmxTVfhEXj uhnl37Ongildag/4SH0Hft7xX8wL7++zyTgc53xe0CK4LAnsRIc1SdxHhheNhqKt504b rao1gCrFDqOKGZ0oeZR/JUBsSQBVmXvesD+qumSFpXZVWnG7aUPyPZxzvuLgEz+wNUYr 0/dWd2lm4pEGUQQzMZ35U1MXhFWsbrhtebGgYu89bEExy5DtbcYlbV4yHxXcLDdzm5ae Z/dP4ZgF0I9N+8Dt4PI04epnsvdOn2Od5T3iDA5BX73+oLDNEA90wOXIghggusJFVW1G k9Pw== X-Forwarded-Encrypted: i=1; AJvYcCUUEINqsLrtZHxE473vAg4aLn3xzgz8q8lzEENuA4L+nDeRl7pngv9iD5P/jGIxZNbFptkrRX6oWkeC/zM=@vger.kernel.org X-Gm-Message-State: AOJu0YzVnNSXybz/2t8LhRGCzn9Uh1JEcPYj8ll4VPUcCZXWYywZxP/w FNpiWRmS5QzP/BD2IDMX2uDV89YsB4kXDnqBZV3m1XElAiEsje39LYCheHSjBvuB2aw45+/az+w K+5DjSFuiofAXxyKCD/s8t95i+A== X-Google-Smtp-Source: AGHT+IHZrAcneZVhNsCIJl4OSOoxoaOpAg9w4VYA1++o7u1kqFXGpYUShSf1O/vsRV3hJwyf6gqPsZGiC0raVqrtViE= X-Received: from plbkw5.prod.google.com ([2002:a17:902:f905:b0:212:71c4:23f6]) (user=samitolvanen job=prod-delivery.src-stubby-dispatcher) by 2002:a17:902:f610:b0:216:3436:b85a with SMTP id d9443c01a7336-219e6f4319fmr2835485ad.52.1734642482229; Thu, 19 Dec 2024 13:08:02 -0800 (PST) Date: Thu, 19 Dec 2024 21:07:44 +0000 In-Reply-To: <20241219210736.2990838-20-samitolvanen@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20241219210736.2990838-20-samitolvanen@google.com> X-Developer-Key: i=samitolvanen@google.com; a=openpgp; fpr=35CCFB63B283D6D3AEB783944CB5F6848BBC56EE X-Developer-Signature: v=1; a=openpgp-sha256; l=2300; i=samitolvanen@google.com; h=from:subject; bh=V88Ux5YpLtipLnwT7oAorrJvHrfCrHoGnWDZa7njhBA=; b=owGbwMvMwCEWxa662nLh8irG02pJDOkp3TLvp/H9tv5kvenc6S9TLjAISJ2d27a1NzJd4Onzq 8Lz2vjmd5SyMIhxMMiKKbK0fF29dfd3p9RXn4skYOawMoEMYeDiFICJLL3D8E8/w7dtVYumj1ed wCWlAtVXLxNT3+XL1y6a8osnLTDOMpThfx4HT57ele1uqz8KPelavWCaCu9ul6uPlhRPljufk1l owQIA X-Mailer: git-send-email 2.47.1.613.gc27f4b7a9f-goog Message-ID: <20241219210736.2990838-27-samitolvanen@google.com> Subject: [PATCH v7 07/18] gendwarfksyms: Expand array_type From: Sami Tolvanen To: Masahiro Yamada , Luis Chamberlain , Miguel Ojeda , Greg Kroah-Hartman Cc: Matthew Maurer , Alex Gaynor , Gary Guo , Petr Pavlu , Daniel Gomez , Neal Gompa , Hector Martin , Janne Grunau , Miroslav Benes , Asahi Linux , Sedat Dilek , linux-kbuild@vger.kernel.org, linux-kernel@vger.kernel.org, linux-modules@vger.kernel.org, rust-for-linux@vger.kernel.org, Sami Tolvanen Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add support for expanding DW_TAG_array_type, and the subrange type indicating array size. Example source code: const char *s[34]; Output with --dump-dies: variable array_type[34] { pointer_type { const_type { base_type char byte_size(1) encoding(6) } } byte_size(8) } Signed-off-by: Sami Tolvanen Reviewed-by: Petr Pavlu --- scripts/gendwarfksyms/dwarf.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/scripts/gendwarfksyms/dwarf.c b/scripts/gendwarfksyms/dwarf.c index 7d8a4eb6c387..46ce17b2459b 100644 --- a/scripts/gendwarfksyms/dwarf.c +++ b/scripts/gendwarfksyms/dwarf.c @@ -220,6 +220,7 @@ DEFINE_PROCESS_UDATA_ATTRIBUTE(encoding) } =20 DEFINE_MATCH(formal_parameter) +DEFINE_MATCH(subrange) =20 bool match_all(Dwarf_Die *die) { @@ -342,6 +343,33 @@ DEFINE_PROCESS_TYPE(shared) DEFINE_PROCESS_TYPE(volatile) DEFINE_PROCESS_TYPE(typedef) =20 +static void process_subrange_type(struct state *state, struct die *cache, + Dwarf_Die *die) +{ + Dwarf_Word count =3D 0; + + if (get_udata_attr(die, DW_AT_count, &count)) + process_fmt(cache, "[%" PRIu64 "]", count); + else if (get_udata_attr(die, DW_AT_upper_bound, &count)) + process_fmt(cache, "[%" PRIu64 "]", count + 1); + else + process(cache, "[]"); +} + +static void process_array_type(struct state *state, struct die *cache, + Dwarf_Die *die) +{ + process(cache, "array_type"); + /* Array size */ + check(process_die_container(state, cache, die, process_type, + match_subrange_type)); + process(cache, " {"); + process_linebreak(cache, 1); + process_type_attr(state, cache, die); + process_linebreak(cache, -1); + process(cache, "}"); +} + static void __process_subroutine_type(struct state *state, struct die *cac= he, Dwarf_Die *die, const char *type) { @@ -437,7 +465,9 @@ static int process_type(struct state *state, struct die= *parent, Dwarf_Die *die) PROCESS_TYPE(volatile) /* Subtypes */ PROCESS_TYPE(formal_parameter) + PROCESS_TYPE(subrange) /* Other types */ + PROCESS_TYPE(array) PROCESS_TYPE(base) PROCESS_TYPE(subroutine) PROCESS_TYPE(typedef) --=20 2.47.1.613.gc27f4b7a9f-goog From nobody Mon Feb 9 13:01:05 2026 Received: from mail-pj1-f74.google.com (mail-pj1-f74.google.com [209.85.216.74]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 509221B6544 for ; Thu, 19 Dec 2024 21:08:04 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.216.74 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734642486; cv=none; b=N3qrEHq+85kk5OBt4MhgRwmrDNPwj5pceEvTR3uTtkCrgziBFoaMFgZt4ijJa2zmNmpvlCjgbWluvHbIigMaBAa3oH4o4JJZPEitYGiAYdT8+rAjHODh/oUlro1RysIZxH9TznIA+jft9QhD5w2HnhaRa8POeycOrDEhNDibpB8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734642486; c=relaxed/simple; bh=ewl5S2jzanve+U7ARk/uAO2NDn3AtA0CV1SBDzIA0jY=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=dQbQunqpHmj6kL/ovSwxZLzgcTV0Oxx09rxTAkOSDnRBvqG/+aJteT4C9wx9bf3YQNmWsKLfpjgzADu6RE7PNVrzx30u69V5/d7t/dJpbCO2rPLBpsH0mH4Qa6gMqUZ43FTPlGXUXcxAnuQNgnxfZ8Rejo8fTBYvcCJy2iyESFQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--samitolvanen.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=UINVSsiH; arc=none smtp.client-ip=209.85.216.74 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--samitolvanen.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="UINVSsiH" Received: by mail-pj1-f74.google.com with SMTP id 98e67ed59e1d1-2ef80d30df1so1096035a91.1 for ; Thu, 19 Dec 2024 13:08:04 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1734642483; x=1735247283; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=umEBs0sJokKjcG+vSqWh5DOC7EvkghygpqnTohIGBMM=; b=UINVSsiHgcem1XcWXWaVPtZEoStAlAGM4vIa4f9CzUiguRttwQf1Xrr5BZpW4Eo05/ zXgNMiqXmB+SsZ6sswWUEGP9RezbVYvNayU8a8DLWz0U17/pzOhmRmoNAWpbw8/paavP rrrOHbFCo96NX2Kt7qOvylleYeNI/vqiIBLV+U6pcZmXX9JDFWznUij2FEkSmnZhse4d C+Jx3rkObWr6hOYpRNT+qb5/mpMnCVfpxAXIXcxD18dvkGLe6LEiC+/czEBPc9rLkdqS HtQ2riy5/FtilusgAQuF1y3Jde1UvfGiKsGQlRMhouiKpQKi9SQ304Ltd03gyQcneBpi bfJA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1734642483; x=1735247283; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=umEBs0sJokKjcG+vSqWh5DOC7EvkghygpqnTohIGBMM=; b=YfdEDaacvsz06Jvqt/Wd8C29IyuHHheXbP93xgLvbAbm+4xI75nKGr3YsiniWBGqpE zF+ytrMvbEzxMai+xpC91z+R+7L9Y6YZ7j9L8BykCqmAdvwGl3tRFOLxlP+a2+o4Lx1n Qzf6xRccMw50UKaEkF4uD+biW3+OPXIs8JJwDy8g21+/LpUsSDuYZOHZQffL3e2K1HRu CHtRXrxNLFkJ3AgYMbxw2o+JGLveKLqL3w9gVZWUBs9fubogzke266OXS6ixi9LOF6z9 VqoN0gZZnX0jH9os+TeNq+3kDOUpov/BY9mw6ptq93qttMHaQNXlGlc5a+g5XS2zVrm+ KP7g== X-Forwarded-Encrypted: i=1; AJvYcCWUiS+20yh+uVb3WpEJCvz4Ukjy5uWdu0Ji4dHuDgfEL0FK9IJJOKCBwNWcEcgn4DXMU2CxyJcDr1tRB0M=@vger.kernel.org X-Gm-Message-State: AOJu0Yx5rjivk17dB2hBVWKiNOcM60PvMui+H7tRQD3drD4F6gwoBhAb HECMXzmu4ANbFDhu405rhjE0bbjwYgHDjEd8ORDXeGhAgBiQHtwMhhIYMbGKDAFWYb59SdB+F1b 0knGdoexYWy8EG+T4U2CYamV2eQ== X-Google-Smtp-Source: AGHT+IFZLJjZiq3z/pCvK3dJtKs7TBnrDNe2jR+10ciU1eC0JgJpI+SURfuYR5xumsXZFN/QsSEl95pXD5lBgflgI/4= X-Received: from pjbtb12.prod.google.com ([2002:a17:90b:53cc:b0:2ef:7483:e770]) (user=samitolvanen job=prod-delivery.src-stubby-dispatcher) by 2002:a17:90b:2545:b0:2ea:3f34:f18f with SMTP id 98e67ed59e1d1-2f452e49630mr701607a91.19.1734642483608; Thu, 19 Dec 2024 13:08:03 -0800 (PST) Date: Thu, 19 Dec 2024 21:07:45 +0000 In-Reply-To: <20241219210736.2990838-20-samitolvanen@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20241219210736.2990838-20-samitolvanen@google.com> X-Developer-Key: i=samitolvanen@google.com; a=openpgp; fpr=35CCFB63B283D6D3AEB783944CB5F6848BBC56EE X-Developer-Signature: v=1; a=openpgp-sha256; l=8481; i=samitolvanen@google.com; h=from:subject; bh=ewl5S2jzanve+U7ARk/uAO2NDn3AtA0CV1SBDzIA0jY=; b=owGbwMvMwCEWxa662nLh8irG02pJDOkp3TKCsSWmsz2vz8vfW3l0b8SBK3JMARHbJcVclgY9e FOXvCu7o5SFQYyDQVZMkaXl6+qtu787pb76XCQBM4eVCWQIAxenAFxkLyPDPbbky91T5cN1GnfV zFZTe72PI27Dw5V5Lrvv3L2WEjlZlJFhhkLa9K1CMlfsCrbYCR+ScmCqECubcths7e3bkb0rxRz 4AA== X-Mailer: git-send-email 2.47.1.613.gc27f4b7a9f-goog Message-ID: <20241219210736.2990838-28-samitolvanen@google.com> Subject: [PATCH v7 08/18] gendwarfksyms: Expand structure types From: Sami Tolvanen To: Masahiro Yamada , Luis Chamberlain , Miguel Ojeda , Greg Kroah-Hartman Cc: Matthew Maurer , Alex Gaynor , Gary Guo , Petr Pavlu , Daniel Gomez , Neal Gompa , Hector Martin , Janne Grunau , Miroslav Benes , Asahi Linux , Sedat Dilek , linux-kbuild@vger.kernel.org, linux-kernel@vger.kernel.org, linux-modules@vger.kernel.org, rust-for-linux@vger.kernel.org, Sami Tolvanen Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Recursively expand DWARF structure types, i.e. structs, unions, and enums. Also include relevant DWARF attributes in type strings to encode structure layout, for example. Example output with --dump-dies: subprogram ( formal_parameter structure_type &str { member pointer_type { base_type u8 byte_size(1) encoding(7) } data_ptr data_member_location(0) , member base_type usize byte_size(8) encoding(7) length data_member_lo= cation(8) } byte_size(16) alignment(8) msg ) -> base_type void Signed-off-by: Sami Tolvanen Reviewed-by: Petr Pavlu --- scripts/gendwarfksyms/dwarf.c | 138 +++++++++++++++++++++++++- scripts/gendwarfksyms/gendwarfksyms.h | 5 + 2 files changed, 141 insertions(+), 2 deletions(-) diff --git a/scripts/gendwarfksyms/dwarf.c b/scripts/gendwarfksyms/dwarf.c index 46ce17b2459b..6ec1138c459f 100644 --- a/scripts/gendwarfksyms/dwarf.c +++ b/scripts/gendwarfksyms/dwarf.c @@ -208,9 +208,14 @@ static void process_fqn(struct die *cache, Dwarf_Die *= die) value); \ } =20 +DEFINE_PROCESS_UDATA_ATTRIBUTE(accessibility) DEFINE_PROCESS_UDATA_ATTRIBUTE(alignment) +DEFINE_PROCESS_UDATA_ATTRIBUTE(bit_size) DEFINE_PROCESS_UDATA_ATTRIBUTE(byte_size) DEFINE_PROCESS_UDATA_ATTRIBUTE(encoding) +DEFINE_PROCESS_UDATA_ATTRIBUTE(data_bit_offset) +DEFINE_PROCESS_UDATA_ATTRIBUTE(data_member_location) +DEFINE_PROCESS_UDATA_ATTRIBUTE(discr_value) =20 /* Match functions -- die_match_callback_t */ #define DEFINE_MATCH(type) \ @@ -219,7 +224,9 @@ DEFINE_PROCESS_UDATA_ATTRIBUTE(encoding) return dwarf_tag(die) =3D=3D DW_TAG_##type##_type; \ } =20 +DEFINE_MATCH(enumerator) DEFINE_MATCH(formal_parameter) +DEFINE_MATCH(member) DEFINE_MATCH(subrange) =20 bool match_all(Dwarf_Die *die) @@ -298,6 +305,10 @@ static void __process_list_type(struct state *state, s= truct die *cache, process(cache, " "); process(cache, name); } + process_accessibility_attr(cache, die); + process_bit_size_attr(cache, die); + process_data_bit_offset_attr(cache, die); + process_data_member_location_attr(cache, die); } =20 #define DEFINE_PROCESS_LIST_TYPE(type) = \ @@ -308,6 +319,7 @@ static void __process_list_type(struct state *state, st= ruct die *cache, } =20 DEFINE_PROCESS_LIST_TYPE(formal_parameter) +DEFINE_PROCESS_LIST_TYPE(member) =20 /* Container types with DW_AT_type */ static void __process_type(struct state *state, struct die *cache, @@ -340,6 +352,7 @@ DEFINE_PROCESS_TYPE(reference) DEFINE_PROCESS_TYPE(restrict) DEFINE_PROCESS_TYPE(rvalue_reference) DEFINE_PROCESS_TYPE(shared) +DEFINE_PROCESS_TYPE(template_type_parameter) DEFINE_PROCESS_TYPE(volatile) DEFINE_PROCESS_TYPE(typedef) =20 @@ -393,6 +406,107 @@ static void process_subroutine_type(struct state *sta= te, struct die *cache, __process_subroutine_type(state, cache, die, "subroutine_type"); } =20 +static void process_variant_type(struct state *state, struct die *cache, + Dwarf_Die *die) +{ + process_list_comma(state, cache); + process(cache, "variant {"); + process_linebreak(cache, 1); + check(process_die_container(state, cache, die, process_type, + match_member_type)); + process_linebreak(cache, -1); + process(cache, "}"); + process_discr_value_attr(cache, die); +} + +static void process_variant_part_type(struct state *state, struct die *cac= he, + Dwarf_Die *die) +{ + process_list_comma(state, cache); + process(cache, "variant_part {"); + process_linebreak(cache, 1); + check(process_die_container(state, cache, die, process_type, + match_all)); + process_linebreak(cache, -1); + process(cache, "}"); +} + +static int ___process_structure_type(struct state *state, struct die *cach= e, + Dwarf_Die *die) +{ + switch (dwarf_tag(die)) { + case DW_TAG_member: + case DW_TAG_variant_part: + return check(process_type(state, cache, die)); + case DW_TAG_class_type: + case DW_TAG_enumeration_type: + case DW_TAG_structure_type: + case DW_TAG_template_type_parameter: + case DW_TAG_union_type: + case DW_TAG_subprogram: + /* Skip non-member types, including member functions */ + return 0; + default: + error("unexpected structure_type child: %x", dwarf_tag(die)); + } +} + +static void __process_structure_type(struct state *state, struct die *cach= e, + Dwarf_Die *die, const char *type, + die_callback_t process_func, + die_match_callback_t match_func) +{ + process(cache, type); + process_fqn(cache, die); + process(cache, " {"); + process_linebreak(cache, 1); + + check(process_die_container(state, cache, die, process_func, + match_func)); + + process_linebreak(cache, -1); + process(cache, "}"); + + process_byte_size_attr(cache, die); + process_alignment_attr(cache, die); +} + +#define DEFINE_PROCESS_STRUCTURE_TYPE(structure) \ + static void process_##structure##_type( \ + struct state *state, struct die *cache, Dwarf_Die *die) \ + { \ + __process_structure_type(state, cache, die, \ + #structure "_type", \ + ___process_structure_type, \ + match_all); \ + } + +DEFINE_PROCESS_STRUCTURE_TYPE(class) +DEFINE_PROCESS_STRUCTURE_TYPE(structure) +DEFINE_PROCESS_STRUCTURE_TYPE(union) + +static void process_enumerator_type(struct state *state, struct die *cache, + Dwarf_Die *die) +{ + Dwarf_Word value; + + process_list_comma(state, cache); + process(cache, "enumerator"); + process_fqn(cache, die); + + if (get_udata_attr(die, DW_AT_const_value, &value)) { + process(cache, " =3D "); + process_fmt(cache, "%" PRIu64, value); + } +} + +static void process_enumeration_type(struct state *state, struct die *cach= e, + Dwarf_Die *die) +{ + __process_structure_type(state, cache, die, "enumeration_type", + process_type, match_enumerator_type); +} + static void process_base_type(struct state *state, struct die *cache, Dwarf_Die *die) { @@ -403,6 +517,16 @@ static void process_base_type(struct state *state, str= uct die *cache, process_alignment_attr(cache, die); } =20 +static void process_unspecified_type(struct state *state, struct die *cach= e, + Dwarf_Die *die) +{ + /* + * These can be emitted for stand-alone assembly code, which means we + * might run into them in vmlinux.o. + */ + process(cache, "unspecified_type"); +} + static void process_cached(struct state *state, struct die *cache, Dwarf_Die *die) { @@ -463,17 +587,27 @@ static int process_type(struct state *state, struct d= ie *parent, Dwarf_Die *die) PROCESS_TYPE(rvalue_reference) PROCESS_TYPE(shared) PROCESS_TYPE(volatile) + /* Container types */ + PROCESS_TYPE(class) + PROCESS_TYPE(structure) + PROCESS_TYPE(union) + PROCESS_TYPE(enumeration) /* Subtypes */ + PROCESS_TYPE(enumerator) PROCESS_TYPE(formal_parameter) + PROCESS_TYPE(member) PROCESS_TYPE(subrange) + PROCESS_TYPE(template_type_parameter) + PROCESS_TYPE(variant) + PROCESS_TYPE(variant_part) /* Other types */ PROCESS_TYPE(array) PROCESS_TYPE(base) PROCESS_TYPE(subroutine) PROCESS_TYPE(typedef) + PROCESS_TYPE(unspecified) default: - debug("unimplemented type: %x", tag); - break; + error("unexpected type: %x", tag); } =20 /* Update cache state and append to the parent (if any) */ diff --git a/scripts/gendwarfksyms/gendwarfksyms.h b/scripts/gendwarfksyms/= gendwarfksyms.h index 0746a36f4924..1796f71b3a34 100644 --- a/scripts/gendwarfksyms/gendwarfksyms.h +++ b/scripts/gendwarfksyms/gendwarfksyms.h @@ -60,8 +60,13 @@ extern int dump_dies; #define checkp(expr) __check(expr, __res < 0) =20 /* Consistent aliases (DW_TAG__type) for DWARF tags */ +#define DW_TAG_enumerator_type DW_TAG_enumerator #define DW_TAG_formal_parameter_type DW_TAG_formal_parameter +#define DW_TAG_member_type DW_TAG_member +#define DW_TAG_template_type_parameter_type DW_TAG_template_type_parameter #define DW_TAG_typedef_type DW_TAG_typedef +#define DW_TAG_variant_part_type DW_TAG_variant_part +#define DW_TAG_variant_type DW_TAG_variant =20 /* * symbols.c --=20 2.47.1.613.gc27f4b7a9f-goog From nobody Mon Feb 9 13:01:05 2026 Received: from mail-pl1-f202.google.com (mail-pl1-f202.google.com [209.85.214.202]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 3AFA71FCCE1 for ; Thu, 19 Dec 2024 21:08:06 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.202 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734642488; cv=none; b=ea3l9CF5fg5BbdfuxgQeROO3BS2FtcAGtpExNDmOLZcMF/tsgBMxnQRFYrGUtmjxW0pv1ANjl9MJM9EXQ77b4cN8tLrt9IpZhrYFZtxuC0W7bAsG8H2gRjotfo+QeEDGbXsuhr6fMhDcxgg5OID6execfhoWYP/u+4DlxPoFoUU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734642488; c=relaxed/simple; bh=dvuUA3B6USfgxNyOUC1rE7HluY9N6X+YJCbsWpYa2eA=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=kZ3L+BzvlKxdTJNSidRjqjaZmmoQz9xQ6MS6DMyqDd3G9wBtH0eGg8WXRe+38fmHDVHT26egCi9aVzzKdwlnk942RQFxCUpYRdTkQZVBJmtO4p2ZDNmsrlVboT0eMjO0nRCVxrL5c06GQCoLCmQQwwZeimciBoZ74Fgs4MgjSMs= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--samitolvanen.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=WWyKPs7D; arc=none smtp.client-ip=209.85.214.202 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--samitolvanen.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="WWyKPs7D" Received: by mail-pl1-f202.google.com with SMTP id d9443c01a7336-216266cc0acso17902195ad.0 for ; Thu, 19 Dec 2024 13:08:06 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1734642485; x=1735247285; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=rUUeBhr/XftIxo5nShGbrucXNy5piFLfIDtOuXUslzs=; b=WWyKPs7DsU7J6ywYVQHikdGn0/Rl35K+ol9SpHaYYUlfrytVhEY9yJQqh42PBYkYvr RsNZChwDjYWZsaPlLzHpH1SKmZerAjslvXwm/nzrotn+jr7CK5faAR+qw8ufniLQkkg0 0tfEhOOe4JaRpCGODCYRpfgi2Agxbo9qesLY8JrKhsvmoi5VXC9a+xdaP3bVzfaZqTGD utpJpuXhkK1A3OPnQcWPZW6PQ8XLAY9mPH3Sn+nzfmdtvpuy+wPQBLIofsWCt5i18t7b axykmnP52X3HyvSVcdJSb+3x2QCmZNVTbCG0TOcDU/r1RMz+d1+VcgFMBk9FMnoau1x8 PmNw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1734642485; x=1735247285; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=rUUeBhr/XftIxo5nShGbrucXNy5piFLfIDtOuXUslzs=; b=GDqHkKGVLeLNA+7S4vzgvujDGfkbU36yBMhnOeCs8zDgmX0HSEpRcYW51ewCvet2Tu pboOhz4fMefy5KzgAHz5ON2HgNeWe4DY2KNm27/dfTxLHxAbEysZjKrPu6nqYEGpR3N0 ZREueNE2YHPyI6RbRhOZMa1S4+is2u2I0u1sH6cQyCHQyXkV0vS6eicCc+XQbRIVNoeu 2rTPxGdL6alPUmUUpPEtcEXgbRxybzDhgBDFVX+PSN37MeAjUo0G/b0J6iFrXD0VdoNA HzOt8JQTOB6oNvZTUu+nH1TGI15PijFNk0kMX6X6NTLVNpjpudKL2TdXg0vSpQ8W93v7 2ZFQ== X-Forwarded-Encrypted: i=1; AJvYcCV71uECuNIxIxYynqx9X/QXdqyWFTWq2qI1C8axhl0d21PfrFyPZByaN51qN3a/XYpNAZk8lGgxA3VG0WY=@vger.kernel.org X-Gm-Message-State: AOJu0YxVHHjgO93LdKYi/wM4QffpX+bIhpb6exTGWysdj03wRQa0RHUO 05jZ7SeJhHPqPhMZ4DlaNyEWIA14JQt+3puxW82Ng+bXxD49oLcVnqSA6g0ezxY8Lh8Zb0pI6g9 XXXlMjwN+1Q/BTur2DftuTGP2zw== X-Google-Smtp-Source: AGHT+IE10v7BuiQHjG3YQtc/VKxJidE1ZQf77DGZGzuzCHodyvU4Ihqpe4MxDy0iYufVOwWkvBXFnyBeLI1pN4n+9dU= X-Received: from pjd7.prod.google.com ([2002:a17:90b:54c7:b0:2ef:78ff:bc3b]) (user=samitolvanen job=prod-delivery.src-stubby-dispatcher) by 2002:a17:903:191:b0:216:6be9:fd48 with SMTP id d9443c01a7336-219da5b9c45mr60633335ad.3.1734642485300; Thu, 19 Dec 2024 13:08:05 -0800 (PST) Date: Thu, 19 Dec 2024 21:07:46 +0000 In-Reply-To: <20241219210736.2990838-20-samitolvanen@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20241219210736.2990838-20-samitolvanen@google.com> X-Developer-Key: i=samitolvanen@google.com; a=openpgp; fpr=35CCFB63B283D6D3AEB783944CB5F6848BBC56EE X-Developer-Signature: v=1; a=openpgp-sha256; l=10472; i=samitolvanen@google.com; h=from:subject; bh=dvuUA3B6USfgxNyOUC1rE7HluY9N6X+YJCbsWpYa2eA=; b=owGbwMvMwCEWxa662nLh8irG02pJDOkp3bLzNs0sEN0ftHWF6T0puYx9W+4vfj8vjLv+5d0rU XEuWUkbOkpZGMQ4GGTFFFlavq7euvu7U+qrz0USMHNYmUCGMHBxCsBEpoQw/NNpuJAw0TrwmFfH rvWsb1pLld0a63zL5zWteZTSvl/dJJPhr2ztJINvfW+k9gtt3bQ34MWNrXcD+DZFZLy11vooaFV sxgwA X-Mailer: git-send-email 2.47.1.613.gc27f4b7a9f-goog Message-ID: <20241219210736.2990838-29-samitolvanen@google.com> Subject: [PATCH v7 09/18] gendwarfksyms: Limit structure expansion From: Sami Tolvanen To: Masahiro Yamada , Luis Chamberlain , Miguel Ojeda , Greg Kroah-Hartman Cc: Matthew Maurer , Alex Gaynor , Gary Guo , Petr Pavlu , Daniel Gomez , Neal Gompa , Hector Martin , Janne Grunau , Miroslav Benes , Asahi Linux , Sedat Dilek , linux-kbuild@vger.kernel.org, linux-kernel@vger.kernel.org, linux-modules@vger.kernel.org, rust-for-linux@vger.kernel.org, Sami Tolvanen Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Expand each structure type only once per exported symbol. This is necessary to support self-referential structures, which would otherwise result in infinite recursion, and it's sufficient for catching ABI changes. Types defined in .c files are opaque to external users and thus cannot affect the ABI. Consider type definitions in .c files to be declarations to prevent opaque types from changing symbol versions. Signed-off-by: Sami Tolvanen Reviewed-by: Petr Pavlu --- scripts/gendwarfksyms/Makefile | 1 + scripts/gendwarfksyms/cache.c | 51 +++++++++++ scripts/gendwarfksyms/dwarf.c | 125 ++++++++++++++++++++++++-- scripts/gendwarfksyms/gendwarfksyms.h | 46 ++++++++++ 4 files changed, 215 insertions(+), 8 deletions(-) create mode 100644 scripts/gendwarfksyms/cache.c diff --git a/scripts/gendwarfksyms/Makefile b/scripts/gendwarfksyms/Makefile index c0d4ce50fc27..c06145d84df8 100644 --- a/scripts/gendwarfksyms/Makefile +++ b/scripts/gendwarfksyms/Makefile @@ -2,6 +2,7 @@ hostprogs-always-y +=3D gendwarfksyms =20 gendwarfksyms-objs +=3D gendwarfksyms.o +gendwarfksyms-objs +=3D cache.o gendwarfksyms-objs +=3D die.o gendwarfksyms-objs +=3D dwarf.o gendwarfksyms-objs +=3D symbols.o diff --git a/scripts/gendwarfksyms/cache.c b/scripts/gendwarfksyms/cache.c new file mode 100644 index 000000000000..c9c19b86a686 --- /dev/null +++ b/scripts/gendwarfksyms/cache.c @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2024 Google LLC + */ + +#include "gendwarfksyms.h" + +struct cache_item { + unsigned long key; + int value; + struct hlist_node hash; +}; + +void cache_set(struct cache *cache, unsigned long key, int value) +{ + struct cache_item *ci; + + ci =3D xmalloc(sizeof(struct cache_item)); + ci->key =3D key; + ci->value =3D value; + hash_add(cache->cache, &ci->hash, hash_32(key)); +} + +int cache_get(struct cache *cache, unsigned long key) +{ + struct cache_item *ci; + + hash_for_each_possible(cache->cache, ci, hash, hash_32(key)) { + if (ci->key =3D=3D key) + return ci->value; + } + + return -1; +} + +void cache_init(struct cache *cache) +{ + hash_init(cache->cache); +} + +void cache_free(struct cache *cache) +{ + struct hlist_node *tmp; + struct cache_item *ci; + + hash_for_each_safe(cache->cache, ci, tmp, hash) { + free(ci); + } + + hash_init(cache->cache); +} diff --git a/scripts/gendwarfksyms/dwarf.c b/scripts/gendwarfksyms/dwarf.c index 6ec1138c459f..6b30e45a4e82 100644 --- a/scripts/gendwarfksyms/dwarf.c +++ b/scripts/gendwarfksyms/dwarf.c @@ -27,6 +27,7 @@ static void process_linebreak(struct die *cache, int n) !dwarf_form##attr(&da, value); \ } =20 +DEFINE_GET_ATTR(flag, bool) DEFINE_GET_ATTR(udata, Dwarf_Word) =20 static bool get_ref_die_attr(Dwarf_Die *die, unsigned int id, Dwarf_Die *v= alue) @@ -80,6 +81,55 @@ static bool match_export_symbol(struct state *state, Dwa= rf_Die *die) return !!state->sym; } =20 +/* DW_AT_decl_file -> struct srcfile */ +static struct cache srcfile_cache; + +static bool is_definition_private(Dwarf_Die *die) +{ + Dwarf_Word filenum; + Dwarf_Files *files; + Dwarf_Die cudie; + const char *s; + int res; + + /* + * Definitions in .c files cannot change the public ABI, + * so consider them private. + */ + if (!get_udata_attr(die, DW_AT_decl_file, &filenum)) + return false; + + res =3D cache_get(&srcfile_cache, filenum); + if (res >=3D 0) + return !!res; + + if (!dwarf_cu_die(die->cu, &cudie, NULL, NULL, NULL, NULL, NULL, NULL)) + error("dwarf_cu_die failed: '%s'", dwarf_errmsg(-1)); + + if (dwarf_getsrcfiles(&cudie, &files, NULL)) + error("dwarf_getsrcfiles failed: '%s'", dwarf_errmsg(-1)); + + s =3D dwarf_filesrc(files, filenum, NULL, NULL); + if (!s) + error("dwarf_filesrc failed: '%s'", dwarf_errmsg(-1)); + + s =3D strrchr(s, '.'); + res =3D s && !strcmp(s, ".c"); + cache_set(&srcfile_cache, filenum, res); + + return !!res; +} + +static bool is_kabi_definition(Dwarf_Die *die) +{ + bool value; + + if (get_flag_attr(die, DW_AT_declaration, &value) && value) + return false; + + return !is_definition_private(die); +} + /* * Type string processing */ @@ -456,19 +506,27 @@ static void __process_structure_type(struct state *st= ate, struct die *cache, die_callback_t process_func, die_match_callback_t match_func) { + bool expand; + process(cache, type); process_fqn(cache, die); process(cache, " {"); process_linebreak(cache, 1); =20 - check(process_die_container(state, cache, die, process_func, - match_func)); + expand =3D state->expand.expand && is_kabi_definition(die); + + if (expand) { + check(process_die_container(state, cache, die, process_func, + match_func)); + } =20 process_linebreak(cache, -1); process(cache, "}"); =20 - process_byte_size_attr(cache, die); - process_alignment_attr(cache, die); + if (expand) { + process_byte_size_attr(cache, die); + process_alignment_attr(cache, die); + } } =20 #define DEFINE_PROCESS_STRUCTURE_TYPE(structure) \ @@ -553,6 +611,30 @@ static void process_cached(struct state *state, struct= die *cache, } } =20 +static void state_init(struct state *state) +{ + state->expand.expand =3D true; + cache_init(&state->expansion_cache); +} + +static void expansion_state_restore(struct expansion_state *state, + struct expansion_state *saved) +{ + state->expand =3D saved->expand; +} + +static void expansion_state_save(struct expansion_state *state, + struct expansion_state *saved) +{ + expansion_state_restore(saved, state); +} + +static bool is_expanded_type(int tag) +{ + return tag =3D=3D DW_TAG_class_type || tag =3D=3D DW_TAG_structure_type || + tag =3D=3D DW_TAG_union_type || tag =3D=3D DW_TAG_enumeration_type; +} + #define PROCESS_TYPE(type) \ case DW_TAG_##type##_type: \ process_##type##_type(state, cache, die); \ @@ -560,18 +642,39 @@ static void process_cached(struct state *state, struc= t die *cache, =20 static int process_type(struct state *state, struct die *parent, Dwarf_Die= *die) { + enum die_state want_state =3D DIE_COMPLETE; struct die *cache; + struct expansion_state saved; int tag =3D dwarf_tag(die); =20 + expansion_state_save(&state->expand, &saved); + /* - * If we have the DIE already cached, use it instead of walking + * Structures and enumeration types are expanded only once per + * exported symbol. This is sufficient for detecting ABI changes + * within the structure. + */ + if (is_expanded_type(tag)) { + if (cache_was_expanded(&state->expansion_cache, die->addr)) + state->expand.expand =3D false; + + if (state->expand.expand) + cache_mark_expanded(&state->expansion_cache, die->addr); + else + want_state =3D DIE_UNEXPANDED; + } + + /* + * If we have want_state already cached, use it instead of walking * through DWARF. */ - cache =3D die_map_get(die, DIE_COMPLETE); + cache =3D die_map_get(die, want_state); =20 - if (cache->state =3D=3D DIE_COMPLETE) { + if (cache->state =3D=3D want_state) { process_cached(state, cache, die); die_map_add_die(parent, cache); + + expansion_state_restore(&state->expand, &saved); return 0; } =20 @@ -612,9 +715,10 @@ static int process_type(struct state *state, struct di= e *parent, Dwarf_Die *die) =20 /* Update cache state and append to the parent (if any) */ cache->tag =3D tag; - cache->state =3D DIE_COMPLETE; + cache->state =3D want_state; die_map_add_die(parent, cache); =20 + expansion_state_restore(&state->expand, &saved); return 0; } =20 @@ -676,11 +780,14 @@ static int process_exported_symbols(struct state *unu= sed, struct die *cache, if (!match_export_symbol(&state, die)) return 0; =20 + state_init(&state); + if (tag =3D=3D DW_TAG_subprogram) process_subprogram(&state, &state.die); else process_variable(&state, &state.die); =20 + cache_free(&state.expansion_cache); return 0; } default: @@ -692,4 +799,6 @@ void process_cu(Dwarf_Die *cudie) { check(process_die_container(NULL, NULL, cudie, process_exported_symbols, match_all)); + + cache_free(&srcfile_cache); } diff --git a/scripts/gendwarfksyms/gendwarfksyms.h b/scripts/gendwarfksyms/= gendwarfksyms.h index 1796f71b3a34..941c4134da8e 100644 --- a/scripts/gendwarfksyms/gendwarfksyms.h +++ b/scripts/gendwarfksyms/gendwarfksyms.h @@ -102,6 +102,7 @@ void symbol_free(void); =20 enum die_state { DIE_INCOMPLETE, + DIE_UNEXPANDED, DIE_COMPLETE, DIE_LAST =3D DIE_COMPLETE }; @@ -131,6 +132,7 @@ static inline const char *die_state_name(enum die_state= state) { switch (state) { CASE_CONST_TO_STR(DIE_INCOMPLETE) + CASE_CONST_TO_STR(DIE_UNEXPANDED) CASE_CONST_TO_STR(DIE_COMPLETE) } =20 @@ -153,16 +155,60 @@ void die_map_add_linebreak(struct die *pd, int linebr= eak); void die_map_add_die(struct die *pd, struct die *child); void die_map_free(void); =20 +/* + * cache.c + */ + +#define CACHE_HASH_BITS 10 + +/* A cache for addresses we've already seen. */ +struct cache { + HASHTABLE_DECLARE(cache, 1 << CACHE_HASH_BITS); +}; + +void cache_set(struct cache *cache, unsigned long key, int value); +int cache_get(struct cache *cache, unsigned long key); +void cache_init(struct cache *cache); +void cache_free(struct cache *cache); + +static inline void __cache_mark_expanded(struct cache *cache, uintptr_t ad= dr) +{ + cache_set(cache, addr, 1); +} + +static inline bool __cache_was_expanded(struct cache *cache, uintptr_t add= r) +{ + return cache_get(cache, addr) =3D=3D 1; +} + +static inline void cache_mark_expanded(struct cache *cache, void *addr) +{ + __cache_mark_expanded(cache, (uintptr_t)addr); +} + +static inline bool cache_was_expanded(struct cache *cache, void *addr) +{ + return __cache_was_expanded(cache, (uintptr_t)addr); +} + /* * dwarf.c */ =20 +struct expansion_state { + bool expand; +}; + struct state { struct symbol *sym; Dwarf_Die die; =20 /* List expansion */ bool first_list_item; + + /* Structure expansion */ + struct expansion_state expand; + struct cache expansion_cache; }; =20 typedef int (*die_callback_t)(struct state *state, struct die *cache, --=20 2.47.1.613.gc27f4b7a9f-goog From nobody Mon Feb 9 13:01:05 2026 Received: from mail-pg1-f202.google.com (mail-pg1-f202.google.com [209.85.215.202]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 70F1E1AE875 for ; Thu, 19 Dec 2024 21:08:07 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.215.202 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734642489; cv=none; b=FBo19wDjio1gZ2eEd8DX4XCavzBXaKrktQYDlwpZZW68brAo6lxY5Zq4hiccAzZS+U9dsmW6io6CWBqTqGS+EyV1hGMRusUYHaDOMxXG1u8hx/QH4WNBMXsOuDVI3LkPpNvhBZW0cg0zv5HDAVa7y3aTpqlMG/MfOsw9Lfy19X8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734642489; c=relaxed/simple; bh=z4LlX2NA/VOO+u0MsQLoG0hK+o21j55ziLDvSdXsUpY=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=pi2dTj2VbSr2vxuoPa+CWqpHq90OJAoVE90yip6QAu6EC5cFnrCUK9zTZqhiPorxaWJzfPGwrOynLjeEBGuYUORJgx8wDeJptNkF2fPCggtKNRWI4G75HxZyQGgUZz8jtCbH/54kHVfnsTNrjzyG1x/U0ZcTmfNeJPNB29RnJZo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--samitolvanen.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=mzJgLb3O; arc=none smtp.client-ip=209.85.215.202 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--samitolvanen.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="mzJgLb3O" Received: by mail-pg1-f202.google.com with SMTP id 41be03b00d2f7-801d2d2d31cso851789a12.1 for ; Thu, 19 Dec 2024 13:08:07 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1734642487; x=1735247287; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=pO282fqtB5vJYiuotdsRJO4FLzqnxpwBoCSMUagkCSs=; b=mzJgLb3OHfLNrtz6I40H4KjRz5X0VoOYhOL+daWePEvEg27sPGOyytYu1Z49flzqHF 9KiFetE6fHOtiip2jxKQ47Jbkt5mbfyLyc7GyDv72tDbE+5dgYxQg4nkZ+s1p3RYv2Dq js+tdED3RRPc1kEDpCJhXiXgFXO0YJjjuWja8NTMFTVZi9BtyAODDde/qR1PpMcLtlZz Am9WwYCUUcXWzuteewvwtadkQkxcoHNQj7QHLOKOjMMtMrSeEkvM6bgq76PhYT1VWCYu TMVeQIuUR6fVl9uS3QjV1AC6SCG5CznTBt7I5ADyFta9v4fXxJBWBINPRrq2vHH1l2vQ EEPg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1734642487; x=1735247287; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=pO282fqtB5vJYiuotdsRJO4FLzqnxpwBoCSMUagkCSs=; b=uMEvToaIbfWiaM9CaXzhpsUWYqjL6Fb+zB80OpdSDUY84Svr3DShurBt/90wNlPs/B ELCTaagcCrt51Kn6iN8o4zzOE37LM/Fbe3j696jiCEjKYSsYXQnC6BM1L1JWHa2k6Io3 U9DG7VMefv8QYo38CkuuxOfvYo+TDwFZwJeIr202XMSyNBHD4UdstzkpX9KE30VNEEml BBMrsWdolU+rwivPNXU6+WMdlclPHVOpLs1KUS9QmSYUp4YeSltCvRR+ZsZwEB/Behr6 aI0dGcdH5SfX/Xlzx9e04T0ksX6TcqcDL7oosdPgaCtGQSv7nxSVo5izvVz09iSYWW0q vuMQ== X-Forwarded-Encrypted: i=1; AJvYcCVRhEg8szdFK9p6L5jYTI4eZ8zPkr6wNJthiTy0CjWZPqDFXz8ooUMa0iCBDqp7DfYBc0ozoukM9+7NDsY=@vger.kernel.org X-Gm-Message-State: AOJu0YxeWGhB1/WQqrSbLi4dlALYpnd+Hrhk3yzg73R6aPfiSSfN10QY GT0HD37XUTZvlNwyRjr/qUdtCFkOVIwbaQk8AOp+xifsC37U+OIVd8AfC5tHMY/TYEKRGX45yM2 6KgzOwyv4uuVDOlmR9muFlcRR9A== X-Google-Smtp-Source: AGHT+IEs5HlzO29/nEh+AUCTYj+CNxhpdYNxqXdg+eTPXZ86bI4o4X9oHHTHHKt1fNyuU7gXXI7nk7bL5Bf/Ric0P/Q= X-Received: from pjbsx14.prod.google.com ([2002:a17:90b:2cce:b0:2ea:6b84:3849]) (user=samitolvanen job=prod-delivery.src-stubby-dispatcher) by 2002:a17:90b:4ec6:b0:2ee:cdea:ad91 with SMTP id 98e67ed59e1d1-2f452e2e460mr797298a91.15.1734642486838; Thu, 19 Dec 2024 13:08:06 -0800 (PST) Date: Thu, 19 Dec 2024 21:07:47 +0000 In-Reply-To: <20241219210736.2990838-20-samitolvanen@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20241219210736.2990838-20-samitolvanen@google.com> X-Developer-Key: i=samitolvanen@google.com; a=openpgp; fpr=35CCFB63B283D6D3AEB783944CB5F6848BBC56EE X-Developer-Signature: v=1; a=openpgp-sha256; l=5088; i=samitolvanen@google.com; h=from:subject; bh=z4LlX2NA/VOO+u0MsQLoG0hK+o21j55ziLDvSdXsUpY=; b=owGbwMvMwCEWxa662nLh8irG02pJDOkp3bKNy/YFt59fuuLV7fbJmjo6pr9VP1ntuHRL5sr3+ PrLFZendZSyMIhxMMiKKbK0fF29dfd3p9RXn4skYOawMoEMYeDiFICJmHQw/OHcEPzi4doZk3eF Xk5SPbvI58+k7uwsg4pnu6f4rj/sH3+bkeFjc8zhhzdVvcSnZa3nPhpzmOtXNtu/ksrv1mcM61X 33WAFAA== X-Mailer: git-send-email 2.47.1.613.gc27f4b7a9f-goog Message-ID: <20241219210736.2990838-30-samitolvanen@google.com> Subject: [PATCH v7 10/18] gendwarfksyms: Add die_map debugging From: Sami Tolvanen To: Masahiro Yamada , Luis Chamberlain , Miguel Ojeda , Greg Kroah-Hartman Cc: Matthew Maurer , Alex Gaynor , Gary Guo , Petr Pavlu , Daniel Gomez , Neal Gompa , Hector Martin , Janne Grunau , Miroslav Benes , Asahi Linux , Sedat Dilek , linux-kbuild@vger.kernel.org, linux-kernel@vger.kernel.org, linux-modules@vger.kernel.org, rust-for-linux@vger.kernel.org, Sami Tolvanen Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Debugging the DWARF processing can be somewhat challenging, so add more detailed debugging output for die_map operations. Add the --dump-die-map flag, which adds color coded tags to the output for die_map changes. Signed-off-by: Sami Tolvanen Reviewed-by: Petr Pavlu --- scripts/gendwarfksyms/dwarf.c | 15 +++++++++++++++ scripts/gendwarfksyms/gendwarfksyms.c | 7 +++++++ scripts/gendwarfksyms/gendwarfksyms.h | 13 +++++++++++++ 3 files changed, 35 insertions(+) diff --git a/scripts/gendwarfksyms/dwarf.c b/scripts/gendwarfksyms/dwarf.c index 6b30e45a4e82..364ff4892d5c 100644 --- a/scripts/gendwarfksyms/dwarf.c +++ b/scripts/gendwarfksyms/dwarf.c @@ -146,6 +146,8 @@ static void process(struct die *cache, const char *s) if (dump_dies) fputs(s, stderr); =20 + if (cache) + die_debug_r("cache %p string '%s'", cache, s); die_map_add_string(cache, s); } =20 @@ -594,6 +596,8 @@ static void process_cached(struct state *state, struct = die *cache, list_for_each_entry(df, &cache->fragments, list) { switch (df->type) { case FRAGMENT_STRING: + die_debug_b("cache %p STRING '%s'", cache, + df->data.str); process(NULL, df->data.str); break; case FRAGMENT_LINEBREAK: @@ -603,6 +607,8 @@ static void process_cached(struct state *state, struct = die *cache, if (!dwarf_die_addr_die(dwarf_cu_getdwarf(die->cu), (void *)df->data.addr, &child)) error("dwarf_die_addr_die failed"); + die_debug_b("cache %p DIE addr %" PRIxPTR " tag %x", + cache, df->data.addr, dwarf_tag(&child)); check(process_type(state, NULL, &child)); break; default: @@ -671,6 +677,9 @@ static int process_type(struct state *state, struct die= *parent, Dwarf_Die *die) cache =3D die_map_get(die, want_state); =20 if (cache->state =3D=3D want_state) { + die_debug_g("cached addr %p tag %x -- %s", die->addr, tag, + die_state_name(cache->state)); + process_cached(state, cache, die); die_map_add_die(parent, cache); =20 @@ -678,6 +687,9 @@ static int process_type(struct state *state, struct die= *parent, Dwarf_Die *die) return 0; } =20 + die_debug_g("addr %p tag %x -- %s -> %s", die->addr, tag, + die_state_name(cache->state), die_state_name(want_state)); + switch (tag) { /* Type modifiers */ PROCESS_TYPE(atomic) @@ -713,6 +725,9 @@ static int process_type(struct state *state, struct die= *parent, Dwarf_Die *die) error("unexpected type: %x", tag); } =20 + die_debug_r("parent %p cache %p die addr %p tag %x", parent, cache, + die->addr, tag); + /* Update cache state and append to the parent (if any) */ cache->tag =3D tag; cache->state =3D want_state; diff --git a/scripts/gendwarfksyms/gendwarfksyms.c b/scripts/gendwarfksyms/= gendwarfksyms.c index 7552fde495ef..ed6d8c585268 100644 --- a/scripts/gendwarfksyms/gendwarfksyms.c +++ b/scripts/gendwarfksyms/gendwarfksyms.c @@ -19,6 +19,8 @@ int debug; /* Dump DIE contents */ int dump_dies; +/* Print debugging information about die_map changes */ +int dump_die_map; =20 static void usage(void) { @@ -26,6 +28,7 @@ static void usage(void) "Options:\n" " -d, --debug Print debugging information\n" " --dump-dies Dump DWARF DIE contents\n" + " --dump-die-map Print debugging information about die_map c= hanges\n" " -h, --help Print this message\n" "\n", stderr); @@ -74,6 +77,7 @@ int main(int argc, char **argv) =20 struct option opts[] =3D { { "debug", 0, NULL, 'd' }, { "dump-dies", 0, &dump_dies, 1 }, + { "dump-die-map", 0, &dump_die_map, 1 }, { "help", 0, NULL, 'h' }, { 0, 0, NULL, 0 } }; =20 @@ -93,6 +97,9 @@ int main(int argc, char **argv) } } =20 + if (dump_die_map) + dump_dies =3D 1; + if (optind >=3D argc) { usage(); error("no input files?"); diff --git a/scripts/gendwarfksyms/gendwarfksyms.h b/scripts/gendwarfksyms/= gendwarfksyms.h index 941c4134da8e..251832dac599 100644 --- a/scripts/gendwarfksyms/gendwarfksyms.h +++ b/scripts/gendwarfksyms/gendwarfksyms.h @@ -21,6 +21,7 @@ */ extern int debug; extern int dump_dies; +extern int dump_die_map; =20 /* * Output helpers @@ -43,6 +44,18 @@ extern int dump_dies; exit(1); \ } while (0) =20 +#define __die_debug(color, format, ...) \ + do { \ + if (dump_dies && dump_die_map) \ + fprintf(stderr, \ + "\033[" #color "m<" format ">\033[39m", \ + __VA_ARGS__); \ + } while (0) + +#define die_debug_r(format, ...) __die_debug(91, format, __VA_ARGS__) +#define die_debug_g(format, ...) __die_debug(92, format, __VA_ARGS__) +#define die_debug_b(format, ...) __die_debug(94, format, __VA_ARGS__) + /* * Error handling helpers */ --=20 2.47.1.613.gc27f4b7a9f-goog From nobody Mon Feb 9 13:01:05 2026 Received: from mail-pj1-f74.google.com (mail-pj1-f74.google.com [209.85.216.74]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id D92371DC9BE for ; Thu, 19 Dec 2024 21:08:08 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.216.74 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734642491; cv=none; b=T/ee6icpL4ib2gBnAmhyxfdpDUGCS9VJN7OSDIuYLzML2OKz2kQJkjBgt21RrcLWjz/WJf6+nRBi9ilUb9i38Wvk/UzDEZARLhNVNOLKG7PC/+o52zzAVSWB/nzZiNIa5AzZKZ5h/7NG11Hj9sQX2+eG32R7ofdIJTEU70BbN80= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734642491; c=relaxed/simple; bh=lv/LqT3Rp5/bfJTOpHCnS5zJtNsJpm7Pz2uB72SikQI=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=YOKnKTrooGBwhueP73WUWO/8HucOgJNAuj+K6hMEu4YGf3GGytqa13VpqO1Ck2nMKvAZuI6P7qsmMBcLIe/KtsZYb7xC1hTpyvB12V5DR6/4027oPFMyNU/++ga20PC5xxk/BPdsLFyllg0JDouQVAVdydw+o5K0GRvsTl84ivY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--samitolvanen.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=huEl5H9f; arc=none smtp.client-ip=209.85.216.74 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--samitolvanen.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="huEl5H9f" Received: by mail-pj1-f74.google.com with SMTP id 98e67ed59e1d1-2efc3292021so1582161a91.1 for ; Thu, 19 Dec 2024 13:08:08 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1734642488; x=1735247288; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=fAHZq0kfLV3UeGZUx6isEk5xVJWDBU5J/Bt8Xe87dg0=; b=huEl5H9fte4vLp77qpD7NzPNJkaImffwIOsI+9gTlitIe1ia80aTET9osKrIxh+nGG gqmCjNKxT/26qyrbuPZG+mCOWIwk+u9yHRgvGlEfR2+4HifCSyDoY4Iirvd7nNe83ZXg CjN3RS4jgIGpE2IUDLk5DYgTgN2/xdojU9vbw5ZP5J0XDFBRFXxeRqrGzCTIHdfAM5iq AYxnJhAeBT9NxbD1qm5MeJRx5U60KguNx8RkA5Gw14ufo90BNDRzLGJx8C/DK6oPpxHx 8KIcOwUQnqvNainRdYm+1yRbWyjB5OtZqNmudqfWL0BIBdUNFP1bSQtZbsJFECVdncYr WCUg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1734642488; x=1735247288; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=fAHZq0kfLV3UeGZUx6isEk5xVJWDBU5J/Bt8Xe87dg0=; b=g9hNckUSUMppmSzY5Eak7RYmlgGXbHu+Y8H6Y3bi8Psgn2ufkApO/YcypicGuZmb0Q +Ys6ToT/3maofd2atmko6ZreYxbcR+YEoRjq1MuUdaLo8YIiM3Ps8gk9jxj+mU1ZuOiX 7ZHXGMSMDUWvTzdVhIJmajAnACliI2hmgaQ4AMt1QgF8nNc7Mz7l8FxHD6g/E7QsodGG wrGSPHZfKIL4uyafKUPtWgPYn0+7N5BYH8ODE8PpwI1fYXZIlxhijx236XYN4H88SMIS bz7VE2i9yN9UFyjdirSZxeTOh4BfPF352z8e1s0ptPoTLH4KOWhRuHXox8w1+a/0XHyp K0jg== X-Forwarded-Encrypted: i=1; AJvYcCVnykMYBxw7/iiszQZR+3r8jB8FshcttedgFecotAxOY6pQ007+RACEB/s0tMZlEzMYXsU/diizG7/lOmg=@vger.kernel.org X-Gm-Message-State: AOJu0Yxwj4DDW3CSFRt15dMKxTITlfp79eElYSAvOcyFQ216hlhMpfFI wHJB4mYFaq8sD9CbtdMYjsO5EZf1j27K0ggjYh5Uo5IYOpzmLMKFxs5TPQTjDejO3fCtV1YHt14 aerwroFZR+MPbpUxEctN7/G3JMw== X-Google-Smtp-Source: AGHT+IEj/+XppaPIq5moHy1ZMSwAeqI9ueHhzP1Zk7JQo4M+YW0jvkoi2EmRIB/EaTyexeUM6csG1ZFdJvq8qWTBm+0= X-Received: from pjbqi9.prod.google.com ([2002:a17:90b:2749:b0:2e0:52d7:183e]) (user=samitolvanen job=prod-delivery.src-stubby-dispatcher) by 2002:a17:90a:dfcd:b0:2ee:7233:4e8c with SMTP id 98e67ed59e1d1-2f452dfa47amr734025a91.8.1734642488187; Thu, 19 Dec 2024 13:08:08 -0800 (PST) Date: Thu, 19 Dec 2024 21:07:48 +0000 In-Reply-To: <20241219210736.2990838-20-samitolvanen@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20241219210736.2990838-20-samitolvanen@google.com> X-Developer-Key: i=samitolvanen@google.com; a=openpgp; fpr=35CCFB63B283D6D3AEB783944CB5F6848BBC56EE X-Developer-Signature: v=1; a=openpgp-sha256; l=17017; i=samitolvanen@google.com; h=from:subject; bh=lv/LqT3Rp5/bfJTOpHCnS5zJtNsJpm7Pz2uB72SikQI=; b=owGbwMvMwCEWxa662nLh8irG02pJDOkp3XJf7vNsqbp0Z06b8VFFp5XeE/9Fb9j5smLfv/r7f 9ZJtzu4dZSyMIhxMMiKKbK0fF29dfd3p9RXn4skYOawMoEMYeDiFICJqH9i+MPTuvTtw4YlztWa s7yEbwaedeS9t3hVwvRFzXPXLOJ4dagdqKKPWcUqN+rSuzmfXjZP+rw2oGuRW2eyaQBTuFf4078 uXAA= X-Mailer: git-send-email 2.47.1.613.gc27f4b7a9f-goog Message-ID: <20241219210736.2990838-31-samitolvanen@google.com> Subject: [PATCH v7 11/18] gendwarfksyms: Add symtypes output From: Sami Tolvanen To: Masahiro Yamada , Luis Chamberlain , Miguel Ojeda , Greg Kroah-Hartman Cc: Matthew Maurer , Alex Gaynor , Gary Guo , Petr Pavlu , Daniel Gomez , Neal Gompa , Hector Martin , Janne Grunau , Miroslav Benes , Asahi Linux , Sedat Dilek , linux-kbuild@vger.kernel.org, linux-kernel@vger.kernel.org, linux-modules@vger.kernel.org, rust-for-linux@vger.kernel.org, Sami Tolvanen Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add support for producing genksyms-style symtypes files. Process die_map to find the longest expansions for each type, and use symtypes references in type definitions. The basic file format is similar to genksyms, with two notable exceptions: 1. Type names with spaces (common with Rust) in references are wrapped in single quotes. E.g.: s#'core::result::Result' 2. The actual type definition is the simple parsed DWARF format we output with --dump-dies, not the preprocessed C-style format genksyms produces. Signed-off-by: Sami Tolvanen Reviewed-by: Petr Pavlu --- scripts/gendwarfksyms/Makefile | 1 + scripts/gendwarfksyms/die.c | 11 + scripts/gendwarfksyms/dwarf.c | 1 + scripts/gendwarfksyms/gendwarfksyms.c | 33 ++- scripts/gendwarfksyms/gendwarfksyms.h | 19 ++ scripts/gendwarfksyms/symbols.c | 4 +- scripts/gendwarfksyms/types.c | 363 ++++++++++++++++++++++++++ 7 files changed, 429 insertions(+), 3 deletions(-) create mode 100644 scripts/gendwarfksyms/types.c diff --git a/scripts/gendwarfksyms/Makefile b/scripts/gendwarfksyms/Makefile index c06145d84df8..6540282dc746 100644 --- a/scripts/gendwarfksyms/Makefile +++ b/scripts/gendwarfksyms/Makefile @@ -6,5 +6,6 @@ gendwarfksyms-objs +=3D cache.o gendwarfksyms-objs +=3D die.o gendwarfksyms-objs +=3D dwarf.o gendwarfksyms-objs +=3D symbols.o +gendwarfksyms-objs +=3D types.o =20 HOSTLDLIBS_gendwarfksyms :=3D -ldw -lelf diff --git a/scripts/gendwarfksyms/die.c b/scripts/gendwarfksyms/die.c index 0d70e02d02b5..66bd4c9bc952 100644 --- a/scripts/gendwarfksyms/die.c +++ b/scripts/gendwarfksyms/die.c @@ -22,6 +22,7 @@ static inline unsigned int die_hash(uintptr_t addr, enum = die_state state) static void init_die(struct die *cd) { cd->state =3D DIE_INCOMPLETE; + cd->mapped =3D false; cd->fqn =3D NULL; cd->tag =3D -1; cd->addr =3D 0; @@ -83,6 +84,16 @@ static void reset_die(struct die *cd) init_die(cd); } =20 +void die_map_for_each(die_map_callback_t func, void *arg) +{ + struct hlist_node *tmp; + struct die *cd; + + hash_for_each_safe(die_map, cd, tmp, hash) { + func(cd, arg); + } +} + void die_map_free(void) { struct hlist_node *tmp; diff --git a/scripts/gendwarfksyms/dwarf.c b/scripts/gendwarfksyms/dwarf.c index 364ff4892d5c..a9966a23167a 100644 --- a/scripts/gendwarfksyms/dwarf.c +++ b/scripts/gendwarfksyms/dwarf.c @@ -745,6 +745,7 @@ static void process_symbol(struct state *state, Dwarf_D= ie *die, { debug("%s", state->sym->name); check(process_func(state, NULL, die)); + state->sym->state =3D SYMBOL_MAPPED; if (dump_dies) fputs("\n", stderr); } diff --git a/scripts/gendwarfksyms/gendwarfksyms.c b/scripts/gendwarfksyms/= gendwarfksyms.c index ed6d8c585268..76a38b733ad2 100644 --- a/scripts/gendwarfksyms/gendwarfksyms.c +++ b/scripts/gendwarfksyms/gendwarfksyms.c @@ -21,6 +21,11 @@ int debug; int dump_dies; /* Print debugging information about die_map changes */ int dump_die_map; +/* Print out type strings (i.e. type_map) */ +int dump_types; +/* Write a symtypes file */ +int symtypes; +static const char *symtypes_file; =20 static void usage(void) { @@ -29,6 +34,8 @@ static void usage(void) " -d, --debug Print debugging information\n" " --dump-dies Dump DWARF DIE contents\n" " --dump-die-map Print debugging information about die_map c= hanges\n" + " --dump-types Dump type strings\n" + " -T, --symtypes file Write a symtypes file\n" " -h, --help Print this message\n" "\n", stderr); @@ -41,6 +48,7 @@ static int process_module(Dwfl_Module *mod, void **userda= ta, const char *name, Dwarf_Die cudie; Dwarf_CU *cu =3D NULL; Dwarf *dbg; + FILE *symfile =3D arg; int res; =20 debug("%s", name); @@ -60,6 +68,10 @@ static int process_module(Dwfl_Module *mod, void **userd= ata, const char *name, process_cu(&cudie); } while (cu); =20 + /* + * Use die_map to expand type strings and write them to `symfile`. + */ + generate_symtypes(symfile); die_map_free(); =20 return DWARF_CB_OK; @@ -72,22 +84,29 @@ static const Dwfl_Callbacks callbacks =3D { =20 int main(int argc, char **argv) { + FILE *symfile =3D NULL; unsigned int n; int opt; =20 struct option opts[] =3D { { "debug", 0, NULL, 'd' }, { "dump-dies", 0, &dump_dies, 1 }, { "dump-die-map", 0, &dump_die_map, 1 }, + { "dump-types", 0, &dump_types, 1 }, + { "symtypes", 1, NULL, 'T' }, { "help", 0, NULL, 'h' }, { 0, 0, NULL, 0 } }; =20 - while ((opt =3D getopt_long(argc, argv, "dh", opts, NULL)) !=3D EOF) { + while ((opt =3D getopt_long(argc, argv, "dT:h", opts, NULL)) !=3D EOF) { switch (opt) { case 0: break; case 'd': debug =3D 1; break; + case 'T': + symtypes =3D 1; + symtypes_file =3D optarg; + break; case 'h': usage(); return 0; @@ -107,6 +126,13 @@ int main(int argc, char **argv) =20 symbol_read_exports(stdin); =20 + if (symtypes_file) { + symfile =3D fopen(symtypes_file, "w"); + if (!symfile) + error("fopen failed for '%s': %s", symtypes_file, + strerror(errno)); + } + for (n =3D optind; n < argc; n++) { Dwfl *dwfl; int fd; @@ -129,12 +155,15 @@ int main(int argc, char **argv) =20 dwfl_report_end(dwfl, NULL, NULL); =20 - if (dwfl_getmodules(dwfl, &process_module, NULL, 0)) + if (dwfl_getmodules(dwfl, &process_module, symfile, 0)) error("dwfl_getmodules failed for '%s'", argv[n]); =20 dwfl_end(dwfl); } =20 + if (symfile) + check(fclose(symfile)); + symbol_free(); =20 return 0; diff --git a/scripts/gendwarfksyms/gendwarfksyms.h b/scripts/gendwarfksyms/= gendwarfksyms.h index 251832dac599..98d5b2315f21 100644 --- a/scripts/gendwarfksyms/gendwarfksyms.h +++ b/scripts/gendwarfksyms/gendwarfksyms.h @@ -22,6 +22,8 @@ extern int debug; extern int dump_dies; extern int dump_die_map; +extern int dump_types; +extern int symtypes; =20 /* * Output helpers @@ -90,6 +92,11 @@ static inline unsigned int addr_hash(uintptr_t addr) return hash_ptr((const void *)addr); } =20 +enum symbol_state { + SYMBOL_UNPROCESSED, + SYMBOL_MAPPED, +}; + struct symbol_addr { uint32_t section; Elf64_Addr address; @@ -100,6 +107,8 @@ struct symbol { struct symbol_addr addr; struct hlist_node addr_hash; struct hlist_node name_hash; + enum symbol_state state; + uintptr_t die_addr; }; =20 typedef void (*symbol_callback_t)(struct symbol *, void *arg); @@ -154,6 +163,7 @@ static inline const char *die_state_name(enum die_state= state) =20 struct die { enum die_state state; + bool mapped; char *fqn; int tag; uintptr_t addr; @@ -161,10 +171,13 @@ struct die { struct hlist_node hash; }; =20 +typedef void (*die_map_callback_t)(struct die *, void *arg); + int __die_map_get(uintptr_t addr, enum die_state state, struct die **res); struct die *die_map_get(Dwarf_Die *die, enum die_state state); void die_map_add_string(struct die *pd, const char *str); void die_map_add_linebreak(struct die *pd, int linebreak); +void die_map_for_each(die_map_callback_t func, void *arg); void die_map_add_die(struct die *pd, struct die *child); void die_map_free(void); =20 @@ -235,4 +248,10 @@ int process_die_container(struct state *state, struct = die *cache, =20 void process_cu(Dwarf_Die *cudie); =20 +/* + * types.c + */ + +void generate_symtypes(FILE *file); + #endif /* __GENDWARFKSYMS_H */ diff --git a/scripts/gendwarfksyms/symbols.c b/scripts/gendwarfksyms/symbol= s.c index 98febb524dd5..0d2ce7284a53 100644 --- a/scripts/gendwarfksyms/symbols.c +++ b/scripts/gendwarfksyms/symbols.c @@ -92,6 +92,7 @@ void symbol_read_exports(FILE *file) sym =3D xcalloc(1, sizeof(struct symbol)); sym->name =3D name; sym->addr.section =3D SHN_UNDEF; + sym->state =3D SYMBOL_UNPROCESSED; =20 hash_add(symbol_names, &sym->name_hash, hash_str(sym->name)); ++nsym; @@ -107,7 +108,8 @@ static void get_symbol(struct symbol *sym, void *arg) { struct symbol **res =3D arg; =20 - *res =3D sym; + if (sym->state =3D=3D SYMBOL_UNPROCESSED) + *res =3D sym; } =20 struct symbol *symbol_get(const char *name) diff --git a/scripts/gendwarfksyms/types.c b/scripts/gendwarfksyms/types.c new file mode 100644 index 000000000000..21d7a34228eb --- /dev/null +++ b/scripts/gendwarfksyms/types.c @@ -0,0 +1,363 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2024 Google LLC + */ + +#define _GNU_SOURCE +#include +#include + +#include "gendwarfksyms.h" + +static struct cache expansion_cache; + +/* + * A simple linked list of shared or owned strings to avoid copying strings + * around when not necessary. + */ +struct type_list_entry { + const char *str; + void *owned; + struct list_head list; +}; + +static void type_list_free(struct list_head *list) +{ + struct type_list_entry *entry; + struct type_list_entry *tmp; + + list_for_each_entry_safe(entry, tmp, list, list) { + if (entry->owned) + free(entry->owned); + free(entry); + } + + INIT_LIST_HEAD(list); +} + +static int type_list_append(struct list_head *list, const char *s, void *o= wned) +{ + struct type_list_entry *entry; + + if (!s) + return 0; + + entry =3D xmalloc(sizeof(struct type_list_entry)); + entry->str =3D s; + entry->owned =3D owned; + list_add_tail(&entry->list, list); + + return strlen(entry->str); +} + +static void type_list_write(struct list_head *list, FILE *file) +{ + struct type_list_entry *entry; + + list_for_each_entry(entry, list, list) { + if (entry->str) + checkp(fputs(entry->str, file)); + } +} + +/* + * An expanded type string in symtypes format. + */ +struct type_expansion { + char *name; + size_t len; + struct list_head expanded; + struct hlist_node hash; +}; + +static void type_expansion_init(struct type_expansion *type) +{ + type->name =3D NULL; + type->len =3D 0; + INIT_LIST_HEAD(&type->expanded); +} + +static inline void type_expansion_free(struct type_expansion *type) +{ + free(type->name); + type->name =3D NULL; + type->len =3D 0; + type_list_free(&type->expanded); +} + +static void type_expansion_append(struct type_expansion *type, const char = *s, + void *owned) +{ + type->len +=3D type_list_append(&type->expanded, s, owned); +} + +/* + * type_map -- the longest expansions for each type. + * + * const char *name -> struct type_expansion * + */ +#define TYPE_HASH_BITS 12 +static HASHTABLE_DEFINE(type_map, 1 << TYPE_HASH_BITS); + +static int type_map_get(const char *name, struct type_expansion **res) +{ + struct type_expansion *e; + + hash_for_each_possible(type_map, e, hash, hash_str(name)) { + if (!strcmp(name, e->name)) { + *res =3D e; + return 0; + } + } + + return -1; +} + +static void type_map_add(const char *name, struct type_expansion *type) +{ + struct type_expansion *e; + + if (type_map_get(name, &e)) { + e =3D xmalloc(sizeof(struct type_expansion)); + type_expansion_init(e); + e->name =3D xstrdup(name); + + hash_add(type_map, &e->hash, hash_str(e->name)); + + if (dump_types) + debug("adding %s", e->name); + } else { + /* Use the longest available expansion */ + if (type->len <=3D e->len) + return; + + type_list_free(&e->expanded); + + if (dump_types) + debug("replacing %s", e->name); + } + + /* Take ownership of type->expanded */ + list_replace_init(&type->expanded, &e->expanded); + e->len =3D type->len; + + if (dump_types) { + checkp(fputs(e->name, stderr)); + checkp(fputs(" ", stderr)); + type_list_write(&e->expanded, stderr); + checkp(fputs("\n", stderr)); + } +} + +static void type_map_write(FILE *file) +{ + struct type_expansion *e; + struct hlist_node *tmp; + + if (!file) + return; + + hash_for_each_safe(type_map, e, tmp, hash) { + checkp(fputs(e->name, file)); + checkp(fputs(" ", file)); + type_list_write(&e->expanded, file); + checkp(fputs("\n", file)); + } +} + +static void type_map_free(void) +{ + struct type_expansion *e; + struct hlist_node *tmp; + + hash_for_each_safe(type_map, e, tmp, hash) { + type_expansion_free(e); + free(e); + } + + hash_init(type_map); +} + +/* + * Type reference format: #, where prefix: + * s -> structure + * u -> union + * e -> enum + * t -> typedef + * + * Names with spaces are additionally wrapped in single quotes. + */ +static char get_type_prefix(int tag) +{ + switch (tag) { + case DW_TAG_class_type: + case DW_TAG_structure_type: + return 's'; + case DW_TAG_union_type: + return 'u'; + case DW_TAG_enumeration_type: + return 'e'; + case DW_TAG_typedef_type: + return 't'; + default: + return 0; + } +} + +static char *get_type_name(struct die *cache) +{ + const char *quote; + char prefix; + char *name; + + if (cache->state =3D=3D DIE_INCOMPLETE) { + warn("found incomplete cache entry: %p", cache); + return NULL; + } + if (!cache->fqn || !*cache->fqn) + return NULL; + + prefix =3D get_type_prefix(cache->tag); + if (!prefix) + return NULL; + + /* Wrap names with spaces in single quotes */ + quote =3D strstr(cache->fqn, " ") ? "'" : ""; + + /* #\0 */ + if (asprintf(&name, "%c#%s%s%s", prefix, quote, cache->fqn, quote) < 0) + error("asprintf failed for '%s'", cache->fqn); + + return name; +} + +static void __type_expand(struct die *cache, struct type_expansion *type, + bool recursive); + +static void type_expand_child(struct die *cache, struct type_expansion *ty= pe, + bool recursive) +{ + struct type_expansion child; + char *name; + + name =3D get_type_name(cache); + if (!name) { + __type_expand(cache, type, recursive); + return; + } + + if (recursive && !__cache_was_expanded(&expansion_cache, cache->addr)) { + __cache_mark_expanded(&expansion_cache, cache->addr); + type_expansion_init(&child); + __type_expand(cache, &child, true); + type_map_add(name, &child); + type_expansion_free(&child); + } + + type_expansion_append(type, name, name); +} + +static void __type_expand(struct die *cache, struct type_expansion *type, + bool recursive) +{ + struct die_fragment *df; + struct die *child; + + list_for_each_entry(df, &cache->fragments, list) { + switch (df->type) { + case FRAGMENT_STRING: + type_expansion_append(type, df->data.str, NULL); + break; + case FRAGMENT_DIE: + /* Use a complete die_map expansion if available */ + if (__die_map_get(df->data.addr, DIE_COMPLETE, + &child) && + __die_map_get(df->data.addr, DIE_UNEXPANDED, + &child)) + error("unknown child: %" PRIxPTR, + df->data.addr); + + type_expand_child(child, type, recursive); + break; + case FRAGMENT_LINEBREAK: + /* + * Keep whitespace in the symtypes format, but avoid + * repeated spaces. + */ + if (list_is_last(&df->list, &cache->fragments) || + list_next_entry(df, list)->type !=3D + FRAGMENT_LINEBREAK) + type_expansion_append(type, " ", NULL); + break; + default: + error("empty die_fragment in %p", cache); + } + } +} + +static void type_expand(struct die *cache, struct type_expansion *type, + bool recursive) +{ + type_expansion_init(type); + __type_expand(cache, type, recursive); + cache_free(&expansion_cache); +} + +static void expand_type(struct die *cache, void *arg) +{ + struct type_expansion type; + char *name; + + if (cache->mapped) + return; + + cache->mapped =3D true; + + /* + * Skip unexpanded die_map entries if there's a complete + * expansion available for this DIE. + */ + if (cache->state =3D=3D DIE_UNEXPANDED && + !__die_map_get(cache->addr, DIE_COMPLETE, &cache)) { + if (cache->mapped) + return; + + cache->mapped =3D true; + } + + name =3D get_type_name(cache); + if (!name) + return; + + debug("%s", name); + type_expand(cache, &type, true); + type_map_add(name, &type); + + type_expansion_free(&type); + free(name); +} + +void generate_symtypes(FILE *file) +{ + cache_init(&expansion_cache); + + /* + * die_map processing: + * + * 1. die_map contains all types referenced in exported symbol + * signatures, but can contain duplicates just like the original + * DWARF, and some references may not be fully expanded depending + * on how far we processed the DIE tree for that specific symbol. + * + * For each die_map entry, find the longest available expansion, + * and add it to type_map. + */ + die_map_for_each(expand_type, NULL); + + /* + * 2. If a symtypes file is requested, write type_map contents to + * the file. + */ + type_map_write(file); + type_map_free(); +} --=20 2.47.1.613.gc27f4b7a9f-goog From nobody Mon Feb 9 13:01:05 2026 Received: from mail-pg1-f201.google.com (mail-pg1-f201.google.com [209.85.215.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 43A481FDE20 for ; Thu, 19 Dec 2024 21:08:10 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.215.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734642492; cv=none; b=BiDQbpxFS/wm0GiFs0KsRMHxKRNDx4bau1Ns02O4v0k2S5McBXOlodF9+An5zVfATodmq+ZM8RUtglY/7NBTEkpbu3e5+0z5WaXz64KJvDBMtLOJNKgydKxBDDUPaWOXhXDvLQ6k4VHakMAheSd0SRbfbmkZbBFPiCHLpoknSxs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734642492; c=relaxed/simple; bh=QbryxAaCawxBZfMRQq7TBeM1EywZwyCC1hWjsgkRH/c=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=g8P3O27cnRIgOAB/mPfiODKNGmtMOtN9Ht/dJfqv7kKffej4yZwv+Rg8/HlcWB56zCeFah1qiY9PWZ52QgK+XwOTNFelMsur6ENAuf7yB8uqGnVuabeMv3BKe5NjYnazojZlQnEfW4YHYZBGWC+ICAdndhIXLJbiTsdswhI0B+s= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--samitolvanen.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=gYEcx0Wh; arc=none smtp.client-ip=209.85.215.201 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--samitolvanen.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="gYEcx0Wh" Received: by mail-pg1-f201.google.com with SMTP id 41be03b00d2f7-801d5add29eso801051a12.3 for ; Thu, 19 Dec 2024 13:08:10 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1734642490; x=1735247290; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=zls+2kQ0MueTIF/Klfb6OSdTqOjwM1Bn5x2gnO5coH4=; b=gYEcx0WhHeWLF/TvWGDq/Fof7e1QTrGZeazeAmUA/h78NZBDoJsEhAXKocIHoESIz8 VuxXpBCr362MMoIRLYFwLNmwDxBnb4avsJxe+ObsxjhV/sMX52jHw6J0YqhgeTrpyEAg EI3ltJPthSP8OaH616yBYHpjg3fYIjkc1gcuWr5xEAkjQfRpBRIz/GExstTRbN211CcZ nmkHW/JBqgK5mrjrUhl/QRmhpO9qNgHryB9GP+LCcEJWge6vx/pUkUpfzZD+GEHGaLzq K1DOCgiKcHdFUuPiaOm++XikP4J932ARqJVU5MNuHltCX1tmIGLkKmZyn1oKRm6r1LdC SCrg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1734642490; x=1735247290; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=zls+2kQ0MueTIF/Klfb6OSdTqOjwM1Bn5x2gnO5coH4=; b=fSPUqLbYxfXNQCy5a63fBUfykR/jYEfWWe64lFx5yiL83OQachsNjVig6xpCNuUqgd FcKyZfHAnA/5g6PqNY/OwdANXEN1fxIfZfraO6meFQz/DerbsUjywuETipWRh5kf6Msl +MBuzyiRjM77uaej/TSCULAYH6M34e0JzZT1KEgIICIMme6R3TrRqVgXef75kHynUxMg 5g/tGRFzvNl7ZqlhGNw/kiBvksK3c8XphqlEfhX6fkfOJ0m5I/9QHA1bMWT9D4UAT7kl 710qsXLEqeUH0WcsiIf//NfqVvdodz0P4+t2ikmMP3rywDVsWi68tDX7Y5yC4BdQDcem Z8PA== X-Forwarded-Encrypted: i=1; AJvYcCV6cblp6pFzk/2bqgJxO132sRbstEwjfPbffTJLdd25f6feUKvro2Ysm/i5yXbPAdh9FD2X8VTjk/7SwD0=@vger.kernel.org X-Gm-Message-State: AOJu0YxuN/nYU59+KWGdBAmtK3ibGsz8N3zZ3tQx51u/KCVGyxoweJFS GGwK1dLth1oXOm5gqNPUlDKxSfY0ISM961mZs3stE7hXwYlxW0RPbxNVgaG7cUqVgNPHDzIV4qu B5a1tNgu1uKz9giHxskh+fv5ykQ== X-Google-Smtp-Source: AGHT+IFH+9afOGlxylZhHE1k+fERcM66+sdoH8sF6V9jFmEpMxL9JVsGX5eicBVFC+xXT/v7Typ9iXR4yCcVLImIn1Y= X-Received: from pfbcw25.prod.google.com ([2002:a05:6a00:4519:b0:727:3c81:f42a]) (user=samitolvanen job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6a21:33a6:b0:1e5:c43f:f36d with SMTP id adf61e73a8af0-1e5e046189cmr865018637.18.1734642489781; Thu, 19 Dec 2024 13:08:09 -0800 (PST) Date: Thu, 19 Dec 2024 21:07:49 +0000 In-Reply-To: <20241219210736.2990838-20-samitolvanen@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20241219210736.2990838-20-samitolvanen@google.com> X-Developer-Key: i=samitolvanen@google.com; a=openpgp; fpr=35CCFB63B283D6D3AEB783944CB5F6848BBC56EE X-Developer-Signature: v=1; a=openpgp-sha256; l=12931; i=samitolvanen@google.com; h=from:subject; bh=QbryxAaCawxBZfMRQq7TBeM1EywZwyCC1hWjsgkRH/c=; b=owGbwMvMwCEWxa662nLh8irG02pJDOkp3XJSZZyG0Wuus1qsmPZEUPhhv0XL871W6zbExiz9z q1jve1HRykLgxgHg6yYIkvL19Vbd393Sn31uUgCZg4rE8gQBi5OAZhIZiwjw56T6lkz/nzqTJyb 3pb5489WFpmld5OOJiW/VLLZblfQJMXI8H9FYp+e5m/ubwYlT43XHJ7iuJuzIH+/X1V4vk7ZoSo 2TgA= X-Mailer: git-send-email 2.47.1.613.gc27f4b7a9f-goog Message-ID: <20241219210736.2990838-32-samitolvanen@google.com> Subject: [PATCH v7 12/18] gendwarfksyms: Add symbol versioning From: Sami Tolvanen To: Masahiro Yamada , Luis Chamberlain , Miguel Ojeda , Greg Kroah-Hartman Cc: Matthew Maurer , Alex Gaynor , Gary Guo , Petr Pavlu , Daniel Gomez , Neal Gompa , Hector Martin , Janne Grunau , Miroslav Benes , Asahi Linux , Sedat Dilek , linux-kbuild@vger.kernel.org, linux-kernel@vger.kernel.org, linux-modules@vger.kernel.org, rust-for-linux@vger.kernel.org, Sami Tolvanen Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Calculate symbol versions from the fully expanded type strings in type_map, and output the versions in a genksyms-compatible format. Signed-off-by: Sami Tolvanen Reviewed-by: Petr Pavlu --- scripts/gendwarfksyms/Makefile | 2 +- scripts/gendwarfksyms/dwarf.c | 25 +++++- scripts/gendwarfksyms/gendwarfksyms.c | 10 ++- scripts/gendwarfksyms/gendwarfksyms.h | 13 ++- scripts/gendwarfksyms/symbols.c | 53 +++++++++++ scripts/gendwarfksyms/types.c | 122 +++++++++++++++++++++++++- 6 files changed, 216 insertions(+), 9 deletions(-) diff --git a/scripts/gendwarfksyms/Makefile b/scripts/gendwarfksyms/Makefile index 6540282dc746..e889b958957b 100644 --- a/scripts/gendwarfksyms/Makefile +++ b/scripts/gendwarfksyms/Makefile @@ -8,4 +8,4 @@ gendwarfksyms-objs +=3D dwarf.o gendwarfksyms-objs +=3D symbols.o gendwarfksyms-objs +=3D types.o =20 -HOSTLDLIBS_gendwarfksyms :=3D -ldw -lelf +HOSTLDLIBS_gendwarfksyms :=3D -ldw -lelf -lz diff --git a/scripts/gendwarfksyms/dwarf.c b/scripts/gendwarfksyms/dwarf.c index a9966a23167a..bdf899d60707 100644 --- a/scripts/gendwarfksyms/dwarf.c +++ b/scripts/gendwarfksyms/dwarf.c @@ -740,12 +740,33 @@ static int process_type(struct state *state, struct d= ie *parent, Dwarf_Die *die) /* * Exported symbol processing */ +static struct die *get_symbol_cache(struct state *state, Dwarf_Die *die) +{ + struct die *cache; + + cache =3D die_map_get(die, DIE_SYMBOL); + + if (cache->state !=3D DIE_INCOMPLETE) + return NULL; /* We already processed a symbol for this DIE */ + + cache->tag =3D dwarf_tag(die); + return cache; +} + static void process_symbol(struct state *state, Dwarf_Die *die, die_callback_t process_func) { + struct die *cache; + + symbol_set_die(state->sym, die); + + cache =3D get_symbol_cache(state, die); + if (!cache) + return; + debug("%s", state->sym->name); - check(process_func(state, NULL, die)); - state->sym->state =3D SYMBOL_MAPPED; + check(process_func(state, cache, die)); + cache->state =3D DIE_SYMBOL; if (dump_dies) fputs("\n", stderr); } diff --git a/scripts/gendwarfksyms/gendwarfksyms.c b/scripts/gendwarfksyms/= gendwarfksyms.c index 76a38b733ad2..fd2429ea198f 100644 --- a/scripts/gendwarfksyms/gendwarfksyms.c +++ b/scripts/gendwarfksyms/gendwarfksyms.c @@ -23,6 +23,8 @@ int dump_dies; int dump_die_map; /* Print out type strings (i.e. type_map) */ int dump_types; +/* Print out expanded type strings used for symbol versions */ +int dump_versions; /* Write a symtypes file */ int symtypes; static const char *symtypes_file; @@ -35,6 +37,7 @@ static void usage(void) " --dump-dies Dump DWARF DIE contents\n" " --dump-die-map Print debugging information about die_map c= hanges\n" " --dump-types Dump type strings\n" + " --dump-versions Dump expanded type strings used for symbol = versions\n" " -T, --symtypes file Write a symtypes file\n" " -h, --help Print this message\n" "\n", @@ -69,9 +72,10 @@ static int process_module(Dwfl_Module *mod, void **userd= ata, const char *name, } while (cu); =20 /* - * Use die_map to expand type strings and write them to `symfile`. + * Use die_map to expand type strings, write them to `symfile`, and + * calculate symbol versions. */ - generate_symtypes(symfile); + generate_symtypes_and_versions(symfile); die_map_free(); =20 return DWARF_CB_OK; @@ -92,6 +96,7 @@ int main(int argc, char **argv) { "dump-dies", 0, &dump_dies, 1 }, { "dump-die-map", 0, &dump_die_map, 1 }, { "dump-types", 0, &dump_types, 1 }, + { "dump-versions", 0, &dump_versions, 1 }, { "symtypes", 1, NULL, 'T' }, { "help", 0, NULL, 'h' }, { 0, 0, NULL, 0 } }; @@ -164,6 +169,7 @@ int main(int argc, char **argv) if (symfile) check(fclose(symfile)); =20 + symbol_print_versions(); symbol_free(); =20 return 0; diff --git a/scripts/gendwarfksyms/gendwarfksyms.h b/scripts/gendwarfksyms/= gendwarfksyms.h index 98d5b2315f21..203534abcd35 100644 --- a/scripts/gendwarfksyms/gendwarfksyms.h +++ b/scripts/gendwarfksyms/gendwarfksyms.h @@ -23,6 +23,7 @@ extern int debug; extern int dump_dies; extern int dump_die_map; extern int dump_types; +extern int dump_versions; extern int symtypes; =20 /* @@ -95,6 +96,7 @@ static inline unsigned int addr_hash(uintptr_t addr) enum symbol_state { SYMBOL_UNPROCESSED, SYMBOL_MAPPED, + SYMBOL_PROCESSED }; =20 struct symbol_addr { @@ -109,6 +111,7 @@ struct symbol { struct hlist_node name_hash; enum symbol_state state; uintptr_t die_addr; + unsigned long crc; }; =20 typedef void (*symbol_callback_t)(struct symbol *, void *arg); @@ -116,6 +119,10 @@ typedef void (*symbol_callback_t)(struct symbol *, voi= d *arg); void symbol_read_exports(FILE *file); void symbol_read_symtab(int fd); struct symbol *symbol_get(const char *name); +void symbol_set_die(struct symbol *sym, Dwarf_Die *die); +void symbol_set_crc(struct symbol *sym, unsigned long crc); +void symbol_for_each(symbol_callback_t func, void *arg); +void symbol_print_versions(void); void symbol_free(void); =20 /* @@ -126,7 +133,8 @@ enum die_state { DIE_INCOMPLETE, DIE_UNEXPANDED, DIE_COMPLETE, - DIE_LAST =3D DIE_COMPLETE + DIE_SYMBOL, + DIE_LAST =3D DIE_SYMBOL }; =20 enum die_fragment_type { @@ -156,6 +164,7 @@ static inline const char *die_state_name(enum die_state= state) CASE_CONST_TO_STR(DIE_INCOMPLETE) CASE_CONST_TO_STR(DIE_UNEXPANDED) CASE_CONST_TO_STR(DIE_COMPLETE) + CASE_CONST_TO_STR(DIE_SYMBOL) } =20 error("unexpected die_state: %d", state); @@ -252,6 +261,6 @@ void process_cu(Dwarf_Die *cudie); * types.c */ =20 -void generate_symtypes(FILE *file); +void generate_symtypes_and_versions(FILE *file); =20 #endif /* __GENDWARFKSYMS_H */ diff --git a/scripts/gendwarfksyms/symbols.c b/scripts/gendwarfksyms/symbol= s.c index 0d2ce7284a53..4c499ba6c86d 100644 --- a/scripts/gendwarfksyms/symbols.c +++ b/scripts/gendwarfksyms/symbols.c @@ -66,6 +66,36 @@ static unsigned int for_each(const char *name, symbol_ca= llback_t func, return 0; } =20 +static void set_crc(struct symbol *sym, void *data) +{ + unsigned long *crc =3D data; + + if (sym->state =3D=3D SYMBOL_PROCESSED && sym->crc !=3D *crc) + warn("overriding version for symbol %s (crc %lx vs. %lx)", + sym->name, sym->crc, *crc); + + sym->state =3D SYMBOL_PROCESSED; + sym->crc =3D *crc; +} + +void symbol_set_crc(struct symbol *sym, unsigned long crc) +{ + if (for_each(sym->name, set_crc, &crc) =3D=3D 0) + error("no matching symbols: '%s'", sym->name); +} + +static void set_die(struct symbol *sym, void *data) +{ + sym->die_addr =3D (uintptr_t)((Dwarf_Die *)data)->addr; + sym->state =3D SYMBOL_MAPPED; +} + +void symbol_set_die(struct symbol *sym, Dwarf_Die *die) +{ + if (for_each(sym->name, set_die, die) =3D=3D 0) + error("no matching symbols: '%s'", sym->name); +} + static bool is_exported(const char *name) { return for_each(name, NULL, NULL) > 0; @@ -120,6 +150,16 @@ struct symbol *symbol_get(const char *name) return sym; } =20 +void symbol_for_each(symbol_callback_t func, void *arg) +{ + struct hlist_node *tmp; + struct symbol *sym; + + hash_for_each_safe(symbol_names, sym, tmp, name_hash) { + func(sym, arg); + } +} + typedef void (*elf_symbol_callback_t)(const char *name, GElf_Sym *sym, Elf32_Word xndx, void *arg); =20 @@ -246,6 +286,19 @@ void symbol_read_symtab(int fd) elf_for_each_global(fd, elf_set_symbol_addr, NULL); } =20 +void symbol_print_versions(void) +{ + struct hlist_node *tmp; + struct symbol *sym; + + hash_for_each_safe(symbol_names, sym, tmp, name_hash) { + if (sym->state !=3D SYMBOL_PROCESSED) + warn("no information for symbol %s", sym->name); + + printf("#SYMVER %s 0x%08lx\n", sym->name, sym->crc); + } +} + void symbol_free(void) { struct hlist_node *tmp; diff --git a/scripts/gendwarfksyms/types.c b/scripts/gendwarfksyms/types.c index 21d7a34228eb..6c03265f4d10 100644 --- a/scripts/gendwarfksyms/types.c +++ b/scripts/gendwarfksyms/types.c @@ -6,6 +6,7 @@ #define _GNU_SOURCE #include #include +#include =20 #include "gendwarfksyms.h" =20 @@ -178,6 +179,33 @@ static void type_map_free(void) hash_init(type_map); } =20 +/* + * CRC for a type, with an optional fully expanded type string for + * debugging. + */ +struct version { + struct type_expansion type; + unsigned long crc; +}; + +static void version_init(struct version *version) +{ + version->crc =3D crc32(0, NULL, 0); + type_expansion_init(&version->type); +} + +static void version_free(struct version *version) +{ + type_expansion_free(&version->type); +} + +static void version_add(struct version *version, const char *s) +{ + version->crc =3D crc32(version->crc, (void *)s, strlen(s)); + if (dump_versions) + type_expansion_append(&version->type, s, NULL); +} + /* * Type reference format: #, where prefix: * s -> structure @@ -187,6 +215,12 @@ static void type_map_free(void) * * Names with spaces are additionally wrapped in single quotes. */ +static inline bool is_type_prefix(const char *s) +{ + return (s[0] =3D=3D 's' || s[0] =3D=3D 'u' || s[0] =3D=3D 'e' || s[0] =3D= =3D 't') && + s[1] =3D=3D '#'; +} + static char get_type_prefix(int tag) { switch (tag) { @@ -214,6 +248,8 @@ static char *get_type_name(struct die *cache) warn("found incomplete cache entry: %p", cache); return NULL; } + if (cache->state =3D=3D DIE_SYMBOL) + return NULL; if (!cache->fqn || !*cache->fqn) return NULL; =20 @@ -231,6 +267,39 @@ static char *get_type_name(struct die *cache) return name; } =20 +static void __calculate_version(struct version *version, struct list_head = *list) +{ + struct type_list_entry *entry; + struct type_expansion *e; + + /* Calculate a CRC over an expanded type string */ + list_for_each_entry(entry, list, list) { + if (is_type_prefix(entry->str)) { + check(type_map_get(entry->str, &e)); + + /* + * It's sufficient to expand each type reference just + * once to detect changes. + */ + if (cache_was_expanded(&expansion_cache, e)) { + version_add(version, entry->str); + } else { + cache_mark_expanded(&expansion_cache, e); + __calculate_version(version, &e->expanded); + } + } else { + version_add(version, entry->str); + } + } +} + +static void calculate_version(struct version *version, struct list_head *l= ist) +{ + version_init(version); + __calculate_version(version, list); + cache_free(&expansion_cache); +} + static void __type_expand(struct die *cache, struct type_expansion *type, bool recursive); =20 @@ -337,7 +406,49 @@ static void expand_type(struct die *cache, void *arg) free(name); } =20 -void generate_symtypes(FILE *file) +static void expand_symbol(struct symbol *sym, void *arg) +{ + struct type_expansion type; + struct version version; + struct die *cache; + + /* + * No need to expand again unless we want a symtypes file entry + * for the symbol. Note that this means `sym` has the same address + * as another symbol that was already processed. + */ + if (!symtypes && sym->state =3D=3D SYMBOL_PROCESSED) + return; + + if (__die_map_get(sym->die_addr, DIE_SYMBOL, &cache)) + return; /* We'll warn about missing CRCs later. */ + + type_expand(cache, &type, false); + + /* If the symbol already has a version, don't calculate it again. */ + if (sym->state !=3D SYMBOL_PROCESSED) { + calculate_version(&version, &type.expanded); + symbol_set_crc(sym, version.crc); + debug("%s =3D %lx", sym->name, version.crc); + + if (dump_versions) { + checkp(fputs(sym->name, stderr)); + checkp(fputs(" ", stderr)); + type_list_write(&version.type.expanded, stderr); + checkp(fputs("\n", stderr)); + } + + version_free(&version); + } + + /* These aren't needed in type_map unless we want a symtypes file. */ + if (symtypes) + type_map_add(sym->name, &type); + + type_expansion_free(&type); +} + +void generate_symtypes_and_versions(FILE *file) { cache_init(&expansion_cache); =20 @@ -355,7 +466,14 @@ void generate_symtypes(FILE *file) die_map_for_each(expand_type, NULL); =20 /* - * 2. If a symtypes file is requested, write type_map contents to + * 2. For each exported symbol, expand the die_map type, and use + * type_map expansions to calculate a symbol version from the + * fully expanded type string. + */ + symbol_for_each(expand_symbol, NULL); + + /* + * 3. If a symtypes file is requested, write type_map contents to * the file. */ type_map_write(file); --=20 2.47.1.613.gc27f4b7a9f-goog From nobody Mon Feb 9 13:01:05 2026 Received: from mail-pf1-f202.google.com (mail-pf1-f202.google.com [209.85.210.202]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C512B1FE463 for ; Thu, 19 Dec 2024 21:08:11 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.202 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734642494; cv=none; b=eR/8luJ771XZqWgB/uW2LtpAJyuYYMh9hHc1lEpufBjKD3jOFniZtpsCvdFYv+TwuH26Zgk+1iUADjTEPccDuiXsXBieINwM4ETxQBkVl9S2rX+N/gVbiaRtwe6NW8xAblLHTygvZNiK1rYJ9EQEz8vFtyIP4C+cxvAtp8htL10= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734642494; c=relaxed/simple; bh=jDQKbg/it2lSQcMa4QhFOxem892cYQdK5o/DJi06Ji8=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=F+2WlMQ/1AyX6TZJUg0aT/UIGZEfjX87FVTo1CyiATT+MwYgVbxa8ls8BtZXh+SGc2aSetRvMZKHoX4z2zo1CK8y0Pl1z1I0yb5cGWta4/BO8b7mKNuw6elwXRmJ0OPjESpYk45C+HhN/6Wy9IYI/n4VXvsaAfP2G9VczuS9jZg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--samitolvanen.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=x/eb9/Il; arc=none smtp.client-ip=209.85.210.202 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--samitolvanen.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="x/eb9/Il" Received: by mail-pf1-f202.google.com with SMTP id d2e1a72fcca58-725e3c6ad0dso1697250b3a.0 for ; Thu, 19 Dec 2024 13:08:11 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1734642491; x=1735247291; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=hdbZ+f1RHV1+aLyJkFOTreqSjkO/ig/SI3dMZwuF37I=; b=x/eb9/Il+kZrUaJ6exslF4x1/zIOFf/nIWoDRygIzDXuWBsyESTorwhwqDEaWoC3Y5 O2nWSLNd4kPMIIqgq5pevWIyDUy8sNM7MezZ87xJ+XzJ4Dp3EUYpbWkNwu9p66CDctNJ 8xEeE52DPf1TrOLhDMJCxlq7kUDNfRgoT/GFilp0IhxglWHr10ZzZEaX6kIVxbBggV5v WQyrZZRdehW/hj55E+OtEAJ6ukSctaee1wVP9gE8XiYtBa8PzKF7tV46fxRyfoHf2+OR bl/zMdpMS2TFAPpRemoiVV9ub5RzZOycRfkEBjxH0scuBIX400V05yUWQlB1d0RCzM+o BYhg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1734642491; x=1735247291; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=hdbZ+f1RHV1+aLyJkFOTreqSjkO/ig/SI3dMZwuF37I=; b=RtXHaVd2o0/ikk3kfcTpx85YpClqgveZPhkdLg4puvKnlRT7E6Jz3fxehd/RGi1B+P nbU2cBLi8bREHKv/8Swgna2USTY1tcxzV9mdtpFzHc45fcU1xCEFmVKgxmOhbozG4fq2 UONzK7eUG/LyX2SKTKL4NgheUsNkHyI4Lfq69+eLRIay18Gq+QvpNFgJs4fcs6GQnpPc Fl8cDz+PERLLjAqI3o9VPAljX7ZBz9TClSC2HvXX091ZKbasNX67sNB8crA7gJBut9aY cnXlmdAZILtJuNQ1+1oPg5aJImxY1KSvIx5eqkEibS9nxidP4aOXQFW4Yr5gDvw1WC26 gZwA== X-Forwarded-Encrypted: i=1; AJvYcCVXzYINwBhLiH74vbIrPoMme+/VV+U4X4RQLOdH+6Ggfm4RuRCABVNH37MNYnjQO7d/d60ZOqkMXDU/JQk=@vger.kernel.org X-Gm-Message-State: AOJu0YzzHxP4oOnyRkD0pC6IJgmQV04h91coT/7s8UKX+5/wu+IUM09w CCGF9qISevsBhQZ3R4ZdOx+dg6PPm1uciDLkH2TEjtsjkvXkTdQpy4bkQNXqQUOqX8NSRmISFDT 3jQHehQfBEb8ICaRrteQjQSHVbw== X-Google-Smtp-Source: AGHT+IEpxOiXRbDsTIVUOc26aPjRm985EW4mAOJN0rz4IQnn1aKdvOv6myjiU0nT+mg/1zDjiQ74cx/rc1xH2MRs9YA= X-Received: from pfxa2.prod.google.com ([2002:a05:6a00:1d02:b0:725:eb13:8be8]) (user=samitolvanen job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6a00:1144:b0:72a:8b8f:a0f1 with SMTP id d2e1a72fcca58-72abde8462dmr270764b3a.20.1734642491336; Thu, 19 Dec 2024 13:08:11 -0800 (PST) Date: Thu, 19 Dec 2024 21:07:50 +0000 In-Reply-To: <20241219210736.2990838-20-samitolvanen@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20241219210736.2990838-20-samitolvanen@google.com> X-Developer-Key: i=samitolvanen@google.com; a=openpgp; fpr=35CCFB63B283D6D3AEB783944CB5F6848BBC56EE X-Developer-Signature: v=1; a=openpgp-sha256; l=21354; i=samitolvanen@google.com; h=from:subject; bh=jDQKbg/it2lSQcMa4QhFOxem892cYQdK5o/DJi06Ji8=; b=owGbwMvMwCEWxa662nLh8irG02pJDOkp3fKJ3u7+ev8FPkjFLq2KTEyvXXw0Nkn+xJcX3x0S1 c8/X/aso5SFQYyDQVZMkaXl6+qtu787pb76XCQBM4eVCWQIAxenAExk6QGGf5bxVR5LokqVPhss 2Ng5ha2IYfb8H7EZZ+/ZCq9cv1ng/S1GhsY7P3wUPBcwPZHuev3lQ3uejFew457EuVoeGl3r25s v8AIA X-Mailer: git-send-email 2.47.1.613.gc27f4b7a9f-goog Message-ID: <20241219210736.2990838-33-samitolvanen@google.com> Subject: [PATCH v7 13/18] gendwarfksyms: Add support for kABI rules From: Sami Tolvanen To: Masahiro Yamada , Luis Chamberlain , Miguel Ojeda , Greg Kroah-Hartman Cc: Matthew Maurer , Alex Gaynor , Gary Guo , Petr Pavlu , Daniel Gomez , Neal Gompa , Hector Martin , Janne Grunau , Miroslav Benes , Asahi Linux , Sedat Dilek , linux-kbuild@vger.kernel.org, linux-kernel@vger.kernel.org, linux-modules@vger.kernel.org, rust-for-linux@vger.kernel.org, Sami Tolvanen Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Distributions that want to maintain a stable kABI need the ability to make ABI compatible changes to kernel without affecting symbol versions, either because of LTS updates or backports. With genksyms, developers would typically hide these changes from version calculation with #ifndef __GENKSYMS__, which would result in the symbol version not changing even though the actual type has changed. When we process precompiled object files, this isn't an option. To support this use case, add a --stable command line flag that gates kABI stability features that are not needed in mainline kernels, but can be useful for distributions, and add support for kABI rules, which can be used to restrict gendwarfksyms output. The rules are specified as a set of null-terminated strings stored in the .discard.gendwarfksyms.kabi_rules section. Each rule consists of four strings as follows: "version\0type\0target\0value" The version string ensures the structure can be changed in a backwards compatible way. The type string indicates the type of the rule, and target and value strings contain rule-specific data. Initially support two simple rules: 1. Declaration-only types A type declaration can change into a full definition when additional includes are pulled in to the TU, which changes the versions of any symbol that references the type. Add support for defining declaration-only types whose definition is not expanded during versioning. 2. Ignored enumerators It's possible to add new enum fields without changing the ABI, but as the fields are included in symbol versioning, this would change the versions. Add support for ignoring specific fields. 3. Overridden enumerator values Add support for overriding enumerator values when calculating versions. This may be needed when the last field of the enum is used as a sentinel and new fields must be added before it. Add examples for using the rules under the examples/ directory. Signed-off-by: Sami Tolvanen --- scripts/gendwarfksyms/Makefile | 1 + scripts/gendwarfksyms/dwarf.c | 25 +- scripts/gendwarfksyms/examples/kabi.h | 70 +++++ scripts/gendwarfksyms/examples/kabi_ex.c | 14 + scripts/gendwarfksyms/examples/kabi_ex.h | 64 +++++ scripts/gendwarfksyms/gendwarfksyms.c | 11 +- scripts/gendwarfksyms/gendwarfksyms.h | 14 + scripts/gendwarfksyms/kabi.c | 336 +++++++++++++++++++++++ 8 files changed, 531 insertions(+), 4 deletions(-) create mode 100644 scripts/gendwarfksyms/examples/kabi.h create mode 100644 scripts/gendwarfksyms/examples/kabi_ex.c create mode 100644 scripts/gendwarfksyms/examples/kabi_ex.h create mode 100644 scripts/gendwarfksyms/kabi.c diff --git a/scripts/gendwarfksyms/Makefile b/scripts/gendwarfksyms/Makefile index e889b958957b..6334c7d3c4d5 100644 --- a/scripts/gendwarfksyms/Makefile +++ b/scripts/gendwarfksyms/Makefile @@ -5,6 +5,7 @@ gendwarfksyms-objs +=3D gendwarfksyms.o gendwarfksyms-objs +=3D cache.o gendwarfksyms-objs +=3D die.o gendwarfksyms-objs +=3D dwarf.o +gendwarfksyms-objs +=3D kabi.o gendwarfksyms-objs +=3D symbols.o gendwarfksyms-objs +=3D types.o =20 diff --git a/scripts/gendwarfksyms/dwarf.c b/scripts/gendwarfksyms/dwarf.c index bdf899d60707..17f7e6b9a7ff 100644 --- a/scripts/gendwarfksyms/dwarf.c +++ b/scripts/gendwarfksyms/dwarf.c @@ -120,13 +120,16 @@ static bool is_definition_private(Dwarf_Die *die) return !!res; } =20 -static bool is_kabi_definition(Dwarf_Die *die) +static bool is_kabi_definition(struct die *cache, Dwarf_Die *die) { bool value; =20 if (get_flag_attr(die, DW_AT_declaration, &value) && value) return false; =20 + if (kabi_is_declonly(cache->fqn)) + return false; + return !is_definition_private(die); } =20 @@ -515,9 +518,10 @@ static void __process_structure_type(struct state *sta= te, struct die *cache, process(cache, " {"); process_linebreak(cache, 1); =20 - expand =3D state->expand.expand && is_kabi_definition(die); + expand =3D state->expand.expand && is_kabi_definition(cache, die); =20 if (expand) { + state->expand.current_fqn =3D cache->fqn; check(process_die_container(state, cache, die, process_func, match_func)); } @@ -548,13 +552,26 @@ DEFINE_PROCESS_STRUCTURE_TYPE(union) static void process_enumerator_type(struct state *state, struct die *cache, Dwarf_Die *die) { + bool overridden =3D false; Dwarf_Word value; =20 + if (stable) { + /* Get the fqn before we process anything */ + update_fqn(cache, die); + + if (kabi_is_enumerator_ignored(state->expand.current_fqn, + cache->fqn)) + return; + + overridden =3D kabi_get_enumerator_value( + state->expand.current_fqn, cache->fqn, &value); + } + process_list_comma(state, cache); process(cache, "enumerator"); process_fqn(cache, die); =20 - if (get_udata_attr(die, DW_AT_const_value, &value)) { + if (overridden || get_udata_attr(die, DW_AT_const_value, &value)) { process(cache, " =3D "); process_fmt(cache, "%" PRIu64, value); } @@ -620,6 +637,7 @@ static void process_cached(struct state *state, struct = die *cache, static void state_init(struct state *state) { state->expand.expand =3D true; + state->expand.current_fqn =3D NULL; cache_init(&state->expansion_cache); } =20 @@ -627,6 +645,7 @@ static void expansion_state_restore(struct expansion_st= ate *state, struct expansion_state *saved) { state->expand =3D saved->expand; + state->current_fqn =3D saved->current_fqn; } =20 static void expansion_state_save(struct expansion_state *state, diff --git a/scripts/gendwarfksyms/examples/kabi.h b/scripts/gendwarfksyms/= examples/kabi.h new file mode 100644 index 000000000000..fcd0300e5b58 --- /dev/null +++ b/scripts/gendwarfksyms/examples/kabi.h @@ -0,0 +1,70 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2024 Google LLC + * + * Example macros for maintaining kABI stability. + * + * This file is based on android_kabi.h, which has the following notice: + * + * Heavily influenced by rh_kabi.h which came from the RHEL/CENTOS kernel + * and was: + * Copyright (c) 2014 Don Zickus + * Copyright (c) 2015-2018 Jiri Benc + * Copyright (c) 2015 Sabrina Dubroca, Hannes Frederic Sowa + * Copyright (c) 2016-2018 Prarit Bhargava + * Copyright (c) 2017 Paolo Abeni, Larry Woodman + */ + +#ifndef __KABI_H__ +#define __KABI_H__ + +/* Kernel macros for userspace testing. */ +#ifndef __aligned +#define __aligned(x) __attribute__((__aligned__(x))) +#endif +#ifndef __used +#define __used __attribute__((__used__)) +#endif +#ifndef __section +#define __section(section) __attribute__((__section__(section))) +#endif +#ifndef __PASTE +#define ___PASTE(a, b) a##b +#define __PASTE(a, b) ___PASTE(a, b) +#endif +#ifndef __stringify +#define __stringify_1(x...) #x +#define __stringify(x...) __stringify_1(x) +#endif + +#define __KABI_RULE(hint, target, value) \ + static const char __PASTE(__gendwarfksyms_rule_, \ + __COUNTER__)[] __used __aligned(1) \ + __section(".discard.gendwarfksyms.kabi_rules") =3D \ + "1\0" #hint "\0" #target "\0" #value + +/* + * KABI_DECLONLY(fqn) + * Treat the struct/union/enum fqn as a declaration, i.e. even if + * a definition is available, don't expand the contents. + */ +#define KABI_DECLONLY(fqn) __KABI_RULE(declonly, fqn, ) + +/* + * KABI_ENUMERATOR_IGNORE(fqn, field) + * When expanding enum fqn, skip the provided field. This makes it + * possible to hide added enum fields from versioning. + */ +#define KABI_ENUMERATOR_IGNORE(fqn, field) \ + __KABI_RULE(enumerator_ignore, fqn field, ) + +/* + * KABI_ENUMERATOR_VALUE(fqn, field, value) + * When expanding enum fqn, use the provided value for the + * specified field. This makes it possible to override enumerator + * values when calculating versions. + */ +#define KABI_ENUMERATOR_VALUE(fqn, field, value) \ + __KABI_RULE(enumerator_value, fqn field, value) + +#endif /* __KABI_H__ */ diff --git a/scripts/gendwarfksyms/examples/kabi_ex.c b/scripts/gendwarfksy= ms/examples/kabi_ex.c new file mode 100644 index 000000000000..799552ea6679 --- /dev/null +++ b/scripts/gendwarfksyms/examples/kabi_ex.c @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * kabi_ex.c + * + * Copyright (C) 2024 Google LLC + * + * Examples for kABI stability features with --stable. See kabi_ex.h + * for details. + */ + +#include "kabi_ex.h" + +struct s e0; +enum e e1; diff --git a/scripts/gendwarfksyms/examples/kabi_ex.h b/scripts/gendwarfksy= ms/examples/kabi_ex.h new file mode 100644 index 000000000000..fca1e07c78e2 --- /dev/null +++ b/scripts/gendwarfksyms/examples/kabi_ex.h @@ -0,0 +1,64 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * kabi_ex.h + * + * Copyright (C) 2024 Google LLC + * + * Examples for kABI stability features with --stable. + */ + +/* + * The comments below each example contain the expected gendwarfksyms + * output, which can be verified using LLVM's FileCheck tool: + * + * https://llvm.org/docs/CommandGuide/FileCheck.html + * + * Usage: + * + * $ gcc -g -c examples/kabi_ex.c -o examples/kabi_ex.o + * + * $ nm examples/kabi_ex.o | awk '{ print $NF }' | \ + * ./gendwarfksyms --stable --dump-dies \ + * examples/kabi_ex.o 2>&1 >/dev/null | \ + * FileCheck examples/kabi_ex.h --check-prefix=3DSTABLE + */ + +#ifndef __KABI_EX_H__ +#define __KABI_EX_H__ + +#include "kabi.h" + +/* + * Example: kABI rules + */ + +struct s { + int a; +}; + +KABI_DECLONLY(s); + +/* + * STABLE: variable structure_type s { + * STABLE-NEXT: } + */ + +enum e { + A, + B, + C, + D, +}; + +KABI_ENUMERATOR_IGNORE(e, B); +KABI_ENUMERATOR_IGNORE(e, C); +KABI_ENUMERATOR_VALUE(e, D, 123456789); + +/* + * STABLE: variable enumeration_type e { + * STABLE-NEXT: enumerator A =3D 0 , + * STABLE-NEXT: enumerator D =3D 123456789 + * STABLE-NEXT: } byte_size(4) + */ + +#endif /* __KABI_EX_H__ */ diff --git a/scripts/gendwarfksyms/gendwarfksyms.c b/scripts/gendwarfksyms/= gendwarfksyms.c index fd2429ea198f..25865d9eab56 100644 --- a/scripts/gendwarfksyms/gendwarfksyms.c +++ b/scripts/gendwarfksyms/gendwarfksyms.c @@ -25,6 +25,8 @@ int dump_die_map; int dump_types; /* Print out expanded type strings used for symbol versions */ int dump_versions; +/* Support kABI stability features */ +int stable; /* Write a symtypes file */ int symtypes; static const char *symtypes_file; @@ -38,6 +40,7 @@ static void usage(void) " --dump-die-map Print debugging information about die_map c= hanges\n" " --dump-types Dump type strings\n" " --dump-versions Dump expanded type strings used for symbol = versions\n" + " -s, --stable Support kABI stability features\n" " -T, --symtypes file Write a symtypes file\n" " -h, --help Print this message\n" "\n", @@ -97,17 +100,21 @@ int main(int argc, char **argv) { "dump-die-map", 0, &dump_die_map, 1 }, { "dump-types", 0, &dump_types, 1 }, { "dump-versions", 0, &dump_versions, 1 }, + { "stable", 0, NULL, 's' }, { "symtypes", 1, NULL, 'T' }, { "help", 0, NULL, 'h' }, { 0, 0, NULL, 0 } }; =20 - while ((opt =3D getopt_long(argc, argv, "dT:h", opts, NULL)) !=3D EOF) { + while ((opt =3D getopt_long(argc, argv, "dsT:h", opts, NULL)) !=3D EOF) { switch (opt) { case 0: break; case 'd': debug =3D 1; break; + case 's': + stable =3D 1; + break; case 'T': symtypes =3D 1; symtypes_file =3D optarg; @@ -148,6 +155,7 @@ int main(int argc, char **argv) strerror(errno)); =20 symbol_read_symtab(fd); + kabi_read_rules(fd); =20 dwfl =3D dwfl_begin(&callbacks); if (!dwfl) @@ -164,6 +172,7 @@ int main(int argc, char **argv) error("dwfl_getmodules failed for '%s'", argv[n]); =20 dwfl_end(dwfl); + kabi_free(); } =20 if (symfile) diff --git a/scripts/gendwarfksyms/gendwarfksyms.h b/scripts/gendwarfksyms/= gendwarfksyms.h index 203534abcd35..c0207ca10e19 100644 --- a/scripts/gendwarfksyms/gendwarfksyms.h +++ b/scripts/gendwarfksyms/gendwarfksyms.h @@ -24,6 +24,7 @@ extern int dump_dies; extern int dump_die_map; extern int dump_types; extern int dump_versions; +extern int stable; extern int symtypes; =20 /* @@ -232,6 +233,7 @@ static inline bool cache_was_expanded(struct cache *cac= he, void *addr) =20 struct expansion_state { bool expand; + const char *current_fqn; }; =20 struct state { @@ -263,4 +265,16 @@ void process_cu(Dwarf_Die *cudie); =20 void generate_symtypes_and_versions(FILE *file); =20 +/* + * kabi.c + */ + +bool kabi_is_enumerator_ignored(const char *fqn, const char *field); +bool kabi_get_enumerator_value(const char *fqn, const char *field, + unsigned long *value); +bool kabi_is_declonly(const char *fqn); + +void kabi_read_rules(int fd); +void kabi_free(void); + #endif /* __GENDWARFKSYMS_H */ diff --git a/scripts/gendwarfksyms/kabi.c b/scripts/gendwarfksyms/kabi.c new file mode 100644 index 000000000000..66f01fcd1607 --- /dev/null +++ b/scripts/gendwarfksyms/kabi.c @@ -0,0 +1,336 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2024 Google LLC + */ + +#define _GNU_SOURCE +#include +#include + +#include "gendwarfksyms.h" + +#define KABI_RULE_SECTION ".discard.gendwarfksyms.kabi_rules" +#define KABI_RULE_VERSION "1" + +/* + * The rule section consists of four null-terminated strings per + * entry: + * + * 1. version + * Entry format version. Must match KABI_RULE_VERSION. + * + * 2. type + * Type of the kABI rule. Must be one of the tags defined below. + * + * 3. target + * Rule-dependent target, typically the fully qualified name of + * the target DIE. + * + * 4. value + * Rule-dependent value. + */ +#define KABI_RULE_MIN_ENTRY_SIZE \ + (/* version\0 */ 2 + /* type\0 */ 2 + /* target\0" */ 1 + \ + /* value\0 */ 1) +#define KABI_RULE_EMPTY_VALUE "" + +/* + * Rule: declonly + * - For the struct/enum/union in the target field, treat it as a + * declaration only even if a definition is available. + */ +#define KABI_RULE_TAG_DECLONLY "declonly" + +/* + * Rule: enumerator_ignore + * - For the enum_field in the target field, ignore the enumerator. + */ +#define KABI_RULE_TAG_ENUMERATOR_IGNORE "enumerator_ignore" + +/* + * Rule: enumerator_value + * - For the fqn_field in the target field, set the value to the + * unsigned integer in the value field. + */ +#define KABI_RULE_TAG_ENUMERATOR_VALUE "enumerator_value" + +enum kabi_rule_type { + KABI_RULE_TYPE_UNKNOWN, + KABI_RULE_TYPE_DECLONLY, + KABI_RULE_TYPE_ENUMERATOR_IGNORE, + KABI_RULE_TYPE_ENUMERATOR_VALUE, +}; + +#define RULE_HASH_BITS 7 + +struct rule { + enum kabi_rule_type type; + const char *target; + const char *value; + struct hlist_node hash; +}; + +/* { type, target } -> struct rule */ +static HASHTABLE_DEFINE(rules, 1 << RULE_HASH_BITS); + +static inline unsigned int rule_values_hash(enum kabi_rule_type type, + const char *target) +{ + return hash_32(type) ^ hash_str(target); +} + +static inline unsigned int rule_hash(const struct rule *rule) +{ + return rule_values_hash(rule->type, rule->target); +} + +static inline const char *get_rule_field(const char **pos, ssize_t *left) +{ + const char *start =3D *pos; + size_t len; + + if (*left <=3D 0) + error("unexpected end of kABI rules"); + + len =3D strnlen(start, *left) + 1; + *pos +=3D len; + *left -=3D len; + + return start; +} + +void kabi_read_rules(int fd) +{ + GElf_Shdr shdr_mem; + GElf_Shdr *shdr; + Elf_Data *rule_data =3D NULL; + Elf_Scn *scn; + Elf *elf; + size_t shstrndx; + const char *rule_str; + ssize_t left; + int i; + + const struct { + enum kabi_rule_type type; + const char *tag; + } rule_types[] =3D { + { + .type =3D KABI_RULE_TYPE_DECLONLY, + .tag =3D KABI_RULE_TAG_DECLONLY, + }, + { + .type =3D KABI_RULE_TYPE_ENUMERATOR_IGNORE, + .tag =3D KABI_RULE_TAG_ENUMERATOR_IGNORE, + }, + { + .type =3D KABI_RULE_TYPE_ENUMERATOR_VALUE, + .tag =3D KABI_RULE_TAG_ENUMERATOR_VALUE, + }, + }; + + if (!stable) + return; + + if (elf_version(EV_CURRENT) !=3D EV_CURRENT) + error("elf_version failed: %s", elf_errmsg(-1)); + + elf =3D elf_begin(fd, ELF_C_READ_MMAP, NULL); + if (!elf) + error("elf_begin failed: %s", elf_errmsg(-1)); + + if (elf_getshdrstrndx(elf, &shstrndx) < 0) + error("elf_getshdrstrndx failed: %s", elf_errmsg(-1)); + + scn =3D elf_nextscn(elf, NULL); + + while (scn) { + const char *sname; + + shdr =3D gelf_getshdr(scn, &shdr_mem); + if (!shdr) + error("gelf_getshdr failed: %s", elf_errmsg(-1)); + + sname =3D elf_strptr(elf, shstrndx, shdr->sh_name); + if (!sname) + error("elf_strptr failed: %s", elf_errmsg(-1)); + + if (!strcmp(sname, KABI_RULE_SECTION)) { + rule_data =3D elf_getdata(scn, NULL); + if (!rule_data) + error("elf_getdata failed: %s", elf_errmsg(-1)); + break; + } + + scn =3D elf_nextscn(elf, scn); + } + + if (!rule_data) { + debug("kABI rules not found"); + check(elf_end(elf)); + return; + } + + rule_str =3D rule_data->d_buf; + left =3D shdr->sh_size; + + if (left < KABI_RULE_MIN_ENTRY_SIZE) + error("kABI rule section too small: %zd bytes", left); + + if (rule_str[left - 1] !=3D '\0') + error("kABI rules are not null-terminated"); + + while (left > KABI_RULE_MIN_ENTRY_SIZE) { + enum kabi_rule_type type =3D KABI_RULE_TYPE_UNKNOWN; + const char *field; + struct rule *rule; + + /* version */ + field =3D get_rule_field(&rule_str, &left); + + if (strcmp(field, KABI_RULE_VERSION)) + error("unsupported kABI rule version: '%s'", field); + + /* type */ + field =3D get_rule_field(&rule_str, &left); + + for (i =3D 0; i < ARRAY_SIZE(rule_types); i++) { + if (!strcmp(field, rule_types[i].tag)) { + type =3D rule_types[i].type; + break; + } + } + + if (type =3D=3D KABI_RULE_TYPE_UNKNOWN) + error("unsupported kABI rule type: '%s'", field); + + rule =3D xmalloc(sizeof(struct rule)); + + rule->type =3D type; + rule->target =3D xstrdup(get_rule_field(&rule_str, &left)); + rule->value =3D xstrdup(get_rule_field(&rule_str, &left)); + + hash_add(rules, &rule->hash, rule_hash(rule)); + + debug("kABI rule: type: '%s', target: '%s', value: '%s'", field, + rule->target, rule->value); + } + + if (left > 0) + warn("unexpected data at the end of the kABI rules section"); + + check(elf_end(elf)); +} + +bool kabi_is_declonly(const char *fqn) +{ + struct rule *rule; + + if (!stable) + return false; + if (!fqn || !*fqn) + return false; + + hash_for_each_possible(rules, rule, hash, + rule_values_hash(KABI_RULE_TYPE_DECLONLY, fqn)) { + if (rule->type =3D=3D KABI_RULE_TYPE_DECLONLY && + !strcmp(fqn, rule->target)) + return true; + } + + return false; +} + +static char *get_enumerator_target(const char *fqn, const char *field) +{ + char *target =3D NULL; + + if (asprintf(&target, "%s %s", fqn, field) < 0) + error("asprintf failed for '%s %s'", fqn, field); + + return target; +} + +static unsigned long get_ulong_value(const char *value) +{ + unsigned long result =3D 0; + char *endptr =3D NULL; + + errno =3D 0; + result =3D strtoul(value, &endptr, 10); + + if (errno || *endptr) + error("invalid unsigned value '%s'", value); + + return result; +} + +bool kabi_is_enumerator_ignored(const char *fqn, const char *field) +{ + bool match =3D false; + struct rule *rule; + char *target; + + if (!stable) + return false; + if (!fqn || !*fqn || !field || !*field) + return false; + + target =3D get_enumerator_target(fqn, field); + + hash_for_each_possible( + rules, rule, hash, + rule_values_hash(KABI_RULE_TYPE_ENUMERATOR_IGNORE, target)) { + if (rule->type =3D=3D KABI_RULE_TYPE_ENUMERATOR_IGNORE && + !strcmp(target, rule->target)) { + match =3D true; + break; + } + } + + free(target); + return match; +} + +bool kabi_get_enumerator_value(const char *fqn, const char *field, + unsigned long *value) +{ + bool match =3D false; + struct rule *rule; + char *target; + + if (!stable) + return false; + if (!fqn || !*fqn || !field || !*field) + return false; + + target =3D get_enumerator_target(fqn, field); + + hash_for_each_possible(rules, rule, hash, + rule_values_hash(KABI_RULE_TYPE_ENUMERATOR_VALUE, + target)) { + if (rule->type =3D=3D KABI_RULE_TYPE_ENUMERATOR_VALUE && + !strcmp(target, rule->target)) { + *value =3D get_ulong_value(rule->value); + match =3D true; + break; + } + } + + free(target); + return match; +} + +void kabi_free(void) +{ + struct hlist_node *tmp; + struct rule *rule; + + hash_for_each_safe(rules, rule, tmp, hash) { + free((void *)rule->target); + free((void *)rule->value); + free(rule); + } + + hash_init(rules); +} --=20 2.47.1.613.gc27f4b7a9f-goog From nobody Mon Feb 9 13:01:05 2026 Received: from mail-pj1-f73.google.com (mail-pj1-f73.google.com [209.85.216.73]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 970E61BEF81 for ; Thu, 19 Dec 2024 21:08:13 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.216.73 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734642496; cv=none; b=O+EMEmhuxJMN9NWvzD9kwf8ryEZU3YxQqDvqDT8x2BmHdxYkg0JZ+rkSZndTwyoHnmoPnhPZXY2YVqX/Io+L68Y03e38GP4Y9U8mC3txowY7gKPpQ6M9qGUE18zmZe7dlUYpaywVGSXMpcbk6k0YecnBHhvGVN5EQDCHOzVGQqk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734642496; c=relaxed/simple; bh=7W2aGp05kJKnJUD6bZE4MziFgiLMkwgrNufoHK2Xnt0=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=l7r7ZCPfldiLHCs26QX2RBzdKpjRnnXPWMIumnpdlIDFRXuZBnVNopCS6RvHu+3JaoxgzgHnGyoMClKSs1QhyD835DlwsG9PHE3gkuZDRFq2zrEhVLwr1+rK9x83ZYhH22WMtQGiS6YcMF7WsVVNYYaLiWCtlX652UgYU5bQ4RY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--samitolvanen.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=RmdSrL6e; arc=none smtp.client-ip=209.85.216.73 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--samitolvanen.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="RmdSrL6e" Received: by mail-pj1-f73.google.com with SMTP id 98e67ed59e1d1-2ee5668e09bso1136023a91.3 for ; Thu, 19 Dec 2024 13:08:13 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1734642493; x=1735247293; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=tUuRzCa6rGp0zLolmMgSi+Fq+2YRWA9tSP3uXfn3qjQ=; b=RmdSrL6eLsy5LvE2UwXJPdQ2wyGx40Pf3am6HX8bk33cpB4p/rWRhDl9QWBDEffCpk 50b0u1FOHgO9DubwHhVL/NP4PxdTC8utsrn9mNnEpiMB2yQJEb98RDTw9VLXD2vB3M6m KZbPsz+wd71jy61Q64CG7Z+99Iu4V/Y4c2qm4SIjSK2IHpcfDK25A9Xow4PJ8rSJcR7+ S88zvUJODWjWCWHp3W6K7w+oc1QF74wLw0/oSaBqsepusKDkiJATWpsrrPzxS5qXiDrf F0efk3fQARkaUsj8jaX/exJVJqrE8mvsp3fy9jmt3pWFkpFVbOZty7URoZOK+I3zsnB8 YVIw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1734642493; x=1735247293; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=tUuRzCa6rGp0zLolmMgSi+Fq+2YRWA9tSP3uXfn3qjQ=; b=t4iBWVN8SGAx/gG0p0YPDA1POcTj4V6NYkkhtMk9R/f3KMpJiOfL/UMQ0LQaouEkHt 7MfcfwaPRYRGPzoko9ru7rRdjch3JgNzWu1u3oM88HYbSKbDB9Yx2iz+4OQpsYDcmE8t cs6ttf8V4Qq02Ds4fwp47PbA5g3hR6zYqrAhaYlceVDYdzF3ZCD/iA3LF6X2CInFHvwB RhgIRNe43+BaC64+tCESvzeXY1XmaCfeCaYjBM13CQHcLMnEMnIw0EO8sB/AputSUZW8 smCJy7KYPim1jBXHIbfQL3iEzntKEVoNh/fepUSy5GlskWJqLpXee+Gngd36XPOovkSS TC1Q== X-Forwarded-Encrypted: i=1; AJvYcCWcYEAMidLywEnGa/2WSLW7U26FjOZiACty1euQBfFCtm6b+jWpWlEQM78ORchkOIvkqUh9SZxzlpy2K2g=@vger.kernel.org X-Gm-Message-State: AOJu0YzkBtayNy1RFqs5pyvy2lGFUAIZTntTTaIDS6vaCQ4VheQUdhQ2 3iVrzGc22YJom80kqIg2hllPS6m0Doa7KRPchP9SvCd1/ncsoZiMqvYhWyMs3mI/iu9kQ/+2JvJ Yd4bRrnsHdCcUlv1DvR+7daYyuQ== X-Google-Smtp-Source: AGHT+IE2fhrtt79thMb1vL08eWfwNpNMt0TyMwXbZKH8l0+d4VQODMdXV7LsdsyMG3Bk4FCHvZOBKWKl2M1ReUHFKxY= X-Received: from pjbsk3.prod.google.com ([2002:a17:90b:2dc3:b0:2ea:5084:5297]) (user=samitolvanen job=prod-delivery.src-stubby-dispatcher) by 2002:a17:90a:d88c:b0:2ee:94d1:7a9d with SMTP id 98e67ed59e1d1-2f452eed6cemr613447a91.32.1734642492871; Thu, 19 Dec 2024 13:08:12 -0800 (PST) Date: Thu, 19 Dec 2024 21:07:51 +0000 In-Reply-To: <20241219210736.2990838-20-samitolvanen@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20241219210736.2990838-20-samitolvanen@google.com> X-Developer-Key: i=samitolvanen@google.com; a=openpgp; fpr=35CCFB63B283D6D3AEB783944CB5F6848BBC56EE X-Developer-Signature: v=1; a=openpgp-sha256; l=22891; i=samitolvanen@google.com; h=from:subject; bh=7W2aGp05kJKnJUD6bZE4MziFgiLMkwgrNufoHK2Xnt0=; b=owGbwMvMwCEWxa662nLh8irG02pJDOkp3QqhRbKzbJLnduzYorlGb+Imtqfz3V+FLqsyeKzWo xE6SflrRykLgxgHg6yYIkvL19Vbd393Sn31uUgCZg4rE8gQBi5OAZhIzUGG/0H5Cr12Al/iDdbF MR2rKPfYPu8XS9jp5Xfm7GcpFmjhcGBk2N6RMYHbf9beiFwFG9Zv1dME5rRFrL19Li30cAaj5I1 TjAA= X-Mailer: git-send-email 2.47.1.613.gc27f4b7a9f-goog Message-ID: <20241219210736.2990838-34-samitolvanen@google.com> Subject: [PATCH v7 14/18] gendwarfksyms: Add support for reserved and ignored fields From: Sami Tolvanen To: Masahiro Yamada , Luis Chamberlain , Miguel Ojeda , Greg Kroah-Hartman Cc: Matthew Maurer , Alex Gaynor , Gary Guo , Petr Pavlu , Daniel Gomez , Neal Gompa , Hector Martin , Janne Grunau , Miroslav Benes , Asahi Linux , Sedat Dilek , linux-kbuild@vger.kernel.org, linux-kernel@vger.kernel.org, linux-modules@vger.kernel.org, rust-for-linux@vger.kernel.org, Sami Tolvanen Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Distributions that want to maintain a stable kABI need the ability to make ABI compatible changes to kernel data structures without affecting symbol versions, either because of LTS updates or backports. With genksyms, developers would typically hide these changes from version calculation with #ifndef __GENKSYMS__, which would result in the symbol version not changing even though the actual type has changed. When we process precompiled object files, this isn't an option. Change union processing to recognize field name prefixes that allow the user to ignore the union completely during symbol versioning with a __kabi_ignored prefix in a field name, or to replace the type of a placeholder field using a __kabi_reserved field name prefix. For example, assume we want to add a new field to an existing alignment hole in a data structure, and ignore the new field when calculating symbol versions: struct struct1 { int a; /* a 4-byte alignment hole */ unsigned long b; }; To add `int n` to the alignment hole, we can add a union that includes a __kabi_ignored field that causes gendwarfksyms to ignore the entire union: struct struct1 { int a; union { char __kabi_ignored_0; int n; }; unsigned long b; }; With --stable, both structs produce the same symbol version. Alternatively, when a distribution expects future modification to a data structure, they can explicitly add reserved fields: struct struct2 { long a; long __kabi_reserved_0; /* reserved for future use */ }; To take the field into use, we can again replace it with a union, with one of the fields keeping the __kabi_reserved name prefix to indicate the original type: struct struct2 { long a; union { long __kabi_reserved_0; struct { int b; int v; }; }; Here gendwarfksyms --stable replaces the union with the type of the placeholder field when calculating versions. Signed-off-by: Sami Tolvanen Reviewed-by: Petr Pavlu --- scripts/gendwarfksyms/dwarf.c | 248 ++++++++++++++++++++++- scripts/gendwarfksyms/examples/kabi.h | 87 ++++++++ scripts/gendwarfksyms/examples/kabi_ex.c | 16 ++ scripts/gendwarfksyms/examples/kabi_ex.h | 199 ++++++++++++++++++ scripts/gendwarfksyms/gendwarfksyms.h | 9 + 5 files changed, 558 insertions(+), 1 deletion(-) diff --git a/scripts/gendwarfksyms/dwarf.c b/scripts/gendwarfksyms/dwarf.c index 17f7e6b9a7ff..746a89d9e3d4 100644 --- a/scripts/gendwarfksyms/dwarf.c +++ b/scripts/gendwarfksyms/dwarf.c @@ -3,10 +3,33 @@ * Copyright (C) 2024 Google LLC */ =20 +#include #include #include #include "gendwarfksyms.h" =20 +/* See get_union_kabi_status */ +#define KABI_PREFIX "__kabi_" +#define KABI_PREFIX_LEN (sizeof(KABI_PREFIX) - 1) +#define KABI_RESERVED_PREFIX "reserved" +#define KABI_RESERVED_PREFIX_LEN (sizeof(KABI_RESERVED_PREFIX) - 1) +#define KABI_RENAMED_PREFIX "renamed" +#define KABI_RENAMED_PREFIX_LEN (sizeof(KABI_RENAMED_PREFIX) - 1) +#define KABI_IGNORED_PREFIX "ignored" +#define KABI_IGNORED_PREFIX_LEN (sizeof(KABI_IGNORED_PREFIX) - 1) + +static inline bool is_kabi_prefix(const char *name) +{ + return name && !strncmp(name, KABI_PREFIX, KABI_PREFIX_LEN); +} + +enum kabi_status { + /* >0 to stop DIE processing */ + KABI_NORMAL =3D 1, + KABI_RESERVED, + KABI_IGNORED, +}; + static bool do_linebreak; static int indentation_level; =20 @@ -353,13 +376,23 @@ static void __process_list_type(struct state *state, = struct die *cache, { const char *name =3D get_name_attr(die); =20 + if (stable) { + if (is_kabi_prefix(name)) + name =3D NULL; + state->kabi.orig_name =3D NULL; + } + process_list_comma(state, cache); process(cache, type); process_type_attr(state, cache, die); + + if (stable && state->kabi.orig_name) + name =3D state->kabi.orig_name; if (name) { process(cache, " "); process(cache, name); } + process_accessibility_attr(cache, die); process_bit_size_attr(cache, die); process_data_bit_offset_attr(cache, die); @@ -486,11 +519,208 @@ static void process_variant_part_type(struct state *= state, struct die *cache, process(cache, "}"); } =20 +static int get_kabi_status(Dwarf_Die *die, const char **suffix) +{ + const char *name =3D get_name_attr(die); + + if (suffix) + *suffix =3D NULL; + + if (is_kabi_prefix(name)) { + name +=3D KABI_PREFIX_LEN; + + if (!strncmp(name, KABI_RESERVED_PREFIX, + KABI_RESERVED_PREFIX_LEN)) + return KABI_RESERVED; + if (!strncmp(name, KABI_IGNORED_PREFIX, + KABI_IGNORED_PREFIX_LEN)) + return KABI_IGNORED; + + if (!strncmp(name, KABI_RENAMED_PREFIX, + KABI_RENAMED_PREFIX_LEN)) { + if (suffix) { + name +=3D KABI_RENAMED_PREFIX_LEN; + *suffix =3D name; + } + return KABI_RESERVED; + } + } + + return KABI_NORMAL; +} + +static int check_struct_member_kabi_status(struct state *state, + struct die *__unused, Dwarf_Die *die) +{ + int res; + + assert(dwarf_tag(die) =3D=3D DW_TAG_member_type); + + /* + * If the union member is a struct, expect the __kabi field to + * be the first member of the structure, i.e..: + * + * union { + * type new_member; + * struct { + * type __kabi_field; + * } + * }; + */ + res =3D get_kabi_status(die, &state->kabi.orig_name); + + if (res =3D=3D KABI_RESERVED && + !get_ref_die_attr(die, DW_AT_type, &state->kabi.placeholder)) + error("structure member missing a type?"); + + return res; +} + +static int check_union_member_kabi_status(struct state *state, + struct die *__unused, Dwarf_Die *die) +{ + Dwarf_Die type; + int res; + + assert(dwarf_tag(die) =3D=3D DW_TAG_member_type); + + if (!get_ref_die_attr(die, DW_AT_type, &type)) + error("union member missing a type?"); + + /* + * We expect a union with two members. Check if either of them + * has a __kabi name prefix, i.e.: + * + * union { + * ... + * type memberN; // <- type, N =3D {0,1} + * ... + * }; + * + * The member can also be a structure type, in which case we'll + * check the first structure member. + * + * In any case, stop processing after we've seen two members. + */ + res =3D get_kabi_status(die, &state->kabi.orig_name); + + if (res =3D=3D KABI_RESERVED) + state->kabi.placeholder =3D type; + if (res !=3D KABI_NORMAL) + return res; + + if (dwarf_tag(&type) =3D=3D DW_TAG_structure_type) + res =3D checkp(process_die_container( + state, NULL, &type, check_struct_member_kabi_status, + match_member_type)); + + if (res <=3D KABI_NORMAL && ++state->kabi.members < 2) + return 0; /* Continue */ + + return res; +} + +static int get_union_kabi_status(Dwarf_Die *die, Dwarf_Die *placeholder, + const char **orig_name) +{ + struct state state; + int res; + + if (!stable) + return KABI_NORMAL; + + /* + * To maintain a stable kABI, distributions may choose to reserve + * space in structs for later use by adding placeholder members, + * for example: + * + * struct s { + * u32 a; + * // an 8-byte placeholder for future use + * u64 __kabi_reserved_0; + * }; + * + * When the reserved member is taken into use, the type change + * would normally cause the symbol version to change as well, but + * if the replacement uses the following convention, gendwarfksyms + * continues to use the placeholder type for versioning instead, + * thus maintaining the same symbol version: + * + * struct s { + * u32 a; + * union { + * // placeholder replaced with a new member `b` + * struct t b; + * struct { + * // the placeholder type that is still + * // used for versioning + * u64 __kabi_reserved_0; + * }; + * }; + * }; + * + * I.e., as long as the replaced member is in a union, and the + * placeholder has a __kabi_reserved name prefix, we'll continue + * to use the placeholder type (here u64) for version calculation + * instead of the union type. + * + * It's also possible to ignore new members from versioning if + * they've been added to alignment holes, for example, by + * including them in a union with another member that uses the + * __kabi_ignored name prefix: + * + * struct s { + * u32 a; + * // an alignment hole is used to add `n` + * union { + * u32 n; + * // hide the entire union member from versioning + * u8 __kabi_ignored_0; + * }; + * u64 b; + * }; + * + * Note that the user of this feature is responsible for ensuring + * that the structure actually remains ABI compatible. + */ + memset(&state.kabi, 0, sizeof(struct kabi_state)); + + res =3D checkp(process_die_container(&state, NULL, die, + check_union_member_kabi_status, + match_member_type)); + + if (res =3D=3D KABI_RESERVED) { + if (placeholder) + *placeholder =3D state.kabi.placeholder; + if (orig_name) + *orig_name =3D state.kabi.orig_name; + } + + return res; +} + +static bool is_kabi_ignored(Dwarf_Die *die) +{ + Dwarf_Die type; + + if (!stable) + return false; + + if (!get_ref_die_attr(die, DW_AT_type, &type)) + error("member missing a type?"); + + return dwarf_tag(&type) =3D=3D DW_TAG_union_type && + checkp(get_union_kabi_status(&type, NULL, NULL)) =3D=3D KABI_IGNOR= ED; +} + static int ___process_structure_type(struct state *state, struct die *cach= e, Dwarf_Die *die) { switch (dwarf_tag(die)) { case DW_TAG_member: + if (is_kabi_ignored(die)) + return 0; + return check(process_type(state, cache, die)); case DW_TAG_variant_part: return check(process_type(state, cache, die)); case DW_TAG_class_type: @@ -547,7 +777,23 @@ static void __process_structure_type(struct state *sta= te, struct die *cache, =20 DEFINE_PROCESS_STRUCTURE_TYPE(class) DEFINE_PROCESS_STRUCTURE_TYPE(structure) -DEFINE_PROCESS_STRUCTURE_TYPE(union) + +static void process_union_type(struct state *state, struct die *cache, + Dwarf_Die *die) +{ + Dwarf_Die placeholder; + + int res =3D checkp(get_union_kabi_status(die, &placeholder, + &state->kabi.orig_name)); + + if (res =3D=3D KABI_RESERVED) + check(process_type(state, cache, &placeholder)); + if (res > KABI_NORMAL) + return; + + __process_structure_type(state, cache, die, "union_type", + ___process_structure_type, match_all); +} =20 static void process_enumerator_type(struct state *state, struct die *cache, Dwarf_Die *die) diff --git a/scripts/gendwarfksyms/examples/kabi.h b/scripts/gendwarfksyms/= examples/kabi.h index fcd0300e5b58..97a5669b083d 100644 --- a/scripts/gendwarfksyms/examples/kabi.h +++ b/scripts/gendwarfksyms/examples/kabi.h @@ -43,6 +43,28 @@ __section(".discard.gendwarfksyms.kabi_rules") =3D \ "1\0" #hint "\0" #target "\0" #value =20 +#define __KABI_NORMAL_SIZE_ALIGN(_orig, _new) = \ + union { = \ + _Static_assert( = \ + sizeof(struct { _new; }) <=3D sizeof(struct { _orig; }), \ + __FILE__ ":" __stringify(__LINE__) ": " __stringify( \ + _new) " is larger than " __stringify(_orig)); \ + _Static_assert( = \ + __alignof__(struct { _new; }) <=3D \ + __alignof__(struct { _orig; }), \ + __FILE__ ":" __stringify(__LINE__) ": " __stringify( \ + _orig) " is not aligned the same as " __stringify(_new)); \ + } + +#define __KABI_REPLACE(_orig, _new) \ + union { \ + _new; \ + struct { \ + _orig; \ + }; \ + __KABI_NORMAL_SIZE_ALIGN(_orig, _new); \ + } + /* * KABI_DECLONLY(fqn) * Treat the struct/union/enum fqn as a declaration, i.e. even if @@ -67,4 +89,69 @@ #define KABI_ENUMERATOR_VALUE(fqn, field, value) \ __KABI_RULE(enumerator_value, fqn field, value) =20 +/* + * KABI_RESERVE + * Reserve some "padding" in a structure for use by LTS backports. + * This is normally placed at the end of a structure. + * number: the "number" of the padding variable in the structure. Start= with + * 1 and go up. + */ +#define KABI_RESERVE(n) unsigned long __kabi_reserved##n + +/* + * KABI_RESERVE_ARRAY + * Same as _BACKPORT_RESERVE but allocates an array with the specified + * size in bytes. + */ +#define KABI_RESERVE_ARRAY(n, s) \ + unsigned char __aligned(8) __kabi_reserved##n[s] + +/* + * KABI_IGNORE + * Add a new field that's ignored in versioning. + */ +#define KABI_IGNORE(n, _new) \ + union { \ + _new; \ + unsigned char __kabi_ignored##n; \ + } + +/* + * KABI_REPLACE + * Replace a field with a compatible new field. + */ +#define KABI_REPLACE(_oldtype, _oldname, _new) \ + __KABI_REPLACE(_oldtype __kabi_renamed##_oldname, struct { _new; }) + +/* + * KABI_USE(number, _new) + * Use a previous padding entry that was defined with KABI_RESERVE + * number: the previous "number" of the padding variable + * _new: the variable to use now instead of the padding variable + */ +#define KABI_USE(number, _new) __KABI_REPLACE(KABI_RESERVE(number), _new) + +/* + * KABI_USE2(number, _new1, _new2) + * Use a previous padding entry that was defined with KABI_RESERVE for + * two new variables that fit into 64 bits. This is good for when you d= o not + * want to "burn" a 64bit padding variable for a smaller variable size i= f not + * needed. + */ +#define KABI_USE2(number, _new1, _new2) \ + __KABI_REPLACE( \ + KABI_RESERVE(number), struct { \ + _new1; \ + _new2; \ + }) +/* + * KABI_USE_ARRAY(number, bytes, _new) + * Use a previous padding entry that was defined with KABI_RESERVE_ARRAY + * number: the previous "number" of the padding variable + * bytes: the size in bytes reserved for the array + * _new: the variable to use now instead of the padding variable + */ +#define KABI_USE_ARRAY(number, bytes, _new) \ + __KABI_REPLACE(KABI_RESERVE_ARRAY(number, bytes), _new) + #endif /* __KABI_H__ */ diff --git a/scripts/gendwarfksyms/examples/kabi_ex.c b/scripts/gendwarfksy= ms/examples/kabi_ex.c index 799552ea6679..0b7ffd830541 100644 --- a/scripts/gendwarfksyms/examples/kabi_ex.c +++ b/scripts/gendwarfksyms/examples/kabi_ex.c @@ -12,3 +12,19 @@ =20 struct s e0; enum e e1; + +struct ex0a ex0a; +struct ex0b ex0b; +struct ex0c ex0c; + +struct ex1a ex1a; +struct ex1b ex1b; +struct ex1c ex1c; + +struct ex2a ex2a; +struct ex2b ex2b; +struct ex2c ex2c; + +struct ex3a ex3a; +struct ex3b ex3b; +struct ex3c ex3c; diff --git a/scripts/gendwarfksyms/examples/kabi_ex.h b/scripts/gendwarfksy= ms/examples/kabi_ex.h index fca1e07c78e2..1736e0f65208 100644 --- a/scripts/gendwarfksyms/examples/kabi_ex.h +++ b/scripts/gendwarfksyms/examples/kabi_ex.h @@ -59,6 +59,205 @@ KABI_ENUMERATOR_VALUE(e, D, 123456789); * STABLE-NEXT: enumerator A =3D 0 , * STABLE-NEXT: enumerator D =3D 123456789 * STABLE-NEXT: } byte_size(4) +*/ + +/* + * Example: Reserved fields + */ +struct ex0a { + int a; + KABI_RESERVE(0); + KABI_RESERVE(1); +}; + +/* + * STABLE: variable structure_type ex0a { + * STABLE-NEXT: member base_type int byte_size(4) encoding(5) a data_mem= ber_location(0) , + * STABLE-NEXT: member base_type [[ULONG:long unsigned int|unsigned long= ]] byte_size(8) encoding(7) data_member_location(8) , + * STABLE-NEXT: member base_type [[ULONG]] byte_size(8) encoding(7) data= _member_location(16) + * STABLE-NEXT: } byte_size(24) + */ + +struct ex0b { + int a; + KABI_RESERVE(0); + KABI_USE2(1, int b, int c); +}; + +/* + * STABLE: variable structure_type ex0b { + * STABLE-NEXT: member base_type int byte_size(4) encoding(5) a data_mem= ber_location(0) , + * STABLE-NEXT: member base_type [[ULONG]] byte_size(8) encoding(7) data= _member_location(8) , + * STABLE-NEXT: member base_type [[ULONG]] byte_size(8) encoding(7) data= _member_location(16) + * STABLE-NEXT: } byte_size(24) + */ + +struct ex0c { + int a; + KABI_USE(0, void *p); + KABI_USE2(1, int b, int c); +}; + +/* + * STABLE: variable structure_type ex0c { + * STABLE-NEXT: member base_type int byte_size(4) encoding(5) a data_mem= ber_location(0) , + * STABLE-NEXT: member base_type [[ULONG]] byte_size(8) encoding(7) data= _member_location(8) , + * STABLE-NEXT: member base_type [[ULONG]] byte_size(8) encoding(7) data= _member_location(16) + * STABLE-NEXT: } byte_size(24) + */ + +/* + * Example: A reserved array + */ + +struct ex1a { + unsigned int a; + KABI_RESERVE_ARRAY(0, 64); +}; + +/* + * STABLE: variable structure_type ex1a { + * STABLE-NEXT: member base_type unsigned int byte_size(4) encoding(7) a= data_member_location(0) , + * STABLE-NEXT: member array_type[64] { + * STABLE-NEXT: base_type unsigned char byte_size(1) encoding(8) + * STABLE-NEXT: } data_member_location(8) + * STABLE-NEXT: } byte_size(72) + */ + +struct ex1b { + unsigned int a; + KABI_USE_ARRAY( + 0, 64, struct { + void *p; + KABI_RESERVE_ARRAY(1, 56); + }); +}; + +/* + * STABLE: variable structure_type ex1b { + * STABLE-NEXT: member base_type unsigned int byte_size(4) encoding(7) a= data_member_location(0) , + * STABLE-NEXT: member array_type[64] { + * STABLE-NEXT: base_type unsigned char byte_size(1) encoding(8) + * STABLE-NEXT: } data_member_location(8) + * STABLE-NEXT: } byte_size(72) + */ + +struct ex1c { + unsigned int a; + KABI_USE_ARRAY(0, 64, void *p[8]); +}; + +/* + * STABLE: variable structure_type ex1c { + * STABLE-NEXT: member base_type unsigned int byte_size(4) encoding(7) a= data_member_location(0) , + * STABLE-NEXT: member array_type[64] { + * STABLE-NEXT: base_type unsigned char byte_size(1) encoding(8) + * STABLE-NEXT: } data_member_location(8) + * STABLE-NEXT: } byte_size(72) + */ + +/* + * Example: An ignored field added to an alignment hole + */ + +struct ex2a { + int a; + unsigned long b; + int c; + unsigned long d; +}; + +/* + * STABLE: variable structure_type ex2a { + * STABLE-NEXT: member base_type int byte_size(4) encoding(5) a data_mem= ber_location(0) , + * STABLE-NEXT: member base_type [[ULONG:long unsigned int|unsigned long= ]] byte_size(8) encoding(7) b data_member_location(8) + * STABLE-NEXT: member base_type int byte_size(4) encoding(5) c data_mem= ber_location(16) , + * STABLE-NEXT: member base_type [[ULONG]] byte_size(8) encoding(7) d da= ta_member_location(24) + * STABLE-NEXT: } byte_size(32) + */ + +struct ex2b { + int a; + KABI_IGNORE(0, unsigned int n); + unsigned long b; + int c; + unsigned long d; +}; + +_Static_assert(sizeof(struct ex2a) =3D=3D sizeof(struct ex2b), "ex2a size = doesn't match ex2b"); + +/* + * STABLE: variable structure_type ex2b { + * STABLE-NEXT: member base_type int byte_size(4) encoding(5) a data_mem= ber_location(0) , + * STABLE-NEXT: member base_type [[ULONG]] byte_size(8) encoding(7) b da= ta_member_location(8) + * STABLE-NEXT: member base_type int byte_size(4) encoding(5) c data_mem= ber_location(16) , + * STABLE-NEXT: member base_type [[ULONG]] byte_size(8) encoding(7) d da= ta_member_location(24) + * STABLE-NEXT: } byte_size(32) + */ + +struct ex2c { + int a; + KABI_IGNORE(0, unsigned int n); + unsigned long b; + int c; + KABI_IGNORE(1, unsigned int m); + unsigned long d; +}; + +_Static_assert(sizeof(struct ex2a) =3D=3D sizeof(struct ex2c), "ex2a size = doesn't match ex2c"); + +/* + * STABLE: variable structure_type ex2c { + * STABLE-NEXT: member base_type int byte_size(4) encoding(5) a data_mem= ber_location(0) , + * STABLE-NEXT: member base_type [[ULONG]] byte_size(8) encoding(7) b da= ta_member_location(8) + * STABLE-NEXT: member base_type int byte_size(4) encoding(5) c data_mem= ber_location(16) , + * STABLE-NEXT: member base_type [[ULONG]] byte_size(8) encoding(7) d da= ta_member_location(24) + * STABLE-NEXT: } byte_size(32) + */ + + +/* + * Example: A replaced field + */ + +struct ex3a { + unsigned long a; + unsigned long unused; +}; + +/* + * STABLE: variable structure_type ex3a { + * STABLE-NEXT: member base_type [[ULONG:long unsigned int|unsigned long= ]] byte_size(8) encoding(7) a data_member_location(0) + * STABLE-NEXT: member base_type [[ULONG]] byte_size(8) encoding(7) unus= ed data_member_location(8) + * STABLE-NEXT: } byte_size(16) + */ + +struct ex3b { + unsigned long a; + KABI_REPLACE(unsigned long, unused, unsigned long renamed); +}; + +_Static_assert(sizeof(struct ex3a) =3D=3D sizeof(struct ex3b), "ex3a size = doesn't match ex3b"); + +/* + * STABLE: variable structure_type ex3b { + * STABLE-NEXT: member base_type [[ULONG]] byte_size(8) encoding(7) a da= ta_member_location(0) + * STABLE-NEXT: member base_type [[ULONG]] byte_size(8) encoding(7) unus= ed data_member_location(8) + * STABLE-NEXT: } byte_size(16) + */ + +struct ex3c { + unsigned long a; + KABI_REPLACE(unsigned long, unused, long replaced); +}; + +_Static_assert(sizeof(struct ex3a) =3D=3D sizeof(struct ex3c), "ex3a size = doesn't match ex3c"); + +/* + * STABLE: variable structure_type ex3c { + * STABLE-NEXT: member base_type [[ULONG]] byte_size(8) encoding(7) a da= ta_member_location(0) + * STABLE-NEXT: member base_type [[ULONG]] byte_size(8) encoding(7) unus= ed data_member_location(8) + * STABLE-NEXT: } byte_size(16) */ =20 #endif /* __KABI_EX_H__ */ diff --git a/scripts/gendwarfksyms/gendwarfksyms.h b/scripts/gendwarfksyms/= gendwarfksyms.h index c0207ca10e19..fe49730fe623 100644 --- a/scripts/gendwarfksyms/gendwarfksyms.h +++ b/scripts/gendwarfksyms/gendwarfksyms.h @@ -236,6 +236,12 @@ struct expansion_state { const char *current_fqn; }; =20 +struct kabi_state { + int members; + Dwarf_Die placeholder; + const char *orig_name; +}; + struct state { struct symbol *sym; Dwarf_Die die; @@ -246,6 +252,9 @@ struct state { /* Structure expansion */ struct expansion_state expand; struct cache expansion_cache; + + /* Reserved or ignored members */ + struct kabi_state kabi; }; =20 typedef int (*die_callback_t)(struct state *state, struct die *cache, --=20 2.47.1.613.gc27f4b7a9f-goog From nobody Mon Feb 9 13:01:05 2026 Received: from mail-pl1-f202.google.com (mail-pl1-f202.google.com [209.85.214.202]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 053461FF1C1 for ; Thu, 19 Dec 2024 21:08:14 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.202 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734642498; cv=none; b=pIsHfLronhB6XbvnoHjOcSbhM4RpZuYY0Um8VXUnM446YD1EfQpTDxa4Muw7ofv8y78KU8z7MUQ+L3IDIGwc5D8N9/csevEO3ECvE0urEF4fdVt5JV58mITf1OceY6U2V5+MGUfRo7zZ7lImEAJxxuAnet/89/zN4p5GiB2NimM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734642498; c=relaxed/simple; bh=meWJOhPVkswEJEUPXpRMtDuGyzKKL9cF0sOOnTujhIQ=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=q/7xXOJf/AW6SNRTB+BD7D7FGp1f4E0XEL3/ZTjRLBJOe8TLMhPWV8lzeOvl0pr3rCK61Cx2/KgVU/qeI+MT+g0LYzht/sqMT71tfFoNfJlv94gaZ21qcEdPIL+lPTuitWDj/3+v2ZbwUTJR5wNXSR6Q+86TGHkBC52MDCH17N4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--samitolvanen.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=2PKkc+tW; arc=none smtp.client-ip=209.85.214.202 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--samitolvanen.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="2PKkc+tW" Received: by mail-pl1-f202.google.com with SMTP id d9443c01a7336-2166a1a5cc4so11302295ad.3 for ; Thu, 19 Dec 2024 13:08:14 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1734642494; x=1735247294; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=BJ+bQtpgXwuh9TDVVL7KrLC8CdDggoJteu7mzxqQJxM=; b=2PKkc+tWijCOqRnr4WXcjJfj3mOQGjm+17rpOKvfesZTYu1U+Evo74tUZ9mfSQnRVg +gEmg4OEy/GwpRZrry6CBSYypSxHwr1oGqSel2xgVm+PFWJnAt+oKR4o9YGtgMcmGzTV lJcmbZQbIFbm95pLaG4bdorOC4NSNi+c6hETnZlLBGMwpr5+n5pqETw1dPxTGWWHn+tZ wbipKx8B+0FmqIgCOXmv7hKAynQ/bVedPncjLq+35wQUUeEWU2NO8VaXgjp4cxD4ZJNM oYQg9DsVpQ2iFOHYlEQvo7Bq94j+/TggbYatZnS6DsHaSJCyT0Y3c9IchYUFTH+XzHDn 4u8Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1734642494; x=1735247294; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=BJ+bQtpgXwuh9TDVVL7KrLC8CdDggoJteu7mzxqQJxM=; b=qjU4LKf/LVu+rgM7nz1w5WMy5YjfB98emwo5hlqRzgEKc8LQi719WLIgYUcLTie/qx uvG/XpvXGWXnt2X7Gavfp3TQAI4m0n1+GyC6Fs4raMLpegrRWZDvFQsdw3IolWwAoDSl u+joEqz9iHve8EBSfGVYf/yMMe3kSKemlnNXOlUukbBCuU+C1ihbD4AfgFAi0MHDwXmj BIXWuzK4ByLKx16QLoyU7SD/mZ//ssIASjuOkXp/2litdidc+astUsc2vfo9BnIf+GDx Qs74AaBPM9+ocBWLO1FzeSKvTF/iE9DitS2rEWjSfM2xiVDOCZURkw8ZY7Q1RHfY8rdq x8FA== X-Forwarded-Encrypted: i=1; AJvYcCX6s+JpAsGcbC7hBm6Qi0c6GmUWDnu6dIKTJOquVx+opZ/8l9wotdtN3V8LbWGP9BGnpBSjVdv5ReJ9QgA=@vger.kernel.org X-Gm-Message-State: AOJu0YzGYgdFGEu6sYity45exbqtoLnnTlfNH64hO7mWsAjOANJkFtGB TLq2HL15FFykO8c8g52EtkXkKZxT5GbBc9hzZXz3iEYjhU/F3cuNGR8SyBjnuTfXOFtftWojBgS 7ePF3D0tQieYnWZ/HYZt/M3IUXQ== X-Google-Smtp-Source: AGHT+IFanGBqP4nFKDIDHoYd02bX7Fby8FIHEYxpEIjfOOg6TCvJOUA3qQnwUsNt2GWM+nb/JBf8ycMhpKxFRcd5rHY= X-Received: from pjur4.prod.google.com ([2002:a17:90a:d404:b0:2ea:448a:8cd1]) (user=samitolvanen job=prod-delivery.src-stubby-dispatcher) by 2002:a17:90b:2c84:b0:2ee:f687:6ad5 with SMTP id 98e67ed59e1d1-2f452dfd364mr694606a91.2.1734642494365; Thu, 19 Dec 2024 13:08:14 -0800 (PST) Date: Thu, 19 Dec 2024 21:07:52 +0000 In-Reply-To: <20241219210736.2990838-20-samitolvanen@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20241219210736.2990838-20-samitolvanen@google.com> X-Developer-Key: i=samitolvanen@google.com; a=openpgp; fpr=35CCFB63B283D6D3AEB783944CB5F6848BBC56EE X-Developer-Signature: v=1; a=openpgp-sha256; l=7893; i=samitolvanen@google.com; h=from:subject; bh=meWJOhPVkswEJEUPXpRMtDuGyzKKL9cF0sOOnTujhIQ=; b=owGbwMvMwCEWxa662nLh8irG02pJDOkp3QprJt5xy297p+c4h5v117ka+5XB987+nDhz06mHm dN25DyW6ChlYRDjYJAVU2Rp+bp66+7vTqmvPhdJwMxhZQIZwsDFKQATCatk+O86J7wpnmP2Zu1e a4Xb6XMiPx9g6g7SO5uSXyOrtErK/Scjw48HUbsbE/gOnHgc4NU6rbVnBtvKhd+LvX9vXzh/1+K WfA4A X-Mailer: git-send-email 2.47.1.613.gc27f4b7a9f-goog Message-ID: <20241219210736.2990838-35-samitolvanen@google.com> Subject: [PATCH v7 15/18] gendwarfksyms: Add support for symbol type pointers From: Sami Tolvanen To: Masahiro Yamada , Luis Chamberlain , Miguel Ojeda , Greg Kroah-Hartman Cc: Matthew Maurer , Alex Gaynor , Gary Guo , Petr Pavlu , Daniel Gomez , Neal Gompa , Hector Martin , Janne Grunau , Miroslav Benes , Asahi Linux , Sedat Dilek , linux-kbuild@vger.kernel.org, linux-kernel@vger.kernel.org, linux-modules@vger.kernel.org, rust-for-linux@vger.kernel.org, Sami Tolvanen Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" The compiler may choose not to emit type information in DWARF for external symbols. Clang, for example, does this for symbols not defined in the current TU. To provide a way to work around this issue, add support for __gendwarfksyms_ptr_ pointers that force the compiler to emit the necessary type information in DWARF also for the missing symbols. Example usage: #define GENDWARFKSYMS_PTR(sym) \ static typeof(sym) *__gendwarfksyms_ptr_##sym __used \ __section(".discard.gendwarfksyms") =3D &sym; extern int external_symbol(void); GENDWARFKSYMS_PTR(external_symbol); Signed-off-by: Sami Tolvanen Reviewed-by: Petr Pavlu --- scripts/gendwarfksyms/dwarf.c | 55 +++++++++++++++++++++- scripts/gendwarfksyms/examples/symbolptr.c | 33 +++++++++++++ scripts/gendwarfksyms/gendwarfksyms.h | 7 +++ scripts/gendwarfksyms/symbols.c | 27 +++++++++++ 4 files changed, 121 insertions(+), 1 deletion(-) create mode 100644 scripts/gendwarfksyms/examples/symbolptr.c diff --git a/scripts/gendwarfksyms/dwarf.c b/scripts/gendwarfksyms/dwarf.c index 746a89d9e3d4..534d9aa7c114 100644 --- a/scripts/gendwarfksyms/dwarf.c +++ b/scripts/gendwarfksyms/dwarf.c @@ -1061,6 +1061,31 @@ static void process_variable(struct state *state, Dw= arf_Die *die) process_symbol(state, die, __process_variable); } =20 +static void save_symbol_ptr(struct state *state) +{ + Dwarf_Die ptr_type; + Dwarf_Die type; + + if (!get_ref_die_attr(&state->die, DW_AT_type, &ptr_type) || + dwarf_tag(&ptr_type) !=3D DW_TAG_pointer_type) + error("%s must be a pointer type!", + get_symbol_name(&state->die)); + + if (!get_ref_die_attr(&ptr_type, DW_AT_type, &type)) + error("%s pointer missing a type attribute?", + get_symbol_name(&state->die)); + + /* + * Save the symbol pointer DIE in case the actual symbol is + * missing from the DWARF. Clang, for example, intentionally + * omits external symbols from the debugging information. + */ + if (dwarf_tag(&type) =3D=3D DW_TAG_subroutine_type) + symbol_set_ptr(state->sym, &type); + else + symbol_set_ptr(state->sym, &ptr_type); +} + static int process_exported_symbols(struct state *unused, struct die *cach= e, Dwarf_Die *die) { @@ -1084,7 +1109,9 @@ static int process_exported_symbols(struct state *unu= sed, struct die *cache, =20 state_init(&state); =20 - if (tag =3D=3D DW_TAG_subprogram) + if (is_symbol_ptr(get_symbol_name(&state.die))) + save_symbol_ptr(&state); + else if (tag =3D=3D DW_TAG_subprogram) process_subprogram(&state, &state.die); else process_variable(&state, &state.die); @@ -1097,10 +1124,36 @@ static int process_exported_symbols(struct state *u= nused, struct die *cache, } } =20 +static void process_symbol_ptr(struct symbol *sym, void *arg) +{ + struct state state; + Dwarf *dwarf =3D arg; + + if (sym->state !=3D SYMBOL_UNPROCESSED || !sym->ptr_die_addr) + return; + + debug("%s", sym->name); + state_init(&state); + state.sym =3D sym; + + if (!dwarf_die_addr_die(dwarf, (void *)sym->ptr_die_addr, &state.die)) + error("dwarf_die_addr_die failed for symbol ptr: '%s'", + sym->name); + + if (dwarf_tag(&state.die) =3D=3D DW_TAG_subroutine_type) + process_subprogram(&state, &state.die); + else + process_variable(&state, &state.die); + + cache_free(&state.expansion_cache); +} + void process_cu(Dwarf_Die *cudie) { check(process_die_container(NULL, NULL, cudie, process_exported_symbols, match_all)); =20 + symbol_for_each(process_symbol_ptr, dwarf_cu_getdwarf(cudie->cu)); + cache_free(&srcfile_cache); } diff --git a/scripts/gendwarfksyms/examples/symbolptr.c b/scripts/gendwarfk= syms/examples/symbolptr.c new file mode 100644 index 000000000000..88bc1bd60da8 --- /dev/null +++ b/scripts/gendwarfksyms/examples/symbolptr.c @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2024 Google LLC + * + * Example for symbol pointers. When compiled with Clang, gendwarfkyms + * uses a symbol pointer for `f`. + * + * $ clang -g -c examples/symbolptr.c -o examples/symbolptr.o + * $ echo -e "f\ng\np" | ./gendwarfksyms -d examples/symbolptr.o + */ + +/* Kernel macros for userspace testing. */ +#ifndef __used +#define __used __attribute__((__used__)) +#endif +#ifndef __section +#define __section(section) __attribute__((__section__(section))) +#endif + +#define __GENDWARFKSYMS_EXPORT(sym) \ + static typeof(sym) *__gendwarfksyms_ptr_##sym __used \ + __section(".discard.gendwarfksyms") =3D &sym; + +extern void f(unsigned int arg); +void g(int *arg); +void g(int *arg) {} + +struct s; +extern struct s *p; + +__GENDWARFKSYMS_EXPORT(f); +__GENDWARFKSYMS_EXPORT(g); +__GENDWARFKSYMS_EXPORT(p); diff --git a/scripts/gendwarfksyms/gendwarfksyms.h b/scripts/gendwarfksyms/= gendwarfksyms.h index fe49730fe623..197a1a8123c6 100644 --- a/scripts/gendwarfksyms/gendwarfksyms.h +++ b/scripts/gendwarfksyms/gendwarfksyms.h @@ -89,6 +89,10 @@ extern int symtypes; * symbols.c */ =20 +/* See symbols.c:is_symbol_ptr */ +#define SYMBOL_PTR_PREFIX "__gendwarfksyms_ptr_" +#define SYMBOL_PTR_PREFIX_LEN (sizeof(SYMBOL_PTR_PREFIX) - 1) + static inline unsigned int addr_hash(uintptr_t addr) { return hash_ptr((const void *)addr); @@ -112,14 +116,17 @@ struct symbol { struct hlist_node name_hash; enum symbol_state state; uintptr_t die_addr; + uintptr_t ptr_die_addr; unsigned long crc; }; =20 typedef void (*symbol_callback_t)(struct symbol *, void *arg); =20 +bool is_symbol_ptr(const char *name); void symbol_read_exports(FILE *file); void symbol_read_symtab(int fd); struct symbol *symbol_get(const char *name); +void symbol_set_ptr(struct symbol *sym, Dwarf_Die *ptr); void symbol_set_die(struct symbol *sym, Dwarf_Die *die); void symbol_set_crc(struct symbol *sym, unsigned long crc); void symbol_for_each(symbol_callback_t func, void *arg); diff --git a/scripts/gendwarfksyms/symbols.c b/scripts/gendwarfksyms/symbol= s.c index 4c499ba6c86d..327f87389c34 100644 --- a/scripts/gendwarfksyms/symbols.c +++ b/scripts/gendwarfksyms/symbols.c @@ -39,6 +39,20 @@ static unsigned int __for_each_addr(struct symbol *sym, = symbol_callback_t func, return processed; } =20 +/* + * For symbols without debugging information (e.g. symbols defined in other + * TUs), we also match __gendwarfksyms_ptr_ symbols, which the + * kernel uses to ensure type information is present in the TU that exports + * the symbol. A __gendwarfksyms_ptr pointer must have the same type as the + * exported symbol, e.g.: + * + * typeof(symname) *__gendwarf_ptr_symname =3D &symname; + */ +bool is_symbol_ptr(const char *name) +{ + return name && !strncmp(name, SYMBOL_PTR_PREFIX, SYMBOL_PTR_PREFIX_LEN); +} + static unsigned int for_each(const char *name, symbol_callback_t func, void *data) { @@ -47,6 +61,8 @@ static unsigned int for_each(const char *name, symbol_cal= lback_t func, =20 if (!name || !*name) return 0; + if (is_symbol_ptr(name)) + name +=3D SYMBOL_PTR_PREFIX_LEN; =20 hash_for_each_possible_safe(symbol_names, match, tmp, name_hash, hash_str(name)) { @@ -84,6 +100,17 @@ void symbol_set_crc(struct symbol *sym, unsigned long c= rc) error("no matching symbols: '%s'", sym->name); } =20 +static void set_ptr(struct symbol *sym, void *data) +{ + sym->ptr_die_addr =3D (uintptr_t)((Dwarf_Die *)data)->addr; +} + +void symbol_set_ptr(struct symbol *sym, Dwarf_Die *ptr) +{ + if (for_each(sym->name, set_ptr, ptr) =3D=3D 0) + error("no matching symbols: '%s'", sym->name); +} + static void set_die(struct symbol *sym, void *data) { sym->die_addr =3D (uintptr_t)((Dwarf_Die *)data)->addr; --=20 2.47.1.613.gc27f4b7a9f-goog From nobody Mon Feb 9 13:01:05 2026 Received: from mail-pj1-f73.google.com (mail-pj1-f73.google.com [209.85.216.73]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 8E1851FECB9 for ; Thu, 19 Dec 2024 21:08:16 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.216.73 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734642498; cv=none; b=q8SkNL/EmYT5T+DP125XmpUFzrGtTgV2dkA765XZY+s1kAvByDiPWbPpvhI1Y0TZ81ocvZeJG52C0S/DKwAEbsknaCW+HeN4O89idW5du42Bt/iASbLXnjpI8gYzWFXHVmCE5ZZyOqt0yt2Q3bLuBd5lV/um7BpjOnJPgNsaIfw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734642498; c=relaxed/simple; bh=G8T+NnXPkjDtKGjHLSfjrDpCNmmPfEyUeqSk1ZhBztg=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=U3fi86CTioI1V5xdBmCqtq63somdcTBQWV9Le2XkAB7eVBMPu6emcxdbcNi2B4TskGMFHEi7hVvGknbhco/2MAHUZQsyByydlz1fkv1mE50kVW2UZ05tnBFBPQ1fb/w/LNToj4Chawr1tyJPybJ9BcmCfvKY2Jro60bJsAIQ3+A= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--samitolvanen.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=DBTjqzFB; arc=none smtp.client-ip=209.85.216.73 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--samitolvanen.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="DBTjqzFB" Received: by mail-pj1-f73.google.com with SMTP id 98e67ed59e1d1-2ef775ec883so1103364a91.1 for ; Thu, 19 Dec 2024 13:08:16 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1734642496; x=1735247296; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=XhebaHvwRpIK3ajuqUsaMJY6c1H8vjbSZoFxdXzqCTY=; b=DBTjqzFB9cUlXBv+JhaOM3TbZRs+CLHHWMir38Pm7DMPiIUog5czwtL9iYxrCPWfpC y+YvPjXxTQRL0sMlBckBNSkiPNL7GqDnSOzR3Svr9CKlXU4FGQNzx55iHTBNn2DRcQni mA0d5W2sBwGzoFMuxMHRcf3yTCxzcvar5KSos9a5fZDVjFRp0r84KleayRgX4MiZTBFE i1XUnrDZ2DtbRXekJGcK8CFsHxgsmrfO3zxJNrOj6JtPiFQIRgKoD3juwdQMOynaao9y tUkvUVzzMTNdclFxg9BIVx2cb43Ls8mXC/PgqjNidJU8vea3zeiyM9FSJ1YpcMuX+GE5 FLDQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1734642496; x=1735247296; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=XhebaHvwRpIK3ajuqUsaMJY6c1H8vjbSZoFxdXzqCTY=; b=CaqUA0GVTA+74CbJeQoYcU0t3x3PuU3SF5TQQV4l5ZVpEGUyfXqEJZkavgHmWgFBSR 7yw6E+j8JtRsSGn2JPjPMocyw3ICFh8WWd+lnijrKInIvVKpRw9CclJQoSbnUz72lIUP J3EpjtxZVY8SHT/l6I9VGzflwPrAw72NQ6iICOuKsNM5Xx9O0YwYXkRTaZQ0I9GYS0WZ 3NJ1/m0/LEWYXcGQAwRYNGMeOuTHsgQmjEnJbSb28y0D2PSgb57Ehu70vgfuR3z3KnzW bebXTBSJE7IS1+pQ9TdisgPgEcQV7yOZ9uV4L3LCsovcy2qZY7BxD5kqheZzhkcVgVoY sqog== X-Forwarded-Encrypted: i=1; AJvYcCUIqwRDBGsJ4yUA+MiG4yjmaxG96+ryhZvCtyndekeqOQ0hNZLDF+Tx0TAC7e7W1PvVxPjLZ94+FCIY5HU=@vger.kernel.org X-Gm-Message-State: AOJu0YyHMpSx2kbtl34sib8fA10mRVAhBphBfz7iuXK424qE+eWkae52 Nj7phJpCwvjgd5UrXMpBb3n0UCiD2dUxuAPUkp9fuuFVTDVDUcMFofWCQ1JB1crIiJgYG23VgnA X6UMV/X9h69rdXlNI47qzzIJHww== X-Google-Smtp-Source: AGHT+IFhC4Ah0P2LpeeGNVWwyHAZfHL11yB3Qlfn6u2eyEw2X2bDrlrkxGMrpOMsrenz4F16xpWQ4hhDijC681Gi99s= X-Received: from pjbsc15.prod.google.com ([2002:a17:90b:510f:b0:2da:ac73:93e0]) (user=samitolvanen job=prod-delivery.src-stubby-dispatcher) by 2002:a17:90b:2744:b0:2ee:d7d3:3008 with SMTP id 98e67ed59e1d1-2f452e205b2mr861955a91.12.1734642495981; Thu, 19 Dec 2024 13:08:15 -0800 (PST) Date: Thu, 19 Dec 2024 21:07:53 +0000 In-Reply-To: <20241219210736.2990838-20-samitolvanen@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20241219210736.2990838-20-samitolvanen@google.com> X-Developer-Key: i=samitolvanen@google.com; a=openpgp; fpr=35CCFB63B283D6D3AEB783944CB5F6848BBC56EE X-Developer-Signature: v=1; a=openpgp-sha256; l=2005; i=samitolvanen@google.com; h=from:subject; bh=G8T+NnXPkjDtKGjHLSfjrDpCNmmPfEyUeqSk1ZhBztg=; b=owGbwMvMwCEWxa662nLh8irG02pJDOkp3YrdtVHhySouOkF7m0o/qbT80J9sEuBUNadufYapv 7naryUdpSwMYhwMsmKKLC1fV2/d/d0p9dXnIgmYOaxMIEMYuDgFYCL6mYwMC8QNvC5Va/C6soQc 2nND0fFj1mrj2OxZJ382S7zpEX4XwfBPU+d02AeenJOZBg++HOXPnffloVHvtx28p1rmeYb8rvz ACAA= X-Mailer: git-send-email 2.47.1.613.gc27f4b7a9f-goog Message-ID: <20241219210736.2990838-36-samitolvanen@google.com> Subject: [PATCH v7 16/18] export: Add __gendwarfksyms_ptr_ references to exported symbols From: Sami Tolvanen To: Masahiro Yamada , Luis Chamberlain , Miguel Ojeda , Greg Kroah-Hartman Cc: Matthew Maurer , Alex Gaynor , Gary Guo , Petr Pavlu , Daniel Gomez , Neal Gompa , Hector Martin , Janne Grunau , Miroslav Benes , Asahi Linux , Sedat Dilek , linux-kbuild@vger.kernel.org, linux-kernel@vger.kernel.org, linux-modules@vger.kernel.org, rust-for-linux@vger.kernel.org, Sami Tolvanen Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" With gendwarfksyms, we need each TU where the EXPORT_SYMBOL() macro is used to also contain DWARF type information for the symbols it exports. However, as a TU can also export external symbols and compilers may choose not to emit debugging information for symbols not defined in the current TU, the missing types will result in missing symbol versions. Stand-alone assembly code also doesn't contain type information for exported symbols, so we need to compile a temporary object file with asm-prototypes.h instead, and similarly need to ensure the DWARF in the temporary object file contains the necessary types. To always emit type information for external exports, add explicit __gendwarfksyms_ptr_ references to them in EXPORT_SYMBOL(). gendwarfksyms will use the type information for __gendwarfksyms_ptr_* if needed. Discard the pointers from the final binary to avoid further bloat. Signed-off-by: Sami Tolvanen --- include/linux/export.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/include/linux/export.h b/include/linux/export.h index 2633df4d31e6..a8c23d945634 100644 --- a/include/linux/export.h +++ b/include/linux/export.h @@ -52,9 +52,24 @@ =20 #else =20 +#ifdef CONFIG_GENDWARFKSYMS +/* + * With CONFIG_GENDWARFKSYMS, ensure the compiler emits debugging + * information for all exported symbols, including those defined in + * different TUs, by adding a __gendwarfksyms_ptr_ pointer + * that's discarded during the final link. + */ +#define __GENDWARFKSYMS_EXPORT(sym) \ + static typeof(sym) *__gendwarfksyms_ptr_##sym __used \ + __section(".discard.gendwarfksyms") =3D &sym; +#else +#define __GENDWARFKSYMS_EXPORT(sym) +#endif + #define __EXPORT_SYMBOL(sym, license, ns) \ extern typeof(sym) sym; \ __ADDRESSABLE(sym) \ + __GENDWARFKSYMS_EXPORT(sym) \ asm(__stringify(___EXPORT_SYMBOL(sym, license, ns))) =20 #endif --=20 2.47.1.613.gc27f4b7a9f-goog From nobody Mon Feb 9 13:01:05 2026 Received: from mail-pf1-f201.google.com (mail-pf1-f201.google.com [209.85.210.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 56728200BA2 for ; Thu, 19 Dec 2024 21:08:18 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734642500; cv=none; b=E45aHf5g/wP3rTrVMHzie1DlM24CFgYmeF2NjmNR/6mxPfXePGDIJ+CO7cJ2jrH+c/J9WOpAcmhOoS+jbmItq30+iuU9EIdJ7AXlCv6LpSoXARyHWuNuIE+gJN0/9ywu6EwcjIM3l5DJ5mvwkXMAn9jawDHRyJKmdxQA3IiJgFg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734642500; c=relaxed/simple; bh=p7WWEhhYSoB9EsyiZb7zkPmioP1Ghg8VnlGqhauZXHQ=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=gsKh+eaXuwXcn9k/81ZpBZUs5gqBFyrlqVN6Xcd8yaFZTdyipep54seH/OQSqj/k2ovyiNY4p8bgwCZGEQ5zz2ortqWXvfKWGxa7RqcEfBYzAojbWNOLfOReSCT79eWoD7Sf5tYJ8wgtnc6SAUUnT0brB1SyQdtyFS334l1gas8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--samitolvanen.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=KKC2XYju; arc=none smtp.client-ip=209.85.210.201 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--samitolvanen.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="KKC2XYju" Received: by mail-pf1-f201.google.com with SMTP id d2e1a72fcca58-728e3d9706dso1167663b3a.3 for ; Thu, 19 Dec 2024 13:08:18 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1734642497; x=1735247297; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=K9QWQProj0DRDekjJKvkceMs2crMPK7X9JqHuvPddMI=; b=KKC2XYjuSy0XsoY/oBy7mUHNHZTn8TeZV/niwAFTcU7EE/Hv1bG4dGQRTXvKzmDHMq ofMRlDLt6nTf/b1JPIfmktnRraGPaQNHTAeaJiB81RX+gyANGnpU+/ksHOv2WnQbrwRj xTp8yE7dBdcGT9KXeqcGY04tQSdrORkWwRkm0Zz3kOKOipTJjRuiD+5RpKHjvID2NQBD 369XLs80+uM6R1JyY3usmkXfOL6jHcTjsY37pVkU40Z+3pBbEI673sx+ZId3S5xnluDK wfpABrdWM+mliXg32/RoliP88uVJqaES1qPGE4Oz6YJWd04OWt+WEynUIfhG/ginX34+ Np7Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1734642497; x=1735247297; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=K9QWQProj0DRDekjJKvkceMs2crMPK7X9JqHuvPddMI=; b=UDKxc+rw85gx2+yx/RQ+Pz+j6R32/nzBYJC//iou49BwU543znfTU5vh7j8wo+ZxDJ 3Jl4pRIK2sMyx6vQqIe7+FXRXGg+K7TSmlvwu+y9KKhqb0mhw10ey+LcdYX1Mfp0Wxq9 9sPR6FF+utXLLwgatUVWjDSTlqPvBQQ/zpFbW30MANCLfYYSJeT19dJmJdZRIF27Py4n cfd3VgBDO1xWDtGahwjh+n6Z8SdZQX3fsFp8KKOhKXYSSacatf15h7YQVBE7OeaptD7s 4rmIbvy9JveADhI1zWElDAhGZpVYINnygcrGTMZMnSeNUDFss5N5JWVzao0rGfzFkAYG lcWQ== X-Forwarded-Encrypted: i=1; AJvYcCXOI+0SICqHpUro9ZYYclA0zpCK/1BiT0KGsILfzHH9FISyFrsO6rzbLS69dfNMICo4RljbeY8hgVOI5qU=@vger.kernel.org X-Gm-Message-State: AOJu0YzBlJOMICPy07HlFwCSEUbStA0ydjOpyZFi7FZrSn6LgzEMuBbI QB0kIhwS0T7ZPAfs8EbDdjt3TmVNHBFLQiUM1h2aSPPVTakr1DoEwfkGZfBFpOz3TGdw9IU+SoB fQi0DC9FlNEf2jFJ5g2LQL/yr6g== X-Google-Smtp-Source: AGHT+IGuKGndGRuHlhBBZFNCEbRkZFNy7qrppC6TOn/wTic9OAjDh2APD+XkcWOgBZYYA5gWeEtA9OnLhFZCfhA992o= X-Received: from pfbeb15.prod.google.com ([2002:a05:6a00:4c8f:b0:728:e3af:6bb0]) (user=samitolvanen job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6a00:1309:b0:725:e015:9082 with SMTP id d2e1a72fcca58-72abdd502d5mr301666b3a.5.1734642497599; Thu, 19 Dec 2024 13:08:17 -0800 (PST) Date: Thu, 19 Dec 2024 21:07:54 +0000 In-Reply-To: <20241219210736.2990838-20-samitolvanen@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20241219210736.2990838-20-samitolvanen@google.com> X-Developer-Key: i=samitolvanen@google.com; a=openpgp; fpr=35CCFB63B283D6D3AEB783944CB5F6848BBC56EE X-Developer-Signature: v=1; a=openpgp-sha256; l=4688; i=samitolvanen@google.com; h=from:subject; bh=p7WWEhhYSoB9EsyiZb7zkPmioP1Ghg8VnlGqhauZXHQ=; b=owGbwMvMwCEWxa662nLh8irG02pJDOkp3YrpVpoOXc0C/cZ2+8v1jIQnyB/b0b27ZNIizpV2c 8q4BUI6SlkYxDgYZMUUWVq+rt66+7tT6qvPRRIwc1iZQIYwcHEKwERmX2Vk2DE7Ylvq3KsTJy1l zavaxBBrqifvfyvyzrvs2wLaPw4tSmNkeDh9kRzr30s7lhfV/XskONuiWOm8qNJUfcVI+bUzlbq DmAE= X-Mailer: git-send-email 2.47.1.613.gc27f4b7a9f-goog Message-ID: <20241219210736.2990838-37-samitolvanen@google.com> Subject: [PATCH v7 17/18] kbuild: Add gendwarfksyms as an alternative to genksyms From: Sami Tolvanen To: Masahiro Yamada , Luis Chamberlain , Miguel Ojeda , Greg Kroah-Hartman Cc: Matthew Maurer , Alex Gaynor , Gary Guo , Petr Pavlu , Daniel Gomez , Neal Gompa , Hector Martin , Janne Grunau , Miroslav Benes , Asahi Linux , Sedat Dilek , linux-kbuild@vger.kernel.org, linux-kernel@vger.kernel.org, linux-modules@vger.kernel.org, rust-for-linux@vger.kernel.org, Sami Tolvanen Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" When MODVERSIONS is enabled, allow selecting gendwarfksyms as the implementation, but default to genksyms. Signed-off-by: Sami Tolvanen --- kernel/module/Kconfig | 22 ++++++++++++++++++++++ scripts/Makefile | 2 +- scripts/Makefile.build | 35 +++++++++++++++++++++++++++++------ 3 files changed, 52 insertions(+), 7 deletions(-) diff --git a/kernel/module/Kconfig b/kernel/module/Kconfig index 4637f063d0fc..d443fc504ffc 100644 --- a/kernel/module/Kconfig +++ b/kernel/module/Kconfig @@ -169,6 +169,22 @@ config MODVERSIONS make them incompatible with the kernel you are running. If unsure, say N. =20 +choice + prompt "Module versioning implementation" + depends on MODVERSIONS + help + Select the tool used to calculate symbol versions for modules. + + If unsure, select GENKSYMS. + +config GENKSYMS + bool "genksyms (from source code)" + help + Calculate symbol versions from pre-processed source code using + genksyms. + + If unsure, say Y. + config GENDWARFKSYMS bool "gendwarfksyms (from debugging information)" depends on DEBUG_INFO @@ -176,6 +192,12 @@ config GENDWARFKSYMS depends on !DEBUG_INFO_REDUCED && !DEBUG_INFO_SPLIT # Requires ELF object files. depends on !LTO + help + Calculate symbol versions from DWARF debugging information using + gendwarfksyms. Requires DEBUG_INFO to be enabled. + + If unsure, say N. +endchoice =20 config ASM_MODVERSIONS bool diff --git a/scripts/Makefile b/scripts/Makefile index d7fec46d38c0..8533f4498885 100644 --- a/scripts/Makefile +++ b/scripts/Makefile @@ -53,7 +53,7 @@ hostprogs +=3D unifdef targets +=3D module.lds =20 subdir-$(CONFIG_GCC_PLUGINS) +=3D gcc-plugins -subdir-$(CONFIG_MODVERSIONS) +=3D genksyms +subdir-$(CONFIG_GENKSYMS) +=3D genksyms subdir-$(CONFIG_GENDWARFKSYMS) +=3D gendwarfksyms subdir-$(CONFIG_SECURITY_SELINUX) +=3D selinux subdir-$(CONFIG_SECURITY_IPE) +=3D ipe diff --git a/scripts/Makefile.build b/scripts/Makefile.build index c16e4cf54d77..81d9dacad03c 100644 --- a/scripts/Makefile.build +++ b/scripts/Makefile.build @@ -107,13 +107,24 @@ cmd_cpp_i_c =3D $(CPP) $(c_flags) -o $@ $< $(obj)/%.i: $(obj)/%.c FORCE $(call if_changed_dep,cpp_i_c) =20 +getexportsymbols =3D $(NM) $@ | sed -n 's/.* __export_symbol_\(.*\)/$(1)/p' + +gendwarfksyms =3D $(objtree)/scripts/gendwarfksyms/gendwarfksyms \ + $(if $(KBUILD_SYMTYPES), --symtypes $(@:.o=3D.symtypes)) \ + $(if $(KBUILD_GENDWARFKSYMS_STABLE), --stable) + genksyms =3D $(objtree)/scripts/genksyms/genksyms \ $(if $(KBUILD_SYMTYPES), -T $(@:.o=3D.symtypes)) \ $(if $(KBUILD_PRESERVE), -p) \ $(addprefix -r , $(wildcard $(@:.o=3D.symref))) =20 # These mirror gensymtypes_S and co below, keep them in synch. +ifdef CONFIG_GENDWARFKSYMS +cmd_gensymtypes_c =3D $(if $(skip_gendwarfksyms),, \ + $(call getexportsymbols,\1) | $(gendwarfksyms) $@) +else cmd_gensymtypes_c =3D $(CPP) -D__GENKSYMS__ $(c_flags) $< | $(genksyms) +endif # CONFIG_GENDWARFKSYMS =20 # LLVM assembly # Generate .ll files from .c @@ -286,14 +297,26 @@ $(obj)/%.rs: $(obj)/%.rs.S FORCE # This is convoluted. The .S file must first be preprocessed to run guards= and # expand names, then the resulting exports must be constructed into plain # EXPORT_SYMBOL(symbol); to build our dummy C file, and that gets preproce= ssed -# to make the genksyms input. +# to make the genksyms input or compiled into an object for gendwarfksyms. # # These mirror gensymtypes_c and co above, keep them in synch. -cmd_gensymtypes_S =3D = \ - { echo "\#include " ; = \ - echo "\#include " ; = \ - $(NM) $@ | sed -n 's/.* __export_symbol_\(.*\)/EXPORT_SYMBOL(\1);/p' = ; } | \ - $(CPP) -D__GENKSYMS__ $(c_flags) -xc - | $(genksyms) +getasmexports =3D \ + { echo "\#include " ; \ + echo "\#include " ; \ + echo "\#include " ; \ + $(call getexportsymbols,EXPORT_SYMBOL(\1);) ; } + +ifdef CONFIG_GENDWARFKSYMS +cmd_gensymtypes_S =3D \ + $(getasmexports) | \ + $(CC) $(c_flags) -c -o $(@:.o=3D.gendwarfksyms.o) -xc -; \ + $(call getexportsymbols,\1) | \ + $(gendwarfksyms) $(@:.o=3D.gendwarfksyms.o) +else +cmd_gensymtypes_S =3D \ + $(getasmexports) | \ + $(CPP) -D__GENKSYMS__ $(c_flags) -xc - | $(genksyms) +endif # CONFIG_GENDWARFKSYMS =20 quiet_cmd_cpp_s_S =3D CPP $(quiet_modtag) $@ cmd_cpp_s_S =3D $(CPP) $(a_flags) -o $@ $< --=20 2.47.1.613.gc27f4b7a9f-goog From nobody Mon Feb 9 13:01:05 2026 Received: from mail-pg1-f202.google.com (mail-pg1-f202.google.com [209.85.215.202]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 940FA203703 for ; Thu, 19 Dec 2024 21:08:19 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.215.202 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734642503; cv=none; b=IV39bI0nNeoKgf2xQJhcX3oTL3jEm5aump7bFQfS+QyATjJLUEYZRrXdDshiVQWnejtTmo66XTOqe2ve7t7CfMmoKttZdvcYBnb5AgblU4rNTRSxB7qvWY78kyeM2P5cVsgsyOlmtTYNyuh0ROwUuitlLF0qJ4iYwSSk63nE3R4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1734642503; c=relaxed/simple; bh=eBWSrd2j7HvMb7oRH1RLo5t203oukOJEVtlknSsCqM0=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=EL48KbeTpRLbQxMEyx4ThZ2Vjvycp8ujytbO5ZKZzA4xhW+0HOPwA6xNxbJaX/R5l5t0yf6VHCXYLt+5YEs/EXb5PUd7rElwZLdv1+fFbfDWuh9izh7HQKxzmtgZq+OXvODUL5S8HEN0MdBXFKNtXXHrcMxBYMqiSuGUv4IyET4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--samitolvanen.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=eCfZ6ZUL; arc=none smtp.client-ip=209.85.215.202 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--samitolvanen.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="eCfZ6ZUL" Received: by mail-pg1-f202.google.com with SMTP id 41be03b00d2f7-7fcca85ffdaso677462a12.3 for ; Thu, 19 Dec 2024 13:08:19 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1734642499; x=1735247299; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=clWazEynvGGklOBHtSTCV/CnP6B5ZIpWEbRoz38skJM=; b=eCfZ6ZULewVSC7Fbc3a8iTJ2NKaH7WPS29TzPPMaFMlf5jw5mHl3JUWqCW1IE8M/Md d05K5yGEuhd85kZ41PTalstGWOR833kdQQqc9CW+c8sAs3E/jQFQxZc4ukwwgC7kgoc4 DbiuI6CzSREiuajKNFs9ISwr+YX9RxLVryWEOwe8Hq1r5kjVVX1rrtgDIOCb2XBQrgPa Bd/TY98V3zJIuHZ2NbZg2JfCv/98IT+INXJ9y4ydVisa22ck7MRlf2Z5Kv1dQlWtfwFY fGux+ha5zovPFZPESsc9pXhG0awt5I7vo825C0biOtI1/zzHi9WOk+/7pn4ZknmREcD+ v4Pg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1734642499; x=1735247299; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=clWazEynvGGklOBHtSTCV/CnP6B5ZIpWEbRoz38skJM=; b=cM1c7VzlEvie5AXc7zkAVHTuE0bYGuZunmQQI7gQW9gU+JdymTmnmH0aT3RkWPJjs0 7yNmUjrKQ1iB+gLqNQCP4Xt3BRNsB9BqOnvEHjm0E+pYP+fyUOG1h1aWAk+73npyqJb+ M6QBHYMsfvmjWzRwZm9ZpwHgQoryVDYyGMfYBWkJ4aI/O4UZRZce0TWNh9MNqTI7sKfC 3NDy5pTq4VzQjOnJRJ4B0v1r7AKdztyHql9CsD5YFZLE+2dFgQta370EDIKxymBCehOF T/WXF1fCuwc8rBMzyXZbGocCE8GM5d5ZZxE6Fm1MsqIT+6TGU7BpgemPNF4dyAT83wqI mWDA== X-Forwarded-Encrypted: i=1; AJvYcCVxdpb048Mja7nAo4eoiCagTkzNSrW57xD5J9ot+NRfq1ciGJdWJY4rFoUX9XWhxzuLJInHxVQkh5igJSE=@vger.kernel.org X-Gm-Message-State: AOJu0Yzn9AmKpZFm4KI55xs4KbATBF70fjaM9e2lyOaaHOoMrn1v8Qv7 4tIJ6Zk1/e8ULQUjUZH9EpYeDmZsbJv/i+1cf1W46pVb4JztM/LNwcLzSSbGO34+gd8xfMHiBkD 7jRkWrh4OR2R4c4K6VCel+o8q+g== X-Google-Smtp-Source: AGHT+IFpvXX0vIlQH5KAo17JTxu452Yd9q/FUXEA6Jqw9ws0fLFVjMTh9aCKxl4PDOhzik0oW8AS17kUHRwkbGNdNR0= X-Received: from pjtq6.prod.google.com ([2002:a17:90a:c106:b0:2e2:9f67:1ca3]) (user=samitolvanen job=prod-delivery.src-stubby-dispatcher) by 2002:a17:90b:2b8e:b0:2ee:49c4:4a7c with SMTP id 98e67ed59e1d1-2f452e39845mr680990a91.18.1734642498967; Thu, 19 Dec 2024 13:08:18 -0800 (PST) Date: Thu, 19 Dec 2024 21:07:55 +0000 In-Reply-To: <20241219210736.2990838-20-samitolvanen@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20241219210736.2990838-20-samitolvanen@google.com> X-Developer-Key: i=samitolvanen@google.com; a=openpgp; fpr=35CCFB63B283D6D3AEB783944CB5F6848BBC56EE X-Developer-Signature: v=1; a=openpgp-sha256; l=13480; i=samitolvanen@google.com; h=from:subject; bh=eBWSrd2j7HvMb7oRH1RLo5t203oukOJEVtlknSsCqM0=; b=owGbwMvMwCEWxa662nLh8irG02pJDOkp3Uqd+jsvGHmXBTVfdF5xgmPTtuBjx6prCrbKNNsIp l1ZkDO7o5SFQYyDQVZMkaXl6+qtu787pb76XCQBM4eVCWQIAxenAEwkcDYjQ9upundHn9qYd4Zd v8T4pvVnx6Ilc8s030jenFF6tvHaY36G/8FqfPfbJWQPnOV9uUvxbSLb26uXTLyKGewuvFpQvTf rLDMA X-Mailer: git-send-email 2.47.1.613.gc27f4b7a9f-goog Message-ID: <20241219210736.2990838-38-samitolvanen@google.com> Subject: [PATCH v7 18/18] Documentation/kbuild: Add DWARF module versioning From: Sami Tolvanen To: Masahiro Yamada , Luis Chamberlain , Miguel Ojeda , Greg Kroah-Hartman Cc: Matthew Maurer , Alex Gaynor , Gary Guo , Petr Pavlu , Daniel Gomez , Neal Gompa , Hector Martin , Janne Grunau , Miroslav Benes , Asahi Linux , Sedat Dilek , linux-kbuild@vger.kernel.org, linux-kernel@vger.kernel.org, linux-modules@vger.kernel.org, rust-for-linux@vger.kernel.org, Sami Tolvanen Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add documentation for gendwarfksyms changes, and the kABI stability features that can be useful for distributions even though they're not used in mainline kernels. Signed-off-by: Sami Tolvanen --- Documentation/kbuild/gendwarfksyms.rst | 308 +++++++++++++++++++++++++ Documentation/kbuild/index.rst | 1 + 2 files changed, 309 insertions(+) create mode 100644 Documentation/kbuild/gendwarfksyms.rst diff --git a/Documentation/kbuild/gendwarfksyms.rst b/Documentation/kbuild/= gendwarfksyms.rst new file mode 100644 index 000000000000..e4beaae7e456 --- /dev/null +++ b/Documentation/kbuild/gendwarfksyms.rst @@ -0,0 +1,308 @@ +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D +DWARF module versioning +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +1. Introduction +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +When CONFIG_MODVERSIONS is enabled, symbol versions for modules +are typically calculated from preprocessed source code using the +**genksyms** tool. However, this is incompatible with languages such +as Rust, where the source code has insufficient information about +the resulting ABI. With CONFIG_GENDWARFKSYMS (and CONFIG_DEBUG_INFO) +selected, **gendwarfksyms** is used instead to calculate symbol versions +from the DWARF debugging information, which contains the necessary +details about the final module ABI. + +1.1. Usage +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +gendwarfksyms accepts a list of object files on the command line, and a +list of symbol names (one per line) in standard input:: + + Usage: gendwarfksyms [options] elf-object-file ... < symbol-list + + Options: + -d, --debug Print debugging information + --dump-dies Dump DWARF DIE contents + --dump-die-map Print debugging information about die_map c= hanges + --dump-types Dump type strings + --dump-versions Dump expanded type strings used for symbol = versions + -s, --stable Support kABI stability features + -T, --symtypes file Write a symtypes file + -h, --help Print this message + + +2. Type information availability +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D + +While symbols are typically exported in the same translation unit (TU) +where they're defined, it's also perfectly fine for a TU to export +external symbols. For example, this is done when calculating symbol +versions for exports in stand-alone assembly code. + +To ensure the compiler emits the necessary DWARF type information in the +TU where symbols are actually exported, gendwarfksyms adds a pointer +to exported symbols in the `EXPORT_SYMBOL()` macro using the following +macro:: + + #define __GENDWARFKSYMS_EXPORT(sym) \ + static typeof(sym) *__gendwarfksyms_ptr_##sym __used \ + __section(".discard.gendwarfksyms") =3D &sym; + + +When a symbol pointer is found in DWARF, gendwarfksyms can use its +type for calculating symbol versions even if the symbol is defined +elsewhere. The name of the symbol pointer is expected to start with +`__gendwarfksyms_ptr_`, followed by the name of the exported symbol. + +3. Symtypes output format +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D + +Similarly to genksyms, gendwarfksyms supports writing a symtypes +file for each processed object that contain types for exported +symbols and each referenced type that was used in calculating symbol +versions. These files can be useful when trying to determine what +exactly caused symbol versions to change between builds. To generate +symtypes files during a kernel build, set `KBUILD_SYMTYPES=3D1`. + +Matching the existing format, the first column of each line contains +either a type reference or a symbol name. Type references have a +one-letter prefix followed by "#" and the name of the type. Four +reference types are supported:: + + e# =3D enum + s# =3D struct + t# =3D typedef + u# =3D union + +Type names with spaces in them are wrapped in single quotes, e.g.:: + + s#'core::result::Result' + +The rest of the line contains a type string. Unlike with genksyms that +produces C-style type strings, gendwarfksyms uses the same simple parsed +DWARF format produced by **--dump-dies**, but with type references +instead of fully expanded strings. + +4. Maintaining a stable kABI +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D + +Distribution maintainers often need the ability to make ABI compatible +changes to kernel data structures due to LTS updates or backports. Using +the traditional `#ifndef __GENKSYMS__` to hide these changes from symbol +versioning won't work when processing object files. To support this +use case, gendwarfksyms provides kABI stability features designed to +hide changes that won't affect the ABI when calculating versions. These +features are all gated behind the **--stable** command line flag and are +not used in the mainline kernel. To use stable features during a kernel +build, set `KBUILD_GENDWARFKSYMS_STABLE=3D1`. + +Examples for using these features are provided in the +**scripts/gendwarfksyms/examples** directory, including helper macros +for source code annotation. Note that as these features are only used to +transform the inputs for symbol versioning, the user is responsible for +ensuring that their changes actually won't break the ABI. + +4.1. kABI rules +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +kABI rules allow distributions to fine-tune certain parts +of gendwarfksyms output and thus control how symbol +versions are calculated. These rules are defined in the +`.discard.gendwarfksyms.kabi_rules` section of the object file and +consist of simple null-terminated strings with the following structure:: + + version\0type\0target\0value\0 + +This string sequence is repeated as many times as needed to express all +the rules. The fields are as follows: + +- `version`: Ensures backward compatibility for future changes to the + structure. Currently expected to be "1". +- `type`: Indicates the type of rule being applied. +- `target`: Specifies the target of the rule, typically the fully + qualified name of the DWARF Debugging Information Entry (DIE). +- `value`: Provides rule-specific data. + +The following helper macro, for example, can be used to specify rules +in the source code:: + + #define __KABI_RULE(hint, target, value) \ + static const char __PASTE(__gendwarfksyms_rule_, \ + __COUNTER__)[] __used __aligned(1) \ + __section(".discard.gendwarfksyms.kabi_rules") =3D \ + "1\0" #hint "\0" #target "\0" #value + + +Currently, only the rules discussed in this section are supported, but +the format is extensible enough to allow further rules to be added as +need arises. + +4.1.1. Managing definition visibility +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +A declaration can change into a full definition when additional includes +are pulled into the translation unit. This changes the versions of any +symbol that references the type even if the ABI remains unchanged. As +it may not be possible to drop includes without breaking the build, the +`declonly` rule can be used to specify a type as declaration-only, even +if the debugging information contains the full definition. + +The rule fields are expected to be as follows: + +- `type`: "declonly" +- `target`: The fully qualified name of the target data structure + (as shown in **--dump-dies** output). +- `value`: This field is ignored. + +Using the `__KABI_RULE` macro, this rule can be defined as:: + + #define KABI_DECLONLY(fqn) __KABI_RULE(declonly, fqn, ) + +Example usage:: + + struct s { + /* definition */ + }; + + KABI_DECLONLY(s); + +4.1.2. Adding enumerators +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D + +For enums, all enumerators and their values are included in calculating +symbol versions, which becomes a problem if we later need to add more +enumerators without changing symbol versions. The `enumerator_ignore` +rule allows us to hide named enumerators from the input. + +The rule fields are expected to be as follows: + +- `type`: "enumerator_ignore" +- `target`: The fully qualified name of the target enum + (as shown in **--dump-dies** output) and the name of the + enumerator field separated by a space. +- `value`: This field is ignored. + +Using the `__KABI_RULE` macro, this rule can be defined as:: + + #define KABI_ENUMERATOR_IGNORE(fqn, field) \ + __KABI_RULE(enumerator_ignore, fqn field, ) + +Example usage:: + + enum e { + A, B, C, D, + }; + + KABI_ENUMERATOR_IGNORE(e, B); + KABI_ENUMERATOR_IGNORE(e, C); + +If the enum additionally includes an end marker and new values must +be added in the middle, we may need to use the old value for the last +enumerator when calculating versions. The `enumerator_value` rule allows +us to override the value of an enumerator for version calculation: + +- `type`: "enumerator_value" +- `target`: The fully qualified name of the target enum + (as shown in **--dump-dies** output) and the name of the + enumerator field separated by a space. +- `value`: Integer value used for the field. + +Using the `__KABI_RULE` macro, this rule can be defined as:: + + #define KABI_ENUMERATOR_VALUE(fqn, field, value) \ + __KABI_RULE(enumerator_value, fqn field, value) + +Example usage:: + + enum e { + A, B, C, LAST, + }; + + KABI_ENUMERATOR_IGNORE(e, C); + KABI_ENUMERATOR_VALUE(e, LAST, 2); + +4.3. Adding structure members +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D + +Perhaps the most common ABI compatible change is adding a member to a +kernel data structure. When changes to a structure are anticipated, +distribution maintainers can pre-emptively reserve space in the +structure and take it into use later without breaking the ABI. If +changes are needed to data structures without reserved space, existing +alignment holes can potentially be used instead. While kABI rules could +be added for these type of changes, using unions is typically a more +natural method. This section describes gendwarfksyms support for using +reserved space in data structures and hiding members that don't change +the ABI when calculating symbol versions. + +4.3.1. Reserving space and replacing members +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +Space is typically reserved for later use by appending integer types, or +arrays, to the end of the data structure, but any type can be used. Each +reserved member needs a unique name, but as the actual purpose is usually +not known at the time the space is reserved, for convenience, names that +start with `__kabi_` are left out when calculating symbol versions:: + + struct s { + long a; + long __kabi_reserved_0; /* reserved for future use */ + }; + +The reserved space can be taken into use by wrapping the member in a +union, which includes the original type and the replacement member:: + + struct s { + long a; + union { + long __kabi_reserved_0; /* original type */ + struct b b; /* replaced field */ + }; + }; + +If the `__kabi_` naming scheme was used when reserving space, the name +of the first member of the union must start with `__kabi_reserved`. This +ensures the original type is used when calculating versions, but the name +is again left out. The rest of the union is ignored. + +If we're replacing a member that doesn't follow this naming convention, +we also need to preserve the original name to avoid changing versions, +which we can do by changing the first union member's name to start with +`__kabi_renamed` followed by the original name. + +The examples include `KABI_(RESERVE|USE|REPLACE)*` macros that help +simplify the process and also ensure the replacement member is correctly +aligned and its size won't exceed the reserved space. + +4.3.2. Hiding members +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +Predicting which structures will require changes during the support +timeframe isn't always possible, in which case one might have to resort +to placing new members into existing alignment holes:: + + struct s { + int a; + /* a 4-byte alignment hole */ + unsigned long b; + }; + + +While this won't change the size of the data structure, one needs to +be able to hide the added members from symbol versioning. Similarly +to reserved fields, this can be accomplished by wrapping the added +member to a union where one of the fields has a name starting with +`__kabi_ignored`:: + + struct s { + int a; + union { + char __kabi_ignored_0; + int n; + }; + unsigned long b; + }; + +With **--stable**, both versions produce the same symbol version. diff --git a/Documentation/kbuild/index.rst b/Documentation/kbuild/index.rst index cee2f99f734b..e82af05cd652 100644 --- a/Documentation/kbuild/index.rst +++ b/Documentation/kbuild/index.rst @@ -21,6 +21,7 @@ Kernel Build System reproducible-builds gcc-plugins llvm + gendwarfksyms =20 .. only:: subproject and html =20 --=20 2.47.1.613.gc27f4b7a9f-goog