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/. */
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); \
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);
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
44 // TODO: Rename Elf_* types
48 class ElfDynamic_Section
;
49 class ElfStrtab_Section
;
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
{
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
{
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
{
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
{
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
{
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
{
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
{
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
);
131 virtual unsigned int getValue() { return 0; }
132 virtual ElfSection
* getSection() { return nullptr; }
135 class ElfPlainValue
: public ElfValue
{
139 ElfPlainValue(unsigned int val
) : value(val
) {};
140 unsigned int getValue() { return value
; }
143 class ElfLocation
: public ElfValue
{
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
{
162 ElfSize(ElfSection
* s
) : section(s
) {};
163 unsigned int getValue();
164 ElfSection
* getSection() { return section
; }
167 class ElfEntSize
: public ElfValue
{
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
{
180 serializable(const typename
T::Type64
& p
) : T::Type64(p
) {};
183 template <typename R
>
184 void init(const char* buf
, size_t len
, unsigned char ei_data
) {
186 assert(len
>= sizeof(e
));
187 memcpy(&e
, buf
, sizeof(e
));
188 if (ei_data
== ELFDATA2LSB
) {
189 T::template swap
<little_endian
>(e
, *this);
191 } else if (ei_data
== ELFDATA2MSB
) {
192 T::template swap
<big_endian
>(e
, *this);
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
);
204 } else if (ei_data
== ELFDATA2MSB
) {
205 T::template swap
<big_endian
>(*this, *(R
*)buf
);
208 throw std::runtime_error("Unsupported ELF data encoding");
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
);
217 } else if (ei_class
== ELFCLASS64
) {
218 init
<typename
T::Type64
>(buf
, len
, ei_data
);
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
);
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
);
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
));
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
));
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
);
261 } else if (ei_class
== ELFCLASS64
) {
262 serialize
<typename
T::Type64
>(buf
, len
, ei_data
);
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
);
277 typedef serializable
<Elf_Shdr_Traits
> Elf_Shdr
;
281 Elf(std::ifstream
& file
);
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();
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
);
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 */
319 std::ifstream
* tmp_file
;
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
;
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
;
360 Elf64_Off
getOffset();
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
;
381 if (section
!= nullptr) {
382 next
= section
->next
;
383 section
->next
= this;
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
;
395 if (section
!= nullptr) {
396 previous
= section
->previous
;
397 section
->previous
= this;
400 if (previous
!= nullptr) previous
->next
= this;
401 if (dirty
) markDirty();
402 insertInSegments(section
->segments
);
406 if (link
!= nullptr) shdr
.sh_link
= -1;
407 if (info
.index
) shdr
.sh_info
= -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
);
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
);
443 ElfSection
*next
, *previous
;
445 std::vector
<ElfSegment
*> segments
;
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(); }
475 int v_p_diff
; // Difference between physical and virtual address
478 std::list
<ElfSection
*> sections
;
479 // The following are only really used for PT_GNU_RELRO until something
482 unsigned int filesz
, memsz
;
485 class Elf_Ehdr
: public serializable
<Elf_Ehdr_Traits
>, public ElfSection
{
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
> {
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
))
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
{
521 class ElfDynamic_Section
: public ElfSection
{
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
);
534 std::vector
<Elf_DynValue
> dyns
;
537 typedef serializable
<Elf_Sym_Traits
> Elf_Sym
;
539 struct Elf_SymValue
{
548 #define STT(type) (1 << STT_##type)
550 class ElfSymtab_Section
: public ElfSection
{
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
> {
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
> {
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
;
589 class ElfRel_Section
: public ElfSection
{
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());
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();
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
{
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
)
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
);
635 struct table_storage
{
636 unsigned int size
, used
;
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() {
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
;
668 inline void ElfSection::insertInSegments(std::vector
<ElfSegment
*>& segs
) {
669 for (std::vector
<ElfSegment
*>::iterator it
= segs
.begin(); it
!= segs
.end();
671 (*it
)->addSection(this);
675 inline ElfLocation::ElfLocation(ElfSection
* section
, unsigned int off
,
678 if ((pos
== ABSOLUTE
) && section
)
679 offset
= off
- section
->getAddr();
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(); }