Places calling LoadModuleAtAddress() already call ModulesDidLoad() after a loop calling LoadModuleAtAddress(), so it's not necessary to call it from there, and the batched ModulesDidLoad() may be more efficient than this place calling it one after one. This also makes the ModuleLoadedNotifys test pass on Linux now that the duplicates no longer bring down the average of modules notified per call. Differential Revision: https://reviews.llvm.org/D123128
118 lines
5.0 KiB
Python
118 lines
5.0 KiB
Python
"""
|
|
Test how many times newly loaded binaries are notified;
|
|
they should be delivered in batches instead of one-by-one.
|
|
"""
|
|
|
|
from __future__ import print_function
|
|
|
|
|
|
import lldb
|
|
from lldbsuite.test.decorators import *
|
|
from lldbsuite.test.lldbtest import *
|
|
from lldbsuite.test import lldbutil
|
|
|
|
class ModuleLoadedNotifysTestCase(TestBase):
|
|
|
|
mydir = TestBase.compute_mydir(__file__)
|
|
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 test_launch_notifications(self):
|
|
"""Test that lldb broadcasts newly loaded libraries in batches."""
|
|
self.build()
|
|
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)
|
|
|
|
# Create a target by the debugger.
|
|
target = self.dbg.CreateTarget(exe)
|
|
self.assertTrue(target, VALID_TARGET)
|
|
|
|
# break on main
|
|
breakpoint = target.BreakpointCreateByName('main', 'a.out')
|
|
|
|
event = lldb.SBEvent()
|
|
# CreateTarget() generated modules-loaded events; consume them & toss
|
|
while listener.GetNextEvent(event):
|
|
True
|
|
|
|
error = lldb.SBError()
|
|
flags = target.GetLaunchInfo().GetLaunchFlags()
|
|
process = target.Launch(listener,
|
|
None, # argv
|
|
None, # envp
|
|
None, # stdin_path
|
|
None, # stdout_path
|
|
None, # stderr_path
|
|
None, # working directory
|
|
flags, # launch flags
|
|
False, # Stop at entry
|
|
error) # 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 = []
|
|
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 = []
|
|
i = 0
|
|
while i < solib_count:
|
|
module = lldb.SBTarget.GetModuleAtIndexFromEvent(i, event)
|
|
self.assertTrue(module not in already_loaded_modules)
|
|
already_loaded_modules.append(module)
|
|
if self.TraceOn():
|
|
added_files.append(module.GetFileSpec().GetFilename())
|
|
i = i + 1
|
|
if self.TraceOn():
|
|
# print all of the binaries that have been added
|
|
print("Loaded files: %s" % (', '.join(added_files)))
|
|
|
|
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():
|
|
# print all of the binaries that have been removed
|
|
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)))
|
|
|
|
|
|
# This is testing that we get back a small number of events with the loaded
|
|
# 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))
|
|
self.assertGreater(avg_solibs_added_per_event, 1)
|