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    # DynamicLoaderDarwin should batch up notifications about
20    # newly added/removed libraries.  Other DynamicLoaders may
21    # not be written this way.
22    @skipUnlessDarwin
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        process = target.Launch(listener,
56                                None,      # argv
57                                None,      # envp
58                                None,      # stdin_path
59                                None,      # stdout_path
60                                None,      # stderr_path
61                                None,      # working directory
62                                0,         # launch flags
63                                False,     # Stop at entry
64                                error)     # error
65
66        self.assertTrue(
67            process.GetState() == lldb.eStateStopped,
68            PROCESS_STOPPED)
69
70        total_solibs_added = 0
71        total_solibs_removed = 0
72        total_modules_added_events = 0
73        total_modules_removed_events = 0
74        while listener.GetNextEvent(event):
75            if lldb.SBTarget.EventIsTargetEvent(event):
76                if event.GetType() == lldb.SBTarget.eBroadcastBitModulesLoaded:
77                    solib_count = lldb.SBTarget.GetNumModulesFromEvent(event)
78                    total_modules_added_events += 1
79                    total_solibs_added += solib_count
80                    if self.TraceOn():
81                        # print all of the binaries that have been added
82                        added_files = []
83                        i = 0
84                        while i < solib_count:
85                            module = lldb.SBTarget.GetModuleAtIndexFromEvent(i, event)
86                            added_files.append(module.GetFileSpec().GetFilename())
87                            i = i + 1
88                        print("Loaded files: %s" % (', '.join(added_files)))
89
90                if event.GetType() == lldb.SBTarget.eBroadcastBitModulesUnloaded:
91                    solib_count = lldb.SBTarget.GetNumModulesFromEvent(event)
92                    total_modules_removed_events += 1
93                    total_solibs_removed += solib_count
94                    if self.TraceOn():
95                        # print all of the binaries that have been removed
96                        removed_files = []
97                        i = 0
98                        while i < solib_count:
99                            module = lldb.SBTarget.GetModuleAtIndexFromEvent(i, event)
100                            removed_files.append(module.GetFileSpec().GetFilename())
101                            i = i + 1
102                        print("Unloaded files: %s" % (', '.join(removed_files)))
103
104
105        # This is testing that we get back a small number of events with the loaded
106        # binaries in batches.  Check that we got back more than 1 solib per event.
107        # In practice on Darwin today, we get back two events for a do-nothing c
108        # program: a.out and dyld, and then all the rest of the system libraries.
109
110        avg_solibs_added_per_event = int(float(total_solibs_added) / float(total_modules_added_events))
111        self.assertGreater(avg_solibs_added_per_event, 1)
112