On 9/23/24 20:18, Sami Tolvanen wrote:
> 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
> ---
> kernel/module/Kconfig | 8 ++
> scripts/Makefile | 1 +
> scripts/gendwarfksyms/.gitignore | 2 +
> scripts/gendwarfksyms/Makefile| 8 ++
> scripts/gendwarfksyms/dwarf.c | 166 ++
> scripts/gendwarfksyms/gendwarfksyms.c | 132
> scripts/gendwarfksyms/gendwarfksyms.h | 97 +++
> scripts/gendwarfksyms/symbols.c | 82 +
> 8 files changed, 496 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/kernel/module/Kconfig b/kernel/module/Kconfig
> index ccdbd1bc12aa..c3a0172a909f 100644
> --- a/kernel/module/Kconfig
> +++ b/kernel/module/Kconfig
> @@ -168,6 +168,14 @@ config MODVERSIONS
> make them incompatible with the kernel you are running. If
> unsure, say N.
>
> +config GENDWARFKSYMS
> + bool
> + 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 += module.lds
>
> subdir-$(CONFIG_GCC_PLUGINS) += gcc-plugins
> subdir-$(CONFIG_MODVERSIONS) += genksyms
> +subdir-$(CONFIG_GENDWARFKSYMS) += gendwarfksyms
> subdir-$(CONFIG_SECURITY_SELINUX) += selinux
> subdir-$(CONFIG_SECURITY_IPE) += ipe
>
> diff --git a/scripts/gendwarfksyms/.gitignore
> b/scripts/gendwarfksyms/.gitignore
> new file mode 100644
> index ..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 ..9f8fec4fd39b
> --- /dev/null
> +++ b/scripts/gendwarfksyms/Makefile
> @@ -0,0 +1,8 @@
> +# SPDX-License-Identifier: GPL-2.0
> +hostprogs-always-y += gendwarfksyms
> +
> +gendwarfksyms-objs += gendwarfksyms.o
> +gendwarfksyms-objs += dwarf.o
> +gendwarfksyms-objs += symbols.o
> +
> +HOSTLDLIBS_gendwarfksyms := -ldw -lelf
> diff --git a/scripts/gendwarfksyms/dwarf.c b/scripts/gendwarfksyms/dwarf.c
> new file mode 100644
> index ..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
> *value)
> +{
> + 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 = get_linkage_name_attr(die);
> + if (!name)
> + name = get_name_attr(die);
> +
> + return name;
> +}
> +
> +static bool match_export_symbol(struct state *state, Dwarf_Die *die)
> +{
> + Dwarf_Die *source = 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 = &origin;
> +
> + state->sym = symbol_get(get_symbol_name(die));
> +
> + /* Look up using the origin name if there are no matches. */
> + if (!state->sym && source != die)
> + state->sym = symbol_get(get_symbol_name(source));
> +
> + state->