1#include "common/linux/synth_elf.h"
2
3#include <assert.h>
4#include <elf.h>
5#include <stdio.h>
6#include <string.h>
7
8#include "common/linux/elf_gnu_compat.h"
9#include "common/using_std_string.h"
10
11namespace google_breakpad {
12namespace synth_elf {
13
14ELF::ELF(uint16_t machine,
15         uint8_t file_class,
16         Endianness endianness)
17  : Section(endianness),
18    addr_size_(file_class == ELFCLASS64 ? 8 : 4),
19    program_count_(0),
20    program_header_table_(endianness),
21    section_count_(0),
22    section_header_table_(endianness),
23    section_header_strings_(endianness) {
24  // Could add support for more machine types here if needed.
25  assert(machine == EM_386 ||
26         machine == EM_X86_64 ||
27         machine == EM_ARM);
28  assert(file_class == ELFCLASS32 || file_class == ELFCLASS64);
29
30  start() = 0;
31  // Add ELF header
32  // e_ident
33  // EI_MAG0...EI_MAG3
34  D8(ELFMAG0);
35  D8(ELFMAG1);
36  D8(ELFMAG2);
37  D8(ELFMAG3);
38  // EI_CLASS
39  D8(file_class);
40  // EI_DATA
41  D8(endianness == kLittleEndian ? ELFDATA2LSB : ELFDATA2MSB);
42  // EI_VERSION
43  D8(EV_CURRENT);
44  // EI_OSABI
45  D8(ELFOSABI_SYSV);
46  // EI_ABIVERSION
47  D8(0);
48  // EI_PAD
49  Append(7, 0);
50  assert(Size() == EI_NIDENT);
51
52  // e_type
53  D16(ET_EXEC);  //TODO: allow passing ET_DYN?
54  // e_machine
55  D16(machine);
56  // e_version
57  D32(EV_CURRENT);
58  // e_entry
59  Append(endianness, addr_size_, 0);
60  // e_phoff
61  Append(endianness, addr_size_, program_header_label_);
62  // e_shoff
63  Append(endianness, addr_size_, section_header_label_);
64  // e_flags
65  D32(0);
66  // e_ehsize
67  D16(addr_size_ == 8 ? sizeof(Elf64_Ehdr) : sizeof(Elf32_Ehdr));
68  // e_phentsize
69  D16(addr_size_ == 8 ? sizeof(Elf64_Phdr) : sizeof(Elf32_Phdr));
70  // e_phnum
71  D16(program_count_label_);
72  // e_shentsize
73  D16(addr_size_ == 8 ? sizeof(Elf64_Shdr) : sizeof(Elf32_Shdr));
74  // e_shnum
75  D16(section_count_label_);
76  // e_shstrndx
77  D16(section_header_string_index_);
78
79  // Add an empty section for SHN_UNDEF.
80  Section shn_undef;
81  AddSection("", shn_undef, SHT_NULL);
82}
83
84int ELF::AddSection(const string& name, const Section& section,
85                    uint32_t type, uint32_t flags, uint64_t addr,
86                    uint32_t link, uint64_t entsize, uint64_t offset) {
87  Label offset_label;
88  Label string_label(section_header_strings_.Add(name));
89  size_t size = section.Size();
90
91  int index = section_count_;
92  ++section_count_;
93
94  section_header_table_
95    // sh_name
96    .D32(string_label)
97    // sh_type
98    .D32(type)
99    // sh_flags
100    .Append(endianness(), addr_size_, flags)
101    // sh_addr
102    .Append(endianness(), addr_size_, addr)
103    // sh_offset
104    .Append(endianness(), addr_size_, offset_label)
105    // sh_size
106    .Append(endianness(), addr_size_, size)
107    // sh_link
108    .D32(link)
109    // sh_info
110    .D32(0)
111    // sh_addralign
112    .Append(endianness(), addr_size_, 0)
113    // sh_entsize
114    .Append(endianness(), addr_size_, entsize);
115
116  sections_.push_back(ElfSection(section, type, addr, offset, offset_label,
117                                 size));
118  return index;
119}
120
121void ELF::AppendSection(ElfSection &section) {
122  // NULL and NOBITS sections have no content, so they
123  // don't need to be written to the file.
124  if (section.type_ == SHT_NULL) {
125    section.offset_label_ = 0;
126  } else if (section.type_ == SHT_NOBITS) {
127    section.offset_label_ = section.offset_;
128  } else {
129    Mark(&section.offset_label_);
130    Append(section);
131    Align(4);
132  }
133}
134
135void ELF::AddSegment(int start, int end, uint32_t type, uint32_t flags) {
136  assert(start > 0);
137  assert(size_t(start) < sections_.size());
138  assert(end > 0);
139  assert(size_t(end) < sections_.size());
140  ++program_count_;
141
142  // p_type
143  program_header_table_.D32(type);
144
145  if (addr_size_ == 8) {
146    // p_flags
147    program_header_table_.D32(flags);
148  }
149
150  size_t filesz = 0;
151  size_t memsz = 0;
152  bool prev_was_nobits = false;
153  for (int i = start; i <= end; ++i) {
154    size_t size = sections_[i].size_;
155    if (sections_[i].type_ != SHT_NOBITS) {
156      assert(!prev_was_nobits);
157      // non SHT_NOBITS sections are 4-byte aligned (see AddSection)
158      size = (size + 3) & ~3;
159      filesz += size;
160    } else {
161      prev_was_nobits = true;
162    }
163    memsz += size;
164  }
165
166  program_header_table_
167    // p_offset
168    .Append(endianness(), addr_size_, sections_[start].offset_label_)
169    // p_vaddr
170    .Append(endianness(), addr_size_, sections_[start].addr_)
171    // p_paddr
172    .Append(endianness(), addr_size_, sections_[start].addr_)
173    // p_filesz
174    .Append(endianness(), addr_size_, filesz)
175    // p_memsz
176    .Append(endianness(), addr_size_, memsz);
177
178  if (addr_size_ == 4) {
179    // p_flags
180    program_header_table_.D32(flags);
181  }
182
183  // p_align
184  program_header_table_.Append(endianness(), addr_size_, 0);
185}
186
187void ELF::Finish() {
188  // Add the section header string table at the end.
189  section_header_string_index_ = section_count_;
190  //printf(".shstrtab size: %ld\n", section_header_strings_.Size());
191  AddSection(".shstrtab", section_header_strings_, SHT_STRTAB);
192  //printf("section_count_: %ld, sections_.size(): %ld\n",
193  //     section_count_, sections_.size());
194  if (program_count_) {
195    Mark(&program_header_label_);
196    Append(program_header_table_);
197  } else {
198    program_header_label_ = 0;
199  }
200
201  for (vector<ElfSection>::iterator it = sections_.begin();
202       it < sections_.end(); ++it) {
203    AppendSection(*it);
204  }
205  section_count_label_ = section_count_;
206  program_count_label_ = program_count_;
207
208  // Section header table starts here.
209  Mark(&section_header_label_);
210  Append(section_header_table_);
211}
212
213SymbolTable::SymbolTable(Endianness endianness,
214                         size_t addr_size,
215                         StringTable& table) : Section(endianness),
216                                               addr_size_(addr_size),
217                                               table_(table) {
218  assert(addr_size_ == 4 || addr_size_ == 8);
219}
220
221void SymbolTable::AddSymbol(const string& name, uint32_t value,
222                            uint32_t size, unsigned info, uint16_t shndx) {
223  assert(addr_size_ == 4);
224  D32(table_.Add(name));
225  D32(value);
226  D32(size);
227  D8(info);
228  D8(0); // other
229  D16(shndx);
230}
231
232void SymbolTable::AddSymbol(const string& name, uint64_t value,
233                            uint64_t size, unsigned info, uint16_t shndx) {
234  assert(addr_size_ == 8);
235  D32(table_.Add(name));
236  D8(info);
237  D8(0); // other
238  D16(shndx);
239  D64(value);
240  D64(size);
241}
242
243void Notes::AddNote(int type, const string &name, const uint8_t* desc_bytes,
244                    size_t desc_size) {
245  // Elf32_Nhdr and Elf64_Nhdr are exactly the same.
246  Elf32_Nhdr note_header;
247  memset(&note_header, 0, sizeof(note_header));
248  note_header.n_namesz = name.length() + 1;
249  note_header.n_descsz = desc_size;
250  note_header.n_type = type;
251
252  Append(reinterpret_cast<const uint8_t*>(&note_header),
253         sizeof(note_header));
254  AppendCString(name);
255  Align(4);
256  Append(desc_bytes, desc_size);
257  Align(4);
258}
259
260}  // namespace synth_elf
261}  // namespace google_breakpad
262