ACPI AML decompiler w/ CFG recovery and structured pseudocode
29

Configure Feed

Select the types of activity you want to include in your feed.

tobi / src / nm.c
12 kB 430 lines
1#include "nm.h" 2 3#include "mem.h" 4#include "str.h" 5 6#include <ctype.h> 7#include <stdlib.h> 8#include <string.h> 9 10int tobi_nm_is_lead(unsigned char c) { 11 return (c >= 'A' && c <= 'Z') || c == '_'; 12} 13 14int tobi_nm_is_tail(unsigned char c) { 15 return tobi_nm_is_lead(c) || (c >= '0' && c <= '9'); 16} 17 18int tobi_nm_nameseg(tobi_rd *rd, char **out) { 19 size_t start = rd->pos; 20 uint8_t b[4]; 21 if (!tobi_rd_bytes(rd, b, sizeof(b))) { 22 rd->pos = start; 23 return 0; 24 } 25 if (!tobi_nm_is_lead(b[0])) { 26 rd->pos = start; 27 rd->failed = 1; 28 return 0; 29 } 30 for (size_t i = 1; i < 4; i++) { 31 if (!tobi_nm_is_tail(b[i])) { 32 rd->pos = start; 33 rd->failed = 1; 34 return 0; 35 } 36 } 37 *out = tobi_xstrndup((const char *)b, 4); 38 return 1; 39} 40 41static void add_seg(tobi_sb *sb, const char *seg, int *first) { 42 if (!*first && sb->len > 0 && sb->buf[sb->len - 1] != '\\' && sb->buf[sb->len - 1] != '^') { 43 tobi_sb_ch(sb, '.'); 44 } 45 tobi_sb_add(sb, seg); 46 *first = 0; 47} 48 49int tobi_nm_namestring(tobi_rd *rd, char **out) { 50 size_t start = rd->pos; 51 tobi_sb sb; 52 tobi_sb_init(&sb); 53 uint8_t b = 0; 54 int first = 1; 55 if (!tobi_rd_peek(rd, &b)) { 56 tobi_sb_free(&sb); 57 return 0; 58 } 59 if (b == '\\') { 60 (void)tobi_rd_u8(rd, &b); 61 tobi_sb_ch(&sb, '\\'); 62 } else { 63 while (tobi_rd_peek(rd, &b) && b == '^') { 64 (void)tobi_rd_u8(rd, &b); 65 tobi_sb_ch(&sb, '^'); 66 } 67 } 68 if (!tobi_rd_peek(rd, &b)) { 69 tobi_sb_free(&sb); 70 rd->pos = start; 71 return 0; 72 } 73 if (b == 0x00) { 74 (void)tobi_rd_u8(rd, &b); 75 if (sb.len == 0) { 76 tobi_sb_add(&sb, "<null>"); 77 } 78 *out = tobi_sb_take(&sb); 79 return 1; 80 } 81 if (b == 0x2e) { 82 (void)tobi_rd_u8(rd, &b); 83 for (int i = 0; i < 2; i++) { 84 char *seg = NULL; 85 if (!tobi_nm_nameseg(rd, &seg)) { 86 tobi_sb_free(&sb); 87 rd->pos = start; 88 return 0; 89 } 90 add_seg(&sb, seg, &first); 91 free(seg); 92 } 93 *out = tobi_sb_take(&sb); 94 return 1; 95 } 96 if (b == 0x2f) { 97 (void)tobi_rd_u8(rd, &b); 98 uint8_t count = 0; 99 if (!tobi_rd_u8(rd, &count) || count == 0) { 100 tobi_sb_free(&sb); 101 rd->pos = start; 102 rd->failed = 1; 103 return 0; 104 } 105 for (uint8_t i = 0; i < count; i++) { 106 char *seg = NULL; 107 if (!tobi_nm_nameseg(rd, &seg)) { 108 tobi_sb_free(&sb); 109 rd->pos = start; 110 return 0; 111 } 112 add_seg(&sb, seg, &first); 113 free(seg); 114 } 115 *out = tobi_sb_take(&sb); 116 return 1; 117 } 118 char *seg = NULL; 119 if (!tobi_nm_nameseg(rd, &seg)) { 120 tobi_sb_free(&sb); 121 rd->pos = start; 122 return 0; 123 } 124 add_seg(&sb, seg, &first); 125 free(seg); 126 *out = tobi_sb_take(&sb); 127 return 1; 128} 129 130static char *pop_scope(const char *scope) { 131 if (!scope || strcmp(scope, "\\") == 0 || scope[0] == '\0') { 132 return tobi_xstrdup("\\"); 133 } 134 const char *last = strrchr(scope, '.'); 135 if (!last) { 136 return tobi_xstrdup("\\"); 137 } 138 return tobi_xstrndup(scope, (size_t)(last - scope)); 139} 140 141char *tobi_nm_resolve(const char *scope, const char *name) { 142 if (!name || name[0] == '\0') { 143 return tobi_xstrdup(scope && scope[0] ? scope : "\\"); 144 } 145 if (name[0] == '\\') { 146 return tobi_xstrdup(name); 147 } 148 char *cur = tobi_xstrdup(scope && scope[0] ? scope : "\\"); 149 const char *rest = name; 150 while (*rest == '^') { 151 char *p = pop_scope(cur); 152 free(cur); 153 cur = p; 154 rest++; 155 } 156 if (*rest == '\0' || strcmp(rest, "<null>") == 0) { 157 return cur; 158 } 159 tobi_sb sb; 160 tobi_sb_init(&sb); 161 if (strcmp(cur, "\\") == 0) { 162 tobi_sb_add(&sb, "\\"); 163 tobi_sb_add(&sb, rest); 164 } else { 165 tobi_sb_add(&sb, cur); 166 tobi_sb_ch(&sb, '.'); 167 tobi_sb_add(&sb, rest); 168 } 169 free(cur); 170 return tobi_sb_take(&sb); 171} 172 173void tobi_ns_init(tobi_ns *ns) { 174 ns->items = NULL; 175 ns->len = 0; 176 ns->cap = 0; 177} 178 179static void ns_ent_free(tobi_ns_ent *e) { 180 free(e->path); 181 free(e->name); 182 free(e->owner); 183 free(e->target); 184 free(e->source); 185} 186 187void tobi_ns_free(tobi_ns *ns) { 188 if (!ns) { 189 return; 190 } 191 for (size_t i = 0; i < ns->len; i++) { 192 ns_ent_free(&ns->items[i]); 193 } 194 free(ns->items); 195 ns->items = NULL; 196 ns->len = 0; 197 ns->cap = 0; 198} 199 200const char *tobi_ns_kind_name(tobi_ns_kind kind) { 201 switch (kind) { 202 case TOBI_NS_UNKNOWN: return "unknown"; 203 case TOBI_NS_SCOPE: return "scope"; 204 case TOBI_NS_DEVICE: return "device"; 205 case TOBI_NS_METHOD: return "method"; 206 case TOBI_NS_PROCESSOR: return "processor"; 207 case TOBI_NS_NAME: return "name"; 208 case TOBI_NS_ALIAS: return "alias"; 209 case TOBI_NS_OPREGION: return "opregion"; 210 case TOBI_NS_FIELD: return "field"; 211 case TOBI_NS_MUTEX: return "mutex"; 212 case TOBI_NS_EVENT: return "event"; 213 case TOBI_NS_EXTERNAL: return "external"; 214 } 215 return "invalid"; 216} 217 218const char *tobi_ns_leaf(const char *path) { 219 if (!path || path[0] == '\0') { 220 return ""; 221 } 222 const char *dot = strrchr(path, '.'); 223 if (dot && dot[1]) { 224 return dot + 1; 225 } 226 if (path[0] == '\\') { 227 return path + 1; 228 } 229 return path; 230} 231 232tobi_ns_ent *tobi_ns_find(tobi_ns *ns, const char *path) { 233 if (!ns || !path) { 234 return NULL; 235 } 236 for (size_t i = 0; i < ns->len; i++) { 237 if (strcmp(ns->items[i].path, path) == 0) { 238 return &ns->items[i]; 239 } 240 } 241 return NULL; 242} 243 244const tobi_ns_ent *tobi_ns_find_const(const tobi_ns *ns, const char *path) { 245 if (!ns || !path) { 246 return NULL; 247 } 248 for (size_t i = 0; i < ns->len; i++) { 249 if (strcmp(ns->items[i].path, path) == 0) { 250 return &ns->items[i]; 251 } 252 } 253 return NULL; 254} 255 256const tobi_ns_ent *tobi_ns_find_method(const tobi_ns *ns, const char *name) { 257 if (!ns || !name) { 258 return NULL; 259 } 260 for (size_t i = 0; i < ns->len; i++) { 261 const tobi_ns_ent *e = &ns->items[i]; 262 if (e->kind == TOBI_NS_METHOD && strcmp(e->path, name) == 0) { 263 return e; 264 } 265 } 266 for (size_t i = 0; i < ns->len; i++) { 267 const tobi_ns_ent *e = &ns->items[i]; 268 if (e->kind == TOBI_NS_METHOD && strcmp(e->name, name) == 0) { 269 return e; 270 } 271 } 272 const char *leaf = strrchr(name, '.'); 273 leaf = leaf ? leaf + 1 : name; 274 for (size_t i = 0; i < ns->len; i++) { 275 const tobi_ns_ent *e = &ns->items[i]; 276 if (e->kind == TOBI_NS_METHOD && strcmp(e->name, leaf) == 0) { 277 return e; 278 } 279 } 280 return NULL; 281} 282 283static char *ns_parent(const char *scope) { 284 if (!scope || strcmp(scope, "\\") == 0 || scope[0] == '\0') { 285 return NULL; 286 } 287 const char *dot = strrchr(scope, '.'); 288 if (!dot) { 289 return tobi_xstrdup("\\"); 290 } 291 if (dot == scope || (scope[0] == '\\' && dot == scope + 1)) { 292 return tobi_xstrdup("\\"); 293 } 294 return tobi_xstrndup(scope, (size_t)(dot - scope)); 295} 296 297static char *ns_join(const char *scope, const char *name) { 298 tobi_sb sb; 299 tobi_sb_init(&sb); 300 if (!scope || scope[0] == '\0' || strcmp(scope, "\\") == 0) { 301 tobi_sb_add(&sb, "\\"); 302 tobi_sb_add(&sb, name); 303 } else { 304 tobi_sb_add(&sb, scope); 305 tobi_sb_ch(&sb, '.'); 306 tobi_sb_add(&sb, name); 307 } 308 return tobi_sb_take(&sb); 309} 310 311static const tobi_ns_ent *ns_follow_alias(const tobi_ns *ns, const tobi_ns_ent *ent) { 312 const tobi_ns_ent *cur = ent; 313 for (unsigned i = 0; cur && cur->kind == TOBI_NS_ALIAS && cur->target && i < 16; i++) { 314 const tobi_ns_ent *next = tobi_ns_find_const(ns, cur->target); 315 if (!next || next == cur) { 316 break; 317 } 318 cur = next; 319 } 320 return cur; 321} 322 323const tobi_ns_ent *tobi_ns_lookup(const tobi_ns *ns, const char *scope, const char *name) { 324 if (!ns || !name || name[0] == '\0') { 325 return NULL; 326 } 327 if (name[0] == '\\' || name[0] == '^' || strcmp(name, "<null>") == 0) { 328 char *path = tobi_nm_resolve(scope, name); 329 const tobi_ns_ent *ent = ns_follow_alias(ns, tobi_ns_find_const(ns, path)); 330 free(path); 331 return ent; 332 } 333 char *cur = tobi_xstrdup(scope && scope[0] ? scope : "\\"); 334 for (;;) { 335 char *candidate = ns_join(cur, name); 336 const tobi_ns_ent *ent = ns_follow_alias(ns, tobi_ns_find_const(ns, candidate)); 337 free(candidate); 338 if (ent) { 339 free(cur); 340 return ent; 341 } 342 char *parent = ns_parent(cur); 343 free(cur); 344 if (!parent) { 345 break; 346 } 347 cur = parent; 348 } 349 char *root = ns_join("\\", name); 350 const tobi_ns_ent *ent = ns_follow_alias(ns, tobi_ns_find_const(ns, root)); 351 free(root); 352 return ent; 353} 354 355char *tobi_ns_resolve_path(const tobi_ns *ns, const char *scope, const char *name) { 356 const tobi_ns_ent *ent = tobi_ns_lookup(ns, scope, name); 357 if (ent) { 358 return tobi_xstrdup(ent->path); 359 } 360 return tobi_nm_resolve(scope, name); 361} 362 363tobi_ns_ent *tobi_ns_add(tobi_ns *ns, tobi_ns_kind kind, const char *path, const char *owner, 364 size_t off, unsigned args, unsigned flags, int external, 365 const char *target, int *duplicate) { 366 if (duplicate) { 367 *duplicate = 0; 368 } 369 if (!ns || !path || path[0] == '\0') { 370 return NULL; 371 } 372 tobi_ns_ent *old = tobi_ns_find(ns, path); 373 if (old) { 374 int old_is_external = old->external || old->kind == TOBI_NS_EXTERNAL; 375 int same_scope = old->kind == TOBI_NS_SCOPE && kind == TOBI_NS_SCOPE; 376 int same_decl = old->kind == kind && old->off == off; 377 if (duplicate && !same_decl && !same_scope && !(old_is_external && !external)) { 378 *duplicate = 1; 379 } 380 if (old_is_external && !external) { 381 old->kind = kind; 382 old->external = 0; 383 old->off = off; 384 old->args = args; 385 } else if (kind == TOBI_NS_METHOD && old->kind == TOBI_NS_METHOD) { 386 old->args = args; 387 } 388 old->flags = flags; 389 if (target) { 390 free(old->target); 391 old->target = tobi_xstrdup(target); 392 } 393 return old; 394 } 395 if (ns->len == ns->cap) { 396 ns->cap = tobi_xgrow_cap(ns->cap, ns->len + 1u, 16u); 397 ns->items = tobi_xrealloc(ns->items, tobi_xmul_size(ns->cap, sizeof(ns->items[0]))); 398 } 399 tobi_ns_ent *e = &ns->items[ns->len++]; 400 memset(e, 0, sizeof(*e)); 401 e->path = tobi_xstrdup(path); 402 e->name = tobi_xstrdup(tobi_ns_leaf(path)); 403 e->owner = tobi_xstrdup(owner && owner[0] ? owner : "\\"); 404 e->target = target ? tobi_xstrdup(target) : NULL; 405 e->kind = kind; 406 e->off = off; 407 e->args = args; 408 e->flags = flags; 409 e->external = external; 410 return e; 411} 412 413void tobi_ns_ent_set_source(tobi_ns_ent *e, const char *source, size_t input_index) { 414 if (!e || !source) { 415 return; 416 } 417 free(e->source); 418 e->source = tobi_xstrdup(source); 419 e->input_index = input_index; 420 e->has_source = 1; 421} 422 423void tobi_ns_set_source(tobi_ns *ns, const char *source, size_t input_index) { 424 if (!ns || !source) { 425 return; 426 } 427 for (size_t i = 0; i < ns->len; i++) { 428 tobi_ns_ent_set_source(&ns->items[i], source, input_index); 429 } 430}