1d327108dSMed Ismail Bennani"""
2d327108dSMed Ismail BennaniTest python scripted process in lldb
3d327108dSMed Ismail Bennani"""
4d327108dSMed Ismail Bennani
5d327108dSMed Ismail Bennaniimport os, json, tempfile
6d327108dSMed Ismail Bennani
7d327108dSMed Ismail Bennaniimport lldb
8d327108dSMed Ismail Bennanifrom lldbsuite.test.decorators import *
9d327108dSMed Ismail Bennanifrom lldbsuite.test.lldbtest import *
10d327108dSMed Ismail Bennanifrom lldbsuite.test import lldbutil
11d327108dSMed Ismail Bennanifrom lldbsuite.test import lldbtest
12d327108dSMed Ismail Bennani
13d327108dSMed Ismail Bennaniclass StackCoreScriptedProcesTestCase(TestBase):
14d327108dSMed Ismail Bennani
15d327108dSMed Ismail Bennani    NO_DEBUG_INFO_TESTCASE = True
16d327108dSMed Ismail Bennani
17d327108dSMed Ismail Bennani    def setUp(self):
18d327108dSMed Ismail Bennani        TestBase.setUp(self)
19d327108dSMed Ismail Bennani
20d327108dSMed Ismail Bennani    def tearDown(self):
21d327108dSMed Ismail Bennani        TestBase.tearDown(self)
22d327108dSMed Ismail Bennani
23d327108dSMed Ismail Bennani    def create_stack_skinny_corefile(self, file):
24d327108dSMed Ismail Bennani        self.build()
25d327108dSMed Ismail Bennani        target, process, thread, _ = lldbutil.run_to_source_breakpoint(self, "// break here",
26680ca7f2SMed Ismail Bennani                                                                       lldb.SBFileSpec("baz.c"))
27d327108dSMed Ismail Bennani        self.assertTrue(process.IsValid(), "Process is invalid.")
28d327108dSMed Ismail Bennani        # FIXME: Use SBAPI to save the process corefile.
29d327108dSMed Ismail Bennani        self.runCmd("process save-core -s stack  " + file)
30d327108dSMed Ismail Bennani        self.assertTrue(os.path.exists(file), "No stack-only corefile found.")
31d327108dSMed Ismail Bennani        self.assertTrue(self.dbg.DeleteTarget(target), "Couldn't delete target")
32d327108dSMed Ismail Bennani
33680ca7f2SMed Ismail Bennani    def get_module_with_name(self, target, name):
34680ca7f2SMed Ismail Bennani        for module in target.modules:
35680ca7f2SMed Ismail Bennani            if name in module.GetFileSpec().GetFilename():
36680ca7f2SMed Ismail Bennani                return module
37680ca7f2SMed Ismail Bennani        return None
38680ca7f2SMed Ismail Bennani
39d327108dSMed Ismail Bennani    @skipUnlessDarwin
40d327108dSMed Ismail Bennani    @skipIfOutOfTreeDebugserver
41*065e3c9aSJonas Devlieghere    @skipIfRemote
42d327108dSMed Ismail Bennani    def test_launch_scripted_process_stack_frames(self):
43d327108dSMed Ismail Bennani        """Test that we can launch an lldb scripted process from the command
44d327108dSMed Ismail Bennani        line, check its process ID and read string from memory."""
45d327108dSMed Ismail Bennani        self.build()
46d327108dSMed Ismail Bennani        target = self.dbg.CreateTarget(self.getBuildArtifact("a.out"))
47d327108dSMed Ismail Bennani        self.assertTrue(target, VALID_TARGET)
48d327108dSMed Ismail Bennani
49680ca7f2SMed Ismail Bennani        main_module = self.get_module_with_name(target, 'a.out')
50d327108dSMed Ismail Bennani        self.assertTrue(main_module, "Invalid main module.")
51d327108dSMed Ismail Bennani        error = target.SetModuleLoadAddress(main_module, 0)
52779bbbf2SDave Lee        self.assertSuccess(error, "Reloading main module at offset 0 failed.")
53d327108dSMed Ismail Bennani
54680ca7f2SMed Ismail Bennani        scripted_dylib = self.get_module_with_name(target, 'libbaz.dylib')
55680ca7f2SMed Ismail Bennani        self.assertTrue(scripted_dylib, "Dynamic library libbaz.dylib not found.")
56680ca7f2SMed Ismail Bennani        self.assertEqual(scripted_dylib.GetObjectFileHeaderAddress().GetLoadAddress(target), 0xffffffffffffffff)
57680ca7f2SMed Ismail Bennani
58d327108dSMed Ismail Bennani        os.environ['SKIP_SCRIPTED_PROCESS_LAUNCH'] = '1'
59d327108dSMed Ismail Bennani        def cleanup():
60d327108dSMed Ismail Bennani          del os.environ["SKIP_SCRIPTED_PROCESS_LAUNCH"]
61d327108dSMed Ismail Bennani        self.addTearDownHook(cleanup)
62d327108dSMed Ismail Bennani
63d327108dSMed Ismail Bennani        scripted_process_example_relpath = 'stack_core_scripted_process.py'
64d327108dSMed Ismail Bennani        self.runCmd("command script import " + os.path.join(self.getSourceDir(),
65d327108dSMed Ismail Bennani                                                            scripted_process_example_relpath))
66d327108dSMed Ismail Bennani
67d327108dSMed Ismail Bennani        corefile_process = None
68d327108dSMed Ismail Bennani        with tempfile.NamedTemporaryFile() as file:
69d327108dSMed Ismail Bennani            self.create_stack_skinny_corefile(file.name)
70d327108dSMed Ismail Bennani            corefile_target = self.dbg.CreateTarget(None)
71d327108dSMed Ismail Bennani            corefile_process = corefile_target.LoadCore(self.getBuildArtifact(file.name))
72d327108dSMed Ismail Bennani        self.assertTrue(corefile_process, PROCESS_IS_VALID)
73d327108dSMed Ismail Bennani
74d327108dSMed Ismail Bennani        structured_data = lldb.SBStructuredData()
75d327108dSMed Ismail Bennani        structured_data.SetFromJSON(json.dumps({
76680ca7f2SMed Ismail Bennani            "backing_target_idx" : self.dbg.GetIndexOfTarget(corefile_process.GetTarget()),
77680ca7f2SMed Ismail Bennani            "libbaz_path" : self.getBuildArtifact("libbaz.dylib")
78d327108dSMed Ismail Bennani        }))
79d327108dSMed Ismail Bennani        launch_info = lldb.SBLaunchInfo(None)
80d327108dSMed Ismail Bennani        launch_info.SetProcessPluginName("ScriptedProcess")
81d327108dSMed Ismail Bennani        launch_info.SetScriptedProcessClassName("stack_core_scripted_process.StackCoreScriptedProcess")
82d327108dSMed Ismail Bennani        launch_info.SetScriptedProcessDictionary(structured_data)
83d327108dSMed Ismail Bennani
84d327108dSMed Ismail Bennani        error = lldb.SBError()
85d327108dSMed Ismail Bennani        process = target.Launch(launch_info, error)
86779bbbf2SDave Lee        self.assertSuccess(error)
87d327108dSMed Ismail Bennani        self.assertTrue(process, PROCESS_IS_VALID)
88d327108dSMed Ismail Bennani        self.assertEqual(process.GetProcessID(), 42)
89d327108dSMed Ismail Bennani
90680ca7f2SMed Ismail Bennani        self.assertEqual(process.GetNumThreads(), 2)
91d327108dSMed Ismail Bennani        thread = process.GetSelectedThread()
92d327108dSMed Ismail Bennani        self.assertTrue(thread, "Invalid thread.")
93680ca7f2SMed Ismail Bennani        self.assertEqual(thread.GetName(), "StackCoreScriptedThread.thread-1")
94d327108dSMed Ismail Bennani
95d327108dSMed Ismail Bennani        self.assertTrue(target.triple, "Invalid target triple")
96d327108dSMed Ismail Bennani        arch = target.triple.split('-')[0]
97d327108dSMed Ismail Bennani        supported_arch = ['x86_64', 'arm64', 'arm64e']
98d327108dSMed Ismail Bennani        self.assertIn(arch, supported_arch)
99d327108dSMed Ismail Bennani        # When creating a corefile of a arm process, lldb saves the exception
100d327108dSMed Ismail Bennani        # that triggers the breakpoint in the LC_NOTES of the corefile, so they
101d327108dSMed Ismail Bennani        # can be reloaded with the corefile on the next debug session.
102d327108dSMed Ismail Bennani        if arch in 'arm64e':
103d327108dSMed Ismail Bennani            self.assertTrue(thread.GetStopReason(), lldb.eStopReasonException)
104d327108dSMed Ismail Bennani        # However, it's architecture specific, and corefiles made from intel
105d327108dSMed Ismail Bennani        # process don't save any metadata to retrieve to stop reason.
106d327108dSMed Ismail Bennani        # To mitigate this, the StackCoreScriptedProcess will report a
107d327108dSMed Ismail Bennani        # eStopReasonSignal with a SIGTRAP, mimicking what debugserver does.
108d327108dSMed Ismail Bennani        else:
109d327108dSMed Ismail Bennani            self.assertTrue(thread.GetStopReason(), lldb.eStopReasonSignal)
110d327108dSMed Ismail Bennani
111680ca7f2SMed Ismail Bennani        self.assertEqual(thread.GetNumFrames(), 5)
112d327108dSMed Ismail Bennani        frame = thread.GetSelectedFrame()
113d327108dSMed Ismail Bennani        self.assertTrue(frame, "Invalid frame.")
114680ca7f2SMed Ismail Bennani        func = frame.GetFunction()
115680ca7f2SMed Ismail Bennani        self.assertTrue(func, "Invalid function.")
116680ca7f2SMed Ismail Bennani
117680ca7f2SMed Ismail Bennani        self.assertIn("baz", frame.GetFunctionName())
118680ca7f2SMed Ismail Bennani        self.assertEqual(frame.vars.GetSize(), 2)
119680ca7f2SMed Ismail Bennani        self.assertEqual(int(frame.vars.GetFirstValueByName('j').GetValue()), 42 * 42)
120680ca7f2SMed Ismail Bennani        self.assertEqual(int(frame.vars.GetFirstValueByName('k').GetValue()), 42)
121680ca7f2SMed Ismail Bennani
122999e7547SMed Ismail Bennani        corefile_dylib = self.get_module_with_name(corefile_target, 'libbaz.dylib')
123999e7547SMed Ismail Bennani        self.assertTrue(corefile_dylib, "Dynamic library libbaz.dylib not found.")
124680ca7f2SMed Ismail Bennani        scripted_dylib = self.get_module_with_name(target, 'libbaz.dylib')
125680ca7f2SMed Ismail Bennani        self.assertTrue(scripted_dylib, "Dynamic library libbaz.dylib not found.")
126999e7547SMed Ismail Bennani        self.assertEqual(scripted_dylib.GetObjectFileHeaderAddress().GetLoadAddress(target),
127999e7547SMed Ismail Bennani                         corefile_dylib.GetObjectFileHeaderAddress().GetLoadAddress(target))
128