ACPI AML decompiler w/ CFG recovery and structured pseudocode
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
9static 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
29static 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
36int 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
72 char *g = tobi_graph_dot(r.root, &r.ns, TOBI_GRAPH_CFG);
73 const char *cfg_want =
74 "digraph tobi_cfg {\n"
75 " graph [rankdir=TB,bgcolor=\"#ffffff\",pad=0.18,nodesep=0.5,ranksep=0.72,splines=ortho,outputorder=edgesfirst];\n"
76 " node [shape=box,style=\"solid\",color=\"#000000\",fontcolor=\"#000000\",fontname=\"Courier\",fontsize=12,margin=\"0.12,0.07\",penwidth=1.1];\n"
77 " edge [color=\"#000000\",fontcolor=\"#000000\",arrowsize=0.75,penwidth=1.1];\n"
78 " n0 [label=\"root\\noff=0x0\"];\n"
79 " n1 [label=\"method\\nMTH0\\noff=0x0\"];\n"
80 " n2 [label=\"store\\noff=0x7\"];\n"
81 " e0 [shape=box,style=\"solid\",color=\"#000000\",fontcolor=\"#000000\",fontname=\"Times-Roman\",fontsize=10,margin=\"0.06,0.03\",height=0,width=0,label=\"entry\"];\n"
82 " n1 -> e0 [arrowhead=none, weight=2];\n"
83 " e0 -> n2 [weight=2];\n"
84 " n3 [label=\"return\\noff=0xb\"];\n"
85 " e1 [shape=box,style=\"solid\",color=\"#000000\",fontcolor=\"#000000\",fontname=\"Times-Roman\",fontsize=10,margin=\"0.06,0.03\",height=0,width=0,label=\"next\"];\n"
86 " n2 -> e1 [arrowhead=none, weight=2];\n"
87 " e1 -> n3 [weight=2];\n"
88 " e2 [shape=box,style=\"solid\",color=\"#000000\",fontcolor=\"#000000\",fontname=\"Times-Roman\",fontsize=10,margin=\"0.06,0.03\",height=0,width=0,label=\"entry\"];\n"
89 " n0 -> e2 [arrowhead=none, weight=2];\n"
90 " e2 -> n1 [weight=2];\n"
91 "}\n";
92 T_CHECK(strcmp(g, cfg_want) == 0);
93 free(g);
94
95 g = tobi_graph_dot(r.root, &r.ns, TOBI_GRAPH_AST);
96 const char *ast_want =
97 "digraph tobi_ast {\n"
98 " graph [rankdir=TB,bgcolor=\"#ffffff\",pad=0.18,nodesep=0.5,ranksep=0.72,splines=ortho,outputorder=edgesfirst];\n"
99 " node [shape=box,style=\"solid\",color=\"#000000\",fontcolor=\"#000000\",fontname=\"Courier\",fontsize=12,margin=\"0.12,0.07\",penwidth=1.1];\n"
100 " edge [color=\"#000000\",fontcolor=\"#000000\",arrowsize=0.75,penwidth=1.1];\n"
101 " n0 [label=\"root\\noff=0x0\"];\n"
102 " n1 [label=\"method\\nMTH0\\noff=0x0\"];\n"
103 " n2 [label=\"block\\noff=0x7\"];\n"
104 " n3 [label=\"store\\noff=0x7\"];\n"
105 " n4 [label=\"integer\\noff=0x8\"];\n"
106 " n3 -> n4;\n"
107 " n5 [label=\"ref\\nLocal0\\noff=0xa\"];\n"
108 " n3 -> n5;\n"
109 " n2 -> n3;\n"
110 " n6 [label=\"return\\noff=0xb\"];\n"
111 " n7 [label=\"ref\\nLocal0\\noff=0xc\"];\n"
112 " n6 -> n7;\n"
113 " n2 -> n6;\n"
114 " n1 -> n2;\n"
115 " n0 -> n1;\n"
116 "}\n";
117 T_CHECK(strcmp(g, ast_want) == 0);
118 free(g);
119
120 g = tobi_graph_dot(r.root, &r.ns, TOBI_GRAPH_NAMESPACE);
121 const char *ns_want =
122 "digraph tobi_namespace {\n"
123 " graph [rankdir=TB,bgcolor=\"#ffffff\",pad=0.18,nodesep=0.5,ranksep=0.72,splines=ortho,outputorder=edgesfirst];\n"
124 " node [shape=box,style=\"solid\",color=\"#000000\",fontcolor=\"#000000\",fontname=\"Courier\",fontsize=12,margin=\"0.12,0.07\",penwidth=1.1];\n"
125 " edge [color=\"#000000\",fontcolor=\"#000000\",arrowsize=0.75,penwidth=1.1];\n"
126 " n0 [label=\"namespace\\n\\\\\"];\n"
127 " n1 [label=\"method\\nMTH0\\n\\\\MTH0\\noff=0x0\"];\n"
128 " n0 -> n1;\n"
129 "}\n";
130 T_CHECK(strcmp(g, ns_want) == 0);
131 free(g);
132 tobi_parse_result_free(&r);
133
134 uint8_t nested[] = {
135 0x10,0x14,'\\','_','S','B','_',0x5b,0x82,0x0c,'D','E','V','0',
136 0x14,0x06,'M','0','0','0',0x00
137 };
138 T_CHECK(tobi_parse(nested, sizeof(nested), 0, &r));
139 T_CHECK(strcmp(r.root->scope, "\\") == 0);
140 T_CHECK(strcmp(r.root->child[0]->child[0]->scope, "\\_SB_") == 0);
141 T_CHECK(strcmp(r.root->child[0]->child[0]->child[0]->child[0]->scope, "\\_SB_.DEV0") == 0);
142 T_CHECK(strcmp(r.root->child[0]->child[0]->child[0]->child[0]->child[0]->child[0]->scope,
143 "\\_SB_.DEV0.M000") == 0);
144 T_CHECK(r.root->child[0]->id == 2);
145 T_CHECK(r.root->child[0]->child[0]->parent_id == r.root->child[0]->id);
146 tobi_parse_result_free(&r);
147 return 0;
148}