xref: /llvm-project/lldb/test/API/functionalities/gdb_remote_client/TestGdbClientModuleLoad.py (revision 4cc8f2a017c76af25234afc7c380550e9c93135c)
1import lldb
2from lldbsuite.test.lldbtest import *
3from lldbsuite.test.decorators import *
4from lldbsuite.test.gdbclientutils import *
5from lldbsuite.test.lldbgdbclient import GDBRemoteTestBase
6from lldbsuite.support import seven
7
8class MyResponder(MockGDBServerResponder):
9    """
10    A responder which simulates a process with a single shared library loaded.
11    Its parameters allow configuration of various properties of the library.
12    """
13
14    def __init__(self, testcase, triple, library_name, auxv_entry, region_info):
15        MockGDBServerResponder.__init__(self)
16        self.testcase = testcase
17        self._triple = triple
18        self._library_name = library_name
19        self._auxv_entry = auxv_entry
20        self._region_info = region_info
21
22    def qSupported(self, client_supported):
23        return (super().qSupported(client_supported) +
24            ";qXfer:auxv:read+;qXfer:libraries-svr4:read+")
25
26    def qXferRead(self, obj, annex, offset, length):
27        if obj == "features" and annex == "target.xml":
28            return """<?xml version="1.0"?>
29                <target version="1.0">
30                  <architecture>i386:x86-64</architecture>
31                  <feature name="org.gnu.gdb.i386.core">
32                    <reg name="rip" bitsize="64" regnum="0" type="code_ptr" group="general"/>
33                  </feature>
34                </target>""", False
35        elif obj == "auxv":
36            # 0x09 = AT_ENTRY, which lldb uses to compute the load bias of the
37            # main binary.
38            return hex_decode_bytes(self._auxv_entry +
39                "09000000000000000000ee000000000000000000000000000000000000000000"), False
40        elif obj == "libraries-svr4":
41            return """<?xml version="1.0"?>
42                <library-list-svr4 version="1.0">
43                  <library name="%s" lm="0xdeadbeef" l_addr="0xef0000" l_ld="0xdeadbeef"/>
44                </library-list-svr4>""" % self._library_name, False
45        else:
46            return None, False
47
48    def qfThreadInfo(self):
49        return "m47"
50
51    def qsThreadInfo(self):
52        return "l"
53
54    def qProcessInfo(self):
55        return "pid:47;ptrsize:8;endian:little;triple:%s;" % hex_encode_bytes(self._triple)
56
57    def setBreakpoint(self, packet):
58        return "OK"
59
60    def readMemory(self, addr, length):
61        if addr == 0xee1000:
62            return "00"*0x30 + "0020ee0000000000"
63        elif addr == 0xee2000:
64            return "01000000000000000030ee0000000000dead00000000000000000000000000000000000000000000"
65        elif addr == 0xef0000:
66            with open(self.testcase.getBuildArtifact("libmodule_load.so"), "rb") as f:
67                contents = f.read(-1)
68            return hex_encode_bytes(seven.bitcast_to_string(contents))
69        return ("baadf00d00"*1000)[0:length*2]
70
71    def qMemoryRegionInfo(self, addr):
72        if addr < 0xee0000:
73            return "start:0;size:ee0000;"
74        elif addr < 0xef0000:
75            return "start:ee0000;size:10000;"
76        elif addr < 0xf00000:
77            return "start:ef0000;size:1000;permissions:rx;" + self._region_info
78        else:
79            return "start:ef1000;size:ffffffffff10f000"
80
81class TestGdbClientModuleLoad(GDBRemoteTestBase):
82
83    @skipIfXmlSupportMissing
84    def test_android_app_process(self):
85        """
86        This test simulates the scenario where the (android) dynamic linker
87        reports incorrect file name of the main executable. Lldb uses
88        qMemoryRegionInfo to get the correct value.
89        """
90        region_info = "name:%s;" % (
91                    hex_encode_bytes(self.getBuildArtifact("libmodule_load.so")))
92        self.server.responder = MyResponder(self, "x86_64-pc-linux-android",
93                "bogus-name", "", region_info)
94        self.yaml2obj("module_load.yaml", self.getBuildArtifact("libmodule_load.so"))
95        target = self.createTarget("module_load.yaml")
96
97        process = self.connect(target)
98        self.assertTrue(process.IsValid(), "Process is valid")
99
100        lldbutil.expect_state_changes(self, self.dbg.GetListener(), process,
101                [lldb.eStateStopped])
102
103        self.filecheck("image list", __file__, "-check-prefix=ANDROID")
104# ANDROID: [  0] {{.*}} 0x0000000000ee0000 {{.*}}module_load
105# ANDROID: [  1] {{.*}} 0x0000000000ef0000 {{.*}}libmodule_load.so
106
107    @skipIfXmlSupportMissing
108    def test_vdso(self):
109        """
110        This test checks vdso loading in the situation where the process does
111        not have memory region information about the vdso address. This can
112        happen in core files, as they don't store this data.
113        We want to check that the vdso is loaded exactly once.
114        """
115        # vdso address
116        AT_SYSINFO_EHDR = "21000000000000000000ef0000000000"
117        self.server.responder = MyResponder(self, "x86_64-pc-linux",
118                "linux-vdso.so.1", AT_SYSINFO_EHDR, "")
119        self.yaml2obj("module_load.yaml", self.getBuildArtifact("libmodule_load.so"))
120        target = self.createTarget("module_load.yaml")
121
122        process = self.connect(target)
123        self.assertTrue(process.IsValid(), "Process is valid")
124
125        lldbutil.expect_state_changes(self, self.dbg.GetListener(), process,
126                [lldb.eStateStopped])
127
128        self.filecheck("image list", __file__, "-check-prefix=VDSO")
129# VDSO: [  0] {{.*}} 0x0000000000ee0000 {{.*}}module_load
130# VDSO: [  1] {{.*}} 0x0000000000ef0000 {{.*}}[vdso]
131        self.assertEquals(self.target().GetNumModules(), 2)
132