ACPI AML decompiler w/ CFG recovery and structured pseudocode
29

Configure Feed

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

Add deterministic corpus regression runner across parse decompile disassemble and JSON

+154 -3
+2 -2
CMakeLists.txt
··· 41 41 add_executable(tobi_test 42 42 test/main.c test/t_rd.c test/t_nm.c test/t_p.c test/t_ir.c 43 43 test/t_cf.c test/t_da.c test/t_dc.c test/t_js.c test/t_bad.c test/t_cli.c 44 - test/t_prod.c) 44 + test/t_prod.c test/t_corpus.c) 45 45 target_link_libraries(tobi_test PRIVATE tobilib) 46 46 target_compile_options(tobi_test PRIVATE ${TOBI_WARN}) 47 47 target_compile_definitions(tobi_test PRIVATE ··· 52 52 target_link_options(tobi_test PRIVATE ${SAN_FLAGS}) 53 53 endif() 54 54 55 - foreach(t rd nm p ir cf da dc js bad cli prod) 55 + foreach(t rd nm p ir cf da dc js bad cli prod corpus) 56 56 add_test(NAME ${t} COMMAND tobi_test ${t}) 57 57 endforeach() 58 58
+1 -1
test/main.c
··· 4 4 struct ent { const char *name; int (*fn)(void); } tests[] = { 5 5 {"rd", t_rd}, {"nm", t_nm}, {"p", t_p}, {"ir", t_ir}, {"cf", t_cf}, 6 6 {"da", t_da}, {"dc", t_dc}, {"js", t_js}, {"bad", t_bad}, {"cli", t_cli}, 7 - {"prod", t_prod}, 7 + {"prod", t_prod}, {"corpus", t_corpus}, 8 8 }; 9 9 if (argc == 2) { 10 10 for (size_t i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) {
+1
test/t.h
··· 19 19 int t_bad(void); 20 20 int t_cli(void); 21 21 int t_prod(void); 22 + int t_corpus(void); 22 23 23 24 #endif
+150
test/t_corpus.c
··· 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 + 17 + static 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 + 48 + static 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 + 89 + static 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 + 115 + static 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 + 142 + int 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 + }