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