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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
|
import lldb
from lldbsuite.test.lldbtest import *
from lldbsuite.test.decorators import *
from lldbsuite.test.gdbclientutils import *
from lldbsuite.test.lldbgdbclient import GDBRemoteTestBase
class MyResponder(MockGDBServerResponder):
"""
A responder which simulates a process with a single shared library loaded.
Its parameters allow configuration of various properties of the library.
"""
def __init__(self, testcase, triple, library_name, auxv_entry, region_info):
MockGDBServerResponder.__init__(self)
self.testcase = testcase
self._triple = triple
self._library_name = library_name
self._auxv_entry = auxv_entry
self._region_info = region_info
def qSupported(self, client_supported):
return (
super().qSupported(client_supported)
+ ";qXfer:auxv:read+;qXfer:libraries-svr4:read+"
)
def qXferRead(self, obj, annex, offset, length):
if obj == "features" and annex == "target.xml":
return (
"""<?xml version="1.0"?>
<target version="1.0">
<architecture>i386:x86-64</architecture>
<feature name="org.gnu.gdb.i386.core">
<reg name="rip" bitsize="64" regnum="0" type="code_ptr" group="general"/>
</feature>
</target>""",
False,
)
elif obj == "auxv":
# 0x09 = AT_ENTRY, which lldb uses to compute the load bias of the
# main binary.
return (
hex_decode_bytes(
self._auxv_entry
+ "09000000000000000000ee000000000000000000000000000000000000000000"
),
False,
)
elif obj == "libraries-svr4":
return (
"""<?xml version="1.0"?>
<library-list-svr4 version="1.0">
<library name="%s" lm="0xdeadbeef" l_addr="0xef0000" l_ld="0xdeadbeef"/>
</library-list-svr4>"""
% self._library_name,
False,
)
else:
return None, False
def qfThreadInfo(self):
return "m47"
def qsThreadInfo(self):
return "l"
def qProcessInfo(self):
return "pid:47;ptrsize:8;endian:little;triple:%s;" % hex_encode_bytes(
self._triple
)
def setBreakpoint(self, packet):
return "OK"
def readMemory(self, addr, length):
if addr == 0xEE1000:
return "00" * 0x30 + "0020ee0000000000"
elif addr == 0xEE2000:
return "01000000000000000030ee0000000000dead00000000000000000000000000000000000000000000"
elif addr == 0xEF0000:
with open(self.testcase.getBuildArtifact("libmodule_load.so"), "rb") as f:
contents = f.read(-1)
return hex_encode_bytes(seven.bitcast_to_string(contents))
return ("baadf00d00" * 1000)[0 : length * 2]
def qMemoryRegionInfo(self, addr):
if addr < 0xEE0000:
return "start:0;size:ee0000;"
elif addr < 0xEF0000:
return "start:ee0000;size:10000;"
elif addr < 0xF00000:
return "start:ef0000;size:1000;permissions:rx;" + self._region_info
else:
return "start:ef1000;size:ffffffffff10f000"
class TestGdbClientModuleLoad(GDBRemoteTestBase):
@skipIfXmlSupportMissing
def test_android_app_process(self):
"""
This test simulates the scenario where the (android) dynamic linker
reports incorrect file name of the main executable. Lldb uses
qMemoryRegionInfo to get the correct value.
"""
region_info = "name:%s;" % (
hex_encode_bytes(self.getBuildArtifact("libmodule_load.so"))
)
self.server.responder = MyResponder(
self, "x86_64-pc-linux-android", "bogus-name", "", region_info
)
self.yaml2obj("module_load.yaml", self.getBuildArtifact("libmodule_load.so"))
target = self.createTarget("module_load.yaml")
process = self.connect(target)
self.assertTrue(process.IsValid(), "Process is valid")
lldbutil.expect_state_changes(
self, self.dbg.GetListener(), process, [lldb.eStateStopped]
)
self.filecheck("image list", __file__, "-check-prefix=ANDROID")
# ANDROID: [ 0] {{.*}} 0x0000000000ee0000 {{.*}}module_load
# ANDROID: [ 1] {{.*}} 0x0000000000ef0000 {{.*}}libmodule_load.so
@skipIfXmlSupportMissing
def test_vdso(self):
"""
This test checks vdso loading in the situation where the process does
not have memory region information about the vdso address. This can
happen in core files, as they don't store this data.
We want to check that the vdso is loaded exactly once.
"""
# vdso address
AT_SYSINFO_EHDR = "21000000000000000000ef0000000000"
self.server.responder = MyResponder(
self, "x86_64-pc-linux", "linux-vdso.so.1", AT_SYSINFO_EHDR, ""
)
self.yaml2obj("module_load.yaml", self.getBuildArtifact("libmodule_load.so"))
target = self.createTarget("module_load.yaml")
process = self.connect(target)
self.assertTrue(process.IsValid(), "Process is valid")
lldbutil.expect_state_changes(
self, self.dbg.GetListener(), process, [lldb.eStateStopped]
)
self.filecheck("image list", __file__, "-check-prefix=VDSO")
# VDSO: [ 0] {{.*}} 0x0000000000ee0000 {{.*}}module_load
# VDSO: [ 1] {{.*}} 0x0000000000ef0000 {{.*}}[vdso]
self.assertEqual(self.target().GetNumModules(), 2)
|