media/libvpx/build/make/obj_int_extract.c

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

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 }

mercurial