[Lldb-commits] [lldb] fda53ad - [lldb] Support Universal Mach-O binaries with a fat64 header

Jonas Devlieghere via lldb-commits lldb-commits at lists.llvm.org
Tue Mar 28 15:46:34 PDT 2023


Author: Jonas Devlieghere
Date: 2023-03-28T15:46:26-07:00
New Revision: fda53ad9374b60fc83f1a6065ae3e7985182a5d2

URL: https://github.com/llvm/llvm-project/commit/fda53ad9374b60fc83f1a6065ae3e7985182a5d2
DIFF: https://github.com/llvm/llvm-project/commit/fda53ad9374b60fc83f1a6065ae3e7985182a5d2.diff

LOG: [lldb] Support Universal Mach-O binaries with a fat64 header

Support universal Mach-O binaries with a fat64 header. After
4d683f7fa7d4, dsymutil can now generate such binaries when the offsets
would otherwise overflow the 32-bit offsets in the regular fat header.

rdar://107289570

Differential revision: https://reviews.llvm.org/D147012

Added: 
    lldb/test/API/macosx/universal64/Makefile
    lldb/test/API/macosx/universal64/TestUniversal64.py
    lldb/test/API/macosx/universal64/main.c

Modified: 
    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

Removed: 
    


################################################################################
diff  --git a/lldb/packages/Python/lldbsuite/test/make/Makefile.rules b/lldb/packages/Python/lldbsuite/test/make/Makefile.rules
index 4c225ed360be5..bfd249ccd43f2 100644
--- a/lldb/packages/Python/lldbsuite/test/make/Makefile.rules
+++ b/lldb/packages/Python/lldbsuite/test/make/Makefile.rules
@@ -153,7 +153,7 @@ ARCHFLAG ?= -arch
 #----------------------------------------------------------------------
 ifeq "$(OS)" "Darwin"
 	DS := $(DSYMUTIL)
-	DSFLAGS =
+	DSFLAGS := $(DSFLAGS_EXTRAS)
 	DSYM = $(EXE).dSYM
 	AR := $(CROSS_COMPILE)libtool
 	ARFLAGS := -static -o

diff  --git a/lldb/source/Plugins/ObjectContainer/Universal-Mach-O/ObjectContainerUniversalMachO.cpp b/lldb/source/Plugins/ObjectContainer/Universal-Mach-O/ObjectContainerUniversalMachO.cpp
index 78e0a4b2f499f..9af9c0120dd7d 100644
--- a/lldb/source/Plugins/ObjectContainer/Universal-Mach-O/ObjectContainerUniversalMachO.cpp
+++ b/lldb/source/Plugins/ObjectContainer/Universal-Mach-O/ObjectContainerUniversalMachO.cpp
@@ -57,7 +57,8 @@ ObjectContainer *ObjectContainerUniversalMachO::CreateInstance(
 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() {
 
 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 @@ size_t ObjectContainerUniversalMachO::GetNumArchitectures() const {
 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 @@ ObjectContainerUniversalMachO::GetObjectFile(const FileSpec *file) {
       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 @@ size_t ObjectContainerUniversalMachO::GetModuleSpecifications(
 
   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);
         }

diff  --git a/lldb/source/Plugins/ObjectContainer/Universal-Mach-O/ObjectContainerUniversalMachO.h b/lldb/source/Plugins/ObjectContainer/Universal-Mach-O/ObjectContainerUniversalMachO.h
index 4fbea936ac85c..20f1f051e07a0 100644
--- a/lldb/source/Plugins/ObjectContainer/Universal-Mach-O/ObjectContainerUniversalMachO.h
+++ b/lldb/source/Plugins/ObjectContainer/Universal-Mach-O/ObjectContainerUniversalMachO.h
@@ -63,11 +63,46 @@ class ObjectContainerUniversalMachO : public lldb_private::ObjectContainer {
 
 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

diff  --git a/lldb/test/API/macosx/universal64/Makefile b/lldb/test/API/macosx/universal64/Makefile
new file mode 100644
index 0000000000000..f763f3ae2f6c9
--- /dev/null
+++ b/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 $@ $<

diff  --git a/lldb/test/API/macosx/universal64/TestUniversal64.py b/lldb/test/API/macosx/universal64/TestUniversal64.py
new file mode 100644
index 0000000000000..0c4226fac5380
--- /dev/null
+++ b/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()

diff  --git a/lldb/test/API/macosx/universal64/main.c b/lldb/test/API/macosx/universal64/main.c
new file mode 100644
index 0000000000000..5124e0afbfc19
--- /dev/null
+++ b/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(); }


        


More information about the lldb-commits mailing list