diff --git a/lldb/packages/Python/lldbsuite/test/make/Makefile.rules b/lldb/packages/Python/lldbsuite/test/make/Makefile.rules --- a/lldb/packages/Python/lldbsuite/test/make/Makefile.rules +++ b/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 diff --git a/lldb/source/Plugins/ObjectContainer/Universal-Mach-O/ObjectContainerUniversalMachO.h b/lldb/source/Plugins/ObjectContainer/Universal-Mach-O/ObjectContainerUniversalMachO.h --- a/lldb/source/Plugins/ObjectContainer/Universal-Mach-O/ObjectContainerUniversalMachO.h +++ b/lldb/source/Plugins/ObjectContainer/Universal-Mach-O/ObjectContainerUniversalMachO.h @@ -63,11 +63,46 @@ protected: llvm::MachO::fat_header m_header; - std::vector 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 m_fat_archs; static bool ParseHeader(lldb_private::DataExtractor &data, llvm::MachO::fat_header &header, - std::vector &fat_archs); + std::vector &fat_archs); }; #endif // LLDB_SOURCE_PLUGINS_OBJECTCONTAINER_UNIVERSAL_MACH_O_OBJECTCONTAINERUNIVERSALMACHO_H diff --git a/lldb/source/Plugins/ObjectContainer/Universal-Mach-O/ObjectContainerUniversalMachO.cpp b/lldb/source/Plugins/ObjectContainer/Universal-Mach-O/ObjectContainerUniversalMachO.cpp --- a/lldb/source/Plugins/ObjectContainer/Universal-Mach-O/ObjectContainerUniversalMachO.cpp +++ b/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 &fat_archs) { - bool success = false; + std::vector &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 fat_archs; + std::vector 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/test/API/macosx/universal64/Makefile b/lldb/test/API/macosx/universal64/Makefile new file mode 100644 --- /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 --- /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 --- /dev/null +++ b/lldb/test/API/macosx/universal64/main.c @@ -0,0 +1,5 @@ +#include + +int foo() { return 0; } + +int main(int argc, char **argv) { return foo(); }