Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
michael@0 | 1 | /* |
michael@0 | 2 | * Copyright (c) 2010 The WebM project authors. All Rights Reserved. |
michael@0 | 3 | * |
michael@0 | 4 | * Use of this source code is governed by a BSD-style license |
michael@0 | 5 | * that can be found in the LICENSE file in the root of the source |
michael@0 | 6 | * tree. An additional intellectual property rights grant can be found |
michael@0 | 7 | * in the file PATENTS. All contributing project authors may |
michael@0 | 8 | * be found in the AUTHORS file in the root of the source tree. |
michael@0 | 9 | */ |
michael@0 | 10 | |
michael@0 | 11 | |
michael@0 | 12 | #include <stdarg.h> |
michael@0 | 13 | #include <stdio.h> |
michael@0 | 14 | #include <stdlib.h> |
michael@0 | 15 | #include <string.h> |
michael@0 | 16 | |
michael@0 | 17 | #include "vpx_config.h" |
michael@0 | 18 | #include "vpx/vpx_integer.h" |
michael@0 | 19 | |
michael@0 | 20 | typedef enum { |
michael@0 | 21 | OUTPUT_FMT_PLAIN, |
michael@0 | 22 | OUTPUT_FMT_RVDS, |
michael@0 | 23 | OUTPUT_FMT_GAS, |
michael@0 | 24 | } output_fmt_t; |
michael@0 | 25 | |
michael@0 | 26 | int log_msg(const char *fmt, ...) { |
michael@0 | 27 | int res; |
michael@0 | 28 | va_list ap; |
michael@0 | 29 | va_start(ap, fmt); |
michael@0 | 30 | res = vfprintf(stderr, fmt, ap); |
michael@0 | 31 | va_end(ap); |
michael@0 | 32 | return res; |
michael@0 | 33 | } |
michael@0 | 34 | |
michael@0 | 35 | #if defined(__GNUC__) && __GNUC__ |
michael@0 | 36 | #if defined(__MACH__) |
michael@0 | 37 | |
michael@0 | 38 | #include <mach-o/loader.h> |
michael@0 | 39 | #include <mach-o/nlist.h> |
michael@0 | 40 | |
michael@0 | 41 | int print_macho_equ(output_fmt_t mode, uint8_t* name, int val) { |
michael@0 | 42 | switch (mode) { |
michael@0 | 43 | case OUTPUT_FMT_RVDS: |
michael@0 | 44 | printf("%-40s EQU %5d\n", name, val); |
michael@0 | 45 | return 0; |
michael@0 | 46 | case OUTPUT_FMT_GAS: |
michael@0 | 47 | printf(".set %-40s, %5d\n", name, val); |
michael@0 | 48 | return 0; |
michael@0 | 49 | default: |
michael@0 | 50 | log_msg("Unsupported mode: %d", mode); |
michael@0 | 51 | return 1; |
michael@0 | 52 | } |
michael@0 | 53 | } |
michael@0 | 54 | |
michael@0 | 55 | int parse_macho(uint8_t *base_buf, size_t sz, output_fmt_t mode) { |
michael@0 | 56 | int i, j; |
michael@0 | 57 | struct mach_header header; |
michael@0 | 58 | uint8_t *buf = base_buf; |
michael@0 | 59 | int base_data_section = 0; |
michael@0 | 60 | int bits = 0; |
michael@0 | 61 | |
michael@0 | 62 | /* We can read in mach_header for 32 and 64 bit architectures |
michael@0 | 63 | * because it's identical to mach_header_64 except for the last |
michael@0 | 64 | * element (uint32_t reserved), which we don't use. Then, when |
michael@0 | 65 | * we know which architecture we're looking at, increment buf |
michael@0 | 66 | * appropriately. |
michael@0 | 67 | */ |
michael@0 | 68 | memcpy(&header, buf, sizeof(struct mach_header)); |
michael@0 | 69 | |
michael@0 | 70 | if (header.magic == MH_MAGIC) { |
michael@0 | 71 | if (header.cputype == CPU_TYPE_ARM |
michael@0 | 72 | || header.cputype == CPU_TYPE_X86) { |
michael@0 | 73 | bits = 32; |
michael@0 | 74 | buf += sizeof(struct mach_header); |
michael@0 | 75 | } else { |
michael@0 | 76 | log_msg("Bad cputype for object file. Currently only tested for CPU_TYPE_[ARM|X86].\n"); |
michael@0 | 77 | goto bail; |
michael@0 | 78 | } |
michael@0 | 79 | } else if (header.magic == MH_MAGIC_64) { |
michael@0 | 80 | if (header.cputype == CPU_TYPE_X86_64) { |
michael@0 | 81 | bits = 64; |
michael@0 | 82 | buf += sizeof(struct mach_header_64); |
michael@0 | 83 | } else { |
michael@0 | 84 | log_msg("Bad cputype for object file. Currently only tested for CPU_TYPE_X86_64.\n"); |
michael@0 | 85 | goto bail; |
michael@0 | 86 | } |
michael@0 | 87 | } else { |
michael@0 | 88 | log_msg("Bad magic number for object file. 0x%x or 0x%x expected, 0x%x found.\n", |
michael@0 | 89 | MH_MAGIC, MH_MAGIC_64, header.magic); |
michael@0 | 90 | goto bail; |
michael@0 | 91 | } |
michael@0 | 92 | |
michael@0 | 93 | if (header.filetype != MH_OBJECT) { |
michael@0 | 94 | log_msg("Bad filetype for object file. Currently only tested for MH_OBJECT.\n"); |
michael@0 | 95 | goto bail; |
michael@0 | 96 | } |
michael@0 | 97 | |
michael@0 | 98 | for (i = 0; i < header.ncmds; i++) { |
michael@0 | 99 | struct load_command lc; |
michael@0 | 100 | |
michael@0 | 101 | memcpy(&lc, buf, sizeof(struct load_command)); |
michael@0 | 102 | |
michael@0 | 103 | if (lc.cmd == LC_SEGMENT) { |
michael@0 | 104 | uint8_t *seg_buf = buf; |
michael@0 | 105 | struct section s; |
michael@0 | 106 | struct segment_command seg_c; |
michael@0 | 107 | |
michael@0 | 108 | memcpy(&seg_c, seg_buf, sizeof(struct segment_command)); |
michael@0 | 109 | seg_buf += sizeof(struct segment_command); |
michael@0 | 110 | |
michael@0 | 111 | /* Although each section is given it's own offset, nlist.n_value |
michael@0 | 112 | * references the offset of the first section. This isn't |
michael@0 | 113 | * apparent without debug information because the offset of the |
michael@0 | 114 | * data section is the same as the first section. However, with |
michael@0 | 115 | * debug sections mixed in, the offset of the debug section |
michael@0 | 116 | * increases but n_value still references the first section. |
michael@0 | 117 | */ |
michael@0 | 118 | if (seg_c.nsects < 1) { |
michael@0 | 119 | log_msg("Not enough sections\n"); |
michael@0 | 120 | goto bail; |
michael@0 | 121 | } |
michael@0 | 122 | |
michael@0 | 123 | memcpy(&s, seg_buf, sizeof(struct section)); |
michael@0 | 124 | base_data_section = s.offset; |
michael@0 | 125 | } else if (lc.cmd == LC_SEGMENT_64) { |
michael@0 | 126 | uint8_t *seg_buf = buf; |
michael@0 | 127 | struct section_64 s; |
michael@0 | 128 | struct segment_command_64 seg_c; |
michael@0 | 129 | |
michael@0 | 130 | memcpy(&seg_c, seg_buf, sizeof(struct segment_command_64)); |
michael@0 | 131 | seg_buf += sizeof(struct segment_command_64); |
michael@0 | 132 | |
michael@0 | 133 | /* Explanation in LG_SEGMENT */ |
michael@0 | 134 | if (seg_c.nsects < 1) { |
michael@0 | 135 | log_msg("Not enough sections\n"); |
michael@0 | 136 | goto bail; |
michael@0 | 137 | } |
michael@0 | 138 | |
michael@0 | 139 | memcpy(&s, seg_buf, sizeof(struct section_64)); |
michael@0 | 140 | base_data_section = s.offset; |
michael@0 | 141 | } else if (lc.cmd == LC_SYMTAB) { |
michael@0 | 142 | if (base_data_section != 0) { |
michael@0 | 143 | struct symtab_command sc; |
michael@0 | 144 | uint8_t *sym_buf = base_buf; |
michael@0 | 145 | uint8_t *str_buf = base_buf; |
michael@0 | 146 | |
michael@0 | 147 | memcpy(&sc, buf, sizeof(struct symtab_command)); |
michael@0 | 148 | |
michael@0 | 149 | if (sc.cmdsize != sizeof(struct symtab_command)) { |
michael@0 | 150 | log_msg("Can't find symbol table!\n"); |
michael@0 | 151 | goto bail; |
michael@0 | 152 | } |
michael@0 | 153 | |
michael@0 | 154 | sym_buf += sc.symoff; |
michael@0 | 155 | str_buf += sc.stroff; |
michael@0 | 156 | |
michael@0 | 157 | for (j = 0; j < sc.nsyms; j++) { |
michael@0 | 158 | /* Location of string is cacluated each time from the |
michael@0 | 159 | * start of the string buffer. On darwin the symbols |
michael@0 | 160 | * are prefixed by "_", so we bump the pointer by 1. |
michael@0 | 161 | * The target value is defined as an int in *_asm_*_offsets.c, |
michael@0 | 162 | * which is 4 bytes on all targets we currently use. |
michael@0 | 163 | */ |
michael@0 | 164 | if (bits == 32) { |
michael@0 | 165 | struct nlist nl; |
michael@0 | 166 | int val; |
michael@0 | 167 | |
michael@0 | 168 | memcpy(&nl, sym_buf, sizeof(struct nlist)); |
michael@0 | 169 | sym_buf += sizeof(struct nlist); |
michael@0 | 170 | |
michael@0 | 171 | memcpy(&val, base_buf + base_data_section + nl.n_value, |
michael@0 | 172 | sizeof(val)); |
michael@0 | 173 | print_macho_equ(mode, str_buf + nl.n_un.n_strx + 1, val); |
michael@0 | 174 | } else { /* if (bits == 64) */ |
michael@0 | 175 | struct nlist_64 nl; |
michael@0 | 176 | int val; |
michael@0 | 177 | |
michael@0 | 178 | memcpy(&nl, sym_buf, sizeof(struct nlist_64)); |
michael@0 | 179 | sym_buf += sizeof(struct nlist_64); |
michael@0 | 180 | |
michael@0 | 181 | memcpy(&val, base_buf + base_data_section + nl.n_value, |
michael@0 | 182 | sizeof(val)); |
michael@0 | 183 | print_macho_equ(mode, str_buf + nl.n_un.n_strx + 1, val); |
michael@0 | 184 | } |
michael@0 | 185 | } |
michael@0 | 186 | } |
michael@0 | 187 | } |
michael@0 | 188 | |
michael@0 | 189 | buf += lc.cmdsize; |
michael@0 | 190 | } |
michael@0 | 191 | |
michael@0 | 192 | return 0; |
michael@0 | 193 | bail: |
michael@0 | 194 | return 1; |
michael@0 | 195 | |
michael@0 | 196 | } |
michael@0 | 197 | |
michael@0 | 198 | #elif defined(__ELF__) |
michael@0 | 199 | #include "elf.h" |
michael@0 | 200 | |
michael@0 | 201 | #define COPY_STRUCT(dst, buf, ofst, sz) do {\ |
michael@0 | 202 | if(ofst + sizeof((*(dst))) > sz) goto bail;\ |
michael@0 | 203 | memcpy(dst, buf+ofst, sizeof((*(dst))));\ |
michael@0 | 204 | } while(0) |
michael@0 | 205 | |
michael@0 | 206 | #define ENDIAN_ASSIGN(val, memb) do {\ |
michael@0 | 207 | if(!elf->le_data) {log_msg("Big Endian data not supported yet!\n");goto bail;}\ |
michael@0 | 208 | (val) = (memb);\ |
michael@0 | 209 | } while(0) |
michael@0 | 210 | |
michael@0 | 211 | #define ENDIAN_ASSIGN_IN_PLACE(memb) do {\ |
michael@0 | 212 | ENDIAN_ASSIGN(memb, memb);\ |
michael@0 | 213 | } while(0) |
michael@0 | 214 | |
michael@0 | 215 | typedef struct { |
michael@0 | 216 | uint8_t *buf; /* Buffer containing ELF data */ |
michael@0 | 217 | size_t sz; /* Buffer size */ |
michael@0 | 218 | int le_data; /* Data is little-endian */ |
michael@0 | 219 | unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */ |
michael@0 | 220 | int bits; /* 32 or 64 */ |
michael@0 | 221 | Elf32_Ehdr hdr32; |
michael@0 | 222 | Elf64_Ehdr hdr64; |
michael@0 | 223 | } elf_obj_t; |
michael@0 | 224 | |
michael@0 | 225 | int parse_elf_header(elf_obj_t *elf) { |
michael@0 | 226 | int res; |
michael@0 | 227 | /* Verify ELF Magic numbers */ |
michael@0 | 228 | COPY_STRUCT(&elf->e_ident, elf->buf, 0, elf->sz); |
michael@0 | 229 | res = elf->e_ident[EI_MAG0] == ELFMAG0; |
michael@0 | 230 | res &= elf->e_ident[EI_MAG1] == ELFMAG1; |
michael@0 | 231 | res &= elf->e_ident[EI_MAG2] == ELFMAG2; |
michael@0 | 232 | res &= elf->e_ident[EI_MAG3] == ELFMAG3; |
michael@0 | 233 | res &= elf->e_ident[EI_CLASS] == ELFCLASS32 |
michael@0 | 234 | || elf->e_ident[EI_CLASS] == ELFCLASS64; |
michael@0 | 235 | res &= elf->e_ident[EI_DATA] == ELFDATA2LSB; |
michael@0 | 236 | |
michael@0 | 237 | if (!res) goto bail; |
michael@0 | 238 | |
michael@0 | 239 | elf->le_data = elf->e_ident[EI_DATA] == ELFDATA2LSB; |
michael@0 | 240 | |
michael@0 | 241 | /* Read in relevant values */ |
michael@0 | 242 | if (elf->e_ident[EI_CLASS] == ELFCLASS32) { |
michael@0 | 243 | elf->bits = 32; |
michael@0 | 244 | COPY_STRUCT(&elf->hdr32, elf->buf, 0, elf->sz); |
michael@0 | 245 | |
michael@0 | 246 | ENDIAN_ASSIGN_IN_PLACE(elf->hdr32.e_type); |
michael@0 | 247 | ENDIAN_ASSIGN_IN_PLACE(elf->hdr32.e_machine); |
michael@0 | 248 | ENDIAN_ASSIGN_IN_PLACE(elf->hdr32.e_version); |
michael@0 | 249 | ENDIAN_ASSIGN_IN_PLACE(elf->hdr32.e_entry); |
michael@0 | 250 | ENDIAN_ASSIGN_IN_PLACE(elf->hdr32.e_phoff); |
michael@0 | 251 | ENDIAN_ASSIGN_IN_PLACE(elf->hdr32.e_shoff); |
michael@0 | 252 | ENDIAN_ASSIGN_IN_PLACE(elf->hdr32.e_flags); |
michael@0 | 253 | ENDIAN_ASSIGN_IN_PLACE(elf->hdr32.e_ehsize); |
michael@0 | 254 | ENDIAN_ASSIGN_IN_PLACE(elf->hdr32.e_phentsize); |
michael@0 | 255 | ENDIAN_ASSIGN_IN_PLACE(elf->hdr32.e_phnum); |
michael@0 | 256 | ENDIAN_ASSIGN_IN_PLACE(elf->hdr32.e_shentsize); |
michael@0 | 257 | ENDIAN_ASSIGN_IN_PLACE(elf->hdr32.e_shnum); |
michael@0 | 258 | ENDIAN_ASSIGN_IN_PLACE(elf->hdr32.e_shstrndx); |
michael@0 | 259 | } else { /* if (elf->e_ident[EI_CLASS] == ELFCLASS64) */ |
michael@0 | 260 | elf->bits = 64; |
michael@0 | 261 | COPY_STRUCT(&elf->hdr64, elf->buf, 0, elf->sz); |
michael@0 | 262 | |
michael@0 | 263 | ENDIAN_ASSIGN_IN_PLACE(elf->hdr64.e_type); |
michael@0 | 264 | ENDIAN_ASSIGN_IN_PLACE(elf->hdr64.e_machine); |
michael@0 | 265 | ENDIAN_ASSIGN_IN_PLACE(elf->hdr64.e_version); |
michael@0 | 266 | ENDIAN_ASSIGN_IN_PLACE(elf->hdr64.e_entry); |
michael@0 | 267 | ENDIAN_ASSIGN_IN_PLACE(elf->hdr64.e_phoff); |
michael@0 | 268 | ENDIAN_ASSIGN_IN_PLACE(elf->hdr64.e_shoff); |
michael@0 | 269 | ENDIAN_ASSIGN_IN_PLACE(elf->hdr64.e_flags); |
michael@0 | 270 | ENDIAN_ASSIGN_IN_PLACE(elf->hdr64.e_ehsize); |
michael@0 | 271 | ENDIAN_ASSIGN_IN_PLACE(elf->hdr64.e_phentsize); |
michael@0 | 272 | ENDIAN_ASSIGN_IN_PLACE(elf->hdr64.e_phnum); |
michael@0 | 273 | ENDIAN_ASSIGN_IN_PLACE(elf->hdr64.e_shentsize); |
michael@0 | 274 | ENDIAN_ASSIGN_IN_PLACE(elf->hdr64.e_shnum); |
michael@0 | 275 | ENDIAN_ASSIGN_IN_PLACE(elf->hdr64.e_shstrndx); |
michael@0 | 276 | } |
michael@0 | 277 | |
michael@0 | 278 | return 0; |
michael@0 | 279 | bail: |
michael@0 | 280 | log_msg("Failed to parse ELF file header"); |
michael@0 | 281 | return 1; |
michael@0 | 282 | } |
michael@0 | 283 | |
michael@0 | 284 | int parse_elf_section(elf_obj_t *elf, int idx, Elf32_Shdr *hdr32, Elf64_Shdr *hdr64) { |
michael@0 | 285 | if (hdr32) { |
michael@0 | 286 | if (idx >= elf->hdr32.e_shnum) |
michael@0 | 287 | goto bail; |
michael@0 | 288 | |
michael@0 | 289 | COPY_STRUCT(hdr32, elf->buf, elf->hdr32.e_shoff + idx * elf->hdr32.e_shentsize, |
michael@0 | 290 | elf->sz); |
michael@0 | 291 | ENDIAN_ASSIGN_IN_PLACE(hdr32->sh_name); |
michael@0 | 292 | ENDIAN_ASSIGN_IN_PLACE(hdr32->sh_type); |
michael@0 | 293 | ENDIAN_ASSIGN_IN_PLACE(hdr32->sh_flags); |
michael@0 | 294 | ENDIAN_ASSIGN_IN_PLACE(hdr32->sh_addr); |
michael@0 | 295 | ENDIAN_ASSIGN_IN_PLACE(hdr32->sh_offset); |
michael@0 | 296 | ENDIAN_ASSIGN_IN_PLACE(hdr32->sh_size); |
michael@0 | 297 | ENDIAN_ASSIGN_IN_PLACE(hdr32->sh_link); |
michael@0 | 298 | ENDIAN_ASSIGN_IN_PLACE(hdr32->sh_info); |
michael@0 | 299 | ENDIAN_ASSIGN_IN_PLACE(hdr32->sh_addralign); |
michael@0 | 300 | ENDIAN_ASSIGN_IN_PLACE(hdr32->sh_entsize); |
michael@0 | 301 | } else { /* if (hdr64) */ |
michael@0 | 302 | if (idx >= elf->hdr64.e_shnum) |
michael@0 | 303 | goto bail; |
michael@0 | 304 | |
michael@0 | 305 | COPY_STRUCT(hdr64, elf->buf, elf->hdr64.e_shoff + idx * elf->hdr64.e_shentsize, |
michael@0 | 306 | elf->sz); |
michael@0 | 307 | ENDIAN_ASSIGN_IN_PLACE(hdr64->sh_name); |
michael@0 | 308 | ENDIAN_ASSIGN_IN_PLACE(hdr64->sh_type); |
michael@0 | 309 | ENDIAN_ASSIGN_IN_PLACE(hdr64->sh_flags); |
michael@0 | 310 | ENDIAN_ASSIGN_IN_PLACE(hdr64->sh_addr); |
michael@0 | 311 | ENDIAN_ASSIGN_IN_PLACE(hdr64->sh_offset); |
michael@0 | 312 | ENDIAN_ASSIGN_IN_PLACE(hdr64->sh_size); |
michael@0 | 313 | ENDIAN_ASSIGN_IN_PLACE(hdr64->sh_link); |
michael@0 | 314 | ENDIAN_ASSIGN_IN_PLACE(hdr64->sh_info); |
michael@0 | 315 | ENDIAN_ASSIGN_IN_PLACE(hdr64->sh_addralign); |
michael@0 | 316 | ENDIAN_ASSIGN_IN_PLACE(hdr64->sh_entsize); |
michael@0 | 317 | } |
michael@0 | 318 | |
michael@0 | 319 | return 0; |
michael@0 | 320 | bail: |
michael@0 | 321 | return 1; |
michael@0 | 322 | } |
michael@0 | 323 | |
michael@0 | 324 | char *parse_elf_string_table(elf_obj_t *elf, int s_idx, int idx) { |
michael@0 | 325 | if (elf->bits == 32) { |
michael@0 | 326 | Elf32_Shdr shdr; |
michael@0 | 327 | |
michael@0 | 328 | if (parse_elf_section(elf, s_idx, &shdr, NULL)) { |
michael@0 | 329 | log_msg("Failed to parse ELF string table: section %d, index %d\n", |
michael@0 | 330 | s_idx, idx); |
michael@0 | 331 | return ""; |
michael@0 | 332 | } |
michael@0 | 333 | |
michael@0 | 334 | return (char *)(elf->buf + shdr.sh_offset + idx); |
michael@0 | 335 | } else { /* if (elf->bits == 64) */ |
michael@0 | 336 | Elf64_Shdr shdr; |
michael@0 | 337 | |
michael@0 | 338 | if (parse_elf_section(elf, s_idx, NULL, &shdr)) { |
michael@0 | 339 | log_msg("Failed to parse ELF string table: section %d, index %d\n", |
michael@0 | 340 | s_idx, idx); |
michael@0 | 341 | return ""; |
michael@0 | 342 | } |
michael@0 | 343 | |
michael@0 | 344 | return (char *)(elf->buf + shdr.sh_offset + idx); |
michael@0 | 345 | } |
michael@0 | 346 | } |
michael@0 | 347 | |
michael@0 | 348 | int parse_elf_symbol(elf_obj_t *elf, unsigned int ofst, Elf32_Sym *sym32, Elf64_Sym *sym64) { |
michael@0 | 349 | if (sym32) { |
michael@0 | 350 | COPY_STRUCT(sym32, elf->buf, ofst, elf->sz); |
michael@0 | 351 | ENDIAN_ASSIGN_IN_PLACE(sym32->st_name); |
michael@0 | 352 | ENDIAN_ASSIGN_IN_PLACE(sym32->st_value); |
michael@0 | 353 | ENDIAN_ASSIGN_IN_PLACE(sym32->st_size); |
michael@0 | 354 | ENDIAN_ASSIGN_IN_PLACE(sym32->st_info); |
michael@0 | 355 | ENDIAN_ASSIGN_IN_PLACE(sym32->st_other); |
michael@0 | 356 | ENDIAN_ASSIGN_IN_PLACE(sym32->st_shndx); |
michael@0 | 357 | } else { /* if (sym64) */ |
michael@0 | 358 | COPY_STRUCT(sym64, elf->buf, ofst, elf->sz); |
michael@0 | 359 | ENDIAN_ASSIGN_IN_PLACE(sym64->st_name); |
michael@0 | 360 | ENDIAN_ASSIGN_IN_PLACE(sym64->st_value); |
michael@0 | 361 | ENDIAN_ASSIGN_IN_PLACE(sym64->st_size); |
michael@0 | 362 | ENDIAN_ASSIGN_IN_PLACE(sym64->st_info); |
michael@0 | 363 | ENDIAN_ASSIGN_IN_PLACE(sym64->st_other); |
michael@0 | 364 | ENDIAN_ASSIGN_IN_PLACE(sym64->st_shndx); |
michael@0 | 365 | } |
michael@0 | 366 | return 0; |
michael@0 | 367 | bail: |
michael@0 | 368 | return 1; |
michael@0 | 369 | } |
michael@0 | 370 | |
michael@0 | 371 | int parse_elf(uint8_t *buf, size_t sz, output_fmt_t mode) { |
michael@0 | 372 | elf_obj_t elf; |
michael@0 | 373 | unsigned int ofst; |
michael@0 | 374 | int i; |
michael@0 | 375 | Elf32_Off strtab_off32; |
michael@0 | 376 | Elf64_Off strtab_off64; /* save String Table offset for later use */ |
michael@0 | 377 | |
michael@0 | 378 | memset(&elf, 0, sizeof(elf)); |
michael@0 | 379 | elf.buf = buf; |
michael@0 | 380 | elf.sz = sz; |
michael@0 | 381 | |
michael@0 | 382 | /* Parse Header */ |
michael@0 | 383 | if (parse_elf_header(&elf)) |
michael@0 | 384 | goto bail; |
michael@0 | 385 | |
michael@0 | 386 | if (elf.bits == 32) { |
michael@0 | 387 | Elf32_Shdr shdr; |
michael@0 | 388 | for (i = 0; i < elf.hdr32.e_shnum; i++) { |
michael@0 | 389 | parse_elf_section(&elf, i, &shdr, NULL); |
michael@0 | 390 | |
michael@0 | 391 | if (shdr.sh_type == SHT_STRTAB) { |
michael@0 | 392 | char strtsb_name[128]; |
michael@0 | 393 | |
michael@0 | 394 | strcpy(strtsb_name, (char *)(elf.buf + shdr.sh_offset + shdr.sh_name)); |
michael@0 | 395 | |
michael@0 | 396 | if (!(strcmp(strtsb_name, ".shstrtab"))) { |
michael@0 | 397 | /* log_msg("found section: %s\n", strtsb_name); */ |
michael@0 | 398 | strtab_off32 = shdr.sh_offset; |
michael@0 | 399 | break; |
michael@0 | 400 | } |
michael@0 | 401 | } |
michael@0 | 402 | } |
michael@0 | 403 | } else { /* if (elf.bits == 64) */ |
michael@0 | 404 | Elf64_Shdr shdr; |
michael@0 | 405 | for (i = 0; i < elf.hdr64.e_shnum; i++) { |
michael@0 | 406 | parse_elf_section(&elf, i, NULL, &shdr); |
michael@0 | 407 | |
michael@0 | 408 | if (shdr.sh_type == SHT_STRTAB) { |
michael@0 | 409 | char strtsb_name[128]; |
michael@0 | 410 | |
michael@0 | 411 | strcpy(strtsb_name, (char *)(elf.buf + shdr.sh_offset + shdr.sh_name)); |
michael@0 | 412 | |
michael@0 | 413 | if (!(strcmp(strtsb_name, ".shstrtab"))) { |
michael@0 | 414 | /* log_msg("found section: %s\n", strtsb_name); */ |
michael@0 | 415 | strtab_off64 = shdr.sh_offset; |
michael@0 | 416 | break; |
michael@0 | 417 | } |
michael@0 | 418 | } |
michael@0 | 419 | } |
michael@0 | 420 | } |
michael@0 | 421 | |
michael@0 | 422 | /* Parse all Symbol Tables */ |
michael@0 | 423 | if (elf.bits == 32) { |
michael@0 | 424 | Elf32_Shdr shdr; |
michael@0 | 425 | for (i = 0; i < elf.hdr32.e_shnum; i++) { |
michael@0 | 426 | parse_elf_section(&elf, i, &shdr, NULL); |
michael@0 | 427 | |
michael@0 | 428 | if (shdr.sh_type == SHT_SYMTAB) { |
michael@0 | 429 | for (ofst = shdr.sh_offset; |
michael@0 | 430 | ofst < shdr.sh_offset + shdr.sh_size; |
michael@0 | 431 | ofst += shdr.sh_entsize) { |
michael@0 | 432 | Elf32_Sym sym; |
michael@0 | 433 | |
michael@0 | 434 | parse_elf_symbol(&elf, ofst, &sym, NULL); |
michael@0 | 435 | |
michael@0 | 436 | /* For all OBJECTS (data objects), extract the value from the |
michael@0 | 437 | * proper data segment. |
michael@0 | 438 | */ |
michael@0 | 439 | /* if (ELF32_ST_TYPE(sym.st_info) == STT_OBJECT && sym.st_name) |
michael@0 | 440 | log_msg("found data object %s\n", |
michael@0 | 441 | parse_elf_string_table(&elf, |
michael@0 | 442 | shdr.sh_link, |
michael@0 | 443 | sym.st_name)); |
michael@0 | 444 | */ |
michael@0 | 445 | |
michael@0 | 446 | if (ELF32_ST_TYPE(sym.st_info) == STT_OBJECT |
michael@0 | 447 | && sym.st_size == 4) { |
michael@0 | 448 | Elf32_Shdr dhdr; |
michael@0 | 449 | int val = 0; |
michael@0 | 450 | char section_name[128]; |
michael@0 | 451 | |
michael@0 | 452 | parse_elf_section(&elf, sym.st_shndx, &dhdr, NULL); |
michael@0 | 453 | |
michael@0 | 454 | /* For explanition - refer to _MSC_VER version of code */ |
michael@0 | 455 | strcpy(section_name, (char *)(elf.buf + strtab_off32 + dhdr.sh_name)); |
michael@0 | 456 | /* log_msg("Section_name: %s, Section_type: %d\n", section_name, dhdr.sh_type); */ |
michael@0 | 457 | |
michael@0 | 458 | if (strcmp(section_name, ".bss")) { |
michael@0 | 459 | if (sizeof(val) != sym.st_size) { |
michael@0 | 460 | /* The target value is declared as an int in |
michael@0 | 461 | * *_asm_*_offsets.c, which is 4 bytes on all |
michael@0 | 462 | * targets we currently use. Complain loudly if |
michael@0 | 463 | * this is not true. |
michael@0 | 464 | */ |
michael@0 | 465 | log_msg("Symbol size is wrong\n"); |
michael@0 | 466 | goto bail; |
michael@0 | 467 | } |
michael@0 | 468 | |
michael@0 | 469 | memcpy(&val, |
michael@0 | 470 | elf.buf + dhdr.sh_offset + sym.st_value, |
michael@0 | 471 | sym.st_size); |
michael@0 | 472 | } |
michael@0 | 473 | |
michael@0 | 474 | if (!elf.le_data) { |
michael@0 | 475 | log_msg("Big Endian data not supported yet!\n"); |
michael@0 | 476 | goto bail; |
michael@0 | 477 | } |
michael@0 | 478 | |
michael@0 | 479 | switch (mode) { |
michael@0 | 480 | case OUTPUT_FMT_RVDS: |
michael@0 | 481 | printf("%-40s EQU %5d\n", |
michael@0 | 482 | parse_elf_string_table(&elf, |
michael@0 | 483 | shdr.sh_link, |
michael@0 | 484 | sym.st_name), |
michael@0 | 485 | val); |
michael@0 | 486 | break; |
michael@0 | 487 | case OUTPUT_FMT_GAS: |
michael@0 | 488 | printf(".equ %-40s, %5d\n", |
michael@0 | 489 | parse_elf_string_table(&elf, |
michael@0 | 490 | shdr.sh_link, |
michael@0 | 491 | sym.st_name), |
michael@0 | 492 | val); |
michael@0 | 493 | break; |
michael@0 | 494 | default: |
michael@0 | 495 | printf("%s = %d\n", |
michael@0 | 496 | parse_elf_string_table(&elf, |
michael@0 | 497 | shdr.sh_link, |
michael@0 | 498 | sym.st_name), |
michael@0 | 499 | val); |
michael@0 | 500 | } |
michael@0 | 501 | } |
michael@0 | 502 | } |
michael@0 | 503 | } |
michael@0 | 504 | } |
michael@0 | 505 | } else { /* if (elf.bits == 64) */ |
michael@0 | 506 | Elf64_Shdr shdr; |
michael@0 | 507 | for (i = 0; i < elf.hdr64.e_shnum; i++) { |
michael@0 | 508 | parse_elf_section(&elf, i, NULL, &shdr); |
michael@0 | 509 | |
michael@0 | 510 | if (shdr.sh_type == SHT_SYMTAB) { |
michael@0 | 511 | for (ofst = shdr.sh_offset; |
michael@0 | 512 | ofst < shdr.sh_offset + shdr.sh_size; |
michael@0 | 513 | ofst += shdr.sh_entsize) { |
michael@0 | 514 | Elf64_Sym sym; |
michael@0 | 515 | |
michael@0 | 516 | parse_elf_symbol(&elf, ofst, NULL, &sym); |
michael@0 | 517 | |
michael@0 | 518 | /* For all OBJECTS (data objects), extract the value from the |
michael@0 | 519 | * proper data segment. |
michael@0 | 520 | */ |
michael@0 | 521 | /* if (ELF64_ST_TYPE(sym.st_info) == STT_OBJECT && sym.st_name) |
michael@0 | 522 | log_msg("found data object %s\n", |
michael@0 | 523 | parse_elf_string_table(&elf, |
michael@0 | 524 | shdr.sh_link, |
michael@0 | 525 | sym.st_name)); |
michael@0 | 526 | */ |
michael@0 | 527 | |
michael@0 | 528 | if (ELF64_ST_TYPE(sym.st_info) == STT_OBJECT |
michael@0 | 529 | && sym.st_size == 4) { |
michael@0 | 530 | Elf64_Shdr dhdr; |
michael@0 | 531 | int val = 0; |
michael@0 | 532 | char section_name[128]; |
michael@0 | 533 | |
michael@0 | 534 | parse_elf_section(&elf, sym.st_shndx, NULL, &dhdr); |
michael@0 | 535 | |
michael@0 | 536 | /* For explanition - refer to _MSC_VER version of code */ |
michael@0 | 537 | strcpy(section_name, (char *)(elf.buf + strtab_off64 + dhdr.sh_name)); |
michael@0 | 538 | /* log_msg("Section_name: %s, Section_type: %d\n", section_name, dhdr.sh_type); */ |
michael@0 | 539 | |
michael@0 | 540 | if ((strcmp(section_name, ".bss"))) { |
michael@0 | 541 | if (sizeof(val) != sym.st_size) { |
michael@0 | 542 | /* The target value is declared as an int in |
michael@0 | 543 | * *_asm_*_offsets.c, which is 4 bytes on all |
michael@0 | 544 | * targets we currently use. Complain loudly if |
michael@0 | 545 | * this is not true. |
michael@0 | 546 | */ |
michael@0 | 547 | log_msg("Symbol size is wrong\n"); |
michael@0 | 548 | goto bail; |
michael@0 | 549 | } |
michael@0 | 550 | |
michael@0 | 551 | memcpy(&val, |
michael@0 | 552 | elf.buf + dhdr.sh_offset + sym.st_value, |
michael@0 | 553 | sym.st_size); |
michael@0 | 554 | } |
michael@0 | 555 | |
michael@0 | 556 | if (!elf.le_data) { |
michael@0 | 557 | log_msg("Big Endian data not supported yet!\n"); |
michael@0 | 558 | goto bail; |
michael@0 | 559 | } |
michael@0 | 560 | |
michael@0 | 561 | switch (mode) { |
michael@0 | 562 | case OUTPUT_FMT_RVDS: |
michael@0 | 563 | printf("%-40s EQU %5d\n", |
michael@0 | 564 | parse_elf_string_table(&elf, |
michael@0 | 565 | shdr.sh_link, |
michael@0 | 566 | sym.st_name), |
michael@0 | 567 | val); |
michael@0 | 568 | break; |
michael@0 | 569 | case OUTPUT_FMT_GAS: |
michael@0 | 570 | printf(".equ %-40s, %5d\n", |
michael@0 | 571 | parse_elf_string_table(&elf, |
michael@0 | 572 | shdr.sh_link, |
michael@0 | 573 | sym.st_name), |
michael@0 | 574 | val); |
michael@0 | 575 | break; |
michael@0 | 576 | default: |
michael@0 | 577 | printf("%s = %d\n", |
michael@0 | 578 | parse_elf_string_table(&elf, |
michael@0 | 579 | shdr.sh_link, |
michael@0 | 580 | sym.st_name), |
michael@0 | 581 | val); |
michael@0 | 582 | } |
michael@0 | 583 | } |
michael@0 | 584 | } |
michael@0 | 585 | } |
michael@0 | 586 | } |
michael@0 | 587 | } |
michael@0 | 588 | |
michael@0 | 589 | if (mode == OUTPUT_FMT_RVDS) |
michael@0 | 590 | printf(" END\n"); |
michael@0 | 591 | |
michael@0 | 592 | return 0; |
michael@0 | 593 | bail: |
michael@0 | 594 | log_msg("Parse error: File does not appear to be valid ELF32 or ELF64\n"); |
michael@0 | 595 | return 1; |
michael@0 | 596 | } |
michael@0 | 597 | |
michael@0 | 598 | #endif |
michael@0 | 599 | #endif /* defined(__GNUC__) && __GNUC__ */ |
michael@0 | 600 | |
michael@0 | 601 | |
michael@0 | 602 | #if defined(_MSC_VER) || defined(__MINGW32__) || defined(__CYGWIN__) |
michael@0 | 603 | /* See "Microsoft Portable Executable and Common Object File Format Specification" |
michael@0 | 604 | for reference. |
michael@0 | 605 | */ |
michael@0 | 606 | #define get_le32(x) ((*(x)) | (*(x+1)) << 8 |(*(x+2)) << 16 | (*(x+3)) << 24 ) |
michael@0 | 607 | #define get_le16(x) ((*(x)) | (*(x+1)) << 8) |
michael@0 | 608 | |
michael@0 | 609 | int parse_coff(uint8_t *buf, size_t sz) { |
michael@0 | 610 | unsigned int nsections, symtab_ptr, symtab_sz, strtab_ptr; |
michael@0 | 611 | unsigned int sectionrawdata_ptr; |
michael@0 | 612 | unsigned int i; |
michael@0 | 613 | uint8_t *ptr; |
michael@0 | 614 | uint32_t symoffset; |
michael@0 | 615 | |
michael@0 | 616 | char **sectionlist; // this array holds all section names in their correct order. |
michael@0 | 617 | // it is used to check if the symbol is in .bss or .rdata section. |
michael@0 | 618 | |
michael@0 | 619 | nsections = get_le16(buf + 2); |
michael@0 | 620 | symtab_ptr = get_le32(buf + 8); |
michael@0 | 621 | symtab_sz = get_le32(buf + 12); |
michael@0 | 622 | strtab_ptr = symtab_ptr + symtab_sz * 18; |
michael@0 | 623 | |
michael@0 | 624 | if (nsections > 96) { |
michael@0 | 625 | log_msg("Too many sections\n"); |
michael@0 | 626 | return 1; |
michael@0 | 627 | } |
michael@0 | 628 | |
michael@0 | 629 | sectionlist = malloc(nsections * sizeof(sectionlist)); |
michael@0 | 630 | |
michael@0 | 631 | if (sectionlist == NULL) { |
michael@0 | 632 | log_msg("Allocating first level of section list failed\n"); |
michael@0 | 633 | return 1; |
michael@0 | 634 | } |
michael@0 | 635 | |
michael@0 | 636 | // log_msg("COFF: Found %u symbols in %u sections.\n", symtab_sz, nsections); |
michael@0 | 637 | |
michael@0 | 638 | /* |
michael@0 | 639 | The size of optional header is always zero for an obj file. So, the section header |
michael@0 | 640 | follows the file header immediately. |
michael@0 | 641 | */ |
michael@0 | 642 | |
michael@0 | 643 | ptr = buf + 20; // section header |
michael@0 | 644 | |
michael@0 | 645 | for (i = 0; i < nsections; i++) { |
michael@0 | 646 | char sectionname[9] = {0, 0, 0, 0, 0, 0, 0, 0, 0}; |
michael@0 | 647 | strncpy(sectionname, ptr, 8); |
michael@0 | 648 | // log_msg("COFF: Parsing section %s\n",sectionname); |
michael@0 | 649 | |
michael@0 | 650 | sectionlist[i] = malloc(strlen(sectionname) + 1); |
michael@0 | 651 | |
michael@0 | 652 | if (sectionlist[i] == NULL) { |
michael@0 | 653 | log_msg("Allocating storage for %s failed\n", sectionname); |
michael@0 | 654 | goto bail; |
michael@0 | 655 | } |
michael@0 | 656 | strcpy(sectionlist[i], sectionname); |
michael@0 | 657 | |
michael@0 | 658 | if (!strcmp(sectionname, ".rdata")) sectionrawdata_ptr = get_le32(ptr + 20); |
michael@0 | 659 | |
michael@0 | 660 | ptr += 40; |
michael@0 | 661 | } |
michael@0 | 662 | |
michael@0 | 663 | // log_msg("COFF: Symbol table at offset %u\n", symtab_ptr); |
michael@0 | 664 | // log_msg("COFF: raw data pointer ofset for section .rdata is %u\n", sectionrawdata_ptr); |
michael@0 | 665 | |
michael@0 | 666 | /* The compiler puts the data with non-zero offset in .rdata section, but puts the data with |
michael@0 | 667 | zero offset in .bss section. So, if the data in in .bss section, set offset=0. |
michael@0 | 668 | Note from Wiki: In an object module compiled from C, the bss section contains |
michael@0 | 669 | the local variables (but not functions) that were declared with the static keyword, |
michael@0 | 670 | except for those with non-zero initial values. (In C, static variables are initialized |
michael@0 | 671 | to zero by default.) It also contains the non-local (both extern and static) variables |
michael@0 | 672 | that are also initialized to zero (either explicitly or by default). |
michael@0 | 673 | */ |
michael@0 | 674 | // move to symbol table |
michael@0 | 675 | /* COFF symbol table: |
michael@0 | 676 | offset field |
michael@0 | 677 | 0 Name(*) |
michael@0 | 678 | 8 Value |
michael@0 | 679 | 12 SectionNumber |
michael@0 | 680 | 14 Type |
michael@0 | 681 | 16 StorageClass |
michael@0 | 682 | 17 NumberOfAuxSymbols |
michael@0 | 683 | */ |
michael@0 | 684 | ptr = buf + symtab_ptr; |
michael@0 | 685 | |
michael@0 | 686 | for (i = 0; i < symtab_sz; i++) { |
michael@0 | 687 | int16_t section = get_le16(ptr + 12); // section number |
michael@0 | 688 | |
michael@0 | 689 | if (section > 0 && ptr[16] == 2) { |
michael@0 | 690 | // if(section > 0 && ptr[16] == 3 && get_le32(ptr+8)) { |
michael@0 | 691 | |
michael@0 | 692 | if (get_le32(ptr)) { |
michael@0 | 693 | char name[9] = {0, 0, 0, 0, 0, 0, 0, 0, 0}; |
michael@0 | 694 | strncpy(name, ptr, 8); |
michael@0 | 695 | // log_msg("COFF: Parsing symbol %s\n",name); |
michael@0 | 696 | /* The 64bit Windows compiler doesn't prefix with an _. |
michael@0 | 697 | * Check what's there, and bump if necessary |
michael@0 | 698 | */ |
michael@0 | 699 | if (name[0] == '_') |
michael@0 | 700 | printf("%-40s EQU ", name + 1); |
michael@0 | 701 | else |
michael@0 | 702 | printf("%-40s EQU ", name); |
michael@0 | 703 | } else { |
michael@0 | 704 | // log_msg("COFF: Parsing symbol %s\n", |
michael@0 | 705 | // buf + strtab_ptr + get_le32(ptr+4)); |
michael@0 | 706 | if ((buf + strtab_ptr + get_le32(ptr + 4))[0] == '_') |
michael@0 | 707 | printf("%-40s EQU ", |
michael@0 | 708 | buf + strtab_ptr + get_le32(ptr + 4) + 1); |
michael@0 | 709 | else |
michael@0 | 710 | printf("%-40s EQU ", buf + strtab_ptr + get_le32(ptr + 4)); |
michael@0 | 711 | } |
michael@0 | 712 | |
michael@0 | 713 | if (!(strcmp(sectionlist[section - 1], ".bss"))) { |
michael@0 | 714 | symoffset = 0; |
michael@0 | 715 | } else { |
michael@0 | 716 | symoffset = get_le32(buf + sectionrawdata_ptr + get_le32(ptr + 8)); |
michael@0 | 717 | } |
michael@0 | 718 | |
michael@0 | 719 | // log_msg(" Section: %d\n",section); |
michael@0 | 720 | // log_msg(" Class: %d\n",ptr[16]); |
michael@0 | 721 | // log_msg(" Address: %u\n",get_le32(ptr+8)); |
michael@0 | 722 | // log_msg(" Offset: %u\n", symoffset); |
michael@0 | 723 | |
michael@0 | 724 | printf("%5d\n", symoffset); |
michael@0 | 725 | } |
michael@0 | 726 | |
michael@0 | 727 | ptr += 18; |
michael@0 | 728 | } |
michael@0 | 729 | |
michael@0 | 730 | printf(" END\n"); |
michael@0 | 731 | |
michael@0 | 732 | for (i = 0; i < nsections; i++) { |
michael@0 | 733 | free(sectionlist[i]); |
michael@0 | 734 | } |
michael@0 | 735 | |
michael@0 | 736 | free(sectionlist); |
michael@0 | 737 | |
michael@0 | 738 | return 0; |
michael@0 | 739 | bail: |
michael@0 | 740 | |
michael@0 | 741 | for (i = 0; i < nsections; i++) { |
michael@0 | 742 | free(sectionlist[i]); |
michael@0 | 743 | } |
michael@0 | 744 | |
michael@0 | 745 | free(sectionlist); |
michael@0 | 746 | |
michael@0 | 747 | return 1; |
michael@0 | 748 | } |
michael@0 | 749 | #endif /* defined(_MSC_VER) || defined(__MINGW32__) || defined(__CYGWIN__) */ |
michael@0 | 750 | |
michael@0 | 751 | int main(int argc, char **argv) { |
michael@0 | 752 | output_fmt_t mode = OUTPUT_FMT_PLAIN; |
michael@0 | 753 | const char *f; |
michael@0 | 754 | uint8_t *file_buf; |
michael@0 | 755 | int res; |
michael@0 | 756 | FILE *fp; |
michael@0 | 757 | long int file_size; |
michael@0 | 758 | |
michael@0 | 759 | if (argc < 2 || argc > 3) { |
michael@0 | 760 | fprintf(stderr, "Usage: %s [output format] <obj file>\n\n", argv[0]); |
michael@0 | 761 | fprintf(stderr, " <obj file>\tobject file to parse\n"); |
michael@0 | 762 | fprintf(stderr, "Output Formats:\n"); |
michael@0 | 763 | fprintf(stderr, " gas - compatible with GNU assembler\n"); |
michael@0 | 764 | fprintf(stderr, " rvds - compatible with armasm\n"); |
michael@0 | 765 | goto bail; |
michael@0 | 766 | } |
michael@0 | 767 | |
michael@0 | 768 | f = argv[2]; |
michael@0 | 769 | |
michael@0 | 770 | if (!strcmp(argv[1], "rvds")) |
michael@0 | 771 | mode = OUTPUT_FMT_RVDS; |
michael@0 | 772 | else if (!strcmp(argv[1], "gas")) |
michael@0 | 773 | mode = OUTPUT_FMT_GAS; |
michael@0 | 774 | else |
michael@0 | 775 | f = argv[1]; |
michael@0 | 776 | |
michael@0 | 777 | fp = fopen(f, "rb"); |
michael@0 | 778 | |
michael@0 | 779 | if (!fp) { |
michael@0 | 780 | perror("Unable to open file"); |
michael@0 | 781 | goto bail; |
michael@0 | 782 | } |
michael@0 | 783 | |
michael@0 | 784 | if (fseek(fp, 0, SEEK_END)) { |
michael@0 | 785 | perror("stat"); |
michael@0 | 786 | goto bail; |
michael@0 | 787 | } |
michael@0 | 788 | |
michael@0 | 789 | file_size = ftell(fp); |
michael@0 | 790 | file_buf = malloc(file_size); |
michael@0 | 791 | |
michael@0 | 792 | if (!file_buf) { |
michael@0 | 793 | perror("malloc"); |
michael@0 | 794 | goto bail; |
michael@0 | 795 | } |
michael@0 | 796 | |
michael@0 | 797 | rewind(fp); |
michael@0 | 798 | |
michael@0 | 799 | if (fread(file_buf, sizeof(char), file_size, fp) != file_size) { |
michael@0 | 800 | perror("read"); |
michael@0 | 801 | goto bail; |
michael@0 | 802 | } |
michael@0 | 803 | |
michael@0 | 804 | if (fclose(fp)) { |
michael@0 | 805 | perror("close"); |
michael@0 | 806 | goto bail; |
michael@0 | 807 | } |
michael@0 | 808 | |
michael@0 | 809 | #if defined(__GNUC__) && __GNUC__ |
michael@0 | 810 | #if defined(__MACH__) |
michael@0 | 811 | res = parse_macho(file_buf, file_size, mode); |
michael@0 | 812 | #elif defined(__ELF__) |
michael@0 | 813 | res = parse_elf(file_buf, file_size, mode); |
michael@0 | 814 | #endif |
michael@0 | 815 | #endif |
michael@0 | 816 | #if defined(_MSC_VER) || defined(__MINGW32__) || defined(__CYGWIN__) |
michael@0 | 817 | res = parse_coff(file_buf, file_size); |
michael@0 | 818 | #endif |
michael@0 | 819 | |
michael@0 | 820 | free(file_buf); |
michael@0 | 821 | |
michael@0 | 822 | if (!res) |
michael@0 | 823 | return EXIT_SUCCESS; |
michael@0 | 824 | |
michael@0 | 825 | bail: |
michael@0 | 826 | return EXIT_FAILURE; |
michael@0 | 827 | } |