Minimalist Mach-O binary format support

This code is sucessfully able to load and recognize Mach-O binary files.
It is able to sort through the FAT file headers and identify compatible
files, although it currently is hardcoded for PowerPC64 architecture.

Does not yet support load_commands or actually mapping the Mach-O files
into memory.

Signed-off-by: Kyle Moffett <[EMAIL PROTECTED]>
---
fs/Kconfig.binfmt   |   14 ++
fs/Makefile         |    1 +
fs/mach-o/Makefile  |    8 ++
fs/mach-o/binfmt.c | 321 +++++++++++++++++++++++++++++++++++++++++++ ++++++ fs/mach-o/cpus.h | 329 +++++++++++++++++++++++++++++++++++++++++++ ++++++++
fs/mach-o/debug.h   |    9 ++
fs/mach-o/files.h   |  139 ++++++++++++++++++++++
fs/mach-o/headers.h |   49 ++++++++
8 files changed, 870 insertions(+), 0 deletions(-)

diff --git a/fs/Kconfig.binfmt b/fs/Kconfig.binfmt
index f3d3d81..c29b544 100644
--- a/fs/Kconfig.binfmt
+++ b/fs/Kconfig.binfmt
@@ -55,6 +55,20 @@ config BINFMT_SHARED_FLAT
        help
          Support FLAT shared libraries
 
+config BINFMT_MACHO
+       tristate "Kernel support for Mach-O and FAT Mach-O binaries"
+       ---help---
+         Mach-O (Mach Object) is a format for libraries and executables used
+         by the Mach and Darwin operating systems on multiple architectures.
+         Saying Y here will enable your kernel to run Mach-O binaries built
+         for your platform.  If the program or library is a FAT Mach-O
+         binary then it may be run on any platform where an appropriate
+         binary exists.
+
+         If you wish to actually run programs compiled for either Darwin or
+         Mac OS X, you probably also want to enable
+         "Darwin syscall personality support" for your architecture.
+
 config BINFMT_AOUT
        tristate "Kernel support for a.out and ECOFF binaries"
        depends on X86_32 || ALPHA || ARM || M68K || SPARC32
diff --git a/fs/Makefile b/fs/Makefile
index 9edf411..bd70dd3 100644
--- a/fs/Makefile
+++ b/fs/Makefile
@@ -38,6 +38,7 @@ obj-$(CONFIG_BINFMT_ELF)      += binfmt_elf.o
 obj-$(CONFIG_BINFMT_ELF_FDPIC) += binfmt_elf_fdpic.o
 obj-$(CONFIG_BINFMT_SOM)       += binfmt_som.o
 obj-$(CONFIG_BINFMT_FLAT)      += binfmt_flat.o
+obj-$(CONFIG_BINFMT_MACHO)     += mach-o/
 
 obj-$(CONFIG_FS_MBCACHE)       += mbcache.o
 obj-$(CONFIG_FS_POSIX_ACL)     += posix_acl.o xattr_acl.o
diff --git a/fs/mach-o/Makefile b/fs/mach-o/Makefile
new file mode 100644
index 0000000..9d1d374
--- /dev/null
+++ b/fs/mach-o/Makefile
@@ -0,0 +1,8 @@
+#
+# Makefile for Mach-O binary format support
+#
+
+obj-$(CONFIG_BINFMT_MACHO) += binfmt_mach-o.o
+
+binfmt_mach-o-objs := binfmt.o
+
diff --git a/fs/mach-o/binfmt.c b/fs/mach-o/binfmt.c
new file mode 100644
index 0000000..b5ea936
--- /dev/null
+++ b/fs/mach-o/binfmt.c
@@ -0,0 +1,321 @@
+/*
+ * linux/fs/mach-o/binfmt.c
+ *
+ * These are the functions used to load Mach-O format executables as used
+ * on Mac OS X and Darwin machines.
+ *
+ * Copyright (C) 2006, Kyle Moffett <[EMAIL PROTECTED]>
+ *
+ * Designed from public documentation and Darwin sources as well as the Linux
+ * ELF loader by Eric Youngdale ([EMAIL PROTECTED]).
+ */
+
+#include <linux/module.h>
+#include <linux/binfmts.h>
+#include <linux/fs.h>
+#include <linux/err.h>
+
+#include "debug.h"
+#include "cpus.h"
+#include "headers.h"
+#include "files.h"
+
+#if 0
+#include <linux/kernel.h>
+#include <linux/stat.h>
+#include <linux/time.h>
+#include <linux/mm.h>
+#include <linux/mman.h>
+#include <linux/a.out.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/string.h>
+#include <linux/file.h>
+#include <linux/fcntl.h>
+#include <linux/ptrace.h>
+#include <linux/slab.h>
+#include <linux/shm.h>
+#include <linux/personality.h>
+#include <linux/elfcore.h>
+#include <linux/init.h>
+#include <linux/highuid.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/compiler.h>
+#include <linux/highmem.h>
+#include <linux/pagemap.h>
+#include <linux/security.h>
+#include <linux/syscalls.h>
+#include <linux/random.h>
+
+#include <asm/uaccess.h>
+#include <asm/param.h>
+#include <asm/page.h>
+#endif
+
+MODULE_LICENSE("GPL");
+
+/* Function prototypes */
+static unsigned long get_arch_offset(struct linux_binprm *bprm);
+static int load_macho_binary(struct linux_binprm *bprm, struct pt_regs *regs);
+
+/* Mach-O binary format */
+static struct linux_binfmt binfmt_macho = {
+       .module         = THIS_MODULE,
+       .load_binary    = load_macho_binary,
+       .load_shlib     = NULL,
+       .core_dump      = NULL,
+       .min_coredump   = PAGE_SIZE,
+};
+
+/* Module init and exit */
+static int __init init_binfmt_macho(void)
+{
+       return register_binfmt(&binfmt_macho);
+}
+core_initcall(init_binfmt_macho);
+
+static void __exit exit_binfmt_macho(void)
+{
+       unregister_binfmt(&binfmt_macho);
+}
+module_exit(exit_binfmt_macho);
+
+
+/*
+ * Read Mach-O file headers to find out where our architecture-specific
+ * portion is.
+ */
+#define MAX_ARCH_COUNT (PAGE_SIZE/sizeof(struct macho_fat_arch))
+static unsigned long get_arch_offset(struct linux_binprm *bprm)
+{
+       struct macho_fat_header *header;
+       struct macho_fat_arch *archs;
+       unsigned long arch_count, arch_data, i, offset = 0;
+       long retval;
+       unsigned int best_pref, best_arch;
+
+       /* Without a FAT (multi-arch binary) header just assume no offset */
+       header = (struct macho_fat_header *)bprm->buf;
+       if (header->magic != MACHO_FAT_MAGIC)
+               goto out;
+
+       macho_dbg("Found a Mach-O FAT header!\n");
+
+       /* Figure out how many archs to read (no more than a page worth) */
+       arch_count = __be32_to_cpu(header->arch_count);
+       if (arch_count > MAX_ARCH_COUNT) {
+               macho_dbg("Too many archs (%lu) in Mach-O binary.  Only using"
+                               " %lu!\n", arch_count, MAX_ARCH_COUNT);
+               arch_count = MAX_ARCH_COUNT;
+       }
+
+       /* Size of the architecture data (for kmalloc and read) */
+       arch_data = arch_count * sizeof(struct macho_fat_arch);
+
+       /* Allocate memory for the architecture list */
+       archs = kmalloc(arch_data, GFP_KERNEL);
+       if (!archs) {
+               offset = (unsigned long)(-ENOMEM);
+               goto out;
+       }
+
+       /* Read in the architecture list */
+       retval = kernel_read(bprm->file, sizeof(struct macho_fat_header),
+                       (void *)archs, arch_data);
+       if (retval != arch_data) {
+               if (retval < 0) {
+                       macho_dbg("Error while reading Mach-O architecture"
+                                       " list: %li\n", retval);
+                       offset = (unsigned long)retval;
+               } else {
+                       macho_dbg("Truncated arch list (got %lub, wanted"
+                                       " %lub)\n", retval, arch_data);
+                       offset = (unsigned long)(-ENOEXEC);
+               }
+               goto out;
+       }
+
+       /*
+        * Iterate over the architecture list looking for the most-preferred
+        * arch.  NOTE:  An architecture with a preference of 0 is not
+        * compatible with the current CPU.
+        */
+       best_pref = 0;
+       best_arch = 0;
+       for (i = 0; i < arch_count; i++) {
+               unsigned int pref = macho_check_cpu(
+                               __be32_to_cpu(archs[i].cpu_type),
+                               __be32_to_cpu(archs[i].cpu_subtype));
+               if (best_pref < pref) {
+                       best_pref = pref;
+                       best_arch = i;
+               }
+       }
+
+       /* If we didn't find any useable architectures then give up */
+       if (best_pref == 0) {
+               macho_dbg("No compatible binaries in Mach-O FAT binary\n");
+               offset = (unsigned long)(-ENOEXEC);
+               goto out;
+       }
+
+       /* Pick up the offset of the best available architecture */
+       offset = __be32_to_cpu(archs[best_arch].offset);
+
+       /*
+        * If the offset would be confused with an error value then
+        * it's too big (4GB program binary?!?!?) and we should just
+        * return ENOEXEC instead
+        */
+       if (IS_ERR_VALUE(offset))
+               offset = (unsigned long)(-ENOEXEC);
+
+out:
+       return offset;
+}
+
+/*
+ * Load a Mach-O binary
+ */
+static int load_macho_binary(struct linux_binprm *bprm, struct pt_regs *regs)
+{
+       struct {
+               union {
+                       /* The first 4 bytes of either header are the magic */
+                       __u32 magic;
+                       struct macho_mach32_header mach32;
+                       struct macho_mach64_header mach64;
+               } header;
+#if 0
+               struct macho_loadcmd loadcmd;
+#endif
+       } *data = NULL;
+       unsigned long offset;
+       long retval;
+       int err;
+
+       /*
+        * Read the Mach-O file headers to find the offset of our
+        * architecture-specific portion
+        */
+       offset = get_arch_offset(bprm);
+       if (IS_ERR_VALUE(offset)) {
+               err = (long)offset;
+               goto out;
+       }
+
+       /* Allocate space for the file headers and a load command */
+       data = kmalloc(sizeof(*data), GFP_KERNEL);
+       if (!data) {
+               err = -ENOMEM;
+               goto out;
+       }
+
+       /* Read the header data and check the magic */
+       retval = kernel_read(bprm->file, offset,
+                       (void *)&data->header, sizeof(data->header));
+       if (retval != sizeof(data->header)) {
+               /*
+                * If we didn't see an arch table then it must not really be
+                * a Mach-O file so just return as not executable.
+                */
+               if (!offset)
+                       err = -ENOEXEC;
+
+               /* If kernel_read() returned an error, handle it */
+               else if (retval < 0) {
+                       macho_dbg("Error while reading Mach-O object"
+                                       " header: %li\n", retval);
+                       err = retval;
+               } else {
+                       macho_dbg("Truncated Mach-O object header: "
+                                       "(got %lub, wanted %lub)\n", retval,
+                                       sizeof(data->header));
+                       err = -ENOEXEC;
+               }
+               goto out;
+       }
+
+       /* Check for backwards-endian files */
+       if (data->header.magic == MACHO_MACH32_CIGAM ||
+                       data->header.magic == MACHO_MACH64_CIGAM) {
+               macho_dbg("Wrong endianness in Mach-O file\n");
+               err = -ENOEXEC;
+               goto out;
+       }
+
+       /*
+        * It's not a valid Mach-O file then return, but print an error
+        * message first if it was embedded in a Mach-O FAT wrapper.
+        */
+       if (data->header.magic != MACHO_MACH32_MAGIC &&
+                       data->header.magic != MACHO_MACH64_MAGIC) {
+               if (offset)
+                       macho_dbg("Corrupt embedded Mach-O object!\n");
+               err = -ENOEXEC;
+               goto out;
+       }
+
+       /* CPU type (lines up between 32-bit and 64-bit Mach-O files) */
+       if (!macho_check_cpu(data->header.mach32.cpu_type,
+                       data->header.mach32.cpu_subtype)) {
+
+               /*
+                * The CPU didn't match, so either this is Mach-O file is for
+                * a different platform (offset == 0) or the FAT Mach-O has
+                * been corrupted.
+                */
+               if (offset)
+                       macho_dbg("FAT Mach-O wrapper has mismatched CPU"
+                                       " types:  Mach-O file corrupt?\n");
+               else
+                       macho_dbg("Wrong architecture in Mach-O file\n");
+               err = -ENOEXEC;
+               goto out;
+       }
+
+       /* File type (also lines up between 32-bit and 64-bit) */
+       if (!macho_check_file(data->header.mach32.filetype,
+                       data->header.mach32.flags)) {
+               macho_dbg("Attempted to execute nonexecutable Mach-O file\n");
+               err = -ENOEXEC;
+               goto out;
+       }
+
+       /* Move past the Mach-O header to find the first load_command */
+       if (data->header.magic == MACHO_MACH32_MAGIC)
+               offset += sizeof(struct macho_mach32_header);
+       else
+               offset += sizeof(struct macho_mach64_header);
+
+       err = -EINVAL;
+       goto out;
+
+out:
+       kfree(data);
+       return err;
+}
+
+
+
+#if 0
+       char buf[BINPRM_BUF_SIZE];
+       struct page *page[MAX_ARG_PAGES];
+       struct mm_struct *mm;
+       unsigned long p; /* current top of mem */
+       int sh_bang;
+       struct file * file;
+       int e_uid, e_gid;
+       kernel_cap_t cap_inheritable, cap_permitted, cap_effective;
+       void *security;
+       int argc, envc;
+       char * filename;        /* Name of binary as seen by procps */
+       char * interp;          /* Name of the binary really executed. Most
+                                  of the time same as filename, but could be
+                                  different for binfmt_{misc,script} */
+       unsigned interp_flags;
+       unsigned interp_data;
+       unsigned long loader, exec;
+#endif
+
diff --git a/fs/mach-o/cpus.h b/fs/mach-o/cpus.h
new file mode 100644
index 0000000..a1f2276
--- /dev/null
+++ b/fs/mach-o/cpus.h
@@ -0,0 +1,329 @@
+#ifndef  _MACHO_CPUS_H
+# define _MACHO_CPUS_H 1
+
+# include <linux/compiler.h>
+# include <linux/types.h>
+# include <linux/err.h>
+
+/*
+ * Mach-O CPU types, borrowed from Darwin
+ */
+typedef __u32 __bitwise macho_cpu_type_t;
+#define _ENTRY(type, num) \
+       MACHO_CPU_TYPE_##type = ((__force macho_cpu_type_t)num)
+enum {
+       _ENTRY(VAX,     0x00000001),
+       _ENTRY(M68K,    0x00000006),
+       _ENTRY(I386,    0x00000007),
+       _ENTRY(MIPS,    0x00000008),
+       _ENTRY(M98K,    0x0000000a),
+       _ENTRY(PARISC,  0x0000000b),
+       _ENTRY(ARM,     0x0000000c),
+       _ENTRY(M88K,    0x0000000d),
+       _ENTRY(SPARC,   0x0000000e),
+       _ENTRY(I860,    0x0000000f),
+       _ENTRY(ALPHA,   0x00000010),
+       _ENTRY(PPC32,   0x00000012),
+       _ENTRY(PPC64,   0x01000012),
+       _ENTRY(ANY,     0xffffffff),
+};
+#undef _ENTRY
+
+/*
+ * Mach-O CPU subtypes, borrowed from Darwin
+ */
+typedef __u32 __bitwise macho_cpu_subtype_t;
+#define _ENTRY(subtype, num) \
+       MACHO_CPU_SUBTYPE_##subtype = ((__force macho_cpu_subtype_t)num)
+enum {
+       /* Generic CPU subtypes (unused?) */
+       _ENTRY(MULTIPLE,                0xffffffff),
+       _ENTRY(LITTLE_ENDIAN,           0x00000000),
+       _ENTRY(BIG_ENDIAN,              0x00000001),
+
+       /* VAX subtypes */
+       _ENTRY(VAX_ALL,                 0x00000000),
+       _ENTRY(VAX_VAX780,              0x00000001),
+       _ENTRY(VAX_VAX785,              0x00000002),
+       _ENTRY(VAX_VAX750,              0x00000003),
+       _ENTRY(VAX_VAX730,              0x00000004),
+       _ENTRY(VAX_UVAXI,               0x00000005),
+       _ENTRY(VAX_UVAXII,              0x00000006),
+       _ENTRY(VAX_VAX8200,             0x00000007),
+       _ENTRY(VAX_VAX8500,             0x00000008),
+       _ENTRY(VAX_VAX8600,             0x00000009),
+       _ENTRY(VAX_VAX8650,             0x0000000a),
+       _ENTRY(VAX_VAX8800,             0x0000000b),
+       _ENTRY(VAX_UVAXIII,             0x0000000c),
+
+       /* Motorola 680x0 subtypes */
+       _ENTRY(M68K_MC680X0,            0x00000001),
+       _ENTRY(M68K_MC68040,            0x00000002),
+       _ENTRY(M68K_MC68030,            0x00000003),
+
+       /* Intel/AMD x86 subtypes */
+       _ENTRY(I386_ALL,                0x00000003),
+       _ENTRY(I386_386,                0x00000003),
+       _ENTRY(I386_486,                0x00000004),
+       _ENTRY(I386_486SX,              0x00000084),
+       _ENTRY(I386_586,                0x00000005),
+       _ENTRY(I386_PENTIUM,            0x00000005),
+       _ENTRY(I386_PPRO,               0x00000016),
+       _ENTRY(I386_PENTIUM2_M3,        0x00000036),
+       _ENTRY(I386_PENTIUM2_M5,        0x00000056),
+       _ENTRY(I386_CELERON,            0x00000067),
+       _ENTRY(I386_CELERON_M,          0x00000077),
+       _ENTRY(I386_PENTIUM3,           0x00000008),
+       _ENTRY(I386_PENTIUM3_M,         0x00000018),
+       _ENTRY(I386_PENTIUM3_XEON,      0x00000028),
+       _ENTRY(I386_PENTIUM_M,          0x00000009),
+       _ENTRY(I386_PENTIUM4,           0x0000000a),
+       _ENTRY(I386_PENTIUM4_M,         0x0000001a),
+       _ENTRY(I386_ITANIUM,            0x0000000b),
+       _ENTRY(I386_ITANIUM2,           0x0000001b),
+       _ENTRY(I386_XEON,               0x0000000c),
+       _ENTRY(I386_XEON_MP,            0x0000001c),
+
+       /* MIPS subtypes */
+       _ENTRY(MIPS_ALL,                0x00000000),
+       _ENTRY(MIPS_R2300,              0x00000001),
+       _ENTRY(MIPS_R2600,              0x00000002),
+       _ENTRY(MIPS_R2800,              0x00000003),
+       _ENTRY(MIPS_R2000A,             0x00000004),
+       _ENTRY(MIPS_R2000,              0x00000005),
+       _ENTRY(MIPS_R3000A,             0x00000006),
+       _ENTRY(MIPS_R3000,              0x00000007),
+
+       /* Motorola 98xxx subtypes */
+       _ENTRY(M98K_ALL,                0x00000000),
+       _ENTRY(M98K_MC98601,            0x00000001),
+
+       /* HPPA subtypes */
+       _ENTRY(PARISC_ALL,              0x00000000),
+       _ENTRY(PARISC_7100LC,           0x00000001),
+
+       /* Motorola 88xxx subtypes */
+       _ENTRY(M88K_ALL,                0x00000000),
+       _ENTRY(M88K_MC88100,            0x00000001),
+       _ENTRY(M88K_MC88110,            0x00000002),
+
+       /* Sparc subtypes */
+       _ENTRY(SPARC_ALL,               0x00000000),
+
+       /* I860?? subtypes */
+       _ENTRY(I860_ALL,                0x00000000),
+       _ENTRY(I860_860,                0x00000001),
+
+       /* Motorola/Freescale/IBM PowerPC subtypes */
+       _ENTRY(PPC32_ALL,               0x00000000),
+       _ENTRY(PPC32_601,               0x00000001),
+       _ENTRY(PPC32_602,               0x00000002),
+       _ENTRY(PPC32_603,               0x00000003),
+       _ENTRY(PPC32_603E,              0x00000004),
+       _ENTRY(PPC32_603EV,             0x00000005),
+       _ENTRY(PPC32_604,               0x00000006),
+       _ENTRY(PPC32_604E,              0x00000007),
+       _ENTRY(PPC32_620,               0x00000008),
+       _ENTRY(PPC32_750,               0x00000009),
+       _ENTRY(PPC32_7400,              0x0000000a),
+       _ENTRY(PPC32_7450,              0x0000000b),
+       _ENTRY(PPC32_970,               0x00000064),
+
+       /* Motorola/Freescale/IBM PowerPC64 subtypes */
+       _ENTRY(PPC64_ALL,               0x00000000),
+       /*_ENTRY(PPC64_970,             0x00000001),*/
+};
+#undef _ENTRY
+
+/*
+ * A CPU subtype mapping table with human-readable strings
+ */
+struct macho_cpu_subentry {
+       const char *            name;
+       macho_cpu_type_t        type;
+       macho_cpu_subtype_t     subtype;
+       unsigned int            preference;
+};
+
+#define _ENTRY(TYPE, SUBTYPE, NAME, PREFERENCE) {                      \
+               .name = NAME,                                           \
+               .type = MACHO_CPU_TYPE_ ## TYPE,                        \
+               .subtype = MACHO_CPU_SUBTYPE_ ## TYPE ## _ ## SUBTYPE,  \
+               .preference = (PREFERENCE)                              \
+       }
+
+static const struct macho_cpu_subentry macho_cpu_vax_subtypes[] = {
+       _ENTRY(VAX,     ALL,            "all VAX",                       0),
+       _ENTRY(VAX,     VAX780,         "VAX-780",                       0),
+       _ENTRY(VAX,     VAX785,         "VAX-785",                       0),
+       _ENTRY(VAX,     VAX750,         "VAX-750",                       0),
+       _ENTRY(VAX,     VAX730,         "VAX-730",                       0),
+       _ENTRY(VAX,     UVAXI,          "UVAX-I",                        0),
+       _ENTRY(VAX,     UVAXII,         "UVAX-II",                       0),
+       _ENTRY(VAX,     VAX8200,        "VAX-8200",                      0),
+       _ENTRY(VAX,     VAX8500,        "VAX-8500",                      0),
+       _ENTRY(VAX,     VAX8600,        "VAX-8600",                      0),
+       _ENTRY(VAX,     VAX8650,        "VAX-8650",                      0),
+       _ENTRY(VAX,     VAX8800,        "VAX-8800",                      0),
+       _ENTRY(VAX,     UVAXIII,        "UVAX-III",                      0),
+       { .name = NULL },
+};
+static const struct macho_cpu_subentry macho_cpu_m68k_subtypes[] = {
+       _ENTRY(M68K,    MC680X0,        "all Motorola 68xxx",            0),
+       _ENTRY(M68K,    MC68040,        "Motorola 68040",                0),
+       _ENTRY(M68K,    MC68030,        "Motorola 68030",                0),
+       { .name = NULL },
+};
+static const struct macho_cpu_subentry macho_cpu_i386_subtypes[] = {
+       _ENTRY(I386,    ALL,            "all Intel/AMD",                 0),
+       _ENTRY(I386,    386,            "Intel 386",                     0),
+       _ENTRY(I386,    486,            "Intel 486",                     0),
+       _ENTRY(I386,    486SX,          "Intel 486SX",                   0),
+       _ENTRY(I386,    586,            "Intel 586",                     0),
+       _ENTRY(I386,    PENTIUM,        "Intel Pentium",                 0),
+       _ENTRY(I386,    PPRO,           "Intel Pentium Pro",             0),
+       _ENTRY(I386,    PENTIUM2_M3,    "Intel Pentium II M3",           0),
+       _ENTRY(I386,    PENTIUM2_M5,    "Intel Pentium II M5",           0),
+       _ENTRY(I386,    CELERON,        "Intel Celeron",                 0),
+       _ENTRY(I386,    CELERON_M,      "Intel Celeron/M",               0),
+       _ENTRY(I386,    PENTIUM3,       "Intel Pentium III",             0),
+       _ENTRY(I386,    PENTIUM3_M,     "Intel Pentium III M",           0),
+       _ENTRY(I386,    PENTIUM3_XEON,  "Intel Pentium III Xeon",        0),
+       _ENTRY(I386,    PENTIUM_M,      "Intel Pentium/M",               0),
+       _ENTRY(I386,    PENTIUM4,       "Intel Pentium IV",              0),
+       _ENTRY(I386,    PENTIUM4_M,     "Intel Pentium IV/M",            0),
+       _ENTRY(I386,    ITANIUM,        "Intel Itanium",                 0),
+       _ENTRY(I386,    ITANIUM2,       "Intel Itanium 2",               0),
+       _ENTRY(I386,    XEON,           "Intel Xeon",                    0),
+       _ENTRY(I386,    XEON_MP,        "Intel Xeon SMP",                0),
+       { .name = NULL },
+};
+static const struct macho_cpu_subentry macho_cpu_mips_subtypes[] = {
+       _ENTRY(MIPS,    ALL,            "all MIPS",                      0),
+       _ENTRY(MIPS,    R2300,          "MIPS r2300",                    0),
+       _ENTRY(MIPS,    R2600,          "MIPS r2600",                    0),
+       _ENTRY(MIPS,    R2800,          "MIPS r2800",                    0),
+       _ENTRY(MIPS,    R2000A,         "MIPS r2000a",                   0),
+       _ENTRY(MIPS,    R2000,          "MIPS r2000",                    0),
+       _ENTRY(MIPS,    R3000A,         "MIPS r3000a",                   0),
+       _ENTRY(MIPS,    R3000,          "MIPS r3000",                    0),
+       { .name = NULL },
+};
+static const struct macho_cpu_subentry macho_cpu_m98k_subtypes[] = {
+       _ENTRY(M98K,    ALL,            "all Motorola 98xxx",            0),
+       _ENTRY(M98K,    MC98601,        "Motorola 98601",                0),
+       { .name = NULL },
+};
+static const struct macho_cpu_subentry macho_cpu_parisc_subtypes[] = {
+       _ENTRY(PARISC,  ALL,            "all HPPA/PaRISC",               0),
+       _ENTRY(PARISC,  7100LC,         "HPPA 7100LC",                   0),
+       { .name = NULL },
+};
+static const struct macho_cpu_subentry macho_cpu_m88k_subtypes[] = {
+       _ENTRY(M88K,    ALL,            "All Motorola 88xxx",            0),
+       _ENTRY(M88K,    MC88100,        "Motorola 88100",                0),
+       _ENTRY(M88K,    MC88110,        "Motorola 88110",                0),
+       { .name = NULL },
+};
+static const struct macho_cpu_subentry macho_cpu_sparc_subtypes[] = {
+       _ENTRY(SPARC,   ALL,            "all Sparc",                     0),
+       { .name = NULL },
+};
+static const struct macho_cpu_subentry macho_cpu_i860_subtypes[] = {
+       _ENTRY(I860,    ALL,            "all i860",                      0),
+       _ENTRY(I860,    860,            "i860",                          0),
+       { .name = NULL },
+};
+static const struct macho_cpu_subentry macho_cpu_ppc32_subtypes[] = {
+       _ENTRY(PPC32,   ALL,            "all PowerPC",                   1),
+       _ENTRY(PPC32,   601,            "PowerPC 601",                   2),
+       _ENTRY(PPC32,   602,            "PowerPC 602",                   3),
+       _ENTRY(PPC32,   603,            "PowerPC 603",                   4),
+       _ENTRY(PPC32,   603E,           "PowerPC 603e",                  5),
+       _ENTRY(PPC32,   603EV,          "PowerPC 603ev",                 6),
+       _ENTRY(PPC32,   604,            "PowerPC 604",                   7),
+       _ENTRY(PPC32,   604E,           "PowerPC 604e",                  8),
+       _ENTRY(PPC32,   620,            "PowerPC 620",                   9),
+       _ENTRY(PPC32,   750,            "PowerPC 750",                  10),
+       _ENTRY(PPC32,   7400,           "PowerPC 7400",                 11),
+       _ENTRY(PPC32,   7450,           "PowerPC 7450",                 12),
+       _ENTRY(PPC32,   970,            "PowerPC 970",                  13),
+       { .name = NULL },
+};
+static const struct macho_cpu_subentry macho_cpu_ppc64_subtypes[] = {
+       _ENTRY(PPC64,   ALL,            "all PowerPC64",                14),
+       /*_ENTRY(PPC64, 970,            "PowerPC 970",                   1),*/
+       { .name = NULL },
+};
+#undef _ENTRY
+
+/*
+ * A CPU type mapping table with human-readable strings
+ */
+struct macho_cpu_entry {
+       const char *name;
+       macho_cpu_type_t type;
+       const struct macho_cpu_subentry *subtypes;
+};
+static const struct macho_cpu_entry macho_cpu_types[] = {
+#define _ENTRY(TYPE, SUBTYPES, NAME) {                         \
+               .name = NAME,                                   \
+               .type = MACHO_CPU_TYPE_ ## TYPE,                \
+               .subtypes = SUBTYPES                            \
+       }
+       _ENTRY(PPC32,   macho_cpu_ppc32_subtypes,       "PowerPC"       ),
+       _ENTRY(PPC64,   macho_cpu_ppc64_subtypes,       "PowerPC64"     ),
+       _ENTRY(I386,    macho_cpu_i386_subtypes,        "Intel x86"     ),
+       _ENTRY(VAX,     macho_cpu_vax_subtypes,         "VAX"           ),
+       _ENTRY(M68K,    macho_cpu_m68k_subtypes,        "Motorola 68xxx"),
+       _ENTRY(MIPS,    macho_cpu_mips_subtypes,        "MIPS"          ),
+       _ENTRY(M98K,    macho_cpu_m98k_subtypes,        "Motorola 98xxx"),
+       _ENTRY(PARISC,  macho_cpu_parisc_subtypes,      "HPPA/PaRISC"   ),
+       _ENTRY(ARM,     NULL,                           "ARM"           ),
+       _ENTRY(M88K,    macho_cpu_m88k_subtypes,        "Motorola 88xxx"),
+       _ENTRY(SPARC,   macho_cpu_sparc_subtypes,       "Sparc"         ),
+       _ENTRY(I860,    macho_cpu_i860_subtypes,        "i860"          ),
+       _ENTRY(ALPHA,   NULL,                           "Alpha"         ),
+       _ENTRY(ANY,     NULL,                           "unknown"       ),
+       { .name = NULL },
+#undef _ENTRY
+};
+
+static unsigned int macho_check_cpu(macho_cpu_type_t type,
+                                       macho_cpu_subtype_t subtype)
+{
+       const struct macho_cpu_subentry *entry = NULL;
+       unsigned long i;
+
+       /* Iterate over all the CPU types */
+       for (i = 0; macho_cpu_types[i].name; i++)
+               if (type == macho_cpu_types[i].type)
+                       break;
+
+       /* Invalid CPU if we didn't find a match */
+       if (!macho_cpu_types[i].name) {
+               macho_dbg("Unknown CPU type (%u)\n", type);
+               return 0;
+       }
+
+       entry = macho_cpu_types[i].subtypes;
+
+       /* Iterate over all the CPU subtypes (if any) */
+       for (; entry && entry->name; entry++)
+               if (type == entry->type && subtype == entry->subtype)
+                       break;
+
+       /* Invalid CPU if we didn't find a match */
+       if (!entry) {
+               macho_dbg("Unknown %s subtype (%u)\n",
+                               macho_cpu_types[i].name, subtype);
+               return 0;
+       }
+
+       macho_dbg("Found binary image for %s\n", entry->name);
+
+       /* Return the preference level for this code */
+       return entry->preference;
+}
+
+#endif /* not _MACHO_CPUS_H */
diff --git a/fs/mach-o/debug.h b/fs/mach-o/debug.h
new file mode 100644
index 0000000..205cbfe
--- /dev/null
+++ b/fs/mach-o/debug.h
@@ -0,0 +1,9 @@
+#ifndef  _MACHO_DEBUG_H
+# define _MACHO_DEBUG_H 1
+
+# include <linux/kernel.h>     /* For printk() */
+
+# define macho_dbg(x, args...) \
+       printk(KERN_DEBUG "binfmt_mach-o: " x,##args)
+
+#endif /* not _MACHO_DEBUG_H */
diff --git a/fs/mach-o/files.h b/fs/mach-o/files.h
new file mode 100644
index 0000000..17253d9
--- /dev/null
+++ b/fs/mach-o/files.h
@@ -0,0 +1,139 @@
+#ifndef  _MACHO_FILES_H
+# define _MACHO_FILES_H 1
+
+# include "debug.h"
+# include <linux/types.h>      /* For __u32    */
+
+/*
+ * Mach-O file types, borrowed from Darwin
+ */
+typedef __u32 __bitwise macho_file_type_t;
+# define _ENTRY(type, num) \
+       MACHO_FILE_TYPE_##type = ((__force macho_file_type_t)num)
+enum {
+       _ENTRY(OBJECT,          1),
+       _ENTRY(EXECUTE,         2),
+       _ENTRY(FVMLIB,          3),
+       _ENTRY(CORE,            4),
+       _ENTRY(PRELOAD,         5),
+       _ENTRY(DYLIB,           6),
+       _ENTRY(DYLINKER,        7),
+       _ENTRY(BUNDLE,          8),
+       _ENTRY(DYLIB_STUB,      9),
+};
+#undef _ENTRY
+
+/*
+ * A file type mapping table with human-readable strings
+ */
+struct macho_file_type_entry {
+       const char *name;
+       macho_file_type_t type;
+       unsigned int runnable;
+};
+
+static const struct macho_file_type_entry macho_file_types[] = {
+#define _ENTRY(TYPE, NAME, RUNNABLE) {                 \
+               .name = NAME,                           \
+               .type = MACHO_FILE_TYPE_ ## TYPE,       \
+               .runnable = RUNNABLE                    \
+       }
+       _ENTRY(OBJECT,          "relocatable object",                   1),
+       _ENTRY(EXECUTE,         "demand-paged executable",              1),
+       _ENTRY(FVMLIB,          "fixed-virtual-memory shared library",  0),
+       _ENTRY(CORE,            "coredump",                             0),
+       _ENTRY(PRELOAD,         "preloaded executable",                 1),
+       _ENTRY(DYLIB,           "dynamically linked shared library",    0),
+       _ENTRY(DYLINKER,        "dynamic link editor",                  0),
+       _ENTRY(BUNDLE,          "dynamically linked module",            0),
+       _ENTRY(DYLIB_STUB,      "shared library stub for static link",  0),
+       { .name = NULL, }
+#undef _ENTRY
+};
+
+/*
+ * Mach-O file flags, borrowed from Darwin
+ */
+enum macho_file_flag {
+       MACHO_FILE_FLAG_NO_UNDEF        = 0,
+       MACHO_FILE_FLAG_INCR_LINK       = 1,
+       MACHO_FILE_FLAG_DYN_LINK        = 2,
+       MACHO_FILE_FLAG_BIND_AT_LOAD    = 3,
+       MACHO_FILE_FLAG_PREBOUND        = 4,
+       MACHO_FILE_FLAG_SPLIT_SEGS      = 5,
+       MACHO_FILE_FLAG_LAZY_INIT       = 6,
+       MACHO_FILE_FLAG_TWO_LEVEL       = 7,
+       MACHO_FILE_FLAG_FORCE_FLAT      = 8,
+       MACHO_FILE_FLAG_NO_MULT_DEFS    = 9,
+       MACHO_FILE_FLAG_NO_FIX_PREBIND  = 10,
+       MACHO_FILE_FLAG_PREBINDABLE     = 11,
+       MACHO_FILE_FLAG_ALL_MODS_BOUND  = 12,
+       MACHO_FILE_FLAG_SUBSECT_VIA_SYM = 13,
+       MACHO_FILE_FLAG_CANONICAL       = 14,
+       MACHO_FILE_FLAG_WEAK_DEFINES    = 15,
+       MACHO_FILE_FLAG_BINDS_TO_WEAK   = 16,
+       MACHO_FILE_FLAG_EXECSTACK       = 17,
+};
+
+/*
+ * A file flag mapping table with human-readable strings
+ */
+static const char *macho_file_flags[] = {
+#define _ENTRY(FLAG, NAME) [MACHO_FILE_FLAG_ ## FLAG] = NAME
+       _ENTRY( NO_UNDEF,       "has no undefined references"           ),
+       _ENTRY( INCR_LINK,      "was incrementally linked"              ),
+       _ENTRY( DYN_LINK,       "was dynamically linked"                ),
+       _ENTRY( BIND_AT_LOAD,   "will bind undefined refs during load"  ),
+       _ENTRY( PREBOUND,       "is prebound"                           ),
+       _ENTRY( SPLIT_SEGS,     "has split RO and R/W segments"         ),
+       _ENTRY( LAZY_INIT,      "is lazily initialized"                 ),
+       _ENTRY( TWO_LEVEL,      "uses two-level namespace bindings"     ),
+       _ENTRY( FORCE_FLAT,     "forces flat namespace bindings"        ),
+       _ENTRY( NO_MULT_DEFS,   "doesn't have multiply defined symbols" ),
+       _ENTRY( NO_FIX_PREBIND, "won't notify the prebinding agent"     ),
+       _ENTRY( PREBINDABLE,    "can be prebound"                       ),
+       _ENTRY( ALL_MODS_BOUND, "is fully bound to two-level namespaces"),
+       _ENTRY( SUBSECT_VIA_SYM,"can be divided via symbols"            ),
+       _ENTRY( CANONICAL,      "is canonicalized by un-prebinding"     ),
+       _ENTRY( WEAK_DEFINES,   "exports weak symbols"                  ),
+       _ENTRY( BINDS_TO_WEAK,  "imports weak symbols"                  ),
+       _ENTRY( EXECSTACK,      "requires executable stack"             ),
+       NULL
+};
+
+static int macho_check_file(macho_file_type_t type, __u32 flags)
+{
+       enum macho_file_flag flag = /* 0 */ MACHO_FILE_FLAG_NO_UNDEF;
+       unsigned long i;
+
+       /* Iterate over the list of file types */
+       for (i = 0; macho_file_types[i].name; i++)
+               if (macho_file_types[i].type == type)
+                       break;
+
+       /* If we didn't find the file type then it's not executable */
+       if (!macho_file_types[i].name) {
+               macho_dbg("Unknown filetype (%u)\n", type);
+               return 0;
+       }
+
+       macho_dbg("Mach-O %s (%sexecutable):\n", macho_file_types[i].name,
+                       macho_file_types[i].runnable?"":"not ");
+
+       /* Check every flag */
+       while (flags && macho_file_flags[flag]) {
+               if (flags & 1)
+                       macho_dbg("    %s\n", macho_file_flags[flag]);
+
+               flag++;
+               flags >>= 1;
+       }
+
+       if (flags)
+               macho_dbg("Unknown file flag bits: 0x%08lx\n",
+                               (unsigned long)(flags << flag));
+
+       return macho_file_types[i].runnable;
+}
+
+#endif /* not _MACHO_FILES_H */
diff --git a/fs/mach-o/headers.h b/fs/mach-o/headers.h
new file mode 100644
index 0000000..17f019d
--- /dev/null
+++ b/fs/mach-o/headers.h
@@ -0,0 +1,49 @@
+#ifndef  _MACHO_HEADERS_H
+# define _MACHO_HEADERS_H 1
+
+# include <linux/types.h>
+# include "cpus.h"
+
+/* Mach-O universal binary header */
+# define MACHO_FAT_MAGIC (__constant_cpu_to_be32(0xcafebabe))
+struct macho_fat_header {
+       __be32 magic;
+       __be32 arch_count;
+} __attribute__((__packed__));
+
+struct macho_fat_arch {
+       __be32 cpu_type;
+       __be32 cpu_subtype;
+       __be32 offset;
+       __be32 size;
+       __be32 align;
+} __attribute__((__packed__));
+
+/* Mach-O 32-bit arch-specific binary header */
+# define MACHO_MACH32_MAGIC (0xfeedface)
+# define MACHO_MACH32_CIGAM (___constant_swab32(MACHO_MACH32_MAGIC))
+struct macho_mach32_header {
+       __u32 magic;
+       macho_cpu_type_t cpu_type;
+       macho_cpu_subtype_t cpu_subtype;
+       __u32 filetype;
+       __u32 cmd_count;
+       __u32 cmd_size;
+       __u32 flags;
+} __attribute__((__packed__));
+
+/* Mach-O 64-bit arch-specific binary header */
+# define MACHO_MACH64_MAGIC (0xfeedfacf)
+# define MACHO_MACH64_CIGAM (___constant_swab32(MACHO_MACH64_MAGIC))
+struct macho_mach64_header {
+       __u32 magic;
+       macho_cpu_type_t cpu_type;
+       macho_cpu_subtype_t cpu_subtype;
+       __u32 filetype;
+       __u32 cmd_count;
+       __u32 cmd_size;
+       __u32 flags;
+       __u32 reserved;
+} __attribute__((__packed__));
+
+#endif /* not _MACHO_HEADERS_H */

Reply via email to