JDevlieghere created this revision.
JDevlieghere added reviewers: jasonmolenda, pete, aprantl.
Herald added a project: All.
JDevlieghere requested review of this revision.

Support universal Mach-O binaries with a fat64 header. After D146879 
<https://reviews.llvm.org/D146879>, dsymutil can now generate such binaries 
when the offsets would otherwise overflow the 32-bit offsets in the regular fat 
header.

rdar://107289570


https://reviews.llvm.org/D147012

Files:
  lldb/packages/Python/lldbsuite/test/make/Makefile.rules
  
lldb/source/Plugins/ObjectContainer/Universal-Mach-O/ObjectContainerUniversalMachO.cpp
  
lldb/source/Plugins/ObjectContainer/Universal-Mach-O/ObjectContainerUniversalMachO.h
  lldb/test/API/macosx/universal64/Makefile
  lldb/test/API/macosx/universal64/TestUniversal64.py
  lldb/test/API/macosx/universal64/main.c

Index: lldb/test/API/macosx/universal64/main.c
===================================================================
--- /dev/null
+++ lldb/test/API/macosx/universal64/main.c
@@ -0,0 +1,5 @@
+#include <stdio.h>
+
+int foo() { return 0; }
+
+int main(int argc, char **argv) { return foo(); }
Index: lldb/test/API/macosx/universal64/TestUniversal64.py
===================================================================
--- /dev/null
+++ lldb/test/API/macosx/universal64/TestUniversal64.py
@@ -0,0 +1,39 @@
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+
+class Universal64TestCase(TestBase):
+    NO_DEBUG_INFO_TESTCASE = True
+
+    def do_test(self):
+        # Get the executable.
+        exe = self.getBuildArtifact("fat.out")
+
+        # Create a target.
+        self.target = self.dbg.CreateTarget(exe)
+
+        # Create a breakpoint on main.
+        main_bp = self.target.BreakpointCreateByName("main")
+        self.assertTrue(main_bp, VALID_BREAKPOINT)
+
+        # Make sure the binary and the dSYM are in the image list.
+        self.expect("image list ", patterns=['fat.out', 'fat.out.dSYM'])
+
+        # The dynamic loader doesn't support fat64 executables so we can't
+        # actually launch them here.
+
+    @skipUnlessDarwin
+    @skipIfDarwinEmbedded
+    def test_universal64_executable(self):
+        """Test fat64 universal executable"""
+        self.build(debug_info="dsym")
+        self.do_test()
+
+    @skipUnlessDarwin
+    @skipIfDarwinEmbedded
+    @skipIf(compiler="clang", compiler_version=['<', '7.0'])
+    def test_universal64_dsym(self):
+        """Test fat64 universal dSYM"""
+        self.build(debug_info="dsym", dictionary={'FAT64_DSYM': '1'})
+        self.do_test()
Index: lldb/test/API/macosx/universal64/Makefile
===================================================================
--- /dev/null
+++ lldb/test/API/macosx/universal64/Makefile
@@ -0,0 +1,24 @@
+EXE := fat.out
+
+ifdef FAT64_DSYM
+	DSFLAGS_EXTRAS=-fat64
+endif
+
+include Makefile.rules
+
+all: fat.out
+
+fat.out: fat.arm64.out fat.x86_64.out
+	lipo -fat64 -create -o $@ $^
+
+fat.x86_64.out: fat.x86_64.o
+	$(CC) -isysroot $(SDKROOT) -target x86_64-apple-macosx10.9 -o $@ $<
+
+fat.arm64.out: fat.arm64.o
+	$(CC) -isysroot $(SDKROOT) -target arm64-apple-macosx10.9 -o $@ $<
+
+fat.x86_64.o: main.c
+	$(CC) -isysroot $(SDKROOT) -g -O0 -target x86_64-apple-macosx11 -c -o $@ $<
+
+fat.arm64.o: main.c
+	$(CC) -isysroot $(SDKROOT) -g -O0 -target arm64-apple-macosx11 -c -o $@ $<
Index: lldb/source/Plugins/ObjectContainer/Universal-Mach-O/ObjectContainerUniversalMachO.h
===================================================================
--- lldb/source/Plugins/ObjectContainer/Universal-Mach-O/ObjectContainerUniversalMachO.h
+++ lldb/source/Plugins/ObjectContainer/Universal-Mach-O/ObjectContainerUniversalMachO.h
@@ -63,11 +63,46 @@
 
 protected:
   llvm::MachO::fat_header m_header;
-  std::vector<llvm::MachO::fat_arch> m_fat_archs;
+
+  struct FatArch {
+    FatArch(llvm::MachO::fat_arch arch) : m_arch(arch), m_is_fat64(false) {}
+    FatArch(llvm::MachO::fat_arch_64 arch) : m_arch(arch), m_is_fat64(true) {}
+
+    uint32_t GetCPUType() const {
+      return m_is_fat64 ? m_arch.fat_arch_64.cputype : m_arch.fat_arch.cputype;
+    }
+
+    uint32_t GetCPUSubType() const {
+      return m_is_fat64 ? m_arch.fat_arch_64.cpusubtype
+                        : m_arch.fat_arch.cpusubtype;
+    }
+
+    uint64_t GetOffset() const {
+      return m_is_fat64 ? m_arch.fat_arch_64.offset : m_arch.fat_arch.offset;
+    }
+
+    uint64_t GetSize() const {
+      return m_is_fat64 ? m_arch.fat_arch_64.size : m_arch.fat_arch.size;
+    }
+
+    uint32_t GetAlign() const {
+      return m_is_fat64 ? m_arch.fat_arch_64.align : m_arch.fat_arch.align;
+    }
+
+  private:
+    const union Arch {
+      Arch(llvm::MachO::fat_arch arch) : fat_arch(arch) {}
+      Arch(llvm::MachO::fat_arch_64 arch) : fat_arch_64(arch) {}
+      llvm::MachO::fat_arch fat_arch;
+      llvm::MachO::fat_arch_64 fat_arch_64;
+    } m_arch;
+    const bool m_is_fat64;
+  };
+  std::vector<FatArch> m_fat_archs;
 
   static bool ParseHeader(lldb_private::DataExtractor &data,
                           llvm::MachO::fat_header &header,
-                          std::vector<llvm::MachO::fat_arch> &fat_archs);
+                          std::vector<FatArch> &fat_archs);
 };
 
 #endif // LLDB_SOURCE_PLUGINS_OBJECTCONTAINER_UNIVERSAL_MACH_O_OBJECTCONTAINERUNIVERSALMACHO_H
Index: lldb/source/Plugins/ObjectContainer/Universal-Mach-O/ObjectContainerUniversalMachO.cpp
===================================================================
--- lldb/source/Plugins/ObjectContainer/Universal-Mach-O/ObjectContainerUniversalMachO.cpp
+++ lldb/source/Plugins/ObjectContainer/Universal-Mach-O/ObjectContainerUniversalMachO.cpp
@@ -57,7 +57,8 @@
 bool ObjectContainerUniversalMachO::MagicBytesMatch(const DataExtractor &data) {
   lldb::offset_t offset = 0;
   uint32_t magic = data.GetU32(&offset);
-  return magic == FAT_MAGIC || magic == FAT_CIGAM;
+  return magic == FAT_MAGIC || magic == FAT_CIGAM || magic == FAT_MAGIC_64 ||
+         magic == FAT_CIGAM_64;
 }
 
 ObjectContainerUniversalMachO::ObjectContainerUniversalMachO(
@@ -82,38 +83,51 @@
 
 bool ObjectContainerUniversalMachO::ParseHeader(
     lldb_private::DataExtractor &data, llvm::MachO::fat_header &header,
-    std::vector<llvm::MachO::fat_arch> &fat_archs) {
-  bool success = false;
+    std::vector<FatArch> &fat_archs) {
   // Store the file offset for this universal file as we could have a universal
   // .o file in a BSD archive, or be contained in another kind of object.
-  // Universal mach-o files always have their headers in big endian.
   lldb::offset_t offset = 0;
   data.SetByteOrder(eByteOrderBig);
   header.magic = data.GetU32(&offset);
   fat_archs.clear();
 
-  if (header.magic == FAT_MAGIC) {
-
-    data.SetAddressByteSize(4);
+  // Universal mach-o files always have their headers in big endian.
+  if (header.magic == FAT_MAGIC || header.magic == FAT_MAGIC_64) {
+    const bool is_fat64 = header.magic == FAT_MAGIC_64;
+    data.SetAddressByteSize(is_fat64 ? 8 : 4);
 
     header.nfat_arch = data.GetU32(&offset);
 
     // Now we should have enough data for all of the fat headers, so lets index
     // them so we know how many architectures that this universal binary
     // contains.
-    uint32_t arch_idx = 0;
-    for (arch_idx = 0; arch_idx < header.nfat_arch; ++arch_idx) {
+    for (uint32_t arch_idx = 0; arch_idx < header.nfat_arch; ++arch_idx) {
       if (data.ValidOffsetForDataOfSize(offset, sizeof(fat_arch))) {
-        fat_arch arch;
-        if (data.GetU32(&offset, &arch, sizeof(fat_arch) / sizeof(uint32_t)))
-          fat_archs.push_back(arch);
+        if (is_fat64) {
+          fat_arch_64 arch;
+          arch.cputype = data.GetU32(&offset);
+          arch.cpusubtype = data.GetU32(&offset);
+          arch.offset = data.GetU64(&offset);
+          arch.size = data.GetU64(&offset);
+          arch.align = data.GetU32(&offset);
+          arch.reserved = data.GetU32(&offset);
+          fat_archs.emplace_back(arch);
+        } else {
+          fat_arch arch;
+          arch.cputype = data.GetU32(&offset);
+          arch.cpusubtype = data.GetU32(&offset);
+          arch.offset = data.GetU32(&offset);
+          arch.size = data.GetU32(&offset);
+          arch.align = data.GetU32(&offset);
+          fat_archs.emplace_back(arch);
+        }
       }
     }
-    success = true;
-  } else {
-    memset(&header, 0, sizeof(header));
+    return true;
   }
-  return success;
+
+  memset(&header, 0, sizeof(header));
+  return true;
 }
 
 size_t ObjectContainerUniversalMachO::GetNumArchitectures() const {
@@ -123,8 +137,8 @@
 bool ObjectContainerUniversalMachO::GetArchitectureAtIndex(
     uint32_t idx, ArchSpec &arch) const {
   if (idx < m_header.nfat_arch) {
-    arch.SetArchitecture(eArchTypeMachO, m_fat_archs[idx].cputype,
-                         m_fat_archs[idx].cpusubtype);
+    arch.SetArchitecture(eArchTypeMachO, m_fat_archs[idx].GetCPUType(),
+                         m_fat_archs[idx].GetCPUSubType());
     return true;
   }
   return false;
@@ -166,8 +180,8 @@
       DataBufferSP data_sp;
       lldb::offset_t data_offset = 0;
       return ObjectFile::FindPlugin(
-          module_sp, file, m_offset + m_fat_archs[arch_idx].offset,
-          m_fat_archs[arch_idx].size, data_sp, data_offset);
+          module_sp, file, m_offset + m_fat_archs[arch_idx].GetOffset(),
+          m_fat_archs[arch_idx].GetSize(), data_sp, data_offset);
     }
   }
   return ObjectFileSP();
@@ -184,11 +198,12 @@
 
   if (ObjectContainerUniversalMachO::MagicBytesMatch(data)) {
     llvm::MachO::fat_header header;
-    std::vector<llvm::MachO::fat_arch> fat_archs;
+    std::vector<FatArch> fat_archs;
     if (ParseHeader(data, header, fat_archs)) {
-      for (const llvm::MachO::fat_arch &fat_arch : fat_archs) {
-        const lldb::offset_t slice_file_offset = fat_arch.offset + file_offset;
-        if (fat_arch.offset < file_size && file_size > slice_file_offset) {
+      for (const FatArch &fat_arch : fat_archs) {
+        const lldb::offset_t slice_file_offset =
+            fat_arch.GetOffset() + file_offset;
+        if (fat_arch.GetOffset() < file_size && file_size > slice_file_offset) {
           ObjectFile::GetModuleSpecifications(
               file, slice_file_offset, file_size - slice_file_offset, specs);
         }
Index: lldb/packages/Python/lldbsuite/test/make/Makefile.rules
===================================================================
--- lldb/packages/Python/lldbsuite/test/make/Makefile.rules
+++ lldb/packages/Python/lldbsuite/test/make/Makefile.rules
@@ -153,7 +153,7 @@
 #----------------------------------------------------------------------
 ifeq "$(OS)" "Darwin"
 	DS := $(DSYMUTIL)
-	DSFLAGS =
+	DSFLAGS := $(DSFLAGS_EXTRAS)
 	DSYM = $(EXE).dSYM
 	AR := $(CROSS_COMPILE)libtool
 	ARFLAGS := -static -o
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to