ACPI AML decompiler w/ CFG recovery and structured pseudocode
29

Configure Feed

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

Add semantic validation for AML method calls unresolved refs externals and alias cycles

+115
+96
src/p.c
··· 1157 1157 add_expr_children(p, rd, depth, n, 2); 1158 1158 tobi_ir *dst = ref_from_name(p, rd, off, "bad create-field namestring"); 1159 1159 if (dst) { 1160 + if (dst->path && dst->path[0] == '\\') { 1161 + ns_declare_path(p, TOBI_NS_FIELD, dst->path, dst->off, 0, op, 0, NULL); 1162 + } 1160 1163 tobi_ir_add(n, dst); 1161 1164 } 1162 1165 n->len = tobi_rd_off(rd) - off; ··· 1406 1409 } 1407 1410 } 1408 1411 1412 + static void sem_diag(parser *p, size_t off, const char *fmt, ...) { 1413 + va_list ap; 1414 + va_start(ap, fmt); 1415 + va_list cp; 1416 + va_copy(cp, ap); 1417 + int n = vsnprintf(NULL, 0, fmt, cp); 1418 + va_end(cp); 1419 + if (n < 0) { 1420 + n = 0; 1421 + } 1422 + char *msg = tobi_xmalloc((size_t)n + 1); 1423 + (void)vsnprintf(msg, (size_t)n + 1, fmt, ap); 1424 + va_end(ap); 1425 + diag(p, p->strict ? TOBI_DIAG_ERROR : TOBI_DIAG_WARN, off, "%s", msg); 1426 + free(msg); 1427 + } 1428 + 1429 + static int semantic_alias_cycle_from(const tobi_ns *ns, const tobi_ns_ent *start) { 1430 + const tobi_ns_ent *cur = start; 1431 + for (unsigned depth = 0; cur && cur->kind == TOBI_NS_ALIAS && cur->target; depth++) { 1432 + if (depth > ns->len) { 1433 + return 1; 1434 + } 1435 + const tobi_ns_ent *next = tobi_ns_find_const(ns, cur->target); 1436 + if (!next) { 1437 + return 0; 1438 + } 1439 + if (next == start) { 1440 + return 1; 1441 + } 1442 + cur = next; 1443 + } 1444 + return 0; 1445 + } 1446 + 1447 + static int semantic_ref_is_value(const tobi_ir *parent) { 1448 + if (!parent) { 1449 + return 1; 1450 + } 1451 + if (parent->kind == TOBI_IR_EXPR && parent->name) { 1452 + if (strncmp(parent->name, "create_", 7) == 0 || strcmp(parent->name, "cond_ref_of") == 0 || 1453 + strcmp(parent->name, "load") == 0 || strcmp(parent->name, "ref_of") == 0 || 1454 + strcmp(parent->name, "acquire") == 0 || strcmp(parent->name, "wait") == 0 || 1455 + strcmp(parent->name, "signal") == 0 || strcmp(parent->name, "reset") == 0 || 1456 + strcmp(parent->name, "release") == 0) { 1457 + return 0; 1458 + } 1459 + } 1460 + return 1; 1461 + } 1462 + 1463 + static void semantic_walk(parser *p, const tobi_ir *n, const tobi_ir *parent) { 1464 + if (!n) { 1465 + return; 1466 + } 1467 + if (n->kind == TOBI_IR_CALL && n->path && n->path[0] == '\\') { 1468 + const tobi_ns_ent *ent = tobi_ns_find_const(p->ns, n->path); 1469 + if (!ent || ent->kind != TOBI_NS_METHOD) { 1470 + sem_diag(p, n->off, "unresolved AML method call %s", n->path); 1471 + } else if (n->child_len != (size_t)ent->args) { 1472 + sem_diag(p, n->off, "AML method call %s has %zu args but namespace declares %u", 1473 + n->path, n->child_len, ent->args); 1474 + } 1475 + } else if (n->kind == TOBI_IR_REF && n->path && n->path[0] == '\\' && semantic_ref_is_value(parent)) { 1476 + const tobi_ns_ent *ent = tobi_ns_find_const(p->ns, n->path); 1477 + if (!ent) { 1478 + sem_diag(p, n->off, "unresolved AML namespace reference %s", n->path); 1479 + } 1480 + } 1481 + for (size_t i = 0; i < n->child_len; i++) { 1482 + semantic_walk(p, n->child[i], n); 1483 + } 1484 + } 1485 + 1486 + static void semantic_validate(parser *p, const tobi_ir *root) { 1487 + for (size_t i = 0; i < p->ns->len; i++) { 1488 + const tobi_ns_ent *e = &p->ns->items[i]; 1489 + if (e->external && e->kind == TOBI_NS_METHOD) { 1490 + sem_diag(p, e->off, "external AML method %s remains unresolved", e->path); 1491 + } 1492 + if (e->kind == TOBI_NS_ALIAS) { 1493 + if (e->target && !tobi_ns_find_const(p->ns, e->target)) { 1494 + sem_diag(p, e->off, "AML alias %s targets unresolved object %s", e->path, e->target); 1495 + } else if (semantic_alias_cycle_from(p->ns, e)) { 1496 + sem_diag(p, e->off, "AML alias cycle includes %s", e->path); 1497 + } 1498 + } 1499 + } 1500 + semantic_walk(p, root, NULL); 1501 + } 1502 + 1409 1503 int tobi_parse(const uint8_t *data, size_t len, int strict, tobi_parse_result *out) { 1410 1504 memset(out, 0, sizeof(*out)); 1411 1505 tobi_diag_init(&out->diag); ··· 1428 1522 tobi_rd_init(&rd, data + out->meta.aml_off, out->meta.aml_len, out->meta.aml_off); 1429 1523 (void)parse_term_list(&p, &rd, out->root, 0); 1430 1524 } 1525 + semantic_validate(&p, out->root); 1431 1526 parser_free(&p); 1432 1527 return !(strict && tobi_diag_has_error(&out->diag)); 1433 1528 } ··· 1476 1571 tobi_ir_add(out->root, file); 1477 1572 } 1478 1573 } 1574 + semantic_validate(&p, out->root); 1479 1575 parser_free(&p); 1480 1576 free(metas); 1481 1577 return ok && !(strict && tobi_diag_has_error(&out->diag));
+19
test/t_p.c
··· 246 246 T_CHECK(!tobi_parse(dup_name, sizeof(dup_name), 1, &r)); 247 247 T_CHECK(tobi_diag_has_error(&r.diag)); 248 248 tobi_parse_result_free(&r); 249 + 250 + uint8_t unresolved_ref[] = {0x14,0x0b,'U','N','R','0',0x00,0xa4,'N','O','P','E'}; 251 + T_CHECK(tobi_parse(unresolved_ref, sizeof(unresolved_ref), 0, &r)); 252 + T_CHECK(r.diag.len == 1); 253 + T_CHECK(r.diag.items[0].level == TOBI_DIAG_WARN); 254 + T_STR(r.diag.items[0].msg, "unresolved AML namespace reference"); 255 + tobi_parse_result_free(&r); 256 + T_CHECK(!tobi_parse(unresolved_ref, sizeof(unresolved_ref), 1, &r)); 257 + T_CHECK(tobi_diag_has_error(&r.diag)); 258 + tobi_parse_result_free(&r); 259 + 260 + uint8_t alias_cycle[] = { 261 + 0x06,'A','L','B','0','A','L','A','0', 262 + 0x06,'A','L','A','0','A','L','B','0' 263 + }; 264 + T_CHECK(tobi_parse(alias_cycle, sizeof(alias_cycle), 0, &r)); 265 + T_CHECK(r.diag.len >= 1); 266 + T_STR(r.diag.items[0].msg, "alias cycle"); 267 + tobi_parse_result_free(&r); 249 268 return 0; 250 269 }