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