Skip to content

Commit ace14ca

Browse files
authored
Merge pull request #6546 from apple/🍒/navy/fda53ad9374b
[lldb] Support Universal Mach-O binaries with a fat64 header
2 parents 9bd3727 + 6702301 commit ace14ca

File tree

6 files changed

+145
-27
lines changed

6 files changed

+145
-27
lines changed

lldb/packages/Python/lldbsuite/test/make/Makefile.rules

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ ARCHFLAG ?= -arch
183183
#----------------------------------------------------------------------
184184
ifeq "$(OS)" "Darwin"
185185
DS := $(DSYMUTIL)
186-
DSFLAGS =
186+
DSFLAGS := $(DSFLAGS_EXTRAS)
187187
DSYM = $(EXE).dSYM
188188
AR := $(CROSS_COMPILE)libtool
189189
ARFLAGS := -static -o

lldb/source/Plugins/ObjectContainer/Universal-Mach-O/ObjectContainerUniversalMachO.cpp

Lines changed: 39 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,8 @@ ObjectContainer *ObjectContainerUniversalMachO::CreateInstance(
5757
bool ObjectContainerUniversalMachO::MagicBytesMatch(const DataExtractor &data) {
5858
lldb::offset_t offset = 0;
5959
uint32_t magic = data.GetU32(&offset);
60-
return magic == FAT_MAGIC || magic == FAT_CIGAM;
60+
return magic == FAT_MAGIC || magic == FAT_CIGAM || magic == FAT_MAGIC_64 ||
61+
magic == FAT_CIGAM_64;
6162
}
6263

6364
ObjectContainerUniversalMachO::ObjectContainerUniversalMachO(
@@ -82,38 +83,51 @@ bool ObjectContainerUniversalMachO::ParseHeader() {
8283

8384
bool ObjectContainerUniversalMachO::ParseHeader(
8485
lldb_private::DataExtractor &data, llvm::MachO::fat_header &header,
85-
std::vector<llvm::MachO::fat_arch> &fat_archs) {
86-
bool success = false;
86+
std::vector<FatArch> &fat_archs) {
8787
// Store the file offset for this universal file as we could have a universal
8888
// .o file in a BSD archive, or be contained in another kind of object.
89-
// Universal mach-o files always have their headers in big endian.
9089
lldb::offset_t offset = 0;
9190
data.SetByteOrder(eByteOrderBig);
9291
header.magic = data.GetU32(&offset);
9392
fat_archs.clear();
9493

95-
if (header.magic == FAT_MAGIC) {
96-
97-
data.SetAddressByteSize(4);
94+
// Universal mach-o files always have their headers in big endian.
95+
if (header.magic == FAT_MAGIC || header.magic == FAT_MAGIC_64) {
96+
const bool is_fat64 = header.magic == FAT_MAGIC_64;
97+
data.SetAddressByteSize(is_fat64 ? 8 : 4);
9898

9999
header.nfat_arch = data.GetU32(&offset);
100100

101101
// Now we should have enough data for all of the fat headers, so lets index
102102
// them so we know how many architectures that this universal binary
103103
// contains.
104-
uint32_t arch_idx = 0;
105-
for (arch_idx = 0; arch_idx < header.nfat_arch; ++arch_idx) {
104+
for (uint32_t arch_idx = 0; arch_idx < header.nfat_arch; ++arch_idx) {
106105
if (data.ValidOffsetForDataOfSize(offset, sizeof(fat_arch))) {
107-
fat_arch arch;
108-
if (data.GetU32(&offset, &arch, sizeof(fat_arch) / sizeof(uint32_t)))
109-
fat_archs.push_back(arch);
106+
if (is_fat64) {
107+
fat_arch_64 arch;
108+
arch.cputype = data.GetU32(&offset);
109+
arch.cpusubtype = data.GetU32(&offset);
110+
arch.offset = data.GetU64(&offset);
111+
arch.size = data.GetU64(&offset);
112+
arch.align = data.GetU32(&offset);
113+
arch.reserved = data.GetU32(&offset);
114+
fat_archs.emplace_back(arch);
115+
} else {
116+
fat_arch arch;
117+
arch.cputype = data.GetU32(&offset);
118+
arch.cpusubtype = data.GetU32(&offset);
119+
arch.offset = data.GetU32(&offset);
120+
arch.size = data.GetU32(&offset);
121+
arch.align = data.GetU32(&offset);
122+
fat_archs.emplace_back(arch);
123+
}
110124
}
111125
}
112-
success = true;
113-
} else {
114-
memset(&header, 0, sizeof(header));
126+
return true;
115127
}
116-
return success;
128+
129+
memset(&header, 0, sizeof(header));
130+
return true;
117131
}
118132

119133
size_t ObjectContainerUniversalMachO::GetNumArchitectures() const {
@@ -123,8 +137,8 @@ size_t ObjectContainerUniversalMachO::GetNumArchitectures() const {
123137
bool ObjectContainerUniversalMachO::GetArchitectureAtIndex(
124138
uint32_t idx, ArchSpec &arch) const {
125139
if (idx < m_header.nfat_arch) {
126-
arch.SetArchitecture(eArchTypeMachO, m_fat_archs[idx].cputype,
127-
m_fat_archs[idx].cpusubtype);
140+
arch.SetArchitecture(eArchTypeMachO, m_fat_archs[idx].GetCPUType(),
141+
m_fat_archs[idx].GetCPUSubType());
128142
return true;
129143
}
130144
return false;
@@ -166,8 +180,8 @@ ObjectContainerUniversalMachO::GetObjectFile(const FileSpec *file) {
166180
DataBufferSP data_sp;
167181
lldb::offset_t data_offset = 0;
168182
return ObjectFile::FindPlugin(
169-
module_sp, file, m_offset + m_fat_archs[arch_idx].offset,
170-
m_fat_archs[arch_idx].size, data_sp, data_offset);
183+
module_sp, file, m_offset + m_fat_archs[arch_idx].GetOffset(),
184+
m_fat_archs[arch_idx].GetSize(), data_sp, data_offset);
171185
}
172186
}
173187
return ObjectFileSP();
@@ -184,11 +198,12 @@ size_t ObjectContainerUniversalMachO::GetModuleSpecifications(
184198

185199
if (ObjectContainerUniversalMachO::MagicBytesMatch(data)) {
186200
llvm::MachO::fat_header header;
187-
std::vector<llvm::MachO::fat_arch> fat_archs;
201+
std::vector<FatArch> fat_archs;
188202
if (ParseHeader(data, header, fat_archs)) {
189-
for (const llvm::MachO::fat_arch &fat_arch : fat_archs) {
190-
const lldb::offset_t slice_file_offset = fat_arch.offset + file_offset;
191-
if (fat_arch.offset < file_size && file_size > slice_file_offset) {
203+
for (const FatArch &fat_arch : fat_archs) {
204+
const lldb::offset_t slice_file_offset =
205+
fat_arch.GetOffset() + file_offset;
206+
if (fat_arch.GetOffset() < file_size && file_size > slice_file_offset) {
192207
ObjectFile::GetModuleSpecifications(
193208
file, slice_file_offset, file_size - slice_file_offset, specs);
194209
}

lldb/source/Plugins/ObjectContainer/Universal-Mach-O/ObjectContainerUniversalMachO.h

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,11 +63,46 @@ class ObjectContainerUniversalMachO : public lldb_private::ObjectContainer {
6363

6464
protected:
6565
llvm::MachO::fat_header m_header;
66-
std::vector<llvm::MachO::fat_arch> m_fat_archs;
66+
67+
struct FatArch {
68+
FatArch(llvm::MachO::fat_arch arch) : m_arch(arch), m_is_fat64(false) {}
69+
FatArch(llvm::MachO::fat_arch_64 arch) : m_arch(arch), m_is_fat64(true) {}
70+
71+
uint32_t GetCPUType() const {
72+
return m_is_fat64 ? m_arch.fat_arch_64.cputype : m_arch.fat_arch.cputype;
73+
}
74+
75+
uint32_t GetCPUSubType() const {
76+
return m_is_fat64 ? m_arch.fat_arch_64.cpusubtype
77+
: m_arch.fat_arch.cpusubtype;
78+
}
79+
80+
uint64_t GetOffset() const {
81+
return m_is_fat64 ? m_arch.fat_arch_64.offset : m_arch.fat_arch.offset;
82+
}
83+
84+
uint64_t GetSize() const {
85+
return m_is_fat64 ? m_arch.fat_arch_64.size : m_arch.fat_arch.size;
86+
}
87+
88+
uint32_t GetAlign() const {
89+
return m_is_fat64 ? m_arch.fat_arch_64.align : m_arch.fat_arch.align;
90+
}
91+
92+
private:
93+
const union Arch {
94+
Arch(llvm::MachO::fat_arch arch) : fat_arch(arch) {}
95+
Arch(llvm::MachO::fat_arch_64 arch) : fat_arch_64(arch) {}
96+
llvm::MachO::fat_arch fat_arch;
97+
llvm::MachO::fat_arch_64 fat_arch_64;
98+
} m_arch;
99+
const bool m_is_fat64;
100+
};
101+
std::vector<FatArch> m_fat_archs;
67102

68103
static bool ParseHeader(lldb_private::DataExtractor &data,
69104
llvm::MachO::fat_header &header,
70-
std::vector<llvm::MachO::fat_arch> &fat_archs);
105+
std::vector<FatArch> &fat_archs);
71106
};
72107

73108
#endif // LLDB_SOURCE_PLUGINS_OBJECTCONTAINER_UNIVERSAL_MACH_O_OBJECTCONTAINERUNIVERSALMACHO_H
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
EXE := fat.out
2+
3+
ifdef FAT64_DSYM
4+
DSFLAGS_EXTRAS=-fat64
5+
endif
6+
7+
include Makefile.rules
8+
9+
all: fat.out
10+
11+
fat.out: fat.arm64.out fat.x86_64.out
12+
lipo -fat64 -create -o $@ $^
13+
14+
fat.x86_64.out: fat.x86_64.o
15+
$(CC) -isysroot $(SDKROOT) -target x86_64-apple-macosx10.9 -o $@ $<
16+
17+
fat.arm64.out: fat.arm64.o
18+
$(CC) -isysroot $(SDKROOT) -target arm64-apple-macosx10.9 -o $@ $<
19+
20+
fat.x86_64.o: main.c
21+
$(CC) -isysroot $(SDKROOT) -g -O0 -target x86_64-apple-macosx11 -c -o $@ $<
22+
23+
fat.arm64.o: main.c
24+
$(CC) -isysroot $(SDKROOT) -g -O0 -target arm64-apple-macosx11 -c -o $@ $<
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
from lldbsuite.test.decorators import *
2+
from lldbsuite.test.lldbtest import *
3+
from lldbsuite.test import lldbutil
4+
5+
6+
class Universal64TestCase(TestBase):
7+
NO_DEBUG_INFO_TESTCASE = True
8+
9+
def do_test(self):
10+
# Get the executable.
11+
exe = self.getBuildArtifact("fat.out")
12+
13+
# Create a target.
14+
self.target = self.dbg.CreateTarget(exe)
15+
16+
# Create a breakpoint on main.
17+
main_bp = self.target.BreakpointCreateByName("main")
18+
self.assertTrue(main_bp, VALID_BREAKPOINT)
19+
20+
# Make sure the binary and the dSYM are in the image list.
21+
self.expect("image list ", patterns=['fat.out', 'fat.out.dSYM'])
22+
23+
# The dynamic loader doesn't support fat64 executables so we can't
24+
# actually launch them here.
25+
26+
@skipUnlessDarwin
27+
@skipIfDarwinEmbedded
28+
def test_universal64_executable(self):
29+
"""Test fat64 universal executable"""
30+
self.build(debug_info="dsym")
31+
self.do_test()
32+
33+
@skipUnlessDarwin
34+
@skipIfDarwinEmbedded
35+
@skipIf(compiler="clang", compiler_version=['<', '7.0'])
36+
def test_universal64_dsym(self):
37+
"""Test fat64 universal dSYM"""
38+
self.build(debug_info="dsym", dictionary={'FAT64_DSYM': '1'})
39+
self.do_test()
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#include <stdio.h>
2+
3+
int foo() { return 0; }
4+
5+
int main(int argc, char **argv) { return foo(); }

0 commit comments

Comments
 (0)