"""
Test how many times newly loaded binaries are notified;
they should be delivered in batches instead of one-by-one.
"""
import lldb
from lldbsuite.test.decorators import *
from lldbsuite.test.lldbtest import *
from lldbsuite.test import lldbutil
@skipUnlessPlatform(["linux"] + lldbplatformutil.getDarwinOSTriples())
class ModuleLoadedNotifysTestCase(TestBase):
NO_DEBUG_INFO_TESTCASE = True
def setUp(self):
TestBase.setUp(self)
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."""
expected_solibs = [
"lib_a." + self.platformContext.shlib_extension,
"lib_b." + self.platformContext.shlib_extension,
"lib_c." + self.platformContext.shlib_extension,
"lib_d." + self.platformContext.shlib_extension,
]
self.build()
self.setup_test(expected_solibs)
exe = self.getBuildArtifact("a.out")
self.dbg.SetAsync(False)
listener = self.dbg.GetListener()
listener.StartListeningForEventClass(
self.dbg,
lldb.SBTarget.GetBroadcasterClassName(),
lldb.SBTarget.eBroadcastBitModulesLoaded
| lldb.SBTarget.eBroadcastBitModulesUnloaded,
)
target = self.dbg.CreateTarget(exe)
self.assertTrue(target, VALID_TARGET)
breakpoint = target.BreakpointCreateByName("main", "a.out")
event = lldb.SBEvent()
while listener.GetNextEvent(event):
True
error = lldb.SBError()
flags = target.GetLaunchInfo().GetLaunchFlags()
process = target.Launch(
listener,
None,
None,
None,
None,
None,
None,
flags,
False,
error,
)
self.assertEqual(process.GetState(), lldb.eStateStopped, PROCESS_STOPPED)
total_solibs_added = 0
total_solibs_removed = 0
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:
solib_count = lldb.SBTarget.GetNumModulesFromEvent(event)
total_modules_added_events += 1
total_solibs_added += solib_count
added_files = []
for i in range(solib_count):
module = lldb.SBTarget.GetModuleAtIndexFromEvent(i, event)
exe_basename = lldb.SBFileSpec(exe).basename
if module.file.basename not in ["dyld", exe_basename]:
self.assertNotIn(
module,
already_loaded_modules,
"{} is already loaded".format(module),
)
already_loaded_modules.append(module)
added_files.append(module.GetFileSpec().GetFilename())
if self.TraceOn():
print("Loaded files: %s" % (", ".join(added_files)))
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
total_solibs_removed += solib_count
if self.TraceOn():
removed_files = []
i = 0
while i < solib_count:
module = lldb.SBTarget.GetModuleAtIndexFromEvent(i, event)
removed_files.append(module.GetFileSpec().GetFilename())
i = i + 1
print("Unloaded files: %s" % (", ".join(removed_files)))
self.assertLessEqual(set(expected_solibs), set(max_solib_chunk_per_event))