ACPI AML decompiler w/ CFG recovery and structured pseudocode
29

Configure Feed

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

Model AML method locals args stores and conservative intra method dataflow

+211 -1
+193 -1
src/p.c
··· 1619 1619 } 1620 1620 } 1621 1621 1622 - static void semantic_validate(parser *p, const tobi_ir *root) { 1622 + typedef struct method_state { 1623 + parser *p; 1624 + tobi_ir *method; 1625 + uint16_t locals; 1626 + uint16_t local_reads; 1627 + uint16_t local_writes; 1628 + uint16_t arg_reads; 1629 + uint16_t arg_writes; 1630 + unsigned warnings; 1631 + } method_state; 1632 + 1633 + static int ref_index(const tobi_ir *n, const char *prefix, unsigned max, unsigned *idx) { 1634 + size_t plen = strlen(prefix); 1635 + if (!n || n->kind != TOBI_IR_REF || !n->name || strncmp(n->name, prefix, plen) != 0) { 1636 + return 0; 1637 + } 1638 + char c = n->name[plen]; 1639 + if (n->name[plen + 1u] != '\0' || c < '0' || c > (char)('0' + max)) { 1640 + return 0; 1641 + } 1642 + *idx = (unsigned)(c - '0'); 1643 + return 1; 1644 + } 1645 + 1646 + static void method_mark_ref(method_state *st, tobi_ir *n, int write_target) { 1647 + unsigned idx = 0; 1648 + if (ref_index(n, "Local", 7, &idx)) { 1649 + if (write_target) { 1650 + st->locals |= (uint16_t)(1u << idx); 1651 + st->local_writes |= (uint16_t)(1u << idx); 1652 + tobi_ir_set_str(n, "method_symbol=local write=initialised"); 1653 + } else if ((st->locals & (uint16_t)(1u << idx)) == 0) { 1654 + st->local_reads |= (uint16_t)(1u << idx); 1655 + st->warnings++; 1656 + sem_diag(st->p, n->off, "Local%u may be read before being initialised in method %s", 1657 + idx, st->method->path ? st->method->path : st->method->name); 1658 + tobi_ir_set_str(n, "method_symbol=local read=uninitialised"); 1659 + } else { 1660 + st->local_reads |= (uint16_t)(1u << idx); 1661 + tobi_ir_set_str(n, "method_symbol=local read=initialised"); 1662 + } 1663 + } else if (ref_index(n, "Arg", 6, &idx)) { 1664 + if (write_target) { 1665 + st->arg_writes |= (uint16_t)(1u << idx); 1666 + } else { 1667 + st->arg_reads |= (uint16_t)(1u << idx); 1668 + } 1669 + if (idx >= st->method->method_args) { 1670 + st->warnings++; 1671 + sem_diag(st->p, n->off, "Arg%u %s exceeds declared argument count %u in method %s", 1672 + idx, write_target ? "write" : "read", 1673 + st->method->method_args, st->method->path ? st->method->path : st->method->name); 1674 + tobi_ir_set_str(n, write_target ? "method_symbol=arg write=out_of_range" : 1675 + "method_symbol=arg read=out_of_range"); 1676 + } else if (write_target) { 1677 + tobi_ir_set_str(n, "method_symbol=arg write=declared"); 1678 + } else { 1679 + tobi_ir_set_str(n, "method_symbol=arg read=declared"); 1680 + } 1681 + } 1682 + } 1683 + 1684 + static void method_symbols_node(method_state *st, tobi_ir *n); 1685 + 1686 + static void method_symbols_block(method_state *st, tobi_ir *b) { 1687 + if (!b) { 1688 + return; 1689 + } 1690 + for (size_t i = 0; i < b->child_len; i++) { 1691 + method_symbols_node(st, b->child[i]); 1692 + } 1693 + } 1694 + 1695 + static void method_symbols_node(method_state *st, tobi_ir *n) { 1696 + if (!n) { 1697 + return; 1698 + } 1699 + if (n->kind == TOBI_IR_STORE) { 1700 + if (n->child_len > 0) { 1701 + method_symbols_node(st, n->child[0]); 1702 + } 1703 + if (n->child_len > 1) { 1704 + unsigned idx = 0; 1705 + if (ref_index(n->child[1], "Local", 7, &idx) || ref_index(n->child[1], "Arg", 6, &idx)) { 1706 + method_mark_ref(st, n->child[1], 1); 1707 + } else { 1708 + method_symbols_node(st, n->child[1]); 1709 + } 1710 + } 1711 + return; 1712 + } 1713 + if (n->kind == TOBI_IR_REF) { 1714 + method_mark_ref(st, n, 0); 1715 + return; 1716 + } 1717 + if (n->kind == TOBI_IR_EXPR && n->name) { 1718 + size_t target_start = n->child_len; 1719 + if (strcmp(n->name, "div") == 0 && n->child_len >= 4) { 1720 + target_start = 2; 1721 + } else if ((strcmp(n->name, "add") == 0 || strcmp(n->name, "concat") == 0 || 1722 + strcmp(n->name, "sub") == 0 || strcmp(n->name, "mul") == 0 || 1723 + strcmp(n->name, "shl") == 0 || strcmp(n->name, "shr") == 0 || 1724 + strcmp(n->name, "and") == 0 || strcmp(n->name, "nand") == 0 || 1725 + strcmp(n->name, "or") == 0 || strcmp(n->name, "nor") == 0 || 1726 + strcmp(n->name, "xor") == 0 || strcmp(n->name, "not") == 0 || 1727 + strcmp(n->name, "find_set_left_bit") == 0 || 1728 + strcmp(n->name, "find_set_right_bit") == 0 || 1729 + strcmp(n->name, "concat_res") == 0 || strcmp(n->name, "mod") == 0 || 1730 + strcmp(n->name, "index") == 0 || strcmp(n->name, "to_buffer") == 0 || 1731 + strcmp(n->name, "to_decimal_string") == 0 || 1732 + strcmp(n->name, "to_hex_string") == 0 || strcmp(n->name, "to_integer") == 0 || 1733 + strcmp(n->name, "to_string") == 0 || strcmp(n->name, "copy_object") == 0 || 1734 + strcmp(n->name, "mid") == 0) && n->child_len >= 3) { 1735 + target_start = n->child_len - 1u; 1736 + } 1737 + for (size_t i = 0; i < target_start; i++) { 1738 + method_symbols_node(st, n->child[i]); 1739 + } 1740 + for (size_t i = target_start; i < n->child_len; i++) { 1741 + unsigned idx = 0; 1742 + if (ref_index(n->child[i], "Local", 7, &idx) || ref_index(n->child[i], "Arg", 6, &idx)) { 1743 + method_mark_ref(st, n->child[i], 1); 1744 + } else { 1745 + method_symbols_node(st, n->child[i]); 1746 + } 1747 + } 1748 + return; 1749 + } 1750 + if (n->kind == TOBI_IR_IF) { 1751 + if (n->child_len > 0) { 1752 + method_symbols_node(st, n->child[0]); 1753 + } 1754 + uint16_t base = st->locals; 1755 + uint16_t then_locals = base; 1756 + uint16_t else_locals = base; 1757 + if (n->child_len > 1) { 1758 + st->locals = base; 1759 + method_symbols_block(st, n->child[1]); 1760 + then_locals = st->locals; 1761 + } 1762 + if (n->child_len > 2) { 1763 + st->locals = base; 1764 + method_symbols_block(st, n->child[2]); 1765 + else_locals = st->locals; 1766 + st->locals = then_locals & else_locals; 1767 + } else { 1768 + st->locals = base; 1769 + } 1770 + return; 1771 + } 1772 + if (n->kind == TOBI_IR_WHILE) { 1773 + if (n->child_len > 0) { 1774 + method_symbols_node(st, n->child[0]); 1775 + } 1776 + uint16_t base = st->locals; 1777 + if (n->child_len > 1) { 1778 + st->locals = base; 1779 + method_symbols_block(st, n->child[1]); 1780 + } 1781 + st->locals = base; 1782 + return; 1783 + } 1784 + for (size_t i = 0; i < n->child_len; i++) { 1785 + method_symbols_node(st, n->child[i]); 1786 + } 1787 + } 1788 + 1789 + static void semantic_methods(parser *p, tobi_ir *n) { 1790 + if (!n) { 1791 + return; 1792 + } 1793 + if (n->kind == TOBI_IR_METHOD) { 1794 + method_state st; 1795 + memset(&st, 0, sizeof(st)); 1796 + st.p = p; 1797 + st.method = n; 1798 + if (n->child_len > 0) { 1799 + method_symbols_block(&st, n->child[0]); 1800 + } 1801 + char summary[160]; 1802 + (void)snprintf(summary, sizeof(summary), 1803 + "method_symbols args=%u local_reads=0x%x local_writes=0x%x final_locals=0x%x arg_reads=0x%x arg_writes=0x%x warnings=%u", 1804 + n->method_args, st.local_reads, st.local_writes, st.locals, 1805 + st.arg_reads, st.arg_writes, st.warnings); 1806 + tobi_ir_set_target(n, summary); 1807 + } 1808 + for (size_t i = 0; i < n->child_len; i++) { 1809 + semantic_methods(p, n->child[i]); 1810 + } 1811 + } 1812 + 1813 + static void semantic_validate(parser *p, tobi_ir *root) { 1623 1814 for (size_t i = 0; i < p->ns->len; i++) { 1624 1815 const tobi_ns_ent *e = &p->ns->items[i]; 1625 1816 if (e->external && e->kind == TOBI_NS_METHOD) { ··· 1634 1825 } 1635 1826 } 1636 1827 semantic_walk(p, root, NULL); 1828 + semantic_methods(p, root); 1637 1829 } 1638 1830 1639 1831 int tobi_parse(const uint8_t *data, size_t len, int strict, tobi_parse_result *out) {
+18
test/t_p.c
··· 286 286 T_CHECK(r.diag.len >= 1); 287 287 T_STR(r.diag.items[0].msg, "alias cycle"); 288 288 tobi_parse_result_free(&r); 289 + 290 + uint8_t symbols[] = { 291 + 0x14,0x0a,'S','Y','M','0',0x01, 292 + 0xa4,0x60,0xa4,0x69 293 + }; 294 + T_CHECK(tobi_parse(symbols, sizeof(symbols), 0, &r)); 295 + T_CHECK(r.diag.len >= 2); 296 + T_STR(r.diag.items[0].msg, "Local0 may be read before"); 297 + T_STR(r.diag.items[1].msg, "Arg1 read exceeds declared argument count"); 298 + T_STR(r.root->child[0]->target, "method_symbols"); 299 + T_STR(r.root->child[0]->target, "local_reads=0x1"); 300 + T_STR(r.root->child[0]->target, "arg_reads=0x2"); 301 + T_STR(r.root->child[0]->target, "warnings=2"); 302 + tobi_ir *sym_ret = r.root->child[0]->child[0]->child[0]; 303 + T_CHECK(sym_ret->kind == TOBI_IR_RETURN); 304 + T_STR(sym_ret->child[0]->str, "uninitialised"); 305 + T_STR(r.root->child[0]->child[0]->child[1]->child[0]->str, "out_of_range"); 306 + tobi_parse_result_free(&r); 289 307 return 0; 290 308 }