History

gendwarfksyms: Add a kABI rule to override byte_size attributes

A data structure can be partially opaque to modules if its allocation is handled by the core kernel, and modules only need to access some of its members. In this situation, it's possible to append new members to the structure without breaking the ABI, as long as the layout for the original members remains unchanged. For example, consider the following struct: struct s { unsigned long a; void *p; }; gendwarfksyms --stable --dump-dies produces the following type expansion: variable structure_type s { member base_type long unsigned int byte_size(8) encoding(7) a data_member_location(0) , member pointer_type { base_type void } byte_size(8) p data_member_location(8) } byte_size(16) To append new members, we can use the KABI_IGNORE() macro to hide them from gendwarfksyms --stable: struct s { /* old members with unchanged layout */ unsigned long a; void *p; /* new members not accessed by modules */ KABI_IGNORE(0, unsigned long n); }; However, we can't hide the fact that adding new members changes the struct size, as seen in the updated type string: variable structure_type s { member base_type long unsigned int byte_size(8) encoding(7) a data_member_location(0) , member pointer_type { base_type void } byte_size(8) p data_member_location(8) } byte_size(24) In order to support this use case, add a kABI rule that makes it possible to override the byte_size attribute for types: /* * struct s allocation is handled by the kernel, so * appending new members without changing the original * layout won't break the ABI. */ KABI_BYTE_SIZE(s, 16); This results in a type string that's unchanged from the original and therefore, won't change versions for symbols that reference the changed structure.

Sami Tolvanen committed 1 year ago

Commit db59d741 parent ff2c5f56 files · +70 −1Browse files

Showing the changes to scripts (6 of 6 files). Show all

Unified · Split

6 files
  1. scripts/gendwarfksyms/dwarf.c +13 −1
  2. scripts/gendwarfksyms/examples/kabi.h +7 −0
  3. scripts/gendwarfksyms/examples/kabi_ex.c +2 −0
  4. scripts/gendwarfksyms/examples/kabi_ex.h +22 −0
  5. scripts/gendwarfksyms/gendwarfksyms.h +1 −0
  6. scripts/gendwarfksyms/kabi.c +25 −0
scripts/gendwarfksyms/dwarf.c+13−1
@@ -228,12 +228,24 @@ static void process_fqn(struct die *cache, Dwarf_Die *die) · 227 unmodified lines
228DEFINE_PROCESS_UDATA_ATTRIBUTE(accessibility)228DEFINE_PROCESS_UDATA_ATTRIBUTE(accessibility)
229DEFINE_PROCESS_UDATA_ATTRIBUTE(alignment)229DEFINE_PROCESS_UDATA_ATTRIBUTE(alignment)
230DEFINE_PROCESS_UDATA_ATTRIBUTE(bit_size)230DEFINE_PROCESS_UDATA_ATTRIBUTE(bit_size)
231DEFINE_PROCESS_UDATA_ATTRIBUTE(byte_size)
232DEFINE_PROCESS_UDATA_ATTRIBUTE(encoding)231DEFINE_PROCESS_UDATA_ATTRIBUTE(encoding)
233DEFINE_PROCESS_UDATA_ATTRIBUTE(data_bit_offset)232DEFINE_PROCESS_UDATA_ATTRIBUTE(data_bit_offset)
234DEFINE_PROCESS_UDATA_ATTRIBUTE(data_member_location)233DEFINE_PROCESS_UDATA_ATTRIBUTE(data_member_location)
235DEFINE_PROCESS_UDATA_ATTRIBUTE(discr_value)234DEFINE_PROCESS_UDATA_ATTRIBUTE(discr_value)
236 235
236static void process_byte_size_attr(struct die *cache, Dwarf_Die *die)
237{
238 Dwarf_Word value;
239 unsigned long override;
240
241 if (get_udata_attr(die, DW_AT_byte_size, &value)) {
242 if (stable && kabi_get_byte_size(cache->fqn, &override))
243 value = override;
244
245 process_fmt(cache, " byte_size(%" PRIu64 ")", value);
246 }
247}
248
237/* Match functions -- die_match_callback_t */249/* Match functions -- die_match_callback_t */
238#define DEFINE_MATCH(type) \250#define DEFINE_MATCH(type) \
239 static bool match_##type##_type(Dwarf_Die *die) \251 static bool match_##type##_type(Dwarf_Die *die) \
scripts/gendwarfksyms/examples/kabi.h+7−0
@@ -89,6 +89,13 @@ · 88 unmodified lines
89#define KABI_ENUMERATOR_VALUE(fqn, field, value) \89#define KABI_ENUMERATOR_VALUE(fqn, field, value) \
90 __KABI_RULE(enumerator_value, fqn field, value)90 __KABI_RULE(enumerator_value, fqn field, value)
91 91
92/*
93 * KABI_BYTE_SIZE(fqn, value)
94 * Set the byte_size attribute for the struct/union/enum fqn to
95 * value bytes.
96 */
97#define KABI_BYTE_SIZE(fqn, value) __KABI_RULE(byte_size, fqn, value)
98
92/*99/*
93 * KABI_RESERVE100 * KABI_RESERVE
94 * Reserve some "padding" in a structure for use by LTS backports.101 * Reserve some "padding" in a structure for use by LTS backports.
scripts/gendwarfksyms/examples/kabi_ex.c+2−0
@@ -28,3 +28,5 @@ struct ex2c ex2c; · 27 unmodified lines
28struct ex3a ex3a;28struct ex3a ex3a;
29struct ex3b ex3b;29struct ex3b ex3b;
30struct ex3c ex3c;30struct ex3c ex3c;
31
32struct ex4a ex4a;
scripts/gendwarfksyms/examples/kabi_ex.h+22−0
@@ -260,4 +260,26 @@ _Static_assert(sizeof(struct ex3a) == sizeof(struct ex3c), "ex3a size doesn't ma · 259 unmodified lines
260 * STABLE-NEXT: } byte_size(16)260 * STABLE-NEXT: } byte_size(16)
261 */261 */
262 262
263/*
264 * Example: An ignored field added to an end of a partially opaque struct,
265 * while keeping the byte_size attribute unchanged.
266 */
267
268struct ex4a {
269 unsigned long a;
270 KABI_IGNORE(0, unsigned long b);
271};
272
273/*
274 * This may be safe if the structure allocation is managed by the core kernel
275 * and the layout remains unchanged except for appended new members.
276 */
277KABI_BYTE_SIZE(ex4a, 8);
278
279/*
280 * STABLE: variable structure_type ex4a {
281 * STABLE-NEXT: member base_type [[ULONG]] byte_size(8) encoding(7) a data_member_location(0)
282 * STABLE-NEXT: } byte_size(8)
283 */
284
263#endif /* __KABI_EX_H__ */285#endif /* __KABI_EX_H__ */
scripts/gendwarfksyms/gendwarfksyms.h+1−0
@@ -287,6 +287,7 @@ void generate_symtypes_and_versions(FILE *file); · 286 unmodified lines
287 * kabi.c287 * kabi.c
288 */288 */
289 289
290bool kabi_get_byte_size(const char *fqn, unsigned long *value);
290bool kabi_is_enumerator_ignored(const char *fqn, const char *field);291bool kabi_is_enumerator_ignored(const char *fqn, const char *field);
291bool kabi_get_enumerator_value(const char *fqn, const char *field,292bool kabi_get_enumerator_value(const char *fqn, const char *field,
292 unsigned long *value);293 unsigned long *value);
scripts/gendwarfksyms/kabi.c+25−0
@@ -54,11 +54,19 @@ · 53 unmodified lines
54 */54 */
55#define KABI_RULE_TAG_ENUMERATOR_VALUE "enumerator_value"55#define KABI_RULE_TAG_ENUMERATOR_VALUE "enumerator_value"
56 56
57/*
58 * Rule: byte_size
59 * - For the fqn_field in the target field, set the byte_size
60 * attribute to the value in the value field.
61 */
62#define KABI_RULE_TAG_BYTE_SIZE "byte_size"
63
57enum kabi_rule_type {64enum kabi_rule_type {
58 KABI_RULE_TYPE_UNKNOWN,65 KABI_RULE_TYPE_UNKNOWN,
59 KABI_RULE_TYPE_DECLONLY,66 KABI_RULE_TYPE_DECLONLY,
60 KABI_RULE_TYPE_ENUMERATOR_IGNORE,67 KABI_RULE_TYPE_ENUMERATOR_IGNORE,
61 KABI_RULE_TYPE_ENUMERATOR_VALUE,68 KABI_RULE_TYPE_ENUMERATOR_VALUE,
69 KABI_RULE_TYPE_BYTE_SIZE,
62};70};
63 71
64#define RULE_HASH_BITS 772#define RULE_HASH_BITS 7
@@ -127,6 +135,10 @@ void kabi_read_rules(int fd) · 62 unmodified lines
127 .type = KABI_RULE_TYPE_ENUMERATOR_VALUE,135 .type = KABI_RULE_TYPE_ENUMERATOR_VALUE,
128 .tag = KABI_RULE_TAG_ENUMERATOR_VALUE,136 .tag = KABI_RULE_TAG_ENUMERATOR_VALUE,
129 },137 },
138 {
139 .type = KABI_RULE_TYPE_BYTE_SIZE,
140 .tag = KABI_RULE_TAG_BYTE_SIZE,
141 },
130 };142 };
131 143
132 if (!stable)144 if (!stable)
@@ -308,6 +320,19 @@ bool kabi_get_enumerator_value(const char *fqn, const char *field, · 175 unmodified lines
308 return false;320 return false;
309}321}
310 322
323bool kabi_get_byte_size(const char *fqn, unsigned long *value)
324{
325 struct rule *rule;
326
327 rule = find_rule(KABI_RULE_TYPE_BYTE_SIZE, fqn);
328 if (rule) {
329 *value = get_ulong_value(rule->value);
330 return true;
331 }
332
333 return false;
334}
335
311void kabi_free(void)336void kabi_free(void)
312{337{
313 struct hlist_node *tmp;338 struct hlist_node *tmp;