From ff46ad92ae59fdbe9e2bda6976a1254a1e44275c Mon Sep 17 00:00:00 2001
From: Charles Davis <cdavis5x@gmail.com>
Date: Sat, 7 Dec 2013 17:34:09 -0700
Subject: [PATCH 2/2] kernel32: Also recognize and handle Mach-O fat binaries.

This will be needed for WOW64 support on Mac OS, because there are no
separate directories for 32-bit and 64-bit libraries.
---
 dlls/kernel32/module.c | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 76 insertions(+)

diff --git a/dlls/kernel32/module.c b/dlls/kernel32/module.c
index f495e81..7b0f64d 100644
--- a/dlls/kernel32/module.c
+++ b/dlls/kernel32/module.c
@@ -250,6 +250,11 @@ void MODULE_get_binary_info( HANDLE hfile, struct binary_info *info )
             unsigned int cpusubtype;
             unsigned int filetype;
         } macho;
+        struct
+        {
+            unsigned int magic;
+            unsigned int nfat_arch;
+        } macho_fat;
         IMAGE_DOS_HEADER mz;
     } header;
 
@@ -259,6 +264,7 @@ void MODULE_get_binary_info( HANDLE hfile, struct binary_info *info )
 
     /* Seek to the start of the file and read the header information. */
     if (SetFilePointer( hfile, 0, NULL, SEEK_SET ) == -1) return;
+read_header:
     if (!ReadFile( hfile, &header, sizeof(header), &len, NULL ) || len != sizeof(header)) return;
 
     if (!memcmp( header.elf.magic, "\177ELF", 4 ))
@@ -312,6 +318,76 @@ void MODULE_get_binary_info( HANDLE hfile, struct binary_info *info )
         case 0x00000012: info->arch = IMAGE_FILE_MACHINE_POWERPC; break;
         }
     }
+    /* Mach-O fat file with Endian set to Big Endian or Little Endian */
+    else if (header.macho_fat.magic == 0xcafebabe || header.macho_fat.magic == 0xbebafeca)
+    {
+        struct
+        {
+            unsigned int cputype;
+            unsigned int cpusubtype;
+            unsigned int offset;
+            unsigned int size;
+            unsigned int align;
+        } fat_arch;
+        unsigned int i, offset = 0, first_offset = 0;
+#ifdef __i386__
+        BOOL is_wow64;
+        IsWow64Process( GetCurrentProcess(), &is_wow64 );
+#endif
+        if (header.macho_fat.magic == 0xbebafeca)
+            header.macho_fat.nfat_arch = RtlUlongByteSwap( header.macho_fat.nfat_arch );
+        /* Try and find an architecture we can execute */
+        for (i = 0; i < header.macho_fat.nfat_arch; i++)
+        {
+            if (!ReadFile( hfile, &fat_arch, sizeof(fat_arch), &len, NULL ) || len < sizeof(fat_arch)) return;
+            if (header.macho_fat.magic == 0xbebafeca)
+            {
+                fat_arch.cputype = RtlUlongByteSwap( fat_arch.cputype );
+                fat_arch.offset = RtlUlongByteSwap( fat_arch.offset );
+            }
+            if (!first_offset) first_offset = fat_arch.offset;
+#if defined(__x86_64__)
+            /* Always prefer x86_64 */
+            if (fat_arch.cputype == 0x010000007)
+            {
+                offset = fat_arch.offset;
+                break;
+            }
+            /* But consider i386, too */
+            if (fat_arch.cputype == 0x000000007)
+                offset = fat_arch.offset;
+#elif defined(__i386__)
+            /* If WOW64, prefer x86_64; otherwise, prefer i386 */
+            if ((is_wow64 && fat_arch.cputype == 0x01000007) ||
+                (!is_wow64 && fat_arch.cputype == 0x00000007))
+            {
+                offset = fat_arch.offset;
+                break;
+            }
+            /* If WOW64, consider i386, too */
+            if (is_wow64 && fat_arch.cputype == 0x00000007)
+                offset = fat_arch.offset;
+#elif defined(__aarch64__)
+            if (fat_arch.cputype == 0x0100000c)
+                offset = fat_arch.offset;
+#elif defined(__arm__)
+            if (fat_arch.cputype == 0x0000000c)
+                offset = fat_arch.offset;
+#elif defined(__powerpc__)
+            if (fat_arch.cputype == 0x00000012)
+                offset = fat_arch.offset;
+#endif
+        }
+        /* If we can't execute any of the architectures,
+         * just use the first one. We don't really have the
+         * support to say, "this file works on more than one
+         * architecture" yet. */
+        if (!offset) offset = first_offset;
+
+        /* Go and read the executable header */
+        if (SetFilePointer( hfile, offset, NULL, SEEK_SET ) == -1) return;
+        goto read_header;
+    }
     /* Not ELF, try DOS */
     else if (header.mz.e_magic == IMAGE_DOS_SIGNATURE)
     {
-- 
2.3.7

