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