xref: /linux/scripts/gendwarfksyms/kabi.c (revision ba6ec09911b805778a2fed6d626bfe77b011a717)
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 enum kabi_rule_type {
58 	KABI_RULE_TYPE_UNKNOWN,
59 	KABI_RULE_TYPE_DECLONLY,
60 	KABI_RULE_TYPE_ENUMERATOR_IGNORE,
61 	KABI_RULE_TYPE_ENUMERATOR_VALUE,
62 };
63 
64 #define RULE_HASH_BITS 7
65 
66 struct rule {
67 	enum kabi_rule_type type;
68 	const char *target;
69 	const char *value;
70 	struct hlist_node hash;
71 };
72 
73 /* { type, target } -> struct rule */
74 static HASHTABLE_DEFINE(rules, 1 << RULE_HASH_BITS);
75 
rule_values_hash(enum kabi_rule_type type,const char * target)76 static inline unsigned int rule_values_hash(enum kabi_rule_type type,
77 					    const char *target)
78 {
79 	return hash_32(type) ^ hash_str(target);
80 }
81 
rule_hash(const struct rule * rule)82 static inline unsigned int rule_hash(const struct rule *rule)
83 {
84 	return rule_values_hash(rule->type, rule->target);
85 }
86 
get_rule_field(const char ** pos,ssize_t * left)87 static inline const char *get_rule_field(const char **pos, ssize_t *left)
88 {
89 	const char *start = *pos;
90 	size_t len;
91 
92 	if (*left <= 0)
93 		error("unexpected end of kABI rules");
94 
95 	len = strnlen(start, *left) + 1;
96 	*pos += len;
97 	*left -= len;
98 
99 	return start;
100 }
101 
kabi_read_rules(int fd)102 void kabi_read_rules(int fd)
103 {
104 	GElf_Shdr shdr_mem;
105 	GElf_Shdr *shdr;
106 	Elf_Data *rule_data = NULL;
107 	Elf_Scn *scn;
108 	Elf *elf;
109 	size_t shstrndx;
110 	const char *rule_str;
111 	ssize_t left;
112 	int i;
113 
114 	const struct {
115 		enum kabi_rule_type type;
116 		const char *tag;
117 	} rule_types[] = {
118 		{
119 			.type = KABI_RULE_TYPE_DECLONLY,
120 			.tag = KABI_RULE_TAG_DECLONLY,
121 		},
122 		{
123 			.type = KABI_RULE_TYPE_ENUMERATOR_IGNORE,
124 			.tag = KABI_RULE_TAG_ENUMERATOR_IGNORE,
125 		},
126 		{
127 			.type = KABI_RULE_TYPE_ENUMERATOR_VALUE,
128 			.tag = KABI_RULE_TAG_ENUMERATOR_VALUE,
129 		},
130 	};
131 
132 	if (!stable)
133 		return;
134 
135 	if (elf_version(EV_CURRENT) != EV_CURRENT)
136 		error("elf_version failed: %s", elf_errmsg(-1));
137 
138 	elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
139 	if (!elf)
140 		error("elf_begin failed: %s", elf_errmsg(-1));
141 
142 	if (elf_getshdrstrndx(elf, &shstrndx) < 0)
143 		error("elf_getshdrstrndx failed: %s", elf_errmsg(-1));
144 
145 	scn = elf_nextscn(elf, NULL);
146 
147 	while (scn) {
148 		const char *sname;
149 
150 		shdr = gelf_getshdr(scn, &shdr_mem);
151 		if (!shdr)
152 			error("gelf_getshdr failed: %s", elf_errmsg(-1));
153 
154 		sname = elf_strptr(elf, shstrndx, shdr->sh_name);
155 		if (!sname)
156 			error("elf_strptr failed: %s", elf_errmsg(-1));
157 
158 		if (!strcmp(sname, KABI_RULE_SECTION)) {
159 			rule_data = elf_getdata(scn, NULL);
160 			if (!rule_data)
161 				error("elf_getdata failed: %s", elf_errmsg(-1));
162 			break;
163 		}
164 
165 		scn = elf_nextscn(elf, scn);
166 	}
167 
168 	if (!rule_data) {
169 		debug("kABI rules not found");
170 		check(elf_end(elf));
171 		return;
172 	}
173 
174 	rule_str = rule_data->d_buf;
175 	left = shdr->sh_size;
176 
177 	if (left < KABI_RULE_MIN_ENTRY_SIZE)
178 		error("kABI rule section too small: %zd bytes", left);
179 
180 	if (rule_str[left - 1] != '\0')
181 		error("kABI rules are not null-terminated");
182 
183 	while (left > KABI_RULE_MIN_ENTRY_SIZE) {
184 		enum kabi_rule_type type = KABI_RULE_TYPE_UNKNOWN;
185 		const char *field;
186 		struct rule *rule;
187 
188 		/* version */
189 		field = get_rule_field(&rule_str, &left);
190 
191 		if (strcmp(field, KABI_RULE_VERSION))
192 			error("unsupported kABI rule version: '%s'", field);
193 
194 		/* type */
195 		field = get_rule_field(&rule_str, &left);
196 
197 		for (i = 0; i < ARRAY_SIZE(rule_types); i++) {
198 			if (!strcmp(field, rule_types[i].tag)) {
199 				type = rule_types[i].type;
200 				break;
201 			}
202 		}
203 
204 		if (type == KABI_RULE_TYPE_UNKNOWN)
205 			error("unsupported kABI rule type: '%s'", field);
206 
207 		rule = xmalloc(sizeof(struct rule));
208 
209 		rule->type = type;
210 		rule->target = xstrdup(get_rule_field(&rule_str, &left));
211 		rule->value = xstrdup(get_rule_field(&rule_str, &left));
212 
213 		hash_add(rules, &rule->hash, rule_hash(rule));
214 
215 		debug("kABI rule: type: '%s', target: '%s', value: '%s'", field,
216 		      rule->target, rule->value);
217 	}
218 
219 	if (left > 0)
220 		warn("unexpected data at the end of the kABI rules section");
221 
222 	check(elf_end(elf));
223 }
224 
kabi_is_declonly(const char * fqn)225 bool kabi_is_declonly(const char *fqn)
226 {
227 	struct rule *rule;
228 
229 	if (!stable)
230 		return false;
231 	if (!fqn || !*fqn)
232 		return false;
233 
234 	hash_for_each_possible(rules, rule, hash,
235 			       rule_values_hash(KABI_RULE_TYPE_DECLONLY, fqn)) {
236 		if (rule->type == KABI_RULE_TYPE_DECLONLY &&
237 		    !strcmp(fqn, rule->target))
238 			return true;
239 	}
240 
241 	return false;
242 }
243 
get_enumerator_target(const char * fqn,const char * field)244 static char *get_enumerator_target(const char *fqn, const char *field)
245 {
246 	char *target = NULL;
247 
248 	if (asprintf(&target, "%s %s", fqn, field) < 0)
249 		error("asprintf failed for '%s %s'", fqn, field);
250 
251 	return target;
252 }
253 
get_ulong_value(const char * value)254 static unsigned long get_ulong_value(const char *value)
255 {
256 	unsigned long result = 0;
257 	char *endptr = NULL;
258 
259 	errno = 0;
260 	result = strtoul(value, &endptr, 10);
261 
262 	if (errno || *endptr)
263 		error("invalid unsigned value '%s'", value);
264 
265 	return result;
266 }
267 
kabi_is_enumerator_ignored(const char * fqn,const char * field)268 bool kabi_is_enumerator_ignored(const char *fqn, const char *field)
269 {
270 	bool match = false;
271 	struct rule *rule;
272 	char *target;
273 
274 	if (!stable)
275 		return false;
276 	if (!fqn || !*fqn || !field || !*field)
277 		return false;
278 
279 	target = get_enumerator_target(fqn, field);
280 
281 	hash_for_each_possible(
282 		rules, rule, hash,
283 		rule_values_hash(KABI_RULE_TYPE_ENUMERATOR_IGNORE, target)) {
284 		if (rule->type == KABI_RULE_TYPE_ENUMERATOR_IGNORE &&
285 		    !strcmp(target, rule->target)) {
286 			match = true;
287 			break;
288 		}
289 	}
290 
291 	free(target);
292 	return match;
293 }
294 
kabi_get_enumerator_value(const char * fqn,const char * field,unsigned long * value)295 bool kabi_get_enumerator_value(const char *fqn, const char *field,
296 			       unsigned long *value)
297 {
298 	bool match = false;
299 	struct rule *rule;
300 	char *target;
301 
302 	if (!stable)
303 		return false;
304 	if (!fqn || !*fqn || !field || !*field)
305 		return false;
306 
307 	target = get_enumerator_target(fqn, field);
308 
309 	hash_for_each_possible(rules, rule, hash,
310 			       rule_values_hash(KABI_RULE_TYPE_ENUMERATOR_VALUE,
311 						target)) {
312 		if (rule->type == KABI_RULE_TYPE_ENUMERATOR_VALUE &&
313 		    !strcmp(target, rule->target)) {
314 			*value = get_ulong_value(rule->value);
315 			match = true;
316 			break;
317 		}
318 	}
319 
320 	free(target);
321 	return match;
322 }
323 
kabi_free(void)324 void kabi_free(void)
325 {
326 	struct hlist_node *tmp;
327 	struct rule *rule;
328 
329 	hash_for_each_safe(rules, rule, tmp, hash) {
330 		free((void *)rule->target);
331 		free((void *)rule->value);
332 		free(rule);
333 	}
334 
335 	hash_init(rules);
336 }
337