| /* Copyright (C) 2007-2010 The Android Open Source Project | |
| ** | |
| ** This software is licensed under the terms of the GNU General Public | |
| ** License version 2, as published by the Free Software Foundation, and | |
| ** may be copied, distributed, and modified under those terms. | |
| ** | |
| ** This program is distributed in the hope that it will be useful, | |
| ** but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| ** GNU General Public License for more details. | |
| */ | |
| /* | |
| * Contains declaration of ElfFile classes that encapsulate an ELF file. | |
| */ | |
| #ifndef ELFF_ELF_FILE_H_ | |
| #define ELFF_ELF_FILE_H_ | |
| #include "dwarf_die.h" | |
| #include "elf_mapped_section.h" | |
| #include "elff_api.h" | |
| #include "android/utils/mapfile.h" | |
| /* Encapsulates architecture-independent functionality of an ELF file. | |
| * | |
| * This class is a base class for templated ElfFileImpl. This class implements | |
| * functionality around an ELF file that is independent from particulars of the | |
| * ELF's CPU architectire, while ElfFileImpl handles all particulars of CPU | |
| * architecture (namely, 32 or 64-bit), for which ELF file has been built. | |
| * | |
| * NOTE: This class operates on ELF sections that have been mapped to memory. | |
| * | |
| */ | |
| class ElfFile { | |
| public: | |
| /* Constructs ElfFile instance. */ | |
| ElfFile(); | |
| /* Destructs ElfFile instance. */ | |
| virtual ~ElfFile(); | |
| /* Creates ElfFileImpl instance, depending on ELF file CPU architecture. | |
| * This method will collect initial information about requested ELF file, | |
| * and will instantiate appropriate ElfFileImpl class object for it. | |
| * Param: | |
| * path - Full path to the ELF file. | |
| * Return: | |
| * Initialized ElfFileImpl instance, typecasted back to ElfFile object on | |
| * success, or NULL on failure, with errno providing extended error | |
| * information. | |
| */ | |
| static ElfFile* Create(const char* path); | |
| /* Checks if ELF file is a 64, or 32-bit ELF file. */ | |
| bool is_ELF_64() const { | |
| return is_ELF_64_; | |
| } | |
| bool is_ELF_32() const { | |
| return !is_ELF_64_; | |
| } | |
| /* Checks if ELF file data format is big, or little-endian. */ | |
| bool is_elf_big_endian() const { | |
| return is_elf_big_endian_; | |
| } | |
| bool is_elf_little_endian() const { | |
| return !is_elf_big_endian_; | |
| } | |
| /* Checks whether or not endianness of CPU this library is built for matches | |
| * endianness of the ELF file that is represented with this instance. */ | |
| bool same_endianness() const { | |
| return same_endianness_; | |
| } | |
| /* Checks if format of DWARF data in this file is 64, or 32-bit. */ | |
| bool is_DWARF_64() const { | |
| return is_DWARF_64_; | |
| } | |
| bool is_DWARF_32() const { | |
| return !is_DWARF_64_; | |
| } | |
| /* Gets DWARF objects allocator for this instance. */ | |
| class ElfAllocator* allocator() const { | |
| return allocator_; | |
| } | |
| /* Gets head of compilation unit list, collected during parsing of this file. | |
| * NOTE: list of collected compilation units returned from this method is | |
| * in reverse order relatively to the order CUs have been added to the list | |
| * during ELF file parsing. | |
| */ | |
| class DwarfCU* last_cu() const { | |
| return last_cu_; | |
| } | |
| /* Gets number of compilation units, collected during parsing of | |
| * this ELF file with parse_compilation_units() method. | |
| */ | |
| int cu_count() const { | |
| return cu_count_; | |
| } | |
| /* Gets executable file flag */ | |
| bool is_exec() const { | |
| return is_exec_; | |
| } | |
| protected: | |
| /* Initializes ElfFile instance. This method is called from Create method of | |
| * this class after appropriate ElfFileImpl instance has been created. Note, | |
| * that Create() method will validate that requested file is an ELF file, | |
| * prior to instantiating of an ElfFileImpl object, and calling this method. | |
| * Param: | |
| * elf_hdr - Address of the common ELF file header. | |
| * path - See Create(). | |
| * Return: | |
| * true on success, or false on failure, with errno containing extended | |
| * error information. | |
| */ | |
| virtual bool initialize(const Elf_CommonHdr* elf_hdr, const char* path); | |
| /*============================================================================= | |
| * Endianness helper methods. | |
| * Since endianness of ELF file may differ from the endianness of the CPU this | |
| * library runs on, every time a value is required from a section of the ELF | |
| * file, it must be first pulled out of that section to a local variable, and | |
| * then used from that local variable. While value is pulled from ELF file | |
| * section, it must be converted accordingly to the endianness of the CPU and | |
| * ELF file. Routines bellow provide such functionality. | |
| =============================================================================*/ | |
| public: | |
| /* Pulls one byte value from ELF file. Note that for one byte we don't need | |
| * to do any endianness conversion, and these two methods are provided purely | |
| * for completness of the API. | |
| * Param: | |
| * val - References value inside ELF file buffer to pull data from. | |
| * Return | |
| * Pulled value with endianness appropriate for the CPU this library is | |
| * running on. | |
| */ | |
| uint8_t pull_val(const uint8_t* val) const { | |
| return *val; | |
| } | |
| uint8_t pull_val(const uint8_t& val) const { | |
| return val; | |
| } | |
| int8_t pull_val(const int8_t* val) const { | |
| return *val; | |
| } | |
| int8_t pull_val(const int8_t& val) const { | |
| return val; | |
| } | |
| /* Pulls two byte value from ELF file. | |
| * Param: | |
| * val - References value inside ELF file buffer to pull data from. | |
| * Return | |
| * Pulled value with endianness appropriate for the CPU this library is | |
| * running on. | |
| */ | |
| uint16_t pull_val(const uint16_t* val) const { | |
| if (same_endianness()) { | |
| return *val; | |
| } | |
| if (is_elf_big_endian()) { | |
| return (uint16_t)get_byte(val, 0) << 8 | get_byte(val, 1); | |
| } else { | |
| return (uint16_t)get_byte(val, 1) << 8 | get_byte(val, 0); | |
| } | |
| } | |
| uint16_t pull_val(const uint16_t& val) const { | |
| return same_endianness() ? val : pull_val(&val); | |
| } | |
| int16_t pull_val(const int16_t* val) const { | |
| return static_cast<int16_t> | |
| (pull_val(reinterpret_cast<const uint16_t*>(val))); | |
| } | |
| int16_t pull_val(const int16_t& val) const { | |
| return static_cast<int16_t> | |
| (pull_val(reinterpret_cast<const uint16_t&>(val))); | |
| } | |
| /* Pulls four byte value from ELF file. | |
| * Param: | |
| * val - References value inside ELF file buffer to pull data from. | |
| * Return | |
| * Pulled value with endianness appropriate for the CPU this library is | |
| * running on. | |
| */ | |
| uint32_t pull_val(const uint32_t* val) const { | |
| if (same_endianness()) { | |
| return *val; | |
| } | |
| if (is_elf_big_endian()) { | |
| return (uint32_t)get_byte(val, 0) << 24 | | |
| (uint32_t)get_byte(val, 1) << 16 | | |
| (uint32_t)get_byte(val, 2) << 8 | | |
| (uint32_t)get_byte(val, 3); | |
| } else { | |
| return (uint32_t)get_byte(val, 3) << 24 | | |
| (uint32_t)get_byte(val, 2) << 16 | | |
| (uint32_t)get_byte(val, 1) << 8 | | |
| (uint32_t)get_byte(val, 0); | |
| } | |
| } | |
| uint32_t pull_val(const uint32_t& val) const { | |
| return same_endianness() ? val : pull_val(&val); | |
| } | |
| int32_t pull_val(const int32_t* val) const { | |
| return static_cast<int32_t> | |
| (pull_val(reinterpret_cast<const uint32_t*>(val))); | |
| } | |
| int32_t pull_val(const int32_t& val) const { | |
| return static_cast<int32_t> | |
| (pull_val(reinterpret_cast<const uint32_t&>(val))); | |
| } | |
| /* Pulls eight byte value from ELF file. | |
| * Param: | |
| * val - References value inside ELF file buffer to pull data from. | |
| * Return | |
| * Pulled value with endianness appropriate for the CPU this library is | |
| * running on. | |
| */ | |
| uint64_t pull_val(const uint64_t* val) const { | |
| if (same_endianness()) { | |
| return *val; | |
| } | |
| if (is_elf_big_endian()) { | |
| return (uint64_t)get_byte(val, 0) << 56 | | |
| (uint64_t)get_byte(val, 1) << 48 | | |
| (uint64_t)get_byte(val, 2) << 40 | | |
| (uint64_t)get_byte(val, 3) << 32 | | |
| (uint64_t)get_byte(val, 4) << 24 | | |
| (uint64_t)get_byte(val, 5) << 16 | | |
| (uint64_t)get_byte(val, 6) << 8 | | |
| (uint64_t)get_byte(val, 7); | |
| } else { | |
| return (uint64_t)get_byte(val, 7) << 56 | | |
| (uint64_t)get_byte(val, 6) << 48 | | |
| (uint64_t)get_byte(val, 5) << 40 | | |
| (uint64_t)get_byte(val, 4) << 32 | | |
| (uint64_t)get_byte(val, 3) << 24 | | |
| (uint64_t)get_byte(val, 2) << 16 | | |
| (uint64_t)get_byte(val, 1) << 8 | | |
| (uint64_t)get_byte(val, 0); | |
| } | |
| } | |
| uint64_t pull_val(const uint64_t& val) const { | |
| return same_endianness() ? val : pull_val(&val); | |
| } | |
| int64_t pull_val(const int64_t* val) const { | |
| return static_cast<int64_t> | |
| (pull_val(reinterpret_cast<const uint64_t*>(val))); | |
| } | |
| int64_t pull_val(const int64_t& val) const { | |
| return static_cast<int64_t> | |
| (pull_val(reinterpret_cast<const uint64_t&>(val))); | |
| } | |
| //============================================================================= | |
| // ELF file section management. | |
| //============================================================================= | |
| public: | |
| /* Gets a string contained in ELF's string section by index. | |
| * Param: | |
| * index - String index (byte offset) in the ELF's string section. | |
| * Return: | |
| * Pointer to the requested string, or NULL if string index exceeds ELF's | |
| * string section size. | |
| * NOTE: pointer returned from this method points to a mapped section of | |
| * ELF file. | |
| */ | |
| const char* get_str_sec_str(Elf_Xword index) const { | |
| assert(string_section_.is_mapped() && index < string_section_.size()); | |
| if (string_section_.is_mapped() && index < string_section_.size()) { | |
| return INC_CPTR_T(char, string_section_.data(), index); | |
| } else { | |
| _set_errno(EINVAL); | |
| return NULL; | |
| } | |
| } | |
| /* Gets a string contained in ELF's debug string section (.debug_str) | |
| * by index. | |
| * Param: | |
| * index - String index (byte offset) in the ELF's debug string section. | |
| * Return: | |
| * Pointer to the requested string, or NULL if string index exceeds ELF's | |
| * debug string section size. | |
| * NOTE: pointer returned from this method points to a mapped section of | |
| * ELF file. | |
| */ | |
| const char* get_debug_str(Elf_Xword index) const { | |
| assert(debug_str_.is_mapped() && index < debug_str_.size()); | |
| if (debug_str_.is_mapped() && index < debug_str_.size()) { | |
| return INC_CPTR_T(char, debug_str_.data(), index); | |
| } else { | |
| _set_errno(EINVAL); | |
| return NULL; | |
| } | |
| } | |
| protected: | |
| /* Gets pointer to a section header, given section index within ELF's | |
| * section table. | |
| * Param: | |
| * index - Section index within ELF's section table. | |
| * Return: | |
| * Pointer to a section header (ElfXX_SHdr flavor, depending on ELF's CPU | |
| * architecture) on success, or NULL if section index exceeds number of | |
| * sections for this ELF file. | |
| */ | |
| const void* get_section_by_index(Elf_Half index) const { | |
| assert(index < sec_count_); | |
| if (index < sec_count_) { | |
| return INC_CPTR(sec_table_, static_cast<size_t>(index) * sec_entry_size_); | |
| } else { | |
| _set_errno(EINVAL); | |
| return NULL; | |
| } | |
| } | |
| //============================================================================= | |
| // DWARF management. | |
| //============================================================================= | |
| protected: | |
| /* Parses DWARF, and buids a list of compilation units for this ELF file. | |
| * Compilation unit, collected with this methods are linked together in a | |
| * list, head of which is available via last_cu() method of this class. | |
| * NOTE: CUs in the list returned via last_cu() method are in reverse order | |
| * relatively to the order in which CUs are stored in .debug_info section. | |
| * This is ELF and DWARF data format - dependent method. | |
| * Param: | |
| * parse_context - Parsing context that defines which tags, and which | |
| * properties for which tag should be collected during parsing. NULL | |
| * passed in this parameter indicates that all properties for all tags | |
| * should be collected. | |
| * Return: | |
| * Number of compilation units, collected in this method on success, | |
| * or -1 on failure. | |
| */ | |
| virtual int parse_compilation_units(const DwarfParseContext* parse_context) = 0; | |
| public: | |
| /* Gets PC address information. | |
| * Param: | |
| * address - PC address to get information for. The address must be relative | |
| * to the beginning of ELF file represented by this class. | |
| * address_info - Upon success contains information about routine(s) that | |
| * contain the given address. | |
| * Return: | |
| * true if routine(s) containing has been found and its information has been | |
| * saved into address_info, or false if no appropriate routine for that | |
| * address has been found, or there was a memory error when collecting | |
| * routine(s) information. In case of failure, errno contains extended error | |
| * information. | |
| */ | |
| bool get_pc_address_info(Elf_Xword address, Elf_AddressInfo* address_info); | |
| /* Frees resources aqcuired for address information in successful call to | |
| * get_pc_address_info(). | |
| * Param: | |
| * address_info - Address information structure, initialized in successful | |
| * call to get_pc_address_info() routine. | |
| */ | |
| void free_pc_address_info(Elf_AddressInfo* address_info) const; | |
| /* Gets beginning of the .debug_info section data. | |
| * Return: | |
| * Beginning of the .debug_info section data. | |
| * NOTE: pointer returned from this method points to a mapped section of | |
| * ELF file. | |
| */ | |
| const void* get_debug_info_data() const { | |
| return debug_info_.data(); | |
| } | |
| /* Gets beginning of the .debug_abbrev section data. | |
| * Return: | |
| * Beginning of the .debug_abbrev section data. | |
| * NOTE: pointer returned from this method points to a mapped section of | |
| * ELF file. | |
| */ | |
| const void* get_debug_abbrev_data() const { | |
| return debug_abbrev_.data(); | |
| } | |
| /* Gets beginning of the .debug_ranges section data. | |
| * Return: | |
| * Beginning of the .debug_ranges section data. | |
| * NOTE: pointer returned from this method points to a mapped section of | |
| * ELF file. | |
| */ | |
| const void* get_debug_ranges_data() const { | |
| return debug_ranges_.data(); | |
| } | |
| /* Gets beginning of the .debug_line section data. | |
| * Return: | |
| * Beginning of the .debug_line section data. | |
| * NOTE: pointer returned from this method points to a mapped section of | |
| * ELF file. | |
| */ | |
| const void* get_debug_line_data() const { | |
| return debug_line_.data(); | |
| } | |
| /* Checks, if given address range is contained in the mapped .debug_info | |
| * section of this file. | |
| * Param: | |
| * ptr - Starting address of the range. | |
| * size - Range size in bytes. | |
| * Return: | |
| * true if given address range is contained in the mapped .debug_info | |
| * section of this file, or false if any part of the range doesn't belong | |
| * to that section. | |
| */ | |
| bool is_valid_die_ptr(const void* ptr, size_t size) const { | |
| return debug_info_.is_contained(ptr, size); | |
| } | |
| /* Checks, if given address range is contained in the mapped .debug_abbrev | |
| * section of this file. | |
| * Param: | |
| * ptr - Starting address of the range. | |
| * size - Range size in bytes. | |
| * Return: | |
| * true if given address range is contained in the mapped .debug_abbrev | |
| * section of this file, or false if any part of the range doesn't belong | |
| * to that section. | |
| */ | |
| bool is_valid_abbr_ptr(const void* ptr, size_t size) const { | |
| return debug_abbrev_.is_contained(ptr, size); | |
| } | |
| /* Checks if given pointer addresses a valid compilation unit header in the | |
| * mapped .debug_info section of the ELF file. | |
| * Param: | |
| * cu_header - Pointer to a compilation unit header to check. | |
| * Return | |
| * true, if given pointer addresses a valid compilation unit header, or | |
| * false, if it's not. A valid CU header must be fully conained inside | |
| * .debug_info section of the ELF file, and its size must not be zero. | |
| */ | |
| bool is_valid_cu(const void* cu_header) const { | |
| if (is_DWARF_64()) { | |
| return is_valid_die_ptr(cu_header, sizeof(Dwarf64_CUHdr)) && | |
| reinterpret_cast<const Dwarf64_CUHdr*>(cu_header)->size_hdr.size != 0; | |
| } else { | |
| return is_valid_die_ptr(cu_header, sizeof(Dwarf32_CUHdr)) && | |
| reinterpret_cast<const Dwarf32_CUHdr*>(cu_header)->size_hdr.size != 0; | |
| } | |
| } | |
| /* Gets range's low and high pc for the given range reference in the mapped | |
| * .debug_ranges section of an ELF file. | |
| * Template param: | |
| * AddrType - Defines pointer type for the CU the range belongs to. CU's | |
| * pointer type can be defined independently from ELF and DWARF types, | |
| * and is encoded in address_size field of the CU header in .debug_info | |
| * section of ELF file. | |
| * Param: | |
| * offset - Byte offset within .debug_ranges section of the range record. | |
| * low - Upon successful return contains value for range's low pc. | |
| * high - Upon successful return contains value for range's high pc. | |
| * Return: | |
| * true on success, or false, if requested record is not fully contained | |
| * in the .debug_ranges section. | |
| */ | |
| template<typename AddrType> | |
| bool get_range(Elf_Word offset, AddrType* low, AddrType* high) { | |
| const AddrType* ptr = INC_CPTR_T(AddrType, debug_ranges_.data(), offset); | |
| assert(debug_ranges_.is_contained(ptr, sizeof(AddrType) * 2)); | |
| if (!debug_ranges_.is_contained(ptr, sizeof(AddrType) * 2)) { | |
| _set_errno(EINVAL); | |
| return false; | |
| } | |
| *low = pull_val(ptr); | |
| *high = pull_val(ptr + 1); | |
| return true; | |
| } | |
| protected: | |
| /* Mapped ELF string section. */ | |
| ElfMappedSection string_section_; | |
| /* Mapped .debug_info section. */ | |
| ElfMappedSection debug_info_; | |
| /* Mapped .debug_abbrev section. */ | |
| ElfMappedSection debug_abbrev_; | |
| /* Mapped .debug_str section. */ | |
| ElfMappedSection debug_str_; | |
| /* Mapped .debug_line section. */ | |
| ElfMappedSection debug_line_; | |
| /* Mapped .debug_ranges section. */ | |
| ElfMappedSection debug_ranges_; | |
| /* Base address of the loaded module (if fixed), or 0 if module doesn't get | |
| * loaded at fixed address. */ | |
| Elf_Xword fixed_base_address_; | |
| /* Handle to the ELF file represented with this instance. */ | |
| MapFile* elf_handle_; | |
| /* Path to the ELF file represented with this instance. */ | |
| char* elf_file_path_; | |
| /* DWARF objects allocator for this instance. */ | |
| class ElfAllocator* allocator_; | |
| /* Beginning of the cached ELF's section table. */ | |
| void* sec_table_; | |
| /* Number of sections in the ELF file wrapped by this instance. */ | |
| Elf_Half sec_count_; | |
| /* Byte size of an entry in the section table. */ | |
| Elf_Half sec_entry_size_; | |
| /* Head of compilation unit list, collected during the parsing. */ | |
| class DwarfCU* last_cu_; | |
| /* Number of compilation units in last_cu_ list. */ | |
| int cu_count_; | |
| /* Flags ELF's CPU architecture: 64 (true), or 32 bits (false). */ | |
| bool is_ELF_64_; | |
| /* Flags endianness of the processed ELF file. true indicates that ELF file | |
| * data is stored in big-endian form, false indicates that ELF file data is | |
| * stored in big-endian form. | |
| */ | |
| bool is_elf_big_endian_; | |
| /* Flags whether or not endianness of CPU this library is built for matches | |
| * endianness of the ELF file that is represented with this instance. | |
| */ | |
| bool same_endianness_; | |
| /* Flags DWARF format: 64, or 32 bits. DWARF format is determined by looking | |
| * at the first 4 bytes of .debug_info section (which is the beginning of the | |
| * first compilation unit header). If first 4 bytes contain 0xFFFFFFFF, the | |
| * DWARF is 64 bit. Otherwise, DWARF is 32 bit. */ | |
| bool is_DWARF_64_; | |
| /* Flags executable file. If this member is 1, ELF file represented with this | |
| * instance is an executable. If this member is 0, file is a shared library. | |
| */ | |
| bool is_exec_; | |
| }; | |
| /* Encapsulates architecture-dependent functionality of an ELF file. | |
| * Template param: | |
| * Elf_Addr - type for an address field in ELF file. Must be: | |
| * - Elf32_Addr for 32-bit CPU, or | |
| * - Elf64_Addr for 64-bit CPU. | |
| * Elf_Off - type for an offset field in ELF file. Must be: | |
| * - Elf64_Off for 32-bit CPU, or | |
| * - Elf64_Off for 64-bit CPU. | |
| */ | |
| template <typename Elf_Addr, typename Elf_Off> | |
| class ElfFileImpl : protected ElfFile { | |
| /* Instance of this class must be instantiated from | |
| * ElfFile::Create() method only. */ | |
| friend class ElfFile; | |
| protected: | |
| /* Constructs ElfFileImpl instance. */ | |
| ElfFileImpl() { | |
| }; | |
| /* Destructs ElfFileImpl instance. */ | |
| ~ElfFileImpl() { | |
| } | |
| protected: | |
| /* Initializes instance. This is an override of the base class method. | |
| * See ElfFile::initialize(). | |
| */ | |
| bool initialize(const Elf_CommonHdr* elf_hdr, const char* path); | |
| /* Parses DWARF, and buids list of compilation units for this ELF file. | |
| * This is an implementation of the base class' abstract method. | |
| * See ElfFile::parse_compilation_units(). | |
| */ | |
| virtual int parse_compilation_units(const DwarfParseContext* parse_context); | |
| /* Gets section information by section name. | |
| * Param: | |
| * name - Name of the section to get information for. | |
| * offset - Upon success contains offset of the section data in ELF file. | |
| * size - Upon success contains size of the section data in ELF file. | |
| * Return: | |
| * true on sucess, or false if section with such name doesn't exist in | |
| * this ELF file. | |
| */ | |
| bool get_section_info_by_name(const char* name, | |
| Elf_Off* offset, | |
| Elf_Word* size); | |
| /* Maps section by its name. | |
| * Param: | |
| * name - Name of the section to map. | |
| * section - Upon success contains section's mapping information. | |
| * Return: | |
| * true on sucess, or false if section with such name doesn't exist in | |
| * this ELF file, or mapping has failed. | |
| */ | |
| bool map_section_by_name(const char* name, ElfMappedSection* section); | |
| }; | |
| #endif // ELFF_ELF_FILE_H_ |