| /* 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 "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_ |