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->kind == TOBI_IR_INTEGER || n->kind == TOBI_IR_PACKAGE || n->kind == TOBI_IR_FIELD ||
39 n->kind == TOBI_IR_FIELD_ELEM || n->kind == TOBI_IR_CALL || n->kind == TOBI_IR_OPREGION ||
40 n->kind == TOBI_IR_RESOURCE) {
41 comma(sb, &first);
42 tobi_sb_printf(sb, "\"value\":%llu", (unsigned long long)n->value);
43 }
44 if (n->raw_op) {
45 comma(sb, &first);
46 tobi_sb_printf(sb, "\"raw_opcode\":%u", n->raw_op);
47 }
48 if (n->kind == TOBI_IR_METHOD) {
49 comma(sb, &first);
50 tobi_sb_printf(sb, "\"args\":%u", n->method_args);
51 comma(sb, &first);
52 tobi_sb_printf(sb, "\"serialized\":%s", n->method_serialized ? "true" : "false");
53 comma(sb, &first);
54 tobi_sb_printf(sb, "\"sync\":%u", n->method_sync);
55 }
56 comma(sb, &first);
57 tobi_sb_add(sb, "\"children\":[");
58 for (size_t i = 0; i < n->child_len; i++) {
59 if (i) {
60 tobi_sb_ch(sb, ',');
61 }
62 node(sb, n->child[i]);
63 }
64 tobi_sb_add(sb, "]}");
65}
66
67static void namespace_emit(tobi_sb *sb, const tobi_parse_result *res) {
68 tobi_sb_add(sb, "\"namespace\":[");
69 for (size_t i = 0; i < res->ns.len; i++) {
70 const tobi_ns_ent *e = &res->ns.items[i];
71 if (i) {
72 tobi_sb_ch(sb, ',');
73 }
74 tobi_sb_add(sb, "{\"kind\":");
75 tobi_json_string(sb, tobi_ns_kind_name(e->kind));
76 tobi_sb_add(sb, ",\"path\":");
77 tobi_json_string(sb, e->path);
78 tobi_sb_add(sb, ",\"name\":");
79 tobi_json_string(sb, e->name);
80 tobi_sb_add(sb, ",\"owner\":");
81 tobi_json_string(sb, e->owner);
82 tobi_sb_printf(sb, ",\"offset\":%zu,\"args\":%u,\"flags\":%u,\"external\":%s",
83 e->off, e->args, e->flags, e->external ? "true" : "false");
84 if (e->target) {
85 tobi_sb_add(sb, ",\"target\":");
86 tobi_json_string(sb, e->target);
87 }
88 tobi_sb_ch(sb, '}');
89 }
90 tobi_sb_ch(sb, ']');
91}
92
93char *tobi_js_emit(const tobi_parse_result *res) {
94 tobi_sb sb;
95 tobi_sb_init(&sb);
96 tobi_sb_add(&sb, "{\"meta\":{");
97 tobi_sb_printf(&sb, "\"is_table\":%s,", res->meta.is_table ? "true" : "false");
98 tobi_sb_add(&sb, "\"signature\":");
99 tobi_json_string(&sb, res->meta.signature);
100 tobi_sb_printf(&sb, ",\"table_length\":%zu,\"aml_offset\":%zu,\"aml_length\":%zu,"
101 "\"checksum_sum\":%u,\"checksum_valid\":%s},",
102 res->meta.table_len, res->meta.aml_off, res->meta.aml_len,
103 (unsigned)res->meta.checksum_sum, res->meta.checksum_valid ? "true" : "false");
104 tobi_sb_add(&sb, "\"diagnostics\":[");
105 for (size_t i = 0; i < res->diag.len; i++) {
106 if (i) {
107 tobi_sb_ch(&sb, ',');
108 }
109 tobi_sb_printf(&sb, "{\"level\":");
110 tobi_json_string(&sb, tobi_diag_level_name(res->diag.items[i].level));
111 tobi_sb_printf(&sb, ",\"offset\":%zu,\"message\":", res->diag.items[i].off);
112 tobi_json_string(&sb, res->diag.items[i].msg);
113 tobi_sb_ch(&sb, '}');
114 }
115 tobi_sb_add(&sb, "],");
116 namespace_emit(&sb, res);
117 tobi_sb_add(&sb, ",\"ir\":");
118 if (res->root) {
119 node(&sb, res->root);
120 } else {
121 tobi_sb_add(&sb, "null");
122 }
123 tobi_sb_add(&sb, "}\n");
124 return tobi_sb_take(&sb);
125}