ACPI AML decompiler w/ CFG recovery and structured pseudocode
1#include "t.h"
2
3#include "cf.h"
4#include "dc.h"
5#include "js.h"
6#include "p.h"
7
8static void set_len(uint8_t *b, size_t n) {
9 uint32_t v = (uint32_t)n;
10 b[4] = (uint8_t)(v & 0xffu);
11 b[5] = (uint8_t)((v >> 8) & 0xffu);
12 b[6] = (uint8_t)((v >> 16) & 0xffu);
13 b[7] = (uint8_t)((v >> 24) & 0xffu);
14}
15
16static void fix_sum(uint8_t *b, size_t n) {
17 unsigned sum = 0;
18 b[9] = 0;
19 for (size_t i = 0; i < n; i++) {
20 sum = (sum + b[i]) & 0xffu;
21 }
22 b[9] = (uint8_t)((256u - sum) & 0xffu);
23}
24
25int t_prod(void) {
26 uint8_t m0[] = {0x14,0x0c,'M','T','H','0',0x01,0x70,0x0a,0x2a,0x60,0xa4,0x60};
27 uint8_t table[36 + sizeof(m0) + 4];
28 memset(table, 0, sizeof(table));
29 memcpy(table, "DSDT", 4);
30 set_len(table, 36 + sizeof(m0));
31 memcpy(table + 36, m0, sizeof(m0));
32 table[36 + sizeof(m0)] = 0xfe;
33 table[36 + sizeof(m0) + 1] = 0xfe;
34 fix_sum(table, 36 + sizeof(m0));
35 tobi_parse_result r;
36 T_CHECK(tobi_parse(table, sizeof(table), 1, &r));
37 T_CHECK(r.meta.is_table);
38 T_CHECK(r.meta.table_len == 36 + sizeof(m0));
39 T_CHECK(r.meta.aml_len == sizeof(m0));
40 T_CHECK(r.root->child_len == 1);
41 T_CHECK(!tobi_diag_has_error(&r.diag));
42 tobi_parse_result_free(&r);
43
44 table[9] ^= 0x5au;
45 T_CHECK(tobi_parse(table, sizeof(table), 0, &r));
46 T_CHECK(!tobi_diag_has_error(&r.diag));
47 T_CHECK(!r.meta.checksum_valid);
48 T_CHECK(r.diag.len == 1);
49 tobi_parse_result_free(&r);
50
51 uint8_t m1[] = {0x14,0x15,'I','F','E','0',0x01,0xa0,0x06,0x68,0x70,0x0a,0x01,0x60,0xa1,0x05,0x70,0x0a,0x02,0x60,0xa4,0x60};
52 T_CHECK(tobi_parse(m1, sizeof(m1), 0, &r));
53 T_CHECK(tobi_cf_recover(r.root, &r.diag));
54 char *a = tobi_dc_emit(r.root, &r.diag);
55 char *b = tobi_dc_emit(r.root, &r.diag);
56 T_CHECK(strcmp(a, b) == 0);
57 free(a);
58 free(b);
59 a = tobi_js_emit(&r);
60 b = tobi_js_emit(&r);
61 T_CHECK(strcmp(a, b) == 0);
62 T_CHECK(strstr(a, ",}") == NULL);
63 T_CHECK(strstr(a, ",]") == NULL);
64 free(a);
65 free(b);
66 a = tobi_cf_dot(r.root);
67 b = tobi_cf_dot(r.root);
68 T_CHECK(strcmp(a, b) == 0);
69 free(a);
70 free(b);
71 tobi_parse_result_free(&r);
72
73 uint8_t hostile[256];
74 for (size_t i = 0; i < sizeof(hostile); i++) {
75 hostile[i] = (uint8_t)i;
76 }
77 T_CHECK(tobi_parse(hostile, sizeof(hostile), 0, &r));
78 tobi_parse_result_free(&r);
79
80 uint8_t use_file[] = {0x14,0x0d,'U','S','E','X',0x00,0xa4,'C','A','L','X',0x0a,0x33};
81 uint8_t ext_file[] = {0x15,'C','A','L','X',0x08,0x01};
82 tobi_parse_input inputs[] = {
83 {use_file, sizeof(use_file), "usex.aml"},
84 {ext_file, sizeof(ext_file), "extern.aml"}
85 };
86 T_CHECK(tobi_parse_multi(inputs, 2, 0, &r));
87 T_CHECK(r.root->child_len == 2);
88 T_CHECK(r.root->child[0]->child_len == 1);
89 tobi_ir *ret = r.root->child[0]->child[0]->child[0]->child[0];
90 T_CHECK(ret->kind == TOBI_IR_RETURN);
91 T_CHECK(ret->child_len == 1);
92 T_CHECK(ret->child[0]->kind == TOBI_IR_CALL);
93 T_CHECK(ret->child[0]->child_len == 1);
94 const tobi_ns_ent *ext = tobi_ns_find_method(&r.ns, "CALX");
95 T_CHECK(ext != NULL && ext->external && ext->args == 1);
96 tobi_parse_result_free(&r);
97 return 0;
98}