/* p_lx_elf.h --

   This file is part of the UPX executable compressor.

   Copyright (C) 1996-2006 Markus Franz Xaver Johannes Oberhumer
   Copyright (C) 1996-2006 Laszlo Molnar
   Copyright (C) 2000-2006 John F. Reiser
   All Rights Reserved.

   UPX and the UCL library are free software; you can redistribute them
   and/or modify them under the terms of the GNU General Public License as
   published by the Free Software Foundation; either version 2 of
   the License, or (at your option) any later version.

   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.

   You should have received a copy of the GNU General Public License
   along with this program; see the file COPYING.
   If not, write to the Free Software Foundation, Inc.,
   59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

   Markus F.X.J. Oberhumer              Laszlo Molnar
   <mfx@users.sourceforge.net>          <ml1050@users.sourceforge.net>

   John F. Reiser
   <jreiser@users.sourceforge.net>
 */


#ifndef __UPX_P_LX_ELF_H  //{
#define __UPX_P_LX_ELF_H


class PackLinuxElf : public PackUnix
{
    typedef PackUnix super;
public:
    PackLinuxElf(InputFile *f);
    virtual ~PackLinuxElf();
    /*virtual void buildLoader(const Filter *);*/
    virtual bool canUnpackVersion(int version) const { return (version >= 11); }

protected:
    virtual const int *getCompressionMethods(int method, int level) const;

    // All other virtual functions in this class must be pure virtual
    // because they depend on Elf32 or Elf64 data structures, which differ.

    virtual void pack1(OutputFile *, Filter &) = 0;  // generate executable header
    virtual void pack2(OutputFile *, Filter &) = 0;  // append compressed data
    virtual void pack3(OutputFile *, Filter &) = 0;  // append loader
    //virtual void pack4(OutputFile *, Filter &) = 0;  // append pack header

    virtual void generateElfHdr(
        OutputFile *,
        void const *proto,
        unsigned const brka
    ) = 0;
    virtual void defineSymbols(Filter const *);
    virtual void addStubEntrySections(Filter const *);
    virtual void unpack(OutputFile *fo) = 0;

protected:
    char       *file_image;       // if ET_DYN investigation
    char const *dynstr;   // from DT_STRTAB

    unsigned sz_phdrs;  // sizeof Phdr[]
    unsigned sz_elf_hdrs;  // all Elf headers
    unsigned sz_pack2;  // after pack2(), before loader

    unsigned short e_machine;
    unsigned char ei_class;
    unsigned char ei_data;
    unsigned char ei_osabi;
    char const *osabi_note;
};

class PackLinuxElf32 : public PackLinuxElf
{
    typedef PackLinuxElf super;
public:
    PackLinuxElf32(InputFile *f);
    virtual ~PackLinuxElf32();
protected:
    virtual int checkEhdr(Elf32_Ehdr const *ehdr) const;
    virtual bool canPack();

    // These ARM routines are essentially common to big/little endian,
    // but the class hierarchy splits after this class.
    virtual void ARM_defineSymbols(Filter const *ft);
    virtual void ARM_updateLoader(OutputFile *);

    virtual void pack1(OutputFile *, Filter &);  // generate executable header
    virtual void pack2(OutputFile *, Filter &);  // append compressed data
    virtual void pack3(OutputFile *, Filter &);  // append loader
    virtual void pack4(OutputFile *, Filter &);  // append pack header
    virtual void unpack(OutputFile *fo);

    virtual void generateElfHdr(
        OutputFile *,
        void const *proto,
        unsigned const brka
    );
    virtual void buildLinuxLoader(
        upx_byte const *const proto,  // assembly-only sections
        unsigned const szproto,
        upx_byte const *const fold,  // linked assembly + C section
        unsigned const szfold,
        Filter const *ft
    );
    virtual off_t getbrk(const Elf32_Phdr *phdr, int e_phnum) const;
    virtual void patchLoader();
    virtual void updateLoader(OutputFile *fo);
    virtual unsigned find_LOAD_gap(Elf32_Phdr const *const phdri, unsigned const k,
        unsigned const e_phnum);
    virtual off_t getbase(const Elf32_Phdr *phdr, int e_phnum) const;

    static unsigned elf_hash(char const *) /*const*/;
    virtual void const *elf_find_dynamic(unsigned) const;
    virtual Elf32_Sym const *elf_lookup(char const *) const;
    virtual unsigned elf_get_offset_from_address(unsigned) const;

protected:
    Elf32_Ehdr  ehdri; // from input file
    Elf32_Phdr *phdri; // for  input file

    Elf32_Dyn    const *dynseg;   // from PT_DYNAMIC
    unsigned int const *hashtab;  // from DT_HASH
    Elf32_Sym    const *dynsym;   // from DT_SYMTAB

    struct cprElfHdr1 {
        Elf32_Ehdr ehdr;
        Elf32_Phdr phdr[1];
        l_info linfo;
    }
    __attribute_packed;

    struct cprElfHdr2 {
        Elf32_Ehdr ehdr;
        Elf32_Phdr phdr[2];
        l_info linfo;
    }
    __attribute_packed;

    struct cprElfHdr3 {
        Elf32_Ehdr ehdr;
        Elf32_Phdr phdr[3];
        l_info linfo;
    }
    __attribute_packed;

    cprElfHdr3 elfout;

    struct Elf32_Note {
        unsigned namesz;  // 8
        unsigned descsz;  // 4
        unsigned type;    // 1
        char text[0x18 - 4*4];  // "OpenBSD"
        unsigned end;     // 0
    } elfnote;
};


class PackLinuxElf64 : public PackLinuxElf
{
    typedef PackLinuxElf super;
public:
    PackLinuxElf64(InputFile *f);
    virtual ~PackLinuxElf64();
    /*virtual void buildLoader(const Filter *);*/

protected:
    virtual int checkEhdr(Elf64_Ehdr const *ehdr) const;

    virtual void pack1(OutputFile *, Filter &);  // generate executable header
    virtual void pack2(OutputFile *, Filter &);  // append compressed data
    virtual void pack3(OutputFile *, Filter &);  // append loader
    virtual void pack4(OutputFile *, Filter &);  // append pack header
    virtual void unpack(OutputFile *fo);

    virtual void generateElfHdr(
        OutputFile *,
        void const *proto,
        unsigned const brka
    );
    virtual void buildLinuxLoader(
        upx_byte const *const proto,  // assembly-only sections
        unsigned const szproto,
        upx_byte const *const fold,  // linked assembly + C section
        unsigned const szfold,
        Filter const *ft
    );
    virtual off_t getbrk(const Elf64_Phdr *phdr, int e_phnum) const;
    virtual void patchLoader();
    virtual void updateLoader(OutputFile *fo);
    virtual unsigned find_LOAD_gap(Elf64_Phdr const *const phdri, unsigned const k,
        unsigned const e_phnum);

protected:
    Elf64_Ehdr  ehdri; // from input file
    Elf64_Phdr *phdri; // for  input file

    struct cprElfHdr1 {
        Elf64_Ehdr ehdr;
        Elf64_Phdr phdr[1];
        l_info linfo;
    }
    __attribute_packed;

    struct cprElfHdr2 {
        Elf64_Ehdr ehdr;
        Elf64_Phdr phdr[2];
        l_info linfo;
    }
    __attribute_packed;

    struct cprElfHdr3 {
        Elf64_Ehdr ehdr;
        Elf64_Phdr phdr[3];
        l_info linfo;
    }
    __attribute_packed;

    cprElfHdr3 elfout;
};

class PackLinuxElf32Be : public PackLinuxElf32
{
    typedef PackLinuxElf32 super;
protected:
    PackLinuxElf32Be(InputFile *f) : super(f) { bele = &N_BELE_RTP::be_policy; }

    virtual acc_uint64l_t get_native64(const void *b) const { return get_be64(b); }
    virtual unsigned get_native32(const void *b) const { return get_be32(b); }
    virtual unsigned get_native16(const void *b) const { return get_be16(b); }
    virtual void set_native64(void *b, acc_uint64l_t v) const { set_be64(b, v); }
    virtual void set_native32(void *b, unsigned v) const { set_be32(b, v); }
    virtual void set_native16(void *b, unsigned v) const { set_be16(b, v); }
};

class PackLinuxElf32Le : public PackLinuxElf32
{
    typedef PackLinuxElf32 super;
protected:
    PackLinuxElf32Le(InputFile *f) : super(f) { bele = &N_BELE_RTP::le_policy; }

    virtual acc_uint64l_t get_native64(const void *b) const { return get_le64(b); }
    virtual unsigned get_native32(const void *b) const { return get_le32(b); }
    virtual unsigned get_native16(const void *b) const { return get_le16(b); }
    virtual void set_native64(void *b, acc_uint64l_t v) const { set_le64(b, v); }
    virtual void set_native32(void *b, unsigned v) const { set_le32(b, v); }
    virtual void set_native16(void *b, unsigned v) const { set_le16(b, v); }
};

class PackLinuxElf64Le : public PackLinuxElf64
{
    typedef PackLinuxElf64 super;
protected:
    PackLinuxElf64Le(InputFile *f) : super(f) { bele = &N_BELE_RTP::le_policy; }

    virtual acc_uint64l_t get_native64(const void *b) const { return get_le64(b); }
    virtual unsigned get_native32(const void *b) const { return get_le32(b); }
    virtual unsigned get_native16(const void *b) const { return get_le16(b); }
    virtual void set_native64(void *b, acc_uint64l_t v) const { set_le64(b, v); }
    virtual void set_native32(void *b, unsigned v) const { set_le32(b, v); }
    virtual void set_native16(void *b, unsigned v) const { set_le16(b, v); }
};

/*************************************************************************
// linux/elf64amd
**************************************************************************/

class PackLinuxElf64amd : public PackLinuxElf64Le
{
    typedef PackLinuxElf64Le super;
public:
    PackLinuxElf64amd(InputFile *f);
    virtual ~PackLinuxElf64amd();
    virtual int getFormat() const { return UPX_F_LINUX_ELF64_AMD; }
    virtual const char *getName() const { return "linux/ElfAMD"; }
    virtual const char *getFullName(const options_t *) const { return "amd64-linux.elf"; }
    virtual const int *getFilters() const;
    virtual bool canPack();
protected:
    virtual void pack1(OutputFile *, Filter &);  // generate executable header
    //virtual void pack3(OutputFile *, Filter &);  // append loader
    virtual void buildLoader(const Filter *);
    virtual Linker* newLinker() const;
    virtual void defineSymbols(Filter const *);
};

/*************************************************************************
// linux/elf32ppc
**************************************************************************/

class PackLinuxElf32ppc : public PackLinuxElf32Be
{
    typedef PackLinuxElf32Be super;
public:
    PackLinuxElf32ppc(InputFile *f);
    virtual ~PackLinuxElf32ppc();
    virtual int getFormat() const { return UPX_F_LINUX_ELFPPC32; }
    virtual const char *getName() const { return "linux/ElfPPC"; }
    virtual const char *getFullName(const options_t *) const { return "powerpc-linux.elf"; }
    virtual const int *getFilters() const;
protected:
    virtual void pack1(OutputFile *, Filter &);  // generate executable header
    virtual void buildLoader(const Filter *);
    virtual Linker* newLinker() const;
};

/*************************************************************************
// linux/elf386
**************************************************************************/

class PackLinuxElf32x86 : public PackLinuxElf32Le
{
    typedef PackLinuxElf32Le super;
public:
    PackLinuxElf32x86(InputFile *f);
    virtual ~PackLinuxElf32x86();
    virtual int getFormat() const { return UPX_F_LINUX_ELF_i386; }
    virtual const char *getName() const { return "linux/elf386"; }
    virtual const char *getFullName(const options_t *) const { return "i386-linux.elf"; }
    virtual const int *getFilters() const;

    virtual void unpack(OutputFile *fo);

protected:
    virtual void pack1(OutputFile *, Filter &);  // generate executable header

    virtual void buildLoader(const Filter *);
    virtual void addStubEntrySections(Filter const *);
    virtual Linker* newLinker() const;
    virtual void defineSymbols(Filter const *);
};

class PackBSDElf32x86 : public PackLinuxElf32x86
{
    typedef PackLinuxElf32x86 super;
public:
    PackBSDElf32x86(InputFile *f);
    virtual ~PackBSDElf32x86();
    virtual int getFormat() const { return UPX_F_BSD_ELF_i386; }
    virtual const char *getName() const { return "BSD/elf386"; }

protected:
    virtual void pack1(OutputFile *, Filter &);  // generate executable header

    virtual void buildLoader(const Filter *);
};

class PackFreeBSDElf32x86 : public PackBSDElf32x86
{
    typedef PackBSDElf32x86 super;
public:
    PackFreeBSDElf32x86(InputFile *f);
    virtual ~PackFreeBSDElf32x86();
    virtual const char *getFullName(const options_t *) const { return "i386-freebsd.elf"; }
};

class PackNetBSDElf32x86 : public PackBSDElf32x86
{
    typedef PackBSDElf32x86 super;
public:
    PackNetBSDElf32x86(InputFile *f);
    virtual ~PackNetBSDElf32x86();
    virtual const char *getFullName(const options_t *) const { return "i386-netbsd.elf"; }
};

class PackOpenBSDElf32x86 : public PackBSDElf32x86
{
    typedef PackBSDElf32x86 super;
public:
    PackOpenBSDElf32x86(InputFile *f);
    virtual ~PackOpenBSDElf32x86();
    virtual const char *getFullName(const options_t *) const { return "i386-openbsd.elf"; }

protected:
    virtual void buildLoader(const Filter *ft);
    virtual void generateElfHdr(
        OutputFile *,
        void const *proto,
        unsigned const brka
    );
};

/*************************************************************************
// linux/elfarm
**************************************************************************/

class PackLinuxElf32armLe : public PackLinuxElf32Le
{
    typedef PackLinuxElf32Le super;
public:
    PackLinuxElf32armLe(InputFile *f);
    virtual ~PackLinuxElf32armLe();
    virtual int getFormat() const { return UPX_F_LINUX_ELF32_ARMLE; }
    virtual const char *getName() const { return "linux/armLE"; }
    virtual const char *getFullName(const options_t *) const { return "arm-linux.elf"; }
    virtual const int *getFilters() const;

protected:
    virtual const int *getCompressionMethods(int method, int level) const;
    virtual Linker* newLinker() const;
    virtual void pack1(OutputFile *, Filter &);  // generate executable header
    virtual void buildLoader(const Filter *);
    virtual void updateLoader(OutputFile *);
    virtual void defineSymbols(Filter const *);
};

class PackLinuxElf32armBe : public PackLinuxElf32Be
{
    typedef PackLinuxElf32Be super;
public:
    PackLinuxElf32armBe(InputFile *f);
    virtual ~PackLinuxElf32armBe();
    virtual int getFormat() const { return UPX_F_LINUX_ELF32_ARMBE; }
    virtual const char *getName() const { return "linux/armBE"; }
    virtual const char *getFullName(const options_t *) const { return "armeb-linux.elf"; }
    virtual const int *getFilters() const;

protected:
    virtual const int *getCompressionMethods(int method, int level) const;
    virtual Linker* newLinker() const;
    virtual void pack1(OutputFile *, Filter &);  // generate executable header
    virtual void buildLoader(const Filter *);
    virtual void updateLoader(OutputFile *);
    virtual void defineSymbols(Filter const *);
};

#endif /*} already included */


/*
vi:ts=4:et
*/

