summaryrefslogtreecommitdiff
path: root/lldb/test/API/functionalities/scripted_process/TestStackCoreScriptedProcess.py
blob: a4ed443d3fe85a3d92d28cd14fa10c337b25259c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
"""
Test python scripted process in lldb
"""

import os, json, tempfile

import lldb
from lldbsuite.test.decorators import *
from lldbsuite.test.lldbtest import *
from lldbsuite.test import lldbutil
from lldbsuite.test import lldbtest

class StackCoreScriptedProcesTestCase(TestBase):

    NO_DEBUG_INFO_TESTCASE = True

    def create_stack_skinny_corefile(self, file):
        self.build()
        target, process, thread, _ = lldbutil.run_to_source_breakpoint(self, "// break here",
                                                                       lldb.SBFileSpec("baz.cpp"))
        self.assertTrue(process.IsValid(), "Process is invalid.")
        # FIXME: Use SBAPI to save the process corefile.
        self.runCmd("process save-core -s stack  " + file)
        self.assertTrue(os.path.exists(file), "No stack-only corefile found.")
        self.assertTrue(self.dbg.DeleteTarget(target), "Couldn't delete target")

    def get_module_with_name(self, target, name):
        for module in target.modules:
            if name in module.GetFileSpec().GetFilename():
                return module
        return None

    @skipUnlessDarwin
    @skipIfOutOfTreeDebugserver
    @skipIfRemote
    @skipIfAsan # On ASAN builds, this test times-out (rdar://98678134)
    def test_launch_scripted_process_stack_frames(self):
        """Test that we can launch an lldb scripted process from the command
        line, check its process ID and read string from memory."""
        self.build()
        target = self.dbg.CreateTarget(self.getBuildArtifact("a.out"))
        self.assertTrue(target, VALID_TARGET)

        main_module = self.get_module_with_name(target, 'a.out')
        self.assertTrue(main_module, "Invalid main module.")
        error = target.SetModuleLoadAddress(main_module, 0)
        self.assertSuccess(error, "Reloading main module at offset 0 failed.")

        scripted_dylib = self.get_module_with_name(target, 'libbaz.dylib')
        self.assertTrue(scripted_dylib, "Dynamic library libbaz.dylib not found.")
        self.assertEqual(scripted_dylib.GetObjectFileHeaderAddress().GetLoadAddress(target), 0xffffffffffffffff)

        os.environ['SKIP_SCRIPTED_PROCESS_LAUNCH'] = '1'
        def cleanup():
          del os.environ["SKIP_SCRIPTED_PROCESS_LAUNCH"]
        self.addTearDownHook(cleanup)

        scripted_process_example_relpath = 'stack_core_scripted_process.py'
        self.runCmd("command script import " + os.path.join(self.getSourceDir(),
                                                            scripted_process_example_relpath))

        corefile_process = None
        with tempfile.NamedTemporaryFile() as file:
            self.create_stack_skinny_corefile(file.name)
            corefile_target = self.dbg.CreateTarget(None)
            corefile_process = corefile_target.LoadCore(self.getBuildArtifact(file.name))
        self.assertTrue(corefile_process, PROCESS_IS_VALID)

        structured_data = lldb.SBStructuredData()
        structured_data.SetFromJSON(json.dumps({
            "backing_target_idx" : self.dbg.GetIndexOfTarget(corefile_process.GetTarget()),
            "libbaz_path" : self.getBuildArtifact("libbaz.dylib")
        }))
        launch_info = lldb.SBLaunchInfo(None)
        launch_info.SetProcessPluginName("ScriptedProcess")
        launch_info.SetScriptedProcessClassName("stack_core_scripted_process.StackCoreScriptedProcess")
        launch_info.SetScriptedProcessDictionary(structured_data)

        error = lldb.SBError()
        process = target.Launch(launch_info, error)
        self.assertSuccess(error)
        self.assertTrue(process, PROCESS_IS_VALID)
        self.assertEqual(process.GetProcessID(), 42)

        self.assertEqual(process.GetNumThreads(), 2)
        thread = process.GetSelectedThread()
        self.assertTrue(thread, "Invalid thread.")
        self.assertEqual(thread.GetName(), "StackCoreScriptedThread.thread-1")

        self.assertTrue(target.triple, "Invalid target triple")
        arch = target.triple.split('-')[0]
        supported_arch = ['x86_64', 'arm64', 'arm64e']
        self.assertIn(arch, supported_arch)
        # When creating a corefile of a arm process, lldb saves the exception
        # that triggers the breakpoint in the LC_NOTES of the corefile, so they
        # can be reloaded with the corefile on the next debug session.
        if arch in 'arm64e':
            self.assertTrue(thread.GetStopReason(), lldb.eStopReasonException)
        # However, it's architecture specific, and corefiles made from intel
        # process don't save any metadata to retrieve to stop reason.
        # To mitigate this, the StackCoreScriptedProcess will report a
        # eStopReasonSignal with a SIGTRAP, mimicking what debugserver does.
        else:
            self.assertTrue(thread.GetStopReason(), lldb.eStopReasonSignal)

        self.assertEqual(thread.GetNumFrames(), 5)
        frame = thread.GetSelectedFrame()
        self.assertTrue(frame, "Invalid frame.")
        func = frame.GetFunction()
        self.assertTrue(func, "Invalid function.")

        self.assertIn("baz", frame.GetFunctionName())
        self.assertGreater(frame.vars.GetSize(), 0)
        self.assertEqual(int(frame.vars.GetFirstValueByName('k').GetValue()), 42)
        self.assertEqual(int(frame.vars.GetFirstValueByName('j').Dereference().GetValue()), 42 * 42)

        corefile_dylib = self.get_module_with_name(corefile_target, 'libbaz.dylib')
        self.assertTrue(corefile_dylib, "Dynamic library libbaz.dylib not found.")
        scripted_dylib = self.get_module_with_name(target, 'libbaz.dylib')
        self.assertTrue(scripted_dylib, "Dynamic library libbaz.dylib not found.")
        self.assertEqual(scripted_dylib.GetObjectFileHeaderAddress().GetLoadAddress(target),
                         corefile_dylib.GetObjectFileHeaderAddress().GetLoadAddress(target))