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