1 : /* ***** BEGIN LICENSE BLOCK *****
2 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
3 : *
4 : * The contents of this file are subject to the Mozilla Public License Version
5 : * 1.1 (the "License"); you may not use this file except in compliance with
6 : * the License. You may obtain a copy of the License at
7 : * http://www.mozilla.org/MPL/
8 : *
9 : * Software distributed under the License is distributed on an "AS IS" basis,
10 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 : * for the specific language governing rights and limitations under the
12 : * License.
13 : *
14 : * The Original Code is elfhack.
15 : *
16 : * The Initial Developer of the Original Code is
17 : * Mozilla Foundation.
18 : * Portions created by the Initial Developer are Copyright (C) 2010
19 : * the Initial Developer. All Rights Reserved.
20 : *
21 : * Contributor(s):
22 : * Mike Hommey <mh@glandium.org>
23 : *
24 : * Alternatively, the contents of this file may be used under the terms of
25 : * either the GNU General Public License Version 2 or later (the "GPL"), or
26 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 : * in which case the provisions of the GPL or the LGPL are applicable instead
28 : * of those above. If you wish to allow use of your version of this file only
29 : * under the terms of either the GPL or the LGPL, and not to allow others to
30 : * use your version of this file under the terms of the MPL, indicate your
31 : * decision by deleting the provisions above and replace them with the notice
32 : * and other provisions required by the GPL or the LGPL. If you do not delete
33 : * the provisions above, a recipient may use your version of this file under
34 : * the terms of any one of the MPL, the GPL or the LGPL.
35 : *
36 : * ***** END LICENSE BLOCK ***** */
37 :
38 : #undef NDEBUG
39 : #include <cstring>
40 : #include <assert.h>
41 : #include "elfxx.h"
42 :
43 : template <class endian, typename R, typename T>
44 46 : void Elf_Ehdr_Traits::swap(T &t, R &r)
45 : {
46 46 : memcpy(r.e_ident, t.e_ident, sizeof(r.e_ident));
47 46 : r.e_type = endian::swap(t.e_type);
48 46 : r.e_machine = endian::swap(t.e_machine);
49 46 : r.e_version = endian::swap(t.e_version);
50 46 : r.e_entry = endian::swap(t.e_entry);
51 46 : r.e_phoff = endian::swap(t.e_phoff);
52 46 : r.e_shoff = endian::swap(t.e_shoff);
53 46 : r.e_flags = endian::swap(t.e_flags);
54 46 : r.e_ehsize = endian::swap(t.e_ehsize);
55 46 : r.e_phentsize = endian::swap(t.e_phentsize);
56 46 : r.e_phnum = endian::swap(t.e_phnum);
57 46 : r.e_shentsize = endian::swap(t.e_shentsize);
58 46 : r.e_shnum = endian::swap(t.e_shnum);
59 46 : r.e_shstrndx = endian::swap(t.e_shstrndx);
60 46 : }
61 :
62 : template <class endian, typename R, typename T>
63 115 : void Elf_Phdr_Traits::swap(T &t, R &r)
64 : {
65 115 : r.p_type = endian::swap(t.p_type);
66 115 : r.p_offset = endian::swap(t.p_offset);
67 115 : r.p_vaddr = endian::swap(t.p_vaddr);
68 115 : r.p_paddr = endian::swap(t.p_paddr);
69 115 : r.p_filesz = endian::swap(t.p_filesz);
70 115 : r.p_memsz = endian::swap(t.p_memsz);
71 115 : r.p_flags = endian::swap(t.p_flags);
72 115 : r.p_align = endian::swap(t.p_align);
73 115 : }
74 :
75 : template <class endian, typename R, typename T>
76 1179 : void Elf_Shdr_Traits::swap(T &t, R &r)
77 : {
78 1179 : r.sh_name = endian::swap(t.sh_name);
79 1179 : r.sh_type = endian::swap(t.sh_type);
80 1179 : r.sh_flags = endian::swap(t.sh_flags);
81 1179 : r.sh_addr = endian::swap(t.sh_addr);
82 1179 : r.sh_offset = endian::swap(t.sh_offset);
83 1179 : r.sh_size = endian::swap(t.sh_size);
84 1179 : r.sh_link = endian::swap(t.sh_link);
85 1179 : r.sh_info = endian::swap(t.sh_info);
86 1179 : r.sh_addralign = endian::swap(t.sh_addralign);
87 1179 : r.sh_entsize = endian::swap(t.sh_entsize);
88 1179 : }
89 :
90 : template <class endian, typename R, typename T>
91 895 : void Elf_Dyn_Traits::swap(T &t, R &r)
92 : {
93 895 : r.d_tag = endian::swap(t.d_tag);
94 895 : r.d_un.d_val = endian::swap(t.d_un.d_val);
95 895 : }
96 :
97 : template <class endian, typename R, typename T>
98 787943 : void Elf_Sym_Traits::swap(T &t, R &r)
99 : {
100 787943 : r.st_name = endian::swap(t.st_name);
101 787943 : r.st_value = endian::swap(t.st_value);
102 787943 : r.st_size = endian::swap(t.st_size);
103 787943 : r.st_info = t.st_info;
104 787943 : r.st_other = t.st_other;
105 787943 : r.st_shndx = endian::swap(t.st_shndx);
106 787943 : }
107 :
108 : template <class endian>
109 : struct _Rel_info {
110 342792 : static inline void swap(Elf32_Word &t, Elf32_Word &r) { r = endian::swap(t); }
111 : static inline void swap(Elf64_Xword &t, Elf64_Xword &r) { r = endian::swap(t); }
112 0 : static inline void swap(Elf64_Xword &t, Elf32_Word &r) {
113 0 : r = endian::swap(ELF32_R_INFO(ELF64_R_SYM(t), ELF64_R_TYPE(t)));
114 0 : }
115 0 : static inline void swap(Elf32_Word &t, Elf64_Xword &r) {
116 0 : r = endian::swap(ELF64_R_INFO(ELF32_R_SYM(t), ELF32_R_TYPE(t)));
117 0 : }
118 : };
119 :
120 : template <class endian, typename R, typename T>
121 342792 : void Elf_Rel_Traits::swap(T &t, R &r)
122 : {
123 342792 : r.r_offset = endian::swap(t.r_offset);
124 342792 : _Rel_info<endian>::swap(t.r_info, r.r_info);
125 342792 : }
126 :
127 : template <class endian, typename R, typename T>
128 0 : void Elf_Rela_Traits::swap(T &t, R &r)
129 : {
130 0 : r.r_offset = endian::swap(t.r_offset);
131 0 : _Rel_info<endian>::swap(t.r_info, r.r_info);
132 0 : r.r_addend = endian::swap(t.r_addend);
133 0 : }
134 :
135 : static const Elf32_Shdr null32_section =
136 : { 0, SHT_NULL, 0, 0, 0, 0, SHN_UNDEF, 0, 0, 0 };
137 :
138 2 : Elf_Shdr null_section(null32_section);
139 :
140 42 : Elf_Ehdr::Elf_Ehdr(std::ifstream &file, char ei_class, char ei_data)
141 : : serializable<Elf_Ehdr_Traits>(file, ei_class, ei_data),
142 42 : ElfSection(null_section, NULL, NULL)
143 : {
144 42 : shdr.sh_size = Elf_Ehdr::size(ei_class);
145 42 : }
146 :
147 42 : Elf::Elf(std::ifstream &file)
148 : {
149 42 : if (!file.is_open())
150 0 : throw std::runtime_error("Error opening file");
151 :
152 42 : file.exceptions(std::ifstream::eofbit | std::ifstream::failbit | std::ifstream::badbit);
153 : // Read ELF magic number and identification information
154 : char e_ident[EI_VERSION];
155 42 : file.seekg(0);
156 42 : file.read(e_ident, sizeof(e_ident));
157 42 : file.seekg(0);
158 42 : ehdr = new Elf_Ehdr(file, e_ident[EI_CLASS], e_ident[EI_DATA]);
159 :
160 : // ELFOSABI_LINUX is kept unsupported because I haven't looked whether
161 : // STB_GNU_UNIQUE or STT_GNU_IFUNC would need special casing.
162 42 : if ((ehdr->e_ident[EI_OSABI] != ELFOSABI_NONE) && (ehdr->e_ident[EI_ABIVERSION] != 0))
163 0 : throw std::runtime_error("unsupported ELF ABI");
164 :
165 42 : if (ehdr->e_version != 1)
166 0 : throw std::runtime_error("unsupported ELF version");
167 :
168 : // Sanity checks
169 42 : if (ehdr->e_shnum == 0)
170 0 : throw std::runtime_error("sstripped ELF files aren't supported");
171 :
172 42 : if (ehdr->e_ehsize != Elf_Ehdr::size(e_ident[EI_CLASS]))
173 0 : throw std::runtime_error("unsupported ELF inconsistency: ehdr.e_ehsize != sizeof(ehdr)");
174 :
175 42 : if (ehdr->e_shentsize != Elf_Shdr::size(e_ident[EI_CLASS]))
176 0 : throw std::runtime_error("unsupported ELF inconsistency: ehdr.e_shentsize != sizeof(shdr)");
177 :
178 42 : if (ehdr->e_phnum == 0) {
179 21 : if (ehdr->e_phoff != 0)
180 0 : throw std::runtime_error("unsupported ELF inconsistency: e_phnum == 0 && e_phoff != 0");
181 21 : if (ehdr->e_phentsize != 0)
182 0 : throw std::runtime_error("unsupported ELF inconsistency: e_phnum == 0 && e_phentsize != 0");
183 21 : } else if (ehdr->e_phoff != ehdr->e_ehsize)
184 0 : throw std::runtime_error("unsupported ELF inconsistency: ehdr->e_phoff != ehdr->e_ehsize");
185 21 : else if (ehdr->e_phentsize != Elf_Phdr::size(e_ident[EI_CLASS]))
186 0 : throw std::runtime_error("unsupported ELF inconsistency: ehdr->e_phentsize != sizeof(phdr)");
187 :
188 : // Read section headers
189 42 : Elf_Shdr **shdr = new Elf_Shdr *[ehdr->e_shnum];
190 42 : file.seekg(ehdr->e_shoff);
191 1070 : for (int i = 0; i < ehdr->e_shnum; i++)
192 1028 : shdr[i] = new Elf_Shdr(file, e_ident[EI_CLASS], e_ident[EI_DATA]);
193 :
194 : // Sanity check in section header for index 0
195 378 : if ((shdr[0]->sh_name != 0) || (shdr[0]->sh_type != SHT_NULL) ||
196 84 : (shdr[0]->sh_flags != 0) || (shdr[0]->sh_addr != 0) ||
197 84 : (shdr[0]->sh_offset != 0) || (shdr[0]->sh_size != 0) ||
198 84 : (shdr[0]->sh_link != SHN_UNDEF) || (shdr[0]->sh_info != 0) ||
199 84 : (shdr[0]->sh_addralign != 0) || (shdr[0]->sh_entsize != 0))
200 0 : throw std::runtime_error("Section header for index 0 contains unsupported values");
201 :
202 42 : if ((shdr[ehdr->e_shstrndx]->sh_link != 0) || (shdr[ehdr->e_shstrndx]->sh_info != 0))
203 0 : throw std::runtime_error("unsupported ELF content: string table with sh_link != 0 || sh_info != 0");
204 :
205 : // Store these temporarily
206 42 : tmp_shdr = shdr;
207 42 : tmp_file = &file;
208 :
209 : // Fill sections list
210 42 : sections = new ElfSection *[ehdr->e_shnum];
211 1070 : for (int i = 0; i < ehdr->e_shnum; i++)
212 1028 : sections[i] = NULL;
213 1028 : for (int i = 1; i < ehdr->e_shnum; i++) {
214 986 : if (sections[i] != NULL)
215 402 : continue;
216 584 : getSection(i);
217 : }
218 42 : Elf_Shdr s;
219 42 : s.sh_name = 0;
220 42 : s.sh_type = SHT_NULL;
221 42 : s.sh_flags = 0;
222 42 : s.sh_addr = 0;
223 42 : s.sh_offset = ehdr->e_shoff;
224 42 : s.sh_entsize = Elf_Shdr::size(e_ident[EI_CLASS]);
225 42 : s.sh_size = s.sh_entsize * ehdr->e_shnum;
226 42 : s.sh_link = 0;
227 42 : s.sh_info = 0;
228 42 : s.sh_addralign = (e_ident[EI_CLASS] == ELFCLASS32) ? 4 : 8;
229 42 : shdr_section = new ElfSection(s, NULL, NULL);
230 :
231 : // Fake section for program headers
232 42 : s.sh_offset = ehdr->e_phoff;
233 42 : s.sh_addr = ehdr->e_phoff;
234 42 : s.sh_entsize = Elf_Phdr::size(e_ident[EI_CLASS]);
235 42 : s.sh_size = s.sh_entsize * ehdr->e_phnum;
236 42 : phdr_section = new ElfSection(s, NULL, NULL);
237 :
238 42 : phdr_section->insertAfter(ehdr, false);
239 :
240 42 : sections[1]->insertAfter(phdr_section, false);
241 986 : for (int i = 2; i < ehdr->e_shnum; i++) {
242 : // TODO: this should be done in a better way
243 944 : if ((shdr_section->getPrevious() == NULL) && (shdr[i]->sh_offset > ehdr->e_shoff)) {
244 42 : shdr_section->insertAfter(sections[i - 1], false);
245 42 : sections[i]->insertAfter(shdr_section, false);
246 : } else
247 902 : sections[i]->insertAfter(sections[i - 1], false);
248 : }
249 42 : if (shdr_section->getPrevious() == NULL)
250 0 : shdr_section->insertAfter(sections[ehdr->e_shnum - 1], false);
251 :
252 42 : tmp_file = NULL;
253 42 : tmp_shdr = NULL;
254 1070 : for (int i = 0; i < ehdr->e_shnum; i++)
255 1028 : delete shdr[i];
256 42 : delete[] shdr;
257 :
258 42 : eh_shstrndx = (ElfStrtab_Section *)sections[ehdr->e_shstrndx];
259 :
260 : // Skip reading program headers if there aren't any
261 42 : if (ehdr->e_phnum == 0)
262 21 : return;
263 :
264 : // Read program headers
265 21 : file.seekg(ehdr->e_phoff);
266 111 : for (int i = 0; i < ehdr->e_phnum; i++) {
267 90 : Elf_Phdr phdr(file, e_ident[EI_CLASS], e_ident[EI_DATA]);
268 90 : if (phdr.p_type == PT_LOAD) {
269 : // Default alignment for PT_LOAD on x86-64 prevents elfhack from
270 : // doing anything useful. However, the system doesn't actually
271 : // require such a big alignment, so in order for elfhack to work
272 : // efficiently, reduce alignment when it's originally the default
273 : // one.
274 42 : if ((ehdr->e_machine == EM_X86_64) && (phdr.p_align == 0x200000))
275 0 : phdr.p_align = 0x1000;
276 : }
277 90 : ElfSegment *segment = new ElfSegment(&phdr);
278 : // Some segments aren't entirely filled (if at all) by sections
279 : // For those, we use fake sections
280 90 : if ((phdr.p_type == PT_LOAD) && (phdr.p_offset == 0)) {
281 : // Use a fake section for ehdr and phdr
282 21 : ehdr->getShdr().sh_addr = phdr.p_vaddr;
283 21 : phdr_section->getShdr().sh_addr += phdr.p_vaddr;
284 21 : segment->addSection(ehdr);
285 21 : segment->addSection(phdr_section);
286 : }
287 90 : if (phdr.p_type == PT_PHDR)
288 0 : segment->addSection(phdr_section);
289 3326 : for (int j = 1; j < ehdr->e_shnum; j++)
290 3236 : if (phdr.contains(sections[j]))
291 499 : segment->addSection(sections[j]);
292 : // Make sure that our view of segments corresponds to the original
293 : // ELF file.
294 90 : assert(segment->getFileSize() == phdr.p_filesz);
295 90 : assert(segment->getMemSize() == phdr.p_memsz);
296 90 : segments.push_back(segment);
297 : }
298 :
299 21 : new (&eh_entry) ElfLocation(ehdr->e_entry, this);
300 : }
301 :
302 84 : Elf::~Elf()
303 : {
304 136 : for (std::vector<ElfSegment *>::iterator seg = segments.begin(); seg != segments.end(); seg++)
305 94 : delete *seg;
306 42 : delete[] sections;
307 42 : ElfSection *section = ehdr;
308 1238 : while (section != NULL) {
309 1154 : ElfSection *next = section->getNext();
310 1154 : delete section;
311 1154 : section = next;
312 : }
313 42 : }
314 :
315 : // TODO: This shouldn't fail after inserting sections
316 6740860 : ElfSection *Elf::getSection(int index)
317 : {
318 6740860 : if ((index < -1) || (index >= ehdr->e_shnum))
319 0 : throw std::runtime_error("Section index out of bounds");
320 6740860 : if (index == -1)
321 986 : index = ehdr->e_shstrndx; // TODO: should be fixed to use the actual current number
322 : // Special case: the section at index 0 is void
323 6740860 : if (index == 0)
324 9115 : return NULL;
325 : // Infinite recursion guard
326 6731745 : if (sections[index] == (ElfSection *)this)
327 84 : return NULL;
328 6731661 : if (sections[index] == NULL) {
329 986 : sections[index] = (ElfSection *)this;
330 986 : switch (tmp_shdr[index]->sh_type) {
331 : case SHT_DYNAMIC:
332 21 : sections[index] = new ElfDynamic_Section(*tmp_shdr[index], tmp_file, this);
333 21 : break;
334 : case SHT_REL:
335 63 : sections[index] = new ElfRel_Section<Elf_Rel>(*tmp_shdr[index], tmp_file, this);
336 63 : break;
337 : case SHT_RELA:
338 0 : sections[index] = new ElfRel_Section<Elf_Rela>(*tmp_shdr[index], tmp_file, this);
339 0 : break;
340 : case SHT_DYNSYM:
341 : case SHT_SYMTAB:
342 63 : sections[index] = new ElfSymtab_Section(*tmp_shdr[index], tmp_file, this);
343 63 : break;
344 : case SHT_STRTAB:
345 105 : sections[index] = new ElfStrtab_Section(*tmp_shdr[index], tmp_file, this);
346 105 : break;
347 : default:
348 734 : sections[index] = new ElfSection(*tmp_shdr[index], tmp_file, this);
349 : }
350 : }
351 6731661 : return sections[index];
352 : }
353 :
354 311842 : ElfSection *Elf::getSectionAt(unsigned int offset)
355 : {
356 6336980 : for (int i = 1; i < ehdr->e_shnum; i++) {
357 6336980 : ElfSection *section = getSection(i);
358 18411486 : if ((section != NULL) && (section->getFlags() & SHF_ALLOC) && !(section->getFlags() & SHF_TLS) &&
359 12074506 : (offset >= section->getAddr()) && (offset < section->getAddr() + section->getSize()))
360 311842 : return section;
361 : }
362 0 : return NULL;
363 : }
364 :
365 21 : ElfSegment *Elf::getSegmentByType(unsigned int type)
366 : {
367 111 : for (std::vector<ElfSegment *>::iterator seg = segments.begin(); seg != segments.end(); seg++)
368 90 : if ((*seg)->getType() == type)
369 0 : return *seg;
370 21 : return NULL;
371 : }
372 :
373 42 : ElfDynamic_Section *Elf::getDynSection()
374 : {
375 126 : for (std::vector<ElfSegment *>::iterator seg = segments.begin(); seg != segments.end(); seg++)
376 168 : if (((*seg)->getType() == PT_DYNAMIC) && ((*seg)->getFirstSection() != NULL) &&
377 42 : (*seg)->getFirstSection()->getType() == SHT_DYNAMIC)
378 42 : return (ElfDynamic_Section *)(*seg)->getFirstSection();
379 :
380 0 : return NULL;
381 : }
382 :
383 4 : void Elf::write(std::ofstream &file)
384 : {
385 : // fixup section headers sh_name; TODO: that should be done by sections
386 : // themselves
387 163 : for (ElfSection *section = ehdr; section != NULL; section = section->getNext()) {
388 159 : if (section->getIndex() == 0)
389 12 : continue;
390 : else
391 147 : ehdr->e_shnum = section->getIndex() + 1;
392 147 : section->getShdr().sh_name = eh_shstrndx->getStrIndex(section->getName());
393 : }
394 4 : ehdr->markDirty();
395 : // Adjust PT_LOAD segments
396 4 : int i = 0;
397 29 : for (std::vector<ElfSegment *>::iterator seg = segments.begin(); seg != segments.end(); seg++, i++) {
398 25 : if ((*seg)->getType() == PT_LOAD) {
399 12 : std::list<ElfSection *>::iterator it = (*seg)->begin();
400 100 : for (ElfSection *last = *(it++); it != (*seg)->end(); last = *(it++)) {
401 268 : if (((*it)->getType() != SHT_NOBITS) &&
402 176 : ((*it)->getAddr() - last->getAddr()) != ((*it)->getOffset() - last->getOffset())) {
403 4 : std::vector<ElfSegment *>::iterator next = seg;
404 4 : segments.insert(++next, (*seg)->splitBefore(*it));
405 4 : seg = segments.begin() + i;
406 4 : break;
407 : }
408 : }
409 : }
410 : }
411 : // fixup ehdr before writing
412 4 : if (ehdr->e_phnum != segments.size()) {
413 4 : ehdr->e_phnum = segments.size();
414 4 : phdr_section->getShdr().sh_size = segments.size() * Elf_Phdr::size(ehdr->e_ident[EI_CLASS]);
415 4 : phdr_section->getNext()->markDirty();
416 : }
417 : // fixup shdr before writing
418 4 : if (ehdr->e_shnum != shdr_section->getSize() / shdr_section->getEntSize())
419 4 : shdr_section->getShdr().sh_size = ehdr->e_shnum * Elf_Shdr::size(ehdr->e_ident[EI_CLASS]);
420 4 : ehdr->e_shoff = shdr_section->getOffset();
421 4 : ehdr->e_entry = eh_entry.getValue();
422 4 : ehdr->e_shstrndx = eh_shstrndx->getIndex();
423 163 : for (ElfSection *section = ehdr;
424 : section != NULL; section = section->getNext()) {
425 159 : file.seekp(section->getOffset());
426 159 : if (section == phdr_section) {
427 29 : for (std::vector<ElfSegment *>::iterator seg = segments.begin(); seg != segments.end(); seg++) {
428 25 : Elf_Phdr phdr;
429 25 : phdr.p_type = (*seg)->getType();
430 25 : phdr.p_flags = (*seg)->getFlags();
431 25 : phdr.p_offset = (*seg)->getOffset();
432 25 : phdr.p_vaddr = (*seg)->getAddr();
433 25 : phdr.p_paddr = phdr.p_vaddr + (*seg)->getVPDiff();
434 25 : phdr.p_filesz = (*seg)->getFileSize();
435 25 : phdr.p_memsz = (*seg)->getMemSize();
436 25 : phdr.p_align = (*seg)->getAlign();
437 25 : phdr.serialize(file, ehdr->e_ident[EI_CLASS], ehdr->e_ident[EI_DATA]);
438 : }
439 155 : } else if (section == shdr_section) {
440 4 : null_section.serialize(file, ehdr->e_ident[EI_CLASS], ehdr->e_ident[EI_DATA]);
441 163 : for (ElfSection *sec = ehdr; sec!= NULL; sec = sec->getNext()) {
442 159 : if (sec->getType() != SHT_NULL)
443 147 : sec->getShdr().serialize(file, ehdr->e_ident[EI_CLASS], ehdr->e_ident[EI_DATA]);
444 : }
445 : } else
446 151 : section->serialize(file, ehdr->e_ident[EI_CLASS], ehdr->e_ident[EI_DATA]);
447 : }
448 4 : }
449 :
450 1154 : ElfSection::ElfSection(Elf_Shdr &s, std::ifstream *file, Elf *parent)
451 : : shdr(s),
452 239 : link(shdr.sh_link == SHN_UNDEF ? NULL : parent->getSection(shdr.sh_link)),
453 1393 : next(NULL), previous(NULL), index(-1)
454 : {
455 1154 : if ((file == NULL) || (shdr.sh_type == SHT_NULL) || (shdr.sh_type == SHT_NOBITS))
456 212 : data = NULL;
457 : else {
458 942 : data = new char[shdr.sh_size];
459 942 : int pos = file->tellg();
460 942 : file->seekg(shdr.sh_offset);
461 942 : file->read(data, shdr.sh_size);
462 942 : file->seekg(pos);
463 : }
464 1154 : if (shdr.sh_name == 0)
465 168 : name = NULL;
466 : else {
467 986 : ElfStrtab_Section *strtab = (ElfStrtab_Section *) parent->getSection(-1);
468 : // Special case (see elfgeneric.cpp): if strtab is NULL, the
469 : // section being created is the strtab.
470 986 : if (strtab == NULL)
471 42 : name = &data[shdr.sh_name];
472 : else
473 944 : name = strtab->getStr(shdr.sh_name);
474 : }
475 : // Only SHT_REL/SHT_RELA sections use sh_info to store a section
476 : // number.
477 1154 : if ((shdr.sh_type == SHT_REL) || (shdr.sh_type == SHT_RELA))
478 63 : info.section = shdr.sh_info ? parent->getSection(shdr.sh_info) : NULL;
479 : else
480 1091 : info.index = shdr.sh_info;
481 1154 : }
482 :
483 12885272 : unsigned int ElfSection::getAddr()
484 : {
485 12885272 : if (shdr.sh_addr != (Elf32_Word)-1)
486 12885140 : return shdr.sh_addr;
487 :
488 : // It should be safe to adjust sh_addr for all allocated sections that
489 : // are neither SHT_NOBITS nor SHT_PROGBITS
490 132 : if ((previous != NULL) && isRelocatable()) {
491 132 : unsigned int addr = previous->getAddr();
492 132 : if (previous->getType() != SHT_NOBITS)
493 132 : addr += previous->getSize();
494 :
495 132 : if (addr & (getAddrAlign() - 1))
496 58 : addr = (addr | (getAddrAlign() - 1)) + 1;
497 :
498 132 : return (shdr.sh_addr = addr);
499 : }
500 0 : return shdr.sh_addr;
501 : }
502 :
503 2343 : unsigned int ElfSection::getOffset()
504 : {
505 2343 : if (shdr.sh_offset != (Elf32_Word)-1)
506 1481 : return shdr.sh_offset;
507 :
508 862 : if (previous == NULL)
509 4 : return (shdr.sh_offset = 0);
510 :
511 858 : unsigned int offset = previous->getOffset();
512 858 : if (previous->getType() != SHT_NOBITS)
513 830 : offset += previous->getSize();
514 :
515 858 : Elf32_Word align = 0x1000;
516 1376 : for (std::vector<ElfSegment *>::iterator seg = segments.begin(); seg != segments.end(); seg++)
517 518 : align = std::max(align, (*seg)->getAlign());
518 :
519 858 : Elf32_Word mask = align - 1;
520 : // SHF_TLS is used for .tbss which is some kind of special case.
521 858 : if (((getType() != SHT_NOBITS) || (getFlags() & SHF_TLS)) && (getFlags() & SHF_ALLOC)) {
522 511 : if ((getAddr() & mask) < (offset & mask))
523 24 : offset = (offset | mask) + (getAddr() & mask) + 1;
524 : else
525 487 : offset = (offset & ~mask) + (getAddr() & mask);
526 : }
527 858 : if ((getType() != SHT_NOBITS) && (offset & (getAddrAlign() - 1)))
528 36 : offset = (offset | (getAddrAlign() - 1)) + 1;
529 :
530 : // Two subsequent sections can't be mapped in the same page in memory
531 : // if they aren't in the same 4K block on disk.
532 858 : if ((getType() != SHT_NOBITS) && getAddr()) {
533 815 : if (((offset >> 12) != (previous->getOffset() >> 12)) &&
534 306 : ((getAddr() >> 12) == (previous->getAddr() >> 12)))
535 0 : throw std::runtime_error("Moving section would require overlapping segments");
536 : }
537 :
538 858 : return (shdr.sh_offset = offset);
539 : }
540 :
541 374321 : int ElfSection::getIndex()
542 : {
543 374321 : if (index != -1)
544 374036 : return index;
545 285 : if (getType() == SHT_NULL)
546 12 : return (index = 0);
547 : ElfSection *reference;
548 273 : for (reference = previous; (reference != NULL) && (reference->getType() == SHT_NULL); reference = reference->getPrevious());
549 273 : if (reference == NULL)
550 25 : return (index = 1);
551 248 : return (index = reference->getIndex() + 1);
552 : }
553 :
554 415 : Elf_Shdr &ElfSection::getShdr()
555 : {
556 415 : getOffset();
557 415 : if (shdr.sh_link == (Elf32_Word)-1)
558 44 : shdr.sh_link = getLink() ? getLink()->getIndex() : 0;
559 415 : if (shdr.sh_info == (Elf32_Word)-1)
560 40 : shdr.sh_info = ((getType() == SHT_REL) || (getType() == SHT_RELA)) ?
561 8 : (getInfo().section ? getInfo().section->getIndex() : 0) :
562 48 : getInfo().index;
563 :
564 415 : return shdr;
565 : }
566 :
567 94 : ElfSegment::ElfSegment(Elf_Phdr *phdr)
568 : : type(phdr->p_type), v_p_diff(phdr->p_paddr - phdr->p_vaddr),
569 : flags(phdr->p_flags), align(phdr->p_align), vaddr(phdr->p_vaddr),
570 94 : filesz(phdr->p_filesz), memsz(phdr->p_memsz) {}
571 :
572 569 : void ElfSegment::addSection(ElfSection *section)
573 : {
574 : // Make sure all sections in PT_GNU_RELRO won't be moved by elfhack
575 569 : assert(!((type == PT_GNU_RELRO) && (section->isRelocatable())));
576 :
577 : //TODO: Check overlapping sections
578 569 : std::list<ElfSection *>::iterator i;
579 3789 : for (i = sections.begin(); i != sections.end(); ++i)
580 3220 : if ((*i)->getAddr() > section->getAddr())
581 0 : break;
582 569 : sections.insert(i, section);
583 569 : section->addToSegment(this);
584 569 : }
585 :
586 115 : unsigned int ElfSegment::getFileSize()
587 : {
588 115 : if (type == PT_GNU_RELRO)
589 0 : return filesz;
590 :
591 115 : if (sections.empty())
592 25 : return 0;
593 : // Search the last section that is not SHT_NOBITS
594 90 : std::list<ElfSection *>::reverse_iterator i;
595 90 : for (i = sections.rbegin(); (i != sections.rend()) && ((*i)->getType() == SHT_NOBITS); ++i);
596 : // All sections are SHT_NOBITS
597 90 : if (i == sections.rend())
598 4 : return 0;
599 :
600 86 : unsigned int end = (*i)->getAddr() + (*i)->getSize();
601 :
602 86 : return end - sections.front()->getAddr();
603 : }
604 :
605 115 : unsigned int ElfSegment::getMemSize()
606 : {
607 115 : if (type == PT_GNU_RELRO)
608 0 : return memsz;
609 :
610 115 : if (sections.empty())
611 25 : return 0;
612 :
613 90 : unsigned int end = sections.back()->getAddr() + sections.back()->getSize();
614 :
615 90 : return end - sections.front()->getAddr();
616 : }
617 :
618 25 : unsigned int ElfSegment::getOffset()
619 : {
620 25 : if ((type == PT_GNU_RELRO) && !sections.empty() &&
621 0 : (sections.front()->getAddr() != vaddr))
622 0 : throw std::runtime_error("PT_GNU_RELRO segment doesn't start on a section start");
623 :
624 25 : return sections.empty() ? 0 : sections.front()->getOffset();
625 : }
626 :
627 25 : unsigned int ElfSegment::getAddr()
628 : {
629 25 : if ((type == PT_GNU_RELRO) && !sections.empty() &&
630 0 : (sections.front()->getAddr() != vaddr))
631 0 : throw std::runtime_error("PT_GNU_RELRO segment doesn't start on a section start");
632 :
633 25 : return sections.empty() ? 0 : sections.front()->getAddr();
634 : }
635 :
636 4 : ElfSegment *ElfSegment::splitBefore(ElfSection *section)
637 : {
638 4 : std::list<ElfSection *>::iterator i, rm;
639 4 : for (i = sections.begin(); (*i != section) && (i != sections.end()); ++i);
640 4 : if (i == sections.end())
641 0 : return NULL;
642 :
643 : // Probably very wrong.
644 4 : Elf_Phdr phdr;
645 4 : phdr.p_type = type;
646 4 : phdr.p_vaddr = 0;
647 4 : phdr.p_paddr = phdr.p_vaddr + v_p_diff;
648 4 : phdr.p_flags = flags;
649 4 : phdr.p_align = getAlign();
650 4 : phdr.p_filesz = (unsigned int)-1;
651 4 : phdr.p_memsz = (unsigned int)-1;
652 4 : ElfSegment *segment = new ElfSegment(&phdr);
653 :
654 32 : for (rm = i; i != sections.end(); ++i) {
655 28 : (*i)->removeFromSegment(this);
656 28 : segment->addSection(*i);
657 : }
658 4 : sections.erase(rm, sections.end());
659 :
660 4 : return segment;
661 : }
662 :
663 168 : ElfValue *ElfDynamic_Section::getValueForType(unsigned int tag)
664 : {
665 3599 : for (unsigned int i = 0; i < shdr.sh_size / shdr.sh_entsize; i++)
666 3599 : if (dyns[i].tag == tag)
667 168 : return dyns[i].value;
668 :
669 0 : return NULL;
670 : }
671 :
672 147 : ElfSection *ElfDynamic_Section::getSectionForType(unsigned int tag)
673 : {
674 147 : ElfValue *value = getValueForType(tag);
675 147 : return value ? value->getSection() : NULL;
676 : }
677 :
678 42 : void ElfDynamic_Section::setValueForType(unsigned int tag, ElfValue *val)
679 : {
680 : unsigned int i;
681 917 : for (i = 0; (i < shdr.sh_size / shdr.sh_entsize) && (dyns[i].tag != DT_NULL); i++)
682 917 : if (dyns[i].tag == tag) {
683 42 : delete dyns[i].value;
684 42 : dyns[i].value = val;
685 42 : return;
686 : }
687 : // This should never happen, as the last entry is always tagged DT_NULL
688 0 : assert(i < shdr.sh_size / shdr.sh_entsize);
689 : // If we get here, this means we didn't match for the given tag
690 0 : dyns[i].tag = tag;
691 0 : dyns[i++].value = val;
692 :
693 : // If we were on the last entry, we need to grow the section.
694 : // Most of the time, though, there are a few DT_NULL entries.
695 0 : if (i < shdr.sh_size / shdr.sh_entsize)
696 0 : return;
697 :
698 : Elf_DynValue value;
699 0 : value.tag = DT_NULL;
700 0 : value.value = NULL;
701 0 : dyns.push_back(value);
702 : // Resize the section accordingly
703 0 : shdr.sh_size += shdr.sh_entsize;
704 0 : if (getNext() != NULL)
705 0 : getNext()->markDirty();
706 : }
707 :
708 21 : ElfDynamic_Section::ElfDynamic_Section(Elf_Shdr &s, std::ifstream *file, Elf *parent)
709 21 : : ElfSection(s, file, parent)
710 : {
711 21 : int pos = file->tellg();
712 21 : dyns.resize(s.sh_size / s.sh_entsize);
713 21 : file->seekg(shdr.sh_offset);
714 : // Here we assume tags refer to only one section (e.g. DT_RELSZ accounts
715 : // for .rel.dyn size)
716 771 : for (unsigned int i = 0; i < s.sh_size / s.sh_entsize; i++) {
717 750 : Elf_Dyn dyn(*file, parent->getClass(), parent->getData());
718 750 : dyns[i].tag = dyn.d_tag;
719 750 : switch (dyn.d_tag) {
720 : case DT_NULL:
721 : case DT_SYMBOLIC:
722 : case DT_TEXTREL:
723 : case DT_BIND_NOW:
724 110 : dyns[i].value = new ElfValue();
725 110 : break;
726 : case DT_NEEDED:
727 : case DT_SONAME:
728 : case DT_RPATH:
729 : case DT_PLTREL:
730 : case DT_RUNPATH:
731 : case DT_FLAGS:
732 : case DT_RELACOUNT:
733 : case DT_RELCOUNT:
734 : case DT_VERDEFNUM:
735 : case DT_VERNEEDNUM:
736 317 : dyns[i].value = new ElfPlainValue(dyn.d_un.d_val);
737 317 : break;
738 : case DT_PLTGOT:
739 : case DT_HASH:
740 : case DT_STRTAB:
741 : case DT_SYMTAB:
742 : case DT_RELA:
743 : case DT_INIT:
744 : case DT_FINI:
745 : case DT_REL:
746 : case DT_JMPREL:
747 : case DT_INIT_ARRAY:
748 : case DT_FINI_ARRAY:
749 : case DT_GNU_HASH:
750 : case DT_VERSYM:
751 : case DT_VERNEED:
752 : case DT_VERDEF:
753 218 : dyns[i].value = new ElfLocation(dyn.d_un.d_ptr, parent);
754 218 : break;
755 : default:
756 105 : dyns[i].value = NULL;
757 : }
758 : }
759 : // Another loop to get the section sizes
760 771 : for (unsigned int i = 0; i < s.sh_size / s.sh_entsize; i++)
761 750 : switch (dyns[i].tag) {
762 : case DT_PLTRELSZ:
763 21 : dyns[i].value = new ElfSize(getSectionForType(DT_JMPREL));
764 21 : break;
765 : case DT_RELASZ:
766 0 : dyns[i].value = new ElfSize(getSectionForType(DT_RELA));
767 0 : break;
768 : case DT_STRSZ:
769 21 : dyns[i].value = new ElfSize(getSectionForType(DT_STRTAB));
770 21 : break;
771 : case DT_RELSZ:
772 21 : dyns[i].value = new ElfSize(getSectionForType(DT_REL));
773 21 : break;
774 : case DT_INIT_ARRAYSZ:
775 0 : dyns[i].value = new ElfSize(getSectionForType(DT_INIT_ARRAY));
776 0 : break;
777 : case DT_FINI_ARRAYSZ:
778 0 : dyns[i].value = new ElfSize(getSectionForType(DT_FINI_ARRAY));
779 0 : break;
780 : case DT_RELAENT:
781 0 : dyns[i].value = new ElfEntSize(getSectionForType(DT_RELA));
782 0 : break;
783 : case DT_SYMENT:
784 21 : dyns[i].value = new ElfEntSize(getSectionForType(DT_SYMTAB));
785 21 : break;
786 : case DT_RELENT:
787 21 : dyns[i].value = new ElfEntSize(getSectionForType(DT_REL));
788 21 : break;
789 : }
790 :
791 21 : file->seekg(pos);
792 21 : }
793 :
794 63 : ElfDynamic_Section::~ElfDynamic_Section()
795 : {
796 771 : for (unsigned int i = 0; i < shdr.sh_size / shdr.sh_entsize; i++)
797 750 : delete dyns[i].value;
798 42 : }
799 :
800 4 : void ElfDynamic_Section::serialize(std::ofstream &file, char ei_class, char ei_data)
801 : {
802 149 : for (unsigned int i = 0; i < shdr.sh_size / shdr.sh_entsize; i++) {
803 145 : Elf_Dyn dyn;
804 145 : dyn.d_tag = dyns[i].tag;
805 145 : dyn.d_un.d_val = (dyns[i].value != NULL) ? dyns[i].value->getValue() : 0;
806 145 : dyn.serialize(file, ei_class, ei_data);
807 : }
808 4 : }
809 :
810 63 : ElfSymtab_Section::ElfSymtab_Section(Elf_Shdr &s, std::ifstream *file, Elf *parent)
811 63 : : ElfSection(s, file, parent)
812 : {
813 63 : int pos = file->tellg();
814 63 : syms.resize(s.sh_size / s.sh_entsize);
815 63 : ElfStrtab_Section *strtab = (ElfStrtab_Section *)getLink();
816 63 : file->seekg(shdr.sh_offset);
817 406012 : for (unsigned int i = 0; i < shdr.sh_size / shdr.sh_entsize; i++) {
818 405949 : Elf_Sym sym(*file, parent->getClass(), parent->getData());
819 405949 : syms[i].name = strtab->getStr(sym.st_name);
820 405949 : syms[i].info = sym.st_info;
821 405949 : syms[i].other = sym.st_other;
822 405949 : ElfSection *section = (sym.st_shndx == SHN_ABS) ? NULL : parent->getSection(sym.st_shndx);
823 405949 : new (&syms[i].value) ElfLocation(section, sym.st_value, ElfLocation::ABSOLUTE);
824 405949 : syms[i].size = sym.st_size;
825 405949 : syms[i].defined = (sym.st_shndx != SHN_UNDEF);
826 : }
827 63 : file->seekg(pos);
828 63 : }
829 :
830 : void
831 8 : ElfSymtab_Section::serialize(std::ofstream &file, char ei_class, char ei_data)
832 : {
833 8 : ElfStrtab_Section *strtab = (ElfStrtab_Section *)getLink();
834 382002 : for (unsigned int i = 0; i < shdr.sh_size / shdr.sh_entsize; i++) {
835 381994 : Elf_Sym sym;
836 381994 : sym.st_name = strtab->getStrIndex(syms[i].name);
837 381994 : sym.st_info = syms[i].info;
838 381994 : sym.st_other = syms[i].other;
839 381994 : sym.st_value = syms[i].value.getValue();
840 381994 : ElfSection *section = syms[i].value.getSection();
841 381994 : if (syms[i].defined)
842 376889 : sym.st_shndx = section ? section->getIndex() : SHN_ABS;
843 : else
844 5105 : sym.st_shndx = SHN_UNDEF;
845 381994 : sym.st_size = syms[i].size;
846 381994 : sym.serialize(file, ei_class, ei_data);
847 : }
848 8 : }
849 :
850 : Elf_SymValue *
851 42 : ElfSymtab_Section::lookup(const char *name, unsigned int type_filter)
852 : {
853 14892 : for (std::vector<Elf_SymValue>::iterator sym = syms.begin();
854 7446 : sym != syms.end(); sym++) {
855 14568 : if ((type_filter & (1 << ELF32_ST_TYPE(sym->info))) &&
856 7138 : (strcmp(sym->name, name) == 0)) {
857 26 : return &*sym;
858 : }
859 : }
860 16 : return NULL;
861 : }
862 :
863 : const char *
864 406893 : ElfStrtab_Section::getStr(unsigned int index)
865 : {
866 813786 : for (std::vector<table_storage>::iterator t = table.begin();
867 406893 : t != table.end(); t++) {
868 406893 : if (index < t->used)
869 406893 : return t->buf + index;
870 0 : index -= t->used;
871 : }
872 0 : assert(1 == 0);
873 : return NULL;
874 : }
875 :
876 : const char *
877 382141 : ElfStrtab_Section::getStr(const char *string)
878 : {
879 382141 : if (string == NULL)
880 0 : return NULL;
881 :
882 : // If the given string is within the section, return it
883 764306 : for (std::vector<table_storage>::iterator t = table.begin();
884 382153 : t != table.end(); t++)
885 382145 : if ((string >= t->buf) && (string < t->buf + t->used))
886 382133 : return string;
887 :
888 : // TODO: should scan in the section to find an existing string
889 :
890 : // If not, we need to allocate the string in the section
891 8 : size_t len = strlen(string) + 1;
892 :
893 8 : if (table.back().size - table.back().used < len)
894 4 : table.resize(table.size() + 1);
895 :
896 8 : char *alloc_str = table.back().buf + table.back().used;
897 8 : memcpy(alloc_str, string, len);
898 8 : table.back().used += len;
899 :
900 8 : shdr.sh_size += len;
901 8 : markDirty();
902 :
903 8 : return alloc_str;
904 : }
905 :
906 : unsigned int
907 382141 : ElfStrtab_Section::getStrIndex(const char *string)
908 : {
909 382141 : if (string == NULL)
910 0 : return 0;
911 :
912 382141 : unsigned int index = 0;
913 382141 : string = getStr(string);
914 764298 : for (std::vector<table_storage>::iterator t = table.begin();
915 382149 : t != table.end(); t++) {
916 382149 : if ((string >= t->buf) && (string < t->buf + t->used))
917 382141 : return index + (string - t->buf);
918 8 : index += t->used;
919 : }
920 :
921 0 : assert(1 == 0);
922 : return 0;
923 : }
924 :
925 : void
926 12 : ElfStrtab_Section::serialize(std::ofstream &file, char ei_class, char ei_data)
927 : {
928 12 : file.seekp(getOffset());
929 56 : for (std::vector<table_storage>::iterator t = table.begin();
930 28 : t != table.end(); t++)
931 16 : file.write(t->buf, t->used);
932 18 : }
|