1"""
2Test process attach.
3"""
4
5
6
7import os
8import lldb
9import shutil
10from lldbsuite.test.decorators import *
11from lldbsuite.test.lldbtest import *
12from lldbsuite.test import lldbutil
13
14exe_name = "ProcessAttach"  # Must match Makefile
15
16
17class ProcessAttachTestCase(TestBase):
18
19    mydir = TestBase.compute_mydir(__file__)
20
21    NO_DEBUG_INFO_TESTCASE = True
22
23    def setUp(self):
24        # Call super's setUp().
25        TestBase.setUp(self)
26        # Find the line number to break for main.c.
27        self.line = line_number('main.cpp',
28                                '// Waiting to be attached...')
29
30    @skipIfiOSSimulator
31    def test_attach_to_process_by_id(self):
32        """Test attach by process id"""
33        self.build()
34        exe = self.getBuildArtifact(exe_name)
35
36        # Spawn a new process
37        popen = self.spawnSubprocess(exe)
38
39        self.runCmd("process attach -p " + str(popen.pid))
40
41        target = self.dbg.GetSelectedTarget()
42
43        process = target.GetProcess()
44        self.assertTrue(process, PROCESS_IS_VALID)
45
46    @skipIfReproducer # FIXME: Unexpected packet during (active) replay
47    @skipIfWindows # This is flakey on Windows AND when it fails, it hangs: llvm.org/pr48806
48    def test_attach_to_process_from_different_dir_by_id(self):
49        """Test attach by process id"""
50        newdir = self.getBuildArtifact("newdir")
51        try:
52            os.mkdir(newdir)
53        except OSError as e:
54            if e.errno != os.errno.EEXIST:
55                raise
56        testdir = self.getBuildDir()
57        exe = os.path.join(newdir, 'proc_attach')
58        self.buildProgram('main.cpp', exe)
59        self.addTearDownHook(lambda: shutil.rmtree(newdir))
60
61        # Spawn a new process
62        popen = self.spawnSubprocess(exe)
63
64        os.chdir(newdir)
65        self.addTearDownHook(lambda: os.chdir(testdir))
66        self.runCmd("process attach -p " + str(popen.pid))
67
68        target = self.dbg.GetSelectedTarget()
69
70        process = target.GetProcess()
71        self.assertTrue(process, PROCESS_IS_VALID)
72
73    def test_attach_to_process_by_name(self):
74        """Test attach by process name"""
75        self.build()
76        exe = self.getBuildArtifact(exe_name)
77
78        # Spawn a new process
79        popen = self.spawnSubprocess(exe)
80
81        self.runCmd("process attach -n " + exe_name)
82
83        target = self.dbg.GetSelectedTarget()
84
85        process = target.GetProcess()
86        self.assertTrue(process, PROCESS_IS_VALID)
87
88    @expectedFailureNetBSD
89    def test_attach_to_process_by_id_correct_executable_offset(self):
90        """
91        Test that after attaching to a process the executable offset
92        is determined correctly on FreeBSD.  This is a regression test
93        for dyld plugin getting the correct executable path,
94        and therefore being able to identify it in the module list.
95        """
96
97        self.build()
98        exe = self.getBuildArtifact(exe_name)
99
100        # In order to reproduce, we must spawn using a relative path
101        popen = self.spawnSubprocess(os.path.relpath(exe))
102
103        self.runCmd("process attach -p " + str(popen.pid))
104
105        # Make suer we did not attach to early
106        lldbutil.run_break_set_by_file_and_line(
107            self, "main.cpp", self.line, num_expected_locations=1, loc_exact=False)
108        self.runCmd("process continue")
109        self.expect("p g_val", substrs=["$0 = 12345"])
110
111    def tearDown(self):
112        # Destroy process before TestBase.tearDown()
113        self.dbg.GetSelectedTarget().GetProcess().Destroy()
114
115        # Call super's tearDown().
116        TestBase.tearDown(self)
117