synth_elf.cc revision 3ca4a120de8ec3f35e972e4b23f527bb8f65c479
1#include "common/linux/synth_elf.h"
2
3#include <assert.h>
4#include <elf.h>
5#include <stdio.h>
6
7namespace google_breakpad {
8namespace synth_elf {
9
10ELF::ELF(uint16_t machine,
11         uint8_t file_class,
12         Endianness endianness)
13  : Section(endianness),
14    addr_size_(file_class == ELFCLASS64 ? 8 : 4),
15    program_count_(0),
16    section_count_(0),
17    section_header_table_(endianness),
18    section_header_strings_(endianness) {
19  // Could add support for more machine types here if needed.
20  assert(machine == EM_386 ||
21         machine == EM_X86_64 ||
22         machine == EM_ARM);
23  assert(file_class == ELFCLASS32 || file_class == ELFCLASS64);
24
25  start() = 0;
26  // Add ELF header
27  // e_ident
28  // EI_MAG0...EI_MAG3
29  D8(ELFMAG0);
30  D8(ELFMAG1);
31  D8(ELFMAG2);
32  D8(ELFMAG3);
33  // EI_CLASS
34  D8(file_class);
35  // EI_DATA
36  D8(endianness == kLittleEndian ? ELFDATA2LSB : ELFDATA2MSB);
37  // EI_VERSION
38  D8(EV_CURRENT);
39  // EI_OSABI
40  D8(ELFOSABI_SYSV);
41  // EI_ABIVERSION
42  D8(0);
43  // EI_PAD
44  Append(7, 0);
45  assert(Size() == EI_NIDENT);
46
47  // e_type
48  D16(ET_EXEC);  //TODO: allow passing ET_DYN?
49  // e_machine
50  D16(machine);
51  // e_version
52  D32(EV_CURRENT);
53  // e_entry
54  Append(endianness, addr_size_, 0);
55  // e_phoff
56  Append(endianness, addr_size_, program_header_label_);
57  // e_shoff
58  Append(endianness, addr_size_, section_header_label_);
59  // e_flags
60  D32(0);
61  // e_ehsize
62  D16(addr_size_ == 8 ? sizeof(Elf64_Ehdr) : sizeof(Elf32_Ehdr));
63  // e_phentsize
64  D16(addr_size_ == 8 ? sizeof(Elf64_Phdr) : sizeof(Elf32_Phdr));
65  // e_phnum
66  D16(program_count_label_);
67  // e_shentsize
68  D16(addr_size_ == 8 ? sizeof(Elf64_Shdr) : sizeof(Elf32_Shdr));
69  // e_shnum
70  D16(section_count_label_);
71  // e_shstrndx
72  D16(section_header_string_index_);
73
74  // Add an empty section for SHN_UNDEF.
75  Section shn_undef;
76  AddSection("", shn_undef, SHT_NULL);
77}
78
79int ELF::AddSection(const string& name, const Section& section,
80                    uint32_t type, uint32_t flags, uint64_t addr,
81                    uint32_t link, uint64_t entsize, uint64_t offset) {
82  Label offset_label;
83  Label string_label(section_header_strings_.Add(name));
84  size_t size = section.Size();
85
86  int index = section_count_;
87  ++section_count_;
88
89  section_header_table_
90    // sh_name
91    .D32(string_label)
92    // sh_type
93    .D32(type)
94    // sh_flags
95    .Append(endianness(), addr_size_, flags)
96    // sh_addr
97    .Append(endianness(), addr_size_, addr)
98    // sh_offset
99    .Append(endianness(), addr_size_, offset_label)
100    // sh_size
101    .Append(endianness(), addr_size_, size)
102    // sh_link
103    .D32(link)
104    // sh_info
105    .D32(0)
106    // sh_addralign
107    .Append(endianness(), addr_size_, 0)
108    // sh_entsize
109    .Append(endianness(), addr_size_, entsize);
110
111  // NULL and NOBITS sections have no content, so they
112  // don't need to be written to the file.
113  if (type == SHT_NULL) {
114    offset_label = 0;
115  } else if (type == SHT_NOBITS) {
116    offset_label = offset;
117  } else {
118    Mark(&offset_label);
119    Append(section);
120    Align(4);
121  }
122  return index;
123}
124
125void ELF::Finish() {
126  // Add the section header string table at the end.
127  section_header_string_index_ = section_count_;
128  //printf(".shstrtab size: %ld\n", section_header_strings_.Size());
129  AddSection(".shstrtab", section_header_strings_, SHT_STRTAB);
130  //printf("section_count_: %ld, sections_.size(): %ld\n",
131  //     section_count_, sections_.size());
132  section_count_label_ = section_count_;
133  program_count_label_ = program_count_;
134  // TODO:  allow adding entries to program header table
135  program_header_label_ = 0;
136
137  // Section header table starts here.
138  Mark(&section_header_label_);
139  Append(section_header_table_);
140}
141
142SymbolTable::SymbolTable(Endianness endianness,
143                         size_t addr_size,
144                         StringTable& table) : Section(endianness),
145                                               addr_size_(addr_size),
146                                               table_(table) {
147  assert(addr_size_ == 4 || addr_size_ == 8);
148}
149
150void SymbolTable::AddSymbol(const string& name, uint32_t value,
151                            uint32_t size, unsigned info, uint16_t shndx) {
152  assert(addr_size_ == 4);
153  D32(table_.Add(name));
154  D32(value);
155  D32(size);
156  D8(info);
157  D8(0); // other
158  D16(shndx);
159}
160
161void SymbolTable::AddSymbol(const string& name, uint64_t value,
162                            uint64_t size, unsigned info, uint16_t shndx) {
163  assert(addr_size_ == 8);
164  D32(table_.Add(name));
165  D8(info);
166  D8(0); // other
167  D16(shndx);
168  D64(value);
169  D64(size);
170}
171
172}  // namespace synth_elf
173}  // namespace google_breakpad
174
175