ACPI AML decompiler w/ CFG recovery and structured pseudocode
29

Configure Feed

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

Materialise namespace provenance database for AML semantic resolution

+352 -121
-4
README.md
··· 114 114 m2 14 20 57 4c 4f 30 01 70 0a 03 60 a2 13 60 a0 06 68 70 0a 01 61 a1 05 70 0a 02 61 74 60 01 60 a4 61 115 115 dev0 10 31 5c 5f 53 42 5f 5b 82 29 44 45 56 30 5b 80 52 45 47 30 01 0a 10 0a 04 5b 81 0b 52 45 47 30 00 46 4c 44 30 08 14 0b 52 44 4d 30 00 a4 46 4c 44 116 116 ``` 117 - 118 - ## Limits 119 - 120 - This isnt a full ACPICA replacement. Namespace resolution is enough for method-call arity and readable paths but unresolved names can remain refs. Resource descriptors are recognised before theyre fully decoded. Less-structured AML stays as labelled IR/commentary instead of getting rewritten into invented source constructs. Unknown opcode coverage should shrink by adding metadata and operand parsers, not by special casing sample bytes
-5
src/cf.c
··· 135 135 } else if (n->kind == TOBI_IR_WHILE) { 136 136 if (n->child_len > 1) { 137 137 dot_block(sb, n->child[1], id, "while-body", next); 138 - /* 139 - * The body is package-bounded in AML, so a back edge to the 140 - * loop header is justified even when the body internals are only 141 - * partially understood. 142 - */ 143 138 tobi_sb_printf(sb, " n%zu -> n%zu [label=\"back\"];\n", (*next) - 1u, id); 144 139 } 145 140 }
-2
src/cf.h
··· 4 4 #include "dg.h" 5 5 #include "ir.h" 6 6 7 - /** Recover and validate structured control flow already delimited by AML packages. */ 8 7 int tobi_cf_recover(tobi_ir *root, tobi_diag_list *diag); 9 8 10 - /** Emit a deterministic Graphviz DOT view of recovered control flow. */ 11 9 char *tobi_cf_dot(const tobi_ir *root); 12 10 13 11 #endif
-1
src/da.h
··· 6 6 #include <stddef.h> 7 7 #include <stdint.h> 8 8 9 - /** Emit opcode-level AML disassembly for a raw blob or ACPI table. */ 10 9 char *tobi_da_emit(const uint8_t *data, size_t len, const tobi_input_meta *meta); 11 10 12 11 #endif
-1
src/dc.h
··· 4 4 #include "dg.h" 5 5 #include "ir.h" 6 6 7 - /** Emit deterministic readable pseudocode for an IR tree. */ 8 7 char *tobi_dc_emit(const tobi_ir *root, const tobi_diag_list *diag); 9 8 10 9 #endif
-5
src/dg.h
··· 20 20 size_t cap; 21 21 } tobi_diag_list; 22 22 23 - /** Initialise an empty diagnostic list. */ 24 23 void tobi_diag_init(tobi_diag_list *dl); 25 24 26 - /** Free all diagnostics and list storage. */ 27 25 void tobi_diag_free(tobi_diag_list *dl); 28 26 29 - /** Add a formatted diagnostic at a source offset. */ 30 27 void tobi_diag_add(tobi_diag_list *dl, tobi_diag_level level, size_t off, const char *fmt, ...); 31 28 32 - /** Return non-zero when any diagnostic is an error. */ 33 29 int tobi_diag_has_error(const tobi_diag_list *dl); 34 30 35 - /** Return a stable textual name for a diagnostic level. */ 36 31 const char *tobi_diag_level_name(tobi_diag_level level); 37 32 38 33 #endif
-9
src/ir.h
··· 52 52 size_t child_cap; 53 53 } tobi_ir; 54 54 55 - /** Allocate a new IR node with source offset and length. */ 56 55 tobi_ir *tobi_ir_new(tobi_ir_kind kind, size_t off, size_t len); 57 56 58 - /** Recursively free an IR tree. */ 59 57 void tobi_ir_free(tobi_ir *node); 60 58 61 - /** Append child to parent, transferring ownership. */ 62 59 void tobi_ir_add(tobi_ir *parent, tobi_ir *child); 63 60 64 - /** Set node name by copying s. */ 65 61 void tobi_ir_set_name(tobi_ir *node, const char *s); 66 62 67 - /** Set resolved namespace path by copying s. */ 68 63 void tobi_ir_set_path(tobi_ir *node, const char *s); 69 64 70 - /** Set string payload by copying s. */ 71 65 void tobi_ir_set_str(tobi_ir *node, const char *s); 72 66 73 - /** Return a stable textual name for an IR kind. */ 74 67 const char *tobi_ir_kind_name(tobi_ir_kind kind); 75 68 76 - /** Return first direct child of kind or NULL when absent. */ 77 69 tobi_ir *tobi_ir_find_child(tobi_ir *node, tobi_ir_kind kind); 78 70 79 - /** Count direct children with a specific kind. */ 80 71 size_t tobi_ir_count_kind(const tobi_ir *node, tobi_ir_kind kind); 81 72 82 73 #endif
+29 -1
src/js.c
··· 63 63 tobi_sb_add(sb, "]}"); 64 64 } 65 65 66 + static void namespace_emit(tobi_sb *sb, const tobi_parse_result *res) { 67 + tobi_sb_add(sb, "\"namespace\":["); 68 + for (size_t i = 0; i < res->ns.len; i++) { 69 + const tobi_ns_ent *e = &res->ns.items[i]; 70 + if (i) { 71 + tobi_sb_ch(sb, ','); 72 + } 73 + tobi_sb_add(sb, "{\"kind\":"); 74 + tobi_json_string(sb, tobi_ns_kind_name(e->kind)); 75 + tobi_sb_add(sb, ",\"path\":"); 76 + tobi_json_string(sb, e->path); 77 + tobi_sb_add(sb, ",\"name\":"); 78 + tobi_json_string(sb, e->name); 79 + tobi_sb_add(sb, ",\"owner\":"); 80 + tobi_json_string(sb, e->owner); 81 + tobi_sb_printf(sb, ",\"offset\":%zu,\"args\":%u,\"flags\":%u,\"external\":%s", 82 + e->off, e->args, e->flags, e->external ? "true" : "false"); 83 + if (e->target) { 84 + tobi_sb_add(sb, ",\"target\":"); 85 + tobi_json_string(sb, e->target); 86 + } 87 + tobi_sb_ch(sb, '}'); 88 + } 89 + tobi_sb_ch(sb, ']'); 90 + } 91 + 66 92 char *tobi_js_emit(const tobi_parse_result *res) { 67 93 tobi_sb sb; 68 94 tobi_sb_init(&sb); ··· 85 111 tobi_json_string(&sb, res->diag.items[i].msg); 86 112 tobi_sb_ch(&sb, '}'); 87 113 } 88 - tobi_sb_add(&sb, "],\"ir\":"); 114 + tobi_sb_add(&sb, "],"); 115 + namespace_emit(&sb, res); 116 + tobi_sb_add(&sb, ",\"ir\":"); 89 117 if (res->root) { 90 118 node(&sb, res->root); 91 119 } else {
-1
src/js.h
··· 5 5 #include "ir.h" 6 6 #include "p.h" 7 7 8 - /** Emit valid JSON for parse metadata, diagnostics, and IR. */ 9 8 char *tobi_js_emit(const tobi_parse_result *res); 10 9 11 10 #endif
+6 -4
src/main.c
··· 135 135 tobi_parse_result one; 136 136 int ok = tobi_parse(data[i], lens[i], strict, &one); 137 137 if (mode_raw) { 138 - printf("input=%s\nformat=%s\nis_table=%s\ntable_length=%zu\naml_offset=%zu\naml_length=%zu\nchecksum_sum=0x%02x\nchecksum_valid=%s\n", 138 + printf("input=%s\nformat=%s\nis_table=%s\ntable_length=%zu\naml_offset=%zu\naml_length=%zu\nchecksum_sum=0x%02x\nchecksum_valid=%s\nnamespace_objects=%zu\n", 139 139 files[i], one.meta.signature, one.meta.is_table ? "true" : "false", 140 140 one.meta.table_len, one.meta.aml_off, one.meta.aml_len, 141 - (unsigned)one.meta.checksum_sum, one.meta.checksum_valid ? "true" : "false"); 141 + (unsigned)one.meta.checksum_sum, one.meta.checksum_valid ? "true" : "false", 142 + one.ns.len); 142 143 } else { 143 144 if (file_len > 1) { 144 145 printf("== %s ==\n", files[i]); ··· 188 189 } 189 190 (void)tobi_cf_recover(res.root, &res.diag); 190 191 if (mode_raw) { 191 - printf("input=%s\nformat=%s\nis_table=%s\ntable_length=%zu\naml_offset=%zu\naml_length=%zu\nchecksum_sum=0x%02x\nchecksum_valid=%s\n", 192 + printf("input=%s\nformat=%s\nis_table=%s\ntable_length=%zu\naml_offset=%zu\naml_length=%zu\nchecksum_sum=0x%02x\nchecksum_valid=%s\nnamespace_objects=%zu\n", 192 193 files[0], res.meta.signature, res.meta.is_table ? "true" : "false", 193 194 res.meta.table_len, res.meta.aml_off, res.meta.aml_len, 194 - (unsigned)res.meta.checksum_sum, res.meta.checksum_valid ? "true" : "false"); 195 + (unsigned)res.meta.checksum_sum, res.meta.checksum_valid ? "true" : "false", 196 + res.ns.len); 195 197 } else if (mode_json) { 196 198 char *s = tobi_js_emit(&res); 197 199 fputs(s, stdout);
-5
src/mem.h
··· 3 3 4 4 #include <stddef.h> 5 5 6 - /** Allocate n bytes or terminate the process on allocation failure. */ 7 6 void *tobi_xmalloc(size_t n); 8 7 9 - /** Allocate zeroed storage for count elements of size bytes or terminate. */ 10 8 void *tobi_xcalloc(size_t count, size_t size); 11 9 12 - /** Resize an allocation or terminate the process on allocation failure. */ 13 10 void *tobi_xrealloc(void *ptr, size_t n); 14 11 15 - /** Duplicate a NUL-terminated string or terminate on allocation failure. */ 16 12 char *tobi_xstrdup(const char *s); 17 13 18 - /** Duplicate exactly n bytes from a string and add a NUL terminator. */ 19 14 char *tobi_xstrndup(const char *s, size_t n); 20 15 21 16 #endif
+159
src/nm.c
··· 169 169 free(cur); 170 170 return tobi_sb_take(&sb); 171 171 } 172 + 173 + void tobi_ns_init(tobi_ns *ns) { 174 + ns->items = NULL; 175 + ns->len = 0; 176 + ns->cap = 0; 177 + } 178 + 179 + static 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 + } 185 + 186 + void tobi_ns_free(tobi_ns *ns) { 187 + if (!ns) { 188 + return; 189 + } 190 + for (size_t i = 0; i < ns->len; i++) { 191 + ns_ent_free(&ns->items[i]); 192 + } 193 + free(ns->items); 194 + ns->items = NULL; 195 + ns->len = 0; 196 + ns->cap = 0; 197 + } 198 + 199 + const char *tobi_ns_kind_name(tobi_ns_kind kind) { 200 + switch (kind) { 201 + case TOBI_NS_UNKNOWN: return "unknown"; 202 + case TOBI_NS_SCOPE: return "scope"; 203 + case TOBI_NS_DEVICE: return "device"; 204 + case TOBI_NS_METHOD: return "method"; 205 + case TOBI_NS_PROCESSOR: return "processor"; 206 + case TOBI_NS_NAME: return "name"; 207 + case TOBI_NS_ALIAS: return "alias"; 208 + case TOBI_NS_OPREGION: return "opregion"; 209 + case TOBI_NS_FIELD: return "field"; 210 + case TOBI_NS_MUTEX: return "mutex"; 211 + case TOBI_NS_EVENT: return "event"; 212 + case TOBI_NS_EXTERNAL: return "external"; 213 + } 214 + return "invalid"; 215 + } 216 + 217 + const char *tobi_ns_leaf(const char *path) { 218 + if (!path || path[0] == '\0') { 219 + return ""; 220 + } 221 + const char *dot = strrchr(path, '.'); 222 + if (dot && dot[1]) { 223 + return dot + 1; 224 + } 225 + if (path[0] == '\\') { 226 + return path + 1; 227 + } 228 + return path; 229 + } 230 + 231 + tobi_ns_ent *tobi_ns_find(tobi_ns *ns, const char *path) { 232 + if (!ns || !path) { 233 + return NULL; 234 + } 235 + for (size_t i = 0; i < ns->len; i++) { 236 + if (strcmp(ns->items[i].path, path) == 0) { 237 + return &ns->items[i]; 238 + } 239 + } 240 + return NULL; 241 + } 242 + 243 + const tobi_ns_ent *tobi_ns_find_const(const tobi_ns *ns, const char *path) { 244 + if (!ns || !path) { 245 + return NULL; 246 + } 247 + for (size_t i = 0; i < ns->len; i++) { 248 + if (strcmp(ns->items[i].path, path) == 0) { 249 + return &ns->items[i]; 250 + } 251 + } 252 + return NULL; 253 + } 254 + 255 + const tobi_ns_ent *tobi_ns_find_method(const tobi_ns *ns, const char *name) { 256 + if (!ns || !name) { 257 + return NULL; 258 + } 259 + for (size_t i = 0; i < ns->len; i++) { 260 + const tobi_ns_ent *e = &ns->items[i]; 261 + if (e->kind == TOBI_NS_METHOD && strcmp(e->path, name) == 0) { 262 + return e; 263 + } 264 + } 265 + for (size_t i = 0; i < ns->len; i++) { 266 + const tobi_ns_ent *e = &ns->items[i]; 267 + if (e->kind == TOBI_NS_METHOD && strcmp(e->name, name) == 0) { 268 + return e; 269 + } 270 + } 271 + const char *leaf = strrchr(name, '.'); 272 + leaf = leaf ? leaf + 1 : name; 273 + for (size_t i = 0; i < ns->len; i++) { 274 + const tobi_ns_ent *e = &ns->items[i]; 275 + if (e->kind == TOBI_NS_METHOD && strcmp(e->name, leaf) == 0) { 276 + return e; 277 + } 278 + } 279 + return NULL; 280 + } 281 + 282 + tobi_ns_ent *tobi_ns_add(tobi_ns *ns, tobi_ns_kind kind, const char *path, const char *owner, 283 + size_t off, unsigned args, unsigned flags, int external, 284 + const char *target, int *duplicate) { 285 + if (duplicate) { 286 + *duplicate = 0; 287 + } 288 + if (!ns || !path || path[0] == '\0') { 289 + return NULL; 290 + } 291 + tobi_ns_ent *old = tobi_ns_find(ns, path); 292 + if (old) { 293 + int old_is_external = old->external || old->kind == TOBI_NS_EXTERNAL; 294 + int same_scope = old->kind == TOBI_NS_SCOPE && kind == TOBI_NS_SCOPE; 295 + int same_decl = old->kind == kind && old->off == off; 296 + if (duplicate && !same_decl && !same_scope && !(old_is_external && !external)) { 297 + *duplicate = 1; 298 + } 299 + if (old_is_external && !external) { 300 + old->kind = kind; 301 + old->external = 0; 302 + old->off = off; 303 + old->args = args; 304 + } else if (kind == TOBI_NS_METHOD && old->kind == TOBI_NS_METHOD) { 305 + old->args = args; 306 + } 307 + old->flags = flags; 308 + if (target) { 309 + free(old->target); 310 + old->target = tobi_xstrdup(target); 311 + } 312 + return old; 313 + } 314 + if (ns->len == ns->cap) { 315 + ns->cap = ns->cap ? ns->cap * 2 : 16; 316 + ns->items = tobi_xrealloc(ns->items, ns->cap * sizeof(ns->items[0])); 317 + } 318 + tobi_ns_ent *e = &ns->items[ns->len++]; 319 + memset(e, 0, sizeof(*e)); 320 + e->path = tobi_xstrdup(path); 321 + e->name = tobi_xstrdup(tobi_ns_leaf(path)); 322 + e->owner = tobi_xstrdup(owner && owner[0] ? owner : "\\"); 323 + e->target = target ? tobi_xstrdup(target) : NULL; 324 + e->kind = kind; 325 + e->off = off; 326 + e->args = args; 327 + e->flags = flags; 328 + e->external = external; 329 + return e; 330 + }
+54 -5
src/nm.h
··· 3 3 4 4 #include "rd.h" 5 5 6 - /** Return non-zero when c may start an AML NameSeg. */ 6 + #include <stddef.h> 7 + #include <stdint.h> 8 + 9 + typedef enum tobi_ns_kind { 10 + TOBI_NS_UNKNOWN, 11 + TOBI_NS_SCOPE, 12 + TOBI_NS_DEVICE, 13 + TOBI_NS_METHOD, 14 + TOBI_NS_PROCESSOR, 15 + TOBI_NS_NAME, 16 + TOBI_NS_ALIAS, 17 + TOBI_NS_OPREGION, 18 + TOBI_NS_FIELD, 19 + TOBI_NS_MUTEX, 20 + TOBI_NS_EVENT, 21 + TOBI_NS_EXTERNAL 22 + } tobi_ns_kind; 23 + 24 + typedef struct tobi_ns_ent { 25 + char *path; 26 + char *name; 27 + char *owner; 28 + char *target; 29 + tobi_ns_kind kind; 30 + size_t off; 31 + unsigned args; 32 + unsigned flags; 33 + int external; 34 + } tobi_ns_ent; 35 + 36 + typedef struct tobi_ns { 37 + tobi_ns_ent *items; 38 + size_t len; 39 + size_t cap; 40 + } tobi_ns; 41 + 7 42 int tobi_nm_is_lead(unsigned char c); 8 43 9 - /** Return non-zero when c may appear after the first NameSeg byte. */ 10 44 int tobi_nm_is_tail(unsigned char c); 11 45 12 - /** Parse a four-byte AML NameSeg into a newly allocated string. */ 13 46 int tobi_nm_nameseg(tobi_rd *rd, char **out); 14 47 15 - /** Parse an AML NameString, including root, parent, dual, and multi prefixes. */ 16 48 int tobi_nm_namestring(tobi_rd *rd, char **out); 17 49 18 - /** Join a parsed AML path to a lexical scope path. */ 19 50 char *tobi_nm_resolve(const char *scope, const char *name); 51 + 52 + void tobi_ns_init(tobi_ns *ns); 53 + 54 + void tobi_ns_free(tobi_ns *ns); 55 + 56 + const char *tobi_ns_kind_name(tobi_ns_kind kind); 57 + 58 + const char *tobi_ns_leaf(const char *path); 59 + 60 + tobi_ns_ent *tobi_ns_find(tobi_ns *ns, const char *path); 61 + 62 + const tobi_ns_ent *tobi_ns_find_const(const tobi_ns *ns, const char *path); 63 + 64 + const tobi_ns_ent *tobi_ns_find_method(const tobi_ns *ns, const char *name); 65 + 66 + tobi_ns_ent *tobi_ns_add(tobi_ns *ns, tobi_ns_kind kind, const char *path, const char *owner, 67 + size_t off, unsigned args, unsigned flags, int external, 68 + const char *target, int *duplicate); 20 69 21 70 #endif
-4
src/op.h
··· 24 24 const char *operands; 25 25 } tobi_op_desc; 26 26 27 - /** Return metadata for an AML opcode byte or NULL when unsupported. */ 28 27 const tobi_op *tobi_op_find(uint8_t op); 29 28 30 - /** Return metadata for an AML extended opcode following ExtOpPrefix. */ 31 29 const tobi_op *tobi_op_find_ext(uint8_t ext); 32 30 33 - /** Return metadata for a complete opcode code; extended opcodes use 0x5b00|ext. */ 34 31 const tobi_op *tobi_op_find_code(uint16_t code); 35 32 36 - /** Return a compact operand descriptor string for an opcode, or NULL. */ 37 33 const char *tobi_op_operands(uint16_t code); 38 34 39 35 #endif
+60 -50
src/p.c
··· 14 14 #define MAX_DEPTH 64 15 15 #define MAX_TERMS 200000u 16 16 17 - typedef struct method_ent { 18 - char *path; 19 - char *name; 20 - unsigned args; 21 - } method_ent; 22 - 23 17 typedef struct parser { 24 18 tobi_diag_list *diag; 25 19 int strict; 26 20 char *scope; 27 - method_ent *methods; 28 - size_t method_len; 29 - size_t method_cap; 21 + tobi_ns *ns; 30 22 size_t terms; 31 23 } parser; 32 24 ··· 55 47 return memcmp(d, "DSDT", 4) == 0 || memcmp(d, "SSDT", 4) == 0; 56 48 } 57 49 58 - static void method_add(parser *p, const char *path, const char *name, unsigned args) { 59 - for (size_t i = 0; i < p->method_len; i++) { 60 - if (strcmp(p->methods[i].path, path) == 0) { 61 - p->methods[i].args = args; 62 - return; 63 - } 50 + static void parser_free(parser *p) { 51 + free(p->scope); 52 + } 53 + 54 + static tobi_ns_kind ns_kind_from_ir(tobi_ir_kind kind) { 55 + switch (kind) { 56 + case TOBI_IR_SCOPE: return TOBI_NS_SCOPE; 57 + case TOBI_IR_DEVICE: return TOBI_NS_DEVICE; 58 + case TOBI_IR_METHOD: return TOBI_NS_METHOD; 59 + case TOBI_IR_PROCESSOR: return TOBI_NS_PROCESSOR; 60 + case TOBI_IR_NAME: return TOBI_NS_NAME; 61 + case TOBI_IR_ALIAS: return TOBI_NS_ALIAS; 62 + case TOBI_IR_OPREGION: return TOBI_NS_OPREGION; 63 + case TOBI_IR_FIELD: 64 + case TOBI_IR_FIELD_ELEM: return TOBI_NS_FIELD; 65 + case TOBI_IR_MUTEX: return TOBI_NS_MUTEX; 66 + case TOBI_IR_EVENT: return TOBI_NS_EVENT; 67 + default: return TOBI_NS_UNKNOWN; 64 68 } 65 - if (p->method_len == p->method_cap) { 66 - p->method_cap = p->method_cap ? p->method_cap * 2 : 8; 67 - p->methods = tobi_xrealloc(p->methods, p->method_cap * sizeof(p->methods[0])); 68 - } 69 - p->methods[p->method_len].path = tobi_xstrdup(path); 70 - p->methods[p->method_len].name = tobi_xstrdup(name); 71 - p->methods[p->method_len].args = args; 72 - p->method_len++; 73 69 } 74 70 75 - static int method_find(const parser *p, const char *name) { 76 - for (size_t i = 0; i < p->method_len; i++) { 77 - if (strcmp(p->methods[i].path, name) == 0 || strcmp(p->methods[i].name, name) == 0) { 78 - return (int)p->methods[i].args; 79 - } 71 + static void ns_declare_path(parser *p, tobi_ns_kind kind, const char *path, size_t off, 72 + unsigned args, unsigned flags, int external, const char *target) { 73 + if (!p->ns || !path || path[0] == '\0') { 74 + return; 80 75 } 81 - const char *last = strrchr(name, '.'); 82 - if (last) { 83 - last++; 84 - for (size_t i = 0; i < p->method_len; i++) { 85 - if (strcmp(p->methods[i].name, last) == 0) { 86 - return (int)p->methods[i].args; 87 - } 88 - } 76 + int duplicate = 0; 77 + (void)tobi_ns_add(p->ns, kind, path, p->scope, off, args, flags, external, target, &duplicate); 78 + if (duplicate) { 79 + diag(p, p->strict ? TOBI_DIAG_ERROR : TOBI_DIAG_WARN, off, 80 + "duplicate namespace object %s at %s", tobi_ns_kind_name(kind), path); 89 81 } 90 - return -1; 82 + } 83 + 84 + static void ns_declare_name(parser *p, tobi_ns_kind kind, const char *name, size_t off, 85 + unsigned args, unsigned flags, int external, const char *target) { 86 + char *path = tobi_nm_resolve(p->scope, name); 87 + ns_declare_path(p, kind, path, off, args, flags, external, target); 88 + free(path); 91 89 } 92 90 93 - static void parser_free(parser *p) { 94 - free(p->scope); 95 - for (size_t i = 0; i < p->method_len; i++) { 96 - free(p->methods[i].path); 97 - free(p->methods[i].name); 98 - } 99 - free(p->methods); 91 + static int method_find(const parser *p, const char *name) { 92 + const tobi_ns_ent *e = tobi_ns_find_method(p->ns, name); 93 + return e ? (int)e->args : -1; 100 94 } 101 95 102 96 static uint8_t table_sum8(const uint8_t *data, size_t len) { ··· 211 205 tobi_ir *n = tobi_ir_new(kind, op_start, whole_len); 212 206 tobi_ir_set_name(n, name); 213 207 tobi_ir_set_path(n, path); 208 + ns_declare_path(p, ns_kind_from_ir(kind), path, op_start, 0, 0, 0, NULL); 214 209 char *old_scope = p->scope; 215 210 p->scope = tobi_xstrdup(path); 216 211 tobi_ir *block = parse_block_from_reader(p, &body, depth, tobi_rd_off(&body)); ··· 251 246 n->method_args = flags & 0x07u; 252 247 n->method_serialized = (flags >> 3) & 0x01u; 253 248 n->method_sync = (flags >> 4) & 0x0fu; 254 - method_add(p, path, name, n->method_args); 249 + ns_declare_path(p, TOBI_NS_METHOD, path, op_start, n->method_args, flags, 0, NULL); 255 250 char *old_scope = p->scope; 256 251 p->scope = tobi_xstrdup(path); 257 252 tobi_ir *block = parse_block_from_reader(p, &body, depth, tobi_rd_off(&body)); ··· 273 268 tobi_ir *n = tobi_ir_new(TOBI_IR_NAME, op_start, 0); 274 269 tobi_ir_set_name(n, name); 275 270 tobi_ir_set_path(n, path); 271 + ns_declare_path(p, TOBI_NS_NAME, path, op_start, 0, 0, 0, NULL); 276 272 tobi_ir *value = parse_expr(p, rd, depth + 1); 277 273 if (value) { 278 274 tobi_ir_add(n, value); ··· 295 291 tobi_ir_set_name(n, dst); 296 292 tobi_ir_set_str(n, src); 297 293 char *path = tobi_nm_resolve(p->scope, dst); 294 + char *target = tobi_nm_resolve(p->scope, src); 298 295 tobi_ir_set_path(n, path); 296 + ns_declare_path(p, TOBI_NS_ALIAS, path, op_start, 0, 0, 0, target); 297 + free(target); 299 298 free(path); 300 299 free(src); 301 300 free(dst); ··· 323 322 tobi_ir *typ = tobi_ir_new(TOBI_IR_INTEGER, op_start + n->len - 2u, 1); 324 323 typ->value = obj_type; 325 324 tobi_ir_add(n, typ); 326 - if (obj_type == 0x08u) { 327 - method_add(p, path, name, argc & 0x07u); 328 - } 325 + ns_declare_path(p, obj_type == 0x08u ? TOBI_NS_METHOD : TOBI_NS_EXTERNAL, 326 + path, op_start, argc & 0x07u, obj_type, 1, NULL); 329 327 free(path); 330 328 free(name); 331 329 return n; ··· 402 400 tobi_ir *e = tobi_ir_new(TOBI_IR_FIELD_ELEM, foff, tobi_rd_off(body) - foff); 403 401 tobi_ir_set_name(e, fname); 404 402 e->value = bits; 403 + ns_declare_name(p, TOBI_NS_FIELD, fname, foff, 0, 0, 0, NULL); 405 404 tobi_ir_add(n, e); 406 405 free(fname); 407 406 } ··· 559 558 tobi_ir_set_name(n, name); 560 559 tobi_ir_set_path(n, path); 561 560 tobi_ir_set_str(n, kind_name); 561 + ns_declare_path(p, ns_kind_from_ir(kind), path, op_start, 0, raw, 0, NULL); 562 562 char *old_scope = p->scope; 563 563 p->scope = tobi_xstrdup(path); 564 564 tobi_ir *block = parse_block_from_reader(p, &body, depth, tobi_rd_off(&body)); ··· 604 604 tobi_ir *n = tobi_ir_new(TOBI_IR_PROCESSOR, op_start, whole_len); 605 605 tobi_ir_set_name(n, name); 606 606 tobi_ir_set_path(n, path); 607 + ns_declare_path(p, TOBI_NS_PROCESSOR, path, op_start, 0, 0, 0, NULL); 607 608 n->value = proc_id; 608 609 char *old_scope = p->scope; 609 610 p->scope = tobi_xstrdup(path); ··· 630 631 tobi_ir_set_name(n, name); 631 632 char *path = tobi_nm_resolve(p->scope, name); 632 633 tobi_ir_set_path(n, path); 634 + ns_declare_path(p, TOBI_NS_OPREGION, path, op_start, 0, space, 0, NULL); 633 635 n->value = space; 634 636 tobi_ir *off = parse_expr(p, rd, depth + 1); 635 637 tobi_ir *len = parse_expr(p, rd, depth + 1); ··· 712 714 char *path = tobi_nm_resolve(p->scope, name); 713 715 tobi_ir_set_path(n, path); 714 716 tobi_ir_set_str(n, "DataRegion"); 717 + ns_declare_path(p, TOBI_NS_OPREGION, path, op_start, 0, 0, 0, NULL); 715 718 add_expr_children(p, rd, depth, n, 3); 716 719 n->len = tobi_rd_off(rd) - op_start; 717 720 free(path); ··· 728 731 tobi_ir_set_name(n, name); 729 732 char *path = tobi_nm_resolve(p->scope, name); 730 733 tobi_ir_set_path(n, path); 734 + ns_declare_path(p, ext == 0x01 ? TOBI_NS_MUTEX : TOBI_NS_EVENT, path, op_start, 0, 0, 0, NULL); 731 735 if (ext == 0x01) { 732 736 uint8_t sync = 0; 733 737 (void)tobi_rd_u8(rd, &sync); ··· 1297 1301 } 1298 1302 while (tobi_rd_left(rd) > 0) { 1299 1303 size_t start = rd->pos; 1304 + size_t abs_start = rd->base + start; 1300 1305 uint8_t op = 0; 1301 1306 if (!tobi_rd_u8(rd, &op)) { 1302 1307 return; ··· 1319 1324 if (op == 0x14) { 1320 1325 uint8_t flags = 0; 1321 1326 if (tobi_rd_u8(&body, &flags)) { 1322 - method_add(p, path, name, flags & 0x07u); 1327 + ns_declare_path(p, TOBI_NS_METHOD, path, abs_start, flags & 0x07u, flags, 0, NULL); 1323 1328 } 1324 1329 } else { 1325 1330 char *old_scope = p->scope; ··· 1340 1345 uint8_t argc = 0; 1341 1346 if (tobi_rd_u8(rd, &obj_type) && tobi_rd_u8(rd, &argc) && obj_type == 0x08u) { 1342 1347 char *path = tobi_nm_resolve(p->scope, name); 1343 - method_add(p, path, name, argc & 0x07u); 1348 + ns_declare_path(p, TOBI_NS_METHOD, path, abs_start, argc & 0x07u, obj_type, 1, NULL); 1344 1349 free(path); 1345 1350 } 1346 1351 free(name); ··· 1411 1416 int tobi_parse(const uint8_t *data, size_t len, int strict, tobi_parse_result *out) { 1412 1417 memset(out, 0, sizeof(*out)); 1413 1418 tobi_diag_init(&out->diag); 1419 + tobi_ns_init(&out->ns); 1414 1420 if (!detect_input(data, len, strict, &out->diag, &out->meta)) { 1415 1421 return 0; 1416 1422 } ··· 1419 1425 memset(&p, 0, sizeof(p)); 1420 1426 p.diag = &out->diag; 1421 1427 p.strict = strict; 1428 + p.ns = &out->ns; 1422 1429 p.scope = tobi_xstrdup("\\"); 1423 1430 tobi_rd rd; 1424 1431 if (out->meta.aml_off <= len && out->meta.aml_len <= len - out->meta.aml_off) { ··· 1435 1442 int tobi_parse_multi(const tobi_parse_input *inputs, size_t count, int strict, tobi_parse_result *out) { 1436 1443 memset(out, 0, sizeof(*out)); 1437 1444 tobi_diag_init(&out->diag); 1445 + tobi_ns_init(&out->ns); 1438 1446 memcpy(out->meta.signature, "MULT", 4); 1439 1447 out->meta.signature[4] = '\0'; 1440 1448 out->root = tobi_ir_new(TOBI_IR_ROOT, 0, 0); ··· 1448 1456 memset(&p, 0, sizeof(p)); 1449 1457 p.diag = &out->diag; 1450 1458 p.strict = strict; 1459 + p.ns = &out->ns; 1451 1460 p.scope = tobi_xstrdup("\\"); 1452 1461 for (size_t i = 0; i < count; i++) { 1453 1462 if (!detect_input(inputs[i].data, inputs[i].len, strict, &out->diag, &metas[i])) { ··· 1482 1491 void tobi_parse_result_free(tobi_parse_result *res) { 1483 1492 tobi_ir_free(res->root); 1484 1493 res->root = NULL; 1494 + tobi_ns_free(&res->ns); 1485 1495 tobi_diag_free(&res->diag); 1486 1496 }
+2 -3
src/p.h
··· 3 3 4 4 #include "dg.h" 5 5 #include "ir.h" 6 + #include "nm.h" 6 7 7 8 #include <stddef.h> 8 9 #include <stdint.h> ··· 20 21 typedef struct tobi_parse_result { 21 22 tobi_ir *root; 22 23 tobi_diag_list diag; 24 + tobi_ns ns; 23 25 tobi_input_meta meta; 24 26 } tobi_parse_result; 25 27 ··· 29 31 const char *name; 30 32 } tobi_parse_input; 31 33 32 - /** Parse a raw AML blob or DSDT/SSDT table into IR and diagnostics. */ 33 34 int tobi_parse(const uint8_t *data, size_t len, int strict, tobi_parse_result *out); 34 35 35 - /** Parse several AML blobs/tables into one IR with a shared method namespace pre-pass. */ 36 36 int tobi_parse_multi(const tobi_parse_input *inputs, size_t count, int strict, tobi_parse_result *out); 37 37 38 - /** Free all allocations owned by a parse result. */ 39 38 void tobi_parse_result_free(tobi_parse_result *res); 40 39 41 40 #endif
-12
src/rd.h
··· 12 12 int failed; 13 13 } tobi_rd; 14 14 15 - /** Initialise a bounded byte reader over data at a source base offset. */ 16 15 void tobi_rd_init(tobi_rd *rd, const uint8_t *data, size_t len, size_t base); 17 16 18 - /** Return the absolute source offset of the reader cursor. */ 19 17 size_t tobi_rd_off(const tobi_rd *rd); 20 18 21 - /** Return bytes still available in the reader. */ 22 19 size_t tobi_rd_left(const tobi_rd *rd); 23 20 24 - /** Read an unsigned byte. Returns 0 on bounds failure. */ 25 21 int tobi_rd_u8(tobi_rd *rd, uint8_t *out); 26 22 27 - /** Peek an unsigned byte without advancing. Returns 0 on bounds failure. */ 28 23 int tobi_rd_peek(const tobi_rd *rd, uint8_t *out); 29 24 30 - /** Read a little-endian 16-bit integer. */ 31 25 int tobi_rd_u16(tobi_rd *rd, uint16_t *out); 32 26 33 - /** Read a little-endian 32-bit integer. */ 34 27 int tobi_rd_u32(tobi_rd *rd, uint32_t *out); 35 28 36 - /** Read a little-endian 64-bit integer. */ 37 29 int tobi_rd_u64(tobi_rd *rd, uint64_t *out); 38 30 39 - /** Read n bytes into out. */ 40 31 int tobi_rd_bytes(tobi_rd *rd, uint8_t *out, size_t n); 41 32 42 - /** Skip n bytes. */ 43 33 int tobi_rd_skip(tobi_rd *rd, size_t n); 44 34 45 - /** Create a sub-reader spanning n bytes at the current cursor and advance. */ 46 35 int tobi_rd_sub(tobi_rd *rd, size_t n, tobi_rd *sub); 47 36 48 - /** Decode an AML package length and report decoded length plus encoded size. */ 49 37 int tobi_rd_pkg_len(tobi_rd *rd, size_t *pkg_len, size_t *encoded_len); 50 38 51 39 #endif
-9
src/str.h
··· 10 10 size_t cap; 11 11 } tobi_sb; 12 12 13 - /** Initialise an empty string builder. */ 14 13 void tobi_sb_init(tobi_sb *sb); 15 14 16 - /** Release storage owned by a string builder. */ 17 15 void tobi_sb_free(tobi_sb *sb); 18 16 19 - /** Append a NUL-terminated string. */ 20 17 void tobi_sb_add(tobi_sb *sb, const char *s); 21 18 22 - /** Append exactly n bytes. */ 23 19 void tobi_sb_addn(tobi_sb *sb, const char *s, size_t n); 24 20 25 - /** Append one character. */ 26 21 void tobi_sb_ch(tobi_sb *sb, char c); 27 22 28 - /** Append formatted text. */ 29 23 void tobi_sb_printf(tobi_sb *sb, const char *fmt, ...); 30 24 31 - /** Return the builder buffer, transferring ownership to the caller. */ 32 25 char *tobi_sb_take(tobi_sb *sb); 33 26 34 - /** Append a JSON string literal with escaping. */ 35 27 void tobi_json_string(tobi_sb *sb, const char *s); 36 28 37 - /** Append bytes as a lower-case hexadecimal string. */ 38 29 void tobi_hex(tobi_sb *sb, const uint8_t *data, size_t len); 39 30 40 31 #endif
+3
test/t_js.c
··· 11 11 T_STR(s, "\"kind\":\"root\""); 12 12 T_STR(s, "\"checksum_sum\":0"); 13 13 T_STR(s, "\"checksum_valid\":false"); 14 + T_STR(s, "\"namespace\":["); 15 + T_STR(s, "\"path\":\"\\\\STR0\""); 16 + T_STR(s, "\"kind\":\"name\""); 14 17 T_STR(s, "a\\\"b\\\\c"); 15 18 T_STR(s, "\"raw_opcode\":254"); 16 19 T_CHECK(strstr(s, ",}") == NULL);
+17
test/t_nm.c
··· 40 40 s = tobi_nm_resolve("\\_SB_.PCI0", "^DEV0"); 41 41 T_CHECK(strcmp(s, "\\_SB_.DEV0") == 0); 42 42 free(s); 43 + 44 + tobi_ns ns; 45 + tobi_ns_init(&ns); 46 + int dup = 0; 47 + tobi_ns_ent *e = tobi_ns_add(&ns, TOBI_NS_METHOD, "\\CALX", "\\", 4, 1, 0x08, 1, NULL, &dup); 48 + T_CHECK(e != NULL && dup == 0); 49 + T_CHECK(e->external && e->args == 1); 50 + T_CHECK(tobi_ns_find_method(&ns, "CALX") == e); 51 + e = tobi_ns_add(&ns, TOBI_NS_METHOD, "\\CALX", "\\", 20, 2, 0x02, 0, NULL, &dup); 52 + T_CHECK(e != NULL && dup == 0); 53 + T_CHECK(!e->external && e->off == 20 && e->args == 2); 54 + (void)tobi_ns_add(&ns, TOBI_NS_METHOD, "\\CALX", "\\", 40, 2, 0x02, 0, NULL, &dup); 55 + T_CHECK(dup == 1); 56 + e = tobi_ns_add(&ns, TOBI_NS_ALIAS, "\\ALX0", "\\", 44, 0, 0, 0, "\\CALX", &dup); 57 + T_CHECK(e != NULL && dup == 0 && e->target != NULL); 58 + T_CHECK(strcmp(e->target, "\\CALX") == 0); 59 + tobi_ns_free(&ns); 43 60 return 0; 44 61 }
+20
test/t_p.c
··· 70 70 T_CHECK(r.root->child_len == 2); 71 71 T_CHECK(r.root->child[1]->kind == TOBI_IR_FIELD); 72 72 T_CHECK(r.root->child[1]->child_len == 1); 73 + T_CHECK(tobi_ns_find_const(&r.ns, "\\REG0") != NULL); 74 + const tobi_ns_ent *fe = tobi_ns_find_const(&r.ns, "\\FLD0"); 75 + T_CHECK(fe != NULL && fe->kind == TOBI_NS_FIELD); 76 + T_CHECK(r.diag.len == 0); 73 77 tobi_parse_result_free(&r); 74 78 75 79 uint8_t ifld[] = {0x5b,0x86,0x0f,'I','D','X','0','D','A','T','0',0x00,'I','F','L','D',0x08}; ··· 116 120 T_CHECK(use->child[0]->child[0]->child[0]->child_len == 1); 117 121 T_CHECK(r.root->child[1]->kind == TOBI_IR_EXPR); 118 122 T_CHECK(strcmp(r.root->child[1]->name, "external") == 0); 123 + fe = tobi_ns_find_method(&r.ns, "CALX"); 124 + T_CHECK(fe != NULL && fe->external && fe->args == 1); 119 125 tobi_parse_result_free(&r); 120 126 121 127 uint8_t use_file[] = {0x14,0x0d,'U','S','E','0',0x00,0xa4,'C','A','L','0',0x0a,0x05}; ··· 131 137 T_CHECK(use->child[0]->child[0]->kind == TOBI_IR_RETURN); 132 138 T_CHECK(use->child[0]->child[0]->child[0]->kind == TOBI_IR_CALL); 133 139 T_CHECK(use->child[0]->child[0]->child[0]->child_len == 1); 140 + fe = tobi_ns_find_method(&r.ns, "CAL0"); 141 + T_CHECK(fe != NULL && !fe->external && fe->args == 1); 134 142 tobi_parse_result_free(&r); 135 143 136 144 uint8_t fwd[] = { ··· 210 218 T_CHECK(r.root->child[0]->kind == TOBI_IR_EXPR); 211 219 T_CHECK(strcmp(r.root->child[0]->name, "div") == 0); 212 220 T_CHECK(r.root->child[0]->child_len == 4); 221 + tobi_parse_result_free(&r); 222 + 223 + uint8_t dup_name[] = { 224 + 0x08,'D','U','P','0',0x01, 225 + 0x08,'D','U','P','0',0x00 226 + }; 227 + T_CHECK(tobi_parse(dup_name, sizeof(dup_name), 0, &r)); 228 + T_CHECK(r.diag.len == 1); 229 + T_CHECK(r.diag.items[0].level == TOBI_DIAG_WARN); 230 + tobi_parse_result_free(&r); 231 + T_CHECK(!tobi_parse(dup_name, sizeof(dup_name), 1, &r)); 232 + T_CHECK(tobi_diag_has_error(&r.diag)); 213 233 tobi_parse_result_free(&r); 214 234 return 0; 215 235 }
+2
test/t_prod.c
··· 91 91 T_CHECK(ret->child_len == 1); 92 92 T_CHECK(ret->child[0]->kind == TOBI_IR_CALL); 93 93 T_CHECK(ret->child[0]->child_len == 1); 94 + const tobi_ns_ent *ext = tobi_ns_find_method(&r.ns, "CALX"); 95 + T_CHECK(ext != NULL && ext->external && ext->args == 1); 94 96 tobi_parse_result_free(&r); 95 97 return 0; 96 98 }