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->kind == TOBI_IR_INTEGER || n->kind == TOBI_IR_PACKAGE || n->kind == TOBI_IR_FIELD ||
57 n->kind == TOBI_IR_FIELD_ELEM || n->kind == TOBI_IR_CALL || n->kind == TOBI_IR_OPREGION ||
58 n->kind == TOBI_IR_RESOURCE) {
59 comma(sb, &first);
60 tobi_sb_printf(sb, "\"value\":%llu", (unsigned long long)n->value);
61 }
62 if (n->raw_op) {
63 comma(sb, &first);
64 tobi_sb_printf(sb, "\"raw_opcode\":%u", n->raw_op);
65 }
66 if (n->kind == TOBI_IR_METHOD) {
67 comma(sb, &first);
68 tobi_sb_printf(sb, "\"args\":%u", n->method_args);
69 comma(sb, &first);
70 tobi_sb_printf(sb, "\"serialized\":%s", n->method_serialized ? "true" : "false");
71 comma(sb, &first);
72 tobi_sb_printf(sb, "\"sync\":%u", n->method_sync);
73 }
74 if (n->bit_len || n->access_type || n->lock_rule || n->update_rule) {
75 comma(sb, &first);
76 tobi_sb_printf(sb, "\"bit_offset\":%llu", (unsigned long long)n->bit_off);
77 comma(sb, &first);
78 tobi_sb_printf(sb, "\"bit_length\":%llu", (unsigned long long)n->bit_len);
79 comma(sb, &first);
80 tobi_sb_printf(sb, "\"access_type\":%u", n->access_type);
81 comma(sb, &first);
82 tobi_sb_printf(sb, "\"lock_rule\":%u", n->lock_rule);
83 comma(sb, &first);
84 tobi_sb_printf(sb, "\"update_rule\":%u", n->update_rule);
85 }
86 comma(sb, &first);
87 tobi_sb_add(sb, "\"children\":[");
88 for (size_t i = 0; i < n->child_len; i++) {
89 if (i) {
90 tobi_sb_ch(sb, ',');
91 }
92 node(sb, n->child[i]);
93 }
94 tobi_sb_add(sb, "]}");
95}
96
97static void namespace_emit(tobi_sb *sb, const tobi_parse_result *res) {
98 tobi_sb_add(sb, "\"namespace\":[");
99 for (size_t i = 0; i < res->ns.len; i++) {
100 const tobi_ns_ent *e = &res->ns.items[i];
101 if (i) {
102 tobi_sb_ch(sb, ',');
103 }
104 tobi_sb_add(sb, "{\"kind\":");
105 tobi_json_string(sb, tobi_ns_kind_name(e->kind));
106 tobi_sb_add(sb, ",\"path\":");
107 tobi_json_string(sb, e->path);
108 tobi_sb_add(sb, ",\"name\":");
109 tobi_json_string(sb, e->name);
110 tobi_sb_add(sb, ",\"owner\":");
111 tobi_json_string(sb, e->owner);
112 tobi_sb_printf(sb, ",\"offset\":%zu,\"args\":%u,\"flags\":%u,\"external\":%s",
113 e->off, e->args, e->flags, e->external ? "true" : "false");
114 if (e->target) {
115 tobi_sb_add(sb, ",\"target\":");
116 tobi_json_string(sb, e->target);
117 }
118 tobi_sb_ch(sb, '}');
119 }
120 tobi_sb_ch(sb, ']');
121}
122
123char *tobi_js_emit(const tobi_parse_result *res) {
124 tobi_sb sb;
125 tobi_sb_init(&sb);
126 tobi_sb_add(&sb, "{\"meta\":{");
127 tobi_sb_printf(&sb, "\"is_table\":%s,", res->meta.is_table ? "true" : "false");
128 tobi_sb_add(&sb, "\"source\":");
129 tobi_json_string(&sb, res->meta.source);
130 tobi_sb_add(&sb, ",");
131 tobi_sb_add(&sb, "\"signature\":");
132 tobi_json_string(&sb, res->meta.signature);
133 tobi_sb_printf(&sb, ",\"table_length\":%zu,\"aml_offset\":%zu,\"aml_length\":%zu,"
134 "\"revision\":%u,\"checksum_byte\":%u,\"checksum_sum\":%u,"
135 "\"checksum_valid\":%s,\"header_hash\":%u,\"aml_hash\":%u,",
136 res->meta.table_len, res->meta.aml_off, res->meta.aml_len,
137 (unsigned)res->meta.revision, (unsigned)res->meta.checksum_byte,
138 (unsigned)res->meta.checksum_sum, res->meta.checksum_valid ? "true" : "false",
139 res->meta.header_hash, res->meta.aml_hash);
140 tobi_sb_add(&sb, "\"oem_id\":");
141 tobi_json_string(&sb, res->meta.oem_id);
142 tobi_sb_add(&sb, ",\"oem_table_id\":");
143 tobi_json_string(&sb, res->meta.oem_table_id);
144 tobi_sb_printf(&sb, ",\"oem_revision\":%u,", res->meta.oem_revision);
145 tobi_sb_add(&sb, "\"creator_id\":");
146 tobi_json_string(&sb, res->meta.creator_id);
147 tobi_sb_printf(&sb, ",\"creator_revision\":%u},", res->meta.creator_revision);
148 tobi_sb_add(&sb, "\"diagnostics\":[");
149 for (size_t i = 0; i < res->diag.len; i++) {
150 if (i) {
151 tobi_sb_ch(&sb, ',');
152 }
153 tobi_sb_printf(&sb, "{\"level\":");
154 tobi_json_string(&sb, tobi_diag_level_name(res->diag.items[i].level));
155 tobi_sb_printf(&sb, ",\"offset\":%zu,\"message\":", res->diag.items[i].off);
156 tobi_json_string(&sb, res->diag.items[i].msg);
157 tobi_sb_ch(&sb, '}');
158 }
159 tobi_sb_add(&sb, "],");
160 namespace_emit(&sb, res);
161 tobi_sb_add(&sb, ",\"ir\":");
162 if (res->root) {
163 node(&sb, res->root);
164 } else {
165 tobi_sb_add(&sb, "null");
166 }
167 tobi_sb_add(&sb, "}\n");
168 return tobi_sb_take(&sb);
169}