Ben Vanik | 0635b09 | 2023-03-28 13:03:38 -0700 | [diff] [blame] | 1 | // Copyright 2023 The IREE Authors |
| 2 | // |
| 3 | // Licensed under the Apache License v2.0 with LLVM Exceptions. |
| 4 | // See https://llvm.org/LICENSE.txt for license information. |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| 6 | |
| 7 | #include <stdio.h> |
| 8 | |
| 9 | #include "iree/base/api.h" |
| 10 | #include "iree/base/internal/file_io.h" |
| 11 | #include "iree/base/internal/path.h" |
| 12 | #include "iree/hal/local/elf/fatelf.h" |
| 13 | |
| 14 | // NOTE: we don't verify ELF information in here and just pass it along. Don't |
| 15 | // run this on untrusted ELFs. |
| 16 | |
| 17 | // NOTE: errors are handled in here just enough to get error messages - we don't |
| 18 | // care about leaks on failure as the process is going to die right away. |
| 19 | |
| 20 | // TODO(benvanik): make this based on the archs used? It needs to be the common |
| 21 | // page size across all targets used within the file. |
| 22 | #define IREE_FATELF_PAGE_SIZE 4096 |
| 23 | |
| 24 | #if defined(IREE_PLATFORM_WINDOWS) |
| 25 | #include <fcntl.h> |
| 26 | #include <io.h> |
| 27 | #define IREE_SET_BINARY_MODE(handle) _setmode(_fileno(handle), O_BINARY) |
| 28 | #else |
| 29 | #define IREE_SET_BINARY_MODE(handle) ((void)0) |
| 30 | #endif // IREE_PLATFORM_WINDOWS |
| 31 | |
| 32 | static int print_usage() { |
| 33 | fprintf(stderr, "Syntax: iree-fatelf [join|split|select|dump] files...\n"); |
| 34 | fprintf(stderr, "\n"); |
| 35 | fprintf(stderr, "Join multiple ELFs into a FatELF:\n"); |
| 36 | fprintf(stderr, " iree-fatelf join elf_a.so elf_b.so > fatelf.sos\n"); |
| 37 | fprintf(stderr, "\n"); |
| 38 | fprintf(stderr, "Split a FatELF into multiple ELF files (to dir):\n"); |
| 39 | fprintf(stderr, " iree-fatelf split fatelf.sos\n"); |
| 40 | fprintf(stderr, "\n"); |
| 41 | fprintf(stderr, "Select a FatELF matching the current arch:\n"); |
| 42 | fprintf(stderr, " iree-fatelf select fatelf.sos > elf.so\n"); |
| 43 | fprintf(stderr, "\n"); |
| 44 | fprintf(stderr, "Dump header records:\n"); |
| 45 | fprintf(stderr, " iree-fatelf dump fatelf.sos\n"); |
| 46 | fprintf(stderr, "\n"); |
| 47 | return 1; |
| 48 | } |
| 49 | |
| 50 | // NOTE: this is somewhat redundant with fatelf.c but that's ok - this is a |
| 51 | // developer tool and I'd rather have the implementation linked into every |
| 52 | // runtime be kept as simple as possible than not repeating 100 lines of code. |
| 53 | // The runtime version is also designed to gracefully accept ELF files where |
| 54 | // here we only want FatELF files. |
| 55 | static iree_status_t fatelf_parse(iree_const_byte_span_t file_data, |
| 56 | iree_fatelf_header_t** out_header) { |
| 57 | *out_header = NULL; |
| 58 | |
| 59 | if (file_data.data_length < |
| 60 | sizeof(iree_fatelf_header_t) + sizeof(iree_fatelf_record_t)) { |
| 61 | return iree_make_status( |
| 62 | IREE_STATUS_INVALID_ARGUMENT, |
| 63 | "file does not have enough data to even hold a FatELF header"); |
| 64 | } |
| 65 | |
| 66 | const iree_fatelf_header_t* raw_header = |
| 67 | (const iree_fatelf_header_t*)file_data.data; |
| 68 | iree_fatelf_header_t host_header = { |
| 69 | .magic = iree_unaligned_load_le_u32(&raw_header->magic), |
| 70 | .version = iree_unaligned_load_le_u16(&raw_header->version), |
| 71 | .record_count = iree_unaligned_load_le_u8(&raw_header->record_count), |
| 72 | .reserved = iree_unaligned_load_le_u8(&raw_header->reserved), |
| 73 | }; |
| 74 | |
| 75 | if (host_header.magic != IREE_FATELF_MAGIC) { |
| 76 | return iree_make_status( |
| 77 | IREE_STATUS_INVALID_ARGUMENT, |
| 78 | "file magic %08X does not match expected FatELF magic %08X", |
| 79 | host_header.magic, IREE_FATELF_MAGIC); |
| 80 | } |
| 81 | if (host_header.version != IREE_FATELF_FORMAT_VERSION) { |
| 82 | return iree_make_status( |
| 83 | IREE_STATUS_UNIMPLEMENTED, |
| 84 | "FatELF has version %d but runtime only supports version %d", |
| 85 | host_header.version, IREE_FATELF_FORMAT_VERSION); |
| 86 | } |
| 87 | |
| 88 | iree_host_size_t required_bytes = |
| 89 | sizeof(iree_fatelf_header_t) + |
| 90 | host_header.record_count * sizeof(iree_fatelf_record_t); |
| 91 | if (file_data.data_length < required_bytes) { |
| 92 | return iree_make_status(IREE_STATUS_INVALID_ARGUMENT, |
| 93 | "FatELF file truncated, requires at least %" PRIhsz |
| 94 | "B for headers but only have %" PRIhsz |
| 95 | "B available", |
| 96 | required_bytes, file_data.data_length); |
| 97 | } |
| 98 | |
| 99 | // Allocate storage for the parsed header and records. |
| 100 | iree_fatelf_header_t* header = NULL; |
| 101 | IREE_RETURN_IF_ERROR(iree_allocator_malloc( |
| 102 | iree_allocator_system(), |
| 103 | sizeof(iree_fatelf_header_t) + |
| 104 | host_header.record_count * sizeof(iree_fatelf_record_t), |
| 105 | (void**)&header)); |
| 106 | memcpy(header, &host_header, sizeof(*header)); |
| 107 | for (iree_elf64_byte_t i = 0; i < host_header.record_count; ++i) { |
| 108 | const iree_fatelf_record_t* raw_record = &raw_header->records[i]; |
| 109 | const iree_fatelf_record_t host_record = { |
| 110 | .machine = iree_unaligned_load_le_u16(&raw_record->machine), |
| 111 | .osabi = iree_unaligned_load_le_u8(&raw_record->osabi), |
| 112 | .osabi_version = iree_unaligned_load_le_u8(&raw_record->osabi_version), |
| 113 | .word_size = iree_unaligned_load_le_u8(&raw_record->word_size), |
| 114 | .byte_order = iree_unaligned_load_le_u8(&raw_record->byte_order), |
| 115 | .reserved0 = iree_unaligned_load_le_u8(&raw_record->reserved0), |
| 116 | .reserved1 = iree_unaligned_load_le_u8(&raw_record->reserved1), |
| 117 | .offset = iree_unaligned_load_le_u64(&raw_record->offset), |
| 118 | .size = iree_unaligned_load_le_u64(&raw_record->size), |
| 119 | }; |
| 120 | memcpy(&header->records[i], &host_record, sizeof(host_record)); |
| 121 | } |
| 122 | |
| 123 | *out_header = header; |
| 124 | return iree_ok_status(); |
| 125 | } |
| 126 | |
| 127 | // Tries to parse basic ELF metadata from |elf_data|. |
| 128 | // Very little verification done. Note that this must support both 32 and 64-bit |
| 129 | // ELF files regardless of the tool host configuration. |
| 130 | // The returned fields match the ELF spec and may differ from FatELF. |
| 131 | static iree_status_t fatelf_parse_elf_metadata( |
| 132 | iree_const_byte_span_t elf_data, iree_elf64_half_t* out_machine, |
| 133 | iree_elf64_byte_t* out_osabi, iree_elf64_byte_t* out_osabi_version, |
| 134 | iree_elf64_byte_t* out_elf_class, iree_elf64_byte_t* out_elf_data) { |
| 135 | *out_machine = 0; |
| 136 | *out_osabi = 0; |
| 137 | *out_osabi_version = 0; |
| 138 | *out_elf_data = 0; |
| 139 | *out_elf_class = 0; |
| 140 | |
| 141 | if (elf_data.data_length < sizeof(iree_elf32_ehdr_t)) { |
Scott Todd | 60b0764 | 2023-06-15 09:41:01 -0700 | [diff] [blame] | 142 | return iree_make_status(IREE_STATUS_FAILED_PRECONDITION, |
| 143 | "ELF data provided (%" PRIhsz |
| 144 | ") is smaller than ehdr (%zu)", |
| 145 | elf_data.data_length, sizeof(iree_elf32_ehdr_t)); |
Ben Vanik | 0635b09 | 2023-03-28 13:03:38 -0700 | [diff] [blame] | 146 | } |
| 147 | |
| 148 | // The fields we're checking are the same in both 32 and 64 classes so we just |
| 149 | // use 32 for consistency. |
| 150 | const iree_elf32_ehdr_t* ehdr = (const iree_elf32_ehdr_t*)elf_data.data; |
| 151 | static const iree_elf_byte_t elf_magic[4] = {0x7F, 'E', 'L', 'F'}; |
| 152 | if (memcmp(ehdr->e_ident, elf_magic, sizeof(elf_magic)) != 0) { |
| 153 | return iree_make_status( |
| 154 | IREE_STATUS_FAILED_PRECONDITION, |
| 155 | "data provided does not contain the ELF identifier"); |
| 156 | } |
| 157 | |
| 158 | *out_osabi = ehdr->e_ident[IREE_ELF_EI_OSABI]; |
| 159 | *out_osabi_version = ehdr->e_ident[IREE_ELF_EI_ABIVERSION]; |
| 160 | *out_elf_class = ehdr->e_ident[IREE_ELF_EI_CLASS]; |
| 161 | *out_elf_data = ehdr->e_ident[IREE_ELF_EI_DATA]; |
| 162 | |
| 163 | // Note machine is multibyte and respects the declared endianness. |
| 164 | if (ehdr->e_ident[IREE_ELF_EI_DATA] == IREE_ELF_ELFDATA2LSB) { |
| 165 | *out_machine = iree_unaligned_load_le_u16(&ehdr->e_machine); |
| 166 | } else { |
| 167 | #if IREE_ENDIANNESS_BIG |
| 168 | // TODO(benvanik): helpers for big<->little endian |
| 169 | // *out_machine = iree_unaligned_load_be_u16(&ehdr->e_machine); |
| 170 | #error "ELF parsing support only available on little-endian systems today" |
| 171 | #endif // IREE_ENDIANNESS_BIG |
| 172 | } |
| 173 | |
| 174 | return iree_ok_status(); |
| 175 | } |
| 176 | |
| 177 | typedef struct { |
| 178 | uint64_t offset; |
| 179 | iree_file_contents_t* contents; |
| 180 | iree_const_byte_span_t elf_data; |
| 181 | } fatelf_entry_t; |
| 182 | |
| 183 | // Joins one or more ELF files together and writes the output to stdout. |
| 184 | static iree_status_t fatelf_join(int argc, char** argv) { |
| 185 | IREE_SET_BINARY_MODE(stdout); // ensure binary output mode |
| 186 | |
| 187 | #if IREE_ENDIANNESS_BIG |
| 188 | #error "FatELF writing support only available on little-endian systems today" |
| 189 | #endif // IREE_ENDIANNESS_BIG |
| 190 | |
| 191 | // Load all source files. |
| 192 | iree_elf64_byte_t entry_count = argc; |
| 193 | fatelf_entry_t* entries = |
| 194 | (fatelf_entry_t*)iree_alloca(entry_count * sizeof(fatelf_entry_t)); |
| 195 | memset(entries, 0, entry_count * sizeof(*entries)); |
| 196 | for (iree_elf64_byte_t i = 0; i < entry_count; ++i) { |
Ben Vanik | 9d15f36 | 2023-08-03 10:18:58 -0700 | [diff] [blame] | 197 | IREE_RETURN_IF_ERROR( |
| 198 | iree_file_read_contents(argv[i], IREE_FILE_READ_FLAG_DEFAULT, |
| 199 | iree_allocator_system(), &entries[i].contents)); |
Ben Vanik | 0635b09 | 2023-03-28 13:03:38 -0700 | [diff] [blame] | 200 | entries[i].elf_data = entries[i].contents->const_buffer; |
| 201 | } |
| 202 | |
| 203 | // Compute offsets of all files based on their size and padding. |
| 204 | uint64_t file_offset = iree_host_align( |
| 205 | sizeof(iree_fatelf_header_t) + entry_count * sizeof(iree_fatelf_record_t), |
| 206 | IREE_FATELF_PAGE_SIZE); |
| 207 | for (iree_elf64_byte_t i = 0; i < entry_count; ++i) { |
| 208 | entries[i].offset = file_offset; |
| 209 | file_offset += iree_host_align( |
| 210 | entries[i].contents->const_buffer.data_length, IREE_FATELF_PAGE_SIZE); |
| 211 | } |
| 212 | |
| 213 | // Write header without records. |
| 214 | iree_fatelf_header_t host_header = { |
| 215 | .magic = IREE_FATELF_MAGIC, |
| 216 | .version = IREE_FATELF_FORMAT_VERSION, |
| 217 | .record_count = entry_count, |
| 218 | .reserved = 0, |
| 219 | }; |
| 220 | fwrite(&host_header, 1, sizeof(host_header), stdout); |
| 221 | |
| 222 | // Write all records. |
| 223 | for (iree_elf64_byte_t i = 0; i < entry_count; ++i) { |
| 224 | iree_elf64_half_t machine = 0; |
| 225 | iree_elf64_byte_t osabi = 0; |
| 226 | iree_elf64_byte_t osabi_version = 0; |
| 227 | iree_elf64_byte_t elf_class = 0; |
| 228 | iree_elf64_byte_t elf_data = 0; |
| 229 | IREE_RETURN_IF_ERROR( |
| 230 | fatelf_parse_elf_metadata(entries[i].elf_data, &machine, &osabi, |
| 231 | &osabi_version, &elf_class, &elf_data)); |
| 232 | iree_fatelf_record_t host_record = { |
| 233 | .machine = machine, |
| 234 | .osabi = osabi, |
| 235 | .osabi_version = osabi_version, |
| 236 | .word_size = elf_class == IREE_ELF_ELFCLASS32 |
| 237 | ? IREE_FATELF_WORD_SIZE_32 |
| 238 | : IREE_FATELF_WORD_SIZE_64, |
| 239 | .byte_order = elf_data == IREE_ELF_ELFDATA2LSB |
| 240 | ? IREE_FATELF_BYTE_ORDER_LSB |
| 241 | : IREE_FATELF_BYTE_ORDER_MSB, |
| 242 | .reserved0 = 0, |
| 243 | .reserved1 = 0, |
| 244 | .offset = (iree_elf64_off_t)entries[i].offset, |
| 245 | .size = (iree_elf64_xword_t)entries[i].elf_data.data_length, |
| 246 | }; |
| 247 | fwrite(&host_record, 1, sizeof(host_record), stdout); |
| 248 | } |
| 249 | |
| 250 | // Write all files, padding with zeros in-between as needed. |
| 251 | uint64_t write_offset = |
| 252 | sizeof(iree_fatelf_header_t) + entry_count * sizeof(iree_fatelf_record_t); |
| 253 | for (iree_elf64_byte_t i = 0; i < entry_count; ++i) { |
| 254 | uint64_t padding = entries[i].offset - write_offset; |
| 255 | for (uint64_t i = 0; i < padding; ++i) fputc(0, stdout); |
| 256 | write_offset += padding; |
| 257 | if (write_offset != entries[i].offset) { |
| 258 | return iree_make_status(IREE_STATUS_INTERNAL, |
| 259 | "actual offset does not match expected"); |
| 260 | } |
| 261 | fwrite(entries[i].elf_data.data, 1, entries[i].elf_data.data_length, |
| 262 | stdout); |
| 263 | write_offset += entries[i].elf_data.data_length; |
| 264 | } |
| 265 | fflush(stdout); |
| 266 | |
| 267 | for (iree_elf64_byte_t i = 0; i < entry_count; ++i) { |
| 268 | iree_file_contents_free(entries[i].contents); |
| 269 | } |
| 270 | return iree_ok_status(); |
| 271 | } |
| 272 | |
| 273 | static const char* fatelf_machine_id_str(iree_elf64_half_t value) { |
| 274 | // TODO(benvanik): include a full table from the spec? |
| 275 | // http://formats.kaitai.io/elf/ has a good source of canonical short names. |
| 276 | // For now we just support what we have in our ELF loader. |
| 277 | switch (value) { |
| 278 | case 0x03: // EM_386 / 3 |
| 279 | return "x86"; |
| 280 | case 0x28: // EM_ARM / 40 |
| 281 | return "arm"; |
| 282 | case 0xB7: // EM_AARCH64 / 183 |
| 283 | return "aarch64"; |
| 284 | case 0xF3: // EM_RISCV / 243 |
| 285 | return "risvc"; |
| 286 | case 0x3E: // EM_X86_64 / 62 |
| 287 | return "x86_64"; |
| 288 | default: |
| 289 | return "unknown"; |
| 290 | } |
| 291 | } |
| 292 | |
| 293 | static const char* fatelf_osabi_id_str(iree_elf64_byte_t value) { |
| 294 | switch (value) { |
| 295 | case IREE_ELF_ELFOSABI_NONE: |
| 296 | return "none"; |
| 297 | case IREE_ELF_ELFOSABI_LINUX: |
| 298 | return "linux"; |
| 299 | case IREE_ELF_ELFOSABI_STANDALONE: |
| 300 | return "standalone"; |
| 301 | default: |
| 302 | return "unknown"; |
| 303 | } |
| 304 | } |
| 305 | |
| 306 | static const char* fatelf_word_size_id_str(iree_elf64_byte_t value) { |
| 307 | switch (value) { |
| 308 | case IREE_FATELF_WORD_SIZE_32: |
| 309 | return "lp32"; |
| 310 | case IREE_FATELF_WORD_SIZE_64: |
| 311 | return "lp64"; |
| 312 | default: |
| 313 | return "lpUNK"; |
| 314 | } |
| 315 | } |
| 316 | |
| 317 | static const char* fatelf_byte_order_id_str(iree_elf64_byte_t value) { |
| 318 | switch (value) { |
| 319 | case IREE_FATELF_BYTE_ORDER_MSB: |
| 320 | return "be"; |
| 321 | case IREE_FATELF_BYTE_ORDER_LSB: |
| 322 | return "le"; |
| 323 | default: |
| 324 | return "xx"; |
| 325 | } |
| 326 | } |
| 327 | |
| 328 | // Splits a FatELF into multiple files, writing each beside the input file. |
| 329 | static iree_status_t fatelf_split(int argc, char** argv) { |
| 330 | iree_file_contents_t* fatelf_contents = NULL; |
Ben Vanik | 9d15f36 | 2023-08-03 10:18:58 -0700 | [diff] [blame] | 331 | IREE_RETURN_IF_ERROR( |
| 332 | iree_file_read_contents(argv[0], IREE_FILE_READ_FLAG_DEFAULT, |
| 333 | iree_allocator_system(), &fatelf_contents)); |
Ben Vanik | 0635b09 | 2023-03-28 13:03:38 -0700 | [diff] [blame] | 334 | iree_fatelf_header_t* header = NULL; |
| 335 | IREE_RETURN_IF_ERROR(fatelf_parse(fatelf_contents->const_buffer, &header)); |
| 336 | |
| 337 | iree_string_view_t dirname, basename; |
| 338 | iree_file_path_split(iree_make_cstring_view(argv[0]), &dirname, &basename); |
| 339 | iree_string_view_t stem, extension; |
| 340 | iree_file_path_split_basename(basename, &stem, &extension); |
| 341 | |
| 342 | for (iree_elf64_byte_t i = 0; i < header->record_count; ++i) { |
| 343 | const iree_fatelf_record_t* record = &header->records[i]; |
| 344 | |
| 345 | const char* machine_str = fatelf_machine_id_str(record->machine); |
| 346 | const char* osabi_str = fatelf_osabi_id_str(record->osabi); |
| 347 | const char* word_size_str = fatelf_word_size_id_str(record->word_size); |
| 348 | const char* byte_order_str = fatelf_byte_order_id_str(record->byte_order); |
| 349 | |
| 350 | char record_path[2048]; |
| 351 | iree_host_size_t record_path_length = |
| 352 | snprintf(record_path, IREE_ARRAYSIZE(record_path), |
| 353 | "%.*s%s%.*s.%s_%s_%s%s.so", (int)dirname.size, dirname.data, |
| 354 | dirname.size ? "/" : "", (int)stem.size, stem.data, |
| 355 | machine_str, osabi_str, word_size_str, byte_order_str); |
| 356 | record_path_length = |
| 357 | iree_file_path_canonicalize(record_path, record_path_length); |
| 358 | |
| 359 | fprintf(stdout, "Writing record[%d] to '%.*s'...\n", i, |
| 360 | (int)record_path_length, record_path); |
| 361 | |
| 362 | iree_const_byte_span_t record_data = iree_make_const_byte_span( |
| 363 | fatelf_contents->const_buffer.data + record->offset, record->size); |
| 364 | IREE_RETURN_IF_ERROR(iree_file_write_contents(record_path, record_data)); |
| 365 | } |
| 366 | |
| 367 | fprintf(stdout, "Wrote %d records to %.*s!\n", header->record_count, |
| 368 | (int)dirname.size, dirname.data); |
| 369 | iree_allocator_free(iree_allocator_system(), header); |
| 370 | iree_file_contents_free(fatelf_contents); |
| 371 | return iree_ok_status(); |
| 372 | } |
| 373 | |
| 374 | // Selects the ELF matching the current host config from a FatELF and writes |
| 375 | // it to stdout. |
| 376 | static iree_status_t fatelf_select(int argc, char** argv) { |
| 377 | IREE_SET_BINARY_MODE(stdout); // ensure binary output mode |
| 378 | iree_file_contents_t* fatelf_contents = NULL; |
Ben Vanik | 9d15f36 | 2023-08-03 10:18:58 -0700 | [diff] [blame] | 379 | IREE_RETURN_IF_ERROR( |
| 380 | iree_file_read_contents(argv[0], IREE_FILE_READ_FLAG_DEFAULT, |
| 381 | iree_allocator_system(), &fatelf_contents)); |
Ben Vanik | 0635b09 | 2023-03-28 13:03:38 -0700 | [diff] [blame] | 382 | iree_const_byte_span_t elf_data = iree_const_byte_span_empty(); |
| 383 | IREE_RETURN_IF_ERROR( |
| 384 | iree_fatelf_select(fatelf_contents->const_buffer, &elf_data)); |
| 385 | fwrite(elf_data.data, 1, elf_data.data_length, stdout); |
| 386 | iree_file_contents_free(fatelf_contents); |
| 387 | return iree_ok_status(); |
| 388 | } |
| 389 | |
| 390 | static const char* fatelf_word_size_enum_str(iree_elf64_byte_t value) { |
| 391 | switch (value) { |
| 392 | case IREE_FATELF_WORD_SIZE_32: |
| 393 | return "ELFCLASS32"; |
| 394 | case IREE_FATELF_WORD_SIZE_64: |
| 395 | return "ELFCLASS64"; |
| 396 | default: |
| 397 | return "<unknown>"; |
| 398 | } |
| 399 | } |
| 400 | |
| 401 | static const char* fatelf_byte_order_enum_str(iree_elf64_byte_t value) { |
| 402 | switch (value) { |
| 403 | case IREE_FATELF_BYTE_ORDER_MSB: |
| 404 | return "ELFDATA2MSB (big-endian)"; |
| 405 | case IREE_FATELF_BYTE_ORDER_LSB: |
| 406 | return "ELFDATA2LSB (little-endian)"; |
| 407 | default: |
| 408 | return "<unknown>"; |
| 409 | } |
| 410 | } |
| 411 | |
| 412 | // Dumps the FatELF file records. |
| 413 | static iree_status_t fatelf_dump(int argc, char** argv) { |
| 414 | iree_file_contents_t* fatelf_contents = NULL; |
Ben Vanik | 9d15f36 | 2023-08-03 10:18:58 -0700 | [diff] [blame] | 415 | IREE_RETURN_IF_ERROR( |
| 416 | iree_file_read_contents(argv[0], IREE_FILE_READ_FLAG_DEFAULT, |
| 417 | iree_allocator_system(), &fatelf_contents)); |
Ben Vanik | 0635b09 | 2023-03-28 13:03:38 -0700 | [diff] [blame] | 418 | iree_fatelf_header_t* header = NULL; |
| 419 | IREE_RETURN_IF_ERROR(fatelf_parse(fatelf_contents->const_buffer, &header)); |
| 420 | |
| 421 | fprintf(stdout, "iree_fatelf_header_t:\n"); |
| 422 | fprintf(stdout, " magic: %" PRIX32 "\n", header->magic); |
| 423 | fprintf(stdout, " version: %d\n", header->version); |
| 424 | fprintf(stdout, " records: %d\n", header->record_count); |
| 425 | fprintf(stdout, " reserved: %" PRIX8 "\n", header->reserved); |
| 426 | fprintf(stdout, "\n"); |
| 427 | |
| 428 | for (iree_elf64_byte_t i = 0; i < header->record_count; ++i) { |
| 429 | const iree_fatelf_record_t* record = &header->records[i]; |
| 430 | fprintf(stdout, "iree_fatelf_record_t[%d]:\n", i); |
| 431 | fprintf(stdout, " machine: %d / %04X = %s\n", record->machine, |
| 432 | record->machine, fatelf_machine_id_str(record->machine)); |
| 433 | fprintf(stdout, " osabi: %d / %02X = %s\n", record->osabi, |
| 434 | record->osabi, fatelf_osabi_id_str(record->osabi)); |
| 435 | fprintf(stdout, " version: %d / %02X\n", record->osabi_version, |
| 436 | record->osabi_version); |
| 437 | fprintf(stdout, " word_size: %d / %02X = %s\n", record->word_size, |
| 438 | record->word_size, fatelf_word_size_enum_str(record->word_size)); |
| 439 | fprintf(stdout, " byte_order: %d / %02X = %s\n", record->byte_order, |
| 440 | record->byte_order, fatelf_byte_order_enum_str(record->byte_order)); |
| 441 | fprintf(stdout, " reserved0: %d / %02X\n", record->reserved0, |
| 442 | record->reserved0); |
| 443 | fprintf(stdout, " reserved1: %d / %02X\n", record->reserved1, |
| 444 | record->reserved1); |
| 445 | fprintf(stdout, " offset: %" PRIu64 " / %016" PRIX64 "\n", |
| 446 | record->offset, record->offset); |
| 447 | fprintf(stdout, " size: %" PRIu64 " / %016" PRIX64 "\n", record->size, |
| 448 | record->size); |
| 449 | fprintf(stdout, "\n"); |
| 450 | } |
| 451 | |
| 452 | iree_allocator_free(iree_allocator_system(), header); |
| 453 | iree_file_contents_free(fatelf_contents); |
| 454 | return iree_ok_status(); |
| 455 | } |
| 456 | |
| 457 | int main(int argc, char** argv) { |
| 458 | if (argc < 2) { |
| 459 | return print_usage(); |
| 460 | } |
| 461 | |
| 462 | char* command = argv[1]; |
| 463 | int command_argc = argc - 2; |
| 464 | char** command_argv = argv + 2; |
| 465 | |
| 466 | iree_status_t status = iree_ok_status(); |
| 467 | if (strcmp(command, "join") == 0) { |
| 468 | if (command_argc < 1) return print_usage(); |
| 469 | status = fatelf_join(command_argc, command_argv); |
| 470 | } else if (strcmp(command, "split") == 0) { |
| 471 | if (command_argc != 1) return print_usage(); |
| 472 | status = fatelf_split(command_argc, command_argv); |
| 473 | } else if (strcmp(command, "select") == 0) { |
| 474 | if (command_argc != 1) return print_usage(); |
| 475 | status = fatelf_select(command_argc, command_argv); |
| 476 | } else if (strcmp(command, "dump") == 0) { |
| 477 | if (command_argc != 1) return print_usage(); |
| 478 | status = fatelf_dump(command_argc, command_argv); |
| 479 | } else { |
| 480 | return print_usage(); |
| 481 | } |
| 482 | |
| 483 | if (!iree_status_is_ok(status)) { |
| 484 | fprintf(stderr, "iree-fatelf encountered error:\n"); |
| 485 | iree_status_fprint(stderr, status); |
| 486 | iree_status_free(status); |
| 487 | return 1; |
| 488 | } |
| 489 | return 0; |
| 490 | } |