Skip to content

Commit d3134b9

Browse files
jasonmolendaLukacma
authored andcommitted
[lldb] NFC add comments and test case for ObjectFileMachO delay-init (llvm#95067)
Add comments and a test for delay-init libraries on macOS. I originally added the support in 954d00e a month ago, but without these additional clarifications. rdar://126885033
1 parent 7707a5e commit d3134b9

File tree

5 files changed

+91
-0
lines changed

5 files changed

+91
-0
lines changed

lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5140,12 +5140,20 @@ uint32_t ObjectFileMachO::GetDependentModules(FileSpecList &files) {
51405140
case LC_LOADFVMLIB:
51415141
case LC_LOAD_UPWARD_DYLIB: {
51425142
uint32_t name_offset = cmd_offset + m_data.GetU32(&offset);
5143+
// For LC_LOAD_DYLIB there is an alternate encoding
5144+
// which adds a uint32_t `flags` field for `DYLD_USE_*`
5145+
// flags. This can be detected by a timestamp field with
5146+
// the `DYLIB_USE_MARKER` constant value.
51435147
bool is_delayed_init = false;
51445148
uint32_t use_command_marker = m_data.GetU32(&offset);
51455149
if (use_command_marker == 0x1a741800 /* DYLIB_USE_MARKER */) {
51465150
offset += 4; /* uint32_t current_version */
51475151
offset += 4; /* uint32_t compat_version */
51485152
uint32_t flags = m_data.GetU32(&offset);
5153+
// If this LC_LOAD_DYLIB is marked delay-init,
5154+
// don't report it as a dependent library -- it
5155+
// may be loaded in the process at some point,
5156+
// but will most likely not be load at launch.
51495157
if (flags & 0x08 /* DYLIB_USE_DELAYED_INIT */)
51505158
is_delayed_init = true;
51515159
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
C_SOURCES := main.c
2+
LD_EXTRAS := -L. -Wl,-delay_library,libfoo.dylib
3+
4+
.PHONY: build-libfoo
5+
all: build-libfoo a.out
6+
7+
include Makefile.rules
8+
9+
build-libfoo: foo.c
10+
$(MAKE) -f $(MAKEFILE_RULES) \
11+
DYLIB_C_SOURCES=foo.c DYLIB_NAME=foo DYLIB_ONLY=YES
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
"""Test binaries with delay-init dependencies."""
2+
3+
import subprocess
4+
import lldb
5+
from lldbsuite.test.decorators import *
6+
from lldbsuite.test.lldbtest import *
7+
from lldbsuite.test import lldbutil
8+
9+
10+
class TestDelayInitDependencies(TestBase):
11+
NO_DEBUG_INFO_TESTCASE = True
12+
13+
@skipUnlessDarwin
14+
def test_delay_init_dependency(self):
15+
TestBase.setUp(self)
16+
out = subprocess.run(
17+
["xcrun", "ld", "-delay_library"],
18+
universal_newlines=True,
19+
stdout=subprocess.PIPE,
20+
stderr=subprocess.PIPE,
21+
)
22+
if "delay_library missing" not in out.stderr:
23+
self.skipTest(
24+
"Skipped because the linker doesn't know about -delay_library"
25+
)
26+
self.build()
27+
main_source = "main.c"
28+
exe = self.getBuildArtifact("a.out")
29+
lib = self.getBuildArtifact("libfoo.dylib")
30+
31+
target = self.dbg.CreateTarget(exe)
32+
self.assertTrue(target, VALID_TARGET)
33+
34+
# libfoo.dylib should not be in the target pre-execution
35+
for m in target.modules:
36+
self.assertNotEqual(m.GetFileSpec().GetFilename(), "libfoo.dylib")
37+
38+
# This run without arguments will not load libfoo.dylib
39+
li = lldb.SBLaunchInfo([])
40+
li.SetWorkingDirectory(self.getBuildDir())
41+
(target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(
42+
self, "// break here", lldb.SBFileSpec("main.c"), li
43+
)
44+
for m in target.modules:
45+
self.assertNotEqual(m.GetFileSpec().GetFilename(), "libfoo.dylib")
46+
47+
process.Kill()
48+
self.dbg.DeleteTarget(target)
49+
50+
# This run with one argument will load libfoo.dylib
51+
li = lldb.SBLaunchInfo([])
52+
li.SetWorkingDirectory(self.getBuildDir())
53+
li.SetArguments(["one-argument"], True)
54+
(target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(
55+
self, "// break here", lldb.SBFileSpec("main.c"), li
56+
)
57+
58+
found_libfoo = False
59+
for m in target.modules:
60+
if m.GetFileSpec().GetFilename() == "libfoo.dylib":
61+
found_libfoo = True
62+
self.assertTrue(found_libfoo)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
int foo() { return 5; }
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
int foo();
2+
int main(int argc, char **argv) {
3+
int retval = 0;
4+
// Only call foo() if one argument is passed
5+
if (argc == 2)
6+
retval = foo();
7+
8+
return retval; // break here
9+
}

0 commit comments

Comments
 (0)