ACPI AML decompiler w/ CFG recovery and structured pseudocode
1#include "t.h"
2
3#include <sys/wait.h>
4
5#ifndef TOBI_BIN
6#define TOBI_BIN "./tobi"
7#endif
8#ifndef TOBI_SRC_DIR
9#define TOBI_SRC_DIR "."
10#endif
11
12static int write_blob(const char *path, const unsigned char *data, size_t len) {
13 FILE *fp = fopen(path, "wb");
14 if (!fp) {
15 return 0;
16 }
17 int ok = fwrite(data, 1, len, fp) == len;
18 return fclose(fp) == 0 && ok;
19}
20
21static char *run_capture(const char *args, int *status) {
22 char cmd[1024];
23 snprintf(cmd, sizeof(cmd), "%s %s 2>/dev/null", TOBI_BIN, args);
24 FILE *fp = popen(cmd, "r");
25 if (!fp) {
26 *status = 99;
27 return NULL;
28 }
29 size_t cap = 4096;
30 size_t len = 0;
31 char *buf = malloc(cap);
32 if (!buf) {
33 (void)pclose(fp);
34 *status = 99;
35 return NULL;
36 }
37 int c = 0;
38 while ((c = fgetc(fp)) != EOF) {
39 if (len + 1 == cap) {
40 cap *= 2;
41 char *nb = realloc(buf, cap);
42 if (!nb) {
43 free(buf);
44 (void)pclose(fp);
45 *status = 99;
46 return NULL;
47 }
48 buf = nb;
49 }
50 buf[len++] = (char)c;
51 }
52 buf[len] = '\0';
53 int rc = pclose(fp);
54 *status = WIFEXITED(rc) ? WEXITSTATUS(rc) : 99;
55 return buf;
56}
57
58int t_cli(void) {
59 int st = 0;
60 char path[512];
61 snprintf(path, sizeof(path), "%s/sam/m0.aml", TOBI_SRC_DIR);
62 char args[700];
63 snprintf(args, sizeof(args), "%s", path);
64 char *s = run_capture(args, &st);
65 T_CHECK(st == 0);
66 T_STR(s, "method MTH0");
67 T_STR(s, "return Local0");
68 free(s);
69 snprintf(args, sizeof(args), "--dis %s", path);
70 s = run_capture(args, &st);
71 T_CHECK(st == 0);
72 T_STR(s, "0x0000");
73 T_STR(s, "MethodOp");
74 free(s);
75 snprintf(args, sizeof(args), "--json %s", path);
76 s = run_capture(args, &st);
77 T_CHECK(st == 0);
78 T_STR(s, "\"ir\"");
79 T_STR(s, "\"kind\":\"method\"");
80 T_STR(s, path);
81 T_CHECK(strstr(s, "\"source\":\"raw\"") == NULL);
82 free(s);
83 snprintf(args, sizeof(args), "--dot %s", path);
84 s = run_capture(args, &st);
85 T_CHECK(st == 0);
86 T_STR(s, "digraph tobi_cfg");
87 T_STR(s, "method");
88 free(s);
89 {
90 unsigned char user_file[] = {
91 0x14,0x24,'L','L','0','0',0x01,
92 0x70,0x00,0x60,
93 0x70,0x0a,0x03,0x61,
94 0xa2,0x14,0x61,
95 0xa0,0x06,0x68,0x72,0x60,0x01,0x60,
96 0xa1,0x06,0x72,0x60,0x0a,0x02,0x60,
97 0x74,0x61,0x01,0x61,
98 0xa4,0x60
99 };
100 const char *user_path = "/tmp/tobi_cli_user_dot.aml";
101 T_CHECK(write_blob(user_path, user_file, sizeof(user_file)));
102 snprintf(args, sizeof(args), "--dot %s", user_path);
103 s = run_capture(args, &st);
104 T_CHECK(st == 0);
105 T_STR(s, "digraph tobi_cfg");
106 T_STR(s, "LL00");
107 T_STR(s, "while");
108 T_STR(s, "back");
109 free(s);
110 }
111 snprintf(args, sizeof(args), "--raw %s", path);
112 s = run_capture(args, &st);
113 T_CHECK(st == 0);
114 T_STR(s, "checksum_sum=0x00");
115 T_STR(s, "checksum_valid=false");
116 free(s);
117 {
118 unsigned char use_file[] = {0x14,0x0d,'U','S','E','0',0x00,0xa4,'C','A','L','0',0x0a,0x05};
119 unsigned char cal_file[] = {0x14,0x08,'C','A','L','0',0x01,0xa4,0x68};
120 const char *use_path = "/tmp/tobi_cli_use.aml";
121 const char *cal_path = "/tmp/tobi_cli_cal.aml";
122 T_CHECK(write_blob(use_path, use_file, sizeof(use_file)));
123 T_CHECK(write_blob(cal_path, cal_file, sizeof(cal_file)));
124 snprintf(args, sizeof(args), "%s %s", use_path, cal_path);
125 s = run_capture(args, &st);
126 T_CHECK(st == 0);
127 T_STR(s, "method USE0");
128 T_STR(s, "CAL0(0x5)");
129 free(s);
130 }
131 s = run_capture("--help", &st);
132 T_CHECK(st == 0);
133 T_STR(s, "usage: tobi");
134 free(s);
135 s = run_capture("--version", &st);
136 T_CHECK(st == 0);
137 T_STR(s, "tobi");
138 free(s);
139 snprintf(path, sizeof(path), "%s/sam/m0.aml", TOBI_SRC_DIR);
140 snprintf(args, sizeof(args), "--json --dis %s", path);
141 s = run_capture(args, &st);
142 T_CHECK(st == 2);
143 free(s);
144 s = run_capture("--definitely-not-real", &st);
145 T_CHECK(st == 2);
146 free(s);
147 snprintf(path, sizeof(path), "%s/sam/bad0.aml", TOBI_SRC_DIR);
148 snprintf(args, sizeof(args), "--strict %s", path);
149 s = run_capture(args, &st);
150 T_CHECK(st != 0);
151 free(s);
152 return 0;
153}