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