/* p_mach.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
   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
   markus@oberhumer.com      ml1050@users.sourceforge.net
 */


#ifndef __UPX_P_MACHO_H
#define __UPX_P_MACHO_H

/*************************************************************************
// Mach  Mach Object executable
**************************************************************************/

struct Mach_header {
    BE32 magic;
        enum {
            MH_MAGIC = 0xfeedface
        };
    BE32 cputype;
        enum {
            CPU_TYPE_POWERPC = 18
        };
    BE32 cpysubtype;
    BE32 filetype;
        enum {
            MH_EXECUTE = 2
        };
    BE32 ncmds;
    BE32 sizeofcmds;
    BE32 flags;
        enum {
            MH_NOUNDEFS = 1
        };
}
__attribute_packed;

struct Mach_segment_command {
    BE32 cmd;
        enum {
            LC_SEGMENT       = 0x1,
            LC_THREAD        = 0x4,
            LC_UNIXTHREAD    = 0x5,
            LC_LOAD_DYLINKER = 0xe
        };
    BE32 cmdsize;
    char segname[16];
    BE32 vmaddr;
    BE32 vmsize;
    BE32 fileoff;
    BE32 filesize;
    BE32 maxprot;
        enum {
            VM_PROT_READ = 1,
            VM_PROT_WRITE = 2,
            VM_PROT_EXECUTE = 4
        };
    BE32 initprot;
    BE32 nsects;
    BE32 flags;
}
__attribute_packed;

struct Mach_section {
    char sectname[16];
    char segname[16];
    BE32 addr;   /* memory address */
    BE32 size;   /* size in bytes */
    BE32 offset; /* file offset */
    BE32 align;  /* power of 2 */
    BE32 reloff; /* file offset of relocation entries */
    BE32 nreloc; /* number of relocation entries */
    BE32 flags;  /* section type and attributes */
        enum {
            S_REGULAR = 0,
            S_ZEROFILL,
            S_CSTRING_LITERALS,
            S_4BYTE_LITERALS,
            S_8BYTE_LITERALS,
            S_LITERAL_POINTERS,
            S_NON_LAZY_SYMBOL_POINTERS,
            S_LAZY_SYMBOL_POINTERS,
            S_SYMBOL_STUBS,
            S_MOD_INIT_FUNC_POINTERS,
            S_MOD_TERM_FNC_POINTERS,
            S_COALESCED
        };
        enum {
            S_ATTR_PURE_INSTRUCTIONS = 0x80000000,
            S_ATTR_NO_TOC            = 0x40000000,
            S_ATTR_STRIP_STATIC_SYMS = 0x20000000,
            S_ATTR_SOME_INSTRUCTIONS = 0x00000400,
            S_ATTR_EXT_RELOC         = 0x00000200,
            S_ATTR_LOC_RELOC         = 0x00000100
        };
    BE32 reserved1;
    BE32 reserved2;

}
__attribute_packed;

struct Mach_ppc_thread_state {
    BE32 srr0;      /* Instruction address register (PC; entry addr) */
    BE32 srr1;      /* Machine state register (supervisor) */
    BE32  r0, r1, r2, r3, r4, r5, r6, r7;
    BE32  r8, r9,r10,r11,r12,r13,r14,r15;
    BE32 r16,r17,r18,r19,r20,r21,r22,r23;
    BE32 r24,r25,r26,r27,r28,r29,r30,r31;

    BE32 cr;        /* Condition register */
    BE32 xer;       /* User's integer exception register */
    BE32 lr;        /* Link register */
    BE32 ctr;       /* Count register */
    BE32 mq;        /* MQ register (601 only) */

    BE32 vrsave;    /* Vector Save Register */
};

struct Mach_thread_command {
    BE32 cmd;            /* LC_THREAD or  LC_UNIXTHREAD */
    BE32 cmdsize;        /* total size of this command */
    BE32 flavor;
        enum {
            PPC_THREAD_STATE = 1
        };
    BE32 count;          /* sizeof(following_thread_state)/4 */
        enum {
            PPC_THREAD_STATE_COUNT = sizeof(struct Mach_ppc_thread_state)/4
        };
    struct Mach_ppc_thread_state state;
}
__attribute_packed;


#include "p_unix.h"


class PackMachPPC32 : public PackUnixBe32
{
    typedef PackUnixBe32 super;
public:
    PackMachPPC32(InputFile *f);
    virtual ~PackMachPPC32();
    virtual int getVersion() const { return 13; }
    virtual int getFormat() const { return UPX_F_MACH_PPC32; }
    virtual const char *getName() const { return "Mach/ppc32"; }
    virtual const char *getFullName(const options_t *) const { return "powerpc-darwin.macho"; }
    virtual const int *getCompressionMethods(int method, int level) const;
    virtual const int *getFilters() const;

    // called by the generic pack()
    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 PackHeader

    virtual void unpack(OutputFile *fo);

    virtual bool canPack();
    virtual unsigned find_SEGMENT_gap(unsigned const k);

protected:
    virtual void buildLoader(const Filter *ft);
    virtual Linker* newLinker() const;
    virtual void patchLoader();
    virtual void patchLoaderChecksum();
    virtual void updateLoader(OutputFile *);
    virtual void buildMachLoader(
        upx_byte const *const proto,
        unsigned        const szproto,
        upx_byte const *const fold,
        unsigned        const szfold,
        Filter const *ft );
    virtual void defineSymbols(Filter const *);
    virtual void addStubEntrySections(Filter const *);

    unsigned  n_segment;
    unsigned sz_segment;
    unsigned sz_mach_headers;
    Mach_segment_command *rawmseg;  // as input, with sections
    Mach_segment_command *msegcmd;  // LC_SEGMENT first, without sections
    Mach_header mhdri;

    Mach_header mhdro;
    Mach_segment_command segcmdo;
    Mach_thread_command threado;
    struct l_info linfo;
};


#endif /* already included */


/*
vi:ts=4:et
*/

