Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 #include "mozilla/NullPtr.h"
7 #include <stdexcept>
8 #include <list>
9 #include <vector>
10 #include <cstring>
11 #include <iostream>
12 #include <fstream>
13 #include <algorithm>
14 #include <elf.h>
15 #include <asm/byteorder.h>
17 // Technically, __*_to_cpu and __cpu_to* function are equivalent,
18 // so swap can use either of both.
19 #define def_swap(endian, type, bits) \
20 static inline type ## bits ## _t swap(type ## bits ## _t i) { \
21 return __ ## endian ## bits ## _to_cpu(i); \
22 }
24 class little_endian {
25 public:
26 def_swap(le, uint, 16);
27 def_swap(le, uint, 32);
28 def_swap(le, uint, 64);
29 def_swap(le, int, 16);
30 def_swap(le, int, 32);
31 def_swap(le, int, 64);
32 };
34 class big_endian {
35 public:
36 def_swap(be, uint, 16);
37 def_swap(be, uint, 32);
38 def_swap(be, uint, 64);
39 def_swap(be, int, 16);
40 def_swap(be, int, 32);
41 def_swap(be, int, 64);
42 };
44 // forward declaration
45 class ElfSection;
46 class ElfSegment;
47 // TODO: Rename Elf_* types
48 class Elf_Ehdr;
49 class Elf_Phdr;
50 class Elf;
51 class ElfDynamic_Section;
52 class ElfStrtab_Section;
54 class Elf_Ehdr_Traits {
55 public:
56 typedef Elf32_Ehdr Type32;
57 typedef Elf64_Ehdr Type64;
59 template <class endian, typename R, typename T>
60 static void swap(T &t, R &r);
61 };
63 class Elf_Phdr_Traits {
64 public:
65 typedef Elf32_Phdr Type32;
66 typedef Elf64_Phdr Type64;
68 template <class endian, typename R, typename T>
69 static void swap(T &t, R &r);
70 };
72 class Elf_Shdr_Traits {
73 public:
74 typedef Elf32_Shdr Type32;
75 typedef Elf64_Shdr Type64;
77 template <class endian, typename R, typename T>
78 static void swap(T &t, R &r);
79 };
81 class Elf_Dyn_Traits {
82 public:
83 typedef Elf32_Dyn Type32;
84 typedef Elf64_Dyn Type64;
86 template <class endian, typename R, typename T>
87 static void swap(T &t, R &r);
88 };
90 class Elf_Sym_Traits {
91 public:
92 typedef Elf32_Sym Type32;
93 typedef Elf64_Sym Type64;
95 template <class endian, typename R, typename T>
96 static void swap(T &t, R &r);
97 };
99 class Elf_Rel_Traits {
100 public:
101 typedef Elf32_Rel Type32;
102 typedef Elf64_Rel Type64;
104 template <class endian, typename R, typename T>
105 static void swap(T &t, R &r);
106 };
108 class Elf_Rela_Traits {
109 public:
110 typedef Elf32_Rela Type32;
111 typedef Elf64_Rela Type64;
113 template <class endian, typename R, typename T>
114 static void swap(T &t, R &r);
115 };
117 class ElfValue {
118 public:
119 virtual unsigned int getValue() { return 0; }
120 virtual ElfSection *getSection() { return nullptr; }
121 };
123 class ElfPlainValue: public ElfValue {
124 unsigned int value;
125 public:
126 ElfPlainValue(unsigned int val): value(val) {};
127 unsigned int getValue() { return value; }
128 };
130 class ElfLocation: public ElfValue {
131 ElfSection *section;
132 unsigned int offset;
133 public:
134 enum position { ABSOLUTE, RELATIVE };
135 ElfLocation(): section(nullptr), offset(0) {};
136 ElfLocation(ElfSection *section, unsigned int off, enum position pos = RELATIVE);
137 ElfLocation(unsigned int location, Elf *elf);
138 unsigned int getValue();
139 ElfSection *getSection() { return section; }
140 const char *getBuffer();
141 };
143 class ElfSize: public ElfValue {
144 ElfSection *section;
145 public:
146 ElfSize(ElfSection *s): section(s) {};
147 unsigned int getValue();
148 ElfSection *getSection() { return section; }
149 };
151 class ElfEntSize: public ElfValue {
152 ElfSection *section;
153 public:
154 ElfEntSize(ElfSection *s): section(s) {};
155 unsigned int getValue();
156 ElfSection *getSection() { return section; }
157 };
159 template <typename T>
160 class serializable: public T::Type32 {
161 public:
162 serializable() {};
163 serializable(const typename T::Type32 &p): T::Type32(p) {};
165 private:
166 template <typename R>
167 void init(const char *buf, size_t len, char ei_data)
168 {
169 R e;
170 assert(len >= sizeof(e));
171 memcpy(&e, buf, sizeof(e));
172 if (ei_data == ELFDATA2LSB) {
173 T::template swap<little_endian>(e, *this);
174 return;
175 } else if (ei_data == ELFDATA2MSB) {
176 T::template swap<big_endian>(e, *this);
177 return;
178 }
179 throw std::runtime_error("Unsupported ELF data encoding");
180 }
182 template <typename R>
183 void serialize(const char *buf, size_t len, char ei_data)
184 {
185 assert(len >= sizeof(R));
186 if (ei_data == ELFDATA2LSB) {
187 T::template swap<little_endian>(*this, *(R *)buf);
188 return;
189 } else if (ei_data == ELFDATA2MSB) {
190 T::template swap<big_endian>(*this, *(R *)buf);
191 return;
192 }
193 throw std::runtime_error("Unsupported ELF data encoding");
194 }
196 public:
197 serializable(const char *buf, size_t len, char ei_class, char ei_data)
198 {
199 if (ei_class == ELFCLASS32) {
200 init<typename T::Type32>(buf, len, ei_data);
201 return;
202 } else if (ei_class == ELFCLASS64) {
203 init<typename T::Type64>(buf, len, ei_data);
204 return;
205 }
206 throw std::runtime_error("Unsupported ELF class");
207 }
209 serializable(std::ifstream &file, char ei_class, char ei_data)
210 {
211 if (ei_class == ELFCLASS32) {
212 typename T::Type32 e;
213 file.read((char *)&e, sizeof(e));
214 init<typename T::Type32>((char *)&e, sizeof(e), ei_data);
215 return;
216 } else if (ei_class == ELFCLASS64) {
217 typename T::Type64 e;
218 file.read((char *)&e, sizeof(e));
219 init<typename T::Type64>((char *)&e, sizeof(e), ei_data);
220 return;
221 }
222 throw std::runtime_error("Unsupported ELF class or data encoding");
223 }
225 void serialize(std::ofstream &file, char ei_class, char ei_data)
226 {
227 if (ei_class == ELFCLASS32) {
228 typename T::Type32 e;
229 serialize<typename T::Type32>((char *)&e, sizeof(e), ei_data);
230 file.write((char *)&e, sizeof(e));
231 return;
232 } else if (ei_class == ELFCLASS64) {
233 typename T::Type64 e;
234 serialize<typename T::Type64>((char *)&e, sizeof(e), ei_data);
235 file.write((char *)&e, sizeof(e));
236 return;
237 }
238 throw std::runtime_error("Unsupported ELF class or data encoding");
239 }
241 void serialize(char *buf, size_t len, char ei_class, char ei_data)
242 {
243 if (ei_class == ELFCLASS32) {
244 serialize<typename T::Type32>(buf, len, ei_data);
245 return;
246 } else if (ei_class == ELFCLASS64) {
247 serialize<typename T::Type64>(buf, len, ei_data);
248 return;
249 }
250 throw std::runtime_error("Unsupported ELF class");
251 }
253 static inline unsigned int size(char ei_class)
254 {
255 if (ei_class == ELFCLASS32)
256 return sizeof(typename T::Type32);
257 else if (ei_class == ELFCLASS64)
258 return sizeof(typename T::Type64);
259 return 0;
260 }
261 };
263 typedef serializable<Elf_Shdr_Traits> Elf_Shdr;
265 class Elf {
266 public:
267 Elf(std::ifstream &file);
268 ~Elf();
270 /* index == -1 is treated as index == ehdr.e_shstrndx */
271 ElfSection *getSection(int index);
273 ElfSection *getSectionAt(unsigned int offset);
275 ElfSegment *getSegmentByType(unsigned int type, ElfSegment *last = nullptr);
277 ElfDynamic_Section *getDynSection();
279 void normalize();
280 void write(std::ofstream &file);
282 char getClass();
283 char getData();
284 char getType();
285 char getMachine();
286 unsigned int getSize();
288 void insertSegmentAfter(ElfSegment *previous, ElfSegment *segment) {
289 std::vector<ElfSegment *>::iterator prev = std::find(segments.begin(), segments.end(), previous);
290 segments.insert(prev + 1, segment);
291 }
293 void removeSegment(ElfSegment *segment);
295 private:
296 Elf_Ehdr *ehdr;
297 ElfLocation eh_entry;
298 ElfStrtab_Section *eh_shstrndx;
299 ElfSection **sections;
300 std::vector<ElfSegment *> segments;
301 ElfSection *shdr_section, *phdr_section;
302 /* Values used only during initialization */
303 Elf_Shdr **tmp_shdr;
304 std::ifstream *tmp_file;
305 };
307 class ElfSection {
308 public:
309 typedef union {
310 ElfSection *section;
311 int index;
312 } SectionInfo;
314 ElfSection(Elf_Shdr &s, std::ifstream *file, Elf *parent);
316 virtual ~ElfSection() {
317 delete[] data;
318 }
320 const char *getName() { return name; }
321 unsigned int getType() { return shdr.sh_type; }
322 unsigned int getFlags() { return shdr.sh_flags; }
323 unsigned int getAddr();
324 unsigned int getSize() { return shdr.sh_size; }
325 unsigned int getAddrAlign() { return shdr.sh_addralign; }
326 unsigned int getEntSize() { return shdr.sh_entsize; }
327 const char *getData() { return data; }
328 ElfSection *getLink() { return link; }
329 SectionInfo getInfo() { return info; }
331 void shrink(unsigned int newsize) {
332 if (newsize < shdr.sh_size)
333 shdr.sh_size = newsize;
334 }
336 unsigned int getOffset();
337 int getIndex();
338 Elf_Shdr &getShdr();
340 ElfSection *getNext() { return next; }
341 ElfSection *getPrevious() { return previous; }
343 virtual bool isRelocatable() {
344 return ((getType() == SHT_SYMTAB) ||
345 (getType() == SHT_STRTAB) ||
346 (getType() == SHT_RELA) ||
347 (getType() == SHT_HASH) ||
348 (getType() == SHT_NOTE) ||
349 (getType() == SHT_REL) ||
350 (getType() == SHT_DYNSYM) ||
351 (getType() == SHT_GNU_HASH) ||
352 (getType() == SHT_GNU_verdef) ||
353 (getType() == SHT_GNU_verneed) ||
354 (getType() == SHT_GNU_versym) ||
355 getSegmentByType(PT_INTERP)) &&
356 (getFlags() & SHF_ALLOC);
357 }
359 void insertAfter(ElfSection *section, bool dirty = true) {
360 if (previous != nullptr)
361 previous->next = next;
362 if (next != nullptr)
363 next->previous = previous;
364 previous = section;
365 if (section != nullptr) {
366 next = section->next;
367 section->next = this;
368 } else
369 next = nullptr;
370 if (next != nullptr)
371 next->previous = this;
372 if (dirty)
373 markDirty();
374 insertInSegments(section->segments);
375 }
377 void insertBefore(ElfSection *section, bool dirty = true) {
378 if (previous != nullptr)
379 previous->next = next;
380 if (next != nullptr)
381 next->previous = previous;
382 next = section;
383 if (section != nullptr) {
384 previous = section->previous;
385 section->previous = this;
386 } else
387 previous = nullptr;
388 if (previous != nullptr)
389 previous->next = this;
390 if (dirty)
391 markDirty();
392 insertInSegments(section->segments);
393 }
395 void markDirty() {
396 if (link != nullptr)
397 shdr.sh_link = -1;
398 if (info.index)
399 shdr.sh_info = -1;
400 shdr.sh_offset = -1;
401 if (isRelocatable())
402 shdr.sh_addr = -1;
403 if (next)
404 next->markDirty();
405 }
407 virtual void serialize(std::ofstream &file, char ei_class, char ei_data)
408 {
409 if (getType() == SHT_NOBITS)
410 return;
411 file.seekp(getOffset());
412 file.write(data, getSize());
413 }
415 private:
416 friend class ElfSegment;
418 void addToSegment(ElfSegment *segment) {
419 segments.push_back(segment);
420 }
422 void removeFromSegment(ElfSegment *segment) {
423 std::vector<ElfSegment *>::iterator i = std::find(segments.begin(), segments.end(), segment);
424 segments.erase(i, i + 1);
425 }
427 ElfSegment *getSegmentByType(unsigned int type);
429 void insertInSegments(std::vector<ElfSegment *> &segs);
431 protected:
432 Elf_Shdr shdr;
433 char *data;
434 const char *name;
435 private:
436 ElfSection *link;
437 SectionInfo info;
438 ElfSection *next, *previous;
439 int index;
440 std::vector<ElfSegment *> segments;
441 };
443 class ElfSegment {
444 public:
445 ElfSegment(Elf_Phdr *phdr);
447 unsigned int getType() { return type; }
448 unsigned int getFlags() { return flags; }
449 unsigned int getAlign() { return align; }
451 ElfSection *getFirstSection() { return sections.empty() ? nullptr : sections.front(); }
452 int getVPDiff() { return v_p_diff; }
453 unsigned int getFileSize();
454 unsigned int getMemSize();
455 unsigned int getOffset();
456 unsigned int getAddr();
458 void addSection(ElfSection *section);
459 void removeSection(ElfSection *section);
461 std::list<ElfSection *>::iterator begin() { return sections.begin(); }
462 std::list<ElfSection *>::iterator end() { return sections.end(); }
464 void clear();
466 bool isElfHackFillerSegment() {
467 return type == PT_LOAD && flags == 0;
468 }
469 private:
470 unsigned int type;
471 int v_p_diff; // Difference between physical and virtual address
472 unsigned int flags;
473 unsigned int align;
474 std::list<ElfSection *> sections;
475 // The following are only really used for PT_GNU_RELRO until something
476 // better is found.
477 unsigned int vaddr;
478 unsigned int filesz, memsz;
479 };
481 class Elf_Ehdr: public serializable<Elf_Ehdr_Traits>, public ElfSection {
482 public:
483 Elf_Ehdr(std::ifstream &file, char ei_class, char ei_data);
484 void serialize(std::ofstream &file, char ei_class, char ei_data)
485 {
486 serializable<Elf_Ehdr_Traits>::serialize(file, ei_class, ei_data);
487 }
488 };
490 class Elf_Phdr: public serializable<Elf_Phdr_Traits> {
491 public:
492 Elf_Phdr() {};
493 Elf_Phdr(std::ifstream &file, char ei_class, char ei_data)
494 : serializable<Elf_Phdr_Traits>(file, ei_class, ei_data) {};
495 bool contains(ElfSection *section)
496 {
497 unsigned int size = section->getSize();
498 unsigned int addr = section->getAddr();
499 // This may be biased, but should work in most cases
500 if ((section->getFlags() & SHF_ALLOC) == 0)
501 return false;
502 // Special case for PT_DYNAMIC. Eventually, this should
503 // be better handled than special cases
504 if ((p_type == PT_DYNAMIC) && (section->getType() != SHT_DYNAMIC))
505 return false;
506 // Special case for PT_TLS.
507 if ((p_type == PT_TLS) && !(section->getFlags() & SHF_TLS))
508 return false;
509 return (addr >= p_vaddr) &&
510 (addr + size <= p_vaddr + p_memsz);
512 }
513 };
515 typedef serializable<Elf_Dyn_Traits> Elf_Dyn;
517 struct Elf_DynValue {
518 unsigned int tag;
519 ElfValue *value;
520 };
522 class ElfDynamic_Section: public ElfSection {
523 public:
524 ElfDynamic_Section(Elf_Shdr &s, std::ifstream *file, Elf *parent);
525 ~ElfDynamic_Section();
527 void serialize(std::ofstream &file, char ei_class, char ei_data);
529 ElfValue *getValueForType(unsigned int tag);
530 ElfSection *getSectionForType(unsigned int tag);
531 bool setValueForType(unsigned int tag, ElfValue *val);
532 private:
533 std::vector<Elf_DynValue> dyns;
534 };
536 typedef serializable<Elf_Sym_Traits> Elf_Sym;
538 struct Elf_SymValue {
539 const char *name;
540 unsigned char info;
541 unsigned char other;
542 ElfLocation value;
543 unsigned int size;
544 bool defined;
545 };
547 #define STT(type) (1 << STT_ ##type)
549 class ElfSymtab_Section: public ElfSection {
550 public:
551 ElfSymtab_Section(Elf_Shdr &s, std::ifstream *file, Elf *parent);
553 void serialize(std::ofstream &file, char ei_class, char ei_data);
555 Elf_SymValue *lookup(const char *name, unsigned int type_filter = STT(OBJECT) | STT(FUNC));
557 //private: // Until we have a real API
558 std::vector<Elf_SymValue> syms;
559 };
561 class Elf_Rel: public serializable<Elf_Rel_Traits> {
562 public:
563 Elf_Rel(std::ifstream &file, char ei_class, char ei_data)
564 : serializable<Elf_Rel_Traits>(file, ei_class, ei_data) {};
566 static const unsigned int sh_type = SHT_REL;
567 static const unsigned int d_tag = DT_REL;
568 static const unsigned int d_tag_count = DT_RELCOUNT;
569 };
571 class Elf_Rela: public serializable<Elf_Rela_Traits> {
572 public:
573 Elf_Rela(std::ifstream &file, char ei_class, char ei_data)
574 : serializable<Elf_Rela_Traits>(file, ei_class, ei_data) {};
576 static const unsigned int sh_type = SHT_RELA;
577 static const unsigned int d_tag = DT_RELA;
578 static const unsigned int d_tag_count = DT_RELACOUNT;
579 };
581 template <class Rel>
582 class ElfRel_Section: public ElfSection {
583 public:
584 ElfRel_Section(Elf_Shdr &s, std::ifstream *file, Elf *parent)
585 : ElfSection(s, file, parent)
586 {
587 int pos = file->tellg();
588 file->seekg(shdr.sh_offset);
589 for (unsigned int i = 0; i < s.sh_size / s.sh_entsize; i++) {
590 Rel r(*file, parent->getClass(), parent->getData());
591 rels.push_back(r);
592 }
593 file->seekg(pos);
594 }
596 void serialize(std::ofstream &file, char ei_class, char ei_data)
597 {
598 for (typename std::vector<Rel>::iterator i = rels.begin();
599 i != rels.end(); ++i)
600 (*i).serialize(file, ei_class, ei_data);
601 }
602 //private: // Until we have a real API
603 std::vector<Rel> rels;
604 };
606 class ElfStrtab_Section: public ElfSection {
607 public:
608 ElfStrtab_Section(Elf_Shdr &s, std::ifstream *file, Elf *parent)
609 : ElfSection(s, file, parent)
610 {
611 table.push_back(table_storage(data, shdr.sh_size));
612 }
614 ~ElfStrtab_Section()
615 {
616 for (std::vector<table_storage>::iterator t = table.begin() + 1;
617 t != table.end(); t++)
618 delete[] t->buf;
619 }
621 const char *getStr(unsigned int index);
623 const char *getStr(const char *string);
625 unsigned int getStrIndex(const char *string);
627 void serialize(std::ofstream &file, char ei_class, char ei_data);
628 private:
629 struct table_storage {
630 unsigned int size, used;
631 char *buf;
633 table_storage(): size(4096), used(0), buf(new char[4096]) {}
634 table_storage(const char *data, unsigned int sz)
635 : size(sz), used(sz), buf(const_cast<char *>(data)) {}
636 };
637 std::vector<table_storage> table;
638 };
640 inline char Elf::getClass() {
641 return ehdr->e_ident[EI_CLASS];
642 }
644 inline char Elf::getData() {
645 return ehdr->e_ident[EI_DATA];
646 }
648 inline char Elf::getType() {
649 return ehdr->e_type;
650 }
652 inline char Elf::getMachine() {
653 return ehdr->e_machine;
654 }
656 inline unsigned int Elf::getSize() {
657 ElfSection *section;
658 for (section = shdr_section /* It's usually not far from the end */;
659 section->getNext() != nullptr; section = section->getNext());
660 return section->getOffset() + section->getSize();
661 }
663 inline ElfSegment *ElfSection::getSegmentByType(unsigned int type) {
664 for (std::vector<ElfSegment *>::iterator seg = segments.begin(); seg != segments.end(); seg++)
665 if ((*seg)->getType() == type)
666 return *seg;
667 return nullptr;
668 }
670 inline void ElfSection::insertInSegments(std::vector<ElfSegment *> &segs) {
671 for (std::vector<ElfSegment *>::iterator it = segs.begin(); it != segs.end(); ++it) {
672 (*it)->addSection(this);
673 }
674 }
676 inline ElfLocation::ElfLocation(ElfSection *section, unsigned int off, enum position pos)
677 : section(section) {
678 if ((pos == ABSOLUTE) && section)
679 offset = off - section->getAddr();
680 else
681 offset = off;
682 }
684 inline ElfLocation::ElfLocation(unsigned int location, Elf *elf) {
685 section = elf->getSectionAt(location);
686 offset = location - (section ? section->getAddr() : 0);
687 }
689 inline unsigned int ElfLocation::getValue() {
690 return (section ? section->getAddr() : 0) + offset;
691 }
693 inline const char *ElfLocation::getBuffer() {
694 return section ? section->getData() + offset : nullptr;
695 }
697 inline unsigned int ElfSize::getValue() {
698 return section->getSize();
699 }
701 inline unsigned int ElfEntSize::getValue() {
702 return section->getEntSize();
703 }