michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "mozilla/NullPtr.h" michael@0: michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: #include michael@0: michael@0: // Technically, __*_to_cpu and __cpu_to* function are equivalent, michael@0: // so swap can use either of both. michael@0: #define def_swap(endian, type, bits) \ michael@0: static inline type ## bits ## _t swap(type ## bits ## _t i) { \ michael@0: return __ ## endian ## bits ## _to_cpu(i); \ michael@0: } michael@0: michael@0: class little_endian { michael@0: public: michael@0: def_swap(le, uint, 16); michael@0: def_swap(le, uint, 32); michael@0: def_swap(le, uint, 64); michael@0: def_swap(le, int, 16); michael@0: def_swap(le, int, 32); michael@0: def_swap(le, int, 64); michael@0: }; michael@0: michael@0: class big_endian { michael@0: public: michael@0: def_swap(be, uint, 16); michael@0: def_swap(be, uint, 32); michael@0: def_swap(be, uint, 64); michael@0: def_swap(be, int, 16); michael@0: def_swap(be, int, 32); michael@0: def_swap(be, int, 64); michael@0: }; michael@0: michael@0: // forward declaration michael@0: class ElfSection; michael@0: class ElfSegment; michael@0: // TODO: Rename Elf_* types michael@0: class Elf_Ehdr; michael@0: class Elf_Phdr; michael@0: class Elf; michael@0: class ElfDynamic_Section; michael@0: class ElfStrtab_Section; michael@0: michael@0: class Elf_Ehdr_Traits { michael@0: public: michael@0: typedef Elf32_Ehdr Type32; michael@0: typedef Elf64_Ehdr Type64; michael@0: michael@0: template michael@0: static void swap(T &t, R &r); michael@0: }; michael@0: michael@0: class Elf_Phdr_Traits { michael@0: public: michael@0: typedef Elf32_Phdr Type32; michael@0: typedef Elf64_Phdr Type64; michael@0: michael@0: template michael@0: static void swap(T &t, R &r); michael@0: }; michael@0: michael@0: class Elf_Shdr_Traits { michael@0: public: michael@0: typedef Elf32_Shdr Type32; michael@0: typedef Elf64_Shdr Type64; michael@0: michael@0: template michael@0: static void swap(T &t, R &r); michael@0: }; michael@0: michael@0: class Elf_Dyn_Traits { michael@0: public: michael@0: typedef Elf32_Dyn Type32; michael@0: typedef Elf64_Dyn Type64; michael@0: michael@0: template michael@0: static void swap(T &t, R &r); michael@0: }; michael@0: michael@0: class Elf_Sym_Traits { michael@0: public: michael@0: typedef Elf32_Sym Type32; michael@0: typedef Elf64_Sym Type64; michael@0: michael@0: template michael@0: static void swap(T &t, R &r); michael@0: }; michael@0: michael@0: class Elf_Rel_Traits { michael@0: public: michael@0: typedef Elf32_Rel Type32; michael@0: typedef Elf64_Rel Type64; michael@0: michael@0: template michael@0: static void swap(T &t, R &r); michael@0: }; michael@0: michael@0: class Elf_Rela_Traits { michael@0: public: michael@0: typedef Elf32_Rela Type32; michael@0: typedef Elf64_Rela Type64; michael@0: michael@0: template michael@0: static void swap(T &t, R &r); michael@0: }; michael@0: michael@0: class ElfValue { michael@0: public: michael@0: virtual unsigned int getValue() { return 0; } michael@0: virtual ElfSection *getSection() { return nullptr; } michael@0: }; michael@0: michael@0: class ElfPlainValue: public ElfValue { michael@0: unsigned int value; michael@0: public: michael@0: ElfPlainValue(unsigned int val): value(val) {}; michael@0: unsigned int getValue() { return value; } michael@0: }; michael@0: michael@0: class ElfLocation: public ElfValue { michael@0: ElfSection *section; michael@0: unsigned int offset; michael@0: public: michael@0: enum position { ABSOLUTE, RELATIVE }; michael@0: ElfLocation(): section(nullptr), offset(0) {}; michael@0: ElfLocation(ElfSection *section, unsigned int off, enum position pos = RELATIVE); michael@0: ElfLocation(unsigned int location, Elf *elf); michael@0: unsigned int getValue(); michael@0: ElfSection *getSection() { return section; } michael@0: const char *getBuffer(); michael@0: }; michael@0: michael@0: class ElfSize: public ElfValue { michael@0: ElfSection *section; michael@0: public: michael@0: ElfSize(ElfSection *s): section(s) {}; michael@0: unsigned int getValue(); michael@0: ElfSection *getSection() { return section; } michael@0: }; michael@0: michael@0: class ElfEntSize: public ElfValue { michael@0: ElfSection *section; michael@0: public: michael@0: ElfEntSize(ElfSection *s): section(s) {}; michael@0: unsigned int getValue(); michael@0: ElfSection *getSection() { return section; } michael@0: }; michael@0: michael@0: template michael@0: class serializable: public T::Type32 { michael@0: public: michael@0: serializable() {}; michael@0: serializable(const typename T::Type32 &p): T::Type32(p) {}; michael@0: michael@0: private: michael@0: template michael@0: void init(const char *buf, size_t len, char ei_data) michael@0: { michael@0: R e; michael@0: assert(len >= sizeof(e)); michael@0: memcpy(&e, buf, sizeof(e)); michael@0: if (ei_data == ELFDATA2LSB) { michael@0: T::template swap(e, *this); michael@0: return; michael@0: } else if (ei_data == ELFDATA2MSB) { michael@0: T::template swap(e, *this); michael@0: return; michael@0: } michael@0: throw std::runtime_error("Unsupported ELF data encoding"); michael@0: } michael@0: michael@0: template michael@0: void serialize(const char *buf, size_t len, char ei_data) michael@0: { michael@0: assert(len >= sizeof(R)); michael@0: if (ei_data == ELFDATA2LSB) { michael@0: T::template swap(*this, *(R *)buf); michael@0: return; michael@0: } else if (ei_data == ELFDATA2MSB) { michael@0: T::template swap(*this, *(R *)buf); michael@0: return; michael@0: } michael@0: throw std::runtime_error("Unsupported ELF data encoding"); michael@0: } michael@0: michael@0: public: michael@0: serializable(const char *buf, size_t len, char ei_class, char ei_data) michael@0: { michael@0: if (ei_class == ELFCLASS32) { michael@0: init(buf, len, ei_data); michael@0: return; michael@0: } else if (ei_class == ELFCLASS64) { michael@0: init(buf, len, ei_data); michael@0: return; michael@0: } michael@0: throw std::runtime_error("Unsupported ELF class"); michael@0: } michael@0: michael@0: serializable(std::ifstream &file, char ei_class, char ei_data) michael@0: { michael@0: if (ei_class == ELFCLASS32) { michael@0: typename T::Type32 e; michael@0: file.read((char *)&e, sizeof(e)); michael@0: init((char *)&e, sizeof(e), ei_data); michael@0: return; michael@0: } else if (ei_class == ELFCLASS64) { michael@0: typename T::Type64 e; michael@0: file.read((char *)&e, sizeof(e)); michael@0: init((char *)&e, sizeof(e), ei_data); michael@0: return; michael@0: } michael@0: throw std::runtime_error("Unsupported ELF class or data encoding"); michael@0: } michael@0: michael@0: void serialize(std::ofstream &file, char ei_class, char ei_data) michael@0: { michael@0: if (ei_class == ELFCLASS32) { michael@0: typename T::Type32 e; michael@0: serialize((char *)&e, sizeof(e), ei_data); michael@0: file.write((char *)&e, sizeof(e)); michael@0: return; michael@0: } else if (ei_class == ELFCLASS64) { michael@0: typename T::Type64 e; michael@0: serialize((char *)&e, sizeof(e), ei_data); michael@0: file.write((char *)&e, sizeof(e)); michael@0: return; michael@0: } michael@0: throw std::runtime_error("Unsupported ELF class or data encoding"); michael@0: } michael@0: michael@0: void serialize(char *buf, size_t len, char ei_class, char ei_data) michael@0: { michael@0: if (ei_class == ELFCLASS32) { michael@0: serialize(buf, len, ei_data); michael@0: return; michael@0: } else if (ei_class == ELFCLASS64) { michael@0: serialize(buf, len, ei_data); michael@0: return; michael@0: } michael@0: throw std::runtime_error("Unsupported ELF class"); michael@0: } michael@0: michael@0: static inline unsigned int size(char ei_class) michael@0: { michael@0: if (ei_class == ELFCLASS32) michael@0: return sizeof(typename T::Type32); michael@0: else if (ei_class == ELFCLASS64) michael@0: return sizeof(typename T::Type64); michael@0: return 0; michael@0: } michael@0: }; michael@0: michael@0: typedef serializable Elf_Shdr; michael@0: michael@0: class Elf { michael@0: public: michael@0: Elf(std::ifstream &file); michael@0: ~Elf(); michael@0: michael@0: /* index == -1 is treated as index == ehdr.e_shstrndx */ michael@0: ElfSection *getSection(int index); michael@0: michael@0: ElfSection *getSectionAt(unsigned int offset); michael@0: michael@0: ElfSegment *getSegmentByType(unsigned int type, ElfSegment *last = nullptr); michael@0: michael@0: ElfDynamic_Section *getDynSection(); michael@0: michael@0: void normalize(); michael@0: void write(std::ofstream &file); michael@0: michael@0: char getClass(); michael@0: char getData(); michael@0: char getType(); michael@0: char getMachine(); michael@0: unsigned int getSize(); michael@0: michael@0: void insertSegmentAfter(ElfSegment *previous, ElfSegment *segment) { michael@0: std::vector::iterator prev = std::find(segments.begin(), segments.end(), previous); michael@0: segments.insert(prev + 1, segment); michael@0: } michael@0: michael@0: void removeSegment(ElfSegment *segment); michael@0: michael@0: private: michael@0: Elf_Ehdr *ehdr; michael@0: ElfLocation eh_entry; michael@0: ElfStrtab_Section *eh_shstrndx; michael@0: ElfSection **sections; michael@0: std::vector segments; michael@0: ElfSection *shdr_section, *phdr_section; michael@0: /* Values used only during initialization */ michael@0: Elf_Shdr **tmp_shdr; michael@0: std::ifstream *tmp_file; michael@0: }; michael@0: michael@0: class ElfSection { michael@0: public: michael@0: typedef union { michael@0: ElfSection *section; michael@0: int index; michael@0: } SectionInfo; michael@0: michael@0: ElfSection(Elf_Shdr &s, std::ifstream *file, Elf *parent); michael@0: michael@0: virtual ~ElfSection() { michael@0: delete[] data; michael@0: } michael@0: michael@0: const char *getName() { return name; } michael@0: unsigned int getType() { return shdr.sh_type; } michael@0: unsigned int getFlags() { return shdr.sh_flags; } michael@0: unsigned int getAddr(); michael@0: unsigned int getSize() { return shdr.sh_size; } michael@0: unsigned int getAddrAlign() { return shdr.sh_addralign; } michael@0: unsigned int getEntSize() { return shdr.sh_entsize; } michael@0: const char *getData() { return data; } michael@0: ElfSection *getLink() { return link; } michael@0: SectionInfo getInfo() { return info; } michael@0: michael@0: void shrink(unsigned int newsize) { michael@0: if (newsize < shdr.sh_size) michael@0: shdr.sh_size = newsize; michael@0: } michael@0: michael@0: unsigned int getOffset(); michael@0: int getIndex(); michael@0: Elf_Shdr &getShdr(); michael@0: michael@0: ElfSection *getNext() { return next; } michael@0: ElfSection *getPrevious() { return previous; } michael@0: michael@0: virtual bool isRelocatable() { michael@0: return ((getType() == SHT_SYMTAB) || michael@0: (getType() == SHT_STRTAB) || michael@0: (getType() == SHT_RELA) || michael@0: (getType() == SHT_HASH) || michael@0: (getType() == SHT_NOTE) || michael@0: (getType() == SHT_REL) || michael@0: (getType() == SHT_DYNSYM) || michael@0: (getType() == SHT_GNU_HASH) || michael@0: (getType() == SHT_GNU_verdef) || michael@0: (getType() == SHT_GNU_verneed) || michael@0: (getType() == SHT_GNU_versym) || michael@0: getSegmentByType(PT_INTERP)) && michael@0: (getFlags() & SHF_ALLOC); michael@0: } michael@0: michael@0: void insertAfter(ElfSection *section, bool dirty = true) { michael@0: if (previous != nullptr) michael@0: previous->next = next; michael@0: if (next != nullptr) michael@0: next->previous = previous; michael@0: previous = section; michael@0: if (section != nullptr) { michael@0: next = section->next; michael@0: section->next = this; michael@0: } else michael@0: next = nullptr; michael@0: if (next != nullptr) michael@0: next->previous = this; michael@0: if (dirty) michael@0: markDirty(); michael@0: insertInSegments(section->segments); michael@0: } michael@0: michael@0: void insertBefore(ElfSection *section, bool dirty = true) { michael@0: if (previous != nullptr) michael@0: previous->next = next; michael@0: if (next != nullptr) michael@0: next->previous = previous; michael@0: next = section; michael@0: if (section != nullptr) { michael@0: previous = section->previous; michael@0: section->previous = this; michael@0: } else michael@0: previous = nullptr; michael@0: if (previous != nullptr) michael@0: previous->next = this; michael@0: if (dirty) michael@0: markDirty(); michael@0: insertInSegments(section->segments); michael@0: } michael@0: michael@0: void markDirty() { michael@0: if (link != nullptr) michael@0: shdr.sh_link = -1; michael@0: if (info.index) michael@0: shdr.sh_info = -1; michael@0: shdr.sh_offset = -1; michael@0: if (isRelocatable()) michael@0: shdr.sh_addr = -1; michael@0: if (next) michael@0: next->markDirty(); michael@0: } michael@0: michael@0: virtual void serialize(std::ofstream &file, char ei_class, char ei_data) michael@0: { michael@0: if (getType() == SHT_NOBITS) michael@0: return; michael@0: file.seekp(getOffset()); michael@0: file.write(data, getSize()); michael@0: } michael@0: michael@0: private: michael@0: friend class ElfSegment; michael@0: michael@0: void addToSegment(ElfSegment *segment) { michael@0: segments.push_back(segment); michael@0: } michael@0: michael@0: void removeFromSegment(ElfSegment *segment) { michael@0: std::vector::iterator i = std::find(segments.begin(), segments.end(), segment); michael@0: segments.erase(i, i + 1); michael@0: } michael@0: michael@0: ElfSegment *getSegmentByType(unsigned int type); michael@0: michael@0: void insertInSegments(std::vector &segs); michael@0: michael@0: protected: michael@0: Elf_Shdr shdr; michael@0: char *data; michael@0: const char *name; michael@0: private: michael@0: ElfSection *link; michael@0: SectionInfo info; michael@0: ElfSection *next, *previous; michael@0: int index; michael@0: std::vector segments; michael@0: }; michael@0: michael@0: class ElfSegment { michael@0: public: michael@0: ElfSegment(Elf_Phdr *phdr); michael@0: michael@0: unsigned int getType() { return type; } michael@0: unsigned int getFlags() { return flags; } michael@0: unsigned int getAlign() { return align; } michael@0: michael@0: ElfSection *getFirstSection() { return sections.empty() ? nullptr : sections.front(); } michael@0: int getVPDiff() { return v_p_diff; } michael@0: unsigned int getFileSize(); michael@0: unsigned int getMemSize(); michael@0: unsigned int getOffset(); michael@0: unsigned int getAddr(); michael@0: michael@0: void addSection(ElfSection *section); michael@0: void removeSection(ElfSection *section); michael@0: michael@0: std::list::iterator begin() { return sections.begin(); } michael@0: std::list::iterator end() { return sections.end(); } michael@0: michael@0: void clear(); michael@0: michael@0: bool isElfHackFillerSegment() { michael@0: return type == PT_LOAD && flags == 0; michael@0: } michael@0: private: michael@0: unsigned int type; michael@0: int v_p_diff; // Difference between physical and virtual address michael@0: unsigned int flags; michael@0: unsigned int align; michael@0: std::list sections; michael@0: // The following are only really used for PT_GNU_RELRO until something michael@0: // better is found. michael@0: unsigned int vaddr; michael@0: unsigned int filesz, memsz; michael@0: }; michael@0: michael@0: class Elf_Ehdr: public serializable, public ElfSection { michael@0: public: michael@0: Elf_Ehdr(std::ifstream &file, char ei_class, char ei_data); michael@0: void serialize(std::ofstream &file, char ei_class, char ei_data) michael@0: { michael@0: serializable::serialize(file, ei_class, ei_data); michael@0: } michael@0: }; michael@0: michael@0: class Elf_Phdr: public serializable { michael@0: public: michael@0: Elf_Phdr() {}; michael@0: Elf_Phdr(std::ifstream &file, char ei_class, char ei_data) michael@0: : serializable(file, ei_class, ei_data) {}; michael@0: bool contains(ElfSection *section) michael@0: { michael@0: unsigned int size = section->getSize(); michael@0: unsigned int addr = section->getAddr(); michael@0: // This may be biased, but should work in most cases michael@0: if ((section->getFlags() & SHF_ALLOC) == 0) michael@0: return false; michael@0: // Special case for PT_DYNAMIC. Eventually, this should michael@0: // be better handled than special cases michael@0: if ((p_type == PT_DYNAMIC) && (section->getType() != SHT_DYNAMIC)) michael@0: return false; michael@0: // Special case for PT_TLS. michael@0: if ((p_type == PT_TLS) && !(section->getFlags() & SHF_TLS)) michael@0: return false; michael@0: return (addr >= p_vaddr) && michael@0: (addr + size <= p_vaddr + p_memsz); michael@0: michael@0: } michael@0: }; michael@0: michael@0: typedef serializable Elf_Dyn; michael@0: michael@0: struct Elf_DynValue { michael@0: unsigned int tag; michael@0: ElfValue *value; michael@0: }; michael@0: michael@0: class ElfDynamic_Section: public ElfSection { michael@0: public: michael@0: ElfDynamic_Section(Elf_Shdr &s, std::ifstream *file, Elf *parent); michael@0: ~ElfDynamic_Section(); michael@0: michael@0: void serialize(std::ofstream &file, char ei_class, char ei_data); michael@0: michael@0: ElfValue *getValueForType(unsigned int tag); michael@0: ElfSection *getSectionForType(unsigned int tag); michael@0: bool setValueForType(unsigned int tag, ElfValue *val); michael@0: private: michael@0: std::vector dyns; michael@0: }; michael@0: michael@0: typedef serializable Elf_Sym; michael@0: michael@0: struct Elf_SymValue { michael@0: const char *name; michael@0: unsigned char info; michael@0: unsigned char other; michael@0: ElfLocation value; michael@0: unsigned int size; michael@0: bool defined; michael@0: }; michael@0: michael@0: #define STT(type) (1 << STT_ ##type) michael@0: michael@0: class ElfSymtab_Section: public ElfSection { michael@0: public: michael@0: ElfSymtab_Section(Elf_Shdr &s, std::ifstream *file, Elf *parent); michael@0: michael@0: void serialize(std::ofstream &file, char ei_class, char ei_data); michael@0: michael@0: Elf_SymValue *lookup(const char *name, unsigned int type_filter = STT(OBJECT) | STT(FUNC)); michael@0: michael@0: //private: // Until we have a real API michael@0: std::vector syms; michael@0: }; michael@0: michael@0: class Elf_Rel: public serializable { michael@0: public: michael@0: Elf_Rel(std::ifstream &file, char ei_class, char ei_data) michael@0: : serializable(file, ei_class, ei_data) {}; michael@0: michael@0: static const unsigned int sh_type = SHT_REL; michael@0: static const unsigned int d_tag = DT_REL; michael@0: static const unsigned int d_tag_count = DT_RELCOUNT; michael@0: }; michael@0: michael@0: class Elf_Rela: public serializable { michael@0: public: michael@0: Elf_Rela(std::ifstream &file, char ei_class, char ei_data) michael@0: : serializable(file, ei_class, ei_data) {}; michael@0: michael@0: static const unsigned int sh_type = SHT_RELA; michael@0: static const unsigned int d_tag = DT_RELA; michael@0: static const unsigned int d_tag_count = DT_RELACOUNT; michael@0: }; michael@0: michael@0: template michael@0: class ElfRel_Section: public ElfSection { michael@0: public: michael@0: ElfRel_Section(Elf_Shdr &s, std::ifstream *file, Elf *parent) michael@0: : ElfSection(s, file, parent) michael@0: { michael@0: int pos = file->tellg(); michael@0: file->seekg(shdr.sh_offset); michael@0: for (unsigned int i = 0; i < s.sh_size / s.sh_entsize; i++) { michael@0: Rel r(*file, parent->getClass(), parent->getData()); michael@0: rels.push_back(r); michael@0: } michael@0: file->seekg(pos); michael@0: } michael@0: michael@0: void serialize(std::ofstream &file, char ei_class, char ei_data) michael@0: { michael@0: for (typename std::vector::iterator i = rels.begin(); michael@0: i != rels.end(); ++i) michael@0: (*i).serialize(file, ei_class, ei_data); michael@0: } michael@0: //private: // Until we have a real API michael@0: std::vector rels; michael@0: }; michael@0: michael@0: class ElfStrtab_Section: public ElfSection { michael@0: public: michael@0: ElfStrtab_Section(Elf_Shdr &s, std::ifstream *file, Elf *parent) michael@0: : ElfSection(s, file, parent) michael@0: { michael@0: table.push_back(table_storage(data, shdr.sh_size)); michael@0: } michael@0: michael@0: ~ElfStrtab_Section() michael@0: { michael@0: for (std::vector::iterator t = table.begin() + 1; michael@0: t != table.end(); t++) michael@0: delete[] t->buf; michael@0: } michael@0: michael@0: const char *getStr(unsigned int index); michael@0: michael@0: const char *getStr(const char *string); michael@0: michael@0: unsigned int getStrIndex(const char *string); michael@0: michael@0: void serialize(std::ofstream &file, char ei_class, char ei_data); michael@0: private: michael@0: struct table_storage { michael@0: unsigned int size, used; michael@0: char *buf; michael@0: michael@0: table_storage(): size(4096), used(0), buf(new char[4096]) {} michael@0: table_storage(const char *data, unsigned int sz) michael@0: : size(sz), used(sz), buf(const_cast(data)) {} michael@0: }; michael@0: std::vector table; michael@0: }; michael@0: michael@0: inline char Elf::getClass() { michael@0: return ehdr->e_ident[EI_CLASS]; michael@0: } michael@0: michael@0: inline char Elf::getData() { michael@0: return ehdr->e_ident[EI_DATA]; michael@0: } michael@0: michael@0: inline char Elf::getType() { michael@0: return ehdr->e_type; michael@0: } michael@0: michael@0: inline char Elf::getMachine() { michael@0: return ehdr->e_machine; michael@0: } michael@0: michael@0: inline unsigned int Elf::getSize() { michael@0: ElfSection *section; michael@0: for (section = shdr_section /* It's usually not far from the end */; michael@0: section->getNext() != nullptr; section = section->getNext()); michael@0: return section->getOffset() + section->getSize(); michael@0: } michael@0: michael@0: inline ElfSegment *ElfSection::getSegmentByType(unsigned int type) { michael@0: for (std::vector::iterator seg = segments.begin(); seg != segments.end(); seg++) michael@0: if ((*seg)->getType() == type) michael@0: return *seg; michael@0: return nullptr; michael@0: } michael@0: michael@0: inline void ElfSection::insertInSegments(std::vector &segs) { michael@0: for (std::vector::iterator it = segs.begin(); it != segs.end(); ++it) { michael@0: (*it)->addSection(this); michael@0: } michael@0: } michael@0: michael@0: inline ElfLocation::ElfLocation(ElfSection *section, unsigned int off, enum position pos) michael@0: : section(section) { michael@0: if ((pos == ABSOLUTE) && section) michael@0: offset = off - section->getAddr(); michael@0: else michael@0: offset = off; michael@0: } michael@0: michael@0: inline ElfLocation::ElfLocation(unsigned int location, Elf *elf) { michael@0: section = elf->getSectionAt(location); michael@0: offset = location - (section ? section->getAddr() : 0); michael@0: } michael@0: michael@0: inline unsigned int ElfLocation::getValue() { michael@0: return (section ? section->getAddr() : 0) + offset; michael@0: } michael@0: michael@0: inline const char *ElfLocation::getBuffer() { michael@0: return section ? section->getData() + offset : nullptr; michael@0: } michael@0: michael@0: inline unsigned int ElfSize::getValue() { michael@0: return section->getSize(); michael@0: } michael@0: michael@0: inline unsigned int ElfEntSize::getValue() { michael@0: return section->getEntSize(); michael@0: }