//===-- ELFHeader.h ------------------------------------------- -*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
/// @file
/// @brief Generic structures and typedefs for ELF files.
///
/// This file provides definitions for the various entities comprising an ELF
/// file.  The structures are generic in the sense that they do not correspond
/// to the exact binary layout of an ELF, but can be used to hold the
/// information present in both 32 and 64 bit variants of the format.  Each
/// entity provides a \c Parse method which is capable of transparently reading
/// both 32 and 64 bit instances of the object.
//===----------------------------------------------------------------------===//

#ifndef liblldb_ELFHeader_h_
#define liblldb_ELFHeader_h_

#include "llvm/Support/ELF.h"

#include "lldb/lldb-enumerations.h"

namespace lldb_private
{
class DataExtractor;
} // End namespace lldb_private.

namespace elf 
{

//------------------------------------------------------------------------------
/// @name ELF type definitions.
///
/// Types used to represent the various components of ELF structures.  All types
/// are signed or unsigned integral types wide enough to hold values from both
/// 32 and 64 bit ELF variants.
//@{
typedef uint64_t elf_addr;
typedef uint64_t elf_off;
typedef uint16_t elf_half;
typedef uint32_t elf_word;
typedef int32_t  elf_sword;
typedef uint64_t elf_size;
typedef uint64_t elf_xword;
typedef int64_t  elf_sxword;
//@}

//------------------------------------------------------------------------------
/// @class ELFHeader
/// @brief Generic representation of an ELF file header.
///
/// This object is used to identify the general attributes on an ELF file and to
/// locate additional sections within the file.
struct ELFHeader 
{
    unsigned char e_ident[llvm::ELF::EI_NIDENT]; ///< ELF file identification.
    elf_addr      e_entry;            ///< Virtual address program entry point.
    elf_off       e_phoff;            ///< File offset of program header table.
    elf_off       e_shoff;            ///< File offset of section header table.
    elf_word      e_flags;            ///< Processor specific flags.
    elf_word      e_version;          ///< Version of object file (always 1).
    elf_half      e_type;             ///< Object file type.
    elf_half      e_machine;          ///< Target architecture.
    elf_half      e_ehsize;           ///< Byte size of the ELF header.
    elf_half      e_phentsize;        ///< Size of a program header table entry.
    elf_half      e_phnum;            ///< Number of program header entries.
    elf_half      e_shentsize;        ///< Size of a section header table entry.
    elf_half      e_shnum;            ///< Number of section header entries.
    elf_half      e_shstrndx;         ///< String table section index.

    ELFHeader();

    //--------------------------------------------------------------------------
    /// Returns true if this is a 32 bit ELF file header.
    ///
    /// @return
    ///    True if this is a 32 bit ELF file header.
    bool Is32Bit() const { 
        return e_ident[llvm::ELF::EI_CLASS] == llvm::ELF::ELFCLASS32; 
    }

    //--------------------------------------------------------------------------
    /// Returns true if this is a 64 bit ELF file header.
    ///
    /// @return
    ///   True if this is a 64 bit ELF file header.
    bool Is64Bit() const { 
        return e_ident[llvm::ELF::EI_CLASS] == llvm::ELF::ELFCLASS64; 
    }

    //--------------------------------------------------------------------------
    /// The byte order of this ELF file header.
    ///
    /// @return
    ///    The byte order of this ELF file as described by the header.
    lldb::ByteOrder
    GetByteOrder() const;

    //--------------------------------------------------------------------------
    /// The jump slot relocation type of this ELF.
    unsigned
    GetRelocationJumpSlotType() const;

    //--------------------------------------------------------------------------
    /// Parse an ELFHeader entry starting at position \p offset and
    /// update the data extractor with the address size and byte order
    /// attributes as defined by the header.
    ///
    /// @param[in,out] data
    ///    The DataExtractor to read from.  Updated with the address size and
    ///    byte order attributes appropriate to this header.
    ///
    /// @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 ELFHeader was successfully read and false
    ///    otherwise.
    bool
    Parse(lldb_private::DataExtractor &data, lldb::offset_t *offset);

    //--------------------------------------------------------------------------
    /// Examines at most EI_NIDENT bytes starting from the given pointer and
    /// determines if the magic ELF identification exists.
    ///
    /// @return
    ///    True if the given sequence of bytes identifies an ELF file.
    static bool
    MagicBytesMatch(const uint8_t *magic);

    //--------------------------------------------------------------------------
    /// Examines at most EI_NIDENT bytes starting from the given address and
    /// determines the address size of the underlying ELF file.  This function
    /// should only be called on an pointer for which MagicBytesMatch returns
    /// true.
    ///
    /// @return
    ///    The number of bytes forming an address in the ELF file (either 4 or
    ///    8), else zero if the address size could not be determined.
    static unsigned
    AddressSizeInBytes(const uint8_t *magic);
};

//------------------------------------------------------------------------------
/// @class ELFSectionHeader
/// @brief Generic representation of an ELF section header.
struct ELFSectionHeader 
{
    elf_word  sh_name;          ///< Section name string index.
    elf_word  sh_type;          ///< Section type.
    elf_xword sh_flags;         ///< Section attributes. 
    elf_addr  sh_addr;          ///< Virtual address of the section in memory.
    elf_off   sh_offset;        ///< Start of section from beginning of file.
    elf_xword sh_size;          ///< Number of bytes occupied in the file.
    elf_word  sh_link;          ///< Index of associated section.
    elf_word  sh_info;          ///< Extra section info (overloaded).
    elf_xword sh_addralign;     ///< Power of two alignment constraint.
    elf_xword sh_entsize;       ///< Byte size of each section entry.

    ELFSectionHeader();

    //--------------------------------------------------------------------------
    /// Parse an ELFSectionHeader entry from the given DataExtracter starting at
    /// position \p offset.
    ///
    /// @param[in] data
    ///    The DataExtractor to read from.  The address size of the extractor
    ///    determines if a 32 or 64 bit object should be read.
    ///
    /// @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 ELFSectionHeader was successfully read and false
    ///    otherwise.
    bool
    Parse(const lldb_private::DataExtractor &data, lldb::offset_t *offset);
};

//------------------------------------------------------------------------------
/// @class ELFProgramHeader
/// @brief Generic representation of an ELF program header.
struct ELFProgramHeader
{
    elf_word  p_type;           ///< Type of program segment.
    elf_word  p_flags;          ///< Segment attributes.
    elf_off   p_offset;         ///< Start of segment from beginning of file.
    elf_addr  p_vaddr;          ///< Virtual address of segment in memory.
    elf_addr  p_paddr;          ///< Physical address (for non-VM systems). 
    elf_xword p_filesz;         ///< Byte size of the segment in file.
    elf_xword p_memsz;          ///< Byte size of the segment in memory.
    elf_xword p_align;          ///< Segment alignment constraint.

    ELFProgramHeader();

    /// Parse an ELFProgramHeader entry from the given DataExtractor starting at
    /// position \p offset.  The address size of the DataExtractor determines if
    /// a 32 or 64 bit object is to be parsed.
    ///
    /// @param[in] data
    ///    The DataExtractor to read from.  The address size of the extractor
    ///    determines if a 32 or 64 bit object should be read.
    ///
    /// @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 ELFProgramHeader was successfully read and false
    ///    otherwise.
    bool
    Parse(const lldb_private::DataExtractor &data, lldb::offset_t *offset);
};

//------------------------------------------------------------------------------
/// @class ELFSymbol
/// @brief Represents a symbol within an ELF symbol table.
struct ELFSymbol
{
    elf_addr      st_value;     ///< Absolute or relocatable address.
    elf_xword     st_size;      ///< Size of the symbol or zero.
    elf_word      st_name;      ///< Symbol name string index.
    unsigned char st_info;      ///< Symbol type and binding attributes.
    unsigned char st_other;     ///< Reserved for future use.
    elf_half      st_shndx;     ///< Section to which this symbol applies.

    ELFSymbol();

    /// Returns the binding attribute of the st_info member.
    unsigned char getBinding() const { return st_info >> 4; }

    /// Returns the type attribute of the st_info member.
    unsigned char getType() const { return st_info & 0x0F; }

    /// Sets the binding and type of the st_info member.
    void setBindingAndType(unsigned char binding, unsigned char type) {
        st_info = (binding << 4) + (type & 0x0F);
    }

    static const char *
    bindingToCString(unsigned char binding);

    static const char *
    typeToCString(unsigned char type);

    static const char *
    sectionIndexToCString(elf_half shndx,
                          const lldb_private::SectionList *section_list);

    /// Parse an ELFSymbol entry from the given DataExtractor starting at
    /// position \p offset.  The address size of the DataExtractor determines if
    /// a 32 or 64 bit object is to be parsed.
    ///
    /// @param[in] data
    ///    The DataExtractor to read from.  The address size of the extractor
    ///    determines if a 32 or 64 bit object should be read.
    ///
    /// @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 ELFSymbol was successfully read and false otherwise.
    bool
    Parse(const lldb_private::DataExtractor &data, lldb::offset_t *offset);
    
    void
    Dump (lldb_private::Stream *s,
          uint32_t idx,
          const lldb_private::DataExtractor *strtab_data,
          const lldb_private::SectionList *section_list);
};

//------------------------------------------------------------------------------
/// @class ELFDynamic
/// @brief Represents an entry in an ELF dynamic table.
struct ELFDynamic
{
    elf_sxword d_tag;           ///< Type of dynamic table entry.
    union
    {
        elf_xword d_val;        ///< Integer value of the table entry.
        elf_addr  d_ptr;        ///< Pointer value of the table entry.
    };

    ELFDynamic();

    /// Parse an ELFDynamic entry from the given DataExtractor starting at
    /// position \p offset.  The address size of the DataExtractor determines if
    /// a 32 or 64 bit object is to be parsed.
    ///
    /// @param[in] data
    ///    The DataExtractor to read from.  The address size of the extractor
    ///    determines if a 32 or 64 bit object should be read.
    ///
    /// @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 ELFDynamic entry was successfully read and false
    ///    otherwise.
    bool
    Parse(const lldb_private::DataExtractor &data, lldb::offset_t *offset);
};

//------------------------------------------------------------------------------
/// @class ELFRel
/// @brief Represents a relocation entry with an implicit addend.
struct ELFRel
{
    elf_addr  r_offset;         ///< Address of reference.
    elf_xword r_info;           ///< symbol index and type of relocation.

    ELFRel();

    /// Parse an ELFRel entry from the given DataExtractor starting at position
    /// \p offset.  The address size of the DataExtractor determines if a 32 or
    /// 64 bit object is to be parsed.
    ///
    /// @param[in] data
    ///    The DataExtractor to read from.  The address size of the extractor
    ///    determines if a 32 or 64 bit object should be read.
    ///
    /// @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);

    /// Returns the type when the given entry represents a 32-bit relocation.
    static unsigned
    RelocType32(const ELFRel &rel)
    {
        return rel.r_info & 0x0ff;
    }

    /// Returns the type when the given entry represents a 64-bit relocation.
    static unsigned
    RelocType64(const ELFRel &rel)
    {
        return rel.r_info & 0xffffffff;
    }

    /// Returns the symbol index when the given entry represents a 32-bit
    /// relocation.
    static unsigned
    RelocSymbol32(const ELFRel &rel)
    {
        return rel.r_info >> 8;
    }

    /// Returns the symbol index when the given entry represents a 64-bit
    /// relocation.
    static unsigned
    RelocSymbol64(const ELFRel &rel)
    {
        return rel.r_info >> 32;
    }
};

//------------------------------------------------------------------------------
/// @class ELFRela
/// @brief Represents a relocation entry with an explicit addend.
struct ELFRela
{
    elf_addr   r_offset;        ///< Address of reference.
    elf_xword  r_info;          ///< Symbol index and type of relocation.
    elf_sxword r_addend;        ///< Constant part of expression.

    ELFRela();

    /// Parse an ELFRela entry from the given DataExtractor starting at position
    /// \p offset.  The address size of the DataExtractor determines if a 32 or
    /// 64 bit object is to be parsed.
    ///
    /// @param[in] data
    ///    The DataExtractor to read from.  The address size of the extractor
    ///    determines if a 32 or 64 bit object should be read.
    ///
    /// @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 ELFRela entry was successfully read and false otherwise.
    bool
    Parse(const lldb_private::DataExtractor &data, lldb::offset_t *offset);

    /// Returns the type when the given entry represents a 32-bit relocation.
    static unsigned
    RelocType32(const ELFRela &rela)
    {
        return rela.r_info & 0x0ff;
    }

    /// Returns the type when the given entry represents a 64-bit relocation.
    static unsigned
    RelocType64(const ELFRela &rela)
    {
        return rela.r_info & 0xffffffff;
    }

    /// Returns the symbol index when the given entry represents a 32-bit
    /// relocation.
    static unsigned
    RelocSymbol32(const ELFRela &rela)
    {
        return rela.r_info >> 8;
    }

    /// Returns the symbol index when the given entry represents a 64-bit
    /// relocation.
    static unsigned
    RelocSymbol64(const ELFRela &rela)
    {
        return rela.r_info >> 32;
    }
};

} // End namespace elf.

#endif // #ifndef liblldb_ELFHeader_h_
