Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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.

Signed-off-by: Sami Tolvanen <samitolvanen@google.com>
Reviewed-by: Petr Pavlu <petr.pavlu@suse.com>
Signed-off-by: Masahiro Yamada <masahiroy@kernel.org>

authored by

Sami Tolvanen and committed by
Masahiro Yamada
db59d74e ff2c5f5a

+70 -1
+13 -1
scripts/gendwarfksyms/dwarf.c
··· 228 228 DEFINE_PROCESS_UDATA_ATTRIBUTE(accessibility) 229 229 DEFINE_PROCESS_UDATA_ATTRIBUTE(alignment) 230 230 DEFINE_PROCESS_UDATA_ATTRIBUTE(bit_size) 231 - DEFINE_PROCESS_UDATA_ATTRIBUTE(byte_size) 232 231 DEFINE_PROCESS_UDATA_ATTRIBUTE(encoding) 233 232 DEFINE_PROCESS_UDATA_ATTRIBUTE(data_bit_offset) 234 233 DEFINE_PROCESS_UDATA_ATTRIBUTE(data_member_location) 235 234 DEFINE_PROCESS_UDATA_ATTRIBUTE(discr_value) 235 + 236 + static 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 + } 236 248 237 249 /* Match functions -- die_match_callback_t */ 238 250 #define DEFINE_MATCH(type) \
+7
scripts/gendwarfksyms/examples/kabi.h
··· 90 90 __KABI_RULE(enumerator_value, fqn field, value) 91 91 92 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 + 99 + /* 93 100 * KABI_RESERVE 94 101 * Reserve some "padding" in a structure for use by LTS backports. 95 102 * This is normally placed at the end of a structure.
+2
scripts/gendwarfksyms/examples/kabi_ex.c
··· 28 28 struct ex3a ex3a; 29 29 struct ex3b ex3b; 30 30 struct ex3c ex3c; 31 + 32 + struct ex4a ex4a;
+22
scripts/gendwarfksyms/examples/kabi_ex.h
··· 260 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 + 268 + struct 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 + */ 277 + KABI_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 285 #endif /* __KABI_EX_H__ */
+1
scripts/gendwarfksyms/gendwarfksyms.h
··· 287 287 * kabi.c 288 288 */ 289 289 290 + bool kabi_get_byte_size(const char *fqn, unsigned long *value); 290 291 bool kabi_is_enumerator_ignored(const char *fqn, const char *field); 291 292 bool kabi_get_enumerator_value(const char *fqn, const char *field, 292 293 unsigned long *value);
+25
scripts/gendwarfksyms/kabi.c
··· 54 54 */ 55 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 + 57 64 enum kabi_rule_type { 58 65 KABI_RULE_TYPE_UNKNOWN, 59 66 KABI_RULE_TYPE_DECLONLY, 60 67 KABI_RULE_TYPE_ENUMERATOR_IGNORE, 61 68 KABI_RULE_TYPE_ENUMERATOR_VALUE, 69 + KABI_RULE_TYPE_BYTE_SIZE, 62 70 }; 63 71 64 72 #define RULE_HASH_BITS 7 ··· 134 126 { 135 127 .type = KABI_RULE_TYPE_ENUMERATOR_VALUE, 136 128 .tag = KABI_RULE_TAG_ENUMERATOR_VALUE, 129 + }, 130 + { 131 + .type = KABI_RULE_TYPE_BYTE_SIZE, 132 + .tag = KABI_RULE_TAG_BYTE_SIZE, 137 133 }, 138 134 }; 139 135 ··· 312 300 313 301 rule = find_enumerator_rule(KABI_RULE_TYPE_ENUMERATOR_VALUE, fqn, 314 302 field); 303 + if (rule) { 304 + *value = get_ulong_value(rule->value); 305 + return true; 306 + } 307 + 308 + return false; 309 + } 310 + 311 + bool kabi_get_byte_size(const char *fqn, unsigned long *value) 312 + { 313 + struct rule *rule; 314 + 315 + rule = find_rule(KABI_RULE_TYPE_BYTE_SIZE, fqn); 315 316 if (rule) { 316 317 *value = get_ulong_value(rule->value); 317 318 return true;