1"""
2Test how many times newly loaded binaries are notified;
3they should be delivered in batches instead of one-by-one.
4"""
5
6from __future__ import print_function
7
8
9import lldb
10from lldbsuite.test.decorators import *
11from lldbsuite.test.lldbtest import *
12from lldbsuite.test import lldbutil
13
14class ModuleLoadedNotifysTestCase(TestBase):
15
16    mydir = TestBase.compute_mydir(__file__)
17    NO_DEBUG_INFO_TESTCASE = True
18
19    # At least DynamicLoaderDarwin and DynamicLoaderPOSIXDYLD should batch up
20    # notifications about newly added/removed libraries.  Other DynamicLoaders may
21    # not be written this way.
22    @skipUnlessPlatform(["linux"]+lldbplatformutil.getDarwinOSTriples())
23
24    def setUp(self):
25        # Call super's setUp().
26        TestBase.setUp(self)
27        # Find the line number to break inside main().
28        self.line = line_number('main.cpp', '// breakpoint')
29
30    def test_launch_notifications(self):
31        """Test that lldb broadcasts newly loaded libraries in batches."""
32        self.build()
33        exe = self.getBuildArtifact("a.out")
34        self.dbg.SetAsync(False)
35
36        listener = self.dbg.GetListener()
37        listener.StartListeningForEventClass(
38            self.dbg,
39            lldb.SBTarget.GetBroadcasterClassName(),
40            lldb.SBTarget.eBroadcastBitModulesLoaded | lldb.SBTarget.eBroadcastBitModulesUnloaded)
41
42        # Create a target by the debugger.
43        target = self.dbg.CreateTarget(exe)
44        self.assertTrue(target, VALID_TARGET)
45
46        # break on main
47        breakpoint = target.BreakpointCreateByName('main', 'a.out')
48
49        event = lldb.SBEvent()
50        # CreateTarget() generated modules-loaded events; consume them & toss
51        while listener.GetNextEvent(event):
52            True
53
54        error = lldb.SBError()
55        flags = target.GetLaunchInfo().GetLaunchFlags()
56        process = target.Launch(listener,
57                                None,      # argv
58                                None,      # envp
59                                None,      # stdin_path
60                                None,      # stdout_path
61                                None,      # stderr_path
62                                None,      # working directory
63                                flags,     # launch flags
64                                False,     # Stop at entry
65                                error)     # error
66
67        self.assertEqual(
68            process.GetState(), lldb.eStateStopped,
69            PROCESS_STOPPED)
70
71        total_solibs_added = 0
72        total_solibs_removed = 0
73        total_modules_added_events = 0
74        total_modules_removed_events = 0
75        already_loaded_modules = []
76        while listener.GetNextEvent(event):
77            if lldb.SBTarget.EventIsTargetEvent(event):
78                if event.GetType() == lldb.SBTarget.eBroadcastBitModulesLoaded:
79                    solib_count = lldb.SBTarget.GetNumModulesFromEvent(event)
80                    total_modules_added_events += 1
81                    total_solibs_added += solib_count
82                    added_files = []
83                    i = 0
84                    while i < solib_count:
85                        module = lldb.SBTarget.GetModuleAtIndexFromEvent(i, event)
86                        self.assertTrue(module not in already_loaded_modules)
87                        already_loaded_modules.append(module)
88                        if self.TraceOn():
89                            added_files.append(module.GetFileSpec().GetFilename())
90                        i = i + 1
91                    if self.TraceOn():
92                        # print all of the binaries that have been added
93                        print("Loaded files: %s" % (', '.join(added_files)))
94
95                if event.GetType() == lldb.SBTarget.eBroadcastBitModulesUnloaded:
96                    solib_count = lldb.SBTarget.GetNumModulesFromEvent(event)
97                    total_modules_removed_events += 1
98                    total_solibs_removed += solib_count
99                    if self.TraceOn():
100                        # print all of the binaries that have been removed
101                        removed_files = []
102                        i = 0
103                        while i < solib_count:
104                            module = lldb.SBTarget.GetModuleAtIndexFromEvent(i, event)
105                            removed_files.append(module.GetFileSpec().GetFilename())
106                            i = i + 1
107                        print("Unloaded files: %s" % (', '.join(removed_files)))
108
109
110        # This is testing that we get back a small number of events with the loaded
111        # binaries in batches.  Check that we got back more than 1 solib per event.
112        # In practice on Darwin today, we get back two events for a do-nothing c
113        # program: a.out and dyld, and then all the rest of the system libraries.
114        # On Linux we get events for ld.so, [vdso], the binary and then all libraries.
115
116        avg_solibs_added_per_event = round(float(total_solibs_added) / float(total_modules_added_events))
117        self.assertGreater(avg_solibs_added_per_event, 1)
118