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
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
|
import lldb
import unittest
import os
import json
import stat
import sys
from textwrap import dedent
import lldbsuite.test.lldbutil
from lldbsuite.test.lldbtest import *
from lldbsuite.test.decorators import *
from lldbsuite.test.gdbclientutils import *
@skipIfRemote
@skipIfWindows
class TestQemuLaunch(TestBase):
NO_DEBUG_INFO_TESTCASE = True
def set_emulator_setting(self, name, value):
self.runCmd("settings set -- platform.plugin.qemu-user.%s %s" % (name, value))
def setUp(self):
super().setUp()
emulator = self.getBuildArtifact("qemu.py")
with os.fdopen(
os.open(emulator, os.O_WRONLY | os.O_CREAT, stat.S_IRWXU), "w"
) as e:
e.write(
dedent(
"""\
#! {exec!s}
import runpy
import sys
sys.path = {path!r}
runpy.run_path({source!r}, run_name='__main__')
"""
).format(
exec=sys.executable,
path=sys.path,
source=self.getSourcePath("qemu.py"),
)
)
self.set_emulator_setting("architecture", self.getArchitecture())
self.set_emulator_setting("emulator-path", emulator)
def _create_target(self):
self.build()
exe = self.getBuildArtifact()
# Create a target using our platform
error = lldb.SBError()
target = self.dbg.CreateTarget(exe, "", "qemu-user", False, error)
self.assertSuccess(error)
self.assertEqual(target.GetPlatform().GetName(), "qemu-user")
return target
def _run_and_get_state(self, target=None, info=None):
if target is None:
target = self._create_target()
if info is None:
info = target.GetLaunchInfo()
# "Launch" the process. Our fake qemu implementation will pretend it
# immediately exited.
info.SetArguments(["dump:" + self.getBuildArtifact("state.log")], True)
error = lldb.SBError()
process = target.Launch(info, error)
self.assertSuccess(error)
self.assertIsNotNone(process)
self.assertState(process.GetState(), lldb.eStateExited)
self.assertEqual(process.GetExitStatus(), 0x47)
# Verify the qemu invocation parameters.
with open(self.getBuildArtifact("state.log")) as s:
return json.load(s)
def test_basic_launch(self):
state = self._run_and_get_state()
self.assertEqual(state["program"], self.getBuildArtifact())
self.assertEqual(state["args"], ["dump:" + self.getBuildArtifact("state.log")])
def test_stdio_pty(self):
target = self._create_target()
info = target.GetLaunchInfo()
info.SetArguments(
[
"stdin:stdin",
"stdout:STDOUT CONTENT\n",
"stderr:STDERR CONTENT\n",
"dump:" + self.getBuildArtifact("state.log"),
],
False,
)
listener = lldb.SBListener("test_stdio")
info.SetListener(listener)
self.dbg.SetAsync(True)
error = lldb.SBError()
process = target.Launch(info, error)
self.assertSuccess(error)
lldbutil.expect_state_changes(self, listener, process, [lldb.eStateRunning])
process.PutSTDIN("STDIN CONTENT\n")
lldbutil.expect_state_changes(self, listener, process, [lldb.eStateExited])
# Echoed stdin, stdout and stderr. With a pty we cannot split standard
# output and error.
self.assertEqual(
process.GetSTDOUT(1000),
"STDIN CONTENT\r\nSTDOUT CONTENT\r\nSTDERR CONTENT\r\n",
)
with open(self.getBuildArtifact("state.log")) as s:
state = json.load(s)
self.assertEqual(state["stdin"], "STDIN CONTENT\n")
def test_stdio_redirect(self):
self.build()
exe = self.getBuildArtifact()
# Create a target using our platform
error = lldb.SBError()
target = self.dbg.CreateTarget(exe, "", "qemu-user", False, error)
self.assertSuccess(error)
info = lldb.SBLaunchInfo(
[
"stdin:stdin",
"stdout:STDOUT CONTENT",
"stderr:STDERR CONTENT",
"dump:" + self.getBuildArtifact("state.log"),
]
)
info.AddOpenFileAction(0, self.getBuildArtifact("stdin.txt"), True, False)
info.AddOpenFileAction(1, self.getBuildArtifact("stdout.txt"), False, True)
info.AddOpenFileAction(2, self.getBuildArtifact("stderr.txt"), False, True)
with open(self.getBuildArtifact("stdin.txt"), "w") as f:
f.write("STDIN CONTENT")
process = target.Launch(info, error)
self.assertSuccess(error)
self.assertState(process.GetState(), lldb.eStateExited)
with open(self.getBuildArtifact("stdout.txt")) as f:
self.assertEqual(f.read(), "STDOUT CONTENT")
with open(self.getBuildArtifact("stderr.txt")) as f:
self.assertEqual(f.read(), "STDERR CONTENT")
with open(self.getBuildArtifact("state.log")) as s:
state = json.load(s)
self.assertEqual(state["stdin"], "STDIN CONTENT")
def test_find_in_PATH(self):
emulator = self.getBuildArtifact("qemu-" + self.getArchitecture())
os.rename(self.getBuildArtifact("qemu.py"), emulator)
self.set_emulator_setting("emulator-path", "''")
original_path = os.environ["PATH"]
os.environ["PATH"] = (
self.getBuildDir()
+ self.platformContext.shlib_path_separator
+ original_path
)
def cleanup():
os.environ["PATH"] = original_path
self.addTearDownHook(cleanup)
state = self._run_and_get_state()
self.assertEqual(state["program"], self.getBuildArtifact())
self.assertEqual(state["args"], ["dump:" + self.getBuildArtifact("state.log")])
def test_bad_emulator_path(self):
self.set_emulator_setting(
"emulator-path", self.getBuildArtifact("nonexistent.file")
)
target = self._create_target()
info = lldb.SBLaunchInfo([])
error = lldb.SBError()
target.Launch(info, error)
self.assertTrue(error.Fail())
self.assertIn("doesn't exist", error.GetCString())
def test_extra_args(self):
self.set_emulator_setting("emulator-args", "-fake-arg fake-value")
state = self._run_and_get_state()
self.assertEqual(state["fake-arg"], "fake-value")
def test_env_vars(self):
# First clear any global environment to have a clean slate for this test
self.runCmd("settings clear target.env-vars")
self.runCmd("settings clear target.unset-env-vars")
def var(i):
return "LLDB_TEST_QEMU_VAR%d" % i
# Set some variables in the host environment.
for i in range(4):
os.environ[var(i)] = "from host"
def cleanup():
for i in range(4):
del os.environ[var(i)]
self.addTearDownHook(cleanup)
# Set some emulator-only variables.
self.set_emulator_setting("emulator-env-vars", "%s='emulator only'" % var(4))
# And through the platform setting.
self.set_emulator_setting(
"target-env-vars",
"%s='from platform' %s='from platform'" % (var(1), var(2)),
)
target = self._create_target()
info = target.GetLaunchInfo()
env = info.GetEnvironment()
# Platform settings should trump host values. Emulator-only variables
# should not be visible.
self.assertEqual(env.Get(var(0)), "from host")
self.assertEqual(env.Get(var(1)), "from platform")
self.assertEqual(env.Get(var(2)), "from platform")
self.assertEqual(env.Get(var(3)), "from host")
self.assertIsNone(env.Get(var(4)))
# Finally, make some launch_info specific changes.
env.Set(var(2), "from target", True)
env.Unset(var(3))
info.SetEnvironment(env, False)
# Now check everything. Launch info changes should trump everything, but
# only for the target environment -- the emulator should still get the
# host values.
state = self._run_and_get_state(target, info)
for i in range(4):
self.assertEqual(state["environ"][var(i)], "from host")
self.assertEqual(state["environ"][var(4)], "emulator only")
self.assertEqual(
state["environ"]["QEMU_SET_ENV"],
"%s=from platform,%s=from target" % (var(1), var(2)),
)
self.assertEqual(
state["environ"]["QEMU_UNSET_ENV"],
"%s,%s,QEMU_SET_ENV,QEMU_UNSET_ENV" % (var(3), var(4)),
)
def test_arg0(self):
target = self._create_target()
self.runCmd("settings set target.arg0 ARG0")
state = self._run_and_get_state(target)
self.assertEqual(state["program"], self.getBuildArtifact())
self.assertEqual(state["0"], "ARG0")
def test_sysroot(self):
sysroot = self.getBuildArtifact("sysroot")
self.runCmd("platform select qemu-user --sysroot %s" % sysroot)
state = self._run_and_get_state()
self.assertEqual(state["environ"]["QEMU_LD_PREFIX"], sysroot)
self.assertIn("QEMU_LD_PREFIX", state["environ"]["QEMU_UNSET_ENV"].split(","))
|