ACPI AML decompiler w/ CFG recovery and structured pseudocode
29

Configure Feed

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

Merge pull request #2 from 23384/dev

Improve AML namespace resolution/pseudocode expression fidelity

+264 -61
+139 -50
src/dc.c
··· 4 4 #include "str.h" 5 5 6 6 #include <stdio.h> 7 + #include <string.h> 7 8 8 9 static void indent(tobi_sb *sb, unsigned n) { 9 10 for (unsigned i = 0; i < n; i++) { ··· 16 17 17 18 static const char *binop(const char *name) { 18 19 if (!name) { 19 - return "?"; 20 + return NULL; 21 + } 22 + if (strcmp(name, "eq") == 0) return "=="; 23 + if (strcmp(name, "gt") == 0) return ">"; 24 + if (strcmp(name, "lt") == 0) return "<"; 25 + if (strcmp(name, "add") == 0) return "+"; 26 + if (strcmp(name, "sub") == 0) return "-"; 27 + if (strcmp(name, "mul") == 0) return "*"; 28 + if (strcmp(name, "div") == 0) return "/"; 29 + if (strcmp(name, "mod") == 0) return "%"; 30 + if (strcmp(name, "shl") == 0) return "<<"; 31 + if (strcmp(name, "shr") == 0) return ">>"; 32 + if (strcmp(name, "and") == 0) return "&"; 33 + if (strcmp(name, "or") == 0) return "|"; 34 + if (strcmp(name, "xor") == 0) return "^"; 35 + if (strcmp(name, "land") == 0) return "&&"; 36 + if (strcmp(name, "lor") == 0) return "||"; 37 + return NULL; 38 + } 39 + 40 + static const char *unop(const char *name) { 41 + if (!name) { 42 + return NULL; 43 + } 44 + if (strcmp(name, "lnot") == 0) return "!"; 45 + if (strcmp(name, "not") == 0) return "~"; 46 + return NULL; 47 + } 48 + 49 + static int op_prec(const char *name) { 50 + if (!name) { 51 + return 0; 52 + } 53 + if (strcmp(name, "lor") == 0) return 1; 54 + if (strcmp(name, "land") == 0) return 2; 55 + if (strcmp(name, "or") == 0) return 3; 56 + if (strcmp(name, "xor") == 0) return 4; 57 + if (strcmp(name, "and") == 0) return 5; 58 + if (strcmp(name, "eq") == 0 || strcmp(name, "gt") == 0 || strcmp(name, "lt") == 0) return 6; 59 + if (strcmp(name, "shl") == 0 || strcmp(name, "shr") == 0) return 7; 60 + if (strcmp(name, "add") == 0 || strcmp(name, "sub") == 0) return 8; 61 + if (strcmp(name, "mul") == 0 || strcmp(name, "div") == 0 || strcmp(name, "mod") == 0) return 9; 62 + if (unop(name)) return 10; 63 + return 0; 64 + } 65 + 66 + static int op_right_needs_group(const char *name) { 67 + if (!name) { 68 + return 1; 20 69 } 21 - if (name[0] == 'e' && name[1] == 'q') return "=="; 22 - if (name[0] == 'g' && name[1] == 't') return ">"; 23 - if (name[0] == 'l' && name[1] == 't') return "<"; 24 - if (name[0] == 'a' && name[1] == 'd') return "+"; 25 - if (name[0] == 's' && name[1] == 'u') return "-"; 26 - if (name[0] == 'm' && name[1] == 'u') return "*"; 27 - if (name[0] == 'd' && name[1] == 'i') return "/"; 28 - if (name[0] == 'a' && name[1] == 'n') return "&"; 29 - if (name[0] == 'o' && name[1] == 'r') return "|"; 30 - if (name[0] == 'x' && name[1] == 'o') return "^"; 31 - if (name[0] == 'l' && name[1] == 'a') return "&&"; 32 - if (name[0] == 'l' && name[1] == 'o') return "||"; 33 - return name; 70 + return !(strcmp(name, "add") == 0 || strcmp(name, "mul") == 0 || 71 + strcmp(name, "and") == 0 || strcmp(name, "or") == 0 || 72 + strcmp(name, "xor") == 0 || strcmp(name, "land") == 0 || 73 + strcmp(name, "lor") == 0); 34 74 } 35 75 36 - static void expr(tobi_sb *sb, const tobi_ir *n) { 76 + static void expr_prec(tobi_sb *sb, const tobi_ir *n, int parent_prec) { 37 77 if (!n) { 38 78 tobi_sb_add(sb, "<missing>"); 39 79 return; ··· 41 81 switch (n->kind) { 42 82 case TOBI_IR_INTEGER: 43 83 tobi_sb_printf(sb, "0x%llx", (unsigned long long)n->value); 44 - break; 84 + return; 45 85 case TOBI_IR_STRING: 46 86 tobi_sb_ch(sb, '"'); 47 87 if (n->str) { ··· 53 93 } 54 94 } 55 95 tobi_sb_ch(sb, '"'); 56 - break; 96 + return; 57 97 case TOBI_IR_REF: 58 98 tobi_sb_add(sb, n->name ? n->name : "<ref>"); 59 - break; 99 + return; 60 100 case TOBI_IR_CALL: 61 101 tobi_sb_add(sb, n->name ? n->name : "<call>"); 62 102 tobi_sb_ch(sb, '('); ··· 64 104 if (i) { 65 105 tobi_sb_add(sb, ", "); 66 106 } 67 - expr(sb, n->child[i]); 107 + expr_prec(sb, n->child[i], 0); 68 108 } 69 109 tobi_sb_ch(sb, ')'); 70 - break; 71 - case TOBI_IR_EXPR: 72 - if (n->child_len == 1) { 73 - tobi_sb_printf(sb, "%s(", n->name ? n->name : "op"); 74 - expr(sb, n->child[0]); 75 - tobi_sb_ch(sb, ')'); 76 - } else if (n->child_len >= 2) { 77 - tobi_sb_ch(sb, '('); 78 - expr(sb, n->child[0]); 79 - tobi_sb_printf(sb, " %s ", binop(n->name)); 80 - expr(sb, n->child[1]); 81 - tobi_sb_ch(sb, ')'); 82 - } else { 83 - tobi_sb_add(sb, n->name ? n->name : "<expr>"); 110 + return; 111 + case TOBI_IR_EXPR: { 112 + const char *op = binop(n->name); 113 + int prec = op_prec(n->name); 114 + if (op && n->child_len >= 2 && prec > 0) { 115 + int paren = prec < parent_prec; 116 + if (paren) { 117 + tobi_sb_ch(sb, '('); 118 + } 119 + expr_prec(sb, n->child[0], prec); 120 + tobi_sb_printf(sb, " %s ", op); 121 + expr_prec(sb, n->child[1], prec + op_right_needs_group(n->name)); 122 + if (paren) { 123 + tobi_sb_ch(sb, ')'); 124 + } 125 + return; 126 + } 127 + op = unop(n->name); 128 + if (op && n->child_len == 1 && prec > 0) { 129 + int paren = prec < parent_prec; 130 + if (paren) { 131 + tobi_sb_ch(sb, '('); 132 + } 133 + tobi_sb_add(sb, op); 134 + expr_prec(sb, n->child[0], prec); 135 + if (paren) { 136 + tobi_sb_ch(sb, ')'); 137 + } 138 + return; 84 139 } 85 - break; 140 + tobi_sb_printf(sb, "%s(", n->name ? n->name : "op"); 141 + for (size_t i = 0; i < n->child_len; i++) { 142 + if (i) { 143 + tobi_sb_add(sb, ", "); 144 + } 145 + expr_prec(sb, n->child[i], 0); 146 + } 147 + tobi_sb_ch(sb, ')'); 148 + return; 149 + } 86 150 case TOBI_IR_BUFFER: 87 151 tobi_sb_printf(sb, "Buffer[%s]", n->str ? n->str : ""); 88 - break; 152 + return; 89 153 case TOBI_IR_PACKAGE: 90 154 tobi_sb_ch(sb, '{'); 91 155 for (size_t i = 0; i < n->child_len; i++) { 92 156 if (i) { 93 157 tobi_sb_add(sb, ", "); 94 158 } 95 - expr(sb, n->child[i]); 159 + expr_prec(sb, n->child[i], 0); 96 160 } 97 161 tobi_sb_ch(sb, '}'); 98 - break; 162 + return; 99 163 case TOBI_IR_STORE: 100 164 if (n->child_len >= 2) { 101 - expr(sb, n->child[1]); 165 + expr_prec(sb, n->child[1], 0); 102 166 tobi_sb_add(sb, " = "); 103 - expr(sb, n->child[0]); 167 + expr_prec(sb, n->child[0], 0); 104 168 } else { 105 169 tobi_sb_add(sb, "store(?)"); 106 170 } 107 - break; 171 + return; 108 172 case TOBI_IR_UNKNOWN: 109 173 tobi_sb_printf(sb, "unknown_0x%x", n->raw_op); 110 - break; 174 + return; 111 175 default: 112 176 tobi_sb_add(sb, n->name ? n->name : tobi_ir_kind_name(n->kind)); 113 - break; 177 + return; 178 + } 179 + } 180 + 181 + static void expr(tobi_sb *sb, const tobi_ir *n) { 182 + expr_prec(sb, n, 0); 183 + } 184 + 185 + static int expr_has_target(const tobi_ir *n) { 186 + if (!n || n->kind != TOBI_IR_EXPR || !n->name) { 187 + return 0; 114 188 } 189 + if (strcmp(n->name, "div") == 0) { 190 + return n->child_len >= 4; 191 + } 192 + return binop(n->name) && n->child_len >= 3; 193 + } 194 + 195 + static void expr_target_stmt(tobi_sb *sb, const tobi_ir *n) { 196 + if (strcmp(n->name, "div") == 0 && n->child_len >= 4) { 197 + expr(sb, n->child[2]); 198 + tobi_sb_add(sb, ", "); 199 + expr(sb, n->child[3]); 200 + tobi_sb_add(sb, " = divmod("); 201 + expr(sb, n->child[0]); 202 + tobi_sb_add(sb, ", "); 203 + expr(sb, n->child[1]); 204 + tobi_sb_ch(sb, ')'); 205 + return; 206 + } 207 + expr(sb, n->child[2]); 208 + tobi_sb_add(sb, " = "); 209 + expr(sb, n); 115 210 } 116 211 117 212 static void block(tobi_sb *sb, const tobi_ir *b, unsigned ind) { ··· 199 294 case TOBI_IR_EXPR: 200 295 case TOBI_IR_CALL: 201 296 indent(sb, ind); 202 - if (n->child_len >= 3 && n->kind == TOBI_IR_EXPR) { 203 - expr(sb, n->child[2]); 204 - tobi_sb_add(sb, " = "); 205 - tobi_sb_ch(sb, '('); 206 - expr(sb, n->child[0]); 207 - tobi_sb_printf(sb, " %s ", binop(n->name)); 208 - expr(sb, n->child[1]); 209 - tobi_sb_ch(sb, ')'); 297 + if (expr_has_target(n)) { 298 + expr_target_stmt(sb, n); 210 299 } else { 211 300 expr(sb, n); 212 301 }
+80
src/nm.c
··· 279 279 return NULL; 280 280 } 281 281 282 + static char *ns_parent(const char *scope) { 283 + if (!scope || strcmp(scope, "\\") == 0 || scope[0] == '\0') { 284 + return NULL; 285 + } 286 + const char *dot = strrchr(scope, '.'); 287 + if (!dot) { 288 + return tobi_xstrdup("\\"); 289 + } 290 + if (dot == scope || (scope[0] == '\\' && dot == scope + 1)) { 291 + return tobi_xstrdup("\\"); 292 + } 293 + return tobi_xstrndup(scope, (size_t)(dot - scope)); 294 + } 295 + 296 + static char *ns_join(const char *scope, const char *name) { 297 + tobi_sb sb; 298 + tobi_sb_init(&sb); 299 + if (!scope || scope[0] == '\0' || strcmp(scope, "\\") == 0) { 300 + tobi_sb_add(&sb, "\\"); 301 + tobi_sb_add(&sb, name); 302 + } else { 303 + tobi_sb_add(&sb, scope); 304 + tobi_sb_ch(&sb, '.'); 305 + tobi_sb_add(&sb, name); 306 + } 307 + return tobi_sb_take(&sb); 308 + } 309 + 310 + static const tobi_ns_ent *ns_follow_alias(const tobi_ns *ns, const tobi_ns_ent *ent) { 311 + const tobi_ns_ent *cur = ent; 312 + for (unsigned i = 0; cur && cur->kind == TOBI_NS_ALIAS && cur->target && i < 16; i++) { 313 + const tobi_ns_ent *next = tobi_ns_find_const(ns, cur->target); 314 + if (!next || next == cur) { 315 + break; 316 + } 317 + cur = next; 318 + } 319 + return cur; 320 + } 321 + 322 + const tobi_ns_ent *tobi_ns_lookup(const tobi_ns *ns, const char *scope, const char *name) { 323 + if (!ns || !name || name[0] == '\0') { 324 + return NULL; 325 + } 326 + if (name[0] == '\\' || name[0] == '^' || strcmp(name, "<null>") == 0) { 327 + char *path = tobi_nm_resolve(scope, name); 328 + const tobi_ns_ent *ent = ns_follow_alias(ns, tobi_ns_find_const(ns, path)); 329 + free(path); 330 + return ent; 331 + } 332 + char *cur = tobi_xstrdup(scope && scope[0] ? scope : "\\"); 333 + for (;;) { 334 + char *candidate = ns_join(cur, name); 335 + const tobi_ns_ent *ent = ns_follow_alias(ns, tobi_ns_find_const(ns, candidate)); 336 + free(candidate); 337 + if (ent) { 338 + free(cur); 339 + return ent; 340 + } 341 + char *parent = ns_parent(cur); 342 + free(cur); 343 + if (!parent) { 344 + break; 345 + } 346 + cur = parent; 347 + } 348 + char *root = ns_join("\\", name); 349 + const tobi_ns_ent *ent = ns_follow_alias(ns, tobi_ns_find_const(ns, root)); 350 + free(root); 351 + return ent; 352 + } 353 + 354 + char *tobi_ns_resolve_path(const tobi_ns *ns, const char *scope, const char *name) { 355 + const tobi_ns_ent *ent = tobi_ns_lookup(ns, scope, name); 356 + if (ent) { 357 + return tobi_xstrdup(ent->path); 358 + } 359 + return tobi_nm_resolve(scope, name); 360 + } 361 + 282 362 tobi_ns_ent *tobi_ns_add(tobi_ns *ns, tobi_ns_kind kind, const char *path, const char *owner, 283 363 size_t off, unsigned args, unsigned flags, int external, 284 364 const char *target, int *duplicate) {
+4
src/nm.h
··· 63 63 64 64 const tobi_ns_ent *tobi_ns_find_method(const tobi_ns *ns, const char *name); 65 65 66 + const tobi_ns_ent *tobi_ns_lookup(const tobi_ns *ns, const char *scope, const char *name); 67 + 68 + char *tobi_ns_resolve_path(const tobi_ns *ns, const char *scope, const char *name); 69 + 66 70 tobi_ns_ent *tobi_ns_add(tobi_ns *ns, tobi_ns_kind kind, const char *path, const char *owner, 67 71 size_t off, unsigned args, unsigned flags, int external, 68 72 const char *target, int *duplicate);
+4 -11
src/p.c
··· 88 88 free(path); 89 89 } 90 90 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; 94 - } 95 - 96 91 static uint8_t table_sum8(const uint8_t *data, size_t len) { 97 92 uint8_t sum = 0; 98 93 for (size_t i = 0; i < len; i++) { ··· 478 473 } 479 474 tobi_ir *n = tobi_ir_new(TOBI_IR_REF, off, tobi_rd_off(rd) - off); 480 475 tobi_ir_set_name(n, name); 481 - char *path = tobi_nm_resolve(p->scope, name); 476 + char *path = tobi_ns_resolve_path(p->ns, p->scope, name); 482 477 tobi_ir_set_path(n, path); 483 478 free(path); 484 479 free(name); ··· 1043 1038 if (!parse_namestring_diag(p, rd, &name)) { 1044 1039 return unknown_node(p, off, 0, 1, "bad namestring expression"); 1045 1040 } 1046 - char *path = tobi_nm_resolve(p->scope, name); 1047 - int argc = method_find(p, path); 1048 - if (argc < 0) { 1049 - argc = method_find(p, name); 1050 - } 1041 + const tobi_ns_ent *ent = tobi_ns_lookup(p->ns, p->scope, name); 1042 + int argc = ent && ent->kind == TOBI_NS_METHOD ? (int)ent->args : -1; 1043 + char *path = ent ? tobi_xstrdup(ent->path) : tobi_nm_resolve(p->scope, name); 1051 1044 tobi_ir *n = tobi_ir_new(argc >= 0 ? TOBI_IR_CALL : TOBI_IR_REF, off, 0); 1052 1045 tobi_ir_set_name(n, name); 1053 1046 tobi_ir_set_path(n, path);
+12
test/t_dc.c
··· 24 24 T_STR(s, "unknown opcode 0xfe at 0x0"); 25 25 free(s); 26 26 tobi_parse_result_free(&r); 27 + uint8_t exprm[] = { 28 + 0x14,0x19,'E','X','P','R',0x02, 29 + 0x70,0x72,0x68,0x77,0x69,0x0a,0x02,0x60,0x61,0x62, 30 + 0xa4,0x91,0x95,0x60,0x61,0x93,0x62,0x0a,0x00 31 + }; 32 + T_CHECK(tobi_parse(exprm, sizeof(exprm), 0, &r)); 33 + s = tobi_dc_emit(r.root, &r.diag); 34 + T_STR(s, "Local2 = Arg0 + Arg1 * 0x2;"); 35 + T_STR(s, "return Local0 < Local1 || Local2 == 0x0;"); 36 + T_CHECK(strstr(s, "Arg0 + (Arg1 * 0x2)") == NULL); 37 + free(s); 38 + tobi_parse_result_free(&r); 27 39 return 0; 28 40 }
+10
test/t_nm.c
··· 56 56 e = tobi_ns_add(&ns, TOBI_NS_ALIAS, "\\ALX0", "\\", 44, 0, 0, 0, "\\CALX", &dup); 57 57 T_CHECK(e != NULL && dup == 0 && e->target != NULL); 58 58 T_CHECK(strcmp(e->target, "\\CALX") == 0); 59 + (void)tobi_ns_add(&ns, TOBI_NS_METHOD, "\\_SB_.MTH0", "\\_SB_", 52, 3, 0, 0, NULL, &dup); 60 + (void)tobi_ns_add(&ns, TOBI_NS_METHOD, "\\MTH0", "\\", 56, 1, 0, 0, NULL, &dup); 61 + const tobi_ns_ent *found = tobi_ns_lookup(&ns, "\\_SB_.PCI0.DEV0", "MTH0"); 62 + T_CHECK(found != NULL && strcmp(found->path, "\\_SB_.MTH0") == 0 && found->args == 3); 63 + (void)tobi_ns_add(&ns, TOBI_NS_ALIAS, "\\_SB_.PCI0.DEV0.AMTH", "\\_SB_.PCI0.DEV0", 60, 0, 0, 0, "\\_SB_.MTH0", &dup); 64 + found = tobi_ns_lookup(&ns, "\\_SB_.PCI0.DEV0", "AMTH"); 65 + T_CHECK(found != NULL && strcmp(found->path, "\\_SB_.MTH0") == 0); 66 + char *rp = tobi_ns_resolve_path(&ns, "\\_SB_.PCI0.DEV0", "^MTH0"); 67 + T_CHECK(strcmp(rp, "\\_SB_.PCI0.MTH0") == 0); 68 + free(rp); 59 69 tobi_ns_free(&ns); 60 70 return 0; 61 71 }
+15
test/t_p.c
··· 141 141 T_CHECK(fe != NULL && !fe->external && fe->args == 1); 142 142 tobi_parse_result_free(&r); 143 143 144 + uint8_t scoped_call[] = { 145 + 0x10,0x23,'\\','_','S','B','_', 146 + 0x14,0x08,'C','A','L','0',0x01,0xa4,0x68, 147 + 0x5b,0x82,0x12,'D','E','V','0', 148 + 0x14,0x0d,'U','S','E','0',0x00,0xa4,'C','A','L','0',0x0a,0x05 149 + }; 150 + T_CHECK(parse_ok(scoped_call, sizeof(scoped_call), &r)); 151 + use = r.root->child[0]->child[0]->child[1]->child[0]->child[0]; 152 + T_CHECK(use->kind == TOBI_IR_METHOD); 153 + tobi_ir *scall = use->child[0]->child[0]->child[0]; 154 + T_CHECK(scall->kind == TOBI_IR_CALL); 155 + T_CHECK(strcmp(scall->path, "\\_SB_.CAL0") == 0); 156 + T_CHECK(scall->child_len == 1); 157 + tobi_parse_result_free(&r); 158 + 144 159 uint8_t fwd[] = { 145 160 0x14,0x0d,'U','S','E','0',0x00,0xa4,'C','A','L','0',0x0a,0x05, 146 161 0x14,0x08,'C','A','L','0',0x01,0xa4,0x68