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    def test_attach_to_process_from_different_dir_by_id(self):
48        """Test attach by process id"""
49        newdir = self.getBuildArtifact("newdir")
50        try:
51            os.mkdir(newdir)
52        except OSError as e:
53            if e.errno != os.errno.EEXIST:
54                raise
55        testdir = self.getBuildDir()
56        exe = os.path.join(newdir, 'proc_attach')
57        self.buildProgram('main.cpp', exe)
58        self.addTearDownHook(lambda: shutil.rmtree(newdir))
59
60        # Spawn a new process
61        popen = self.spawnSubprocess(exe)
62
63        os.chdir(newdir)
64        self.addTearDownHook(lambda: os.chdir(testdir))
65        self.runCmd("process attach -p " + str(popen.pid))
66
67        target = self.dbg.GetSelectedTarget()
68
69        process = target.GetProcess()
70        self.assertTrue(process, PROCESS_IS_VALID)
71
72    def test_attach_to_process_by_name(self):
73        """Test attach by process name"""
74        self.build()
75        exe = self.getBuildArtifact(exe_name)
76
77        # Spawn a new process
78        popen = self.spawnSubprocess(exe)
79
80        self.runCmd("process attach -n " + exe_name)
81
82        target = self.dbg.GetSelectedTarget()
83
84        process = target.GetProcess()
85        self.assertTrue(process, PROCESS_IS_VALID)
86
87    @expectedFailureNetBSD
88    def test_attach_to_process_by_id_correct_executable_offset(self):
89        """
90        Test that after attaching to a process the executable offset
91        is determined correctly on FreeBSD.  This is a regression test
92        for dyld plugin getting the correct executable path,
93        and therefore being able to identify it in the module list.
94        """
95
96        self.build()
97        exe = self.getBuildArtifact(exe_name)
98
99        # In order to reproduce, we must spawn using a relative path
100        popen = self.spawnSubprocess(os.path.relpath(exe))
101
102        self.runCmd("process attach -p " + str(popen.pid))
103
104        # Make suer we did not attach to early
105        lldbutil.run_break_set_by_file_and_line(
106            self, "main.cpp", self.line, num_expected_locations=1, loc_exact=False)
107        self.runCmd("process continue")
108        self.expect("p g_val", substrs=["$0 = 12345"])
109
110    def tearDown(self):
111        # Destroy process before TestBase.tearDown()
112        self.dbg.GetSelectedTarget().GetProcess().Destroy()
113
114        # Call super's tearDown().
115        TestBase.tearDown(self)
116