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 / src / main.c
7.1 kB 220 lines
1#include "cf.h" 2#include "da.h" 3#include "dc.h" 4#include "js.h" 5#include "mem.h" 6#include "p.h" 7 8#include <errno.h> 9#include <stdio.h> 10#include <stdlib.h> 11#include <string.h> 12 13#define TOBI_VERSION "0.1.0" 14 15static void usage(FILE *f) { 16 fputs("usage: tobi [opts] <file> [file...]\n" 17 "\n" 18 "options:\n" 19 " --dis print opcode-level disassembly\n" 20 " --json print parsed ir as json\n" 21 " --dot print recovered control flow as Graphviz DOT\n" 22 " --raw print input/table metadata and aml offsets\n" 23 " --strict treat malformed or unsupported constructs as hard errors\n" 24 " --plain disable coloured diagnostics\n" 25 " --help print usage\n" 26 " --version print version\n", f); 27} 28 29static int read_file(const char *path, uint8_t **data, size_t *len) { 30 FILE *fp = fopen(path, "rb"); 31 if (!fp) { 32 fprintf(stderr, "tobi: %s: %s\n", path, strerror(errno)); 33 return 0; 34 } 35 if (fseek(fp, 0, SEEK_END) != 0) { 36 fclose(fp); 37 return 0; 38 } 39 long n = ftell(fp); 40 if (n < 0) { 41 fclose(fp); 42 return 0; 43 } 44 rewind(fp); 45 *data = tobi_xmalloc((size_t)n ? (size_t)n : 1); 46 *len = (size_t)n; 47 if (*len && fread(*data, 1, *len, fp) != *len) { 48 fclose(fp); 49 free(*data); 50 *data = NULL; 51 *len = 0; 52 return 0; 53 } 54 fclose(fp); 55 return 1; 56} 57 58static void print_diags(const tobi_diag_list *dl, int plain) { 59 (void)plain; 60 for (size_t i = 0; i < dl->len; i++) { 61 fprintf(stderr, "0x%zx: %s: %s\n", dl->items[i].off, 62 tobi_diag_level_name(dl->items[i].level), dl->items[i].msg); 63 } 64} 65 66int main(int argc, char **argv) { 67 int mode_dis = 0; 68 int mode_json = 0; 69 int mode_dot = 0; 70 int mode_raw = 0; 71 int strict = 0; 72 int plain = 0; 73 const char **files = NULL; 74 size_t file_len = 0; 75 size_t file_cap = 0; 76 for (int i = 1; i < argc; i++) { 77 if (strcmp(argv[i], "--help") == 0) { 78 usage(stdout); 79 return 0; 80 } 81 if (strcmp(argv[i], "--version") == 0) { 82 puts("tobi " TOBI_VERSION); 83 return 0; 84 } 85 if (strcmp(argv[i], "--dis") == 0) { 86 mode_dis = 1; 87 } else if (strcmp(argv[i], "--json") == 0) { 88 mode_json = 1; 89 } else if (strcmp(argv[i], "--dot") == 0) { 90 mode_dot = 1; 91 } else if (strcmp(argv[i], "--raw") == 0) { 92 mode_raw = 1; 93 } else if (strcmp(argv[i], "--strict") == 0) { 94 strict = 1; 95 } else if (strcmp(argv[i], "--plain") == 0) { 96 plain = 1; 97 } else if (argv[i][0] == '-') { 98 fprintf(stderr, "tobi: unknown option %s\n", argv[i]); 99 usage(stderr); 100 return 2; 101 } else { 102 if (file_len == file_cap) { 103 file_cap = file_cap ? file_cap * 2u : 4u; 104 files = tobi_xrealloc(files, file_cap * sizeof(files[0])); 105 } 106 files[file_len++] = argv[i]; 107 } 108 } 109 if (file_len == 0) { 110 usage(stderr); 111 free(files); 112 return 2; 113 } 114 if ((mode_dis + mode_json + mode_dot + mode_raw) > 1) { 115 fprintf(stderr, "tobi: choose only one output mode\n"); 116 free(files); 117 return 2; 118 } 119 uint8_t **data = tobi_xcalloc(file_len, sizeof(data[0])); 120 size_t *lens = tobi_xcalloc(file_len, sizeof(lens[0])); 121 for (size_t i = 0; i < file_len; i++) { 122 if (!read_file(files[i], &data[i], &lens[i])) { 123 for (size_t j = 0; j < file_len; j++) { 124 free(data[j]); 125 } 126 free(lens); 127 free(data); 128 free(files); 129 return 1; 130 } 131 } 132 if (mode_dis || mode_raw) { 133 int fail_any = 0; 134 for (size_t i = 0; i < file_len; i++) { 135 tobi_parse_result one; 136 int ok = tobi_parse(data[i], lens[i], strict, &one); 137 if (mode_raw) { 138 printf("input=%s\nformat=%s\nis_table=%s\ntable_length=%zu\naml_offset=%zu\naml_length=%zu\nchecksum_sum=0x%02x\nchecksum_valid=%s\nnamespace_objects=%zu\n", 139 files[i], one.meta.signature, one.meta.is_table ? "true" : "false", 140 one.meta.table_len, one.meta.aml_off, one.meta.aml_len, 141 (unsigned)one.meta.checksum_sum, one.meta.checksum_valid ? "true" : "false", 142 one.ns.len); 143 } else { 144 if (file_len > 1) { 145 printf("== %s ==\n", files[i]); 146 } 147 char *s = tobi_da_emit(data[i], lens[i], &one.meta); 148 fputs(s, stdout); 149 free(s); 150 } 151 print_diags(&one.diag, plain); 152 if ((strict && tobi_diag_has_error(&one.diag)) || !ok) { 153 fail_any = 1; 154 } 155 tobi_parse_result_free(&one); 156 } 157 for (size_t i = 0; i < file_len; i++) { 158 free(data[i]); 159 } 160 free(lens); 161 free(data); 162 free(files); 163 return fail_any ? 1 : 0; 164 } 165 tobi_parse_result res; 166 int ok = 0; 167 if (file_len == 1) { 168 ok = tobi_parse(data[0], lens[0], strict, &res); 169 } else { 170 tobi_parse_input *inputs = tobi_xcalloc(file_len, sizeof(inputs[0])); 171 for (size_t i = 0; i < file_len; i++) { 172 inputs[i].data = data[i]; 173 inputs[i].len = lens[i]; 174 inputs[i].name = files[i]; 175 } 176 ok = tobi_parse_multi(inputs, file_len, strict, &res); 177 free(inputs); 178 } 179 if (!res.root) { 180 print_diags(&res.diag, plain); 181 tobi_parse_result_free(&res); 182 for (size_t i = 0; i < file_len; i++) { 183 free(data[i]); 184 } 185 free(lens); 186 free(data); 187 free(files); 188 return 1; 189 } 190 (void)tobi_cf_recover(res.root, &res.diag); 191 if (mode_raw) { 192 printf("input=%s\nformat=%s\nis_table=%s\ntable_length=%zu\naml_offset=%zu\naml_length=%zu\nchecksum_sum=0x%02x\nchecksum_valid=%s\nnamespace_objects=%zu\n", 193 files[0], res.meta.signature, res.meta.is_table ? "true" : "false", 194 res.meta.table_len, res.meta.aml_off, res.meta.aml_len, 195 (unsigned)res.meta.checksum_sum, res.meta.checksum_valid ? "true" : "false", 196 res.ns.len); 197 } else if (mode_json) { 198 char *s = tobi_js_emit(&res); 199 fputs(s, stdout); 200 free(s); 201 } else if (mode_dot) { 202 char *s = tobi_cf_dot(res.root); 203 fputs(s, stdout); 204 free(s); 205 } else { 206 char *s = tobi_dc_emit(res.root, &res.diag); 207 fputs(s, stdout); 208 free(s); 209 } 210 print_diags(&res.diag, plain); 211 int fail = (strict && tobi_diag_has_error(&res.diag)) || !ok; 212 tobi_parse_result_free(&res); 213 for (size_t i = 0; i < file_len; i++) { 214 free(data[i]); 215 } 216 free(lens); 217 free(data); 218 free(files); 219 return fail ? 1 : 0; 220}