blob: 1604b5e68aaee1e19f49df2a18f2ca4c34c55feb [file] [log] [blame]
John Koleszar0ea50ce2010-05-18 11:58:33 -04001/*
John Koleszarc2140b82010-09-09 08:16:39 -04002 * Copyright (c) 2010 The WebM project authors. All Rights Reserved.
John Koleszar0ea50ce2010-05-18 11:58:33 -04003 *
John Koleszar94c52e42010-06-18 12:39:21 -04004 * Use of this source code is governed by a BSD-style license
John Koleszar09202d82010-06-04 16:19:40 -04005 * 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
John Koleszar94c52e42010-06-18 12:39:21 -04007 * in the file PATENTS. All contributing project authors may
John Koleszar09202d82010-06-04 16:19:40 -04008 * be found in the AUTHORS file in the root of the source tree.
John Koleszar0ea50ce2010-05-18 11:58:33 -04009 */
10
11
Johannfd7040d2011-03-31 16:35:22 -040012#include <stdarg.h>
John Koleszar0ea50ce2010-05-18 11:58:33 -040013#include <stdio.h>
14#include <stdlib.h>
Johannfd7040d2011-03-31 16:35:22 -040015#include <string.h>
John Koleszar0ea50ce2010-05-18 11:58:33 -040016
17#include "vpx_config.h"
John Koleszarb7492342010-05-24 11:39:59 -040018#include "vpx/vpx_integer.h"
John Koleszar0ea50ce2010-05-18 11:58:33 -040019
John Koleszarc6b90392012-07-13 15:21:29 -070020typedef enum {
21 OUTPUT_FMT_PLAIN,
22 OUTPUT_FMT_RVDS,
23 OUTPUT_FMT_GAS,
John Koleszar0ea50ce2010-05-18 11:58:33 -040024} output_fmt_t;
25
John Koleszarc6b90392012-07-13 15:21:29 -070026int log_msg(const char *fmt, ...) {
27 int res;
28 va_list ap;
29 va_start(ap, fmt);
30 res = vfprintf(stderr, fmt, ap);
31 va_end(ap);
32 return res;
John Koleszar0ea50ce2010-05-18 11:58:33 -040033}
34
35#if defined(__GNUC__) && __GNUC__
John Koleszar0ea50ce2010-05-18 11:58:33 -040036#if defined(__MACH__)
37
38#include <mach-o/loader.h>
39#include <mach-o/nlist.h>
40
John Koleszarc6b90392012-07-13 15:21:29 -070041int parse_macho(uint8_t *base_buf, size_t sz) {
42 int i, j;
43 struct mach_header header;
44 uint8_t *buf = base_buf;
45 int base_data_section = 0;
46 int bits = 0;
John Koleszar0ea50ce2010-05-18 11:58:33 -040047
John Koleszarc6b90392012-07-13 15:21:29 -070048 /* We can read in mach_header for 32 and 64 bit architectures
49 * because it's identical to mach_header_64 except for the last
50 * element (uint32_t reserved), which we don't use. Then, when
51 * we know which architecture we're looking at, increment buf
52 * appropriately.
53 */
54 memcpy(&header, buf, sizeof(struct mach_header));
John Koleszar0ea50ce2010-05-18 11:58:33 -040055
John Koleszarc6b90392012-07-13 15:21:29 -070056 if (header.magic == MH_MAGIC) {
57 if (header.cputype == CPU_TYPE_ARM
58 || header.cputype == CPU_TYPE_X86) {
59 bits = 32;
60 buf += sizeof(struct mach_header);
61 } else {
62 log_msg("Bad cputype for object file. Currently only tested for CPU_TYPE_[ARM|X86].\n");
63 goto bail;
John Koleszar0ea50ce2010-05-18 11:58:33 -040064 }
John Koleszarc6b90392012-07-13 15:21:29 -070065 } else if (header.magic == MH_MAGIC_64) {
66 if (header.cputype == CPU_TYPE_X86_64) {
67 bits = 64;
68 buf += sizeof(struct mach_header_64);
69 } else {
70 log_msg("Bad cputype for object file. Currently only tested for CPU_TYPE_X86_64.\n");
71 goto bail;
Johann5091e012011-02-23 16:08:10 -050072 }
John Koleszarc6b90392012-07-13 15:21:29 -070073 } else {
74 log_msg("Bad magic number for object file. 0x%x or 0x%x expected, 0x%x found.\n",
75 MH_MAGIC, MH_MAGIC_64, header.magic);
76 goto bail;
77 }
78
79 if (header.filetype != MH_OBJECT) {
80 log_msg("Bad filetype for object file. Currently only tested for MH_OBJECT.\n");
81 goto bail;
82 }
83
84 for (i = 0; i < header.ncmds; i++) {
85 struct load_command lc;
86
87 memcpy(&lc, buf, sizeof(struct load_command));
88
89 if (lc.cmd == LC_SEGMENT) {
90 uint8_t *seg_buf = buf;
91 struct section s;
92 struct segment_command seg_c;
93
94 memcpy(&seg_c, seg_buf, sizeof(struct segment_command));
95 seg_buf += sizeof(struct segment_command);
96
97 /* Although each section is given it's own offset, nlist.n_value
98 * references the offset of the first section. This isn't
99 * apparent without debug information because the offset of the
100 * data section is the same as the first section. However, with
101 * debug sections mixed in, the offset of the debug section
102 * increases but n_value still references the first section.
103 */
104 if (seg_c.nsects < 1) {
105 log_msg("Not enough sections\n");
John Koleszar0ea50ce2010-05-18 11:58:33 -0400106 goto bail;
John Koleszarc6b90392012-07-13 15:21:29 -0700107 }
John Koleszar0ea50ce2010-05-18 11:58:33 -0400108
John Koleszarc6b90392012-07-13 15:21:29 -0700109 memcpy(&s, seg_buf, sizeof(struct section));
110 base_data_section = s.offset;
111 } else if (lc.cmd == LC_SEGMENT_64) {
112 uint8_t *seg_buf = buf;
113 struct section_64 s;
114 struct segment_command_64 seg_c;
115
116 memcpy(&seg_c, seg_buf, sizeof(struct segment_command_64));
117 seg_buf += sizeof(struct segment_command_64);
118
119 /* Explanation in LG_SEGMENT */
120 if (seg_c.nsects < 1) {
121 log_msg("Not enough sections\n");
John Koleszar0ea50ce2010-05-18 11:58:33 -0400122 goto bail;
John Koleszarc6b90392012-07-13 15:21:29 -0700123 }
124
125 memcpy(&s, seg_buf, sizeof(struct section_64));
126 base_data_section = s.offset;
127 } else if (lc.cmd == LC_SYMTAB) {
128 if (base_data_section != 0) {
129 struct symtab_command sc;
130 uint8_t *sym_buf = base_buf;
131 uint8_t *str_buf = base_buf;
132
133 memcpy(&sc, buf, sizeof(struct symtab_command));
134
135 if (sc.cmdsize != sizeof(struct symtab_command)) {
136 log_msg("Can't find symbol table!\n");
137 goto bail;
138 }
139
140 sym_buf += sc.symoff;
141 str_buf += sc.stroff;
142
143 for (j = 0; j < sc.nsyms; j++) {
144 /* Location of string is cacluated each time from the
145 * start of the string buffer. On darwin the symbols
146 * are prefixed by "_", so we bump the pointer by 1.
James Zern08348d92013-03-02 13:42:41 -0800147 * The target value is defined as an int in *_asm_*_offsets.c,
John Koleszarc6b90392012-07-13 15:21:29 -0700148 * which is 4 bytes on all targets we currently use.
149 */
150 if (bits == 32) {
151 struct nlist nl;
152 int val;
153
154 memcpy(&nl, sym_buf, sizeof(struct nlist));
155 sym_buf += sizeof(struct nlist);
156
157 memcpy(&val, base_buf + base_data_section + nl.n_value,
158 sizeof(val));
159 printf("%-40s EQU %5d\n",
160 str_buf + nl.n_un.n_strx + 1, val);
161 } else { /* if (bits == 64) */
162 struct nlist_64 nl;
163 int val;
164
165 memcpy(&nl, sym_buf, sizeof(struct nlist_64));
166 sym_buf += sizeof(struct nlist_64);
167
168 memcpy(&val, base_buf + base_data_section + nl.n_value,
169 sizeof(val));
170 printf("%-40s EQU %5d\n",
171 str_buf + nl.n_un.n_strx + 1, val);
172 }
173 }
174 }
John Koleszar0ea50ce2010-05-18 11:58:33 -0400175 }
176
John Koleszarc6b90392012-07-13 15:21:29 -0700177 buf += lc.cmdsize;
178 }
John Koleszar0ea50ce2010-05-18 11:58:33 -0400179
John Koleszarc6b90392012-07-13 15:21:29 -0700180 return 0;
John Koleszar0ea50ce2010-05-18 11:58:33 -0400181bail:
John Koleszarc6b90392012-07-13 15:21:29 -0700182 return 1;
John Koleszar0ea50ce2010-05-18 11:58:33 -0400183
184}
185
Johannddd260e2011-02-23 17:07:35 -0500186#elif defined(__ELF__)
John Koleszar0ea50ce2010-05-18 11:58:33 -0400187#include "elf.h"
188
189#define COPY_STRUCT(dst, buf, ofst, sz) do {\
John Koleszarc6b90392012-07-13 15:21:29 -0700190 if(ofst + sizeof((*(dst))) > sz) goto bail;\
191 memcpy(dst, buf+ofst, sizeof((*(dst))));\
192 } while(0)
John Koleszar0ea50ce2010-05-18 11:58:33 -0400193
194#define ENDIAN_ASSIGN(val, memb) do {\
John Koleszarc6b90392012-07-13 15:21:29 -0700195 if(!elf->le_data) {log_msg("Big Endian data not supported yet!\n");goto bail;}\
196 (val) = (memb);\
197 } while(0)
John Koleszar0ea50ce2010-05-18 11:58:33 -0400198
199#define ENDIAN_ASSIGN_IN_PLACE(memb) do {\
John Koleszarc6b90392012-07-13 15:21:29 -0700200 ENDIAN_ASSIGN(memb, memb);\
201 } while(0)
John Koleszar0ea50ce2010-05-18 11:58:33 -0400202
John Koleszarc6b90392012-07-13 15:21:29 -0700203typedef struct {
204 uint8_t *buf; /* Buffer containing ELF data */
205 size_t sz; /* Buffer size */
206 int le_data; /* Data is little-endian */
207 unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */
208 int bits; /* 32 or 64 */
209 Elf32_Ehdr hdr32;
210 Elf64_Ehdr hdr64;
John Koleszar0ea50ce2010-05-18 11:58:33 -0400211} elf_obj_t;
212
John Koleszarc6b90392012-07-13 15:21:29 -0700213int parse_elf_header(elf_obj_t *elf) {
214 int res;
215 /* Verify ELF Magic numbers */
216 COPY_STRUCT(&elf->e_ident, elf->buf, 0, elf->sz);
217 res = elf->e_ident[EI_MAG0] == ELFMAG0;
218 res &= elf->e_ident[EI_MAG1] == ELFMAG1;
219 res &= elf->e_ident[EI_MAG2] == ELFMAG2;
220 res &= elf->e_ident[EI_MAG3] == ELFMAG3;
221 res &= elf->e_ident[EI_CLASS] == ELFCLASS32
222 || elf->e_ident[EI_CLASS] == ELFCLASS64;
223 res &= elf->e_ident[EI_DATA] == ELFDATA2LSB;
John Koleszar0ea50ce2010-05-18 11:58:33 -0400224
John Koleszarc6b90392012-07-13 15:21:29 -0700225 if (!res) goto bail;
John Koleszar0ea50ce2010-05-18 11:58:33 -0400226
John Koleszarc6b90392012-07-13 15:21:29 -0700227 elf->le_data = elf->e_ident[EI_DATA] == ELFDATA2LSB;
John Koleszar0ea50ce2010-05-18 11:58:33 -0400228
John Koleszarc6b90392012-07-13 15:21:29 -0700229 /* Read in relevant values */
230 if (elf->e_ident[EI_CLASS] == ELFCLASS32) {
231 elf->bits = 32;
232 COPY_STRUCT(&elf->hdr32, elf->buf, 0, elf->sz);
Johannddd260e2011-02-23 17:07:35 -0500233
John Koleszarc6b90392012-07-13 15:21:29 -0700234 ENDIAN_ASSIGN_IN_PLACE(elf->hdr32.e_type);
235 ENDIAN_ASSIGN_IN_PLACE(elf->hdr32.e_machine);
236 ENDIAN_ASSIGN_IN_PLACE(elf->hdr32.e_version);
237 ENDIAN_ASSIGN_IN_PLACE(elf->hdr32.e_entry);
238 ENDIAN_ASSIGN_IN_PLACE(elf->hdr32.e_phoff);
239 ENDIAN_ASSIGN_IN_PLACE(elf->hdr32.e_shoff);
240 ENDIAN_ASSIGN_IN_PLACE(elf->hdr32.e_flags);
241 ENDIAN_ASSIGN_IN_PLACE(elf->hdr32.e_ehsize);
242 ENDIAN_ASSIGN_IN_PLACE(elf->hdr32.e_phentsize);
243 ENDIAN_ASSIGN_IN_PLACE(elf->hdr32.e_phnum);
244 ENDIAN_ASSIGN_IN_PLACE(elf->hdr32.e_shentsize);
245 ENDIAN_ASSIGN_IN_PLACE(elf->hdr32.e_shnum);
246 ENDIAN_ASSIGN_IN_PLACE(elf->hdr32.e_shstrndx);
247 } else { /* if (elf->e_ident[EI_CLASS] == ELFCLASS64) */
248 elf->bits = 64;
249 COPY_STRUCT(&elf->hdr64, elf->buf, 0, elf->sz);
Johannddd260e2011-02-23 17:07:35 -0500250
John Koleszarc6b90392012-07-13 15:21:29 -0700251 ENDIAN_ASSIGN_IN_PLACE(elf->hdr64.e_type);
252 ENDIAN_ASSIGN_IN_PLACE(elf->hdr64.e_machine);
253 ENDIAN_ASSIGN_IN_PLACE(elf->hdr64.e_version);
254 ENDIAN_ASSIGN_IN_PLACE(elf->hdr64.e_entry);
255 ENDIAN_ASSIGN_IN_PLACE(elf->hdr64.e_phoff);
256 ENDIAN_ASSIGN_IN_PLACE(elf->hdr64.e_shoff);
257 ENDIAN_ASSIGN_IN_PLACE(elf->hdr64.e_flags);
258 ENDIAN_ASSIGN_IN_PLACE(elf->hdr64.e_ehsize);
259 ENDIAN_ASSIGN_IN_PLACE(elf->hdr64.e_phentsize);
260 ENDIAN_ASSIGN_IN_PLACE(elf->hdr64.e_phnum);
261 ENDIAN_ASSIGN_IN_PLACE(elf->hdr64.e_shentsize);
262 ENDIAN_ASSIGN_IN_PLACE(elf->hdr64.e_shnum);
263 ENDIAN_ASSIGN_IN_PLACE(elf->hdr64.e_shstrndx);
264 }
John Koleszar0ea50ce2010-05-18 11:58:33 -0400265
John Koleszarc6b90392012-07-13 15:21:29 -0700266 return 0;
Johannddd260e2011-02-23 17:07:35 -0500267bail:
John Koleszarc6b90392012-07-13 15:21:29 -0700268 log_msg("Failed to parse ELF file header");
269 return 1;
John Koleszar0ea50ce2010-05-18 11:58:33 -0400270}
271
John Koleszarc6b90392012-07-13 15:21:29 -0700272int parse_elf_section(elf_obj_t *elf, int idx, Elf32_Shdr *hdr32, Elf64_Shdr *hdr64) {
273 if (hdr32) {
274 if (idx >= elf->hdr32.e_shnum)
Johannddd260e2011-02-23 17:07:35 -0500275 goto bail;
John Koleszar0ea50ce2010-05-18 11:58:33 -0400276
John Koleszarc6b90392012-07-13 15:21:29 -0700277 COPY_STRUCT(hdr32, elf->buf, elf->hdr32.e_shoff + idx * elf->hdr32.e_shentsize,
278 elf->sz);
279 ENDIAN_ASSIGN_IN_PLACE(hdr32->sh_name);
280 ENDIAN_ASSIGN_IN_PLACE(hdr32->sh_type);
281 ENDIAN_ASSIGN_IN_PLACE(hdr32->sh_flags);
282 ENDIAN_ASSIGN_IN_PLACE(hdr32->sh_addr);
283 ENDIAN_ASSIGN_IN_PLACE(hdr32->sh_offset);
284 ENDIAN_ASSIGN_IN_PLACE(hdr32->sh_size);
285 ENDIAN_ASSIGN_IN_PLACE(hdr32->sh_link);
286 ENDIAN_ASSIGN_IN_PLACE(hdr32->sh_info);
287 ENDIAN_ASSIGN_IN_PLACE(hdr32->sh_addralign);
288 ENDIAN_ASSIGN_IN_PLACE(hdr32->sh_entsize);
289 } else { /* if (hdr64) */
290 if (idx >= elf->hdr64.e_shnum)
291 goto bail;
John Koleszar0ea50ce2010-05-18 11:58:33 -0400292
John Koleszarc6b90392012-07-13 15:21:29 -0700293 COPY_STRUCT(hdr64, elf->buf, elf->hdr64.e_shoff + idx * elf->hdr64.e_shentsize,
294 elf->sz);
295 ENDIAN_ASSIGN_IN_PLACE(hdr64->sh_name);
296 ENDIAN_ASSIGN_IN_PLACE(hdr64->sh_type);
297 ENDIAN_ASSIGN_IN_PLACE(hdr64->sh_flags);
298 ENDIAN_ASSIGN_IN_PLACE(hdr64->sh_addr);
299 ENDIAN_ASSIGN_IN_PLACE(hdr64->sh_offset);
300 ENDIAN_ASSIGN_IN_PLACE(hdr64->sh_size);
301 ENDIAN_ASSIGN_IN_PLACE(hdr64->sh_link);
302 ENDIAN_ASSIGN_IN_PLACE(hdr64->sh_info);
303 ENDIAN_ASSIGN_IN_PLACE(hdr64->sh_addralign);
304 ENDIAN_ASSIGN_IN_PLACE(hdr64->sh_entsize);
305 }
Johannddd260e2011-02-23 17:07:35 -0500306
John Koleszarc6b90392012-07-13 15:21:29 -0700307 return 0;
John Koleszar0ea50ce2010-05-18 11:58:33 -0400308bail:
John Koleszarc6b90392012-07-13 15:21:29 -0700309 return 1;
310}
311
312char *parse_elf_string_table(elf_obj_t *elf, int s_idx, int idx) {
313 if (elf->bits == 32) {
314 Elf32_Shdr shdr;
315
316 if (parse_elf_section(elf, s_idx, &shdr, NULL)) {
317 log_msg("Failed to parse ELF string table: section %d, index %d\n",
318 s_idx, idx);
319 return "";
320 }
321
322 return (char *)(elf->buf + shdr.sh_offset + idx);
323 } else { /* if (elf->bits == 64) */
324 Elf64_Shdr shdr;
325
326 if (parse_elf_section(elf, s_idx, NULL, &shdr)) {
327 log_msg("Failed to parse ELF string table: section %d, index %d\n",
328 s_idx, idx);
329 return "";
330 }
331
332 return (char *)(elf->buf + shdr.sh_offset + idx);
333 }
334}
335
336int parse_elf_symbol(elf_obj_t *elf, unsigned int ofst, Elf32_Sym *sym32, Elf64_Sym *sym64) {
337 if (sym32) {
338 COPY_STRUCT(sym32, elf->buf, ofst, elf->sz);
339 ENDIAN_ASSIGN_IN_PLACE(sym32->st_name);
340 ENDIAN_ASSIGN_IN_PLACE(sym32->st_value);
341 ENDIAN_ASSIGN_IN_PLACE(sym32->st_size);
342 ENDIAN_ASSIGN_IN_PLACE(sym32->st_info);
343 ENDIAN_ASSIGN_IN_PLACE(sym32->st_other);
344 ENDIAN_ASSIGN_IN_PLACE(sym32->st_shndx);
345 } else { /* if (sym64) */
346 COPY_STRUCT(sym64, elf->buf, ofst, elf->sz);
347 ENDIAN_ASSIGN_IN_PLACE(sym64->st_name);
348 ENDIAN_ASSIGN_IN_PLACE(sym64->st_value);
349 ENDIAN_ASSIGN_IN_PLACE(sym64->st_size);
350 ENDIAN_ASSIGN_IN_PLACE(sym64->st_info);
351 ENDIAN_ASSIGN_IN_PLACE(sym64->st_other);
352 ENDIAN_ASSIGN_IN_PLACE(sym64->st_shndx);
353 }
354 return 0;
355bail:
356 return 1;
357}
358
359int parse_elf(uint8_t *buf, size_t sz, output_fmt_t mode) {
360 elf_obj_t elf;
361 unsigned int ofst;
362 int i;
363 Elf32_Off strtab_off32;
364 Elf64_Off strtab_off64; /* save String Table offset for later use */
365
366 memset(&elf, 0, sizeof(elf));
367 elf.buf = buf;
368 elf.sz = sz;
369
370 /* Parse Header */
371 if (parse_elf_header(&elf))
372 goto bail;
373
374 if (elf.bits == 32) {
375 Elf32_Shdr shdr;
376 for (i = 0; i < elf.hdr32.e_shnum; i++) {
377 parse_elf_section(&elf, i, &shdr, NULL);
378
379 if (shdr.sh_type == SHT_STRTAB) {
380 char strtsb_name[128];
381
382 strcpy(strtsb_name, (char *)(elf.buf + shdr.sh_offset + shdr.sh_name));
383
384 if (!(strcmp(strtsb_name, ".shstrtab"))) {
385 /* log_msg("found section: %s\n", strtsb_name); */
386 strtab_off32 = shdr.sh_offset;
387 break;
388 }
389 }
390 }
391 } else { /* if (elf.bits == 64) */
392 Elf64_Shdr shdr;
393 for (i = 0; i < elf.hdr64.e_shnum; i++) {
394 parse_elf_section(&elf, i, NULL, &shdr);
395
396 if (shdr.sh_type == SHT_STRTAB) {
397 char strtsb_name[128];
398
399 strcpy(strtsb_name, (char *)(elf.buf + shdr.sh_offset + shdr.sh_name));
400
401 if (!(strcmp(strtsb_name, ".shstrtab"))) {
402 /* log_msg("found section: %s\n", strtsb_name); */
403 strtab_off64 = shdr.sh_offset;
404 break;
405 }
406 }
407 }
408 }
409
410 /* Parse all Symbol Tables */
411 if (elf.bits == 32) {
412 Elf32_Shdr shdr;
413 for (i = 0; i < elf.hdr32.e_shnum; i++) {
414 parse_elf_section(&elf, i, &shdr, NULL);
415
416 if (shdr.sh_type == SHT_SYMTAB) {
417 for (ofst = shdr.sh_offset;
418 ofst < shdr.sh_offset + shdr.sh_size;
419 ofst += shdr.sh_entsize) {
420 Elf32_Sym sym;
421
422 parse_elf_symbol(&elf, ofst, &sym, NULL);
423
424 /* For all OBJECTS (data objects), extract the value from the
425 * proper data segment.
426 */
427 /* if (ELF32_ST_TYPE(sym.st_info) == STT_OBJECT && sym.st_name)
428 log_msg("found data object %s\n",
429 parse_elf_string_table(&elf,
430 shdr.sh_link,
431 sym.st_name));
432 */
433
434 if (ELF32_ST_TYPE(sym.st_info) == STT_OBJECT
435 && sym.st_size == 4) {
436 Elf32_Shdr dhdr;
437 int val = 0;
438 char section_name[128];
439
440 parse_elf_section(&elf, sym.st_shndx, &dhdr, NULL);
441
442 /* For explanition - refer to _MSC_VER version of code */
443 strcpy(section_name, (char *)(elf.buf + strtab_off32 + dhdr.sh_name));
444 /* log_msg("Section_name: %s, Section_type: %d\n", section_name, dhdr.sh_type); */
445
446 if (strcmp(section_name, ".bss")) {
447 if (sizeof(val) != sym.st_size) {
448 /* The target value is declared as an int in
James Zern08348d92013-03-02 13:42:41 -0800449 * *_asm_*_offsets.c, which is 4 bytes on all
John Koleszarc6b90392012-07-13 15:21:29 -0700450 * targets we currently use. Complain loudly if
451 * this is not true.
452 */
453 log_msg("Symbol size is wrong\n");
454 goto bail;
455 }
456
457 memcpy(&val,
458 elf.buf + dhdr.sh_offset + sym.st_value,
459 sym.st_size);
460 }
461
462 if (!elf.le_data) {
463 log_msg("Big Endian data not supported yet!\n");
464 goto bail;
465 }
466
467 switch (mode) {
468 case OUTPUT_FMT_RVDS:
469 printf("%-40s EQU %5d\n",
470 parse_elf_string_table(&elf,
471 shdr.sh_link,
472 sym.st_name),
473 val);
474 break;
475 case OUTPUT_FMT_GAS:
476 printf(".equ %-40s, %5d\n",
477 parse_elf_string_table(&elf,
478 shdr.sh_link,
479 sym.st_name),
480 val);
481 break;
482 default:
483 printf("%s = %d\n",
484 parse_elf_string_table(&elf,
485 shdr.sh_link,
486 sym.st_name),
487 val);
488 }
489 }
490 }
491 }
492 }
493 } else { /* if (elf.bits == 64) */
494 Elf64_Shdr shdr;
495 for (i = 0; i < elf.hdr64.e_shnum; i++) {
496 parse_elf_section(&elf, i, NULL, &shdr);
497
498 if (shdr.sh_type == SHT_SYMTAB) {
499 for (ofst = shdr.sh_offset;
500 ofst < shdr.sh_offset + shdr.sh_size;
501 ofst += shdr.sh_entsize) {
502 Elf64_Sym sym;
503
504 parse_elf_symbol(&elf, ofst, NULL, &sym);
505
506 /* For all OBJECTS (data objects), extract the value from the
507 * proper data segment.
508 */
509 /* if (ELF64_ST_TYPE(sym.st_info) == STT_OBJECT && sym.st_name)
510 log_msg("found data object %s\n",
511 parse_elf_string_table(&elf,
512 shdr.sh_link,
513 sym.st_name));
514 */
515
516 if (ELF64_ST_TYPE(sym.st_info) == STT_OBJECT
517 && sym.st_size == 4) {
518 Elf64_Shdr dhdr;
519 int val = 0;
520 char section_name[128];
521
522 parse_elf_section(&elf, sym.st_shndx, NULL, &dhdr);
523
524 /* For explanition - refer to _MSC_VER version of code */
525 strcpy(section_name, (char *)(elf.buf + strtab_off64 + dhdr.sh_name));
526 /* log_msg("Section_name: %s, Section_type: %d\n", section_name, dhdr.sh_type); */
527
528 if ((strcmp(section_name, ".bss"))) {
529 if (sizeof(val) != sym.st_size) {
530 /* The target value is declared as an int in
James Zern08348d92013-03-02 13:42:41 -0800531 * *_asm_*_offsets.c, which is 4 bytes on all
John Koleszarc6b90392012-07-13 15:21:29 -0700532 * targets we currently use. Complain loudly if
533 * this is not true.
534 */
535 log_msg("Symbol size is wrong\n");
536 goto bail;
537 }
538
539 memcpy(&val,
540 elf.buf + dhdr.sh_offset + sym.st_value,
541 sym.st_size);
542 }
543
544 if (!elf.le_data) {
545 log_msg("Big Endian data not supported yet!\n");
546 goto bail;
547 }
548
549 switch (mode) {
550 case OUTPUT_FMT_RVDS:
551 printf("%-40s EQU %5d\n",
552 parse_elf_string_table(&elf,
553 shdr.sh_link,
554 sym.st_name),
555 val);
556 break;
557 case OUTPUT_FMT_GAS:
558 printf(".equ %-40s, %5d\n",
559 parse_elf_string_table(&elf,
560 shdr.sh_link,
561 sym.st_name),
562 val);
563 break;
564 default:
565 printf("%s = %d\n",
566 parse_elf_string_table(&elf,
567 shdr.sh_link,
568 sym.st_name),
569 val);
570 }
571 }
572 }
573 }
574 }
575 }
576
577 if (mode == OUTPUT_FMT_RVDS)
578 printf(" END\n");
579
580 return 0;
581bail:
582 log_msg("Parse error: File does not appear to be valid ELF32 or ELF64\n");
583 return 1;
John Koleszar0ea50ce2010-05-18 11:58:33 -0400584}
585
John Koleszar0ea50ce2010-05-18 11:58:33 -0400586#endif
Johannfd7040d2011-03-31 16:35:22 -0400587#endif /* defined(__GNUC__) && __GNUC__ */
John Koleszar0ea50ce2010-05-18 11:58:33 -0400588
589
Johannfd7040d2011-03-31 16:35:22 -0400590#if defined(_MSC_VER) || defined(__MINGW32__) || defined(__CYGWIN__)
John Koleszar0ea50ce2010-05-18 11:58:33 -0400591/* See "Microsoft Portable Executable and Common Object File Format Specification"
592 for reference.
593*/
594#define get_le32(x) ((*(x)) | (*(x+1)) << 8 |(*(x+2)) << 16 | (*(x+3)) << 24 )
595#define get_le16(x) ((*(x)) | (*(x+1)) << 8)
596
John Koleszarc6b90392012-07-13 15:21:29 -0700597int parse_coff(uint8_t *buf, size_t sz) {
598 unsigned int nsections, symtab_ptr, symtab_sz, strtab_ptr;
599 unsigned int sectionrawdata_ptr;
600 unsigned int i;
601 uint8_t *ptr;
602 uint32_t symoffset;
John Koleszar0ea50ce2010-05-18 11:58:33 -0400603
John Koleszarc6b90392012-07-13 15:21:29 -0700604 char **sectionlist; // this array holds all section names in their correct order.
John Koleszar1d0dc7c2012-11-02 15:17:36 -0700605 // it is used to check if the symbol is in .bss or .rdata section.
John Koleszar0ea50ce2010-05-18 11:58:33 -0400606
John Koleszarc6b90392012-07-13 15:21:29 -0700607 nsections = get_le16(buf + 2);
608 symtab_ptr = get_le32(buf + 8);
609 symtab_sz = get_le32(buf + 12);
610 strtab_ptr = symtab_ptr + symtab_sz * 18;
John Koleszar0ea50ce2010-05-18 11:58:33 -0400611
John Koleszarc6b90392012-07-13 15:21:29 -0700612 if (nsections > 96) {
613 log_msg("Too many sections\n");
614 return 1;
615 }
616
617 sectionlist = malloc(nsections * sizeof(sectionlist));
618
619 if (sectionlist == NULL) {
620 log_msg("Allocating first level of section list failed\n");
621 return 1;
622 }
623
624 // log_msg("COFF: Found %u symbols in %u sections.\n", symtab_sz, nsections);
625
626 /*
627 The size of optional header is always zero for an obj file. So, the section header
628 follows the file header immediately.
629 */
630
631 ptr = buf + 20; // section header
632
633 for (i = 0; i < nsections; i++) {
634 char sectionname[9] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
635 strncpy(sectionname, ptr, 8);
636 // log_msg("COFF: Parsing section %s\n",sectionname);
637
638 sectionlist[i] = malloc(strlen(sectionname) + 1);
639
640 if (sectionlist[i] == NULL) {
641 log_msg("Allocating storage for %s failed\n", sectionname);
642 goto bail;
643 }
644 strcpy(sectionlist[i], sectionname);
645
John Koleszar1d0dc7c2012-11-02 15:17:36 -0700646 if (!strcmp(sectionname, ".rdata")) sectionrawdata_ptr = get_le32(ptr + 20);
John Koleszarc6b90392012-07-13 15:21:29 -0700647
648 ptr += 40;
649 }
650
651 // log_msg("COFF: Symbol table at offset %u\n", symtab_ptr);
John Koleszar1d0dc7c2012-11-02 15:17:36 -0700652 // log_msg("COFF: raw data pointer ofset for section .rdata is %u\n", sectionrawdata_ptr);
John Koleszarc6b90392012-07-13 15:21:29 -0700653
John Koleszar1d0dc7c2012-11-02 15:17:36 -0700654 /* The compiler puts the data with non-zero offset in .rdata section, but puts the data with
John Koleszarc6b90392012-07-13 15:21:29 -0700655 zero offset in .bss section. So, if the data in in .bss section, set offset=0.
656 Note from Wiki: In an object module compiled from C, the bss section contains
657 the local variables (but not functions) that were declared with the static keyword,
658 except for those with non-zero initial values. (In C, static variables are initialized
659 to zero by default.) It also contains the non-local (both extern and static) variables
660 that are also initialized to zero (either explicitly or by default).
661 */
662 // move to symbol table
663 /* COFF symbol table:
664 offset field
665 0 Name(*)
666 8 Value
667 12 SectionNumber
668 14 Type
669 16 StorageClass
670 17 NumberOfAuxSymbols
671 */
672 ptr = buf + symtab_ptr;
673
674 for (i = 0; i < symtab_sz; i++) {
675 int16_t section = get_le16(ptr + 12); // section number
676
677 if (section > 0 && ptr[16] == 2) {
678 // if(section > 0 && ptr[16] == 3 && get_le32(ptr+8)) {
679
680 if (get_le32(ptr)) {
681 char name[9] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
682 strncpy(name, ptr, 8);
683 // log_msg("COFF: Parsing symbol %s\n",name);
684 /* The 64bit Windows compiler doesn't prefix with an _.
685 * Check what's there, and bump if necessary
686 */
687 if (name[0] == '_')
688 printf("%-40s EQU ", name + 1);
689 else
690 printf("%-40s EQU ", name);
691 } else {
692 // log_msg("COFF: Parsing symbol %s\n",
693 // buf + strtab_ptr + get_le32(ptr+4));
694 if ((buf + strtab_ptr + get_le32(ptr + 4))[0] == '_')
695 printf("%-40s EQU ",
696 buf + strtab_ptr + get_le32(ptr + 4) + 1);
697 else
698 printf("%-40s EQU ", buf + strtab_ptr + get_le32(ptr + 4));
699 }
700
701 if (!(strcmp(sectionlist[section - 1], ".bss"))) {
702 symoffset = 0;
703 } else {
704 symoffset = get_le32(buf + sectionrawdata_ptr + get_le32(ptr + 8));
705 }
706
707 // log_msg(" Section: %d\n",section);
708 // log_msg(" Class: %d\n",ptr[16]);
709 // log_msg(" Address: %u\n",get_le32(ptr+8));
710 // log_msg(" Offset: %u\n", symoffset);
711
712 printf("%5d\n", symoffset);
Johann128d2c22011-03-02 09:44:39 -0500713 }
John Koleszar0ea50ce2010-05-18 11:58:33 -0400714
John Koleszarc6b90392012-07-13 15:21:29 -0700715 ptr += 18;
716 }
Johann128d2c22011-03-02 09:44:39 -0500717
John Koleszarc6b90392012-07-13 15:21:29 -0700718 printf(" END\n");
John Koleszar0ea50ce2010-05-18 11:58:33 -0400719
John Koleszarc6b90392012-07-13 15:21:29 -0700720 for (i = 0; i < nsections; i++) {
721 free(sectionlist[i]);
722 }
John Koleszar0ea50ce2010-05-18 11:58:33 -0400723
John Koleszarc6b90392012-07-13 15:21:29 -0700724 free(sectionlist);
John Koleszar0ea50ce2010-05-18 11:58:33 -0400725
John Koleszarc6b90392012-07-13 15:21:29 -0700726 return 0;
John Koleszar0ea50ce2010-05-18 11:58:33 -0400727bail:
728
John Koleszarc6b90392012-07-13 15:21:29 -0700729 for (i = 0; i < nsections; i++) {
730 free(sectionlist[i]);
731 }
John Koleszar0ea50ce2010-05-18 11:58:33 -0400732
John Koleszarc6b90392012-07-13 15:21:29 -0700733 free(sectionlist);
John Koleszar0ea50ce2010-05-18 11:58:33 -0400734
John Koleszarc6b90392012-07-13 15:21:29 -0700735 return 1;
John Koleszar0ea50ce2010-05-18 11:58:33 -0400736}
Johannfd7040d2011-03-31 16:35:22 -0400737#endif /* defined(_MSC_VER) || defined(__MINGW32__) || defined(__CYGWIN__) */
John Koleszar0ea50ce2010-05-18 11:58:33 -0400738
John Koleszarc6b90392012-07-13 15:21:29 -0700739int main(int argc, char **argv) {
740 output_fmt_t mode = OUTPUT_FMT_PLAIN;
741 const char *f;
742 uint8_t *file_buf;
743 int res;
744 FILE *fp;
745 long int file_size;
John Koleszar0ea50ce2010-05-18 11:58:33 -0400746
John Koleszarc6b90392012-07-13 15:21:29 -0700747 if (argc < 2 || argc > 3) {
748 fprintf(stderr, "Usage: %s [output format] <obj file>\n\n", argv[0]);
749 fprintf(stderr, " <obj file>\tobject file to parse\n");
750 fprintf(stderr, "Output Formats:\n");
751 fprintf(stderr, " gas - compatible with GNU assembler\n");
752 fprintf(stderr, " rvds - compatible with armasm\n");
753 goto bail;
754 }
John Koleszar0ea50ce2010-05-18 11:58:33 -0400755
John Koleszarc6b90392012-07-13 15:21:29 -0700756 f = argv[2];
John Koleszar0ea50ce2010-05-18 11:58:33 -0400757
John Koleszarc6b90392012-07-13 15:21:29 -0700758 if (!strcmp(argv[1], "rvds"))
759 mode = OUTPUT_FMT_RVDS;
760 else if (!strcmp(argv[1], "gas"))
761 mode = OUTPUT_FMT_GAS;
762 else
763 f = argv[1];
John Koleszar0ea50ce2010-05-18 11:58:33 -0400764
John Koleszarc6b90392012-07-13 15:21:29 -0700765 fp = fopen(f, "rb");
John Koleszar0ea50ce2010-05-18 11:58:33 -0400766
John Koleszarc6b90392012-07-13 15:21:29 -0700767 if (!fp) {
768 perror("Unable to open file");
769 goto bail;
770 }
Johannfd7040d2011-03-31 16:35:22 -0400771
John Koleszarc6b90392012-07-13 15:21:29 -0700772 if (fseek(fp, 0, SEEK_END)) {
773 perror("stat");
774 goto bail;
775 }
John Koleszar0ea50ce2010-05-18 11:58:33 -0400776
John Koleszarc6b90392012-07-13 15:21:29 -0700777 file_size = ftell(fp);
778 file_buf = malloc(file_size);
John Koleszar0ea50ce2010-05-18 11:58:33 -0400779
John Koleszarc6b90392012-07-13 15:21:29 -0700780 if (!file_buf) {
781 perror("malloc");
782 goto bail;
783 }
John Koleszar0ea50ce2010-05-18 11:58:33 -0400784
John Koleszarc6b90392012-07-13 15:21:29 -0700785 rewind(fp);
Johannfd7040d2011-03-31 16:35:22 -0400786
John Koleszarc6b90392012-07-13 15:21:29 -0700787 if (fread(file_buf, sizeof(char), file_size, fp) != file_size) {
788 perror("read");
789 goto bail;
790 }
John Koleszar0ea50ce2010-05-18 11:58:33 -0400791
John Koleszarc6b90392012-07-13 15:21:29 -0700792 if (fclose(fp)) {
793 perror("close");
794 goto bail;
795 }
John Koleszar0ea50ce2010-05-18 11:58:33 -0400796
Johannfd7040d2011-03-31 16:35:22 -0400797#if defined(__GNUC__) && __GNUC__
798#if defined(__MACH__)
John Koleszarc6b90392012-07-13 15:21:29 -0700799 res = parse_macho(file_buf, file_size);
Johannfd7040d2011-03-31 16:35:22 -0400800#elif defined(__ELF__)
John Koleszarc6b90392012-07-13 15:21:29 -0700801 res = parse_elf(file_buf, file_size, mode);
Johannfd7040d2011-03-31 16:35:22 -0400802#endif
803#endif
804#if defined(_MSC_VER) || defined(__MINGW32__) || defined(__CYGWIN__)
John Koleszarc6b90392012-07-13 15:21:29 -0700805 res = parse_coff(file_buf, file_size);
Johannfd7040d2011-03-31 16:35:22 -0400806#endif
John Koleszar0ea50ce2010-05-18 11:58:33 -0400807
John Koleszarc6b90392012-07-13 15:21:29 -0700808 free(file_buf);
John Koleszar0ea50ce2010-05-18 11:58:33 -0400809
John Koleszarc6b90392012-07-13 15:21:29 -0700810 if (!res)
811 return EXIT_SUCCESS;
John Koleszar0ea50ce2010-05-18 11:58:33 -0400812
813bail:
John Koleszarc6b90392012-07-13 15:21:29 -0700814 return EXIT_FAILURE;
John Koleszar0ea50ce2010-05-18 11:58:33 -0400815}