257 lines
9.2 KiB
Python
257 lines
9.2 KiB
Python
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(","))
|