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 387 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=%llu offset=", n->path ? n->path : n->name, (unsigned long long)n->value); 262 expr(sb, n->child_len > 0 ? n->child[0] : NULL); 263 tobi_sb_add(sb, " length="); 264 expr(sb, n->child_len > 1 ? n->child[1] : NULL); 265 tobi_sb_add(sb, ";\n"); 266 break; 267 case TOBI_IR_FIELD: 268 indent(sb, ind); 269 tobi_sb_printf(sb, "%s %s", n->str ? n->str : "field", n->name ? n->name : "<field>"); 270 if (n->target) { 271 tobi_sb_printf(sb, " backing=%s", n->target); 272 } 273 tobi_sb_printf(sb, " flags=0x%llx access=%u lock=%u update=%u {\n", 274 (unsigned long long)n->value, n->access_type, n->lock_rule, n->update_rule); 275 for (size_t i = 0; i < n->child_len; i++) { 276 indent(sb, ind + 1); 277 if (n->child[i]->kind == TOBI_IR_FIELD_ELEM) { 278 tobi_sb_printf(sb, "%s @%llu:%llu", n->child[i]->name ? n->child[i]->name : "<field>", 279 (unsigned long long)n->child[i]->bit_off, 280 (unsigned long long)n->child[i]->bit_len); 281 if (n->child[i]->str) { 282 tobi_sb_printf(sb, " /* %s */", n->child[i]->str); 283 } 284 tobi_sb_add(sb, ";\n"); 285 } else { 286 tobi_sb_add(sb, "bank_value = "); 287 expr(sb, n->child[i]); 288 tobi_sb_add(sb, ";\n"); 289 } 290 } 291 indent(sb, ind); 292 tobi_sb_add(sb, "}\n"); 293 break; 294 case TOBI_IR_STORE: 295 indent(sb, ind); 296 expr(sb, n); 297 tobi_sb_add(sb, ";\n"); 298 break; 299 case TOBI_IR_EXPR: 300 case TOBI_IR_CALL: 301 indent(sb, ind); 302 if (expr_has_target(n)) { 303 expr_target_stmt(sb, n); 304 } else { 305 expr(sb, n); 306 } 307 tobi_sb_add(sb, ";\n"); 308 break; 309 case TOBI_IR_RETURN: 310 indent(sb, ind); 311 tobi_sb_add(sb, "return"); 312 if (n->child_len) { 313 tobi_sb_ch(sb, ' '); 314 expr(sb, n->child[0]); 315 } 316 tobi_sb_add(sb, ";\n"); 317 break; 318 case TOBI_IR_IF: 319 indent(sb, ind); 320 tobi_sb_add(sb, "if ("); 321 expr(sb, n->child_len ? n->child[0] : NULL); 322 tobi_sb_add(sb, ") {\n"); 323 block(sb, n->child_len > 1 ? n->child[1] : NULL, ind + 1); 324 indent(sb, ind); 325 if (n->child_len > 2) { 326 tobi_sb_add(sb, "} else {\n"); 327 block(sb, n->child[2], ind + 1); 328 indent(sb, ind); 329 } 330 tobi_sb_add(sb, "}\n"); 331 break; 332 case TOBI_IR_WHILE: 333 indent(sb, ind); 334 tobi_sb_add(sb, "while ("); 335 expr(sb, n->child_len ? n->child[0] : NULL); 336 tobi_sb_add(sb, ") {\n"); 337 block(sb, n->child_len > 1 ? n->child[1] : NULL, ind + 1); 338 indent(sb, ind); 339 tobi_sb_add(sb, "}\n"); 340 break; 341 case TOBI_IR_BREAK: 342 indent(sb, ind); 343 tobi_sb_add(sb, "break;\n"); 344 break; 345 case TOBI_IR_CONTINUE: 346 indent(sb, ind); 347 tobi_sb_add(sb, "continue;\n"); 348 break; 349 case TOBI_IR_UNKNOWN: 350 indent(sb, ind); 351 tobi_sb_printf(sb, "/* unknown opcode 0x%x at 0x%zx", n->raw_op, n->off); 352 if (n->str) { 353 tobi_sb_printf(sb, ": %s", n->str); 354 } 355 tobi_sb_add(sb, " */\n"); 356 break; 357 case TOBI_IR_DIAG: 358 indent(sb, ind); 359 tobi_sb_printf(sb, "/* %s at 0x%zx */\n", n->str ? n->str : "diagnostic", n->off); 360 break; 361 case TOBI_IR_BLOCK: 362 block(sb, n, ind); 363 break; 364 default: 365 indent(sb, ind); 366 tobi_sb_printf(sb, "/* %s at 0x%zx */\n", tobi_ir_kind_name(n->kind), n->off); 367 break; 368 } 369} 370 371char *tobi_dc_emit(const tobi_ir *root, const tobi_diag_list *diag) { 372 tobi_sb sb; 373 tobi_sb_init(&sb); 374 if (diag) { 375 for (size_t i = 0; i < diag->len; i++) { 376 if (diag->items[i].level == TOBI_DIAG_WARN) { 377 tobi_sb_printf(&sb, "/* warning at 0x%zx: %s */\n", diag->items[i].off, diag->items[i].msg); 378 } 379 } 380 } 381 if (root) { 382 for (size_t i = 0; i < root->child_len; i++) { 383 stmt(&sb, root->child[i], 0); 384 } 385 } 386 return tobi_sb_take(&sb); 387}