Bug 1922904 - Fix bug 1780701 in a different approach. r=botond
[gecko.git] / build / unix / elfhack / elfxx.h
bloba9354185887f1baf3920a23d1ad572414c2f8634
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 <stdexcept>
6 #include <list>
7 #include <vector>
8 #include <cstring>
9 #include <fstream>
10 #include <algorithm>
11 #include <elf.h>
12 #include <asm/byteorder.h>
14 // Technically, __*_to_cpu and __cpu_to* function are equivalent,
15 // so swap can use either of both.
16 #define def_swap(endian, type, bits) \
17 static inline type##bits##_t swap(type##bits##_t i) { \
18 return __##endian##bits##_to_cpu(i); \
21 class little_endian {
22 public:
23 def_swap(le, uint, 16);
24 def_swap(le, uint, 32);
25 def_swap(le, uint, 64);
26 def_swap(le, int, 16);
27 def_swap(le, int, 32);
28 def_swap(le, int, 64);
31 class big_endian {
32 public:
33 def_swap(be, uint, 16);
34 def_swap(be, uint, 32);
35 def_swap(be, uint, 64);
36 def_swap(be, int, 16);
37 def_swap(be, int, 32);
38 def_swap(be, int, 64);
41 // forward declaration
42 class ElfSection;
43 class ElfSegment;
44 // TODO: Rename Elf_* types
45 class Elf_Ehdr;
46 class Elf_Phdr;
47 class Elf;
48 class ElfDynamic_Section;
49 class ElfStrtab_Section;
51 template <typename X>
52 class FixedSizeData {
53 public:
54 struct Wrapper {
55 X value;
57 typedef Wrapper Type32;
58 typedef Wrapper Type64;
60 template <class endian, typename R, typename T>
61 static void swap(T& t, R& r) {
62 r.value = endian::swap(t.value);
66 class Elf_Ehdr_Traits {
67 public:
68 typedef Elf32_Ehdr Type32;
69 typedef Elf64_Ehdr Type64;
71 template <class endian, typename R, typename T>
72 static void swap(T& t, R& r);
75 class Elf_Phdr_Traits {
76 public:
77 typedef Elf32_Phdr Type32;
78 typedef Elf64_Phdr Type64;
80 template <class endian, typename R, typename T>
81 static void swap(T& t, R& r);
84 class Elf_Shdr_Traits {
85 public:
86 typedef Elf32_Shdr Type32;
87 typedef Elf64_Shdr Type64;
89 template <class endian, typename R, typename T>
90 static void swap(T& t, R& r);
93 class Elf_Dyn_Traits {
94 public:
95 typedef Elf32_Dyn Type32;
96 typedef Elf64_Dyn Type64;
98 template <class endian, typename R, typename T>
99 static void swap(T& t, R& r);
102 class Elf_Sym_Traits {
103 public:
104 typedef Elf32_Sym Type32;
105 typedef Elf64_Sym Type64;
107 template <class endian, typename R, typename T>
108 static void swap(T& t, R& r);
111 class Elf_Rel_Traits {
112 public:
113 typedef Elf32_Rel Type32;
114 typedef Elf64_Rel Type64;
116 template <class endian, typename R, typename T>
117 static void swap(T& t, R& r);
120 class Elf_Rela_Traits {
121 public:
122 typedef Elf32_Rela Type32;
123 typedef Elf64_Rela Type64;
125 template <class endian, typename R, typename T>
126 static void swap(T& t, R& r);
129 class ElfValue {
130 public:
131 virtual unsigned int getValue() { return 0; }
132 virtual ElfSection* getSection() { return nullptr; }
135 class ElfPlainValue : public ElfValue {
136 unsigned int value;
138 public:
139 ElfPlainValue(unsigned int val) : value(val) {};
140 unsigned int getValue() { return value; }
143 class ElfLocation : public ElfValue {
144 ElfSection* section;
145 unsigned int offset;
147 public:
148 enum position { ABSOLUTE, RELATIVE };
149 ElfLocation() : section(nullptr), offset(0) {};
150 ElfLocation(ElfSection* section, unsigned int off,
151 enum position pos = RELATIVE);
152 ElfLocation(unsigned int location, Elf* elf);
153 unsigned int getValue();
154 ElfSection* getSection() { return section; }
155 const char* getBuffer();
158 class ElfSize : public ElfValue {
159 ElfSection* section;
161 public:
162 ElfSize(ElfSection* s) : section(s) {};
163 unsigned int getValue();
164 ElfSection* getSection() { return section; }
167 class ElfEntSize : public ElfValue {
168 ElfSection* section;
170 public:
171 ElfEntSize(ElfSection* s) : section(s) {};
172 unsigned int getValue();
173 ElfSection* getSection() { return section; }
176 template <typename T>
177 class serializable : public T::Type64 {
178 public:
179 serializable() {};
180 serializable(const typename T::Type64& p) : T::Type64(p) {};
182 private:
183 template <typename R>
184 void init(const char* buf, size_t len, unsigned char ei_data) {
185 R e;
186 assert(len >= sizeof(e));
187 memcpy(&e, buf, sizeof(e));
188 if (ei_data == ELFDATA2LSB) {
189 T::template swap<little_endian>(e, *this);
190 return;
191 } else if (ei_data == ELFDATA2MSB) {
192 T::template swap<big_endian>(e, *this);
193 return;
195 throw std::runtime_error("Unsupported ELF data encoding");
198 template <typename R>
199 void serialize(const char* buf, size_t len, unsigned char ei_data) {
200 assert(len >= sizeof(R));
201 if (ei_data == ELFDATA2LSB) {
202 T::template swap<little_endian>(*this, *(R*)buf);
203 return;
204 } else if (ei_data == ELFDATA2MSB) {
205 T::template swap<big_endian>(*this, *(R*)buf);
206 return;
208 throw std::runtime_error("Unsupported ELF data encoding");
211 public:
212 serializable(const char* buf, size_t len, unsigned char ei_class,
213 unsigned char ei_data) {
214 if (ei_class == ELFCLASS32) {
215 init<typename T::Type32>(buf, len, ei_data);
216 return;
217 } else if (ei_class == ELFCLASS64) {
218 init<typename T::Type64>(buf, len, ei_data);
219 return;
221 throw std::runtime_error("Unsupported ELF class");
224 serializable(std::ifstream& file, unsigned char ei_class,
225 unsigned char ei_data) {
226 if (ei_class == ELFCLASS32) {
227 typename T::Type32 e;
228 file.read((char*)&e, sizeof(e));
229 init<typename T::Type32>((char*)&e, sizeof(e), ei_data);
230 return;
231 } else if (ei_class == ELFCLASS64) {
232 typename T::Type64 e;
233 file.read((char*)&e, sizeof(e));
234 init<typename T::Type64>((char*)&e, sizeof(e), ei_data);
235 return;
237 throw std::runtime_error("Unsupported ELF class or data encoding");
240 void serialize(std::ofstream& file, unsigned char ei_class,
241 unsigned char ei_data) {
242 if (ei_class == ELFCLASS32) {
243 typename T::Type32 e;
244 serialize<typename T::Type32>((char*)&e, sizeof(e), ei_data);
245 file.write((char*)&e, sizeof(e));
246 return;
247 } else if (ei_class == ELFCLASS64) {
248 typename T::Type64 e;
249 serialize<typename T::Type64>((char*)&e, sizeof(e), ei_data);
250 file.write((char*)&e, sizeof(e));
251 return;
253 throw std::runtime_error("Unsupported ELF class or data encoding");
256 void serialize(char* buf, size_t len, unsigned char ei_class,
257 unsigned char ei_data) {
258 if (ei_class == ELFCLASS32) {
259 serialize<typename T::Type32>(buf, len, ei_data);
260 return;
261 } else if (ei_class == ELFCLASS64) {
262 serialize<typename T::Type64>(buf, len, ei_data);
263 return;
265 throw std::runtime_error("Unsupported ELF class");
268 static inline unsigned int size(unsigned char ei_class) {
269 if (ei_class == ELFCLASS32)
270 return sizeof(typename T::Type32);
271 else if (ei_class == ELFCLASS64)
272 return sizeof(typename T::Type64);
273 return 0;
277 typedef serializable<Elf_Shdr_Traits> Elf_Shdr;
279 class Elf {
280 public:
281 Elf(std::ifstream& file);
282 ~Elf();
284 /* index == -1 is treated as index == ehdr.e_shstrndx */
285 ElfSection* getSection(int index);
287 ElfSection* getSectionAt(Elf64_Off offset);
289 ElfSegment* getSegmentByType(unsigned int type, ElfSegment* last = nullptr);
291 ElfDynamic_Section* getDynSection();
293 void normalize();
294 void write(std::ofstream& file);
296 unsigned char getClass();
297 unsigned char getData();
298 unsigned char getType();
299 unsigned char getMachine();
300 unsigned int getSize();
302 void insertSegmentAfter(ElfSegment* previous, ElfSegment* segment) {
303 std::vector<ElfSegment*>::iterator prev =
304 std::find(segments.begin(), segments.end(), previous);
305 segments.insert(prev + 1, segment);
308 void removeSegment(ElfSegment* segment);
310 private:
311 Elf_Ehdr* ehdr;
312 ElfLocation eh_entry;
313 ElfStrtab_Section* eh_shstrndx;
314 ElfSection** sections;
315 std::vector<ElfSegment*> segments;
316 ElfSection *shdr_section, *phdr_section;
317 /* Values used only during initialization */
318 Elf_Shdr** tmp_shdr;
319 std::ifstream* tmp_file;
322 class ElfSection {
323 public:
324 typedef union {
325 ElfSection* section;
326 int index;
327 } SectionInfo;
329 ElfSection(Elf_Shdr& s, std::ifstream* file, Elf* parent);
331 virtual ~ElfSection() { free(data); }
333 const char* getName() { return name; }
334 unsigned int getType() { return shdr.sh_type; }
335 unsigned int getFlags() { return shdr.sh_flags; }
336 Elf64_Addr getAddr();
337 Elf64_Off getSize() { return shdr.sh_size; }
338 unsigned int getAddrAlign() { return shdr.sh_addralign; }
339 unsigned int getEntSize() { return shdr.sh_entsize; }
340 const char* getData() { return data; }
341 ElfSection* getLink() { return link; }
342 SectionInfo getInfo() { return info; }
344 void shrink(unsigned int newsize) {
345 if (newsize < shdr.sh_size) {
346 shdr.sh_size = newsize;
347 markDirty();
351 void grow(unsigned int newsize) {
352 if (newsize > shdr.sh_size) {
353 data = static_cast<char*>(realloc(data, newsize));
354 memset(data + shdr.sh_size, 0, newsize - shdr.sh_size);
355 shdr.sh_size = newsize;
356 markDirty();
360 Elf64_Off getOffset();
361 int getIndex();
362 Elf_Shdr& getShdr();
364 ElfSection* getNext() { return next; }
365 ElfSection* getPrevious() { return previous; }
367 virtual bool isRelocatable() {
368 return ((getType() == SHT_SYMTAB) || (getType() == SHT_STRTAB) ||
369 (getType() == SHT_RELA) || (getType() == SHT_HASH) ||
370 (getType() == SHT_NOTE) || (getType() == SHT_REL) ||
371 (getType() == SHT_DYNSYM) || (getType() == SHT_GNU_HASH) ||
372 (getType() == SHT_GNU_verdef) || (getType() == SHT_GNU_verneed) ||
373 (getType() == SHT_GNU_versym) || getSegmentByType(PT_INTERP)) &&
374 (getFlags() & SHF_ALLOC);
377 void insertAfter(ElfSection* section, bool dirty = true) {
378 if (previous != nullptr) previous->next = next;
379 if (next != nullptr) next->previous = previous;
380 previous = section;
381 if (section != nullptr) {
382 next = section->next;
383 section->next = this;
384 } else
385 next = nullptr;
386 if (next != nullptr) next->previous = this;
387 if (dirty) markDirty();
388 insertInSegments(section->segments);
391 virtual void insertBefore(ElfSection* section, bool dirty = true) {
392 if (previous != nullptr) previous->next = next;
393 if (next != nullptr) next->previous = previous;
394 next = section;
395 if (section != nullptr) {
396 previous = section->previous;
397 section->previous = this;
398 } else
399 previous = nullptr;
400 if (previous != nullptr) previous->next = this;
401 if (dirty) markDirty();
402 insertInSegments(section->segments);
405 void markDirty() {
406 if (link != nullptr) shdr.sh_link = -1;
407 if (info.index) shdr.sh_info = -1;
408 shdr.sh_offset = -1;
409 if (isRelocatable()) shdr.sh_addr = -1;
410 if (next) next->markDirty();
413 virtual void serialize(std::ofstream& file, unsigned char ei_class,
414 unsigned char ei_data) {
415 if (getType() == SHT_NOBITS) return;
416 file.seekp(getOffset());
417 file.write(data, getSize());
420 ElfSegment* getSegmentByType(unsigned int type);
422 private:
423 friend class ElfSegment;
425 void addToSegment(ElfSegment* segment) { segments.push_back(segment); }
427 void removeFromSegment(ElfSegment* segment) {
428 std::vector<ElfSegment*>::iterator i =
429 std::find(segments.begin(), segments.end(), segment);
430 segments.erase(i, i + 1);
433 void insertInSegments(std::vector<ElfSegment*>& segs);
435 protected:
436 Elf_Shdr shdr;
437 char* data;
438 const char* name;
440 private:
441 ElfSection* link;
442 SectionInfo info;
443 ElfSection *next, *previous;
444 int index;
445 std::vector<ElfSegment*> segments;
448 class ElfSegment {
449 public:
450 ElfSegment(Elf_Phdr* phdr);
452 unsigned int getType() { return type; }
453 unsigned int getFlags() { return flags; }
454 unsigned int getAlign() { return align; }
456 ElfSection* getFirstSection() {
457 return sections.empty() ? nullptr : sections.front();
459 int getVPDiff() { return v_p_diff; }
460 unsigned int getFileSize();
461 unsigned int getMemSize();
462 unsigned int getOffset();
463 unsigned int getAddr();
465 void addSection(ElfSection* section);
466 void removeSection(ElfSection* section);
468 std::list<ElfSection*>::iterator begin() { return sections.begin(); }
469 std::list<ElfSection*>::iterator end() { return sections.end(); }
471 void clear();
473 private:
474 unsigned int type;
475 int v_p_diff; // Difference between physical and virtual address
476 unsigned int flags;
477 unsigned int align;
478 std::list<ElfSection*> sections;
479 // The following are only really used for PT_GNU_RELRO until something
480 // better is found.
481 unsigned int vaddr;
482 unsigned int filesz, memsz;
485 class Elf_Ehdr : public serializable<Elf_Ehdr_Traits>, public ElfSection {
486 public:
487 Elf_Ehdr(std::ifstream& file, unsigned char ei_class, unsigned char ei_data);
488 void serialize(std::ofstream& file, unsigned char ei_class,
489 unsigned char ei_data) {
490 serializable<Elf_Ehdr_Traits>::serialize(file, ei_class, ei_data);
494 class Elf_Phdr : public serializable<Elf_Phdr_Traits> {
495 public:
496 Elf_Phdr() {};
497 Elf_Phdr(std::ifstream& file, unsigned char ei_class, unsigned char ei_data)
498 : serializable<Elf_Phdr_Traits>(file, ei_class, ei_data) {};
499 bool contains(ElfSection* section) {
500 unsigned int size = section->getSize();
501 unsigned int addr = section->getAddr();
502 // This may be biased, but should work in most cases
503 if ((section->getFlags() & SHF_ALLOC) == 0) return false;
504 // Special case for PT_DYNAMIC. Eventually, this should
505 // be better handled than special cases
506 if ((p_type == PT_DYNAMIC) && (section->getType() != SHT_DYNAMIC))
507 return false;
508 // Special case for PT_TLS.
509 if ((p_type == PT_TLS) && !(section->getFlags() & SHF_TLS)) return false;
510 return (addr >= p_vaddr) && (addr + size <= p_vaddr + p_memsz);
514 typedef serializable<Elf_Dyn_Traits> Elf_Dyn;
516 struct Elf_DynValue {
517 unsigned int tag;
518 ElfValue* value;
521 class ElfDynamic_Section : public ElfSection {
522 public:
523 ElfDynamic_Section(Elf_Shdr& s, std::ifstream* file, Elf* parent);
524 ~ElfDynamic_Section();
526 void serialize(std::ofstream& file, unsigned char ei_class,
527 unsigned char ei_data);
529 ElfValue* getValueForType(unsigned int tag);
530 ElfSection* getSectionForType(unsigned int tag);
531 bool setValueForType(unsigned int tag, ElfValue* val);
533 private:
534 std::vector<Elf_DynValue> dyns;
537 typedef serializable<Elf_Sym_Traits> Elf_Sym;
539 struct Elf_SymValue {
540 const char* name;
541 unsigned char info;
542 unsigned char other;
543 ElfLocation value;
544 unsigned int size;
545 bool defined;
548 #define STT(type) (1 << STT_##type)
550 class ElfSymtab_Section : public ElfSection {
551 public:
552 ElfSymtab_Section(Elf_Shdr& s, std::ifstream* file, Elf* parent);
554 void serialize(std::ofstream& file, unsigned char ei_class,
555 unsigned char ei_data);
557 Elf_SymValue* lookup(const char* name,
558 unsigned int type_filter = STT(OBJECT) | STT(FUNC));
560 // private: // Until we have a real API
561 std::vector<Elf_SymValue> syms;
564 class Elf_Rel : public serializable<Elf_Rel_Traits> {
565 public:
566 Elf_Rel() : serializable<Elf_Rel_Traits>() {};
568 Elf_Rel(std::ifstream& file, unsigned char ei_class, unsigned char ei_data)
569 : serializable<Elf_Rel_Traits>(file, ei_class, ei_data) {};
571 static const unsigned int sh_type = SHT_REL;
572 static const unsigned int d_tag = DT_REL;
573 static const unsigned int d_tag_count = DT_RELCOUNT;
576 class Elf_Rela : public serializable<Elf_Rela_Traits> {
577 public:
578 Elf_Rela() : serializable<Elf_Rela_Traits>() {};
580 Elf_Rela(std::ifstream& file, unsigned char ei_class, unsigned char ei_data)
581 : serializable<Elf_Rela_Traits>(file, ei_class, ei_data) {};
583 static const unsigned int sh_type = SHT_RELA;
584 static const unsigned int d_tag = DT_RELA;
585 static const unsigned int d_tag_count = DT_RELACOUNT;
588 template <class Rel>
589 class ElfRel_Section : public ElfSection {
590 public:
591 ElfRel_Section(Elf_Shdr& s, std::ifstream* file, Elf* parent)
592 : ElfSection(s, file, parent) {
593 auto pos = file->tellg();
594 file->seekg(shdr.sh_offset);
595 for (unsigned int i = 0; i < s.sh_size / s.sh_entsize; i++) {
596 Rel r(*file, parent->getClass(), parent->getData());
597 rels.push_back(r);
599 file->seekg(pos);
602 void serialize(std::ofstream& file, unsigned char ei_class,
603 unsigned char ei_data) {
604 for (typename std::vector<Rel>::iterator i = rels.begin(); i != rels.end();
605 ++i)
606 (*i).serialize(file, ei_class, ei_data);
608 // private: // Until we have a real API
609 std::vector<Rel> rels;
612 class ElfStrtab_Section : public ElfSection {
613 public:
614 ElfStrtab_Section(Elf_Shdr& s, std::ifstream* file, Elf* parent)
615 : ElfSection(s, file, parent) {
616 table.push_back(table_storage(data, shdr.sh_size));
619 ~ElfStrtab_Section() {
620 for (std::vector<table_storage>::iterator t = table.begin() + 1;
621 t != table.end(); ++t)
622 delete[] t->buf;
625 const char* getStr(unsigned int index);
627 const char* getStr(const char* string);
629 unsigned int getStrIndex(const char* string);
631 void serialize(std::ofstream& file, unsigned char ei_class,
632 unsigned char ei_data);
634 private:
635 struct table_storage {
636 unsigned int size, used;
637 char* buf;
639 table_storage() : size(4096), used(0), buf(new char[4096]) {}
640 table_storage(const char* data, unsigned int sz)
641 : size(sz), used(sz), buf(const_cast<char*>(data)) {}
643 std::vector<table_storage> table;
646 inline unsigned char Elf::getClass() { return ehdr->e_ident[EI_CLASS]; }
648 inline unsigned char Elf::getData() { return ehdr->e_ident[EI_DATA]; }
650 inline unsigned char Elf::getType() { return ehdr->e_type; }
652 inline unsigned char Elf::getMachine() { return ehdr->e_machine; }
654 inline unsigned int Elf::getSize() {
655 ElfSection* section;
656 for (section = shdr_section /* It's usually not far from the end */;
657 section->getNext() != nullptr; section = section->getNext());
658 return section->getOffset() + section->getSize();
661 inline ElfSegment* ElfSection::getSegmentByType(unsigned int type) {
662 for (std::vector<ElfSegment*>::iterator seg = segments.begin();
663 seg != segments.end(); ++seg)
664 if ((*seg)->getType() == type) return *seg;
665 return nullptr;
668 inline void ElfSection::insertInSegments(std::vector<ElfSegment*>& segs) {
669 for (std::vector<ElfSegment*>::iterator it = segs.begin(); it != segs.end();
670 ++it) {
671 (*it)->addSection(this);
675 inline ElfLocation::ElfLocation(ElfSection* section, unsigned int off,
676 enum position pos)
677 : section(section) {
678 if ((pos == ABSOLUTE) && section)
679 offset = off - section->getAddr();
680 else
681 offset = off;
684 inline ElfLocation::ElfLocation(unsigned int location, Elf* elf) {
685 section = elf->getSectionAt(location);
686 offset = location - (section ? section->getAddr() : 0);
689 inline unsigned int ElfLocation::getValue() {
690 return (section ? section->getAddr() : 0) + offset;
693 inline const char* ElfLocation::getBuffer() {
694 return section ? section->getData() + offset : nullptr;
697 inline unsigned int ElfSize::getValue() { return section->getSize(); }
699 inline unsigned int ElfEntSize::getValue() { return section->getEntSize(); }