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 #5 from 23384/dev

Add deterministic AML IR node identity lexical scope ownership and parser decompiler snapshot coverage

+172 -3
+2 -2
CMakeLists.txt
··· 41 41 add_executable(tobi_test 42 42 test/main.c test/t_rd.c test/t_nm.c test/t_p.c test/t_ir.c 43 43 test/t_cf.c test/t_da.c test/t_dc.c test/t_js.c test/t_bad.c test/t_cli.c 44 - test/t_prod.c test/t_corpus.c) 44 + test/t_prod.c test/t_corpus.c test/t_snap.c) 45 45 target_link_libraries(tobi_test PRIVATE tobilib) 46 46 target_compile_options(tobi_test PRIVATE ${TOBI_WARN}) 47 47 target_compile_definitions(tobi_test PRIVATE ··· 52 52 target_link_options(tobi_test PRIVATE ${SAN_FLAGS}) 53 53 endif() 54 54 55 - foreach(t rd nm p ir cf da dc js bad cli prod corpus) 55 + foreach(t rd nm p ir cf da dc js bad cli prod corpus snap) 56 56 add_test(NAME ${t} COMMAND tobi_test ${t}) 57 57 endforeach() 58 58
+1
src/cf.c
··· 61 61 62 62 int tobi_cf_recover(tobi_ir *root, tobi_diag_list *diag) { 63 63 walk(root, diag, 0); 64 + tobi_ir_assign_ids(root); 64 65 return !tobi_diag_has_error(diag); 65 66 } 66 67
+40
src/ir.c
··· 3 3 #include "mem.h" 4 4 5 5 #include <stdlib.h> 6 + #include <stdint.h> 6 7 7 8 tobi_ir *tobi_ir_new(tobi_ir_kind kind, size_t off, size_t len) { 8 9 tobi_ir *n = tobi_xcalloc(1, sizeof(*n)); 9 10 n->kind = kind; 10 11 n->off = off; 11 12 n->len = len; 13 + n->parent_index = SIZE_MAX; 12 14 return n; 13 15 } 14 16 ··· 22 24 free(node->child); 23 25 free(node->name); 24 26 free(node->path); 27 + free(node->scope); 25 28 free(node->str); 26 29 free(node->target); 27 30 free(node); ··· 35 38 parent->child_cap = parent->child_cap ? parent->child_cap * 2 : 4; 36 39 parent->child = tobi_xrealloc(parent->child, parent->child_cap * sizeof(parent->child[0])); 37 40 } 41 + child->parent_id = parent->id; 42 + child->parent_index = parent->child_len; 38 43 parent->child[parent->child_len++] = child; 39 44 } 40 45 46 + void tobi_ir_assign_ids(tobi_ir *root) { 47 + if (!root) { 48 + return; 49 + } 50 + typedef struct frame { 51 + tobi_ir *node; 52 + size_t parent_id; 53 + size_t parent_index; 54 + } frame; 55 + size_t cap = 64; 56 + size_t len = 0; 57 + frame *stack = tobi_xcalloc(cap, sizeof(stack[0])); 58 + stack[len++] = (frame){root, 0, SIZE_MAX}; 59 + size_t next_id = 1; 60 + while (len > 0) { 61 + frame cur = stack[--len]; 62 + cur.node->id = next_id++; 63 + cur.node->parent_id = cur.parent_id; 64 + cur.node->parent_index = cur.parent_index; 65 + for (size_t i = cur.node->child_len; i > 0; i--) { 66 + if (len == cap) { 67 + cap *= 2u; 68 + stack = tobi_xrealloc(stack, cap * sizeof(stack[0])); 69 + } 70 + stack[len++] = (frame){cur.node->child[i - 1u], cur.node->id, i - 1u}; 71 + } 72 + } 73 + free(stack); 74 + } 75 + 41 76 void tobi_ir_set_name(tobi_ir *node, const char *s) { 42 77 free(node->name); 43 78 node->name = tobi_xstrdup(s ? s : ""); ··· 46 81 void tobi_ir_set_path(tobi_ir *node, const char *s) { 47 82 free(node->path); 48 83 node->path = tobi_xstrdup(s ? s : ""); 84 + } 85 + 86 + void tobi_ir_set_scope(tobi_ir *node, const char *s) { 87 + free(node->scope); 88 + node->scope = tobi_xstrdup(s ? s : ""); 49 89 } 50 90 51 91 void tobi_ir_set_str(tobi_ir *node, const char *s) {
+8
src/ir.h
··· 38 38 39 39 typedef struct tobi_ir { 40 40 tobi_ir_kind kind; 41 + size_t id; 42 + size_t parent_id; 43 + size_t parent_index; 41 44 size_t off; 42 45 size_t len; 43 46 char *name; 44 47 char *path; 48 + char *scope; 45 49 char *str; 46 50 char *target; 47 51 uint64_t value; ··· 65 69 66 70 void tobi_ir_add(tobi_ir *parent, tobi_ir *child); 67 71 72 + void tobi_ir_assign_ids(tobi_ir *root); 73 + 68 74 void tobi_ir_set_name(tobi_ir *node, const char *s); 69 75 70 76 void tobi_ir_set_path(tobi_ir *node, const char *s); 77 + 78 + void tobi_ir_set_scope(tobi_ir *node, const char *s); 71 79 72 80 void tobi_ir_set_str(tobi_ir *node, const char *s); 73 81
+13
src/js.c
··· 17 17 tobi_sb_add(sb, "\"kind\":"); 18 18 tobi_json_string(sb, tobi_ir_kind_name(n->kind)); 19 19 comma(sb, &first); 20 + tobi_sb_printf(sb, "\"id\":%zu", n->id); 21 + if (n->parent_id != 0) { 22 + comma(sb, &first); 23 + tobi_sb_printf(sb, "\"parent_id\":%zu", n->parent_id); 24 + comma(sb, &first); 25 + tobi_sb_printf(sb, "\"parent_index\":%zu", n->parent_index); 26 + } 27 + comma(sb, &first); 20 28 tobi_sb_printf(sb, "\"offset\":%zu", n->off); 21 29 comma(sb, &first); 22 30 tobi_sb_printf(sb, "\"length\":%zu", n->len); ··· 29 37 comma(sb, &first); 30 38 tobi_sb_add(sb, "\"path\":"); 31 39 tobi_json_string(sb, n->path); 40 + } 41 + if (n->scope) { 42 + comma(sb, &first); 43 + tobi_sb_add(sb, "\"scope\":"); 44 + tobi_json_string(sb, n->scope); 32 45 } 33 46 if (n->str) { 34 47 comma(sb, &first);
+6
src/p.c
··· 238 238 239 239 static tobi_ir *parse_block_from_reader(parser *p, tobi_rd *sub, unsigned depth, size_t off) { 240 240 tobi_ir *block = tobi_ir_new(TOBI_IR_BLOCK, off, tobi_rd_left(sub)); 241 + tobi_ir_set_scope(block, p->scope); 241 242 (void)parse_term_list(p, sub, block, depth + 1); 242 243 return block; 243 244 } ··· 1944 1945 return 0; 1945 1946 } 1946 1947 out->root = tobi_ir_new(TOBI_IR_ROOT, out->meta.aml_off, out->meta.aml_len); 1948 + tobi_ir_set_scope(out->root, "\\"); 1947 1949 parser p; 1948 1950 memset(&p, 0, sizeof(p)); 1949 1951 p.diag = &out->diag; ··· 1959 1961 (void)parse_term_list(&p, &rd, out->root, 0); 1960 1962 } 1961 1963 semantic_validate(&p, out->root); 1964 + tobi_ir_assign_ids(out->root); 1962 1965 parser_free(&p); 1963 1966 return !(strict && tobi_diag_has_error(&out->diag)); 1964 1967 } ··· 1971 1974 out->meta.signature[4] = '\0'; 1972 1975 memcpy(out->meta.source, "multi", 6); 1973 1976 out->root = tobi_ir_new(TOBI_IR_ROOT, 0, 0); 1977 + tobi_ir_set_scope(out->root, "\\"); 1974 1978 if (!inputs || count == 0) { 1975 1979 tobi_diag_add(&out->diag, TOBI_DIAG_ERROR, 0, "no AML inputs"); 1976 1980 return 0; ··· 2002 2006 } 2003 2007 tobi_ir *file = tobi_ir_new(TOBI_IR_BLOCK, metas[i].aml_off, metas[i].aml_len); 2004 2008 tobi_ir_set_name(file, inputs[i].name ? inputs[i].name : "<input>"); 2009 + tobi_ir_set_scope(file, "\\"); 2005 2010 tobi_rd rd; 2006 2011 tobi_rd_init(&rd, inputs[i].data + metas[i].aml_off, metas[i].aml_len, metas[i].aml_off); 2007 2012 (void)parse_term_list(&p, &rd, file, 0); ··· 2009 2014 } 2010 2015 } 2011 2016 semantic_validate(&p, out->root); 2017 + tobi_ir_assign_ids(out->root); 2012 2018 parser_free(&p); 2013 2019 free(metas); 2014 2020 return ok && !(strict && tobi_diag_has_error(&out->diag));
+1 -1
test/main.c
··· 4 4 struct ent { const char *name; int (*fn)(void); } tests[] = { 5 5 {"rd", t_rd}, {"nm", t_nm}, {"p", t_p}, {"ir", t_ir}, {"cf", t_cf}, 6 6 {"da", t_da}, {"dc", t_dc}, {"js", t_js}, {"bad", t_bad}, {"cli", t_cli}, 7 - {"prod", t_prod}, {"corpus", t_corpus}, 7 + {"prod", t_prod}, {"corpus", t_corpus}, {"snap", t_snap}, 8 8 }; 9 9 if (argc == 2) { 10 10 for (size_t i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) {
+1
test/t.h
··· 20 20 int t_cli(void); 21 21 int t_prod(void); 22 22 int t_corpus(void); 23 + int t_snap(void); 23 24 24 25 #endif
+13
test/t_ir.c
··· 6 6 tobi_ir *root = tobi_ir_new(TOBI_IR_ROOT, 0, 10); 7 7 tobi_ir *m = tobi_ir_new(TOBI_IR_METHOD, 2, 8); 8 8 tobi_ir_set_name(m, "MTH0"); 9 + tobi_ir_set_scope(root, "\\"); 9 10 tobi_ir_add(root, m); 10 11 tobi_ir_add(m, tobi_ir_new(TOBI_IR_BLOCK, 7, 3)); 12 + tobi_ir_set_scope(m->child[0], "\\MTH0"); 13 + tobi_ir_assign_ids(root); 11 14 T_CHECK(root->kind == TOBI_IR_ROOT); 15 + T_CHECK(root->id == 1 && root->parent_id == 0); 12 16 T_CHECK(root->child_len == 1); 13 17 T_CHECK(root->child[0]->off == 2 && root->child[0]->len == 8); 18 + T_CHECK(root->child[0]->id == 2 && root->child[0]->parent_id == root->id); 19 + T_CHECK(root->child[0]->parent_index == 0); 20 + T_CHECK(m->child[0]->id == 3 && m->child[0]->parent_id == m->id); 21 + T_CHECK(strcmp(root->scope, "\\") == 0); 22 + T_CHECK(strcmp(m->child[0]->scope, "\\MTH0") == 0); 14 23 T_CHECK(tobi_ir_find_child(root, TOBI_IR_METHOD) == m); 15 24 T_CHECK(tobi_ir_count_kind(root, TOBI_IR_METHOD) == 1); 16 25 tobi_ir *u = tobi_ir_new(TOBI_IR_UNKNOWN, 4, 1); 17 26 u->raw_op = 0xfe; 18 27 tobi_ir_add(m->child[0], u); 28 + tobi_ir_assign_ids(root); 19 29 T_CHECK(m->child[0]->child[0]->raw_op == 0xfe); 30 + T_CHECK(m->child[0]->child[0]->id == 4); 31 + T_CHECK(m->child[0]->child[0]->parent_id == m->child[0]->id); 32 + T_CHECK(m->child[0]->child[0]->parent_index == 0); 20 33 tobi_ir_free(root); 21 34 return 0; 22 35 }
+87
test/t_snap.c
··· 1 + #include "t.h" 2 + 3 + #include "cf.h" 4 + #include "dc.h" 5 + #include "js.h" 6 + #include "p.h" 7 + #include "str.h" 8 + 9 + static void snap_node(tobi_sb *sb, const tobi_ir *n) { 10 + tobi_sb_printf(sb, "%zu:%zu:", n->id, n->parent_id); 11 + if (n->parent_id == 0) { 12 + tobi_sb_add(sb, "-"); 13 + } else { 14 + tobi_sb_printf(sb, "%zu", n->parent_index); 15 + } 16 + tobi_sb_printf(sb, ":%s", tobi_ir_kind_name(n->kind)); 17 + if (n->name) { 18 + tobi_sb_printf(sb, ":%s", n->name); 19 + } 20 + if (n->scope) { 21 + tobi_sb_printf(sb, ":scope=%s", n->scope); 22 + } 23 + tobi_sb_ch(sb, '\n'); 24 + for (size_t i = 0; i < n->child_len; i++) { 25 + snap_node(sb, n->child[i]); 26 + } 27 + } 28 + 29 + static char *snapshot(const tobi_ir *root) { 30 + tobi_sb sb; 31 + tobi_sb_init(&sb); 32 + snap_node(&sb, root); 33 + return tobi_sb_take(&sb); 34 + } 35 + 36 + int t_snap(void) { 37 + uint8_t m0[] = {0x14,0x0c,'M','T','H','0',0x01,0x70,0x0a,0x2a,0x60,0xa4,0x60}; 38 + tobi_parse_result r; 39 + T_CHECK(tobi_parse(m0, sizeof(m0), 0, &r)); 40 + T_CHECK(tobi_cf_recover(r.root, &r.diag)); 41 + char *s = snapshot(r.root); 42 + const char *want = 43 + "1:0:-:root:scope=\\\n" 44 + "2:1:0:method:MTH0\n" 45 + "3:2:0:block:scope=\\MTH0\n" 46 + "4:3:0:store\n" 47 + "5:4:0:integer\n" 48 + "6:4:1:ref:Local0\n" 49 + "7:3:1:return\n" 50 + "8:7:0:ref:Local0\n"; 51 + T_CHECK(strcmp(s, want) == 0); 52 + free(s); 53 + 54 + char *j = tobi_js_emit(&r); 55 + T_STR(j, "\"id\":1"); 56 + T_STR(j, "\"parent_id\":1"); 57 + T_STR(j, "\"parent_index\":0"); 58 + T_STR(j, "\"scope\":\"\\\\MTH0\""); 59 + T_CHECK(strstr(j, ",}") == NULL); 60 + T_CHECK(strstr(j, ",]") == NULL); 61 + free(j); 62 + 63 + char *d = tobi_dc_emit(r.root, &r.diag); 64 + const char *dwant = 65 + "method MTH0(args=1, serialized=false, sync=0) {\n" 66 + " Local0 = 0x2a;\n" 67 + " return Local0;\n" 68 + "}\n"; 69 + T_CHECK(strcmp(d, dwant) == 0); 70 + free(d); 71 + tobi_parse_result_free(&r); 72 + 73 + uint8_t nested[] = { 74 + 0x10,0x14,'\\','_','S','B','_',0x5b,0x82,0x0c,'D','E','V','0', 75 + 0x14,0x06,'M','0','0','0',0x00 76 + }; 77 + T_CHECK(tobi_parse(nested, sizeof(nested), 0, &r)); 78 + T_CHECK(strcmp(r.root->scope, "\\") == 0); 79 + T_CHECK(strcmp(r.root->child[0]->child[0]->scope, "\\_SB_") == 0); 80 + T_CHECK(strcmp(r.root->child[0]->child[0]->child[0]->child[0]->scope, "\\_SB_.DEV0") == 0); 81 + T_CHECK(strcmp(r.root->child[0]->child[0]->child[0]->child[0]->child[0]->child[0]->scope, 82 + "\\_SB_.DEV0.M000") == 0); 83 + T_CHECK(r.root->child[0]->id == 2); 84 + T_CHECK(r.root->child[0]->child[0]->parent_id == r.root->child[0]->id); 85 + tobi_parse_result_free(&r); 86 + return 0; 87 + }