summaryrefslogtreecommitdiff
path: root/scripts/gendwarfksyms/dwarf.c
diff options
context:
space:
mode:
authorSami Tolvanen <samitolvanen@google.com>2025-01-03 20:45:35 +0000
committerMasahiro Yamada <masahiroy@kernel.org>2025-01-11 01:25:26 +0900
commit936cf61c3ef5d6dad714d6c01a85704027dddeb9 (patch)
treeb4110f2c69e4c0fbd2311a9be0a8c48a4a12b7bf /scripts/gendwarfksyms/dwarf.c
parent71378888018833a1cdcbf72f1e95d7c010542d8b (diff)
gendwarfksyms: Add support for kABI rules
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 <samitolvanen@google.com> Signed-off-by: Masahiro Yamada <masahiroy@kernel.org>
Diffstat (limited to 'scripts/gendwarfksyms/dwarf.c')
-rw-r--r--scripts/gendwarfksyms/dwarf.c25
1 files changed, 22 insertions, 3 deletions
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;
}
-static bool is_kabi_definition(Dwarf_Die *die)
+static bool is_kabi_definition(struct die *cache, Dwarf_Die *die)
{
bool value;
if (get_flag_attr(die, DW_AT_declaration, &value) && value)
return false;
+ if (kabi_is_declonly(cache->fqn))
+ return false;
+
return !is_definition_private(die);
}
@@ -515,9 +518,10 @@ static void __process_structure_type(struct state *state, struct die *cache,
process(cache, " {");
process_linebreak(cache, 1);
- expand = state->expand.expand && is_kabi_definition(die);
+ expand = state->expand.expand && is_kabi_definition(cache, die);
if (expand) {
+ state->expand.current_fqn = 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 = false;
Dwarf_Word value;
+ 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 = kabi_get_enumerator_value(
+ state->expand.current_fqn, cache->fqn, &value);
+ }
+
process_list_comma(state, cache);
process(cache, "enumerator");
process_fqn(cache, die);
- if (get_udata_attr(die, DW_AT_const_value, &value)) {
+ if (overridden || get_udata_attr(die, DW_AT_const_value, &value)) {
process(cache, " = ");
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 = true;
+ state->expand.current_fqn = NULL;
cache_init(&state->expansion_cache);
}
@@ -627,6 +645,7 @@ static void expansion_state_restore(struct expansion_state *state,
struct expansion_state *saved)
{
state->expand = saved->expand;
+ state->current_fqn = saved->current_fqn;
}
static void expansion_state_save(struct expansion_state *state,