// Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
// All rights reserved.
// This component and the accompanying materials are made available
// under the terms of the License "Eclipse Public License v1.0"
// which accompanies this distribution, and is available
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
//
// Initial Contributors:
// Nokia Corporation - initial contribution.
//
// Contributors:
//
// Description:
//

#include "elf_file_header.h"
#include <stdexcept>
#include <string>


namespace elf
{
    File_header::File_header(const char* p1, const char* p2, bool a_pedantic)
        : m_data( reinterpret_cast<const Elf32_Ehdr*>(p1) )
    {
        if ( p1 + sizeof(Elf32_Ehdr) > p2 )
        {
            throw std::runtime_error("not an ELF object; file too small");
        }

        uint8_t m0 = m_data->e_ident[0];
        uint8_t m1 = m_data->e_ident[1];
        uint8_t m2 = m_data->e_ident[2];
        uint8_t m3 = m_data->e_ident[3];

        if (m0 != 0x7f || m1 != 'E' || m2 != 'L' || m3 != 'F')
        {
            throw std::runtime_error("not an ELF object; bad magic");
        }

        if (a_pedantic) // Do some extra checks for correctness.
        {
            //if (m_data->e_ident[4] != 1)
            //{
            //    throw std::runtime_error("invalid class; this program can only handle 32-bit objects");
            //}

            //if (m_data->e_ident[5] != 1)
            //{
            //    throw std::runtime_error("invalid encoding; this program can only handle little-endian objects");
            //}

            //for (unsigned i = EI_PAD; i < sizeof(m_data->e_ident); ++i)
            //{
            //    if (m_data->e_ident[i] != 0)
            //    {
            //        throw std::runtime_error("non-zero pading");
            //    }
            //}

            //if (m_data->e_type == ET_NONE)
            //{
            //    throw std::runtime_error("invalid type");
            //}

            //if (m_data->e_phoff == 0 && m_data->e_shoff == 0)
            //{
            //    throw std::runtime_error("no program headers and no section headers");
            //}

            //if ( m_data->e_phoff + m_data->e_phentsize * m_data->e_phnum > p2 - p1 + 1 )
            //{
            //    throw std::runtime_error("file too small for header table");
            //}

            //if (m_data->e_shoff + m_data->e_shentsize * m_data->e_shnum > a_mem.get_size() )
            //{
            //    throw std::runtime_error("file too small for header table");
            //}

            //if ( m_data->e_shentsize != sizeof(Elf32_Shdr) )
            //{
            //    throw std::runtime_error("e_shentsize doesn't match the actual size of the type");
            //}

            //if (m_data->e_shoff > 0 && m_data->e_shnum == 0)
            //{
            //    throw std::runtime_error("this program can't handle the combination e_shoff > 0 and e_shnum == 0");
            //}

            //if (m_data->e_shstrndx >= 0xff00)
            //{
            //    throw std::runtime_error("this program can only handle e_shstrndx < 0xff00");
            //}

        } // if (a_pedantic)
    }

    // The following functions are obvious candidates for inlining ...

    // e_type

    bool File_header::is_type_rel() const
    {
        return (m_data->e_type == ET_REL);
    }
    bool File_header::is_type_exec() const
    {
        return (m_data->e_type == ET_EXEC);
    }
    bool File_header::is_type_dyn() const
    {
        return (m_data->e_type == ET_DYN);
    }

    // e_machine

    bool File_header::is_machine_none() const
    {
        return (m_data->e_machine == EM_NONE);
    }
    bool File_header::is_machine_arm() const
    {
        return (m_data->e_machine == EM_ARM);
    }
    bool File_header::is_machine_386() const
    {
        return (m_data->e_machine == EM_386);
    }

    uint32_t File_header::get_entry() const
    {
        return m_data->e_entry;
    }

    uint32_t File_header::get_phoff() const
    {
        return m_data->e_phoff;
    }

    uint32_t File_header::get_shoff() const
    {
        return m_data->e_shoff;
    }

    uint32_t File_header::get_flags() const
    {
        return m_data->e_flags;
    }

    uint16_t File_header::get_ehsize() const
    {
        return m_data->e_ehsize;
    }

    uint16_t File_header::get_phentsize() const
    {
        return m_data->e_phentsize;
    }

    uint16_t File_header::get_phnum() const
    {
        return m_data->e_phnum;
    }

    uint16_t File_header::get_shentsize() const
    {
        return m_data->e_shentsize;
    }

    uint16_t File_header::get_shnum() const
    {
        return m_data->e_shnum;
    }

    uint16_t File_header::get_shstrndx() const
    {
        return m_data->e_shstrndx;
    }

} // namespace elf

