ACPI AML decompiler w/ CFG recovery and structured pseudocode
1#include "t.h"
2
3#include "cf.h"
4#include "da.h"
5#include "dc.h"
6#include "js.h"
7#include "p.h"
8
9#include <dirent.h>
10#include <errno.h>
11#include <sys/stat.h>
12
13#ifndef TOBI_SRC_DIR
14#define TOBI_SRC_DIR "."
15#endif
16
17static int read_blob(const char *path, uint8_t **data, size_t *len) {
18 FILE *fp = fopen(path, "rb");
19 if (!fp) {
20 fprintf(stderr, "open %s: %s\n", path, strerror(errno));
21 return 0;
22 }
23 if (fseek(fp, 0, SEEK_END) != 0) {
24 fclose(fp);
25 return 0;
26 }
27 long n = ftell(fp);
28 if (n < 0) {
29 fclose(fp);
30 return 0;
31 }
32 rewind(fp);
33 *len = (size_t)n;
34 *data = malloc(*len ? *len : 1u);
35 if (!*data) {
36 fclose(fp);
37 return 0;
38 }
39 if (*len && fread(*data, 1, *len, fp) != *len) {
40 free(*data);
41 fclose(fp);
42 return 0;
43 }
44 fclose(fp);
45 return 1;
46}
47
48static int stable_emit_blob(const char *label, const uint8_t *data, size_t len, int strict_should_pass) {
49 int ok = 0;
50 tobi_parse_result a;
51 tobi_parse_result b;
52 tobi_parse_result strict;
53 (void)tobi_parse(data, len, 0, &a);
54 (void)tobi_parse(data, len, 0, &b);
55 int strict_ok = tobi_parse(data, len, 1, &strict);
56 int expected_strict_ok = strict_should_pass && a.diag.len == 0;
57 (void)tobi_cf_recover(a.root, &a.diag);
58 (void)tobi_cf_recover(b.root, &b.diag);
59 char *aj = tobi_js_emit(&a);
60 char *bj = tobi_js_emit(&b);
61 char *ad = tobi_dc_emit(a.root, &a.diag);
62 char *bd = tobi_dc_emit(b.root, &b.diag);
63 char *aa = tobi_da_emit(data, len, &a.meta);
64 char *ba = tobi_da_emit(data, len, &b.meta);
65 ok = aj != NULL && bj != NULL && ad != NULL && bd != NULL && aa != NULL && ba != NULL &&
66 strcmp(aj, bj) == 0 && aj[0] == '{' && strstr(aj, "\"meta\"") != NULL &&
67 strstr(aj, "\"ir\"") != NULL && strstr(aj, ",}") == NULL && strstr(aj, ",]") == NULL &&
68 ad[0] != '\0' && aa[0] != '\0' && strcmp(ad, bd) == 0 && strcmp(aa, ba) == 0;
69 if (expected_strict_ok) {
70 ok = ok && strict_ok && !tobi_diag_has_error(&strict.diag);
71 } else {
72 ok = ok && (!strict_ok || tobi_diag_has_error(&strict.diag));
73 }
74 if (!ok) {
75 fprintf(stderr, "corpus regression failed for %s\n", label);
76 }
77 free(aa);
78 free(ba);
79 free(ad);
80 free(bd);
81 free(aj);
82 free(bj);
83 tobi_parse_result_free(&a);
84 tobi_parse_result_free(&b);
85 tobi_parse_result_free(&strict);
86 return ok ? 0 : 1;
87}
88
89static int stable_emit(const char *path, int strict_should_pass) {
90 uint8_t *data = NULL;
91 size_t len = 0;
92 int rc = 1;
93 if (!read_blob(path, &data, &len)) {
94 return 1;
95 }
96 rc = stable_emit_blob(path, data, len, strict_should_pass);
97 if (rc == 0 && len > 1) {
98 size_t cuts[] = {1u, len / 2u, len - 1u};
99 for (size_t i = 0; i < sizeof(cuts) / sizeof(cuts[0]); i++) {
100 if (cuts[i] == 0 || cuts[i] >= len) {
101 continue;
102 }
103 char label[900];
104 snprintf(label, sizeof(label), "%s truncated:%zu", path, cuts[i]);
105 if (stable_emit_blob(label, data, cuts[i], 0) != 0) {
106 rc = 1;
107 break;
108 }
109 }
110 }
111 free(data);
112 return rc;
113}
114
115static int walk_dir(const char *rel, size_t *count, size_t *bad_count) {
116 char dir_path[512];
117 snprintf(dir_path, sizeof(dir_path), "%s/%s", TOBI_SRC_DIR, rel);
118 DIR *dir = opendir(dir_path);
119 T_CHECK(dir != NULL);
120 struct dirent *de = NULL;
121 while ((de = readdir(dir)) != NULL) {
122 if (de->d_name[0] == '.') {
123 continue;
124 }
125 char path[768];
126 snprintf(path, sizeof(path), "%s/%s", dir_path, de->d_name);
127 struct stat st;
128 T_CHECK(stat(path, &st) == 0);
129 if (S_ISREG(st.st_mode)) {
130 int bad = strstr(de->d_name, "bad") != NULL;
131 T_CHECK(stable_emit(path, !bad) == 0);
132 (*count)++;
133 if (bad) {
134 (*bad_count)++;
135 }
136 }
137 }
138 T_CHECK(closedir(dir) == 0);
139 return 0;
140}
141
142int t_corpus(void) {
143 size_t count = 0;
144 size_t bad_count = 0;
145 T_CHECK(walk_dir("sam", &count, &bad_count) == 0);
146 T_CHECK(walk_dir("fuzz/seed", &count, &bad_count) == 0);
147 T_CHECK(count >= 9);
148 T_CHECK(bad_count >= 2);
149 return 0;
150}