Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,3 +1,23 @@
CXX_SOURCES := main.cpp

include Makefile.rules
CXX_SOURCES := main.cpp
LD_EXTRAS := -L. -lloadunload_d -lloadunload_c -lloadunload_a -lloadunload_b
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please rename the modules to something else (even a simple liba is probably fine).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.


a.out: lib_b lib_a lib_c lib_d

include Makefile.rules

lib_a: lib_b
$(MAKE) -f $(MAKEFILE_RULES) \
DYLIB_ONLY=YES DYLIB_CXX_SOURCES=a.cpp DYLIB_NAME=loadunload_a \
LD_EXTRAS="-L. -lloadunload_b"

lib_b:
$(MAKE) -f $(MAKEFILE_RULES) \
DYLIB_ONLY=YES DYLIB_CXX_SOURCES=b.cpp DYLIB_NAME=loadunload_b

lib_c:
$(MAKE) -f $(MAKEFILE_RULES) \
DYLIB_ONLY=YES DYLIB_CXX_SOURCES=c.cpp DYLIB_NAME=loadunload_c

lib_d:
$(MAKE) -f $(MAKEFILE_RULES) \
DYLIB_ONLY=YES DYLIB_CXX_SOURCES=d.cpp DYLIB_NAME=loadunload_d
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,51 @@
from lldbsuite.test import lldbutil


@skipUnlessPlatform(["linux"] + lldbplatformutil.getDarwinOSTriples())
class ModuleLoadedNotifysTestCase(TestBase):
NO_DEBUG_INFO_TESTCASE = True

# At least DynamicLoaderDarwin and DynamicLoaderPOSIXDYLD should batch up
# notifications about newly added/removed libraries. Other DynamicLoaders may
# not be written this way.
@skipUnlessPlatform(["linux"] + lldbplatformutil.getDarwinOSTriples())
def setUp(self):
# Call super's setUp().
TestBase.setUp(self)
# Find the line number to break inside main().
self.line = line_number("main.cpp", "// breakpoint")

def setup_test(self, solibs):
if lldb.remote_platform:
path = lldb.remote_platform.GetWorkingDirectory()
for f in solibs:
lldbutil.install_to_target(self, self.getBuildArtifact(f))
else:
path = self.getBuildDir()
if self.dylibPath in os.environ:
sep = self.platformContext.shlib_path_separator
path = os.environ[self.dylibPath] + sep + path
self.runCmd(
"settings append target.env-vars '{}={}'".format(self.dylibPath, path)
)
self.default_path = path

def test_launch_notifications(self):
"""Test that lldb broadcasts newly loaded libraries in batches."""

ext = "so"
if self.platformIsDarwin():
ext = "dylib"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should be able to get this as self.platformContext.shlib_extension

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.


expected_solibs = [
"libloadunload_a." + ext,
"libloadunload_b." + ext,
"libloadunload_c." + ext,
"libloadunload_d." + ext,
]

self.build()
self.setup_test(expected_solibs)

exe = self.getBuildArtifact("a.out")
self.dbg.SetAsync(False)

Expand Down Expand Up @@ -70,6 +99,8 @@ def test_launch_notifications(self):
total_modules_added_events = 0
total_modules_removed_events = 0
already_loaded_modules = []
max_solibs_per_event = 0
max_solib_chunk_per_event = []
while listener.GetNextEvent(event):
if lldb.SBTarget.EventIsTargetEvent(event):
if event.GetType() == lldb.SBTarget.eBroadcastBitModulesLoaded:
Expand All @@ -91,12 +122,17 @@ def test_launch_notifications(self):
"{} is already loaded".format(module),
)
already_loaded_modules.append(module)
if self.TraceOn():
added_files.append(module.GetFileSpec().GetFilename())
added_files.append(module.GetFileSpec().GetFilename())
if self.TraceOn():
# print all of the binaries that have been added
print("Loaded files: %s" % (", ".join(added_files)))

# We will check the latest biggest chunk of loaded solibs.
# We expect all of our solibs in the last chunk of loaded modules.
if solib_count >= max_solibs_per_event:
max_solib_chunk_per_event = added_files.copy()
max_solibs_per_event = solib_count

if event.GetType() == lldb.SBTarget.eBroadcastBitModulesUnloaded:
solib_count = lldb.SBTarget.GetNumModulesFromEvent(event)
total_modules_removed_events += 1
Expand All @@ -115,9 +151,10 @@ def test_launch_notifications(self):
# binaries in batches. Check that we got back more than 1 solib per event.
# In practice on Darwin today, we get back two events for a do-nothing c
# program: a.out and dyld, and then all the rest of the system libraries.
# On Linux we get events for ld.so, [vdso], the binary and then all libraries.

avg_solibs_added_per_event = round(
float(total_solibs_added) / float(total_modules_added_events)
# On Linux we get events for ld.so, [vdso], the binary and then all libraries,
# but the different configurations could load a different number of .so modules
# per event.
self.assertGreaterEqual(
len(set(max_solib_chunk_per_event).intersection(expected_solibs)),
len(expected_solibs),
Copy link
Collaborator

@labath labath Jun 10, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this could be assertLessEqual(set(expected_solibs), set(max_solib_chunk_per_event)) (with the advantage being that you'd bet a better error message than 3 is not less than 4 when it fails.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

)
self.assertGreater(avg_solibs_added_per_event, 1)
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
extern "C" int b_function();

int a_init() { return 234; }

int a_global = a_init();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just delete all of this stuff, as it's not relevant for what we're testing. (the a_function -> b_function dep is marginally interesting, as it creates a more interesting dependency graph).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.


extern "C" int a_function() { return b_function(); }
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
int b_init() { return 345; }

int b_global = b_init();

extern "C" int b_function() { return 500; }
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
extern "C" int c_function() { return 600; }
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
int d_init() { return 123; }

int d_global = d_init();

extern "C" int d_function() { return 700; }
Original file line number Diff line number Diff line change
@@ -1,6 +1,16 @@
#include <stdio.h>
int main ()
{
puts("running"); // breakpoint here
return 0;
}
#include <stdio.h>

extern "C" int a_function();
extern "C" int c_function();
extern "C" int b_function();
extern "C" int d_function();

int main() {
a_function();
b_function();
c_function();
d_function();

puts("running"); // breakpoint here
return 0;
}