| //===-- ObjectFileELF.h --------------------------------------- -*- C++ -*-===// | |
| // | |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| // See https://llvm.org/LICENSE.txt for license information. | |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #ifndef LLDB_SOURCE_PLUGINS_OBJECTFILE_ELF_OBJECTFILEELF_H | |
| #define LLDB_SOURCE_PLUGINS_OBJECTFILE_ELF_OBJECTFILEELF_H | |
| #include <cstdint> | |
| #include <optional> | |
| #include <vector> | |
| #include "lldb/Symbol/ObjectFile.h" | |
| #include "lldb/Utility/ArchSpec.h" | |
| #include "lldb/Utility/FileSpec.h" | |
| #include "lldb/Utility/UUID.h" | |
| #include "lldb/lldb-private.h" | |
| #include "ELFHeader.h" | |
| struct ELFNote { | |
| elf::elf_word n_namesz = 0; | |
| elf::elf_word n_descsz = 0; | |
| elf::elf_word n_type = 0; | |
| std::string n_name; | |
| ELFNote() = default; | |
| /// Parse an ELFNote entry from the given DataExtractor starting at position | |
| /// \p offset. | |
| /// | |
| /// \param[in] data | |
| /// The DataExtractor to read from. | |
| /// | |
| /// \param[in,out] offset | |
| /// Pointer to an offset in the data. On return the offset will be | |
| /// advanced by the number of bytes read. | |
| /// | |
| /// \return | |
| /// True if the ELFRel entry was successfully read and false otherwise. | |
| bool Parse(const lldb_private::DataExtractor &data, lldb::offset_t *offset); | |
| size_t GetByteSize() const { | |
| return 12 + llvm::alignTo(n_namesz, 4) + llvm::alignTo(n_descsz, 4); | |
| } | |
| }; | |
| /// \class ObjectFileELF | |
| /// Generic ELF object file reader. | |
| /// | |
| /// This class provides a generic ELF (32/64 bit) reader plugin implementing | |
| /// the ObjectFile protocol. | |
| class ObjectFileELF : public lldb_private::ObjectFile { | |
| public: | |
| // Static Functions | |
| static void Initialize(); | |
| static void Terminate(); | |
| static llvm::StringRef GetPluginNameStatic() { return "elf"; } | |
| static llvm::StringRef GetPluginDescriptionStatic() { | |
| return "ELF object file reader."; | |
| } | |
| static lldb_private::ObjectFile * | |
| CreateInstance(const lldb::ModuleSP &module_sp, | |
| lldb::DataExtractorSP extractor_sp, lldb::offset_t data_offset, | |
| const lldb_private::FileSpec *file, lldb::offset_t file_offset, | |
| lldb::offset_t length); | |
| static lldb_private::ObjectFile *CreateMemoryInstance( | |
| const lldb::ModuleSP &module_sp, lldb::WritableDataBufferSP data_sp, | |
| const lldb::ProcessSP &process_sp, lldb::addr_t header_addr); | |
| static lldb_private::ModuleSpecList | |
| GetModuleSpecifications(const lldb_private::FileSpec &file, | |
| lldb::DataExtractorSP &extractor_sp, | |
| lldb::offset_t file_offset, lldb::offset_t length); | |
| static bool MagicBytesMatch(lldb::DataBufferSP data_sp, lldb::addr_t offset, | |
| lldb::addr_t length); | |
| // PluginInterface protocol | |
| llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); } | |
| // LLVM RTTI support | |
| static char ID; | |
| bool isA(const void *ClassID) const override { | |
| return ClassID == &ID || ObjectFile::isA(ClassID); | |
| } | |
| static bool classof(const ObjectFile *obj) { return obj->isA(&ID); } | |
| // ObjectFile Protocol. | |
| bool ParseHeader() override; | |
| bool SetLoadAddress(lldb_private::Target &target, lldb::addr_t value, | |
| bool value_is_offset) override; | |
| lldb::ByteOrder GetByteOrder() const override; | |
| bool IsExecutable() const override; | |
| uint32_t GetAddressByteSize() const override; | |
| lldb_private::AddressClass GetAddressClass(lldb::addr_t file_addr) override; | |
| void ParseSymtab(lldb_private::Symtab &symtab) override; | |
| bool IsStripped() override; | |
| void CreateSections(lldb_private::SectionList &unified_section_list) override; | |
| void Dump(lldb_private::Stream *s) override; | |
| lldb_private::ArchSpec GetArchitecture() override; | |
| lldb_private::UUID GetUUID() override; | |
| /// Return the contents of the .gnu_debuglink section, if the object file | |
| /// contains it. | |
| std::optional<lldb_private::FileSpec> GetDebugLink(); | |
| uint32_t GetDependentModules(lldb_private::FileSpecList &files) override; | |
| lldb_private::FileSpecList GetReExportedLibraries() override; | |
| bool ReExportedLibrariesShadowLocalDefinitions() const override { | |
| return true; | |
| } | |
| lldb_private::Address | |
| GetImageInfoAddress(lldb_private::Target *target) override; | |
| lldb_private::Address GetEntryPointAddress() override; | |
| lldb_private::Address GetBaseAddress() override; | |
| ObjectFile::Type CalculateType() override; | |
| ObjectFile::Strata CalculateStrata() override; | |
| size_t ReadSectionData(lldb_private::Section *section, | |
| lldb::offset_t section_offset, void *dst, | |
| size_t dst_len) override; | |
| size_t ReadSectionData(lldb_private::Section *section, | |
| lldb_private::DataExtractor §ion_data) override; | |
| llvm::ArrayRef<elf::ELFProgramHeader> ProgramHeaders(); | |
| lldb_private::DataExtractor GetSegmentData(const elf::ELFProgramHeader &H); | |
| llvm::StringRef | |
| StripLinkerSymbolAnnotations(llvm::StringRef symbol_name) const override; | |
| void RelocateSection(lldb_private::Section *section) override; | |
| protected: | |
| std::vector<LoadableData> | |
| GetLoadableData(lldb_private::Target &target) override; | |
| static lldb::WritableDataBufferSP | |
| MapFileDataWritable(const lldb_private::FileSpec &file, uint64_t Size, | |
| uint64_t Offset); | |
| private: | |
| ObjectFileELF(const lldb::ModuleSP &module_sp, | |
| lldb::DataExtractorSP extractor_sp, lldb::offset_t data_offset, | |
| const lldb_private::FileSpec *file, lldb::offset_t offset, | |
| lldb::offset_t length); | |
| ObjectFileELF(const lldb::ModuleSP &module_sp, | |
| lldb::DataBufferSP header_data_sp, | |
| const lldb::ProcessSP &process_sp, lldb::addr_t header_addr); | |
| typedef std::vector<elf::ELFProgramHeader> ProgramHeaderColl; | |
| struct ELFSectionHeaderInfo : public elf::ELFSectionHeader { | |
| std::string section_name; | |
| }; | |
| typedef std::vector<ELFSectionHeaderInfo> SectionHeaderColl; | |
| typedef SectionHeaderColl::iterator SectionHeaderCollIter; | |
| typedef SectionHeaderColl::const_iterator SectionHeaderCollConstIter; | |
| struct ELFDynamicWithName { | |
| elf::ELFDynamic symbol; | |
| std::string name; | |
| }; | |
| typedef std::vector<ELFDynamicWithName> DynamicSymbolColl; | |
| typedef DynamicSymbolColl::iterator DynamicSymbolCollIter; | |
| typedef DynamicSymbolColl::const_iterator DynamicSymbolCollConstIter; | |
| /// An ordered map of file address to address class. Used on architectures | |
| /// like Arm where there is an alternative ISA mode like Thumb. The container | |
| /// is ordered so that it can be binary searched. | |
| typedef std::map<lldb::addr_t, lldb_private::AddressClass> | |
| FileAddressToAddressClassMap; | |
| /// Version of this reader common to all plugins based on this class. | |
| static const uint32_t m_plugin_version = 1; | |
| static const uint32_t g_core_uuid_magic; | |
| /// ELF file header. | |
| elf::ELFHeader m_header; | |
| /// ELF build ID. | |
| lldb_private::UUID m_uuid; | |
| /// ELF .gnu_debuglink file and crc data if available. | |
| std::string m_gnu_debuglink_file; | |
| uint32_t m_gnu_debuglink_crc = 0; | |
| /// Collection of program headers. | |
| ProgramHeaderColl m_program_headers; | |
| /// Collection of section headers. | |
| SectionHeaderColl m_section_headers; | |
| /// The file address of the .dynamic section. This can be found in the p_vaddr | |
| /// of the PT_DYNAMIC program header. | |
| lldb::addr_t m_dynamic_base_addr = LLDB_INVALID_ADDRESS; | |
| /// Collection of symbols from the dynamic table. | |
| DynamicSymbolColl m_dynamic_symbols; | |
| /// Object file parsed from .gnu_debugdata section (\sa | |
| /// GetGnuDebugDataObjectFile()) | |
| std::shared_ptr<ObjectFileELF> m_gnu_debug_data_object_file; | |
| /// List of file specifications corresponding to the modules (shared | |
| /// libraries) on which this object file depends. | |
| mutable std::unique_ptr<lldb_private::FileSpecList> m_filespec_up; | |
| /// Cached value of the entry point for this module. | |
| lldb_private::Address m_entry_point_address; | |
| /// The architecture detected from parsing elf file contents. | |
| lldb_private::ArchSpec m_arch_spec; | |
| /// The address class for each symbol in the elf file | |
| FileAddressToAddressClassMap m_address_class_map; | |
| /// Returns the index of the given section header. | |
| size_t SectionIndex(const SectionHeaderCollIter &I); | |
| /// Returns the index of the given section header. | |
| size_t SectionIndex(const SectionHeaderCollConstIter &I) const; | |
| // Parses the ELF program headers. | |
| static size_t GetProgramHeaderInfo(ProgramHeaderColl &program_headers, | |
| lldb_private::DataExtractor &object_data, | |
| const elf::ELFHeader &header); | |
| // Finds PT_NOTE segments and calculates their crc sum. | |
| static uint32_t | |
| CalculateELFNotesSegmentsCRC32(const ProgramHeaderColl &program_headers, | |
| lldb_private::DataExtractor &data); | |
| /// Parses all section headers present in this object file and populates | |
| /// m_program_headers. This method will compute the header list only once. | |
| /// Returns true iff the headers have been successfully parsed. | |
| bool ParseProgramHeaders(); | |
| /// Parses all section headers present in this object file and populates | |
| /// m_section_headers. This method will compute the header list only once. | |
| /// Returns the number of headers parsed. | |
| size_t ParseSectionHeaders(); | |
| lldb::SectionType GetSectionType(const ELFSectionHeaderInfo &H) const; | |
| static void ParseARMAttributes(lldb_private::DataExtractor &data, | |
| uint64_t length, | |
| lldb_private::ArchSpec &arch_spec); | |
| static void ParseRISCVAttributes(const lldb_private::DataExtractor &data, | |
| uint64_t length, | |
| lldb_private::ArchSpec &arch_spec); | |
| /// Parses the elf section headers and returns the uuid, debug link name, | |
| /// crc, archspec. | |
| static size_t GetSectionHeaderInfo(SectionHeaderColl §ion_headers, | |
| lldb_private::DataExtractor &object_data, | |
| const elf::ELFHeader &header, | |
| lldb_private::UUID &uuid, | |
| std::string &gnu_debuglink_file, | |
| uint32_t &gnu_debuglink_crc, | |
| lldb_private::ArchSpec &arch_spec); | |
| /// Scans the dynamic section and locates all dependent modules (shared | |
| /// libraries) populating m_filespec_up. This method will compute the | |
| /// dependent module list only once. Returns the number of dependent | |
| /// modules parsed. | |
| size_t ParseDependentModules(); | |
| /// Parses the dynamic symbol table and populates m_dynamic_symbols. The | |
| /// vector retains the order as found in the object file. Returns the | |
| /// number of dynamic symbols parsed. | |
| size_t ParseDynamicSymbols(); | |
| /// Populates the symbol table with all non-dynamic linker symbols. This | |
| /// method will parse the symbols only once. Returns the number of symbols | |
| /// parsed and a map of address types (used by targets like Arm that have | |
| /// an alternative ISA mode like Thumb). | |
| std::pair<unsigned, FileAddressToAddressClassMap> | |
| ParseSymbolTable(lldb_private::Symtab *symbol_table, lldb::user_id_t start_id, | |
| lldb_private::Section *symtab); | |
| /// Helper routine for ParseSymbolTable(). | |
| std::pair<unsigned, FileAddressToAddressClassMap> | |
| ParseSymbols(lldb_private::Symtab *symbol_table, lldb::user_id_t start_id, | |
| lldb_private::SectionList *section_list, | |
| const size_t num_symbols, | |
| const lldb_private::DataExtractor &symtab_data, | |
| const lldb_private::DataExtractor &strtab_data); | |
| /// Scans the relocation entries and adds a set of artificial symbols to the | |
| /// given symbol table for each PLT slot. Returns the number of symbols | |
| /// added. | |
| unsigned ParseTrampolineSymbols(lldb_private::Symtab *symbol_table, | |
| lldb::user_id_t start_id, | |
| const ELFSectionHeaderInfo *rela_hdr, | |
| lldb::user_id_t section_id); | |
| void ParseUnwindSymbols(lldb_private::Symtab *symbol_table, | |
| lldb_private::DWARFCallFrameInfo *eh_frame); | |
| /// Relocates debug sections | |
| unsigned RelocateDebugSections(const elf::ELFSectionHeader *rel_hdr, | |
| lldb::user_id_t rel_id, | |
| lldb_private::Symtab *thetab); | |
| unsigned ApplyRelocations(lldb_private::Symtab *symtab, | |
| const elf::ELFHeader *hdr, | |
| const elf::ELFSectionHeader *rel_hdr, | |
| const elf::ELFSectionHeader *symtab_hdr, | |
| const elf::ELFSectionHeader *debug_hdr, | |
| lldb_private::DataExtractor &rel_data, | |
| lldb_private::DataExtractor &symtab_data, | |
| lldb_private::DataExtractor &debug_data, | |
| lldb_private::Section *rel_section); | |
| /// Loads the section name string table into m_shstr_data. Returns the | |
| /// number of bytes constituting the table. | |
| size_t GetSectionHeaderStringTable(); | |
| /// Utility method for looking up a section given its name. Returns the | |
| /// index of the corresponding section or zero if no section with the given | |
| /// name can be found (note that section indices are always 1 based, and so | |
| /// section index 0 is never valid). | |
| lldb::user_id_t GetSectionIndexByName(llvm::StringRef name); | |
| /// Returns the section header with the given id or NULL. | |
| const ELFSectionHeaderInfo *GetSectionHeaderByIndex(lldb::user_id_t id); | |
| /// \name ELF header dump routines | |
| //@{ | |
| static void DumpELFHeader(lldb_private::Stream *s, | |
| const elf::ELFHeader &header); | |
| static void DumpELFHeader_e_ident_EI_DATA(lldb_private::Stream *s, | |
| unsigned char ei_data); | |
| static void DumpELFHeader_e_type(lldb_private::Stream *s, | |
| elf::elf_half e_type); | |
| //@} | |
| /// \name ELF program header dump routines | |
| //@{ | |
| void DumpELFProgramHeaders(lldb_private::Stream *s); | |
| static void DumpELFProgramHeader(lldb_private::Stream *s, | |
| const elf::ELFProgramHeader &ph); | |
| static void DumpELFProgramHeader_p_type(lldb_private::Stream *s, | |
| elf::elf_word p_type); | |
| static void DumpELFProgramHeader_p_flags(lldb_private::Stream *s, | |
| elf::elf_word p_flags); | |
| //@} | |
| /// \name ELF section header dump routines | |
| //@{ | |
| void DumpELFSectionHeaders(lldb_private::Stream *s); | |
| static void DumpELFSectionHeader(lldb_private::Stream *s, | |
| const ELFSectionHeaderInfo &sh); | |
| static void DumpELFSectionHeader_sh_type(lldb_private::Stream *s, | |
| elf::elf_word sh_type); | |
| static void DumpELFSectionHeader_sh_flags(lldb_private::Stream *s, | |
| elf::elf_xword sh_flags); | |
| //@} | |
| /// ELF dependent module dump routine. | |
| void DumpDependentModules(lldb_private::Stream *s); | |
| /// ELF dump the .dynamic section | |
| void DumpELFDynamic(lldb_private::Stream *s); | |
| const elf::ELFDynamic *FindDynamicSymbol(unsigned tag); | |
| unsigned PLTRelocationType(); | |
| static lldb_private::Status | |
| RefineModuleDetailsFromNote(lldb_private::DataExtractor &data, | |
| lldb_private::ArchSpec &arch_spec, | |
| lldb_private::UUID &uuid); | |
| bool AnySegmentHasPhysicalAddress(); | |
| /// Takes the .gnu_debugdata and returns the decompressed object file that is | |
| /// stored within that section. | |
| /// | |
| /// \returns either the decompressed object file stored within the | |
| /// .gnu_debugdata section or \c nullptr if an error occurred or if there's no | |
| /// section with that name. | |
| std::shared_ptr<ObjectFileELF> GetGnuDebugDataObjectFile(); | |
| /// Get the bytes that represent the .dynamic section. | |
| /// | |
| /// This function will fetch the data for the .dynamic section in an ELF file. | |
| /// The PT_DYNAMIC program header will be used to extract the data and this | |
| /// function will fall back to using the section headers if PT_DYNAMIC isn't | |
| /// found. | |
| /// | |
| /// \return The bytes that represent the string table data or \c std::nullopt | |
| /// if an error occurred. | |
| std::optional<lldb_private::DataExtractor> GetDynamicData(); | |
| /// Get the bytes that represent the dynamic string table data. | |
| /// | |
| /// This function will fetch the data for the string table in an ELF file. If | |
| /// the ELF file is loaded from a file on disk, it will use the section | |
| /// headers to extract the data and fall back to using the DT_STRTAB and | |
| /// DT_STRSZ .dynamic entries. | |
| /// | |
| /// \return The bytes that represent the string table data or \c std::nullopt | |
| /// if an error occurred. | |
| std::optional<lldb_private::DataExtractor> GetDynstrData(); | |
| /// Read the bytes pointed to by the \a dyn dynamic entry. | |
| /// | |
| /// ELFDynamic::d_ptr values contain file addresses if we load the ELF file | |
| /// form a file on disk, or they contain load addresses if they were read | |
| /// from memory. This function will correctly extract the data in both cases | |
| /// if it is available. | |
| /// | |
| /// \param[in] dyn The dynamic entry to use to fetch the data from. | |
| /// | |
| /// \param[in] length The number of bytes to read. | |
| /// | |
| /// \param[in] offset The number of bytes to skip after the d_ptr value | |
| /// before reading data. | |
| /// | |
| /// \return The bytes that represent the dynanic entries data or | |
| /// \c std::nullopt if an error occurred or the data is not available. | |
| std::optional<lldb_private::DataExtractor> | |
| ReadDataFromDynamic(const elf::ELFDynamic *dyn, uint64_t length, | |
| uint64_t offset = 0); | |
| /// Get the bytes that represent the dynamic symbol table from the .dynamic | |
| /// section from process memory. | |
| /// | |
| /// This functon uses the DT_SYMTAB value from the .dynamic section to read | |
| /// the symbols table data from process memory. The number of symbols in the | |
| /// symbol table is calculated by looking at the DT_HASH or DT_GNU_HASH | |
| /// values as the symbol count isn't stored in the .dynamic section. | |
| /// | |
| /// \return The bytes that represent the symbol table data from the .dynamic | |
| /// section or section headers or \c std::nullopt if an error | |
| /// occurred or if there is no dynamic symbol data available. | |
| std::optional<lldb_private::DataExtractor> | |
| GetDynsymDataFromDynamic(uint32_t &num_symbols); | |
| /// Get the number of symbols from the DT_HASH dynamic entry. | |
| std::optional<uint32_t> GetNumSymbolsFromDynamicHash(); | |
| /// Get the number of symbols from the DT_GNU_HASH dynamic entry. | |
| std::optional<uint32_t> GetNumSymbolsFromDynamicGnuHash(); | |
| }; | |
| #endif // LLDB_SOURCE_PLUGINS_OBJECTFILE_ELF_OBJECTFILEELF_H |