ACPI AML decompiler w/ CFG recovery and structured pseudocode
1#include "ir.h"
2
3#include "mem.h"
4
5#include <stdlib.h>
6#include <stdint.h>
7
8tobi_ir *tobi_ir_new(tobi_ir_kind kind, size_t off, size_t len) {
9 tobi_ir *n = tobi_xcalloc(1, sizeof(*n));
10 n->kind = kind;
11 n->off = off;
12 n->len = len;
13 n->parent_index = SIZE_MAX;
14 return n;
15}
16
17void tobi_ir_free(tobi_ir *node) {
18 if (!node) {
19 return;
20 }
21 for (size_t i = 0; i < node->child_len; i++) {
22 tobi_ir_free(node->child[i]);
23 }
24 free(node->child);
25 free(node->name);
26 free(node->path);
27 free(node->scope);
28 free(node->str);
29 free(node->target);
30 free(node->source);
31 free(node);
32}
33
34void tobi_ir_add(tobi_ir *parent, tobi_ir *child) {
35 if (!parent || !child) {
36 return;
37 }
38 if (parent->child_len == parent->child_cap) {
39 parent->child_cap = tobi_xgrow_cap(parent->child_cap, parent->child_len + 1u, 4u);
40 parent->child = tobi_xrealloc(parent->child,
41 tobi_xmul_size(parent->child_cap, sizeof(parent->child[0])));
42 }
43 if (parent->has_source && !child->has_source) {
44 tobi_ir_set_source_recursive(child, parent->source, parent->input_index);
45 }
46 child->parent_id = parent->id;
47 child->parent_index = parent->child_len;
48 parent->child[parent->child_len++] = child;
49}
50
51void tobi_ir_assign_ids(tobi_ir *root) {
52 if (!root) {
53 return;
54 }
55 typedef struct frame {
56 tobi_ir *node;
57 size_t parent_id;
58 size_t parent_index;
59 } frame;
60 size_t cap = 64;
61 size_t len = 0;
62 frame *stack = tobi_xcalloc(cap, sizeof(stack[0]));
63 stack[len++] = (frame){root, 0, SIZE_MAX};
64 size_t next_id = 1;
65 while (len > 0) {
66 frame cur = stack[--len];
67 cur.node->id = next_id++;
68 cur.node->parent_id = cur.parent_id;
69 cur.node->parent_index = cur.parent_index;
70 for (size_t i = cur.node->child_len; i > 0; i--) {
71 if (len == cap) {
72 cap = tobi_xgrow_cap(cap, len + 1u, 64u);
73 stack = tobi_xrealloc(stack, tobi_xmul_size(cap, sizeof(stack[0])));
74 }
75 stack[len++] = (frame){cur.node->child[i - 1u], cur.node->id, i - 1u};
76 }
77 }
78 free(stack);
79}
80
81void tobi_ir_set_name(tobi_ir *node, const char *s) {
82 free(node->name);
83 node->name = tobi_xstrdup(s ? s : "");
84}
85
86void tobi_ir_set_path(tobi_ir *node, const char *s) {
87 free(node->path);
88 node->path = tobi_xstrdup(s ? s : "");
89}
90
91void tobi_ir_set_scope(tobi_ir *node, const char *s) {
92 free(node->scope);
93 node->scope = tobi_xstrdup(s ? s : "");
94}
95
96void tobi_ir_set_str(tobi_ir *node, const char *s) {
97 free(node->str);
98 node->str = tobi_xstrdup(s ? s : "");
99}
100
101void tobi_ir_set_target(tobi_ir *node, const char *s) {
102 free(node->target);
103 node->target = tobi_xstrdup(s ? s : "");
104}
105
106void tobi_ir_set_source(tobi_ir *node, const char *s, size_t input_index) {
107 if (!node || !s) {
108 return;
109 }
110 free(node->source);
111 node->source = tobi_xstrdup(s);
112 node->input_index = input_index;
113 node->has_source = 1;
114}
115
116void tobi_ir_set_source_recursive(tobi_ir *node, const char *s, size_t input_index) {
117 if (!node || !s) {
118 return;
119 }
120 tobi_ir_set_source(node, s, input_index);
121 for (size_t i = 0; i < node->child_len; i++) {
122 tobi_ir_set_source_recursive(node->child[i], s, input_index);
123 }
124}
125
126const char *tobi_ir_kind_name(tobi_ir_kind kind) {
127 switch (kind) {
128 case TOBI_IR_ROOT: return "root";
129 case TOBI_IR_BLOCK: return "block";
130 case TOBI_IR_SCOPE: return "scope";
131 case TOBI_IR_DEVICE: return "device";
132 case TOBI_IR_METHOD: return "method";
133 case TOBI_IR_PROCESSOR: return "processor";
134 case TOBI_IR_NAME: return "name";
135 case TOBI_IR_ALIAS: return "alias";
136 case TOBI_IR_OPREGION: return "opregion";
137 case TOBI_IR_FIELD: return "field";
138 case TOBI_IR_FIELD_ELEM: return "field_elem";
139 case TOBI_IR_MUTEX: return "mutex";
140 case TOBI_IR_EVENT: return "event";
141 case TOBI_IR_RESOURCE: return "resource";
142 case TOBI_IR_BUFFER: return "buffer";
143 case TOBI_IR_PACKAGE: return "package";
144 case TOBI_IR_INTEGER: return "integer";
145 case TOBI_IR_STRING: return "string";
146 case TOBI_IR_REF: return "ref";
147 case TOBI_IR_CALL: return "call";
148 case TOBI_IR_EXPR: return "expr";
149 case TOBI_IR_STORE: return "store";
150 case TOBI_IR_RETURN: return "return";
151 case TOBI_IR_IF: return "if";
152 case TOBI_IR_WHILE: return "while";
153 case TOBI_IR_BREAK: return "break";
154 case TOBI_IR_CONTINUE: return "continue";
155 case TOBI_IR_UNKNOWN: return "unknown";
156 case TOBI_IR_DIAG: return "diag";
157 }
158 return "invalid";
159}
160
161tobi_ir *tobi_ir_find_child(tobi_ir *node, tobi_ir_kind kind) {
162 if (!node) {
163 return NULL;
164 }
165 for (size_t i = 0; i < node->child_len; i++) {
166 if (node->child[i]->kind == kind) {
167 return node->child[i];
168 }
169 }
170 return NULL;
171}
172
173size_t tobi_ir_count_kind(const tobi_ir *node, tobi_ir_kind kind) {
174 size_t n = 0;
175 if (!node) {
176 return 0;
177 }
178 for (size_t i = 0; i < node->child_len; i++) {
179 if (node->child[i]->kind == kind) {
180 n++;
181 }
182 }
183 return n;
184}