From 840560c5eb62907d65a655bf49af36d0e3229c66 Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Tue, 31 Aug 2021 16:18:56 -0700 Subject: [PATCH] file: basic Mach-O universal binary support. PowerPC may be dead and gone, but arm64 is the new x86-64, and x86-64 the new PowerPC :-) --- tests/file.test | 4 ++++ toys/posix/file.c | 36 +++++++++++++++++++++++++++++++----- 2 files changed, 35 insertions(+), 5 deletions(-) diff --git a/tests/file.test b/tests/file.test index 2e970998..5e7cccc9 100755 --- a/tests/file.test +++ b/tests/file.test @@ -14,6 +14,7 @@ ln -s $FILES/java.class symlink LINK=$(readlink symlink) ln -s $FILES/java.klass dangler BROKEN=$(readlink dangler) +echo "cafebabe000000020100000700000003000040000000d9300000000e0100000c8000000200014000000098500000000e" | xxd -r -p > universal testing "directory" "file ." ".: directory\n" "" "" testing "empty" "file empty" "empty: empty\n" "" "" @@ -28,6 +29,9 @@ testing "utf-8" \ testing "java class" \ "file $FILES/java.class | egrep -o '(Java class|version 53.0)'"\ "Java class\nversion 53.0\n" "" "" +testing "mach-o universal" \ + "file universal" \ + "universal: Mach-O universal binary with 2 architectures: x86-64,arm64\n" "" "" testing "tar file" "file $FILES/tar/tar.tar | sed 's|$FILES/||'" \ "tar/tar.tar: POSIX tar archive (GNU)\n" "" "" testing "gzip data" "file $FILES/tar/tar.tgz | grep -o 'gzip compressed data'" \ diff --git a/toys/posix/file.c b/toys/posix/file.c index f7a41569..48a1c37a 100644 --- a/toys/posix/file.c +++ b/toys/posix/file.c @@ -237,13 +237,39 @@ static void do_regular_file(int fd, char *name) // TODO: parsing JPEG for width/height is harder than GIF or PNG. else if (len>32 && !memcmp(s, "\xff\xd8", 2)) xputs("JPEG image data"); - // https://en.wikipedia.org/wiki/Java_class_file#General_layout - else if (len>8 && strstart(&s, "\xca\xfe\xba\xbe")) - xprintf("Java class file, version %d.%d (Java 1.%d)\n", - (int)peek_be(s+2, 2), (int)peek_be(s, 2), (int)peek_be(s+2, 2)-44); + else if (len>8 && strstart(&s, "\xca\xfe\xba\xbe")) { + unsigned count = peek_be(s, 4), i, arch; + + // 0xcafebabe can be a Java class file or a Mach-O universal binary. + // Java major version numbers start with 0x2d for JDK 1.1, and realistically + // you're never going to see more than 2 architectures in a binary anyway... + if (count < 0x2d) { + // https://eclecticlight.co/2020/07/28/universal-binaries-inside-fat-headers/ + xprintf("Mach-O universal binary with %u architecture%s:", + count, count == 1 ? "" : "s"); + s += 4; + len -= 8; + for (i = 0; i < count && len >= 20; i++) { + char *name = "unknown"; + + arch = peek_be(s, 4); + if (arch == 0x00000007) name = "i386"; + else if (arch == 0x01000007) name = "x86-64"; + else if (arch == 0x0000000c) name = "arm"; + else if (arch == 0x0100000c) name = "arm64"; + xprintf("%c%s", i?',':' ', name); + s += 20; + len -= 20; + } + xprintf("\n"); + } else { + // https://en.wikipedia.org/wiki/Java_class_file#General_layout + xprintf("Java class file, version %d.%d (Java 1.%d)\n", + (int)peek_be(s+2, 2), (int)peek_be(s, 2), (int)peek_be(s+2, 2)-44); + } // https://source.android.com/devices/tech/dalvik/dex-format#dex-file-magic - else if (len>8 && strstart(&s, "dex\n") && !s[3]) + } else if (len>8 && strstart(&s, "dex\n") && !s[3]) xprintf("Android dex file, version %s\n", s); // https://people.freebsd.org/~kientzle/libarchive/man/cpio.5.txt -- 2.39.2