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