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.4 kB 232 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 66static void set_source(tobi_input_meta *meta, const char *path) { 67 if (!path) { 68 return; 69 } 70 (void)snprintf(meta->source, sizeof(meta->source), "%s", path); 71} 72 73static void print_raw_meta(const char *input, const tobi_parse_result *res) { 74 printf("input=%s\nsource=%s\nformat=%s\nis_table=%s\ntable_length=%zu\naml_offset=%zu\naml_length=%zu\nrevision=%u\nchecksum_byte=0x%02x\nchecksum_sum=0x%02x\nchecksum_valid=%s\noem_id=%s\noem_table_id=%s\noem_revision=%u\ncreator_id=%s\ncreator_revision=%u\nheader_hash=0x%08x\naml_hash=0x%08x\nnamespace_objects=%zu\n", 75 input, res->meta.source, res->meta.signature, res->meta.is_table ? "true" : "false", 76 res->meta.table_len, res->meta.aml_off, res->meta.aml_len, 77 (unsigned)res->meta.revision, (unsigned)res->meta.checksum_byte, 78 (unsigned)res->meta.checksum_sum, res->meta.checksum_valid ? "true" : "false", 79 res->meta.oem_id, res->meta.oem_table_id, res->meta.oem_revision, 80 res->meta.creator_id, res->meta.creator_revision, res->meta.header_hash, 81 res->meta.aml_hash, res->ns.len); 82} 83 84int main(int argc, char **argv) { 85 int mode_dis = 0; 86 int mode_json = 0; 87 int mode_dot = 0; 88 int mode_raw = 0; 89 int strict = 0; 90 int plain = 0; 91 const char **files = NULL; 92 size_t file_len = 0; 93 size_t file_cap = 0; 94 for (int i = 1; i < argc; i++) { 95 if (strcmp(argv[i], "--help") == 0) { 96 usage(stdout); 97 return 0; 98 } 99 if (strcmp(argv[i], "--version") == 0) { 100 puts("tobi " TOBI_VERSION); 101 return 0; 102 } 103 if (strcmp(argv[i], "--dis") == 0) { 104 mode_dis = 1; 105 } else if (strcmp(argv[i], "--json") == 0) { 106 mode_json = 1; 107 } else if (strcmp(argv[i], "--dot") == 0) { 108 mode_dot = 1; 109 } else if (strcmp(argv[i], "--raw") == 0) { 110 mode_raw = 1; 111 } else if (strcmp(argv[i], "--strict") == 0) { 112 strict = 1; 113 } else if (strcmp(argv[i], "--plain") == 0) { 114 plain = 1; 115 } else if (argv[i][0] == '-') { 116 fprintf(stderr, "tobi: unknown option %s\n", argv[i]); 117 usage(stderr); 118 return 2; 119 } else { 120 if (file_len == file_cap) { 121 file_cap = file_cap ? file_cap * 2u : 4u; 122 files = tobi_xrealloc(files, file_cap * sizeof(files[0])); 123 } 124 files[file_len++] = argv[i]; 125 } 126 } 127 if (file_len == 0) { 128 usage(stderr); 129 free(files); 130 return 2; 131 } 132 if ((mode_dis + mode_json + mode_dot + mode_raw) > 1) { 133 fprintf(stderr, "tobi: choose only one output mode\n"); 134 free(files); 135 return 2; 136 } 137 uint8_t **data = tobi_xcalloc(file_len, sizeof(data[0])); 138 size_t *lens = tobi_xcalloc(file_len, sizeof(lens[0])); 139 for (size_t i = 0; i < file_len; i++) { 140 if (!read_file(files[i], &data[i], &lens[i])) { 141 for (size_t j = 0; j < file_len; j++) { 142 free(data[j]); 143 } 144 free(lens); 145 free(data); 146 free(files); 147 return 1; 148 } 149 } 150 if (mode_dis || mode_raw) { 151 int fail_any = 0; 152 for (size_t i = 0; i < file_len; i++) { 153 tobi_parse_result one; 154 int ok = tobi_parse(data[i], lens[i], strict, &one); 155 set_source(&one.meta, files[i]); 156 if (mode_raw) { 157 print_raw_meta(files[i], &one); 158 } else { 159 if (file_len > 1) { 160 printf("== %s ==\n", files[i]); 161 } 162 char *s = tobi_da_emit(data[i], lens[i], &one.meta); 163 fputs(s, stdout); 164 free(s); 165 } 166 print_diags(&one.diag, plain); 167 if ((strict && tobi_diag_has_error(&one.diag)) || !ok) { 168 fail_any = 1; 169 } 170 tobi_parse_result_free(&one); 171 } 172 for (size_t i = 0; i < file_len; i++) { 173 free(data[i]); 174 } 175 free(lens); 176 free(data); 177 free(files); 178 return fail_any ? 1 : 0; 179 } 180 tobi_parse_result res; 181 int ok = 0; 182 if (file_len == 1) { 183 ok = tobi_parse(data[0], lens[0], strict, &res); 184 set_source(&res.meta, files[0]); 185 } else { 186 tobi_parse_input *inputs = tobi_xcalloc(file_len, sizeof(inputs[0])); 187 for (size_t i = 0; i < file_len; i++) { 188 inputs[i].data = data[i]; 189 inputs[i].len = lens[i]; 190 inputs[i].name = files[i]; 191 } 192 ok = tobi_parse_multi(inputs, file_len, strict, &res); 193 free(inputs); 194 } 195 if (!res.root) { 196 print_diags(&res.diag, plain); 197 tobi_parse_result_free(&res); 198 for (size_t i = 0; i < file_len; i++) { 199 free(data[i]); 200 } 201 free(lens); 202 free(data); 203 free(files); 204 return 1; 205 } 206 (void)tobi_cf_recover(res.root, &res.diag); 207 if (mode_raw) { 208 print_raw_meta(files[0], &res); 209 } else if (mode_json) { 210 char *s = tobi_js_emit(&res); 211 fputs(s, stdout); 212 free(s); 213 } else if (mode_dot) { 214 char *s = tobi_cf_dot(res.root); 215 fputs(s, stdout); 216 free(s); 217 } else { 218 char *s = tobi_dc_emit(res.root, &res.diag); 219 fputs(s, stdout); 220 free(s); 221 } 222 print_diags(&res.diag, plain); 223 int fail = (strict && tobi_diag_has_error(&res.diag)) || !ok; 224 tobi_parse_result_free(&res); 225 for (size_t i = 0; i < file_len; i++) { 226 free(data[i]); 227 } 228 free(lens); 229 free(data); 230 free(files); 231 return fail ? 1 : 0; 232}