xref: /linux/scripts/gendwarfksyms/kabi.c (revision 8630c59e99363c4b655788fd01134aef9bcd9264)
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