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 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 82 static inline unsigned int rule_hash(const struct rule *rule) 83 { 84 return rule_values_hash(rule->type, rule->target); 85 } 86 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 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 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 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 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 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 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 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