synth_elf.cc revision 8ade75f9558e31d25aec862a552fe78f9ba98c82
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
8namespace google_breakpad {
9namespace synth_elf {
10
11#ifndef NT_GNU_BUILD_ID
12#define NT_GNU_BUILD_ID 3
13#endif
14
15ELF::ELF(uint16_t machine,
16         uint8_t file_class,
17         Endianness endianness)
18  : Section(endianness),
19    addr_size_(file_class == ELFCLASS64 ? 8 : 4),
20    program_count_(0),
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  // NULL and NOBITS sections have no content, so they
117  // don't need to be written to the file.
118  if (type == SHT_NULL) {
119    offset_label = 0;
120  } else if (type == SHT_NOBITS) {
121    offset_label = offset;
122  } else {
123    Mark(&offset_label);
124    Append(section);
125    Align(4);
126  }
127  return index;
128}
129
130void ELF::Finish() {
131  // Add the section header string table at the end.
132  section_header_string_index_ = section_count_;
133  //printf(".shstrtab size: %ld\n", section_header_strings_.Size());
134  AddSection(".shstrtab", section_header_strings_, SHT_STRTAB);
135  //printf("section_count_: %ld, sections_.size(): %ld\n",
136  //     section_count_, sections_.size());
137  section_count_label_ = section_count_;
138  program_count_label_ = program_count_;
139  // TODO:  allow adding entries to program header table
140  program_header_label_ = 0;
141
142  // Section header table starts here.
143  Mark(&section_header_label_);
144  Append(section_header_table_);
145}
146
147SymbolTable::SymbolTable(Endianness endianness,
148                         size_t addr_size,
149                         StringTable& table) : Section(endianness),
150                                               addr_size_(addr_size),
151                                               table_(table) {
152  assert(addr_size_ == 4 || addr_size_ == 8);
153}
154
155void SymbolTable::AddSymbol(const string& name, uint32_t value,
156                            uint32_t size, unsigned info, uint16_t shndx) {
157  assert(addr_size_ == 4);
158  D32(table_.Add(name));
159  D32(value);
160  D32(size);
161  D8(info);
162  D8(0); // other
163  D16(shndx);
164}
165
166void SymbolTable::AddSymbol(const string& name, uint64_t value,
167                            uint64_t size, unsigned info, uint16_t shndx) {
168  assert(addr_size_ == 8);
169  D32(table_.Add(name));
170  D8(info);
171  D8(0); // other
172  D16(shndx);
173  D64(value);
174  D64(size);
175}
176
177BuildIDNote::BuildIDNote(const uint8_t* id_bytes,
178                         size_t id_size,
179                         Endianness endianness) : Section(endianness) {
180  const char kNoteName[] = "GNU";
181  // Elf32_Nhdr and Elf64_Nhdr are exactly the same.
182  Elf32_Nhdr note_header;
183  memset(&note_header, 0, sizeof(note_header));
184  note_header.n_namesz = sizeof(kNoteName);
185  note_header.n_descsz = id_size;
186  note_header.n_type = NT_GNU_BUILD_ID;
187
188  Append(reinterpret_cast<const uint8_t*>(&note_header),
189         sizeof(note_header));
190  AppendCString(kNoteName);
191  Append(id_bytes, id_size);
192}
193
194// static
195void BuildIDNote::AppendSection(ELF& elf,
196                                const uint8_t* id_bytes,
197                                size_t id_size) {
198  const char kBuildIDSectionName[] = ".note.gnu.build-id";
199  BuildIDNote note(id_bytes, id_size, elf.endianness());
200  elf.AddSection(kBuildIDSectionName, note, SHT_NOTE);
201}
202
203}  // namespace synth_elf
204}  // namespace google_breakpad
205