ACPI AML decompiler w/ CFG recovery and structured pseudocode
29

Configure Feed

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

tobi / test / t_corpus.c
6.6 kB 216 lines
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#include <unistd.h> 13 14#ifndef TOBI_SRC_DIR 15#define TOBI_SRC_DIR "." 16#endif 17 18static int read_blob(const char *path, uint8_t **data, size_t *len) { 19 FILE *fp = fopen(path, "rb"); 20 if (!fp) { 21 fprintf(stderr, "open %s: %s\n", path, strerror(errno)); 22 return 0; 23 } 24 if (fseek(fp, 0, SEEK_END) != 0) { 25 fclose(fp); 26 return 0; 27 } 28 long n = ftell(fp); 29 if (n < 0) { 30 fclose(fp); 31 return 0; 32 } 33 rewind(fp); 34 *len = (size_t)n; 35 *data = malloc(*len ? *len : 1u); 36 if (!*data) { 37 fclose(fp); 38 return 0; 39 } 40 if (*len && fread(*data, 1, *len, fp) != *len) { 41 free(*data); 42 fclose(fp); 43 return 0; 44 } 45 fclose(fp); 46 return 1; 47} 48 49static int write_blob(const char *path, const uint8_t *data, size_t len) { 50 FILE *fp = fopen(path, "wb"); 51 if (!fp) { 52 fprintf(stderr, "open %s: %s\n", path, strerror(errno)); 53 return 0; 54 } 55 if (len && fwrite(data, 1, len, fp) != len) { 56 fclose(fp); 57 return 0; 58 } 59 return fclose(fp) == 0; 60} 61 62static int stable_emit_blob(const char *label, const uint8_t *data, size_t len, int strict_should_pass) { 63 int ok = 0; 64 tobi_parse_result a; 65 tobi_parse_result b; 66 tobi_parse_result strict; 67 (void)tobi_parse(data, len, 0, &a); 68 (void)tobi_parse(data, len, 0, &b); 69 int strict_ok = tobi_parse(data, len, 1, &strict); 70 int expected_strict_ok = strict_should_pass && a.diag.len == 0; 71 (void)tobi_cf_recover(a.root, &a.diag); 72 (void)tobi_cf_recover(b.root, &b.diag); 73 char *aj = tobi_js_emit(&a); 74 char *bj = tobi_js_emit(&b); 75 char *ad = tobi_dc_emit(a.root, &a.diag); 76 char *bd = tobi_dc_emit(b.root, &b.diag); 77 char *aa = tobi_da_emit(data, len, &a.meta); 78 char *ba = tobi_da_emit(data, len, &b.meta); 79 ok = aj != NULL && bj != NULL && ad != NULL && bd != NULL && aa != NULL && ba != NULL && 80 strcmp(aj, bj) == 0 && aj[0] == '{' && strstr(aj, "\"meta\"") != NULL && 81 strstr(aj, "\"ir\"") != NULL && strstr(aj, ",}") == NULL && strstr(aj, ",]") == NULL && 82 ad[0] != '\0' && aa[0] != '\0' && strcmp(ad, bd) == 0 && strcmp(aa, ba) == 0; 83 if (expected_strict_ok) { 84 ok = ok && strict_ok && !tobi_diag_has_error(&strict.diag); 85 } else { 86 ok = ok && (!strict_ok || tobi_diag_has_error(&strict.diag)); 87 } 88 if (!ok) { 89 fprintf(stderr, "corpus regression failed for %s\n", label); 90 } 91 free(aa); 92 free(ba); 93 free(ad); 94 free(bd); 95 free(aj); 96 free(bj); 97 tobi_parse_result_free(&a); 98 tobi_parse_result_free(&b); 99 tobi_parse_result_free(&strict); 100 return ok ? 0 : 1; 101} 102 103static int stable_emit(const char *path, int strict_should_pass) { 104 uint8_t *data = NULL; 105 size_t len = 0; 106 int rc = 1; 107 if (!read_blob(path, &data, &len)) { 108 return 1; 109 } 110 rc = stable_emit_blob(path, data, len, strict_should_pass); 111 if (rc == 0 && len > 1) { 112 size_t cuts[] = {1u, len / 2u, len - 1u}; 113 for (size_t i = 0; i < sizeof(cuts) / sizeof(cuts[0]); i++) { 114 if (cuts[i] == 0 || cuts[i] >= len) { 115 continue; 116 } 117 char label[900]; 118 snprintf(label, sizeof(label), "%s truncated:%zu", path, cuts[i]); 119 if (stable_emit_blob(label, data, cuts[i], 0) != 0) { 120 rc = 1; 121 break; 122 } 123 } 124 } 125 free(data); 126 return rc; 127} 128 129static int has_aml_suffix(const char *name) { 130 size_t len = strlen(name); 131 return len >= 4u && strcmp(name + len - 4u, ".aml") == 0; 132} 133 134static int walk_dir_path(const char *dir_path, size_t *count, size_t *bad_count) { 135 DIR *dir = opendir(dir_path); 136 T_CHECK(dir != NULL); 137 struct dirent *de = NULL; 138 while ((de = readdir(dir)) != NULL) { 139 if (de->d_name[0] == '.') { 140 continue; 141 } 142 char path[1024]; 143 int n = snprintf(path, sizeof(path), "%s/%s", dir_path, de->d_name); 144 T_CHECK(n > 0 && (size_t)n < sizeof(path)); 145 struct stat st; 146 T_CHECK(stat(path, &st) == 0); 147 if (S_ISDIR(st.st_mode)) { 148 T_CHECK(walk_dir_path(path, count, bad_count) == 0); 149 } else if (S_ISREG(st.st_mode) && has_aml_suffix(de->d_name)) { 150 int bad = strstr(de->d_name, "bad") != NULL; 151 T_CHECK(stable_emit(path, !bad) == 0); 152 (*count)++; 153 if (bad) { 154 (*bad_count)++; 155 } 156 } 157 } 158 T_CHECK(closedir(dir) == 0); 159 return 0; 160} 161 162static int walk_dir(const char *rel, size_t *count, size_t *bad_count) { 163 char dir_path[512]; 164 int n = snprintf(dir_path, sizeof(dir_path), "%s/%s", TOBI_SRC_DIR, rel); 165 T_CHECK(n > 0 && (size_t)n < sizeof(dir_path)); 166 return walk_dir_path(dir_path, count, bad_count); 167} 168 169static int walk_optional_external_dir(size_t *count, size_t *bad_count) { 170 const char *dir = getenv("TOBI_AML_CORPUS"); 171 if (!dir || !dir[0]) { 172 dir = getenv("TOBI_CORPUS"); 173 } 174 if (!dir || !dir[0]) { 175 return 0; 176 } 177 size_t before = *count; 178 T_CHECK(walk_dir_path(dir, count, bad_count) == 0); 179 T_CHECK(*count > before); 180 return 0; 181} 182 183static int exercise_external_discovery(void) { 184 char dir[] = "/tmp/tobi-corpus-XXXXXX"; 185 T_CHECK(mkdtemp(dir) != NULL); 186 char nested[256]; 187 int n = snprintf(nested, sizeof(nested), "%s/nested", dir); 188 T_CHECK(n > 0 && (size_t)n < sizeof(nested)); 189 T_CHECK(mkdir(nested, 0700) == 0); 190 char path[256]; 191 n = snprintf(path, sizeof(path), "%s/m0.aml", nested); 192 T_CHECK(n > 0 && (size_t)n < sizeof(path)); 193 uint8_t m0[] = {0x14,0x0c,'M','T','H','0',0x01,0x70,0x0a,0x2a,0x60,0xa4,0x60}; 194 T_CHECK(write_blob(path, m0, sizeof(m0))); 195 size_t count = 0; 196 size_t bad_count = 0; 197 T_CHECK(walk_dir_path(dir, &count, &bad_count) == 0); 198 T_CHECK(count == 1); 199 T_CHECK(bad_count == 0); 200 T_CHECK(unlink(path) == 0); 201 T_CHECK(rmdir(nested) == 0); 202 T_CHECK(rmdir(dir) == 0); 203 return 0; 204} 205 206int t_corpus(void) { 207 size_t count = 0; 208 size_t bad_count = 0; 209 T_CHECK(exercise_external_discovery() == 0); 210 T_CHECK(walk_dir("sam", &count, &bad_count) == 0); 211 T_CHECK(walk_dir("fuzz/seed", &count, &bad_count) == 0); 212 T_CHECK(walk_optional_external_dir(&count, &bad_count) == 0); 213 T_CHECK(count >= 9); 214 T_CHECK(bad_count >= 2); 215 return 0; 216}