1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Copyright (C) 2024 Google LLC
4 */
5
6 #define _GNU_SOURCE
7 #include <errno.h>
8 #include <stdio.h>
9
10 #include "gendwarfksyms.h"
11
12 #define KABI_RULE_SECTION ".discard.gendwarfksyms.kabi_rules"
13 #define KABI_RULE_VERSION "1"
14
15 /*
16 * The rule section consists of four null-terminated strings per
17 * entry:
18 *
19 * 1. version
20 * Entry format version. Must match KABI_RULE_VERSION.
21 *
22 * 2. type
23 * Type of the kABI rule. Must be one of the tags defined below.
24 *
25 * 3. target
26 * Rule-dependent target, typically the fully qualified name of
27 * the target DIE.
28 *
29 * 4. value
30 * Rule-dependent value.
31 */
32 #define KABI_RULE_MIN_ENTRY_SIZE \
33 (/* version\0 */ 2 + /* type\0 */ 2 + /* target\0" */ 1 + \
34 /* value\0 */ 1)
35 #define KABI_RULE_EMPTY_VALUE ""
36
37 /*
38 * Rule: declonly
39 * - For the struct/enum/union in the target field, treat it as a
40 * declaration only even if a definition is available.
41 */
42 #define KABI_RULE_TAG_DECLONLY "declonly"
43
44 /*
45 * Rule: enumerator_ignore
46 * - For the enum_field in the target field, ignore the enumerator.
47 */
48 #define KABI_RULE_TAG_ENUMERATOR_IGNORE "enumerator_ignore"
49
50 /*
51 * Rule: enumerator_value
52 * - For the fqn_field in the target field, set the value to the
53 * unsigned integer in the value field.
54 */
55 #define KABI_RULE_TAG_ENUMERATOR_VALUE "enumerator_value"
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
64 /*
65 * Rule: type_string
66 * - For the type reference in the fqn field, use the type string
67 * in the value field.
68 */
69 #define KABI_RULE_TAG_TYPE_STRING "type_string"
70
71 enum kabi_rule_type {
72 KABI_RULE_TYPE_UNKNOWN,
73 KABI_RULE_TYPE_DECLONLY,
74 KABI_RULE_TYPE_ENUMERATOR_IGNORE,
75 KABI_RULE_TYPE_ENUMERATOR_VALUE,
76 KABI_RULE_TYPE_BYTE_SIZE,
77 KABI_RULE_TYPE_TYPE_STRING,
78 };
79
80 #define RULE_HASH_BITS 7
81
82 struct rule {
83 enum kabi_rule_type type;
84 const char *target;
85 const char *value;
86 struct hlist_node hash;
87 };
88
89 /* { type, target } -> struct rule */
90 static HASHTABLE_DEFINE(rules, 1 << RULE_HASH_BITS);
91
rule_values_hash(enum kabi_rule_type type,const char * target)92 static inline unsigned int rule_values_hash(enum kabi_rule_type type,
93 const char *target)
94 {
95 return hash_32(type) ^ hash_str(target);
96 }
97
rule_hash(const struct rule * rule)98 static inline unsigned int rule_hash(const struct rule *rule)
99 {
100 return rule_values_hash(rule->type, rule->target);
101 }
102
get_rule_field(const char ** pos,ssize_t * left)103 static inline const char *get_rule_field(const char **pos, ssize_t *left)
104 {
105 const char *start = *pos;
106 size_t len;
107
108 if (*left <= 0)
109 error("unexpected end of kABI rules");
110
111 len = strnlen(start, *left) + 1;
112 *pos += len;
113 *left -= len;
114
115 return start;
116 }
117
kabi_read_rules(int fd)118 void kabi_read_rules(int fd)
119 {
120 GElf_Shdr shdr_mem;
121 GElf_Shdr *shdr;
122 Elf_Data *rule_data = NULL;
123 Elf_Scn *scn;
124 Elf *elf;
125 size_t shstrndx;
126 const char *rule_str;
127 ssize_t left;
128 int i;
129
130 const struct {
131 enum kabi_rule_type type;
132 const char *tag;
133 } rule_types[] = {
134 {
135 .type = KABI_RULE_TYPE_DECLONLY,
136 .tag = KABI_RULE_TAG_DECLONLY,
137 },
138 {
139 .type = KABI_RULE_TYPE_ENUMERATOR_IGNORE,
140 .tag = KABI_RULE_TAG_ENUMERATOR_IGNORE,
141 },
142 {
143 .type = KABI_RULE_TYPE_ENUMERATOR_VALUE,
144 .tag = KABI_RULE_TAG_ENUMERATOR_VALUE,
145 },
146 {
147 .type = KABI_RULE_TYPE_BYTE_SIZE,
148 .tag = KABI_RULE_TAG_BYTE_SIZE,
149 },
150 {
151 .type = KABI_RULE_TYPE_TYPE_STRING,
152 .tag = KABI_RULE_TAG_TYPE_STRING,
153 },
154 };
155
156 if (!stable)
157 return;
158
159 if (elf_version(EV_CURRENT) != EV_CURRENT)
160 error("elf_version failed: %s", elf_errmsg(-1));
161
162 elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
163 if (!elf)
164 error("elf_begin failed: %s", elf_errmsg(-1));
165
166 if (elf_getshdrstrndx(elf, &shstrndx) < 0)
167 error("elf_getshdrstrndx failed: %s", elf_errmsg(-1));
168
169 scn = elf_nextscn(elf, NULL);
170
171 while (scn) {
172 const char *sname;
173
174 shdr = gelf_getshdr(scn, &shdr_mem);
175 if (!shdr)
176 error("gelf_getshdr failed: %s", elf_errmsg(-1));
177
178 sname = elf_strptr(elf, shstrndx, shdr->sh_name);
179 if (!sname)
180 error("elf_strptr failed: %s", elf_errmsg(-1));
181
182 if (!strcmp(sname, KABI_RULE_SECTION)) {
183 rule_data = elf_getdata(scn, NULL);
184 if (!rule_data)
185 error("elf_getdata failed: %s", elf_errmsg(-1));
186 break;
187 }
188
189 scn = elf_nextscn(elf, scn);
190 }
191
192 if (!rule_data) {
193 debug("kABI rules not found");
194 check(elf_end(elf));
195 return;
196 }
197
198 rule_str = rule_data->d_buf;
199 left = shdr->sh_size;
200
201 if (left < KABI_RULE_MIN_ENTRY_SIZE)
202 error("kABI rule section too small: %zd bytes", left);
203
204 if (rule_str[left - 1] != '\0')
205 error("kABI rules are not null-terminated");
206
207 while (left > KABI_RULE_MIN_ENTRY_SIZE) {
208 enum kabi_rule_type type = KABI_RULE_TYPE_UNKNOWN;
209 const char *field;
210 struct rule *rule;
211
212 /* version */
213 field = get_rule_field(&rule_str, &left);
214
215 if (strcmp(field, KABI_RULE_VERSION))
216 error("unsupported kABI rule version: '%s'", field);
217
218 /* type */
219 field = get_rule_field(&rule_str, &left);
220
221 for (i = 0; i < ARRAY_SIZE(rule_types); i++) {
222 if (!strcmp(field, rule_types[i].tag)) {
223 type = rule_types[i].type;
224 break;
225 }
226 }
227
228 if (type == KABI_RULE_TYPE_UNKNOWN)
229 error("unsupported kABI rule type: '%s'", field);
230
231 rule = xmalloc(sizeof(struct rule));
232
233 rule->type = type;
234 rule->target = xstrdup(get_rule_field(&rule_str, &left));
235 rule->value = xstrdup(get_rule_field(&rule_str, &left));
236
237 hash_add(rules, &rule->hash, rule_hash(rule));
238
239 debug("kABI rule: type: '%s', target: '%s', value: '%s'", field,
240 rule->target, rule->value);
241 }
242
243 if (left > 0)
244 warn("unexpected data at the end of the kABI rules section");
245
246 check(elf_end(elf));
247 }
248
get_enumerator_target(const char * fqn,const char * field)249 static char *get_enumerator_target(const char *fqn, const char *field)
250 {
251 char *target = NULL;
252
253 if (asprintf(&target, "%s %s", fqn, field) < 0)
254 error("asprintf failed for '%s %s'", fqn, field);
255
256 return target;
257 }
258
find_rule(enum kabi_rule_type type,const char * target)259 static struct rule *find_rule(enum kabi_rule_type type, const char *target)
260 {
261 struct rule *rule;
262
263 if (!stable)
264 return NULL;
265 if (!target || !*target)
266 return NULL;
267
268 hash_for_each_possible(rules, rule, hash,
269 rule_values_hash(type, target)) {
270 if (rule->type == type && !strcmp(target, rule->target))
271 return rule;
272 }
273
274 return NULL;
275 }
276
find_enumerator_rule(enum kabi_rule_type type,const char * fqn,const char * field)277 static struct rule *find_enumerator_rule(enum kabi_rule_type type,
278 const char *fqn, const char *field)
279 {
280 struct rule *rule;
281 char *target;
282
283 if (!stable)
284 return NULL;
285 if (!fqn || !*fqn || !field || !*field)
286 return NULL;
287
288 target = get_enumerator_target(fqn, field);
289 rule = find_rule(type, target);
290
291 free(target);
292 return rule;
293 }
294
kabi_is_declonly(const char * fqn)295 bool kabi_is_declonly(const char *fqn)
296 {
297 return !!find_rule(KABI_RULE_TYPE_DECLONLY, fqn);
298 }
299
get_ulong_value(const char * value)300 static unsigned long get_ulong_value(const char *value)
301 {
302 unsigned long result = 0;
303 char *endptr = NULL;
304
305 errno = 0;
306 result = strtoul(value, &endptr, 10);
307
308 if (errno || *endptr)
309 error("invalid unsigned value '%s'", value);
310
311 return result;
312 }
313
kabi_is_enumerator_ignored(const char * fqn,const char * field)314 bool kabi_is_enumerator_ignored(const char *fqn, const char *field)
315 {
316 return !!find_enumerator_rule(KABI_RULE_TYPE_ENUMERATOR_IGNORE, fqn,
317 field);
318 }
319
kabi_get_enumerator_value(const char * fqn,const char * field,unsigned long * value)320 bool kabi_get_enumerator_value(const char *fqn, const char *field,
321 unsigned long *value)
322 {
323 struct rule *rule;
324
325 rule = find_enumerator_rule(KABI_RULE_TYPE_ENUMERATOR_VALUE, fqn,
326 field);
327 if (rule) {
328 *value = get_ulong_value(rule->value);
329 return true;
330 }
331
332 return false;
333 }
334
kabi_get_byte_size(const char * fqn,unsigned long * value)335 bool kabi_get_byte_size(const char *fqn, unsigned long *value)
336 {
337 struct rule *rule;
338
339 rule = find_rule(KABI_RULE_TYPE_BYTE_SIZE, fqn);
340 if (rule) {
341 *value = get_ulong_value(rule->value);
342 return true;
343 }
344
345 return false;
346 }
347
kabi_get_type_string(const char * type,const char ** str)348 bool kabi_get_type_string(const char *type, const char **str)
349 {
350 struct rule *rule;
351
352 rule = find_rule(KABI_RULE_TYPE_TYPE_STRING, type);
353 if (rule) {
354 *str = rule->value;
355 return true;
356 }
357
358 return false;
359 }
360
kabi_free(void)361 void kabi_free(void)
362 {
363 struct hlist_node *tmp;
364 struct rule *rule;
365
366 hash_for_each_safe(rules, rule, tmp, hash) {
367 free((void *)rule->target);
368 free((void *)rule->value);
369 free(rule);
370 }
371
372 hash_init(rules);
373 }
374