mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [RFC][PATCH 0/2] Darwinux:  Binary compat support for Mach-O/Darwin in Linux
@ 2007-03-30 18:05 Kyle Moffett
  2007-03-30 18:06 ` [RFC][PATCH 1/2] Darwinux: Minimalist Mach-O binary format support Kyle Moffett
  2007-03-30 18:08 ` [RFC][PATCH 2/2] Darwinux: Proper support for digging through the Mach-O load-command table Kyle Moffett
  0 siblings, 2 replies; 3+ messages in thread
From: Kyle Moffett @ 2007-03-30 18:05 UTC (permalink / raw)
  To: LKML Kernel
  Cc: Linus Torvalds, Benjamin Herrenschmidt, Paul Mackerras,
	Mathieu Desnoyers

I've gotten some time to start working with this code again and I'm  
looking for some review on my first couple patches.  After these two  
patches the code does little more than print out lots of details  
about the binary being run to the syslog and then fail with -ENOEXEC,  
but it's a start.  I'm currently fixing up my icky memory-mapping  
code to avoid allocating big chunks of kernel memory for tables in  
the binary, and once I make some progress on that I'll submit it too.

I'd appreciate any information on what is required in the load_binary  
function in my binfmt.  In particular, if there's anything which fs/ 
binfmt_elf.c does do which is *NOT* required, I'd be interested to  
know what and why.  Thanks for all your assistance.

Cheers,
Kyle Moffett

^ permalink raw reply	[flat|nested] 3+ messages in thread

* [RFC][PATCH 1/2] Darwinux: Minimalist Mach-O binary format support
  2007-03-30 18:05 [RFC][PATCH 0/2] Darwinux: Binary compat support for Mach-O/Darwin in Linux Kyle Moffett
@ 2007-03-30 18:06 ` Kyle Moffett
  2007-03-30 18:08 ` [RFC][PATCH 2/2] Darwinux: Proper support for digging through the Mach-O load-command table Kyle Moffett
  1 sibling, 0 replies; 3+ messages in thread
From: Kyle Moffett @ 2007-03-30 18:06 UTC (permalink / raw)
  To: Kyle Moffett
  Cc: LKML Kernel, Linus Torvalds, Benjamin Herrenschmidt,
	Paul Mackerras, Mathieu Desnoyers

[-- Attachment #1: Type: text/plain, Size: 814 bytes --]

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 <mrmacman_g4@mac.com>
---
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(-)


[-- Attachment #2: darwinux_01.txt --]
[-- Type: text/plain, Size: 27533 bytes --]

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 <mrmacman_g4@mac.com>
+ *
+ * Designed from public documentation and Darwin sources as well as the Linux
+ * ELF loader by Eric Youngdale (ericy@cais.com).
+ */
+
+#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 */

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [RFC][PATCH 2/2] Darwinux:  Proper support for digging through the Mach-O load-command table
  2007-03-30 18:05 [RFC][PATCH 0/2] Darwinux: Binary compat support for Mach-O/Darwin in Linux Kyle Moffett
  2007-03-30 18:06 ` [RFC][PATCH 1/2] Darwinux: Minimalist Mach-O binary format support Kyle Moffett
@ 2007-03-30 18:08 ` Kyle Moffett
  1 sibling, 0 replies; 3+ messages in thread
From: Kyle Moffett @ 2007-03-30 18:08 UTC (permalink / raw)
  To: Kyle Moffett
  Cc: LKML Kernel, Linus Torvalds, Benjamin Herrenschmidt,
	Paul Mackerras, Mathieu Desnoyers

[-- Attachment #1: Type: text/plain, Size: 790 bytes --]

Proper support for digging through the Mach-O load-command table

Uses kernel_read() to carefully iterate through all the Mach-O load
commands and logs their properties to the dmesg buffer.  Partial  
support is
also present for VM setup, but it's lacking a necessary symbol export on
PowerPC (arch_pick_mmap_layout).  The process currently receives a  
SIGKILL
after reading through all the load commands; pending completion of the
memory-mapping and setup code.

Signed-off-by: Kyle Moffett <mrmacman_g4@mac.com>
---
fs/mach-o/binfmt.c   |  258 +++++++++++++++++++++++----------
fs/mach-o/cpus.h     |   49 ++++---
fs/mach-o/files.h    |   67 +++++----
fs/mach-o/loadcmds.h |  389 ++++++++++++++++++++++++++++++++++++++++++ 
++++++++
4 files changed, 640 insertions(+), 123 deletions(-)


[-- Attachment #2: darwinux_02.txt --]
[-- Type: text/plain, Size: 29049 bytes --]

diff --git a/fs/mach-o/binfmt.c b/fs/mach-o/binfmt.c
index b5ea936..ea2f46e 100644
--- a/fs/mach-o/binfmt.c
+++ b/fs/mach-o/binfmt.c
@@ -14,44 +14,13 @@
 #include <linux/binfmts.h>
 #include <linux/fs.h>
 #include <linux/err.h>
+#include <linux/personality.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
+#include "loadcmds.h"
 
 MODULE_LICENSE("GPL");
 
@@ -187,21 +156,25 @@ static int load_macho_binary(struct linux_binprm *bprm, struct pt_regs *regs)
 			struct macho_mach32_header mach32;
 			struct macho_mach64_header mach64;
 		} header;
-#if 0
-		struct macho_loadcmd loadcmd;
-#endif
+		union macho_loadcmd loadcmd;
 	} *data = NULL;
-	unsigned long offset;
+	unsigned long hdr_cmd_count, hdr_cmd_size;
+	unsigned long cur_offset, loadcmd_size, i;
+	unsigned long arch_offset;
 	long retval;
-	int err;
+	int err = -ENOEXEC;
+
+	/* Make sure the file has appropriate ops */
+	if (!bprm->file->f_op || !bprm->file->f_op->mmap)
+		goto out;
 
 	/*
 	 * 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;
+	arch_offset = get_arch_offset(bprm);
+	if (IS_ERR_VALUE(arch_offset)) {
+		err = (long)arch_offset;
 		goto out;
 	}
 
@@ -213,14 +186,14 @@ static int load_macho_binary(struct linux_binprm *bprm, struct pt_regs *regs)
 	}
 
 	/* Read the header data and check the magic */
-	retval = kernel_read(bprm->file, offset,
+	retval = kernel_read(bprm->file, arch_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)
+		if (!arch_offset)
 			err = -ENOEXEC;
 
 		/* If kernel_read() returned an error, handle it */
@@ -251,7 +224,7 @@ static int load_macho_binary(struct linux_binprm *bprm, struct pt_regs *regs)
 	 */
 	if (data->header.magic != MACHO_MACH32_MAGIC &&
 			data->header.magic != MACHO_MACH64_MAGIC) {
-		if (offset)
+		if (arch_offset)
 			macho_dbg("Corrupt embedded Mach-O object!\n");
 		err = -ENOEXEC;
 		goto out;
@@ -260,13 +233,12 @@ static int load_macho_binary(struct linux_binprm *bprm, struct pt_regs *regs)
 	/* 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.
+		 * a different platform (arch_offset == 0) or the FAT Mach-O
+		 * has been corrupted.
 		 */
-		if (offset)
+		if (arch_offset)
 			macho_dbg("FAT Mach-O wrapper has mismatched CPU"
 					" types:  Mach-O file corrupt?\n");
 		else
@@ -283,39 +255,175 @@ static int load_macho_binary(struct linux_binprm *bprm, struct pt_regs *regs)
 		goto out;
 	}
 
+	/*
+	 * Get some load-command info out of the header (NOTE: Lines up
+	 * between 32-bit and 64-bit Mach-O files
+	 */
+	hdr_cmd_count = data->header.mach32.cmd_count;
+	hdr_cmd_size  = data->header.mach32.cmd_size;
+
+	/* 
+	 * FIXME:  Limits the total space for load commands to 1MB, but this
+	 * should be made configurable somehow for embedded systems with
+	 * minimal available resources.  Is there an rlimit or some page
+	 * accounting we can hook into?  I don't think this is that critical
+	 * of an issue since for the most part we only store one load-command
+	 * in kernel memory at a time, however some things like unixthread
+	 * and thread load-commands need to be kept around until after we've
+	 * loaded the dynamic linker.
+	 */
+	if (hdr_cmd_size > (1 << 20)) {
+		macho_dbg("Mach-O file has more than 1MB worth of "
+				"load-commands (%lu bytes)\n", hdr_cmd_size);
+		err = -ENOMEM;
+		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);
+	cur_offset = arch_offset +
+		((data->header.magic == MACHO_MACH32_MAGIC)
+			? sizeof(struct macho_mach32_header)
+			: sizeof(struct macho_mach64_header));
+
+#if 0
+	/*
+	 * Just to avoid allocating gobs of kernel memory while we parse the
+	 * load-command table, we're going to go past the point of no return
+	 * nice and early, so we can just start mapping things into memory
+	 */
+	err = flush_old_exec(bprm);
+	if (err)
+		goto out;
+
+	/* FIXME: This needs to actually switch to the darwin personality */
+	set_personality(PER_LINUX);
+	
+	/* FIXME: Set up ugly stack/brk/etc for testing, need to fix later */
+	current->mm->start_data	= 0;
+	current->mm->end_data	= 0;
+	current->mm->end_code	= 0;
+	current->mm->mmap	= NULL;
+	current->mm->def_flags	= 0;
+
+	/* Make sure to clear the fork-but-not-exec bit on this process */
+	current->flags &= ~PF_FORKNOEXEC;
+
+	/*
+	 * FIXME: Figure out how to do MMAP, may need to be changed to be
+	 * darwinish
+	 */
+	current->mm->mmap_base = TASK_UNMAPPED_BASE;
+	current->mm->get_unmapped_area = arch_get_unmapped_area;
+	current->mm->unmap_area = arch_unmap_area;
+	current->mm->free_area_cache = current->mm->mmap_base;
+	current->mm->cached_hole_size = 0;
+#endif
+
+	/* Iterate over reading the load commands */
+	loadcmd_size = 0;
+	for (i = 0; i < hdr_cmd_count; i++) {
+		unsigned long size;
+
+		/* Check that we have room for another load command */
+		if (loadcmd_size + sizeof(data->loadcmd.hdr) > hdr_cmd_size) {
+			macho_dbg("Mach-O header doesn't allocate enough "
+					"space for load-commands %lu-%lu!\n",
+					i, hdr_cmd_count-1);
+			err = -ENOEXEC;
+			goto out_noreturn;
+		}
+
+		/* First read the itty-bitty command num and size fields */
+		retval = kernel_read(bprm->file, cur_offset,
+				(void *)&data->loadcmd.hdr,
+				sizeof(data->loadcmd.hdr));
+		if (retval != sizeof(data->loadcmd.hdr)) {
+			/* If kernel_read() returned an error, handle it */
+			if (retval < 0) {
+				macho_dbg("Error while reading Mach-O load"
+					" command %lu: %li\n", i, retval);
+				err = retval;
+			} else {
+				macho_dbg("Truncated Mach-O load command "
+					"%lu: (got %lib, wanted %lub)\n", i,
+					retval, sizeof(data->loadcmd.hdr));
+				err = -ENOEXEC;
+			}
+			goto out_noreturn;
+		}
+
+		/* Check/display the load command number */
+		macho_check_loadcmd(data->loadcmd.hdr.cmd);
+		size = data->loadcmd.hdr.size;
+
+		/* 
+		 * Ensure the load-command size is a multiple of 4 bytes and
+		 * large enough to contain the load-command header.
+		 */
+		if (size & 0x3 || size < sizeof(data->loadcmd.hdr)) {
+			macho_dbg("Invalid size for load command %lu: %lu\n",
+				i, (unsigned long)data->loadcmd.hdr.size);
+			err = -ENOEXEC;
+			goto out_noreturn;
+		}
+
+		/* Check that we have room for another load command */
+		if (loadcmd_size + size > hdr_cmd_size) {
+			macho_dbg("Mach-O header doesn't allocate enough "
+					"space for load-commands %lu-%lu!\n",
+					i, hdr_cmd_count-1);
+			err = -ENOEXEC;
+			goto out_noreturn;
+		}
+
+		/* Check that it isn't too big */
+		if (size > sizeof(data->loadcmd)) {
+			macho_dbg("Load command %lu is too big (%lu > %lu): "
+				"skipped!\n", i, size, sizeof(data->loadcmd));
+			loadcmd_size += size;
+			cur_offset   += size;
+			continue;
+		}
+
+		/* Read in the rest of the load-command and move past it */
+		retval = kernel_read(bprm->file, cur_offset,
+				(void *)&data->loadcmd, size);
+		if (retval != size) {
+			/* If kernel_read() returned an error, handle it */
+			if (retval < 0) {
+				macho_dbg("Error while reading Mach-O load"
+					" command %lu: %li\n", i, retval);
+				err = retval;
+			} else {
+				macho_dbg("Truncated Mach-O load command "
+					"%lu: (got %lib, wanted %lub)\n", i,
+					retval, size);
+				err = -ENOEXEC;
+			}
+			goto out_noreturn;
+		}
+		loadcmd_size += size;
+		cur_offset   += size;
+
+		switch (data->loadcmd.hdr.cmd) {
+			case MACHO_LOADCMD_NUM_SEGMENT64:
+			case MACHO_LOADCMD_NUM_SEGMENT32:
+			case MACHO_LOADCMD_NUM_THREAD_NOSTACK:
+			case MACHO_LOADCMD_NUM_THREAD:
+			case MACHO_LOADCMD_NUM_REF_DYLD:
+				macho_dbg("    Load command completed!\n");
+				break;
+		}
+		/* XXX FIXME XXX: Process the load-command */
+	}
 
 	err = -EINVAL;
-	goto out;
+	goto out_noreturn;
 
+out_noreturn:
+	send_sig(SIGKILL, current, 0);
 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
index a1f2276..00fa3c0 100644
--- a/fs/mach-o/cpus.h
+++ b/fs/mach-o/cpus.h
@@ -12,20 +12,27 @@ 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),
+	/* Historical architecture codes */
+	_ENTRY(ANY,	0xffffffff),	/* CPU_TYPE_ANY		*/
+	_ENTRY(VAX,	0x00000001),	/* CPU_TYPE_VAX		*/
+	_ENTRY(M68K,	0x00000006),	/* CPU_TYPE_MC680x0	*/
+	_ENTRY(MIPS,	0x00000008),	/* CPU_TYPE_MIPS	*/
+	_ENTRY(M98K,	0x0000000a),	/* CPU_TYPE_M98000	*/
+	_ENTRY(PARISC,	0x0000000b),	/* CPU_TYPE_HPPA	*/
+	_ENTRY(ARM,	0x0000000c),	/* CPU_TYPE_ARM		*/
+	_ENTRY(M88K,	0x0000000d),	/* CPU_TYPE_M88000	*/
+	_ENTRY(SPARC,	0x0000000e),	/* CPU_TYPE_SPARC	*/
+	_ENTRY(I860,	0x0000000f),	/* CPU_TYPE_I860	*/
+	_ENTRY(ALPHA,	0x00000010),	/* CPU_TYPE_ALPHA	*/
+
+	/*
+	 * Modern supported architectures. Note that a "CPU_TYPE_ABI64" flag
+	 * is OR-ed into the architecture code for a 64-bit architecture
+	 */
+	_ENTRY(I386,	0x00000007),	/* CPU_TYPE_X86 / CPU_TYPE_I386	*/
+	_ENTRY(X86_64,	0x01000007),	/* CPU_TYPE_X86_64		*/
+	_ENTRY(PPC32,	0x00000012),	/* CPU_TYPE_POWERPC		*/
+	_ENTRY(PPC64,	0x01000012),	/* CPU_TYPE_POWERPC64		*/
 };
 #undef _ENTRY
 
@@ -84,6 +91,9 @@ enum {
 	_ENTRY(I386_XEON,		0x0000000c),
 	_ENTRY(I386_XEON_MP,		0x0000001c),
 
+	/* AMD 64-bit subtypes */
+	_ENTRY(X86_64_ALL,		0x00000003),
+
 	/* MIPS subtypes */
 	_ENTRY(MIPS_ALL,		0x00000000),
 	_ENTRY(MIPS_R2300,		0x00000001),
@@ -131,7 +141,7 @@ enum {
 
 	/* Motorola/Freescale/IBM PowerPC64 subtypes */
 	_ENTRY(PPC64_ALL,		0x00000000),
-	/*_ENTRY(PPC64_970,		0x00000001),*/
+	_ENTRY(PPC64_970,		0x00000064),
 };
 #undef _ENTRY
 
@@ -198,6 +208,10 @@ static const struct macho_cpu_subentry macho_cpu_i386_subtypes[] = {
 	_ENTRY(I386,	XEON_MP,	"Intel Xeon SMP",		 0),
 	{ .name = NULL },
 };
+static const struct macho_cpu_subentry macho_cpu_x86_64_subtypes[] = {
+	_ENTRY(X86_64,	ALL,		"all 64-bit AMD",		 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),
@@ -252,7 +266,7 @@ static const struct macho_cpu_subentry macho_cpu_ppc32_subtypes[] = {
 };
 static const struct macho_cpu_subentry macho_cpu_ppc64_subtypes[] = {
 	_ENTRY(PPC64,	ALL,		"all PowerPC64",		14),
-	/*_ENTRY(PPC64,	970,		"PowerPC 970",			 1),*/
+	_ENTRY(PPC64,	970,		"PowerPC 970",			15),
 	{ .name = NULL },
 };
 #undef _ENTRY
@@ -273,7 +287,8 @@ static const struct macho_cpu_entry macho_cpu_types[] = {
 	}
 	_ENTRY(PPC32,	macho_cpu_ppc32_subtypes,	"PowerPC"	),
 	_ENTRY(PPC64,	macho_cpu_ppc64_subtypes,	"PowerPC64"	),
-	_ENTRY(I386,	macho_cpu_i386_subtypes,	"Intel x86"	),
+	_ENTRY(I386,	macho_cpu_i386_subtypes,	"Intel/AMD x86"	),
+	_ENTRY(X86_64,	macho_cpu_x86_64_subtypes,	"AMD 64-bit x86"),
 	_ENTRY(VAX,	macho_cpu_vax_subtypes,		"VAX"		),
 	_ENTRY(M68K,	macho_cpu_m68k_subtypes,	"Motorola 68xxx"),
 	_ENTRY(MIPS,	macho_cpu_mips_subtypes,	"MIPS"		),
diff --git a/fs/mach-o/files.h b/fs/mach-o/files.h
index 17253d9..cdbd028 100644
--- a/fs/mach-o/files.h
+++ b/fs/mach-o/files.h
@@ -8,20 +8,21 @@
  * Mach-O file types, borrowed from Darwin
  */
 typedef __u32 __bitwise macho_file_type_t;
+enum {
 # 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),
-};
+	_ENTRY(OBJECT,		0x01), /* MH_OBJECT	*/
+	_ENTRY(EXECUTE,		0x02), /* MH_EXECUTE	*/
+	_ENTRY(FVMLIB,		0x03), /* MH_FVMLIB	*/
+	_ENTRY(CORE,		0x04), /* MH_CORE	*/
+	_ENTRY(PRELOAD,		0x05), /* MH_PRELOAD	*/
+	_ENTRY(DYLIB,		0x06), /* MH_DYLIB	*/
+	_ENTRY(DYLD,		0x07), /* MH_DYLINKER	*/
+	_ENTRY(BUNDLE,		0x08), /* MH_BUNDLE	*/
+	_ENTRY(DYLIB_STUB,	0x09), /* MH_DYLIB_STUB	*/
+	_ENTRY(DEBUG_SYM,	0x0a), /* MY_DSYM	*/
 #undef _ENTRY
+};
 
 /*
  * A file type mapping table with human-readable strings
@@ -44,9 +45,10 @@ static const struct macho_file_type_entry macho_file_types[] = {
 	_ENTRY(CORE,		"coredump",				0),
 	_ENTRY(PRELOAD,		"preloaded executable",			1),
 	_ENTRY(DYLIB,		"dynamically linked shared library",	0),
-	_ENTRY(DYLINKER,	"dynamic link editor",			0),
+	_ENTRY(DYLD,		"dynamic link editor",			0),
 	_ENTRY(BUNDLE,		"dynamically linked module",		0),
 	_ENTRY(DYLIB_STUB,	"shared library stub for static link",	0),
+	_ENTRY(DEBUG_SYM,	"debug symbol file",			0),
 	{ .name = NULL, }
 #undef _ENTRY
 };
@@ -55,24 +57,26 @@ static const struct macho_file_type_entry macho_file_types[] = {
  * 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,
+#define _ENTRY(type, num) MACHO_FILE_FLAG_##type = num
+	_ENTRY(NO_UNDEF,	 0), /* MH_NOUNDEFS			*/
+	_ENTRY(INCR_LINK,	 1), /* MH_INCRLINK			*/
+	_ENTRY(DYN_LINK,	 2), /* MH_DYLDLINK			*/
+	_ENTRY(BIND_AT_LOAD,	 3), /* MH_BINDATLOAD			*/
+	_ENTRY(PREBOUND,	 4), /* MH_PREBOUND			*/
+	_ENTRY(SPLIT_SEGS,	 5), /* MH_SPLIT_SEGS			*/
+	_ENTRY(LAZY_INIT,	 6), /* MH_LAZY_INIT			*/
+	_ENTRY(TWO_LEVEL,	 7), /* MH_TWOLEVEL			*/
+	_ENTRY(FORCE_FLAT,	 8), /* MH_FORCE_FLAT			*/
+	_ENTRY(NO_MULT_DEFS,	 9), /* MH_NOMULTIDEFS			*/
+	_ENTRY(NO_FIX_PREBIND,	10), /* MH_NOFIXPREBINDING		*/
+	_ENTRY(PREBINDABLE,	11), /* MH_PREBINDABLE			*/
+	_ENTRY(ALL_MODS_BOUND,	12), /* MH_ALLMODSBOUND			*/
+	_ENTRY(SUBSECT_VIA_SYM,	13), /* MH_SUBSECTIONS_VIA_SYMBOLS	*/
+	_ENTRY(CANONICAL,	14), /* MH_CANONICAL			*/
+	_ENTRY(WEAK_DEFINES,	15), /* MH_WEAK_DEFINES			*/
+	_ENTRY(BINDS_TO_WEAK,	16), /* MH_BINDS_TO_WEAK		*/
+	_ENTRY(EXECSTACK,	17), /* MH_ALLOW_STACK_EXECUTION	*/
+#undef _ENTRY
 };
 
 /*
@@ -98,7 +102,8 @@ static const char *macho_file_flags[] = {
 	_ENTRY( WEAK_DEFINES,	"exports weak symbols"			),
 	_ENTRY( BINDS_TO_WEAK,	"imports weak symbols"			),
 	_ENTRY( EXECSTACK,	"requires executable stack"		),
-	NULL
+	NULL,
+#undef _ENTRY
 };
 
 static int macho_check_file(macho_file_type_t type, __u32 flags)
diff --git a/fs/mach-o/loadcmds.h b/fs/mach-o/loadcmds.h
new file mode 100644
index 0000000..0ee35c3
--- /dev/null
+++ b/fs/mach-o/loadcmds.h
@@ -0,0 +1,389 @@
+#ifndef  _MACHO_LOADCMDS_H
+# define _MACHO_LOADCMDS_H 1
+
+# include <linux/types.h>
+
+/*
+ * Mach-O load-command types, borrowed from Darwin
+ */
+typedef __u32 __bitwise macho_loadcmd_num_t;
+enum {
+# define _ENTRY(type, num) \
+	MACHO_LOADCMD_NUM_##type = ((__force macho_loadcmd_num_t)num)
+	_ENTRY(SEGMENT32,	0x01), /* LC_SEGMENT		*/
+	_ENTRY(SYMTAB_STAB,	0x02), /* LC_SYMTAB		*/
+	_ENTRY(SYMTAB_GDB,	0x03), /* LC_SYMSEG		*/
+	_ENTRY(THREAD_NOSTACK,	0x04), /* LC_THREAD		*/
+	_ENTRY(THREAD,		0x05), /* LC_UNIXTHREAD		*/
+	_ENTRY(REF_FVMLIB,	0x06), /* LC_LOADFVMLIB		*/
+	_ENTRY(ID_FVMLIB,	0x07), /* LC_IDFVMLIB		*/
+	_ENTRY(ID,		0x08), /* LC_IDENT		*/
+	_ENTRY(FVMFILE,		0x09), /* LC_FVMFILE		*/
+	_ENTRY(PREPAGE,		0x0a), /* LC_PREPAGE		*/
+	_ENTRY(SYMTAB_DYLD,	0x0b), /* LC_DYSYMTAB		*/
+	_ENTRY(REF_DYLIB,	0x0c), /* LC_LOAD_DYLIB		*/
+	_ENTRY(ID_DYLIB,	0x0d), /* LC_ID_DYLIB		*/
+	_ENTRY(REF_DYLD,	0x0e), /* LC_LOAD_DYLINKER	*/
+	_ENTRY(ID_DYLD,		0x0f), /* LC_ID_DYLINKER	*/
+	_ENTRY(PREBINDING,	0x10), /* LC_PREBOUND_DYLIB	*/
+	_ENTRY(INITCODE32,	0x11), /* LC_ROUTINES		*/
+	_ENTRY(SUB_FRAMEWORK,	0x12), /* LC_SUB_FRAMEWORK	*/
+	_ENTRY(SUB_UMBRELLA,	0x13), /* LC_SUB_UMBRELLA	*/
+	_ENTRY(SUB_CLIENT,	0x14), /* LC_SUB_CLIENT		*/
+	_ENTRY(SUB_LIBRARY,	0x15), /* LC_SUB_LIBRARY	*/
+	_ENTRY(HINTS_2LEVEL,	0x16), /* LC_TWOLEVEL_HINTS	*/
+	_ENTRY(PREBIND_CKSUM,	0x17), /* LC_PREBIND_CKSUM	*/
+	_ENTRY(WEAKREF_DYLIB,	0x18), /* LC_LOAD_DYLIB_WEAK	*/
+	_ENTRY(SEGMENT64,	0x19), /* LC_SEGMENT_64		*/
+	_ENTRY(INITCODE64,	0x1a), /* LC_ROUTINES_64	*/
+	_ENTRY(UUID,		0x1b), /* LC_UUID		*/
+# undef _ENTRY
+};
+
+/* Mach-O load command header */
+struct macho_loadcmd_hdr {
+	__u32 cmd;
+	__u32 size;
+} __attribute__((__packed__));
+
+/* Variable-length string in a Mach-O load command */
+struct macho_loadcmd_varstr {
+	__u32 off;
+} __attribute__((__packed__));
+
+/* Generic large load command */
+struct macho_loadcmd_unknown {
+	struct macho_loadcmd_hdr hdr;
+	__u8 data[2048 - sizeof(struct macho_loadcmd_hdr)];
+} __attribute__((__packed__));
+
+/* Mach-O memory-mapped file segment (32-bit) */
+struct macho_loadcmd_segment32 {
+	struct macho_loadcmd_hdr hdr;
+	char name[16];
+	__u32 vm_addr;
+	__u32 vm_size;
+	__u32 file_off;
+	__u32 file_size;
+	__u32 prot_max;
+	__u32 prot_init;
+	__u32 sect_count;
+	__u32 flags;
+} __attribute__((__packed__));
+
+/* Mach-O symbol table (stab) */
+struct macho_loadcmd_symtab_stab {
+	struct macho_loadcmd_hdr hdr;
+	__u32 sym_off;
+	__u32 sym_count;
+	__u32 str_off;
+	__u32 str_size;
+} __attribute__((__packed__));
+
+/* Mach-O symbol table (gdb, obsolete) */
+struct macho_loadcmd_symtab_gdb {
+	struct macho_loadcmd_hdr hdr;
+	__u32 symtab_off;
+	__u32 symtab_size;
+} __attribute__((__packed__));
+
+/* Mach-O new thread (with or without stack) */
+# define MACHO_LOADCMD_THREAD_MAX_PPC 144
+# define MACHO_LOADCMD_THREAD_MAX_X86 144
+struct macho_loadcmd_thread {
+	struct macho_loadcmd_hdr hdr;
+	__u32 threaddata[];
+} __attribute__((__packed__));
+
+/* Mach-O reference to or identity of a fixed-VM shared lib */
+struct macho_loadcmd_fvmlib {
+	struct macho_loadcmd_hdr hdr;
+	struct macho_loadcmd_varstr path;
+	__u32 vers;
+	__u32 addr;
+	__u8 data[];
+} __attribute__((__packed__));
+
+/* Mach-O identity of an object (obsolete) */
+struct macho_loadcmd_id {
+	struct macho_loadcmd_hdr hdr;
+	__u8 iddata[];
+} __attribute__((__packed__));
+
+/* Mach-O reference to a fixed VM file */
+struct macho_loadcmd_fvmfile {
+	struct macho_loadcmd_hdr hdr;
+	struct macho_loadcmd_varstr path;
+	__u32 addr;
+	__u8 data[];
+} __attribute__((__packed__));
+
+/* Mach-O unknown (LC_PREPAGE) */
+struct macho_loadcmd_prepage {
+	struct macho_loadcmd_hdr hdr;
+	__u8 prepagedata[];
+} __attribute__((__packed__));
+
+/* Mach-O symbol table (dyld) */
+struct macho_loadcmd_symtab_dyld {
+	struct macho_loadcmd_hdr hdr;
+	__u32 sym_local_off;
+	__u32 sym_local_num;
+	__u32 sym_extern_off;
+	__u32 sym_extern_num;
+	__u32 sym_undef_off;
+	__u32 sym_undef_num;
+	__u32 toc_off;
+	__u32 toc_num;
+	__u32 modtab_off;
+	__u32 modtab_num;
+	__u32 extref_off;
+	__u32 extref_num;
+	__u32 indirect_off;
+	__u32 indirect_num;
+	__u32 extrel_off;
+	__u32 extrel_num;
+	__u32 localrel_off;
+	__u32 localrel_num;
+} __attribute__((__packed__));
+
+/* Mach-O reference to or identity of a dynamic shared lib */
+struct macho_loadcmd_dylib {
+	struct macho_loadcmd_hdr hdr;
+	struct macho_loadcmd_varstr path;
+	__u32 timestamp;
+	__u32 vers_current;
+	__u32 vers_compat;
+	__u8 data[];
+} __attribute__((__packed__));
+
+/* Mach-O reference to or identity of a dynamic linker */
+struct macho_loadcmd_dyld {
+	struct macho_loadcmd_hdr hdr;
+	struct macho_loadcmd_varstr path;
+	__u8 data[];
+} __attribute__((__packed__));
+
+/* Mach-O prebinding against a dynamic shared lib */
+struct macho_loadcmd_prebinding {
+	struct macho_loadcmd_hdr hdr;
+	struct macho_loadcmd_varstr path;
+	__u32 modvec_num;
+	__u32 modvec_off;
+	__u8 data[];
+} __attribute__((__packed__));
+
+/* Mach-O shared library init routine (32-bit) */
+struct macho_loadcmd_initcode32 {
+	struct macho_loadcmd_hdr hdr;
+	__u32 init_address;
+	__u32 init_module;
+	__u32 reserved[6];
+} __attribute__((__packed__));
+
+/* Mach-O sub-framework file */
+struct macho_loadcmd_sub_framework {
+	struct macho_loadcmd_hdr hdr;
+	struct macho_loadcmd_varstr parent;
+	__u8 data[];
+} __attribute__((__packed__));
+
+/* Mach-O sub-umbrella-framework file */
+struct macho_loadcmd_sub_umbrella {
+	struct macho_loadcmd_hdr hdr;
+	struct macho_loadcmd_varstr parent;
+	__u8 data[];
+} __attribute__((__packed__));
+
+/* Mach-O sub-framework client entry */
+struct macho_loadcmd_sub_client {
+	struct macho_loadcmd_hdr hdr;
+	struct macho_loadcmd_varstr client;
+	__u8 data[];
+} __attribute__((__packed__));
+
+/* Mach-O sub-framework library */
+struct macho_loadcmd_sub_library {
+	struct macho_loadcmd_hdr hdr;
+	struct macho_loadcmd_varstr parent;
+	__u8 data[];
+} __attribute__((__packed__));
+
+/* Mach-O two-level namespace hinting table */
+struct macho_loadcmd_hints_2level {
+	struct macho_loadcmd_hdr hdr;
+	__u32 hinttable_offset;
+	__u32 hinttable_count;
+} __attribute__((__packed__));
+
+/* Mach-O prebinding checksum */
+struct macho_loadcmd_prebind_cksum {
+	struct macho_loadcmd_hdr hdr;
+	__u8 data[];
+} __attribute__((__packed__));
+
+/* Mach-O memory-mapped file segment (64-bit) */
+struct macho_loadcmd_segment64 {
+	struct macho_loadcmd_hdr hdr;
+	char name[16];
+	__u64 vm_addr;
+	__u64 vm_size;
+	__u32 file_off;
+	__u32 file_size;
+	__u32 prot_max;
+	__u32 prot_init;
+	__u32 sect_count;
+	__u32 flags;
+} __attribute__((__packed__));
+
+/* Mach-O shared library init routine (64-bit) */
+struct macho_loadcmd_initcode64 {
+	struct macho_loadcmd_hdr hdr;
+	__u64 init_address;
+	__u64 init_module;
+	__u64 reserved[6];
+} __attribute__((__packed__));
+
+/* Mach-O linked object UUID (LC_UUID) */
+struct macho_loadcmd_uuid {
+	struct macho_loadcmd_hdr hdr;
+	__u8 uuid[16];
+} __attribute__((__packed__));
+
+/* A generic Mach-O load command */
+union macho_loadcmd {
+	struct macho_loadcmd_hdr		hdr;
+	struct macho_loadcmd_unknown		unknown;
+	struct macho_loadcmd_segment32		segment32;
+	struct macho_loadcmd_symtab_stab	symtab_stab;
+	struct macho_loadcmd_symtab_gdb		symtab_gdb;
+	struct macho_loadcmd_thread		thread;
+	struct macho_loadcmd_fvmlib		fvmlib;
+	struct macho_loadcmd_id			id;
+	struct macho_loadcmd_fvmfile		fvmfile;
+	struct macho_loadcmd_prepage		prepage;
+	struct macho_loadcmd_symtab_dyld	symtab_dyld;
+	struct macho_loadcmd_dylib		dylib;
+	struct macho_loadcmd_dyld		dyld;
+	struct macho_loadcmd_prebinding		prebinding;
+	struct macho_loadcmd_initcode32		initcode32;
+	struct macho_loadcmd_sub_framework	sub_framework;
+	struct macho_loadcmd_sub_umbrella	sub_umbrella;
+	struct macho_loadcmd_sub_client		sub_client;
+	struct macho_loadcmd_sub_library	sub_library;
+	struct macho_loadcmd_hints_2level	hints_2level;
+	struct macho_loadcmd_prebind_cksum	prebind_cksum;
+	struct macho_loadcmd_segment64		segment64;
+	struct macho_loadcmd_initcode64		initcode64;
+	struct macho_loadcmd_uuid		uuid;
+} __attribute__((__packed__));
+
+/* Inernal function to check and return a load-command string */
+static inline const __u8 *macho_loadcmd_varstr_get__(
+		const struct macho_loadcmd_hdr *hdr,
+		const struct macho_loadcmd_varstr *varstr,
+		const __u8 *loadcmd_data)
+{
+	unsigned long data_offset = ((const void *)loadcmd_data) -
+			((const void *)hdr);
+	unsigned long str_offset, i;
+
+	/* Make sure the varstr points into the data area */
+	if (varstr->off < data_offset)
+		return NULL;
+	str_offset = varstr->off - data_offset;
+
+	/*
+	 * Iterate over all the characters in the variable-length string to
+	 * ensure that there is a trailing 0 before the end of the data area.
+	 */
+	for (i = str_offset; i < hdr->size; i++)
+		if (!loadcmd_data[i])
+			break;
+
+	/* If we quit before we hit end-of-data then it's a valid string */
+	if (i < hdr->size)
+		return &loadcmd_data[str_offset];
+
+	/* Sadly no such luck, it's a bogus Mach-O file */
+	return NULL;
+}
+
+/*
+ * Wrapper around the macho_loadcmd_varstr_get__ function above to make the
+ * calling-convention much easier.
+ *
+ * Example usage:
+ *   macho_loadcmd_dyld *dyld = (...);
+ *   const char *dyld_path = macho_loadcmd_varstr_get(dyld, path);
+ *   if (!dyld_path)
+ *           return -ENOEXEC;
+ */
+#define macho_loadcmd_varstr_get(LOADCMD, VARSTR) \
+	(macho_loadcmd_varstr_get__(&((LOADCMD)->hdr), \
+			&((LOADCMD)->VARSTR), (LOADCMD)->data))
+
+/*
+ * A Mach-O load-command mapping table with human-readable strings
+ */
+struct macho_loadcmd_entry {
+	const char *name;
+	macho_loadcmd_num_t cmd;
+	int pass;
+};
+
+static const struct macho_loadcmd_entry macho_loadcmds[] = {
+#define _ENTRY(TYPE, NAME) {			\
+		.name = NAME,				\
+		.cmd = MACHO_LOADCMD_NUM_ ## TYPE,	\
+	}
+	_ENTRY(SEGMENT32,	"memory-mapped file segment (32-bit)"),
+	_ENTRY(SYMTAB_STAB,	"symbol table (stab)"),
+	_ENTRY(SYMTAB_GDB,	"symbol table (gdb, obsolete)"),
+	_ENTRY(THREAD_NOSTACK,	"new thread (without stack)"),
+	_ENTRY(THREAD,		"new thread (with stack)"),
+	_ENTRY(REF_FVMLIB,	"reference to a fixed-VM shared lib"),
+	_ENTRY(ID_FVMLIB,	"identity of a fixed-VM shared lib"),
+	_ENTRY(ID,		"identity of an object (obsolete)"),
+	_ENTRY(FVMFILE,		"reference to a fixed VM file"),
+	_ENTRY(PREPAGE,		"unknown (LC_PREPAGE)"),
+	_ENTRY(SYMTAB_DYLD,	"symbol table (dyld)"),
+	_ENTRY(REF_DYLIB,	"reference to a dynamic shared lib"),
+	_ENTRY(ID_DYLIB,	"identity of a dynamic shared lib"),
+	_ENTRY(REF_DYLD,	"reference to a dynamic linker"),
+	_ENTRY(ID_DYLD,		"identity of a dynamic linker"),
+	_ENTRY(PREBINDING,	"prebinding against a dynamic shared lib"),
+	_ENTRY(INITCODE32,	"shared library init routine (32-bit)"),
+	_ENTRY(SUB_FRAMEWORK,	"sub-framework file"),
+	_ENTRY(SUB_UMBRELLA,	"sub-umbrella-framework file"),
+	_ENTRY(SUB_CLIENT,	"sub-framework client entry"),
+	_ENTRY(SUB_LIBRARY,	"sub-framework library"),
+	_ENTRY(HINTS_2LEVEL,	"two-level namespace hinting table"),
+	_ENTRY(PREBIND_CKSUM,	"prebinding checksum"),
+	_ENTRY(WEAKREF_DYLIB,	"weak reference to a dynamic shared lib"),
+	_ENTRY(SEGMENT64,	"memory-mapped file segment (64-bit)"),
+	_ENTRY(INITCODE64,	"shared library init routine (64-bit)"),
+	_ENTRY(UUID,		"linked object UUID"),
+	{ .name = NULL, }
+#undef _ENTRY
+};
+
+static void macho_check_loadcmd(macho_loadcmd_num_t cmd)
+{
+	unsigned long i;
+
+	/* Iterate over the list of file types */
+	for (i = 0; macho_loadcmds[i].name; i++)
+		if (macho_loadcmds[i].cmd == cmd)
+			break;
+
+	/* If we didn't find the load command type then ignore it */
+	if (!macho_loadcmds[i].name) {
+		macho_dbg("  Mach-O load command: unknown (%u)\n", cmd);
+		return;
+	}
+
+	macho_dbg("  Mach-O load command: %s\n", macho_loadcmds[i].name);
+}
+
+#endif /* not _MACHO_LOADCMDS_H */

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2007-03-30 18:08 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2007-03-30 18:05 [RFC][PATCH 0/2] Darwinux: Binary compat support for Mach-O/Darwin in Linux Kyle Moffett
2007-03-30 18:06 ` [RFC][PATCH 1/2] Darwinux: Minimalist Mach-O binary format support Kyle Moffett
2007-03-30 18:08 ` [RFC][PATCH 2/2] Darwinux: Proper support for digging through the Mach-O load-command table Kyle Moffett

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®