ACPI AML decompiler w/ CFG recovery and structured pseudocode
1#include "js.h"
2
3#include "str.h"
4
5static void comma(tobi_sb *sb, int *first) {
6 if (*first) {
7 *first = 0;
8 } else {
9 tobi_sb_ch(sb, ',');
10 }
11}
12
13static void node(tobi_sb *sb, const tobi_ir *n) {
14 int first = 1;
15 tobi_sb_ch(sb, '{');
16 comma(sb, &first);
17 tobi_sb_add(sb, "\"kind\":");
18 tobi_json_string(sb, tobi_ir_kind_name(n->kind));
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);
28 tobi_sb_printf(sb, "\"offset\":%zu", n->off);
29 comma(sb, &first);
30 tobi_sb_printf(sb, "\"length\":%zu", n->len);
31 if (n->name) {
32 comma(sb, &first);
33 tobi_sb_add(sb, "\"name\":");
34 tobi_json_string(sb, n->name);
35 }
36 if (n->path) {
37 comma(sb, &first);
38 tobi_sb_add(sb, "\"path\":");
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);
45 }
46 if (n->str) {
47 comma(sb, &first);
48 tobi_sb_add(sb, "\"string\":");
49 tobi_json_string(sb, n->str);
50 }
51 if (n->target) {
52 comma(sb, &first);
53 tobi_sb_add(sb, "\"target\":");
54 tobi_json_string(sb, n->target);
55 }
56 if (n->has_source && n->source) {
57 comma(sb, &first);
58 tobi_sb_add(sb, "\"source\":");
59 tobi_json_string(sb, n->source);
60 comma(sb, &first);
61 tobi_sb_printf(sb, "\"input_index\":%zu", n->input_index);
62 }
63 if (n->kind == TOBI_IR_INTEGER || n->kind == TOBI_IR_PACKAGE || n->kind == TOBI_IR_FIELD ||
64 n->kind == TOBI_IR_FIELD_ELEM || n->kind == TOBI_IR_CALL || n->kind == TOBI_IR_OPREGION ||
65 n->kind == TOBI_IR_RESOURCE) {
66 comma(sb, &first);
67 tobi_sb_printf(sb, "\"value\":%llu", (unsigned long long)n->value);
68 }
69 if (n->raw_op) {
70 comma(sb, &first);
71 tobi_sb_printf(sb, "\"raw_opcode\":%u", n->raw_op);
72 }
73 if (n->kind == TOBI_IR_METHOD) {
74 comma(sb, &first);
75 tobi_sb_printf(sb, "\"args\":%u", n->method_args);
76 comma(sb, &first);
77 tobi_sb_printf(sb, "\"serialized\":%s", n->method_serialized ? "true" : "false");
78 comma(sb, &first);
79 tobi_sb_printf(sb, "\"sync\":%u", n->method_sync);
80 }
81 if (n->bit_len || n->access_type || n->lock_rule || n->update_rule) {
82 comma(sb, &first);
83 tobi_sb_printf(sb, "\"bit_offset\":%llu", (unsigned long long)n->bit_off);
84 comma(sb, &first);
85 tobi_sb_printf(sb, "\"bit_length\":%llu", (unsigned long long)n->bit_len);
86 comma(sb, &first);
87 tobi_sb_printf(sb, "\"access_type\":%u", n->access_type);
88 comma(sb, &first);
89 tobi_sb_printf(sb, "\"lock_rule\":%u", n->lock_rule);
90 comma(sb, &first);
91 tobi_sb_printf(sb, "\"update_rule\":%u", n->update_rule);
92 }
93 comma(sb, &first);
94 tobi_sb_add(sb, "\"children\":[");
95 for (size_t i = 0; i < n->child_len; i++) {
96 if (i) {
97 tobi_sb_ch(sb, ',');
98 }
99 node(sb, n->child[i]);
100 }
101 tobi_sb_add(sb, "]}");
102}
103
104static void namespace_emit(tobi_sb *sb, const tobi_parse_result *res) {
105 tobi_sb_add(sb, "\"namespace\":[");
106 for (size_t i = 0; i < res->ns.len; i++) {
107 const tobi_ns_ent *e = &res->ns.items[i];
108 if (i) {
109 tobi_sb_ch(sb, ',');
110 }
111 tobi_sb_add(sb, "{\"kind\":");
112 tobi_json_string(sb, tobi_ns_kind_name(e->kind));
113 tobi_sb_add(sb, ",\"path\":");
114 tobi_json_string(sb, e->path);
115 tobi_sb_add(sb, ",\"name\":");
116 tobi_json_string(sb, e->name);
117 tobi_sb_add(sb, ",\"owner\":");
118 tobi_json_string(sb, e->owner);
119 tobi_sb_printf(sb, ",\"offset\":%zu,\"args\":%u,\"flags\":%u,\"external\":%s",
120 e->off, e->args, e->flags, e->external ? "true" : "false");
121 if (e->target) {
122 tobi_sb_add(sb, ",\"target\":");
123 tobi_json_string(sb, e->target);
124 }
125 if (e->has_source && e->source) {
126 tobi_sb_add(sb, ",\"source\":");
127 tobi_json_string(sb, e->source);
128 tobi_sb_printf(sb, ",\"input_index\":%zu", e->input_index);
129 }
130 tobi_sb_ch(sb, '}');
131 }
132 tobi_sb_ch(sb, ']');
133}
134
135static void meta_obj(tobi_sb *sb, const tobi_input_meta *meta) {
136 tobi_sb_ch(sb, '{');
137 tobi_sb_printf(sb, "\"is_table\":%s,", meta->is_table ? "true" : "false");
138 tobi_sb_add(sb, "\"source\":");
139 tobi_json_string(sb, meta->source);
140 tobi_sb_add(sb, ",\"signature\":");
141 tobi_json_string(sb, meta->signature);
142 tobi_sb_printf(sb, ",\"table_length\":%zu,\"aml_offset\":%zu,\"aml_length\":%zu,"
143 "\"revision\":%u,\"checksum_byte\":%u,\"checksum_sum\":%u,"
144 "\"checksum_valid\":%s,\"header_hash\":%u,\"aml_hash\":%u,",
145 meta->table_len, meta->aml_off, meta->aml_len,
146 (unsigned)meta->revision, (unsigned)meta->checksum_byte,
147 (unsigned)meta->checksum_sum, meta->checksum_valid ? "true" : "false",
148 meta->header_hash, meta->aml_hash);
149 tobi_sb_add(sb, "\"oem_id\":");
150 tobi_json_string(sb, meta->oem_id);
151 tobi_sb_add(sb, ",\"oem_table_id\":");
152 tobi_json_string(sb, meta->oem_table_id);
153 tobi_sb_printf(sb, ",\"oem_revision\":%u,", meta->oem_revision);
154 tobi_sb_add(sb, "\"creator_id\":");
155 tobi_json_string(sb, meta->creator_id);
156 tobi_sb_printf(sb, ",\"creator_revision\":%u}", meta->creator_revision);
157}
158
159static void inputs_emit(tobi_sb *sb, const tobi_parse_result *res) {
160 tobi_sb_add(sb, "\"inputs\":[");
161 for (size_t i = 0; i < res->input_len; i++) {
162 if (i) {
163 tobi_sb_ch(sb, ',');
164 }
165 meta_obj(sb, &res->inputs[i]);
166 }
167 tobi_sb_ch(sb, ']');
168}
169
170char *tobi_js_emit(const tobi_parse_result *res) {
171 tobi_sb sb;
172 tobi_sb_init(&sb);
173 tobi_sb_add(&sb, "{\"meta\":");
174 meta_obj(&sb, &res->meta);
175 tobi_sb_ch(&sb, ',');
176 inputs_emit(&sb, res);
177 tobi_sb_ch(&sb, ',');
178 tobi_sb_add(&sb, "\"diagnostics\":[");
179 for (size_t i = 0; i < res->diag.len; i++) {
180 if (i) {
181 tobi_sb_ch(&sb, ',');
182 }
183 tobi_sb_printf(&sb, "{\"level\":");
184 tobi_json_string(&sb, tobi_diag_level_name(res->diag.items[i].level));
185 tobi_sb_printf(&sb, ",\"offset\":%zu,\"message\":", res->diag.items[i].off);
186 tobi_json_string(&sb, res->diag.items[i].msg);
187 if (res->diag.items[i].has_source && res->diag.items[i].source) {
188 tobi_sb_add(&sb, ",\"source\":");
189 tobi_json_string(&sb, res->diag.items[i].source);
190 tobi_sb_printf(&sb, ",\"input_index\":%zu", res->diag.items[i].input_index);
191 }
192 tobi_sb_ch(&sb, '}');
193 }
194 tobi_sb_add(&sb, "],");
195 namespace_emit(&sb, res);
196 tobi_sb_add(&sb, ",\"ir\":");
197 if (res->root) {
198 node(&sb, res->root);
199 } else {
200 tobi_sb_add(&sb, "null");
201 }
202 tobi_sb_add(&sb, "}\n");
203 return tobi_sb_take(&sb);
204}