• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
log_msg(const char * fmt,...)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 
parse_macho(uint8_t * base_buf,size_t sz)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 
main(int argc,char ** argv)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 
parse_elf_header(elf_obj_t * elf)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 
parse_elf_section(elf_obj_t * elf,int idx,Elf32_Shdr * hdr32,Elf64_Shdr * hdr64)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 
parse_elf_string_table(elf_obj_t * elf,int s_idx,int idx)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 
parse_elf_symbol(elf_obj_t * elf,unsigned int ofst,Elf32_Sym * sym32,Elf64_Sym * sym64)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 
parse_elf(uint8_t * buf,size_t sz,output_fmt_t mode)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 
main(int argc,char ** argv)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 
parse_coff(unsigned __int8 * buf,size_t sz)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 
main(int argc,char ** argv)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