result);
return result;
}
+
+ Environment GetTargetEnvVars() {
+ Args args;
+ m_collection_sp->GetPropertyAtIndexAsArgs(nullptr, ePropertyTargetEnvVars,
+ args);
+ return Environment(args);
+ }
};
static PluginProperties &GetGlobalProperties() {
args.GetArgumentArrayRef().end());
}
+// Returns the emulator environment which result in the desired environment
+// being presented to the emulated process. We want to be careful about
+// preserving the host environment, as it may contain entries (LD_LIBRARY_PATH,
+// for example) needed for the operation of the emulator itself.
+static Environment ComputeLaunchEnvironment(Environment target,
+ Environment host) {
+ std::vector<std::string> set_env;
+ for (const auto &KV : target) {
+ // If the host value differs from the target (or is unset), then set it
+ // through QEMU_SET_ENV. Identical entries will be forwarded automatically.
+ auto host_it = host.find(KV.first());
+ if (host_it == host.end() || host_it->second != KV.second)
+ set_env.push_back(Environment::compose(KV));
+ }
+
+ std::vector<llvm::StringRef> unset_env;
+ for (const auto &KV : host) {
+ // If the target is missing some host entries, then unset them through
+ // QEMU_UNSET_ENV.
+ if (target.count(KV.first()) == 0)
+ unset_env.push_back(KV.first());
+ }
+
+ // The actual QEMU_(UN)SET_ENV variables should not be forwarded to the
+ // target.
+ if (!set_env.empty()) {
+ host["QEMU_SET_ENV"] = llvm::join(set_env, ",");
+ unset_env.push_back("QEMU_SET_ENV");
+ }
+ if (!unset_env.empty()) {
+ unset_env.push_back("QEMU_UNSET_ENV");
+ host["QEMU_UNSET_ENV"] = llvm::join(unset_env, ",");
+ }
+ return host;
+}
+
lldb::ProcessSP PlatformQemuUser::DebugProcess(ProcessLaunchInfo &launch_info,
Debugger &debugger,
Target &target, Status &error) {
get_arg_range(args));
launch_info.SetArguments(args, true);
+ launch_info.GetEnvironment() = ComputeLaunchEnvironment(
+ std::move(launch_info.GetEnvironment()), Host::GetEnvironment());
launch_info.SetLaunchInSeparateProcessGroup(true);
launch_info.GetFlags().Clear(eLaunchFlagDebug);
launch_info.SetMonitorProcessCallback(ProcessLaunchInfo::NoOpMonitorCallback,
process_sp->WaitForProcessToStop(llvm::None, nullptr, false, listener_sp);
return process_sp;
}
+
+Environment PlatformQemuUser::GetEnvironment() {
+ Environment env = Host::GetEnvironment();
+ for (const auto &KV : GetGlobalProperties().GetTargetEnvVars())
+ env[KV.first()] = KV.second;
+ return env;
+}
self.set_emulator_setting("architecture", self.getArchitecture())
self.set_emulator_setting("emulator-path", emulator)
- def _run_and_get_state(self):
+ def _create_target(self):
self.build()
exe = self.getBuildArtifact()
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.
- process = target.LaunchSimple(
- ["dump:" + self.getBuildArtifact("state.log")], None, None)
+ info.SetArguments(["dump:" + self.getBuildArtifact("state.log")], True)
+ error = lldb.SBError()
+ process = target.Launch(info, error)
+ self.assertSuccess(error)
self.assertIsNotNone(process)
self.assertEqual(process.GetState(), lldb.eStateExited)
self.assertEqual(process.GetExitStatus(), 0x47)
["dump:" + self.getBuildArtifact("state.log")])
def test_stdio_pty(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)
+ target = self._create_target()
- info = lldb.SBLaunchInfo([
+ 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,
self.set_emulator_setting("emulator-path",
self.getBuildArtifact("nonexistent.file"))
- self.build()
- exe = self.getBuildArtifact()
-
- error = lldb.SBError()
- target = self.dbg.CreateTarget(exe, '', 'qemu-user', False, error)
- self.assertEqual(target.GetPlatform().GetName(), "qemu-user")
- self.assertSuccess(error)
+ 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())
state = self._run_and_get_state()
self.assertEqual(state["fake-arg"], "fake-value")
+
+ def test_target_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)
+
+ # 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.
+ 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")
+
+ # Finally, make some launch_info specific changes.
+ env.Set(var(2), "from target", overwrite=True)
+ env.Unset(var(3))
+ info.SetEnvironment(env, append=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"]["QEMU_SET_ENV"],
+ "%s=from platform,%s=from target" % (var(1), var(2)))
+ self.assertEqual(state["environ"]["QEMU_UNSET_ENV"],
+ "%s,QEMU_SET_ENV,QEMU_UNSET_ENV" % var(3))