obj_int_extract.c 25.2 KB
Newer Older
John Koleszar's avatar
John Koleszar committed
1
/*
2
 *  Copyright (c) 2010 The WebM project authors. All Rights Reserved.
John Koleszar's avatar
John Koleszar committed
3
 *
4
 *  Use of this source code is governed by a BSD-style license
5
6
 *  that can be found in the LICENSE file in the root of the source
 *  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.
John Koleszar's avatar
John Koleszar committed
9
10
11
 */


Johann's avatar
Johann committed
12
#include <stdarg.h>
John Koleszar's avatar
John Koleszar committed
13
14
#include <stdio.h>
#include <stdlib.h>
Johann's avatar
Johann committed
15
#include <string.h>
John Koleszar's avatar
John Koleszar committed
16
17

#include "vpx_config.h"
18
#include "vpx/vpx_integer.h"
John Koleszar's avatar
John Koleszar committed
19

John Koleszar's avatar
John Koleszar committed
20
21
22
23
typedef enum {
  OUTPUT_FMT_PLAIN,
  OUTPUT_FMT_RVDS,
  OUTPUT_FMT_GAS,
Tao Bai's avatar
Tao Bai committed
24
  OUTPUT_FMT_C_HEADER,
John Koleszar's avatar
John Koleszar committed
25
26
} output_fmt_t;

John Koleszar's avatar
John Koleszar committed
27
28
29
30
31
32
33
int log_msg(const char *fmt, ...) {
  int res;
  va_list ap;
  va_start(ap, fmt);
  res = vfprintf(stderr, fmt, ap);
  va_end(ap);
  return res;
John Koleszar's avatar
John Koleszar committed
34
35
36
37
38
39
40
41
}

#if defined(__GNUC__) && __GNUC__
#if defined(__MACH__)

#include <mach-o/loader.h>
#include <mach-o/nlist.h>

42
43
44
45
46
int print_macho_equ(output_fmt_t mode, uint8_t* name, int val) {
  switch (mode) {
    case OUTPUT_FMT_RVDS:
      printf("%-40s EQU %5d\n", name, val);
      return 0;
Johann's avatar
Johann committed
47
    case OUTPUT_FMT_GAS:
48
49
      printf(".set %-40s, %5d\n", name, val);
      return 0;
Johann's avatar
Johann committed
50
    case OUTPUT_FMT_C_HEADER:
Tao Bai's avatar
Tao Bai committed
51
52
      printf("#define %-40s %5d\n", name, val);
      return 0;
53
54
55
56
57
58
59
    default:
      log_msg("Unsupported mode: %d", mode);
      return 1;
  }
}

int parse_macho(uint8_t *base_buf, size_t sz, output_fmt_t mode) {
John Koleszar's avatar
John Koleszar committed
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
  int i, j;
  struct mach_header header;
  uint8_t *buf = base_buf;
  int base_data_section = 0;
  int bits = 0;

  /* We can read in mach_header for 32 and 64 bit architectures
   * because it's identical to mach_header_64 except for the last
   * element (uint32_t reserved), which we don't use. Then, when
   * we know which architecture we're looking at, increment buf
   * appropriately.
   */
  memcpy(&header, buf, sizeof(struct mach_header));

  if (header.magic == MH_MAGIC) {
    if (header.cputype == CPU_TYPE_ARM
        || header.cputype == CPU_TYPE_X86) {
      bits = 32;
      buf += sizeof(struct mach_header);
    } else {
      log_msg("Bad cputype for object file. Currently only tested for CPU_TYPE_[ARM|X86].\n");
      goto bail;
John Koleszar's avatar
John Koleszar committed
82
    }
John Koleszar's avatar
John Koleszar committed
83
84
85
86
87
88
89
  } else if (header.magic == MH_MAGIC_64) {
    if (header.cputype == CPU_TYPE_X86_64) {
      bits = 64;
      buf += sizeof(struct mach_header_64);
    } else {
      log_msg("Bad cputype for object file. Currently only tested for CPU_TYPE_X86_64.\n");
      goto bail;
Johann's avatar
Johann committed
90
    }
John Koleszar's avatar
John Koleszar committed
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
  } else {
    log_msg("Bad magic number for object file. 0x%x or 0x%x expected, 0x%x found.\n",
            MH_MAGIC, MH_MAGIC_64, header.magic);
    goto bail;
  }

  if (header.filetype != MH_OBJECT) {
    log_msg("Bad filetype for object file. Currently only tested for MH_OBJECT.\n");
    goto bail;
  }

  for (i = 0; i < header.ncmds; i++) {
    struct load_command lc;

    memcpy(&lc, buf, sizeof(struct load_command));

    if (lc.cmd == LC_SEGMENT) {
      uint8_t *seg_buf = buf;
      struct section s;
      struct segment_command seg_c;

      memcpy(&seg_c, seg_buf, sizeof(struct segment_command));
      seg_buf += sizeof(struct segment_command);

      /* Although each section is given it's own offset, nlist.n_value
       * references the offset of the first section. This isn't
       * apparent without debug information because the offset of the
       * data section is the same as the first section. However, with
       * debug sections mixed in, the offset of the debug section
       * increases but n_value still references the first section.
       */
      if (seg_c.nsects < 1) {
        log_msg("Not enough sections\n");
John Koleszar's avatar
John Koleszar committed
124
        goto bail;
John Koleszar's avatar
John Koleszar committed
125
126
127
128
129
130
131
132
133
134
135
      }

      memcpy(&s, seg_buf, sizeof(struct section));
      base_data_section = s.offset;
    } else if (lc.cmd == LC_SEGMENT_64) {
      uint8_t *seg_buf = buf;
      struct section_64 s;
      struct segment_command_64 seg_c;

      memcpy(&seg_c, seg_buf, sizeof(struct segment_command_64));
      seg_buf += sizeof(struct segment_command_64);
John Koleszar's avatar
John Koleszar committed
136

John Koleszar's avatar
John Koleszar committed
137
138
139
      /* Explanation in LG_SEGMENT */
      if (seg_c.nsects < 1) {
        log_msg("Not enough sections\n");
John Koleszar's avatar
John Koleszar committed
140
        goto bail;
John Koleszar's avatar
John Koleszar committed
141
      }
John Koleszar's avatar
John Koleszar committed
142

John Koleszar's avatar
John Koleszar committed
143
144
145
146
147
148
149
      memcpy(&s, seg_buf, sizeof(struct section_64));
      base_data_section = s.offset;
    } else if (lc.cmd == LC_SYMTAB) {
      if (base_data_section != 0) {
        struct symtab_command sc;
        uint8_t *sym_buf = base_buf;
        uint8_t *str_buf = base_buf;
John Koleszar's avatar
John Koleszar committed
150

John Koleszar's avatar
John Koleszar committed
151
        memcpy(&sc, buf, sizeof(struct symtab_command));
Johann's avatar
Johann committed
152

John Koleszar's avatar
John Koleszar committed
153
154
155
        if (sc.cmdsize != sizeof(struct symtab_command)) {
          log_msg("Can't find symbol table!\n");
          goto bail;
John Koleszar's avatar
John Koleszar committed
156
157
        }

John Koleszar's avatar
John Koleszar committed
158
159
160
161
162
163
164
        sym_buf += sc.symoff;
        str_buf += sc.stroff;

        for (j = 0; j < sc.nsyms; j++) {
          /* Location of string is cacluated each time from the
           * start of the string buffer.  On darwin the symbols
           * are prefixed by "_", so we bump the pointer by 1.
165
           * The target value is defined as an int in *_asm_*_offsets.c,
John Koleszar's avatar
John Koleszar committed
166
167
168
169
170
171
172
173
174
175
176
           * which is 4 bytes on all targets we currently use.
           */
          if (bits == 32) {
            struct nlist nl;
            int val;

            memcpy(&nl, sym_buf, sizeof(struct nlist));
            sym_buf += sizeof(struct nlist);

            memcpy(&val, base_buf + base_data_section + nl.n_value,
                   sizeof(val));
177
            print_macho_equ(mode, str_buf + nl.n_un.n_strx + 1, val);
John Koleszar's avatar
John Koleszar committed
178
179
180
181
182
183
184
185
186
          } else { /* if (bits == 64) */
            struct nlist_64 nl;
            int val;

            memcpy(&nl, sym_buf, sizeof(struct nlist_64));
            sym_buf += sizeof(struct nlist_64);

            memcpy(&val, base_buf + base_data_section + nl.n_value,
                   sizeof(val));
187
            print_macho_equ(mode, str_buf + nl.n_un.n_strx + 1, val);
John Koleszar's avatar
John Koleszar committed
188
189
190
          }
        }
      }
John Koleszar's avatar
John Koleszar committed
191
192
    }

John Koleszar's avatar
John Koleszar committed
193
194
195
196
    buf += lc.cmdsize;
  }

  return 0;
John Koleszar's avatar
John Koleszar committed
197
bail:
John Koleszar's avatar
John Koleszar committed
198
  return 1;
John Koleszar's avatar
John Koleszar committed
199
200
201

}

Johann's avatar
Johann committed
202
#elif defined(__ELF__)
John Koleszar's avatar
John Koleszar committed
203
204
205
#include "elf.h"

#define COPY_STRUCT(dst, buf, ofst, sz) do {\
John Koleszar's avatar
John Koleszar committed
206
207
208
    if(ofst + sizeof((*(dst))) > sz) goto bail;\
    memcpy(dst, buf+ofst, sizeof((*(dst))));\
  } while(0)
John Koleszar's avatar
John Koleszar committed
209
210

#define ENDIAN_ASSIGN(val, memb) do {\
John Koleszar's avatar
John Koleszar committed
211
212
213
    if(!elf->le_data) {log_msg("Big Endian data not supported yet!\n");goto bail;}\
    (val) = (memb);\
  } while(0)
John Koleszar's avatar
John Koleszar committed
214
215

#define ENDIAN_ASSIGN_IN_PLACE(memb) do {\
John Koleszar's avatar
John Koleszar committed
216
217
218
219
220
221
222
223
224
225
226
    ENDIAN_ASSIGN(memb, memb);\
  } while(0)

typedef struct {
  uint8_t      *buf; /* Buffer containing ELF data */
  size_t        sz;  /* Buffer size */
  int           le_data; /* Data is little-endian */
  unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */
  int           bits; /* 32 or 64 */
  Elf32_Ehdr    hdr32;
  Elf64_Ehdr    hdr64;
John Koleszar's avatar
John Koleszar committed
227
228
} elf_obj_t;

John Koleszar's avatar
John Koleszar committed
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
int parse_elf_header(elf_obj_t *elf) {
  int res;
  /* Verify ELF Magic numbers */
  COPY_STRUCT(&elf->e_ident, elf->buf, 0, elf->sz);
  res = elf->e_ident[EI_MAG0] == ELFMAG0;
  res &= elf->e_ident[EI_MAG1] == ELFMAG1;
  res &= elf->e_ident[EI_MAG2] == ELFMAG2;
  res &= elf->e_ident[EI_MAG3] == ELFMAG3;
  res &= elf->e_ident[EI_CLASS] == ELFCLASS32
         || elf->e_ident[EI_CLASS] == ELFCLASS64;
  res &= elf->e_ident[EI_DATA] == ELFDATA2LSB;

  if (!res) goto bail;

  elf->le_data = elf->e_ident[EI_DATA] == ELFDATA2LSB;

  /* Read in relevant values */
  if (elf->e_ident[EI_CLASS] == ELFCLASS32) {
    elf->bits = 32;
    COPY_STRUCT(&elf->hdr32, elf->buf, 0, elf->sz);

    ENDIAN_ASSIGN_IN_PLACE(elf->hdr32.e_type);
    ENDIAN_ASSIGN_IN_PLACE(elf->hdr32.e_machine);
    ENDIAN_ASSIGN_IN_PLACE(elf->hdr32.e_version);
    ENDIAN_ASSIGN_IN_PLACE(elf->hdr32.e_entry);
    ENDIAN_ASSIGN_IN_PLACE(elf->hdr32.e_phoff);
    ENDIAN_ASSIGN_IN_PLACE(elf->hdr32.e_shoff);
    ENDIAN_ASSIGN_IN_PLACE(elf->hdr32.e_flags);
    ENDIAN_ASSIGN_IN_PLACE(elf->hdr32.e_ehsize);
    ENDIAN_ASSIGN_IN_PLACE(elf->hdr32.e_phentsize);
    ENDIAN_ASSIGN_IN_PLACE(elf->hdr32.e_phnum);
    ENDIAN_ASSIGN_IN_PLACE(elf->hdr32.e_shentsize);
    ENDIAN_ASSIGN_IN_PLACE(elf->hdr32.e_shnum);
    ENDIAN_ASSIGN_IN_PLACE(elf->hdr32.e_shstrndx);
  } else { /* if (elf->e_ident[EI_CLASS] == ELFCLASS64) */
    elf->bits = 64;
    COPY_STRUCT(&elf->hdr64, elf->buf, 0, elf->sz);

    ENDIAN_ASSIGN_IN_PLACE(elf->hdr64.e_type);
    ENDIAN_ASSIGN_IN_PLACE(elf->hdr64.e_machine);
    ENDIAN_ASSIGN_IN_PLACE(elf->hdr64.e_version);
    ENDIAN_ASSIGN_IN_PLACE(elf->hdr64.e_entry);
    ENDIAN_ASSIGN_IN_PLACE(elf->hdr64.e_phoff);
    ENDIAN_ASSIGN_IN_PLACE(elf->hdr64.e_shoff);
    ENDIAN_ASSIGN_IN_PLACE(elf->hdr64.e_flags);
    ENDIAN_ASSIGN_IN_PLACE(elf->hdr64.e_ehsize);
    ENDIAN_ASSIGN_IN_PLACE(elf->hdr64.e_phentsize);
    ENDIAN_ASSIGN_IN_PLACE(elf->hdr64.e_phnum);
    ENDIAN_ASSIGN_IN_PLACE(elf->hdr64.e_shentsize);
    ENDIAN_ASSIGN_IN_PLACE(elf->hdr64.e_shnum);
    ENDIAN_ASSIGN_IN_PLACE(elf->hdr64.e_shstrndx);
  }

  return 0;
John Koleszar's avatar
John Koleszar committed
283
bail:
John Koleszar's avatar
John Koleszar committed
284
285
  log_msg("Failed to parse ELF file header");
  return 1;
John Koleszar's avatar
John Koleszar committed
286
287
}

John Koleszar's avatar
John Koleszar committed
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
int parse_elf_section(elf_obj_t *elf, int idx, Elf32_Shdr *hdr32, Elf64_Shdr *hdr64) {
  if (hdr32) {
    if (idx >= elf->hdr32.e_shnum)
      goto bail;

    COPY_STRUCT(hdr32, elf->buf, elf->hdr32.e_shoff + idx * elf->hdr32.e_shentsize,
                elf->sz);
    ENDIAN_ASSIGN_IN_PLACE(hdr32->sh_name);
    ENDIAN_ASSIGN_IN_PLACE(hdr32->sh_type);
    ENDIAN_ASSIGN_IN_PLACE(hdr32->sh_flags);
    ENDIAN_ASSIGN_IN_PLACE(hdr32->sh_addr);
    ENDIAN_ASSIGN_IN_PLACE(hdr32->sh_offset);
    ENDIAN_ASSIGN_IN_PLACE(hdr32->sh_size);
    ENDIAN_ASSIGN_IN_PLACE(hdr32->sh_link);
    ENDIAN_ASSIGN_IN_PLACE(hdr32->sh_info);
    ENDIAN_ASSIGN_IN_PLACE(hdr32->sh_addralign);
    ENDIAN_ASSIGN_IN_PLACE(hdr32->sh_entsize);
  } else { /* if (hdr64) */
    if (idx >= elf->hdr64.e_shnum)
      goto bail;
John Koleszar's avatar
John Koleszar committed
308

John Koleszar's avatar
John Koleszar committed
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
    COPY_STRUCT(hdr64, elf->buf, elf->hdr64.e_shoff + idx * elf->hdr64.e_shentsize,
                elf->sz);
    ENDIAN_ASSIGN_IN_PLACE(hdr64->sh_name);
    ENDIAN_ASSIGN_IN_PLACE(hdr64->sh_type);
    ENDIAN_ASSIGN_IN_PLACE(hdr64->sh_flags);
    ENDIAN_ASSIGN_IN_PLACE(hdr64->sh_addr);
    ENDIAN_ASSIGN_IN_PLACE(hdr64->sh_offset);
    ENDIAN_ASSIGN_IN_PLACE(hdr64->sh_size);
    ENDIAN_ASSIGN_IN_PLACE(hdr64->sh_link);
    ENDIAN_ASSIGN_IN_PLACE(hdr64->sh_info);
    ENDIAN_ASSIGN_IN_PLACE(hdr64->sh_addralign);
    ENDIAN_ASSIGN_IN_PLACE(hdr64->sh_entsize);
  }

  return 0;
John Koleszar's avatar
John Koleszar committed
324
bail:
John Koleszar's avatar
John Koleszar committed
325
  return 1;
John Koleszar's avatar
John Koleszar committed
326
327
}

328
const char *parse_elf_string_table(elf_obj_t *elf, int s_idx, int idx) {
John Koleszar's avatar
John Koleszar committed
329
330
  if (elf->bits == 32) {
    Elf32_Shdr shdr;
Johann's avatar
Johann committed
331

John Koleszar's avatar
John Koleszar committed
332
333
334
335
    if (parse_elf_section(elf, s_idx, &shdr, NULL)) {
      log_msg("Failed to parse ELF string table: section %d, index %d\n",
              s_idx, idx);
      return "";
John Koleszar's avatar
John Koleszar committed
336
337
    }

John Koleszar's avatar
John Koleszar committed
338
339
340
341
342
343
344
345
    return (char *)(elf->buf + shdr.sh_offset + idx);
  } else { /* if (elf->bits == 64) */
    Elf64_Shdr shdr;

    if (parse_elf_section(elf, s_idx, NULL, &shdr)) {
      log_msg("Failed to parse ELF string table: section %d, index %d\n",
              s_idx, idx);
      return "";
Johann's avatar
Johann committed
346
    }
John Koleszar's avatar
John Koleszar committed
347
348
349

    return (char *)(elf->buf + shdr.sh_offset + idx);
  }
John Koleszar's avatar
John Koleszar committed
350
351
}

John Koleszar's avatar
John Koleszar committed
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
int parse_elf_symbol(elf_obj_t *elf, unsigned int ofst, Elf32_Sym *sym32, Elf64_Sym *sym64) {
  if (sym32) {
    COPY_STRUCT(sym32, elf->buf, ofst, elf->sz);
    ENDIAN_ASSIGN_IN_PLACE(sym32->st_name);
    ENDIAN_ASSIGN_IN_PLACE(sym32->st_value);
    ENDIAN_ASSIGN_IN_PLACE(sym32->st_size);
    ENDIAN_ASSIGN_IN_PLACE(sym32->st_info);
    ENDIAN_ASSIGN_IN_PLACE(sym32->st_other);
    ENDIAN_ASSIGN_IN_PLACE(sym32->st_shndx);
  } else { /* if (sym64) */
    COPY_STRUCT(sym64, elf->buf, ofst, elf->sz);
    ENDIAN_ASSIGN_IN_PLACE(sym64->st_name);
    ENDIAN_ASSIGN_IN_PLACE(sym64->st_value);
    ENDIAN_ASSIGN_IN_PLACE(sym64->st_size);
    ENDIAN_ASSIGN_IN_PLACE(sym64->st_info);
    ENDIAN_ASSIGN_IN_PLACE(sym64->st_other);
    ENDIAN_ASSIGN_IN_PLACE(sym64->st_shndx);
  }
  return 0;
John Koleszar's avatar
John Koleszar committed
371
bail:
John Koleszar's avatar
John Koleszar committed
372
  return 1;
John Koleszar's avatar
John Koleszar committed
373
374
}

John Koleszar's avatar
John Koleszar committed
375
376
377
378
379
380
int parse_elf(uint8_t *buf, size_t sz, output_fmt_t mode) {
  elf_obj_t    elf;
  unsigned int ofst;
  int          i;
  Elf32_Off    strtab_off32;
  Elf64_Off    strtab_off64; /* save String Table offset for later use */
John Koleszar's avatar
John Koleszar committed
381

John Koleszar's avatar
John Koleszar committed
382
383
384
  memset(&elf, 0, sizeof(elf));
  elf.buf = buf;
  elf.sz = sz;
John Koleszar's avatar
John Koleszar committed
385

John Koleszar's avatar
John Koleszar committed
386
387
388
  /* Parse Header */
  if (parse_elf_header(&elf))
    goto bail;
John Koleszar's avatar
John Koleszar committed
389

John Koleszar's avatar
John Koleszar committed
390
391
392
393
394
395
396
397
398
399
400
401
402
403
  if (elf.bits == 32) {
    Elf32_Shdr shdr;
    for (i = 0; i < elf.hdr32.e_shnum; i++) {
      parse_elf_section(&elf, i, &shdr, NULL);

      if (shdr.sh_type == SHT_STRTAB) {
        char strtsb_name[128];

        strcpy(strtsb_name, (char *)(elf.buf + shdr.sh_offset + shdr.sh_name));

        if (!(strcmp(strtsb_name, ".shstrtab"))) {
          /* log_msg("found section: %s\n", strtsb_name); */
          strtab_off32 = shdr.sh_offset;
          break;
John Koleszar's avatar
John Koleszar committed
404
        }
John Koleszar's avatar
John Koleszar committed
405
      }
John Koleszar's avatar
John Koleszar committed
406
    }
John Koleszar's avatar
John Koleszar committed
407
408
409
410
411
412
413
414
415
416
417
418
419
420
  } else { /* if (elf.bits == 64) */
    Elf64_Shdr shdr;
    for (i = 0; i < elf.hdr64.e_shnum; i++) {
      parse_elf_section(&elf, i, NULL, &shdr);

      if (shdr.sh_type == SHT_STRTAB) {
        char strtsb_name[128];

        strcpy(strtsb_name, (char *)(elf.buf + shdr.sh_offset + shdr.sh_name));

        if (!(strcmp(strtsb_name, ".shstrtab"))) {
          /* log_msg("found section: %s\n", strtsb_name); */
          strtab_off64 = shdr.sh_offset;
          break;
Johann's avatar
Johann committed
421
        }
John Koleszar's avatar
John Koleszar committed
422
      }
Johann's avatar
Johann committed
423
    }
John Koleszar's avatar
John Koleszar committed
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
  }

  /* Parse all Symbol Tables */
  if (elf.bits == 32) {
    Elf32_Shdr shdr;
    for (i = 0; i < elf.hdr32.e_shnum; i++) {
      parse_elf_section(&elf, i, &shdr, NULL);

      if (shdr.sh_type == SHT_SYMTAB) {
        for (ofst = shdr.sh_offset;
             ofst < shdr.sh_offset + shdr.sh_size;
             ofst += shdr.sh_entsize) {
          Elf32_Sym sym;

          parse_elf_symbol(&elf, ofst, &sym, NULL);

          /* For all OBJECTS (data objects), extract the value from the
           * proper data segment.
           */
          /* if (ELF32_ST_TYPE(sym.st_info) == STT_OBJECT && sym.st_name)
              log_msg("found data object %s\n",
                      parse_elf_string_table(&elf,
                                             shdr.sh_link,
                                             sym.st_name));
           */

          if (ELF32_ST_TYPE(sym.st_info) == STT_OBJECT
              && sym.st_size == 4) {
            Elf32_Shdr dhdr;
            int val = 0;
            char section_name[128];

            parse_elf_section(&elf, sym.st_shndx, &dhdr, NULL);

            /* For explanition - refer to _MSC_VER version of code */
            strcpy(section_name, (char *)(elf.buf + strtab_off32 + dhdr.sh_name));
            /* log_msg("Section_name: %s, Section_type: %d\n", section_name, dhdr.sh_type); */

            if (strcmp(section_name, ".bss")) {
              if (sizeof(val) != sym.st_size) {
                /* The target value is declared as an int in
465
                 * *_asm_*_offsets.c, which is 4 bytes on all
John Koleszar's avatar
John Koleszar committed
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
                 * targets we currently use. Complain loudly if
                 * this is not true.
                 */
                log_msg("Symbol size is wrong\n");
                goto bail;
              }

              memcpy(&val,
                     elf.buf + dhdr.sh_offset + sym.st_value,
                     sym.st_size);
            }

            if (!elf.le_data) {
              log_msg("Big Endian data not supported yet!\n");
              goto bail;
            }
John Koleszar's avatar
John Koleszar committed
482

John Koleszar's avatar
John Koleszar committed
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
            switch (mode) {
              case OUTPUT_FMT_RVDS:
                printf("%-40s EQU %5d\n",
                       parse_elf_string_table(&elf,
                                              shdr.sh_link,
                                              sym.st_name),
                       val);
                break;
              case OUTPUT_FMT_GAS:
                printf(".equ %-40s, %5d\n",
                       parse_elf_string_table(&elf,
                                              shdr.sh_link,
                                              sym.st_name),
                       val);
                break;
Tao Bai's avatar
Tao Bai committed
498
499
500
501
502
503
504
              case OUTPUT_FMT_C_HEADER:
                printf("#define %-40s %5d\n",
                       parse_elf_string_table(&elf,
                                              shdr.sh_link,
                                              sym.st_name),
                       val);
                break;
John Koleszar's avatar
John Koleszar committed
505
506
507
508
509
510
              default:
                printf("%s = %d\n",
                       parse_elf_string_table(&elf,
                                              shdr.sh_link,
                                              sym.st_name),
                       val);
Johann's avatar
Johann committed
511
            }
John Koleszar's avatar
John Koleszar committed
512
          }
Johann's avatar
Johann committed
513
        }
John Koleszar's avatar
John Koleszar committed
514
      }
Johann's avatar
Johann committed
515
    }
John Koleszar's avatar
John Koleszar committed
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
  } else { /* if (elf.bits == 64) */
    Elf64_Shdr shdr;
    for (i = 0; i < elf.hdr64.e_shnum; i++) {
      parse_elf_section(&elf, i, NULL, &shdr);

      if (shdr.sh_type == SHT_SYMTAB) {
        for (ofst = shdr.sh_offset;
             ofst < shdr.sh_offset + shdr.sh_size;
             ofst += shdr.sh_entsize) {
          Elf64_Sym sym;

          parse_elf_symbol(&elf, ofst, NULL, &sym);

          /* For all OBJECTS (data objects), extract the value from the
           * proper data segment.
           */
          /* if (ELF64_ST_TYPE(sym.st_info) == STT_OBJECT && sym.st_name)
              log_msg("found data object %s\n",
                      parse_elf_string_table(&elf,
                                             shdr.sh_link,
                                             sym.st_name));
           */

          if (ELF64_ST_TYPE(sym.st_info) == STT_OBJECT
              && sym.st_size == 4) {
            Elf64_Shdr dhdr;
            int val = 0;
            char section_name[128];

            parse_elf_section(&elf, sym.st_shndx, NULL, &dhdr);

            /* For explanition - refer to _MSC_VER version of code */
            strcpy(section_name, (char *)(elf.buf + strtab_off64 + dhdr.sh_name));
            /* log_msg("Section_name: %s, Section_type: %d\n", section_name, dhdr.sh_type); */

            if ((strcmp(section_name, ".bss"))) {
              if (sizeof(val) != sym.st_size) {
                /* The target value is declared as an int in
554
                 * *_asm_*_offsets.c, which is 4 bytes on all
John Koleszar's avatar
John Koleszar committed
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
                 * targets we currently use. Complain loudly if
                 * this is not true.
                 */
                log_msg("Symbol size is wrong\n");
                goto bail;
              }

              memcpy(&val,
                     elf.buf + dhdr.sh_offset + sym.st_value,
                     sym.st_size);
            }

            if (!elf.le_data) {
              log_msg("Big Endian data not supported yet!\n");
              goto bail;
            }

            switch (mode) {
              case OUTPUT_FMT_RVDS:
                printf("%-40s EQU %5d\n",
                       parse_elf_string_table(&elf,
                                              shdr.sh_link,
                                              sym.st_name),
                       val);
                break;
              case OUTPUT_FMT_GAS:
                printf(".equ %-40s, %5d\n",
                       parse_elf_string_table(&elf,
                                              shdr.sh_link,
                                              sym.st_name),
                       val);
                break;
              default:
                printf("%s = %d\n",
                       parse_elf_string_table(&elf,
                                              shdr.sh_link,
                                              sym.st_name),
                       val);
John Koleszar's avatar
John Koleszar committed
593
            }
John Koleszar's avatar
John Koleszar committed
594
          }
John Koleszar's avatar
John Koleszar committed
595
        }
John Koleszar's avatar
John Koleszar committed
596
      }
John Koleszar's avatar
John Koleszar committed
597
    }
John Koleszar's avatar
John Koleszar committed
598
  }
John Koleszar's avatar
John Koleszar committed
599

John Koleszar's avatar
John Koleszar committed
600
601
  if (mode == OUTPUT_FMT_RVDS)
    printf("    END\n");
John Koleszar's avatar
John Koleszar committed
602

John Koleszar's avatar
John Koleszar committed
603
  return 0;
John Koleszar's avatar
John Koleszar committed
604
bail:
John Koleszar's avatar
John Koleszar committed
605
606
  log_msg("Parse error: File does not appear to be valid ELF32 or ELF64\n");
  return 1;
John Koleszar's avatar
John Koleszar committed
607
608
609
}

#endif
Johann's avatar
Johann committed
610
#endif /* defined(__GNUC__) && __GNUC__ */
John Koleszar's avatar
John Koleszar committed
611
612


Johann's avatar
Johann committed
613
#if defined(_MSC_VER) || defined(__MINGW32__) || defined(__CYGWIN__)
John Koleszar's avatar
John Koleszar committed
614
615
616
617
618
619
/*  See "Microsoft Portable Executable and Common Object File Format Specification"
    for reference.
*/
#define get_le32(x) ((*(x)) | (*(x+1)) << 8 |(*(x+2)) << 16 | (*(x+3)) << 24 )
#define get_le16(x) ((*(x)) | (*(x+1)) << 8)

John Koleszar's avatar
John Koleszar committed
620
621
622
623
624
625
int parse_coff(uint8_t *buf, size_t sz) {
  unsigned int nsections, symtab_ptr, symtab_sz, strtab_ptr;
  unsigned int sectionrawdata_ptr;
  unsigned int i;
  uint8_t *ptr;
  uint32_t symoffset;
John Koleszar's avatar
John Koleszar committed
626

John Koleszar's avatar
John Koleszar committed
627
  char **sectionlist;  // this array holds all section names in their correct order.
John Koleszar's avatar
John Koleszar committed
628
  // it is used to check if the symbol is in .bss or .rdata section.
Johann's avatar
Johann committed
629

John Koleszar's avatar
John Koleszar committed
630
631
632
633
  nsections = get_le16(buf + 2);
  symtab_ptr = get_le32(buf + 8);
  symtab_sz = get_le32(buf + 12);
  strtab_ptr = symtab_ptr + symtab_sz * 18;
John Koleszar's avatar
John Koleszar committed
634

John Koleszar's avatar
John Koleszar committed
635
636
637
638
  if (nsections > 96) {
    log_msg("Too many sections\n");
    return 1;
  }
John Koleszar's avatar
John Koleszar committed
639

John Koleszar's avatar
John Koleszar committed
640
  sectionlist = malloc(nsections * sizeof(sectionlist));
John Koleszar's avatar
John Koleszar committed
641

John Koleszar's avatar
John Koleszar committed
642
643
644
645
  if (sectionlist == NULL) {
    log_msg("Allocating first level of section list failed\n");
    return 1;
  }
John Koleszar's avatar
John Koleszar committed
646

John Koleszar's avatar
John Koleszar committed
647
  // log_msg("COFF: Found %u symbols in %u sections.\n", symtab_sz, nsections);
John Koleszar's avatar
John Koleszar committed
648

John Koleszar's avatar
John Koleszar committed
649
650
651
652
  /*
  The size of optional header is always zero for an obj file. So, the section header
  follows the file header immediately.
  */
Johann's avatar
Johann committed
653

John Koleszar's avatar
John Koleszar committed
654
  ptr = buf + 20;     // section header
John Koleszar's avatar
John Koleszar committed
655

John Koleszar's avatar
John Koleszar committed
656
657
658
659
  for (i = 0; i < nsections; i++) {
    char sectionname[9] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
    strncpy(sectionname, ptr, 8);
    // log_msg("COFF: Parsing section %s\n",sectionname);
John Koleszar's avatar
John Koleszar committed
660

John Koleszar's avatar
John Koleszar committed
661
    sectionlist[i] = malloc(strlen(sectionname) + 1);
John Koleszar's avatar
John Koleszar committed
662

John Koleszar's avatar
John Koleszar committed
663
664
665
666
667
668
    if (sectionlist[i] == NULL) {
      log_msg("Allocating storage for %s failed\n", sectionname);
      goto bail;
    }
    strcpy(sectionlist[i], sectionname);

John Koleszar's avatar
John Koleszar committed
669
    if (!strcmp(sectionname, ".rdata")) sectionrawdata_ptr = get_le32(ptr + 20);
John Koleszar's avatar
John Koleszar committed
670
671
672
673
674

    ptr += 40;
  }

  // log_msg("COFF: Symbol table at offset %u\n", symtab_ptr);
John Koleszar's avatar
John Koleszar committed
675
  // log_msg("COFF: raw data pointer ofset for section .rdata is %u\n", sectionrawdata_ptr);
John Koleszar's avatar
John Koleszar committed
676

John Koleszar's avatar
John Koleszar committed
677
  /*  The compiler puts the data with non-zero offset in .rdata section, but puts the data with
John Koleszar's avatar
John Koleszar committed
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
      zero offset in .bss section. So, if the data in in .bss section, set offset=0.
      Note from Wiki: In an object module compiled from C, the bss section contains
      the local variables (but not functions) that were declared with the static keyword,
      except for those with non-zero initial values. (In C, static variables are initialized
      to zero by default.) It also contains the non-local (both extern and static) variables
      that are also initialized to zero (either explicitly or by default).
      */
  // move to symbol table
  /* COFF symbol table:
      offset      field
      0           Name(*)
      8           Value
      12          SectionNumber
      14          Type
      16          StorageClass
      17          NumberOfAuxSymbols
      */
  ptr = buf + symtab_ptr;

  for (i = 0; i < symtab_sz; i++) {
    int16_t section = get_le16(ptr + 12); // section number

    if (section > 0 && ptr[16] == 2) {
      // if(section > 0 && ptr[16] == 3 && get_le32(ptr+8)) {

      if (get_le32(ptr)) {
        char name[9] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
        strncpy(name, ptr, 8);
        // log_msg("COFF: Parsing symbol %s\n",name);
        /* The 64bit Windows compiler doesn't prefix with an _.
         * Check what's there, and bump if necessary
         */
        if (name[0] == '_')
          printf("%-40s EQU ", name + 1);
        else
          printf("%-40s EQU ", name);
      } else {
        // log_msg("COFF: Parsing symbol %s\n",
        //        buf + strtab_ptr + get_le32(ptr+4));
        if ((buf + strtab_ptr + get_le32(ptr + 4))[0] == '_')
          printf("%-40s EQU ",
                 buf + strtab_ptr + get_le32(ptr + 4) + 1);
        else
          printf("%-40s EQU ", buf + strtab_ptr + get_le32(ptr + 4));
      }
John Koleszar's avatar
John Koleszar committed
723

John Koleszar's avatar
John Koleszar committed
724
725
726
727
728
      if (!(strcmp(sectionlist[section - 1], ".bss"))) {
        symoffset = 0;
      } else {
        symoffset = get_le32(buf + sectionrawdata_ptr + get_le32(ptr + 8));
      }
John Koleszar's avatar
John Koleszar committed
729

John Koleszar's avatar
John Koleszar committed
730
731
732
733
      // log_msg("      Section: %d\n",section);
      // log_msg("      Class:   %d\n",ptr[16]);
      // log_msg("      Address: %u\n",get_le32(ptr+8));
      // log_msg("      Offset: %u\n", symoffset);
John Koleszar's avatar
John Koleszar committed
734

John Koleszar's avatar
John Koleszar committed
735
      printf("%5d\n", symoffset);
John Koleszar's avatar
John Koleszar committed
736
737
    }

John Koleszar's avatar
John Koleszar committed
738
739
    ptr += 18;
  }
John Koleszar's avatar
John Koleszar committed
740

John Koleszar's avatar
John Koleszar committed
741
742
743
744
745
  printf("    END\n");

  for (i = 0; i < nsections; i++) {
    free(sectionlist[i]);
  }
John Koleszar's avatar
John Koleszar committed
746

John Koleszar's avatar
John Koleszar committed
747
  free(sectionlist);
John Koleszar's avatar
John Koleszar committed
748

John Koleszar's avatar
John Koleszar committed
749
  return 0;
John Koleszar's avatar
John Koleszar committed
750
751
bail:

John Koleszar's avatar
John Koleszar committed
752
753
754
  for (i = 0; i < nsections; i++) {
    free(sectionlist[i]);
  }
John Koleszar's avatar
John Koleszar committed
755

John Koleszar's avatar
John Koleszar committed
756
  free(sectionlist);
John Koleszar's avatar
John Koleszar committed
757

John Koleszar's avatar
John Koleszar committed
758
  return 1;
John Koleszar's avatar
John Koleszar committed
759
}
Johann's avatar
Johann committed
760
#endif /* defined(_MSC_VER) || defined(__MINGW32__) || defined(__CYGWIN__) */
John Koleszar's avatar
John Koleszar committed
761

John Koleszar's avatar
John Koleszar committed
762
763
764
765
766
767
768
769
770
771
772
773
774
775
int main(int argc, char **argv) {
  output_fmt_t mode = OUTPUT_FMT_PLAIN;
  const char *f;
  uint8_t *file_buf;
  int res;
  FILE *fp;
  long int file_size;

  if (argc < 2 || argc > 3) {
    fprintf(stderr, "Usage: %s [output format] <obj file>\n\n", argv[0]);
    fprintf(stderr, "  <obj file>\tobject file to parse\n");
    fprintf(stderr, "Output Formats:\n");
    fprintf(stderr, "  gas  - compatible with GNU assembler\n");
    fprintf(stderr, "  rvds - compatible with armasm\n");
Tao Bai's avatar
Tao Bai committed
776
    fprintf(stderr, "  cheader - c/c++ header file\n");
John Koleszar's avatar
John Koleszar committed
777
778
779
780
781
782
783
784
785
    goto bail;
  }

  f = argv[2];

  if (!strcmp(argv[1], "rvds"))
    mode = OUTPUT_FMT_RVDS;
  else if (!strcmp(argv[1], "gas"))
    mode = OUTPUT_FMT_GAS;
Tao Bai's avatar
Tao Bai committed
786
787
  else if (!strcmp(argv[1], "cheader"))
    mode = OUTPUT_FMT_C_HEADER;
John Koleszar's avatar
John Koleszar committed
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
  else
    f = argv[1];

  fp = fopen(f, "rb");

  if (!fp) {
    perror("Unable to open file");
    goto bail;
  }

  if (fseek(fp, 0, SEEK_END)) {
    perror("stat");
    goto bail;
  }

  file_size = ftell(fp);
  file_buf = malloc(file_size);

  if (!file_buf) {
    perror("malloc");
    goto bail;
  }

  rewind(fp);

  if (fread(file_buf, sizeof(char), file_size, fp) != file_size) {
    perror("read");
    goto bail;
  }

  if (fclose(fp)) {
    perror("close");
    goto bail;
  }
John Koleszar's avatar
John Koleszar committed
822

Johann's avatar
Johann committed
823
824
#if defined(__GNUC__) && __GNUC__
#if defined(__MACH__)
825
  res = parse_macho(file_buf, file_size, mode);
Johann's avatar
Johann committed
826
#elif defined(__ELF__)
John Koleszar's avatar
John Koleszar committed
827
  res = parse_elf(file_buf, file_size, mode);
Johann's avatar
Johann committed
828
829
830
#endif
#endif
#if defined(_MSC_VER) || defined(__MINGW32__) || defined(__CYGWIN__)
John Koleszar's avatar
John Koleszar committed
831
  res = parse_coff(file_buf, file_size);
Johann's avatar
Johann committed
832
#endif
John Koleszar's avatar
John Koleszar committed
833

John Koleszar's avatar
John Koleszar committed
834
  free(file_buf);
John Koleszar's avatar
John Koleszar committed
835

John Koleszar's avatar
John Koleszar committed
836
837
  if (!res)
    return EXIT_SUCCESS;
John Koleszar's avatar
John Koleszar committed
838
839

bail:
John Koleszar's avatar
John Koleszar committed
840
  return EXIT_FAILURE;
John Koleszar's avatar
John Koleszar committed
841
}