From: Sami Tolvanen <samitolvanen@google.com>
To: Masahiro Yamada <masahiroy@kernel.org>,
Luis Chamberlain <mcgrof@kernel.org>,
Miguel Ojeda <ojeda@kernel.org>,
Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Matthew Maurer <mmaurer@google.com>,
Alex Gaynor <alex.gaynor@gmail.com>, Gary Guo <gary@garyguo.net>,
Petr Pavlu <petr.pavlu@suse.com>,
Daniel Gomez <da.gomez@samsung.com>, Neal Gompa <neal@gompa.dev>,
Hector Martin <marcan@marcan.st>, Janne Grunau <j@jannau.net>,
Miroslav Benes <mbenes@suse.cz>,
Asahi Linux <asahi@lists.linux.dev>,
Sedat Dilek <sedat.dilek@gmail.com>,
linux-kbuild@vger.kernel.org, linux-kernel@vger.kernel.org,
linux-modules@vger.kernel.org, rust-for-linux@vger.kernel.org,
Sami Tolvanen <samitolvanen@google.com>
Subject: [PATCH v4 16/19] gendwarfksyms: Add support for symbol type pointers
Date: Tue, 8 Oct 2024 18:38:40 +0000 [thread overview]
Message-ID: <20241008183823.36676-37-samitolvanen@google.com> (raw)
In-Reply-To: <20241008183823.36676-21-samitolvanen@google.com>
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_<symbol> 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") = &sym;
extern int external_symbol(void);
GENDWARFKSYMS_PTR(external_symbol);
Signed-off-by: Sami Tolvanen <samitolvanen@google.com>
Acked-by: Neal Gompa <neal@gompa.dev>
---
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 72e24140b6e3..0112b5e8fbf5 100644
--- a/scripts/gendwarfksyms/dwarf.c
+++ b/scripts/gendwarfksyms/dwarf.c
@@ -992,6 +992,31 @@ static void process_variable(struct state *state, Dwarf_Die *die)
process_symbol(state, die, __process_variable);
}
+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) != 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) == 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 *cache,
Dwarf_Die *die)
{
@@ -1015,7 +1040,9 @@ static int process_exported_symbols(struct state *unused, struct die *cache,
state_init(&state);
- if (tag == DW_TAG_subprogram)
+ if (is_symbol_ptr(get_symbol_name(&state.die)))
+ save_symbol_ptr(&state);
+ else if (tag == DW_TAG_subprogram)
process_subprogram(&state, &state.die);
else
process_variable(&state, &state.die);
@@ -1028,8 +1055,34 @@ static int process_exported_symbols(struct state *unused, struct die *cache,
}
}
+static void process_symbol_ptr(struct symbol *sym, void *arg)
+{
+ struct state state;
+ Dwarf *dwarf = arg;
+
+ if (sym->state != SYMBOL_UNPROCESSED || !sym->ptr_die_addr)
+ return;
+
+ debug("%s", sym->name);
+ state_init(&state);
+ state.sym = 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) == DW_TAG_subroutine_type)
+ process_subprogram(&state, &state.die);
+ else
+ process_variable(&state, &state.die);
+
+ cache_clear_expanded(&state.expansion_cache);
+}
+
void process_cu(Dwarf_Die *cudie)
{
check(process_die_container(NULL, NULL, cudie, process_exported_symbols,
match_all));
+
+ symbol_for_each(process_symbol_ptr, dwarf_cu_getdwarf(cudie->cu));
}
diff --git a/scripts/gendwarfksyms/examples/symbolptr.c b/scripts/gendwarfksyms/examples/symbolptr.c
new file mode 100644
index 000000000000..b7b97cd39769
--- /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 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") = &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 1cff868bacdb..28315b38762f 100644
--- a/scripts/gendwarfksyms/gendwarfksyms.h
+++ b/scripts/gendwarfksyms/gendwarfksyms.h
@@ -92,6 +92,10 @@ extern int symtypes;
* symbols.c
*/
+/* 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);
@@ -115,14 +119,17 @@ struct symbol {
struct hlist_node name_hash;
enum symbol_state state;
uintptr_t die_addr;
+ uintptr_t ptr_die_addr;
unsigned long crc;
};
typedef void (*symbol_callback_t)(struct symbol *, void *arg);
+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/symbols.c
index e17f11a02f6e..ca6a17bd009c 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;
}
+/*
+ * For symbols without debugging information (e.g. symbols defined in other
+ * TUs), we also match __gendwarfksyms_ptr_<symbol_name> 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 = &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_callback_t func,
if (!name || !*name)
return 0;
+ if (is_symbol_ptr(name))
+ name += SYMBOL_PTR_PREFIX_LEN;
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 crc)
error("no matching symbols: '%s'", sym->name);
}
+static void set_ptr(struct symbol *sym, void *data)
+{
+ sym->ptr_die_addr = (uintptr_t)((Dwarf_Die *)data)->addr;
+}
+
+void symbol_set_ptr(struct symbol *sym, Dwarf_Die *ptr)
+{
+ if (for_each(sym->name, set_ptr, ptr) == 0)
+ error("no matching symbols: '%s'", sym->name);
+}
+
static void set_die(struct symbol *sym, void *data)
{
sym->die_addr = (uintptr_t)((Dwarf_Die *)data)->addr;
--
2.47.0.rc0.187.ge670bccf7e-goog
next prev parent reply other threads:[~2024-10-08 18:39 UTC|newest]
Thread overview: 40+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-10-08 18:38 [PATCH v4 00/19] Implement DWARF modversions Sami Tolvanen
2024-10-08 18:38 ` [PATCH v4 01/19] scripts: move genksyms crc32 implementation to a common include Sami Tolvanen
2024-10-08 18:38 ` [PATCH v4 02/19] tools: Add gendwarfksyms Sami Tolvanen
2024-10-08 18:38 ` [PATCH v4 03/19] gendwarfksyms: Add address matching Sami Tolvanen
2024-10-17 14:08 ` Petr Pavlu
2024-10-17 17:16 ` Sami Tolvanen
2024-10-08 18:38 ` [PATCH v4 04/19] gendwarfksyms: Expand base_type Sami Tolvanen
2024-10-08 18:38 ` [PATCH v4 05/19] gendwarfksyms: Add a cache for processed DIEs Sami Tolvanen
2024-10-22 11:39 ` Petr Pavlu
2024-10-08 18:38 ` [PATCH v4 06/19] gendwarfksyms: Expand type modifiers and typedefs Sami Tolvanen
2024-10-08 18:38 ` [PATCH v4 07/19] gendwarfksyms: Expand subroutine_type Sami Tolvanen
2024-10-08 18:38 ` [PATCH v4 08/19] gendwarfksyms: Expand array_type Sami Tolvanen
2024-10-08 18:38 ` [PATCH v4 09/19] gendwarfksyms: Expand structure types Sami Tolvanen
2024-10-22 11:42 ` Petr Pavlu
2024-10-08 18:38 ` [PATCH v4 10/19] gendwarfksyms: Limit structure expansion Sami Tolvanen
2024-10-16 14:16 ` Petr Pavlu
2024-10-16 21:21 ` Sami Tolvanen
2024-10-08 18:38 ` [PATCH v4 11/19] gendwarfksyms: Add die_map debugging Sami Tolvanen
2024-10-17 14:09 ` Petr Pavlu
2024-10-08 18:38 ` [PATCH v4 12/19] gendwarfksyms: Add symtypes output Sami Tolvanen
2024-10-17 14:13 ` Petr Pavlu
2024-10-17 17:35 ` Sami Tolvanen
2024-10-08 18:38 ` [PATCH v4 13/19] gendwarfksyms: Add symbol versioning Sami Tolvanen
2024-10-22 11:48 ` Petr Pavlu
2024-10-23 17:46 ` Sami Tolvanen
2024-10-08 18:38 ` [PATCH v4 14/19] gendwarfksyms: Add support for kABI rules Sami Tolvanen
2024-10-22 14:38 ` Petr Pavlu
2024-10-23 17:47 ` Sami Tolvanen
2024-10-08 18:38 ` [PATCH v4 15/19] gendwarfksyms: Add support for reserved and ignored fields Sami Tolvanen
2024-10-23 14:53 ` Petr Pavlu
2024-10-23 21:05 ` Sami Tolvanen
2024-10-08 18:38 ` Sami Tolvanen [this message]
2024-10-23 14:55 ` [PATCH v4 16/19] gendwarfksyms: Add support for symbol type pointers Petr Pavlu
2024-10-08 18:38 ` [PATCH v4 17/19] export: Add __gendwarfksyms_ptr_ references to exported symbols Sami Tolvanen
2024-10-08 18:38 ` [PATCH v4 18/19] kbuild: Add gendwarfksyms as an alternative to genksyms Sami Tolvanen
2024-10-23 14:59 ` Petr Pavlu
2024-10-23 21:14 ` Sami Tolvanen
2024-10-08 18:38 ` [PATCH v4 19/19] Documentation/kbuild: Add DWARF module versioning Sami Tolvanen
2024-10-11 23:42 ` [PATCH v4 00/19] Implement DWARF modversions Luis Chamberlain
2024-10-12 0:30 ` Sami Tolvanen
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20241008183823.36676-37-samitolvanen@google.com \
--to=samitolvanen@google.com \
--cc=alex.gaynor@gmail.com \
--cc=asahi@lists.linux.dev \
--cc=da.gomez@samsung.com \
--cc=gary@garyguo.net \
--cc=gregkh@linuxfoundation.org \
--cc=j@jannau.net \
--cc=linux-kbuild@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-modules@vger.kernel.org \
--cc=marcan@marcan.st \
--cc=masahiroy@kernel.org \
--cc=mbenes@suse.cz \
--cc=mcgrof@kernel.org \
--cc=mmaurer@google.com \
--cc=neal@gompa.dev \
--cc=ojeda@kernel.org \
--cc=petr.pavlu@suse.com \
--cc=rust-for-linux@vger.kernel.org \
--cc=sedat.dilek@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.