ACPI AML decompiler w/ CFG recovery and structured pseudocode
29

Configure Feed

Select the types of activity you want to include in your feed.

tobi / src / dc.c
12 kB 388 lines
1#include "dc.h" 2 3#include "mem.h" 4#include "str.h" 5 6#include <stdio.h> 7#include <string.h> 8 9static void indent(tobi_sb *sb, unsigned n) { 10 for (unsigned i = 0; i < n; i++) { 11 tobi_sb_add(sb, " "); 12 } 13} 14 15static void expr(tobi_sb *sb, const tobi_ir *n); 16static void stmt(tobi_sb *sb, const tobi_ir *n, unsigned ind); 17 18static const char *binop(const char *name) { 19 if (!name) { 20 return NULL; 21 } 22 if (strcmp(name, "eq") == 0) return "=="; 23 if (strcmp(name, "gt") == 0) return ">"; 24 if (strcmp(name, "lt") == 0) return "<"; 25 if (strcmp(name, "add") == 0) return "+"; 26 if (strcmp(name, "sub") == 0) return "-"; 27 if (strcmp(name, "mul") == 0) return "*"; 28 if (strcmp(name, "div") == 0) return "/"; 29 if (strcmp(name, "mod") == 0) return "%"; 30 if (strcmp(name, "shl") == 0) return "<<"; 31 if (strcmp(name, "shr") == 0) return ">>"; 32 if (strcmp(name, "and") == 0) return "&"; 33 if (strcmp(name, "or") == 0) return "|"; 34 if (strcmp(name, "xor") == 0) return "^"; 35 if (strcmp(name, "land") == 0) return "&&"; 36 if (strcmp(name, "lor") == 0) return "||"; 37 return NULL; 38} 39 40static const char *unop(const char *name) { 41 if (!name) { 42 return NULL; 43 } 44 if (strcmp(name, "lnot") == 0) return "!"; 45 if (strcmp(name, "not") == 0) return "~"; 46 return NULL; 47} 48 49static int op_prec(const char *name) { 50 if (!name) { 51 return 0; 52 } 53 if (strcmp(name, "lor") == 0) return 1; 54 if (strcmp(name, "land") == 0) return 2; 55 if (strcmp(name, "or") == 0) return 3; 56 if (strcmp(name, "xor") == 0) return 4; 57 if (strcmp(name, "and") == 0) return 5; 58 if (strcmp(name, "eq") == 0 || strcmp(name, "gt") == 0 || strcmp(name, "lt") == 0) return 6; 59 if (strcmp(name, "shl") == 0 || strcmp(name, "shr") == 0) return 7; 60 if (strcmp(name, "add") == 0 || strcmp(name, "sub") == 0) return 8; 61 if (strcmp(name, "mul") == 0 || strcmp(name, "div") == 0 || strcmp(name, "mod") == 0) return 9; 62 if (unop(name)) return 10; 63 return 0; 64} 65 66static int op_right_needs_group(const char *name) { 67 if (!name) { 68 return 1; 69 } 70 return !(strcmp(name, "add") == 0 || strcmp(name, "mul") == 0 || 71 strcmp(name, "and") == 0 || strcmp(name, "or") == 0 || 72 strcmp(name, "xor") == 0 || strcmp(name, "land") == 0 || 73 strcmp(name, "lor") == 0); 74} 75 76static void expr_prec(tobi_sb *sb, const tobi_ir *n, int parent_prec) { 77 if (!n) { 78 tobi_sb_add(sb, "<missing>"); 79 return; 80 } 81 switch (n->kind) { 82 case TOBI_IR_INTEGER: 83 tobi_sb_printf(sb, "0x%llx", (unsigned long long)n->value); 84 return; 85 case TOBI_IR_STRING: 86 tobi_sb_ch(sb, '"'); 87 if (n->str) { 88 for (const char *p = n->str; *p; p++) { 89 if (*p == '"' || *p == '\\') { 90 tobi_sb_ch(sb, '\\'); 91 } 92 tobi_sb_ch(sb, *p); 93 } 94 } 95 tobi_sb_ch(sb, '"'); 96 return; 97 case TOBI_IR_REF: 98 tobi_sb_add(sb, n->name ? n->name : "<ref>"); 99 return; 100 case TOBI_IR_CALL: 101 tobi_sb_add(sb, n->name ? n->name : "<call>"); 102 tobi_sb_ch(sb, '('); 103 for (size_t i = 0; i < n->child_len; i++) { 104 if (i) { 105 tobi_sb_add(sb, ", "); 106 } 107 expr_prec(sb, n->child[i], 0); 108 } 109 tobi_sb_ch(sb, ')'); 110 return; 111 case TOBI_IR_EXPR: { 112 const char *op = binop(n->name); 113 int prec = op_prec(n->name); 114 if (op && n->child_len >= 2 && prec > 0) { 115 int paren = prec < parent_prec; 116 if (paren) { 117 tobi_sb_ch(sb, '('); 118 } 119 expr_prec(sb, n->child[0], prec); 120 tobi_sb_printf(sb, " %s ", op); 121 expr_prec(sb, n->child[1], prec + op_right_needs_group(n->name)); 122 if (paren) { 123 tobi_sb_ch(sb, ')'); 124 } 125 return; 126 } 127 op = unop(n->name); 128 if (op && n->child_len == 1 && prec > 0) { 129 int paren = prec < parent_prec; 130 if (paren) { 131 tobi_sb_ch(sb, '('); 132 } 133 tobi_sb_add(sb, op); 134 expr_prec(sb, n->child[0], prec); 135 if (paren) { 136 tobi_sb_ch(sb, ')'); 137 } 138 return; 139 } 140 tobi_sb_printf(sb, "%s(", n->name ? n->name : "op"); 141 for (size_t i = 0; i < n->child_len; i++) { 142 if (i) { 143 tobi_sb_add(sb, ", "); 144 } 145 expr_prec(sb, n->child[i], 0); 146 } 147 tobi_sb_ch(sb, ')'); 148 return; 149 } 150 case TOBI_IR_BUFFER: 151 tobi_sb_printf(sb, "Buffer[%s]", n->str ? n->str : ""); 152 return; 153 case TOBI_IR_PACKAGE: 154 tobi_sb_ch(sb, '{'); 155 for (size_t i = 0; i < n->child_len; i++) { 156 if (i) { 157 tobi_sb_add(sb, ", "); 158 } 159 expr_prec(sb, n->child[i], 0); 160 } 161 tobi_sb_ch(sb, '}'); 162 return; 163 case TOBI_IR_STORE: 164 if (n->child_len >= 2) { 165 expr_prec(sb, n->child[1], 0); 166 tobi_sb_add(sb, " = "); 167 expr_prec(sb, n->child[0], 0); 168 } else { 169 tobi_sb_add(sb, "store(?)"); 170 } 171 return; 172 case TOBI_IR_UNKNOWN: 173 tobi_sb_printf(sb, "unknown_0x%x", n->raw_op); 174 return; 175 default: 176 tobi_sb_add(sb, n->name ? n->name : tobi_ir_kind_name(n->kind)); 177 return; 178 } 179} 180 181static void expr(tobi_sb *sb, const tobi_ir *n) { 182 expr_prec(sb, n, 0); 183} 184 185static int expr_has_target(const tobi_ir *n) { 186 if (!n || n->kind != TOBI_IR_EXPR || !n->name) { 187 return 0; 188 } 189 if (strcmp(n->name, "div") == 0) { 190 return n->child_len >= 4; 191 } 192 return binop(n->name) && n->child_len >= 3; 193} 194 195static void expr_target_stmt(tobi_sb *sb, const tobi_ir *n) { 196 if (strcmp(n->name, "div") == 0 && n->child_len >= 4) { 197 expr(sb, n->child[2]); 198 tobi_sb_add(sb, ", "); 199 expr(sb, n->child[3]); 200 tobi_sb_add(sb, " = divmod("); 201 expr(sb, n->child[0]); 202 tobi_sb_add(sb, ", "); 203 expr(sb, n->child[1]); 204 tobi_sb_ch(sb, ')'); 205 return; 206 } 207 expr(sb, n->child[2]); 208 tobi_sb_add(sb, " = "); 209 expr(sb, n); 210} 211 212static void block(tobi_sb *sb, const tobi_ir *b, unsigned ind) { 213 if (!b) { 214 return; 215 } 216 for (size_t i = 0; i < b->child_len; i++) { 217 stmt(sb, b->child[i], ind); 218 } 219} 220 221static void stmt(tobi_sb *sb, const tobi_ir *n, unsigned ind) { 222 if (!n) { 223 return; 224 } 225 switch (n->kind) { 226 case TOBI_IR_SCOPE: 227 indent(sb, ind); 228 tobi_sb_printf(sb, "scope %s {\n", n->path ? n->path : n->name); 229 block(sb, n->child_len ? n->child[0] : NULL, ind + 1); 230 indent(sb, ind); 231 tobi_sb_add(sb, "}\n"); 232 break; 233 case TOBI_IR_DEVICE: 234 indent(sb, ind); 235 tobi_sb_printf(sb, "device %s {\n", n->path ? n->path : n->name); 236 block(sb, n->child_len ? n->child[0] : NULL, ind + 1); 237 indent(sb, ind); 238 tobi_sb_add(sb, "}\n"); 239 break; 240 case TOBI_IR_METHOD: 241 indent(sb, ind); 242 tobi_sb_printf(sb, "method %s(args=%u, serialized=%s, sync=%u) {\n", 243 n->name ? n->name : "<method>", n->method_args, 244 n->method_serialized ? "true" : "false", n->method_sync); 245 block(sb, n->child_len ? n->child[0] : NULL, ind + 1); 246 indent(sb, ind); 247 tobi_sb_add(sb, "}\n"); 248 break; 249 case TOBI_IR_NAME: 250 indent(sb, ind); 251 tobi_sb_printf(sb, "name %s = ", n->path ? n->path : n->name); 252 if (n->child_len) { 253 expr(sb, n->child[0]); 254 } else { 255 tobi_sb_add(sb, "<missing>"); 256 } 257 tobi_sb_add(sb, ";\n"); 258 break; 259 case TOBI_IR_OPREGION: 260 indent(sb, ind); 261 tobi_sb_printf(sb, "opregion %s space=%s(%llu) offset=", n->path ? n->path : n->name, 262 n->str ? n->str : "unknown", (unsigned long long)n->value); 263 expr(sb, n->child_len > 0 ? n->child[0] : NULL); 264 tobi_sb_add(sb, " length="); 265 expr(sb, n->child_len > 1 ? n->child[1] : NULL); 266 tobi_sb_add(sb, ";\n"); 267 break; 268 case TOBI_IR_FIELD: 269 indent(sb, ind); 270 tobi_sb_printf(sb, "%s %s", n->str ? n->str : "field", n->name ? n->name : "<field>"); 271 if (n->target) { 272 tobi_sb_printf(sb, " backing=%s", n->target); 273 } 274 tobi_sb_printf(sb, " flags=0x%llx access=%u lock=%u update=%u {\n", 275 (unsigned long long)n->value, n->access_type, n->lock_rule, n->update_rule); 276 for (size_t i = 0; i < n->child_len; i++) { 277 indent(sb, ind + 1); 278 if (n->child[i]->kind == TOBI_IR_FIELD_ELEM) { 279 tobi_sb_printf(sb, "%s @%llu:%llu", n->child[i]->name ? n->child[i]->name : "<field>", 280 (unsigned long long)n->child[i]->bit_off, 281 (unsigned long long)n->child[i]->bit_len); 282 if (n->child[i]->str) { 283 tobi_sb_printf(sb, " /* %s */", n->child[i]->str); 284 } 285 tobi_sb_add(sb, ";\n"); 286 } else { 287 tobi_sb_add(sb, "bank_value = "); 288 expr(sb, n->child[i]); 289 tobi_sb_add(sb, ";\n"); 290 } 291 } 292 indent(sb, ind); 293 tobi_sb_add(sb, "}\n"); 294 break; 295 case TOBI_IR_STORE: 296 indent(sb, ind); 297 expr(sb, n); 298 tobi_sb_add(sb, ";\n"); 299 break; 300 case TOBI_IR_EXPR: 301 case TOBI_IR_CALL: 302 indent(sb, ind); 303 if (expr_has_target(n)) { 304 expr_target_stmt(sb, n); 305 } else { 306 expr(sb, n); 307 } 308 tobi_sb_add(sb, ";\n"); 309 break; 310 case TOBI_IR_RETURN: 311 indent(sb, ind); 312 tobi_sb_add(sb, "return"); 313 if (n->child_len) { 314 tobi_sb_ch(sb, ' '); 315 expr(sb, n->child[0]); 316 } 317 tobi_sb_add(sb, ";\n"); 318 break; 319 case TOBI_IR_IF: 320 indent(sb, ind); 321 tobi_sb_add(sb, "if ("); 322 expr(sb, n->child_len ? n->child[0] : NULL); 323 tobi_sb_add(sb, ") {\n"); 324 block(sb, n->child_len > 1 ? n->child[1] : NULL, ind + 1); 325 indent(sb, ind); 326 if (n->child_len > 2) { 327 tobi_sb_add(sb, "} else {\n"); 328 block(sb, n->child[2], ind + 1); 329 indent(sb, ind); 330 } 331 tobi_sb_add(sb, "}\n"); 332 break; 333 case TOBI_IR_WHILE: 334 indent(sb, ind); 335 tobi_sb_add(sb, "while ("); 336 expr(sb, n->child_len ? n->child[0] : NULL); 337 tobi_sb_add(sb, ") {\n"); 338 block(sb, n->child_len > 1 ? n->child[1] : NULL, ind + 1); 339 indent(sb, ind); 340 tobi_sb_add(sb, "}\n"); 341 break; 342 case TOBI_IR_BREAK: 343 indent(sb, ind); 344 tobi_sb_add(sb, "break;\n"); 345 break; 346 case TOBI_IR_CONTINUE: 347 indent(sb, ind); 348 tobi_sb_add(sb, "continue;\n"); 349 break; 350 case TOBI_IR_UNKNOWN: 351 indent(sb, ind); 352 tobi_sb_printf(sb, "/* unknown opcode 0x%x at 0x%zx", n->raw_op, n->off); 353 if (n->str) { 354 tobi_sb_printf(sb, ": %s", n->str); 355 } 356 tobi_sb_add(sb, " */\n"); 357 break; 358 case TOBI_IR_DIAG: 359 indent(sb, ind); 360 tobi_sb_printf(sb, "/* %s at 0x%zx */\n", n->str ? n->str : "diagnostic", n->off); 361 break; 362 case TOBI_IR_BLOCK: 363 block(sb, n, ind); 364 break; 365 default: 366 indent(sb, ind); 367 tobi_sb_printf(sb, "/* %s at 0x%zx */\n", tobi_ir_kind_name(n->kind), n->off); 368 break; 369 } 370} 371 372char *tobi_dc_emit(const tobi_ir *root, const tobi_diag_list *diag) { 373 tobi_sb sb; 374 tobi_sb_init(&sb); 375 if (diag) { 376 for (size_t i = 0; i < diag->len; i++) { 377 if (diag->items[i].level == TOBI_DIAG_WARN) { 378 tobi_sb_printf(&sb, "/* warning at 0x%zx: %s */\n", diag->items[i].off, diag->items[i].msg); 379 } 380 } 381 } 382 if (root) { 383 for (size_t i = 0; i < root->child_len; i++) { 384 stmt(&sb, root->child[i], 0); 385 } 386 } 387 return tobi_sb_take(&sb); 388}