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        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.assertTrue(
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        while listener.GetNextEvent(event):
76            if lldb.SBTarget.EventIsTargetEvent(event):
77                if event.GetType() == lldb.SBTarget.eBroadcastBitModulesLoaded:
78                    solib_count = lldb.SBTarget.GetNumModulesFromEvent(event)
79                    total_modules_added_events += 1
80                    total_solibs_added += solib_count
81                    if self.TraceOn():
82                        # print all of the binaries that have been added
83                        added_files = []
84                        i = 0
85                        while i < solib_count:
86                            module = lldb.SBTarget.GetModuleAtIndexFromEvent(i, event)
87                            added_files.append(module.GetFileSpec().GetFilename())
88                            i = i + 1
89                        print("Loaded files: %s" % (', '.join(added_files)))
90
91                if event.GetType() == lldb.SBTarget.eBroadcastBitModulesUnloaded:
92                    solib_count = lldb.SBTarget.GetNumModulesFromEvent(event)
93                    total_modules_removed_events += 1
94                    total_solibs_removed += solib_count
95                    if self.TraceOn():
96                        # print all of the binaries that have been removed
97                        removed_files = []
98                        i = 0
99                        while i < solib_count:
100                            module = lldb.SBTarget.GetModuleAtIndexFromEvent(i, event)
101                            removed_files.append(module.GetFileSpec().GetFilename())
102                            i = i + 1
103                        print("Unloaded files: %s" % (', '.join(removed_files)))
104
105
106        # This is testing that we get back a small number of events with the loaded
107        # binaries in batches.  Check that we got back more than 1 solib per event.
108        # In practice on Darwin today, we get back two events for a do-nothing c
109        # program: a.out and dyld, and then all the rest of the system libraries.
110
111        avg_solibs_added_per_event = int(float(total_solibs_added) / float(total_modules_added_events))
112        self.assertGreater(avg_solibs_added_per_event, 1)
113