elfxx.h (19403B)
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 <fstream> 10 #include <algorithm> 11 #include <elf.h> 12 #include <asm/byteorder.h> 13 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); \ 19 } 20 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); 29 }; 30 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); 39 }; 40 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; 50 51 template <typename X> 52 class FixedSizeData { 53 public: 54 struct Wrapper { 55 X value; 56 }; 57 typedef Wrapper Type32; 58 typedef Wrapper Type64; 59 60 template <class endian, typename R, typename T> 61 static void swap(T& t, R& r) { 62 r.value = endian::swap(t.value); 63 } 64 }; 65 66 class Elf_Ehdr_Traits { 67 public: 68 typedef Elf32_Ehdr Type32; 69 typedef Elf64_Ehdr Type64; 70 71 template <class endian, typename R, typename T> 72 static void swap(T& t, R& r); 73 }; 74 75 class Elf_Phdr_Traits { 76 public: 77 typedef Elf32_Phdr Type32; 78 typedef Elf64_Phdr Type64; 79 80 template <class endian, typename R, typename T> 81 static void swap(T& t, R& r); 82 }; 83 84 class Elf_Shdr_Traits { 85 public: 86 typedef Elf32_Shdr Type32; 87 typedef Elf64_Shdr Type64; 88 89 template <class endian, typename R, typename T> 90 static void swap(T& t, R& r); 91 }; 92 93 class Elf_Dyn_Traits { 94 public: 95 typedef Elf32_Dyn Type32; 96 typedef Elf64_Dyn Type64; 97 98 template <class endian, typename R, typename T> 99 static void swap(T& t, R& r); 100 }; 101 102 class Elf_Sym_Traits { 103 public: 104 typedef Elf32_Sym Type32; 105 typedef Elf64_Sym Type64; 106 107 template <class endian, typename R, typename T> 108 static void swap(T& t, R& r); 109 }; 110 111 class Elf_Rel_Traits { 112 public: 113 typedef Elf32_Rel Type32; 114 typedef Elf64_Rel Type64; 115 116 template <class endian, typename R, typename T> 117 static void swap(T& t, R& r); 118 }; 119 120 class Elf_Rela_Traits { 121 public: 122 typedef Elf32_Rela Type32; 123 typedef Elf64_Rela Type64; 124 125 template <class endian, typename R, typename T> 126 static void swap(T& t, R& r); 127 }; 128 129 class ElfValue { 130 public: 131 virtual unsigned int getValue() { return 0; } 132 virtual ElfSection* getSection() { return nullptr; } 133 }; 134 135 class ElfPlainValue : public ElfValue { 136 unsigned int value; 137 138 public: 139 ElfPlainValue(unsigned int val) : value(val) {}; 140 unsigned int getValue() { return value; } 141 }; 142 143 class ElfLocation : public ElfValue { 144 ElfSection* section; 145 unsigned int offset; 146 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(); 156 }; 157 158 class ElfSize : public ElfValue { 159 ElfSection* section; 160 161 public: 162 ElfSize(ElfSection* s) : section(s) {}; 163 unsigned int getValue(); 164 ElfSection* getSection() { return section; } 165 }; 166 167 class ElfEntSize : public ElfValue { 168 ElfSection* section; 169 170 public: 171 ElfEntSize(ElfSection* s) : section(s) {}; 172 unsigned int getValue(); 173 ElfSection* getSection() { return section; } 174 }; 175 176 template <typename T> 177 class serializable : public T::Type64 { 178 public: 179 serializable() {}; 180 serializable(const typename T::Type64& p) : T::Type64(p) {}; 181 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; 194 } 195 throw std::runtime_error("Unsupported ELF data encoding"); 196 } 197 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; 207 } 208 throw std::runtime_error("Unsupported ELF data encoding"); 209 } 210 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; 220 } 221 throw std::runtime_error("Unsupported ELF class"); 222 } 223 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; 236 } 237 throw std::runtime_error("Unsupported ELF class or data encoding"); 238 } 239 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; 252 } 253 throw std::runtime_error("Unsupported ELF class or data encoding"); 254 } 255 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; 264 } 265 throw std::runtime_error("Unsupported ELF class"); 266 } 267 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; 274 } 275 }; 276 277 typedef serializable<Elf_Shdr_Traits> Elf_Shdr; 278 279 class Elf { 280 public: 281 Elf(std::ifstream& file); 282 ~Elf(); 283 284 /* index == -1 is treated as index == ehdr.e_shstrndx */ 285 ElfSection* getSection(int index); 286 287 ElfSection* getSectionAt(Elf64_Off offset); 288 289 ElfSegment* getSegmentByType(unsigned int type, ElfSegment* last = nullptr); 290 291 ElfDynamic_Section* getDynSection(); 292 293 void normalize(); 294 void write(std::ofstream& file); 295 296 unsigned char getClass(); 297 unsigned char getData(); 298 unsigned char getType(); 299 unsigned char getMachine(); 300 unsigned int getSize(); 301 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); 306 } 307 308 void removeSegment(ElfSegment* segment); 309 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; 320 }; 321 322 class ElfSection { 323 public: 324 typedef union { 325 ElfSection* section; 326 int index; 327 } SectionInfo; 328 329 ElfSection(Elf_Shdr& s, std::ifstream* file, Elf* parent); 330 331 virtual ~ElfSection() { free(data); } 332 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; } 343 344 void shrink(unsigned int newsize) { 345 if (newsize < shdr.sh_size) { 346 shdr.sh_size = newsize; 347 markDirty(); 348 } 349 } 350 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(); 357 } 358 } 359 360 Elf64_Off getOffset(); 361 int getIndex(); 362 Elf_Shdr& getShdr(); 363 364 ElfSection* getNext() { return next; } 365 ElfSection* getPrevious() { return previous; } 366 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); 375 } 376 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); 389 } 390 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); 403 } 404 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(); 411 } 412 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()); 418 } 419 420 ElfSegment* getSegmentByType(unsigned int type); 421 422 private: 423 friend class ElfSegment; 424 425 void addToSegment(ElfSegment* segment) { segments.push_back(segment); } 426 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); 431 } 432 433 void insertInSegments(std::vector<ElfSegment*>& segs); 434 435 protected: 436 Elf_Shdr shdr; 437 char* data; 438 const char* name; 439 440 private: 441 ElfSection* link; 442 SectionInfo info; 443 ElfSection *next, *previous; 444 int index; 445 std::vector<ElfSegment*> segments; 446 }; 447 448 class ElfSegment { 449 public: 450 ElfSegment(Elf_Phdr* phdr); 451 452 unsigned int getType() { return type; } 453 unsigned int getFlags() { return flags; } 454 unsigned int getAlign() { return align; } 455 456 ElfSection* getFirstSection() { 457 return sections.empty() ? nullptr : sections.front(); 458 } 459 int getVPDiff() { return v_p_diff; } 460 unsigned int getFileSize(); 461 unsigned int getMemSize(); 462 unsigned int getOffset(); 463 unsigned int getAddr(); 464 465 void addSection(ElfSection* section); 466 void removeSection(ElfSection* section); 467 468 std::list<ElfSection*>::iterator begin() { return sections.begin(); } 469 std::list<ElfSection*>::iterator end() { return sections.end(); } 470 471 void clear(); 472 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; 483 }; 484 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); 491 } 492 }; 493 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); 511 } 512 }; 513 514 typedef serializable<Elf_Dyn_Traits> Elf_Dyn; 515 516 struct Elf_DynValue { 517 unsigned int tag; 518 ElfValue* value; 519 }; 520 521 class ElfDynamic_Section : public ElfSection { 522 public: 523 ElfDynamic_Section(Elf_Shdr& s, std::ifstream* file, Elf* parent); 524 ~ElfDynamic_Section(); 525 526 void serialize(std::ofstream& file, unsigned char ei_class, 527 unsigned char ei_data); 528 529 ElfValue* getValueForType(unsigned int tag); 530 ElfSection* getSectionForType(unsigned int tag); 531 bool setValueForType(unsigned int tag, ElfValue* val); 532 533 private: 534 std::vector<Elf_DynValue> dyns; 535 }; 536 537 typedef serializable<Elf_Sym_Traits> Elf_Sym; 538 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; 546 }; 547 548 #define STT(type) (1 << STT_##type) 549 550 class ElfSymtab_Section : public ElfSection { 551 public: 552 ElfSymtab_Section(Elf_Shdr& s, std::ifstream* file, Elf* parent); 553 554 void serialize(std::ofstream& file, unsigned char ei_class, 555 unsigned char ei_data); 556 557 Elf_SymValue* lookup(const char* name, 558 unsigned int type_filter = STT(OBJECT) | STT(FUNC)); 559 560 // private: // Until we have a real API 561 std::vector<Elf_SymValue> syms; 562 }; 563 564 class Elf_Rel : public serializable<Elf_Rel_Traits> { 565 public: 566 Elf_Rel() : serializable<Elf_Rel_Traits>() {}; 567 568 Elf_Rel(std::ifstream& file, unsigned char ei_class, unsigned char ei_data) 569 : serializable<Elf_Rel_Traits>(file, ei_class, ei_data) {}; 570 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; 574 }; 575 576 class Elf_Rela : public serializable<Elf_Rela_Traits> { 577 public: 578 Elf_Rela() : serializable<Elf_Rela_Traits>() {}; 579 580 Elf_Rela(std::ifstream& file, unsigned char ei_class, unsigned char ei_data) 581 : serializable<Elf_Rela_Traits>(file, ei_class, ei_data) {}; 582 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; 586 }; 587 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); 598 } 599 file->seekg(pos); 600 } 601 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); 607 } 608 // private: // Until we have a real API 609 std::vector<Rel> rels; 610 }; 611 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)); 617 } 618 619 ~ElfStrtab_Section() { 620 for (std::vector<table_storage>::iterator t = table.begin() + 1; 621 t != table.end(); ++t) 622 delete[] t->buf; 623 } 624 625 const char* getStr(unsigned int index); 626 627 const char* getStr(const char* string); 628 629 unsigned int getStrIndex(const char* string); 630 631 void serialize(std::ofstream& file, unsigned char ei_class, 632 unsigned char ei_data); 633 634 private: 635 struct table_storage { 636 unsigned int size, used; 637 char* buf; 638 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)) {} 642 }; 643 std::vector<table_storage> table; 644 }; 645 646 inline unsigned char Elf::getClass() { return ehdr->e_ident[EI_CLASS]; } 647 648 inline unsigned char Elf::getData() { return ehdr->e_ident[EI_DATA]; } 649 650 inline unsigned char Elf::getType() { return ehdr->e_type; } 651 652 inline unsigned char Elf::getMachine() { return ehdr->e_machine; } 653 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(); 659 } 660 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; 666 } 667 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); 672 } 673 } 674 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; 682 } 683 684 inline ElfLocation::ElfLocation(unsigned int location, Elf* elf) { 685 section = elf->getSectionAt(location); 686 offset = location - (section ? section->getAddr() : 0); 687 } 688 689 inline unsigned int ElfLocation::getValue() { 690 return (section ? section->getAddr() : 0) + offset; 691 } 692 693 inline const char* ElfLocation::getBuffer() { 694 return section ? section->getData() + offset : nullptr; 695 } 696 697 inline unsigned int ElfSize::getValue() { return section->getSize(); } 698 699 inline unsigned int ElfEntSize::getValue() { return section->getEntSize(); }