File Index
Files and directories
Sign in
FILE

kabi.c

File preview with syntax highlighting.

linux-6.19.14/scripts/gendwarfksyms/kabi.c C
  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
 71enum 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
 82struct 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 */
 90static HASHTABLE_DEFINE(rules, 1 << RULE_HASH_BITS);
 91
 92static 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
 98static inline unsigned int rule_hash(const struct rule *rule)
 99{
100	return rule_values_hash(rule->type, rule->target);
101}
102
103static 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
118void 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(*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
249static 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
259static 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
277static 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
295bool kabi_is_declonly(const char *fqn)
296{
297	return !!find_rule(KABI_RULE_TYPE_DECLONLY, fqn);
298}
299
300static 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
314bool 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
320bool 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
335bool 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
348bool 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
361void 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}
~/ Read-only file preview.