1import lldb
2import binascii
3import os
4import time
5from lldbsuite.test.lldbtest import *
6from lldbsuite.test.decorators import *
7from lldbsuite.test.gdbclientutils import *
8from lldbsuite.test.lldbgdbclient import GDBRemoteTestBase
9
10def hexlify(string):
11    return binascii.hexlify(string.encode()).decode()
12
13class TestPlatformClient(GDBRemoteTestBase):
14
15    def test_process_list_with_all_users(self):
16        """Test connecting to a remote linux platform"""
17
18        class MyResponder(MockGDBServerResponder):
19            def __init__(self):
20                MockGDBServerResponder.__init__(self)
21                self.currentQsProc = 0
22                self.all_users = False
23
24            def qfProcessInfo(self, packet):
25                if "all_users:1" in packet:
26                    self.all_users = True
27                    name = hexlify("/a/test_process")
28                    args = "-".join(map(hexlify,
29                                        ["/system/bin/sh", "-c", "/data/local/tmp/lldb-server"]))
30                    return "pid:10;ppid:1;uid:2;gid:3;euid:4;egid:5;name:" + name + ";args:" + args + ";"
31                else:
32                    self.all_users = False
33                    return "E04"
34
35            def qsProcessInfo(self):
36                if self.all_users:
37                    if self.currentQsProc == 0:
38                        self.currentQsProc = 1
39                        name = hexlify("/b/another_test_process")
40                        # This intentionally has a badly encoded argument
41                        args = "X".join(map(hexlify,
42                                            ["/system/bin/ls", "--help"]))
43                        return "pid:11;ppid:2;uid:3;gid:4;euid:5;egid:6;name:" + name + ";args:" + args + ";"
44                    elif self.currentQsProc == 1:
45                        self.currentQsProc = 0
46                        return "E04"
47                else:
48                    return "E04"
49
50        self.server.responder = MyResponder()
51
52        try:
53            self.runCmd("platform select remote-linux")
54            self.runCmd("platform connect " + self.server.get_connect_url())
55            self.assertTrue(self.dbg.GetSelectedPlatform().IsConnected())
56            self.expect("platform process list -x",
57                        substrs=["2 matching processes were found", "test_process", "another_test_process"])
58            self.expect("platform process list -xv",
59                        substrs=[
60                            "PID    PARENT USER       GROUP      EFF USER   EFF GROUP  TRIPLE                         ARGUMENTS",
61                            "10     1      2          3          4          5                                         /system/bin/sh -c /data/local/tmp/lldb-server",
62                            "11     2      3          4          5          6"])
63            self.expect("platform process list -xv", substrs=["/system/bin/ls"], matching=False)
64            self.expect("platform process list",
65                        error=True,
66                        substrs=["error: no processes were found on the \"remote-linux\" platform"])
67        finally:
68            self.dbg.GetSelectedPlatform().DisconnectRemote()
69
70    class TimeoutResponder(MockGDBServerResponder):
71        """A mock server, which takes a very long time to compute the working
72        directory."""
73        def __init__(self):
74            MockGDBServerResponder.__init__(self)
75
76        def qGetWorkingDir(self):
77            time.sleep(10)
78            return hexlify("/foo/bar")
79
80    def test_no_timeout(self):
81        """Test that we honor the timeout setting. With a large enough timeout,
82        we should get the CWD successfully."""
83
84        self.server.responder = TestPlatformClient.TimeoutResponder()
85        self.runCmd("settings set plugin.process.gdb-remote.packet-timeout 30")
86        plat = lldb.SBPlatform("remote-linux")
87        try:
88            self.assertSuccess(plat.ConnectRemote(lldb.SBPlatformConnectOptions(
89                self.server.get_connect_url())))
90            self.assertEqual(plat.GetWorkingDirectory(), "/foo/bar")
91        finally:
92            plat.DisconnectRemote()
93
94    def test_timeout(self):
95        """Test that we honor the timeout setting. With a small timeout, CWD
96        retrieval should fail."""
97
98        self.server.responder = TestPlatformClient.TimeoutResponder()
99        self.runCmd("settings set plugin.process.gdb-remote.packet-timeout 3")
100        plat = lldb.SBPlatform("remote-linux")
101        try:
102            self.assertSuccess(plat.ConnectRemote(lldb.SBPlatformConnectOptions(
103                self.server.get_connect_url())))
104            self.assertIsNone(plat.GetWorkingDirectory())
105        finally:
106            plat.DisconnectRemote()
107