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
11 namespace google_breakpad {
12 namespace synth_elf {
13
ELF(uint16_t machine,uint8_t file_class,Endianness endianness)14 ELF::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
AddSection(const string & name,const Section & section,uint32_t type,uint32_t flags,uint64_t addr,uint32_t link,uint64_t entsize,uint64_t offset)84 int 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
AppendSection(ElfSection & section)121 void ELF::AppendSection(ElfSection §ion) {
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(§ion.offset_label_);
130 Append(section);
131 Align(4);
132 }
133 }
134
AddSegment(int start,int end,uint32_t type,uint32_t flags)135 void 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
Finish()187 void 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(§ion_header_label_);
210 Append(section_header_table_);
211 }
212
SymbolTable(Endianness endianness,size_t addr_size,StringTable & table)213 SymbolTable::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
AddSymbol(const string & name,uint32_t value,uint32_t size,unsigned info,uint16_t shndx)221 void 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
AddSymbol(const string & name,uint64_t value,uint64_t size,unsigned info,uint16_t shndx)232 void 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
AddNote(int type,const string & name,const uint8_t * desc_bytes,size_t desc_size)243 void 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(¬e_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*>(¬e_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