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