summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPavel Labath <labath@google.com>2018-01-10 11:57:31 +0000
committerPavel Labath <labath@google.com>2018-01-10 11:57:31 +0000
commit62930e57eb9e753951a79df790aa18caaac27690 (patch)
tree62856989fcd998c294b16849aa9d006ad2a7204b
parenta7ec090eaacd393a41c70197b248702d0e999da0 (diff)
downloadbcm5719-llvm-62930e57eb9e753951a79df790aa18caaac27690.tar.gz
bcm5719-llvm-62930e57eb9e753951a79df790aa18caaac27690.zip
Add Utility/Environment class for handling... environments
Summary: There was some confusion in the code about how to represent process environment. Most of the code (ab)used the Args class for this purpose, but some of it used a more basic StringList class instead. In either case, the fact that the underlying abstraction did not provide primitive operations for the typical environment operations meant that even a simple operation like checking for an environment variable value was several lines of code. This patch adds a separate Environment class, which is essentialy a llvm::StringMap<std::string> in disguise. To standard StringMap functionality, it adds a couple of new functions, which are specific to the environment use case: - (most important) envp conversion for passing into execve() and likes. Instead of trying to maintain a constantly up-to-date envp view, it provides a function which creates a envp view on demand, with the expectation that this will be called as the very last thing before handing the value to the system function. - insert(StringRef KeyEqValue) - splits KeyEqValue into (key, value) pair and inserts it into the environment map. - compose(value_type KeyValue) - takes a map entry and converts in back into "KEY=VALUE" representation. With this interface most of the environment-manipulating code becomes one-liners. The only tricky part was maintaining compatibility in SBLaunchInfo, which expects that the environment entries are accessible by index and that the returned const char* is backed by the launch info object (random access into maps is hard and the map stores the entry in a deconstructed form, so we cannot just return a .c_str() value). To solve this, I have the SBLaunchInfo convert the environment into the "envp" form, and use it to answer the environment queries. Extra code is added to make sure the envp version is always in sync. (This also improves the layering situation as Args was in the Interpreter module whereas Environment is in Utility.) Reviewers: zturner, davide, jingham, clayborg Subscribers: emaste, lldb-commits, mgorny Differential Revision: https://reviews.llvm.org/D41359 llvm-svn: 322174
-rw-r--r--lldb/include/lldb/API/SBLaunchInfo.h9
-rw-r--r--lldb/include/lldb/Host/Host.h4
-rw-r--r--lldb/include/lldb/Interpreter/Args.h39
-rw-r--r--lldb/include/lldb/Target/Platform.h2
-rw-r--r--lldb/include/lldb/Target/ProcessInfo.h8
-rw-r--r--lldb/include/lldb/Target/Target.h5
-rw-r--r--lldb/include/lldb/Utility/Environment.h95
-rw-r--r--lldb/packages/Python/lldbsuite/test/python_api/sblaunchinfo/TestSBLaunchInfo.py31
-rw-r--r--lldb/source/API/SBLaunchInfo.cpp47
-rw-r--r--lldb/source/API/SBPlatform.cpp5
-rw-r--r--lldb/source/API/SBProcess.cpp2
-rw-r--r--lldb/source/API/SBTarget.cpp7
-rw-r--r--lldb/source/Commands/CommandObjectProcess.cpp6
-rw-r--r--lldb/source/Host/freebsd/Host.cpp9
-rw-r--r--lldb/source/Host/linux/Host.cpp11
-rw-r--r--lldb/source/Host/macosx/Host.mm73
-rw-r--r--lldb/source/Host/netbsd/Host.cpp9
-rw-r--r--lldb/source/Host/openbsd/Host.cpp7
-rw-r--r--lldb/source/Host/posix/ProcessLauncherPosixFork.cpp19
-rw-r--r--lldb/source/Host/windows/Host.cpp13
-rw-r--r--lldb/source/Interpreter/Args.cpp44
-rw-r--r--lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp42
-rw-r--r--lldb/source/Plugins/Platform/MacOSX/PlatformiOSSimulatorCoreSimulatorSupport.mm25
-rw-r--r--lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp8
-rw-r--r--lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.h2
-rw-r--r--lldb/source/Plugins/Platform/Windows/PlatformWindows.cpp8
-rw-r--r--lldb/source/Plugins/Platform/Windows/PlatformWindows.h2
-rw-r--r--lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp11
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp6
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp9
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h1
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp5
-rw-r--r--lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp11
-rw-r--r--lldb/source/Plugins/StructuredData/DarwinLog/StructuredDataDarwinLog.cpp15
-rw-r--r--lldb/source/Target/Platform.cpp5
-rw-r--r--lldb/source/Target/Process.cpp13
-rw-r--r--lldb/source/Target/ProcessInfo.cpp5
-rw-r--r--lldb/source/Target/Target.cpp63
-rw-r--r--lldb/source/Utility/CMakeLists.txt1
-rw-r--r--lldb/source/Utility/Environment.cpp50
-rw-r--r--lldb/tools/lldb-server/lldb-gdbserver.cpp5
-rw-r--r--lldb/unittests/Host/HostTest.cpp6
-rw-r--r--lldb/unittests/Interpreter/TestArgs.cpp84
-rw-r--r--lldb/unittests/Utility/CMakeLists.txt1
-rw-r--r--lldb/unittests/Utility/EnvironmentTest.cpp49
-rw-r--r--lldb/unittests/tools/lldb-server/tests/TestClient.cpp16
46 files changed, 429 insertions, 459 deletions
diff --git a/lldb/include/lldb/API/SBLaunchInfo.h b/lldb/include/lldb/API/SBLaunchInfo.h
index 1cece235127..80eea7e4292 100644
--- a/lldb/include/lldb/API/SBLaunchInfo.h
+++ b/lldb/include/lldb/API/SBLaunchInfo.h
@@ -12,6 +12,10 @@
#include "lldb/API/SBDefines.h"
+namespace lldb_private {
+class SBLaunchInfoImpl;
+}
+
namespace lldb {
class SBPlatform;
@@ -141,11 +145,10 @@ protected:
friend class SBPlatform;
friend class SBTarget;
- lldb_private::ProcessLaunchInfo &ref();
-
const lldb_private::ProcessLaunchInfo &ref() const;
+ void set_ref(const lldb_private::ProcessLaunchInfo &info);
- ProcessLaunchInfoSP m_opaque_sp;
+ std::shared_ptr<lldb_private::SBLaunchInfoImpl> m_opaque_sp;
};
} // namespace lldb
diff --git a/lldb/include/lldb/Host/Host.h b/lldb/include/lldb/Host/Host.h
index f099c72381b..e0c81848de3 100644
--- a/lldb/include/lldb/Host/Host.h
+++ b/lldb/include/lldb/Host/Host.h
@@ -12,8 +12,8 @@
#include "lldb/Host/File.h"
#include "lldb/Host/HostThread.h"
+#include "lldb/Utility/Environment.h"
#include "lldb/Utility/FileSpec.h"
-#include "lldb/Utility/StringList.h"
#include "lldb/lldb-private-forward.h"
#include "lldb/lldb-private.h"
#include <cerrno>
@@ -242,7 +242,7 @@ public:
static bool OpenFileInExternalEditor(const FileSpec &file_spec,
uint32_t line_no);
- static size_t GetEnvironment(StringList &env);
+ static Environment GetEnvironment();
static std::unique_ptr<Connection>
CreateDefaultConnection(llvm::StringRef url);
diff --git a/lldb/include/lldb/Interpreter/Args.h b/lldb/include/lldb/Interpreter/Args.h
index 19d7ac41856..9bc862e04b3 100644
--- a/lldb/include/lldb/Interpreter/Args.h
+++ b/lldb/include/lldb/Interpreter/Args.h
@@ -21,6 +21,7 @@
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/StringRef.h"
// Project includes
+#include "lldb/Utility/Environment.h"
#include "lldb/Utility/Status.h"
#include "lldb/lldb-private-types.h"
#include "lldb/lldb-types.h"
@@ -95,6 +96,12 @@ public:
//------------------------------------------------------------------
~Args();
+ explicit Args(const Environment &env) : Args() {
+ SetArguments(const_cast<const char **>(env.getEnvp().get()));
+ }
+
+ explicit operator Environment() const { return GetConstArgumentVector(); }
+
//------------------------------------------------------------------
/// Dump all entries to the stream \a s using label \a label_name.
///
@@ -433,38 +440,6 @@ public:
static std::string EscapeLLDBCommandArgument(const std::string &arg,
char quote_char);
- //------------------------------------------------------------------
- /// Add or replace an environment variable with the given value.
- ///
- /// This command adds the environment variable if it is not already
- /// present using the given value. If the environment variable is
- /// already in the list, it replaces the first such occurrence
- /// with the new value.
- //------------------------------------------------------------------
- void AddOrReplaceEnvironmentVariable(llvm::StringRef env_var_name,
- llvm::StringRef new_value);
-
- /// Return whether a given environment variable exists.
- ///
- /// This command treats Args like a list of environment variables,
- /// as used in ProcessLaunchInfo. It treats each argument as
- /// an {env_var_name}={value} or an {env_var_name} entry.
- ///
- /// @param[in] env_var_name
- /// Specifies the name of the environment variable to check.
- ///
- /// @param[out] argument_index
- /// If non-null, then when the environment variable is found,
- /// the index of the argument position will be returned in
- /// the size_t pointed to by this argument.
- ///
- /// @return
- /// true if the specified env var name exists in the list in
- /// either of the above-mentioned formats; otherwise, false.
- //------------------------------------------------------------------
- bool ContainsEnvironmentVariable(llvm::StringRef env_var_name,
- size_t *argument_index = nullptr) const;
-
private:
size_t FindArgumentIndexForOption(Option *long_options,
int long_options_index) const;
diff --git a/lldb/include/lldb/Target/Platform.h b/lldb/include/lldb/Target/Platform.h
index 6288a3ab684..14a27928c01 100644
--- a/lldb/include/lldb/Target/Platform.h
+++ b/lldb/include/lldb/Target/Platform.h
@@ -633,7 +633,7 @@ public:
//----------------------------------------------------------------------
virtual Status Install(const FileSpec &src, const FileSpec &dst);
- virtual size_t GetEnvironment(StringList &environment);
+ virtual Environment GetEnvironment();
virtual bool GetFileExists(const lldb_private::FileSpec &file_spec);
diff --git a/lldb/include/lldb/Target/ProcessInfo.h b/lldb/include/lldb/Target/ProcessInfo.h
index 4077abf89ba..984202b9c2d 100644
--- a/lldb/include/lldb/Target/ProcessInfo.h
+++ b/lldb/include/lldb/Target/ProcessInfo.h
@@ -13,6 +13,7 @@
// LLDB headers
#include "lldb/Interpreter/Args.h"
#include "lldb/Utility/ArchSpec.h"
+#include "lldb/Utility/Environment.h"
#include "lldb/Utility/FileSpec.h"
namespace lldb_private {
@@ -81,9 +82,8 @@ public:
void SetArguments(char const **argv, bool first_arg_is_executable);
- Args &GetEnvironmentEntries() { return m_environment; }
-
- const Args &GetEnvironmentEntries() const { return m_environment; }
+ Environment &GetEnvironment() { return m_environment; }
+ const Environment &GetEnvironment() const { return m_environment; }
protected:
FileSpec m_executable;
@@ -92,7 +92,7 @@ protected:
// that differs from the resolved platform executable
// (which is in m_executable)
Args m_arguments; // All program arguments except argv[0]
- Args m_environment;
+ Environment m_environment;
uint32_t m_uid;
uint32_t m_gid;
ArchSpec m_arch;
diff --git a/lldb/include/lldb/Target/Target.h b/lldb/include/lldb/Target/Target.h
index a5d20006981..bc41765b402 100644
--- a/lldb/include/lldb/Target/Target.h
+++ b/lldb/include/lldb/Target/Target.h
@@ -115,9 +115,8 @@ public:
void SetRunArguments(const Args &args);
- size_t GetEnvironmentAsArgs(Args &env) const;
-
- void SetEnvironmentFromArgs(const Args &env);
+ Environment GetEnvironment() const;
+ void SetEnvironment(Environment env);
bool GetSkipPrologue() const;
diff --git a/lldb/include/lldb/Utility/Environment.h b/lldb/include/lldb/Utility/Environment.h
new file mode 100644
index 00000000000..79e413c2c80
--- /dev/null
+++ b/lldb/include/lldb/Utility/Environment.h
@@ -0,0 +1,95 @@
+//===-- Environment.h -------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_UTILITY_ENVIRONMENT_H
+#define LLDB_UTILITY_ENVIRONMENT_H
+
+#include "llvm/ADT/StringMap.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/FormatProviders.h"
+
+namespace lldb_private {
+
+class Environment : private llvm::StringMap<std::string> {
+ using Base = llvm::StringMap<std::string>;
+
+public:
+ class Envp {
+ public:
+ Envp(Envp &&RHS) = default;
+ Envp &operator=(Envp &&RHS) = default;
+
+ char *const *get() const { return Data; }
+ operator char *const *() const { return get(); }
+
+ private:
+ explicit Envp(const Environment &Env);
+ char *make_entry(llvm::StringRef Key, llvm::StringRef Value);
+ Envp(const Envp &) = delete;
+ Envp &operator=(const Envp &) = delete;
+ friend class Environment;
+
+ llvm::BumpPtrAllocator Allocator;
+ char **Data;
+ };
+
+ using Base::const_iterator;
+ using Base::iterator;
+ using Base::value_type;
+
+ using Base::begin;
+ using Base::clear;
+ using Base::count;
+ using Base::end;
+ using Base::erase;
+ using Base::find;
+ using Base::insert;
+ using Base::lookup;
+ using Base::size;
+ using Base::try_emplace;
+ using Base::operator[];
+
+ Environment() : Base() {}
+ Environment(const Environment &RHS) : Base(RHS) {}
+ Environment(Environment &&RHS) : Base(std::move(RHS)) {}
+ Environment(char *const *Env)
+ : Environment(const_cast<const char *const *>(Env)) {}
+ Environment(const char *const *Env);
+
+ Environment &operator=(Environment RHS) {
+ Base::operator=(std::move(RHS));
+ return *this;
+ }
+
+ std::pair<iterator, bool> insert(llvm::StringRef KeyEqValue) {
+ return insert(KeyEqValue.split('='));
+ }
+
+ void insert(const_iterator first, const_iterator last);
+
+ Envp getEnvp() const { return Envp(*this); }
+
+ static std::string compose(const value_type &KeyValue) {
+ return (KeyValue.first() + "=" + KeyValue.second).str();
+ }
+};
+
+} // namespace lldb_private
+
+namespace llvm {
+template <> struct format_provider<lldb_private::Environment> {
+ static void format(const lldb_private::Environment &Env, raw_ostream &Stream,
+ StringRef Style) {
+ for (const auto &KV : Env)
+ Stream << "env[" << KV.first() << "] = " << KV.second << "\n";
+ }
+};
+} // namespace llvm
+
+#endif // #ifndef LLDB_UTILITY_ENVIRONMENT_H
diff --git a/lldb/packages/Python/lldbsuite/test/python_api/sblaunchinfo/TestSBLaunchInfo.py b/lldb/packages/Python/lldbsuite/test/python_api/sblaunchinfo/TestSBLaunchInfo.py
new file mode 100644
index 00000000000..ee4a102fc14
--- /dev/null
+++ b/lldb/packages/Python/lldbsuite/test/python_api/sblaunchinfo/TestSBLaunchInfo.py
@@ -0,0 +1,31 @@
+"""
+Test SBLaunchInfo
+"""
+
+from __future__ import print_function
+
+
+from lldbsuite.test.lldbtest import *
+
+
+def lookup(info, key):
+ for i in range(info.GetNumEnvironmentEntries()):
+ KeyEqValue = info.GetEnvironmentEntryAtIndex(i)
+ Key, Value = KeyEqValue.split("=")
+ if Key == key:
+ return Value
+ return ""
+
+class TestSBLaunchInfo(TestBase):
+
+ mydir = TestBase.compute_mydir(__file__)
+ NO_DEBUG_INFO_TESTCASE = True
+
+ def test_environment_getset(self):
+ info = lldb.SBLaunchInfo(None)
+ info.SetEnvironmentEntries(["FOO=BAR"], False)
+ self.assertEquals(1, info.GetNumEnvironmentEntries())
+ info.SetEnvironmentEntries(["BAR=BAZ"], True)
+ self.assertEquals(2, info.GetNumEnvironmentEntries())
+ self.assertEquals("BAR", lookup(info, "FOO"))
+ self.assertEquals("BAZ", lookup(info, "BAR"))
diff --git a/lldb/source/API/SBLaunchInfo.cpp b/lldb/source/API/SBLaunchInfo.cpp
index 5f5afccee68..87396eb8c4c 100644
--- a/lldb/source/API/SBLaunchInfo.cpp
+++ b/lldb/source/API/SBLaunchInfo.cpp
@@ -16,8 +16,26 @@
using namespace lldb;
using namespace lldb_private;
+class lldb_private::SBLaunchInfoImpl : public ProcessLaunchInfo {
+public:
+ SBLaunchInfoImpl()
+ : ProcessLaunchInfo(), m_envp(GetEnvironment().getEnvp()) {}
+
+ const char *const *GetEnvp() const { return m_envp; }
+ void RegenerateEnvp() { m_envp = GetEnvironment().getEnvp(); }
+
+ SBLaunchInfoImpl &operator=(const ProcessLaunchInfo &rhs) {
+ ProcessLaunchInfo::operator=(rhs);
+ RegenerateEnvp();
+ return *this;
+ }
+
+private:
+ Environment::Envp m_envp;
+};
+
SBLaunchInfo::SBLaunchInfo(const char **argv)
- : m_opaque_sp(new ProcessLaunchInfo()) {
+ : m_opaque_sp(new SBLaunchInfoImpl()) {
m_opaque_sp->GetFlags().Reset(eLaunchFlagDebug | eLaunchFlagDisableASLR);
if (argv && argv[0])
m_opaque_sp->GetArguments().SetArguments(argv);
@@ -25,12 +43,14 @@ SBLaunchInfo::SBLaunchInfo(const char **argv)
SBLaunchInfo::~SBLaunchInfo() {}
-lldb_private::ProcessLaunchInfo &SBLaunchInfo::ref() { return *m_opaque_sp; }
-
const lldb_private::ProcessLaunchInfo &SBLaunchInfo::ref() const {
return *m_opaque_sp;
}
+void SBLaunchInfo::set_ref(const ProcessLaunchInfo &info) {
+ *m_opaque_sp = info;
+}
+
lldb::pid_t SBLaunchInfo::GetProcessID() { return m_opaque_sp->GetProcessID(); }
uint32_t SBLaunchInfo::GetUserID() { return m_opaque_sp->GetUserID(); }
@@ -83,23 +103,22 @@ void SBLaunchInfo::SetArguments(const char **argv, bool append) {
}
uint32_t SBLaunchInfo::GetNumEnvironmentEntries() {
- return m_opaque_sp->GetEnvironmentEntries().GetArgumentCount();
+ return m_opaque_sp->GetEnvironment().size();
}
const char *SBLaunchInfo::GetEnvironmentEntryAtIndex(uint32_t idx) {
- return m_opaque_sp->GetEnvironmentEntries().GetArgumentAtIndex(idx);
+ if (idx > GetNumEnvironmentEntries())
+ return nullptr;
+ return m_opaque_sp->GetEnvp()[idx];
}
void SBLaunchInfo::SetEnvironmentEntries(const char **envp, bool append) {
- if (append) {
- if (envp)
- m_opaque_sp->GetEnvironmentEntries().AppendArguments(envp);
- } else {
- if (envp)
- m_opaque_sp->GetEnvironmentEntries().SetArguments(envp);
- else
- m_opaque_sp->GetEnvironmentEntries().Clear();
- }
+ Environment env(envp);
+ if (append)
+ m_opaque_sp->GetEnvironment().insert(env.begin(), env.end());
+ else
+ m_opaque_sp->GetEnvironment() = env;
+ m_opaque_sp->RegenerateEnvp();
}
void SBLaunchInfo::Clear() { m_opaque_sp->Clear(); }
diff --git a/lldb/source/API/SBPlatform.cpp b/lldb/source/API/SBPlatform.cpp
index 7ec43f13021..d7715e44e46 100644
--- a/lldb/source/API/SBPlatform.cpp
+++ b/lldb/source/API/SBPlatform.cpp
@@ -416,7 +416,10 @@ SBError SBPlatform::Run(SBPlatformShellCommand &shell_command) {
SBError SBPlatform::Launch(SBLaunchInfo &launch_info) {
return ExecuteConnected([&](const lldb::PlatformSP &platform_sp) {
- return platform_sp->LaunchProcess(launch_info.ref());
+ ProcessLaunchInfo info = launch_info.ref();
+ Status error = platform_sp->LaunchProcess(info);
+ launch_info.set_ref(info);
+ return error;
});
}
diff --git a/lldb/source/API/SBProcess.cpp b/lldb/source/API/SBProcess.cpp
index e08a7f4b08e..6be9825624c 100644
--- a/lldb/source/API/SBProcess.cpp
+++ b/lldb/source/API/SBProcess.cpp
@@ -140,7 +140,7 @@ bool SBProcess::RemoteLaunch(char const **argv, char const **envp,
if (argv)
launch_info.GetArguments().AppendArguments(argv);
if (envp)
- launch_info.GetEnvironmentEntries().SetArguments(envp);
+ launch_info.GetEnvironment() = Environment(envp);
error.SetError(process_sp->Launch(launch_info));
} else {
error.SetErrorString("must be in eStateConnected to call RemoteLaunch");
diff --git a/lldb/source/API/SBTarget.cpp b/lldb/source/API/SBTarget.cpp
index 2c1c6bcac71..878f6edd5ca 100644
--- a/lldb/source/API/SBTarget.cpp
+++ b/lldb/source/API/SBTarget.cpp
@@ -290,7 +290,7 @@ SBProcess SBTarget::Launch(SBListener &listener, char const **argv,
if (argv)
launch_info.GetArguments().AppendArguments(argv);
if (envp)
- launch_info.GetEnvironmentEntries().SetArguments(envp);
+ launch_info.GetEnvironment() = Environment(envp);
if (listener.IsValid())
launch_info.SetListener(listener.GetSP());
@@ -340,7 +340,7 @@ SBProcess SBTarget::Launch(SBLaunchInfo &sb_launch_info, SBError &error) {
}
}
- lldb_private::ProcessLaunchInfo &launch_info = sb_launch_info.ref();
+ lldb_private::ProcessLaunchInfo launch_info = sb_launch_info.ref();
if (!launch_info.GetExecutableFile()) {
Module *exe_module = target_sp->GetExecutableModulePointer();
@@ -353,6 +353,7 @@ SBProcess SBTarget::Launch(SBLaunchInfo &sb_launch_info, SBError &error) {
launch_info.GetArchitecture() = arch_spec;
error.SetError(target_sp->Launch(launch_info, NULL));
+ sb_launch_info.set_ref(launch_info);
sb_process.SetSP(target_sp->GetProcessSP());
} else {
error.SetErrorString("SBTarget is invalid");
@@ -2195,7 +2196,7 @@ lldb::SBLaunchInfo SBTarget::GetLaunchInfo() const {
lldb::SBLaunchInfo launch_info(NULL);
TargetSP target_sp(GetSP());
if (target_sp)
- launch_info.ref() = m_opaque_sp->GetProcessLaunchInfo();
+ launch_info.set_ref(m_opaque_sp->GetProcessLaunchInfo());
return launch_info;
}
diff --git a/lldb/source/Commands/CommandObjectProcess.cpp b/lldb/source/Commands/CommandObjectProcess.cpp
index 9fbdd763054..c763fe51885 100644
--- a/lldb/source/Commands/CommandObjectProcess.cpp
+++ b/lldb/source/Commands/CommandObjectProcess.cpp
@@ -205,11 +205,7 @@ protected:
if (target->GetDisableSTDIO())
m_options.launch_info.GetFlags().Set(eLaunchFlagDisableSTDIO);
- Args environment;
- target->GetEnvironmentAsArgs(environment);
- if (environment.GetArgumentCount() > 0)
- m_options.launch_info.GetEnvironmentEntries().AppendArguments(
- environment);
+ m_options.launch_info.GetEnvironment() = target->GetEnvironment();
if (!target_settings_argv0.empty()) {
m_options.launch_info.GetArguments().AppendArgument(
diff --git a/lldb/source/Host/freebsd/Host.cpp b/lldb/source/Host/freebsd/Host.cpp
index 124a8a76013..37ed80575c8 100644
--- a/lldb/source/Host/freebsd/Host.cpp
+++ b/lldb/source/Host/freebsd/Host.cpp
@@ -243,14 +243,7 @@ bool Host::GetProcessInfo(lldb::pid_t pid, ProcessInstanceInfo &process_info) {
return false;
}
-size_t Host::GetEnvironment(StringList &env) {
- char **host_env = environ;
- char *env_entry;
- size_t i;
- for (i = 0; (env_entry = host_env[i]) != NULL; ++i)
- env.AppendString(env_entry);
- return i;
-}
+Environment Host::GetEnvironment() { return Environment(environ); }
Status Host::ShellExpandArguments(ProcessLaunchInfo &launch_info) {
return Status("unimplemented");
diff --git a/lldb/source/Host/linux/Host.cpp b/lldb/source/Host/linux/Host.cpp
index f43090eadf8..1edef7aceed 100644
--- a/lldb/source/Host/linux/Host.cpp
+++ b/lldb/source/Host/linux/Host.cpp
@@ -199,7 +199,7 @@ static bool GetProcessAndStatInfo(::pid_t pid,
while (!Rest.empty()) {
llvm::StringRef Var;
std::tie(Var, Rest) = Rest.split('\0');
- process_info.GetEnvironmentEntries().AppendArgument(Var);
+ process_info.GetEnvironment().insert(Var);
}
llvm::StringRef Arg0;
@@ -297,14 +297,7 @@ bool Host::GetProcessInfo(lldb::pid_t pid, ProcessInstanceInfo &process_info) {
return GetProcessAndStatInfo(pid, process_info, State, tracerpid);
}
-size_t Host::GetEnvironment(StringList &env) {
- char **host_env = environ;
- char *env_entry;
- size_t i;
- for (i = 0; (env_entry = host_env[i]) != NULL; ++i)
- env.AppendString(env_entry);
- return i;
-}
+Environment Host::GetEnvironment() { return Environment(environ); }
Status Host::ShellExpandArguments(ProcessLaunchInfo &launch_info) {
return Status("unimplemented");
diff --git a/lldb/source/Host/macosx/Host.mm b/lldb/source/Host/macosx/Host.mm
index 7359815fdf7..00be4f73a88 100644
--- a/lldb/source/Host/macosx/Host.mm
+++ b/lldb/source/Host/macosx/Host.mm
@@ -431,33 +431,16 @@ LaunchInNewTerminalWithAppleScript(const char *exe_path,
command.PutCString(" --disable-aslr");
// We are launching on this host in a terminal. So compare the environment on
- // the host
- // to what is supplied in the launch_info. Any items that aren't in the host
- // environment
- // need to be sent to darwin-debug. If we send all environment entries, we
- // might blow the
- // max command line length, so we only send user modified entries.
- const char **envp =
- launch_info.GetEnvironmentEntries().GetConstArgumentVector();
-
- StringList host_env;
- const size_t host_env_count = Host::GetEnvironment(host_env);
-
- if (envp && envp[0]) {
- const char *env_entry;
- for (size_t env_idx = 0; (env_entry = envp[env_idx]) != NULL; ++env_idx) {
- bool add_entry = true;
- for (size_t i = 0; i < host_env_count; ++i) {
- const char *host_env_entry = host_env.GetStringAtIndex(i);
- if (strcmp(env_entry, host_env_entry) == 0) {
- add_entry = false;
- break;
- }
- }
- if (add_entry) {
- command.Printf(" --env='%s'", env_entry);
- }
- }
+ // the host to what is supplied in the launch_info. Any items that aren't in
+ // the host environment need to be sent to darwin-debug. If we send all
+ // environment entries, we might blow the max command line length, so we only
+ // send user modified entries.
+ Environment host_env = Host::GetEnvironment();
+
+ for (const auto &KV : launch_info.GetEnvironment()) {
+ auto host_entry = host_env.find(KV.first());
+ if (host_entry == host_env.end() || host_entry->second != KV.second)
+ command.Format(" --env='{0}'", Environment::compose(KV));
}
command.PutCString(" -- ");
@@ -641,14 +624,7 @@ bool Host::OpenFileInExternalEditor(const FileSpec &file_spec,
#endif // #if !defined(__arm__) && !defined(__arm64__) && !defined(__aarch64__)
}
-size_t Host::GetEnvironment(StringList &env) {
- char **host_env = *_NSGetEnviron();
- char *env_entry;
- size_t i;
- for (i = 0; (env_entry = host_env[i]) != NULL; ++i)
- env.AppendString(env_entry);
- return i;
-}
+Environment Host::GetEnvironment() { return Environment(*_NSGetEnviron()); }
static bool GetMacOSXProcessCPUType(ProcessInstanceInfo &process_info) {
if (process_info.ProcessIDIsValid()) {
@@ -770,7 +746,7 @@ static bool GetMacOSXProcessArgs(const ProcessInstanceInfoMatch *match_info_ptr,
proc_args.AppendArgument(llvm::StringRef(cstr));
}
- Args &proc_env = process_info.GetEnvironmentEntries();
+ Environment &proc_env = process_info.GetEnvironment();
while ((cstr = data.GetCStr(&offset))) {
if (cstr[0] == '\0')
break;
@@ -785,7 +761,7 @@ static bool GetMacOSXProcessArgs(const ProcessInstanceInfoMatch *match_info_ptr,
llvm::Triple::MacOSX);
}
- proc_env.AppendArgument(llvm::StringRef(cstr));
+ proc_env.insert(cstr);
}
return true;
}
@@ -939,6 +915,17 @@ static void PackageXPCArguments(xpc_object_t message, const char *prefix,
}
}
+static void PackageXPCEnvironment(xpc_object_t message, llvm::StringRef prefix,
+ const Environment &env) {
+ xpc_dictionary_set_int64(message, (prefix + "Count").str().c_str(),
+ env.size());
+ size_t i = 0;
+ for (const auto &KV : env) {
+ xpc_dictionary_set_string(message, (prefix + llvm::Twine(i)).str().c_str(),
+ Environment::compose(KV).c_str());
+ }
+}
+
/*
A valid authorizationRef means that
- there is the LaunchUsingXPCRightName rights in the /etc/authorization
@@ -1141,8 +1128,8 @@ static Status LaunchProcessXPC(const char *exe_path,
PackageXPCArguments(message, LauncherXPCServiceArgPrefxKey,
launch_info.GetArguments());
- PackageXPCArguments(message, LauncherXPCServiceEnvPrefxKey,
- launch_info.GetEnvironmentEntries());
+ PackageXPCEnvironment(message, LauncherXPCServiceEnvPrefxKey,
+ launch_info.GetEnvironment());
// Posix spawn stuff.
xpc_dictionary_set_int64(message, LauncherXPCServiceCPUTypeKey,
@@ -1356,8 +1343,7 @@ static Status LaunchProcessPosixSpawn(const char *exe_path,
const char *tmp_argv[2];
char *const *argv = const_cast<char *const *>(
launch_info.GetArguments().GetConstArgumentVector());
- char *const *envp = const_cast<char *const *>(
- launch_info.GetEnvironmentEntries().GetConstArgumentVector());
+ Environment::Envp envp = launch_info.GetEnvironment().getEnvp();
if (argv == NULL) {
// posix_spawn gets very unhappy if it doesn't have at least the program
// name in argv[0]. One of the side affects I have noticed is the
@@ -1425,7 +1411,8 @@ static Status LaunchProcessPosixSpawn(const char *exe_path,
"error: {0}, ::posix_spawnp(pid => {1}, path = '{2}', "
"file_actions = {3}, "
"attr = {4}, argv = {5}, envp = {6} )",
- error, result_pid, exe_path, &file_actions, &attr, argv, envp);
+ error, result_pid, exe_path, &file_actions, &attr, argv,
+ envp.get());
if (log) {
for (int ii = 0; argv[ii]; ++ii)
LLDB_LOG(log, "argv[{0}] = '{1}'", ii, argv[ii]);
@@ -1441,7 +1428,7 @@ static Status LaunchProcessPosixSpawn(const char *exe_path,
LLDB_LOG(log,
"error: {0}, ::posix_spawnp ( pid => {1}, path = '{2}', "
"file_actions = NULL, attr = {3}, argv = {4}, envp = {5} )",
- error, result_pid, exe_path, &attr, argv, envp);
+ error, result_pid, exe_path, &attr, argv, envp.get());
if (log) {
for (int ii = 0; argv[ii]; ++ii)
LLDB_LOG(log, "argv[{0}] = '{1}'", ii, argv[ii]);
diff --git a/lldb/source/Host/netbsd/Host.cpp b/lldb/source/Host/netbsd/Host.cpp
index d927f95f067..8f7d53d857a 100644
--- a/lldb/source/Host/netbsd/Host.cpp
+++ b/lldb/source/Host/netbsd/Host.cpp
@@ -48,14 +48,7 @@ extern char **environ;
using namespace lldb;
using namespace lldb_private;
-size_t Host::GetEnvironment(StringList &env) {
- char **host_env = environ;
- char *env_entry;
- size_t i;
- for (i = 0; (env_entry = host_env[i]) != NULL; ++i)
- env.AppendString(env_entry);
- return i;
-}
+Environment Host::GetEnvironment() { return Environment(environ); }
static bool GetNetBSDProcessArgs(const ProcessInstanceInfoMatch *match_info_ptr,
ProcessInstanceInfo &process_info) {
diff --git a/lldb/source/Host/openbsd/Host.cpp b/lldb/source/Host/openbsd/Host.cpp
index 0535256b9aa..207c7d32773 100644
--- a/lldb/source/Host/openbsd/Host.cpp
+++ b/lldb/source/Host/openbsd/Host.cpp
@@ -45,16 +45,17 @@ extern char **environ;
using namespace lldb;
using namespace lldb_private;
-size_t Host::GetEnvironment(StringList &env) {
+Environment Host::GetEnvironment() {
+ Environment env;
char *v;
char **var = environ;
for (; var != NULL && *var != NULL; ++var) {
v = strchr(*var, (int)'-');
if (v == NULL)
continue;
- env.AppendString(v);
+ env.insert(v);
}
- return env.GetSize();
+ return env;
}
static bool
diff --git a/lldb/source/Host/posix/ProcessLauncherPosixFork.cpp b/lldb/source/Host/posix/ProcessLauncherPosixFork.cpp
index ac1d9011c2b..046cd250393 100644
--- a/lldb/source/Host/posix/ProcessLauncherPosixFork.cpp
+++ b/lldb/source/Host/posix/ProcessLauncherPosixFork.cpp
@@ -38,17 +38,12 @@
using namespace lldb;
using namespace lldb_private;
-static void FixupEnvironment(Args &env) {
+static void FixupEnvironment(Environment &env) {
#ifdef __ANDROID__
// If there is no PATH variable specified inside the environment then set the
// path to /system/bin. It is required because the default path used by
// execve() is wrong on android.
- static const char *path = "PATH=";
- for (auto &entry : env.entries()) {
- if (entry.ref.startswith(path))
- return;
- }
- env.AppendArgument(llvm::StringRef("PATH=/system/bin"));
+ env.try_emplace("PATH", "/system/bin");
#endif
}
@@ -132,9 +127,9 @@ static void LLVM_ATTRIBUTE_NORETURN ChildFunc(int error_fd,
ExitWithError(error_fd, "chdir");
DisableASLRIfRequested(error_fd, info);
- Args env = info.GetEnvironmentEntries();
+ Environment env = info.GetEnvironment();
FixupEnvironment(env);
- const char **envp = env.GetConstArgumentVector();
+ Environment::Envp envp = env.getEnvp();
// Clear the signal mask to prevent the child from being affected by
// any masking done by the parent.
@@ -159,8 +154,7 @@ static void LLVM_ATTRIBUTE_NORETURN ChildFunc(int error_fd,
}
// Execute. We should never return...
- execve(argv[0], const_cast<char *const *>(argv),
- const_cast<char *const *>(envp));
+ execve(argv[0], const_cast<char *const *>(argv), envp);
#if defined(__linux__)
if (errno == ETXTBSY) {
@@ -177,8 +171,7 @@ static void LLVM_ATTRIBUTE_NORETURN ChildFunc(int error_fd,
// this state should clear up quickly, wait a while and then give it one
// more go.
usleep(50000);
- execve(argv[0], const_cast<char *const *>(argv),
- const_cast<char *const *>(envp));
+ execve(argv[0], const_cast<char *const *>(argv), envp);
}
#endif
diff --git a/lldb/source/Host/windows/Host.cpp b/lldb/source/Host/windows/Host.cpp
index 4458ce25e60..53834822404 100644
--- a/lldb/source/Host/windows/Host.cpp
+++ b/lldb/source/Host/windows/Host.cpp
@@ -258,13 +258,12 @@ Status Host::ShellExpandArguments(ProcessLaunchInfo &launch_info) {
return error;
}
-size_t Host::GetEnvironment(StringList &env) {
+Environment Host::GetEnvironment() {
+ Environment env;
// The environment block on Windows is a contiguous buffer of NULL terminated
- // strings,
- // where the end of the environment block is indicated by two consecutive
- // NULLs.
+ // strings, where the end of the environment block is indicated by two
+ // consecutive NULLs.
LPWCH environment_block = ::GetEnvironmentStringsW();
- env.Clear();
while (*environment_block != L'\0') {
std::string current_var;
auto current_var_size = wcslen(environment_block) + 1;
@@ -273,9 +272,9 @@ size_t Host::GetEnvironment(StringList &env) {
continue;
}
if (current_var[0] != '=')
- env.AppendString(current_var);
+ env.insert(current_var);
environment_block += current_var_size;
}
- return env.GetSize();
+ return env;
}
diff --git a/lldb/source/Interpreter/Args.cpp b/lldb/source/Interpreter/Args.cpp
index 07e5191f898..8a651a42809 100644
--- a/lldb/source/Interpreter/Args.cpp
+++ b/lldb/source/Interpreter/Args.cpp
@@ -900,50 +900,6 @@ uint32_t Args::StringToGenericRegister(llvm::StringRef s) {
return result;
}
-void Args::AddOrReplaceEnvironmentVariable(llvm::StringRef env_var_name,
- llvm::StringRef new_value) {
- if (env_var_name.empty())
- return;
-
- // Build the new entry.
- std::string var_string(env_var_name);
- if (!new_value.empty()) {
- var_string += "=";
- var_string += new_value;
- }
-
- size_t index = 0;
- if (ContainsEnvironmentVariable(env_var_name, &index)) {
- ReplaceArgumentAtIndex(index, var_string);
- return;
- }
-
- // We didn't find it. Append it instead.
- AppendArgument(var_string);
-}
-
-bool Args::ContainsEnvironmentVariable(llvm::StringRef env_var_name,
- size_t *argument_index) const {
- // Validate args.
- if (env_var_name.empty())
- return false;
-
- // Check each arg to see if it matches the env var name.
- for (auto arg : llvm::enumerate(m_entries)) {
- llvm::StringRef name, value;
- std::tie(name, value) = arg.value().ref.split('=');
- if (name != env_var_name)
- continue;
-
- if (argument_index)
- *argument_index = arg.index();
- return true;
- }
-
- // We didn't find a match.
- return false;
-}
-
size_t Args::FindArgumentIndexForOption(Option *long_options,
int long_options_index) const {
char short_buffer[3];
diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp
index b04d72f755f..8e031680214 100644
--- a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp
+++ b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp
@@ -1282,14 +1282,8 @@ PlatformDarwin::GetResumeCountForLaunchInfo(ProcessLaunchInfo &launch_info) {
// /bin/sh re-exec's itself as /bin/bash requiring another resume.
// But it only does this if the COMMAND_MODE environment variable
// is set to "legacy".
- const char **envp =
- launch_info.GetEnvironmentEntries().GetConstArgumentVector();
- if (envp != NULL) {
- for (int i = 0; envp[i] != NULL; i++) {
- if (strcmp(envp[i], "COMMAND_MODE=legacy") == 0)
- return 2;
- }
- }
+ if (launch_info.GetEnvironment().lookup("COMMAND_MODE") == "legacy")
+ return 2;
return 1;
} else if (strcmp(shell_name, "csh") == 0 ||
strcmp(shell_name, "tcsh") == 0 ||
@@ -1667,25 +1661,13 @@ bool PlatformDarwin::GetOSVersion(uint32_t &major, uint32_t &minor,
if (process && strstr(GetPluginName().GetCString(), "-simulator")) {
lldb_private::ProcessInstanceInfo proc_info;
if (Host::GetProcessInfo(process->GetID(), proc_info)) {
- Args &env = proc_info.GetEnvironmentEntries();
- const size_t n = env.GetArgumentCount();
- const llvm::StringRef k_runtime_version("SIMULATOR_RUNTIME_VERSION=");
- const llvm::StringRef k_dyld_root_path("DYLD_ROOT_PATH=");
- std::string dyld_root_path;
-
- for (size_t i = 0; i < n; ++i) {
- const char *env_cstr = env.GetArgumentAtIndex(i);
- if (env_cstr) {
- llvm::StringRef env_str(env_cstr);
- if (env_str.consume_front(k_runtime_version)) {
- if (Args::StringToVersion(env_str, major, minor, update))
- return true;
- } else if (env_str.consume_front(k_dyld_root_path)) {
- dyld_root_path = env_str;
- }
- }
- }
+ const Environment &env = proc_info.GetEnvironment();
+
+ if (Args::StringToVersion(env.lookup("SIMULATOR_RUNTIME_VERSION"), major,
+ minor, update))
+ return true;
+ std::string dyld_root_path = env.lookup("DYLD_ROOT_PATH");
if (!dyld_root_path.empty()) {
dyld_root_path += "/System/Library/CoreServices/SystemVersion.plist";
ApplePropertyList system_version_plist(dyld_root_path.c_str());
@@ -1756,14 +1738,12 @@ PlatformDarwin::LaunchProcess(lldb_private::ProcessLaunchInfo &launch_info) {
// LLDB *not* to muck with the OS_ACTIVITY_DT_MODE flag when they
// specifically want it unset.
const char *disable_env_var = "IDE_DISABLED_OS_ACTIVITY_DT_MODE";
- auto &env_vars = launch_info.GetEnvironmentEntries();
- if (!env_vars.ContainsEnvironmentVariable(llvm::StringRef(disable_env_var))) {
+ auto &env_vars = launch_info.GetEnvironment();
+ if (!env_vars.count(disable_env_var)) {
// We want to make sure that OS_ACTIVITY_DT_MODE is set so that
// we get os_log and NSLog messages mirrored to the target process
// stderr.
- if (!env_vars.ContainsEnvironmentVariable(
- llvm::StringRef("OS_ACTIVITY_DT_MODE")))
- env_vars.AppendArgument(llvm::StringRef("OS_ACTIVITY_DT_MODE=enable"));
+ env_vars.try_emplace("OS_ACTIVITY_DT_MODE", "enable");
}
// Let our parent class do the real launching.
diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformiOSSimulatorCoreSimulatorSupport.mm b/lldb/source/Plugins/Platform/MacOSX/PlatformiOSSimulatorCoreSimulatorSupport.mm
index 7bd37683d2f..4516a66ee8c 100644
--- a/lldb/source/Plugins/Platform/MacOSX/PlatformiOSSimulatorCoreSimulatorSupport.mm
+++ b/lldb/source/Plugins/Platform/MacOSX/PlatformiOSSimulatorCoreSimulatorSupport.mm
@@ -478,26 +478,17 @@ CoreSimulatorSupport::Device::Spawn(ProcessLaunchInfo &launch_info) {
[options setObject:args_array forKey:kSimDeviceSpawnArguments];
}
- if (launch_info.GetEnvironmentEntries().GetArgumentCount()) {
- const Args &envs(launch_info.GetEnvironmentEntries());
- NSMutableDictionary *env_dict = [[NSMutableDictionary alloc] init];
- for (size_t idx = 0; idx < envs.GetArgumentCount(); idx++) {
- llvm::StringRef arg_sr(envs.GetArgumentAtIndex(idx));
- auto first_eq = arg_sr.find('=');
- if (first_eq == llvm::StringRef::npos)
- continue;
- llvm::StringRef key = arg_sr.substr(0, first_eq);
- llvm::StringRef value = arg_sr.substr(first_eq + 1);
-
- NSString *key_ns = [NSString stringWithUTF8String:key.str().c_str()];
- NSString *value_ns = [NSString stringWithUTF8String:value.str().c_str()];
-
- [env_dict setValue:value_ns forKey:key_ns];
- }
+ NSMutableDictionary *env_dict = [[NSMutableDictionary alloc] init];
+
+ for (const auto &KV : launch_info.GetEnvironment()) {
+ NSString *key_ns = [NSString stringWithUTF8String:KV.first().str().c_str()];
+ NSString *value_ns = [NSString stringWithUTF8String:KV.second.c_str()];
- [options setObject:env_dict forKey:kSimDeviceSpawnEnvironment];
+ [env_dict setValue:value_ns forKey:key_ns];
}
+ [options setObject:env_dict forKey:kSimDeviceSpawnEnvironment];
+
Status error;
File stdin_file;
File stdout_file;
diff --git a/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp b/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp
index d45a54ee249..35bed7ad214 100644
--- a/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp
+++ b/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp
@@ -658,13 +658,13 @@ bool PlatformPOSIX::GetRemoteOSBuildString(std::string &s) {
return false;
}
-size_t PlatformPOSIX::GetEnvironment(StringList &env) {
+Environment PlatformPOSIX::GetEnvironment() {
if (IsRemote()) {
if (m_remote_platform_sp)
- return m_remote_platform_sp->GetEnvironment(env);
- return 0;
+ return m_remote_platform_sp->GetEnvironment();
+ return Environment();
}
- return Host::GetEnvironment(env);
+ return Host::GetEnvironment();
}
bool PlatformPOSIX::GetRemoteOSKernelDescription(std::string &s) {
diff --git a/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.h b/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.h
index 93bebeb332c..774842810de 100644
--- a/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.h
+++ b/lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.h
@@ -85,7 +85,7 @@ public:
const lldb::UnixSignalsSP &GetRemoteUnixSignals() override;
- size_t GetEnvironment(lldb_private::StringList &environment) override;
+ lldb_private::Environment GetEnvironment() override;
bool IsConnected() const override;
diff --git a/lldb/source/Plugins/Platform/Windows/PlatformWindows.cpp b/lldb/source/Plugins/Platform/Windows/PlatformWindows.cpp
index 3535df0c65c..6dd5e90b43d 100644
--- a/lldb/source/Plugins/Platform/Windows/PlatformWindows.cpp
+++ b/lldb/source/Plugins/Platform/Windows/PlatformWindows.cpp
@@ -587,14 +587,14 @@ void PlatformWindows::GetStatus(Stream &strm) {
bool PlatformWindows::CanDebugProcess() { return true; }
-size_t PlatformWindows::GetEnvironment(StringList &env) {
+Environment PlatformWindows::GetEnvironment() {
if (IsRemote()) {
if (m_remote_platform_sp)
- return m_remote_platform_sp->GetEnvironment(env);
- return 0;
+ return m_remote_platform_sp->GetEnvironment();
+ return Environment();
}
- return Host::GetEnvironment(env);
+ return Host::GetEnvironment();
}
ConstString PlatformWindows::GetFullNameForDylib(ConstString basename) {
diff --git a/lldb/source/Plugins/Platform/Windows/PlatformWindows.h b/lldb/source/Plugins/Platform/Windows/PlatformWindows.h
index 9af42116680..3a15271c576 100644
--- a/lldb/source/Plugins/Platform/Windows/PlatformWindows.h
+++ b/lldb/source/Plugins/Platform/Windows/PlatformWindows.h
@@ -118,7 +118,7 @@ public:
bool CanDebugProcess() override;
- size_t GetEnvironment(StringList &env) override;
+ Environment GetEnvironment() override;
// FIXME not sure what the _sigtramp equivalent would be on this platform
void CalculateTrapHandlerSymbolNames() override {}
diff --git a/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp b/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp
index 759ec7fd1d2..6369435961b 100644
--- a/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp
+++ b/lldb/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp
@@ -423,16 +423,7 @@ Status PlatformRemoteGDBServer::LaunchProcess(ProcessLaunchInfo &launch_info) {
}
// Send the environment and the program + arguments after we connect
- const char **envp =
- launch_info.GetEnvironmentEntries().GetConstArgumentVector();
-
- if (envp) {
- const char *env_entry;
- for (int i = 0; (env_entry = envp[i]); ++i) {
- if (m_gdb_client.SendEnvironmentPacket(env_entry) != 0)
- break;
- }
- }
+ m_gdb_client.SendEnvironment(launch_info.GetEnvironment());
ArchSpec arch_spec = launch_info.GetArchitecture();
const char *arch_triple = arch_spec.GetTriple().str().c_str();
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp
index 949cf19db65..18d9631f6c3 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp
@@ -1206,11 +1206,7 @@ Status GDBRemoteCommunication::StartDebugserverProcess(
}
// Copy the current environment to the gdbserver/debugserver instance
- StringList env;
- if (Host::GetEnvironment(env)) {
- for (size_t i = 0; i < env.GetSize(); ++i)
- launch_info.GetEnvironmentEntries().AppendArgument(env[i]);
- }
+ launch_info.GetEnvironment() = Host::GetEnvironment();
// Close STDIN, STDOUT and STDERR.
launch_info.AppendCloseFileAction(STDIN_FILENO);
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
index 867f57c475c..b0785a687f5 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
@@ -822,6 +822,15 @@ int GDBRemoteCommunicationClient::SendArgumentsPacket(
return -1;
}
+int GDBRemoteCommunicationClient::SendEnvironment(const Environment &env) {
+ for (const auto &KV : env) {
+ int r = SendEnvironmentPacket(Environment::compose(KV).c_str());
+ if (r != 0)
+ return r;
+ }
+ return 0;
+}
+
int GDBRemoteCommunicationClient::SendEnvironmentPacket(
char const *name_equal_value) {
if (name_equal_value && name_equal_value[0]) {
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
index ba67b824639..45913157c29 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
@@ -121,6 +121,7 @@ public:
/// response was received.
//------------------------------------------------------------------
int SendEnvironmentPacket(char const *name_equal_value);
+ int SendEnvironment(const Environment &env);
int SendLaunchArchPacket(const char *arch);
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp
index 3cf6b8ac07b..f098b3068ff 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp
@@ -945,8 +945,7 @@ GDBRemoteCommunicationServerCommon::Handle_QEnvironment(
packet.SetFilePos(::strlen("QEnvironment:"));
const uint32_t bytes_left = packet.GetBytesLeft();
if (bytes_left > 0) {
- m_process_launch_info.GetEnvironmentEntries().AppendArgument(
- llvm::StringRef::withNullAsEmpty(packet.Peek()));
+ m_process_launch_info.GetEnvironment().insert(packet.Peek());
return SendOKResponse();
}
return SendErrorResponse(12);
@@ -960,7 +959,7 @@ GDBRemoteCommunicationServerCommon::Handle_QEnvironmentHexEncoded(
if (bytes_left > 0) {
std::string str;
packet.GetHexByteString(str);
- m_process_launch_info.GetEnvironmentEntries().AppendArgument(str);
+ m_process_launch_info.GetEnvironment().insert(str);
return SendOKResponse();
}
return SendErrorResponse(12);
diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
index 35d02c15ab8..44efcbe20ae 100644
--- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
@@ -888,16 +888,7 @@ Status ProcessGDBRemote::DoLaunch(Module *exe_module,
}
// Send the environment and the program + arguments after we connect
- const Args &environment = launch_info.GetEnvironmentEntries();
- if (environment.GetArgumentCount()) {
- size_t num_environment_entries = environment.GetArgumentCount();
- for (size_t i = 0; i < num_environment_entries; ++i) {
- const char *env_entry = environment.GetArgumentAtIndex(i);
- if (env_entry == NULL ||
- m_gdb_comm.SendEnvironmentPacket(env_entry) != 0)
- break;
- }
- }
+ m_gdb_comm.SendEnvironment(launch_info.GetEnvironment());
{
// Scope for the scoped timeout object
diff --git a/lldb/source/Plugins/StructuredData/DarwinLog/StructuredDataDarwinLog.cpp b/lldb/source/Plugins/StructuredData/DarwinLog/StructuredDataDarwinLog.cpp
index 8424b55ee69..89830f5ed63 100644
--- a/lldb/source/Plugins/StructuredData/DarwinLog/StructuredDataDarwinLog.cpp
+++ b/lldb/source/Plugins/StructuredData/DarwinLog/StructuredDataDarwinLog.cpp
@@ -1514,7 +1514,6 @@ Status StructuredDataDarwinLog::FilterLaunchInfo(ProcessLaunchInfo &launch_info,
SetGlobalEnableOptions(debugger_sp, options_sp);
}
- auto &env_vars = launch_info.GetEnvironmentEntries();
if (!options_sp->GetEchoToStdErr()) {
// The user doesn't want to see os_log/NSLog messages echo to stderr.
// That mechanism is entirely separate from the DarwinLog support.
@@ -1523,16 +1522,11 @@ Status StructuredDataDarwinLog::FilterLaunchInfo(ProcessLaunchInfo &launch_info,
// Here we need to strip out any OS_ACTIVITY_DT_MODE setting to prevent
// echoing of os_log()/NSLog() to stderr in the target program.
- size_t argument_index;
- if (env_vars.ContainsEnvironmentVariable(
- llvm::StringRef("OS_ACTIVITY_DT_MODE"), &argument_index))
- env_vars.DeleteArgumentAtIndex(argument_index);
+ launch_info.GetEnvironment().erase("OS_ACTIVITY_DT_MODE");
// We will also set the env var that tells any downstream launcher
// from adding OS_ACTIVITY_DT_MODE.
- env_vars.AddOrReplaceEnvironmentVariable(
- llvm::StringRef("IDE_DISABLED_OS_ACTIVITY_DT_MODE"),
- llvm::StringRef("1"));
+ launch_info.GetEnvironment()["IDE_DISABLED_OS_ACTIVITY_DT_MODE"] = "1";
}
// Set the OS_ACTIVITY_MODE env var appropriately to enable/disable
@@ -1545,10 +1539,7 @@ Status StructuredDataDarwinLog::FilterLaunchInfo(ProcessLaunchInfo &launch_info,
else
env_var_value = "default";
- if (env_var_value) {
- launch_info.GetEnvironmentEntries().AddOrReplaceEnvironmentVariable(
- llvm::StringRef("OS_ACTIVITY_MODE"), llvm::StringRef(env_var_value));
- }
+ launch_info.GetEnvironment()["OS_ACTIVITY_MODE"] = env_var_value;
return error;
}
diff --git a/lldb/source/Target/Platform.cpp b/lldb/source/Target/Platform.cpp
index 5d60bb79155..bd03fa7ec1e 100644
--- a/lldb/source/Target/Platform.cpp
+++ b/lldb/source/Target/Platform.cpp
@@ -1539,10 +1539,7 @@ lldb_private::Status OptionGroupPlatformCaching::SetOptionValue(
return error;
}
-size_t Platform::GetEnvironment(StringList &environment) {
- environment.Clear();
- return false;
-}
+Environment Platform::GetEnvironment() { return Environment(); }
const std::vector<ConstString> &Platform::GetTrapHandlerSymbolNames() {
if (!m_calculated_trap_handlers) {
diff --git a/lldb/source/Target/Process.cpp b/lldb/source/Target/Process.cpp
index 8fb149fab06..d54112ab5d8 100644
--- a/lldb/source/Target/Process.cpp
+++ b/lldb/source/Target/Process.cpp
@@ -307,16 +307,7 @@ void ProcessInstanceInfo::Dump(Stream &s, Platform *platform) const {
}
}
- const uint32_t envc = m_environment.GetArgumentCount();
- if (envc > 0) {
- for (uint32_t i = 0; i < envc; i++) {
- const char *env = m_environment.GetArgumentAtIndex(i);
- if (i < 10)
- s.Printf(" env[%u] = %s\n", i, env);
- else
- s.Printf("env[%u] = %s\n", i, env);
- }
- }
+ s.Format("{0}", m_environment);
if (m_arch.IsValid()) {
s.Printf(" arch = ");
@@ -529,7 +520,7 @@ Status ProcessLaunchCommandOptions::SetOptionValue(
break;
case 'v':
- launch_info.GetEnvironmentEntries().AppendArgument(option_arg);
+ launch_info.GetEnvironment().insert(option_arg);
break;
default:
diff --git a/lldb/source/Target/ProcessInfo.cpp b/lldb/source/Target/ProcessInfo.cpp
index 0d986bc7691..594a748d248 100644
--- a/lldb/source/Target/ProcessInfo.cpp
+++ b/lldb/source/Target/ProcessInfo.cpp
@@ -35,7 +35,7 @@ ProcessInfo::ProcessInfo(const char *name, const ArchSpec &arch,
void ProcessInfo::Clear() {
m_executable.Clear();
m_arguments.Clear();
- m_environment.Clear();
+ m_environment.clear();
m_uid = UINT32_MAX;
m_gid = UINT32_MAX;
m_arch.Clear();
@@ -59,8 +59,7 @@ void ProcessInfo::Dump(Stream &s, Platform *platform) const {
s << "Arguments:\n";
m_arguments.Dump(s);
- s << "Environment:\n";
- m_environment.Dump(s, "env");
+ s.Format("Environment:\n{0}", m_environment);
}
void ProcessInfo::SetExecutableFile(const FileSpec &exe_file,
diff --git a/lldb/source/Target/Target.cpp b/lldb/source/Target/Target.cpp
index fdc10cf4827..1464d4c999c 100644
--- a/lldb/source/Target/Target.cpp
+++ b/lldb/source/Target/Target.cpp
@@ -3611,36 +3611,19 @@ protected:
nullptr, idx, g_properties[idx].default_uint_value != 0)) {
PlatformSP platform_sp(m_target->GetPlatform());
if (platform_sp) {
- StringList env;
- if (platform_sp->GetEnvironment(env)) {
- OptionValueDictionary *env_dict =
- GetPropertyAtIndexAsOptionValueDictionary(nullptr,
- ePropertyEnvVars);
- if (env_dict) {
- const bool can_replace = false;
- const size_t envc = env.GetSize();
- for (size_t idx = 0; idx < envc; idx++) {
- const char *env_entry = env.GetStringAtIndex(idx);
- if (env_entry) {
- const char *equal_pos = ::strchr(env_entry, '=');
- ConstString key;
- // It is ok to have environment variables with no values
- const char *value = nullptr;
- if (equal_pos) {
- key.SetCStringWithLength(env_entry,
- equal_pos - env_entry);
- if (equal_pos[1])
- value = equal_pos + 1;
- } else {
- key.SetCString(env_entry);
- }
- // Don't allow existing keys to be replaced with ones we get
- // from the platform environment
- env_dict->SetValueForKey(
- key, OptionValueSP(new OptionValueString(value)),
- can_replace);
- }
- }
+ Environment env = platform_sp->GetEnvironment();
+ OptionValueDictionary *env_dict =
+ GetPropertyAtIndexAsOptionValueDictionary(nullptr,
+ ePropertyEnvVars);
+ if (env_dict) {
+ const bool can_replace = false;
+ for (const auto &KV : env) {
+ // Don't allow existing keys to be replaced with ones we get
+ // from the platform environment
+ env_dict->SetValueForKey(
+ ConstString(KV.first()),
+ OptionValueSP(new OptionValueString(KV.second.c_str())),
+ can_replace);
}
}
}
@@ -3906,15 +3889,19 @@ void TargetProperties::SetRunArguments(const Args &args) {
m_launch_info.GetArguments() = args;
}
-size_t TargetProperties::GetEnvironmentAsArgs(Args &env) const {
+Environment TargetProperties::GetEnvironment() const {
+ // TODO: Get rid of the Args intermediate step
+ Args env;
const uint32_t idx = ePropertyEnvVars;
- return m_collection_sp->GetPropertyAtIndexAsArgs(nullptr, idx, env);
+ m_collection_sp->GetPropertyAtIndexAsArgs(nullptr, idx, env);
+ return Environment(env);
}
-void TargetProperties::SetEnvironmentFromArgs(const Args &env) {
+void TargetProperties::SetEnvironment(Environment env) {
+ // TODO: Get rid of the Args intermediate step
const uint32_t idx = ePropertyEnvVars;
- m_collection_sp->SetPropertyAtIndexFromArgs(nullptr, idx, env);
- m_launch_info.GetEnvironmentEntries() = env;
+ m_collection_sp->SetPropertyAtIndexFromArgs(nullptr, idx, Args(env));
+ m_launch_info.GetEnvironment() = std::move(env);
}
bool TargetProperties::GetSkipPrologue() const {
@@ -4152,7 +4139,7 @@ void TargetProperties::SetProcessLaunchInfo(
m_launch_info = launch_info;
SetArg0(launch_info.GetArg0());
SetRunArguments(launch_info.GetArguments());
- SetEnvironmentFromArgs(launch_info.GetEnvironmentEntries());
+ SetEnvironment(launch_info.GetEnvironment());
const FileAction *input_file_action =
launch_info.GetFileActionForFD(STDIN_FILENO);
if (input_file_action) {
@@ -4193,9 +4180,7 @@ void TargetProperties::EnvVarsValueChangedCallback(void *target_property_ptr,
OptionValue *) {
TargetProperties *this_ =
reinterpret_cast<TargetProperties *>(target_property_ptr);
- Args args;
- if (this_->GetEnvironmentAsArgs(args))
- this_->m_launch_info.GetEnvironmentEntries() = args;
+ this_->m_launch_info.GetEnvironment() = this_->GetEnvironment();
}
void TargetProperties::InputPathValueChangedCallback(void *target_property_ptr,
diff --git a/lldb/source/Utility/CMakeLists.txt b/lldb/source/Utility/CMakeLists.txt
index 1a0fb6f86c5..89ae324e56a 100644
--- a/lldb/source/Utility/CMakeLists.txt
+++ b/lldb/source/Utility/CMakeLists.txt
@@ -48,6 +48,7 @@ add_lldb_library(lldbUtility
DataBufferLLVM.cpp
DataEncoder.cpp
DataExtractor.cpp
+ Environment.cpp
FastDemangle.cpp
FileSpec.cpp
History.cpp
diff --git a/lldb/source/Utility/Environment.cpp b/lldb/source/Utility/Environment.cpp
new file mode 100644
index 00000000000..ea20267a236
--- /dev/null
+++ b/lldb/source/Utility/Environment.cpp
@@ -0,0 +1,50 @@
+//===-- Environment.cpp -----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Utility/Environment.h"
+
+using namespace lldb_private;
+
+char *Environment::Envp::make_entry(llvm::StringRef Key,
+ llvm::StringRef Value) {
+ const size_t size = Key.size() + 1 /*=*/ + Value.size() + 1 /*\0*/;
+ char *Result = reinterpret_cast<char *>(
+ Allocator.Allocate(sizeof(char) * size, alignof(char)));
+ char *Next = Result;
+
+ Next = std::copy(Key.begin(), Key.end(), Next);
+ *Next++ = '=';
+ Next = std::copy(Value.begin(), Value.end(), Next);
+ *Next++ = '\0';
+
+ return Result;
+}
+
+Environment::Envp::Envp(const Environment &Env) {
+ Data = reinterpret_cast<char **>(
+ Allocator.Allocate(sizeof(char *) * (Env.size() + 1), alignof(char *)));
+ char **Next = Data;
+ for (const auto &KV : Env)
+ *Next++ = make_entry(KV.first(), KV.second);
+ *Next++ = nullptr;
+}
+
+Environment::Environment(const char *const *Env) {
+ if (!Env)
+ return;
+ while (*Env)
+ insert(*Env++);
+}
+
+void Environment::insert(const_iterator first, const_iterator last) {
+ while (first != last) {
+ try_emplace(first->first(), first->second);
+ ++first;
+ }
+}
diff --git a/lldb/tools/lldb-server/lldb-gdbserver.cpp b/lldb/tools/lldb-server/lldb-gdbserver.cpp
index 810cb92e4ff..c91a8a89e46 100644
--- a/lldb/tools/lldb-server/lldb-gdbserver.cpp
+++ b/lldb/tools/lldb-server/lldb-gdbserver.cpp
@@ -188,10 +188,7 @@ void handle_launch(GDBRemoteCommunicationServerLLGS &gdb_server, int argc,
exit(1);
}
info.SetWorkingDirectory(FileSpec(cwd, true));
-
- StringList env;
- Host::GetEnvironment(env);
- info.GetEnvironmentEntries() = Args(env);
+ info.GetEnvironment() = Host::GetEnvironment();
gdb_server.SetLaunchInfo(info);
diff --git a/lldb/unittests/Host/HostTest.cpp b/lldb/unittests/Host/HostTest.cpp
index 14a459ebf25..4fa874d33a0 100644
--- a/lldb/unittests/Host/HostTest.cpp
+++ b/lldb/unittests/Host/HostTest.cpp
@@ -20,3 +20,9 @@ TEST(Host, WaitStatusFormat) {
EXPECT_EQ("Exited with status 4",
formatv("{0}", WaitStatus{WaitStatus::Exit, 4}).str());
}
+
+TEST(Host, GetEnvironment) {
+ putenv(const_cast<char *>("LLDB_TEST_ENVIRONMENT_VAR=Host::GetEnvironment"));
+ ASSERT_EQ("Host::GetEnvironment",
+ Host::GetEnvironment().lookup("LLDB_TEST_ENVIRONMENT_VAR"));
+}
diff --git a/lldb/unittests/Interpreter/TestArgs.cpp b/lldb/unittests/Interpreter/TestArgs.cpp
index 2aaaab84e21..4f98dc4c503 100644
--- a/lldb/unittests/Interpreter/TestArgs.cpp
+++ b/lldb/unittests/Interpreter/TestArgs.cpp
@@ -276,87 +276,3 @@ TEST(ArgsTest, StringToScriptLanguage) {
&success));
EXPECT_FALSE(success);
}
-
-TEST(ArgsTest, StringToVersion) {}
-
-// Environment Variable Tests
-
-class EnvVarFixture: public ::testing::Test {
-protected:
-
- void SetUp() {
- args.AppendArgument(llvm::StringRef("Arg1=foo"));
- args.AppendArgument(llvm::StringRef("Arg2"));
- args.AppendArgument(llvm::StringRef("Arg3=bar"));
- }
-
- size_t GetIndexForEnvVar(llvm::StringRef envvar_name) {
- size_t argument_index = std::numeric_limits<size_t>::max();
- EXPECT_TRUE(args.ContainsEnvironmentVariable(envvar_name,
- &argument_index));
- EXPECT_LT(argument_index, args.GetArgumentCount());
- return argument_index;
- }
-
- Args args;
-};
-
-
-TEST_F(EnvVarFixture, TestContainsEnvironmentVariableNoValue) {
- EXPECT_TRUE(args.ContainsEnvironmentVariable(llvm::StringRef("Arg2")));
-}
-
-TEST_F(EnvVarFixture, TestContainsEnvironmentVariableWithValue) {
- EXPECT_TRUE(args.ContainsEnvironmentVariable(llvm::StringRef("Arg3")));
-}
-
-TEST_F(EnvVarFixture, TestContainsEnvironmentVariableNonExistentVariable) {
- auto nonexistent_envvar = llvm::StringRef("ThisEnvVarShouldNotExist");
- EXPECT_FALSE(args.ContainsEnvironmentVariable(nonexistent_envvar));
-}
-
-TEST_F(EnvVarFixture, TestReplaceEnvironmentVariableInitialNoValueWithNoValue) {
- auto envvar_name = llvm::StringRef("Arg2");
- auto argument_index = GetIndexForEnvVar(envvar_name);
-
- args.AddOrReplaceEnvironmentVariable(envvar_name, llvm::StringRef(""));
- EXPECT_TRUE(args.ContainsEnvironmentVariable(envvar_name));
- EXPECT_EQ(envvar_name, args.GetArgumentAtIndex(argument_index));
-}
-
-TEST_F(EnvVarFixture, TestReplaceEnvironmentVariableInitialNoValueWithValue) {
- auto envvar_name = llvm::StringRef("Arg2");
- auto argument_index = GetIndexForEnvVar(envvar_name);
-
- auto new_value = llvm::StringRef("NewValue");
- args.AddOrReplaceEnvironmentVariable(envvar_name, new_value);
- EXPECT_TRUE(args.ContainsEnvironmentVariable(envvar_name));
-
- std::stringstream stream;
- stream << envvar_name.str() << '=' << new_value.str();
- EXPECT_EQ(llvm::StringRef(stream.str()),
- args.GetArgumentAtIndex(argument_index));
-}
-
-TEST_F(EnvVarFixture, TestReplaceEnvironmentVariableInitialValueWithNoValue) {
- auto envvar_name = llvm::StringRef("Arg1");
- auto argument_index = GetIndexForEnvVar(envvar_name);
-
- args.AddOrReplaceEnvironmentVariable(envvar_name, llvm::StringRef(""));
- EXPECT_TRUE(args.ContainsEnvironmentVariable(envvar_name));
- EXPECT_EQ(envvar_name, args.GetArgumentAtIndex(argument_index));
-}
-
-TEST_F(EnvVarFixture, TestReplaceEnvironmentVariableInitialValueWithValue) {
- auto envvar_name = llvm::StringRef("Arg1");
- auto argument_index = GetIndexForEnvVar(envvar_name);
-
- auto new_value = llvm::StringRef("NewValue");
- args.AddOrReplaceEnvironmentVariable(envvar_name, new_value);
- EXPECT_TRUE(args.ContainsEnvironmentVariable(envvar_name));
-
- std::stringstream stream;
- stream << envvar_name.str() << '=' << new_value.str();
- EXPECT_EQ(llvm::StringRef(stream.str()),
- args.GetArgumentAtIndex(argument_index));
-}
diff --git a/lldb/unittests/Utility/CMakeLists.txt b/lldb/unittests/Utility/CMakeLists.txt
index 13f840af2bb..00a63efb0ec 100644
--- a/lldb/unittests/Utility/CMakeLists.txt
+++ b/lldb/unittests/Utility/CMakeLists.txt
@@ -1,6 +1,7 @@
add_lldb_unittest(UtilityTests
ArchSpecTest.cpp
ConstStringTest.cpp
+ EnvironmentTest.cpp
JSONTest.cpp
LogTest.cpp
NameMatchesTest.cpp
diff --git a/lldb/unittests/Utility/EnvironmentTest.cpp b/lldb/unittests/Utility/EnvironmentTest.cpp
new file mode 100644
index 00000000000..54915417033
--- /dev/null
+++ b/lldb/unittests/Utility/EnvironmentTest.cpp
@@ -0,0 +1,49 @@
+//===-- EnvironmentTest.cpp -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "gtest/gtest.h"
+
+#include "lldb/Utility/Environment.h"
+
+using namespace lldb_private;
+
+TEST(EnvironmentTest, EnvpConstruction) {
+ const char **Envp1 = nullptr;
+ EXPECT_EQ(0u, Environment(Envp1).size());
+
+ const char *Envp2[] = {"FOO=BAR", nullptr};
+ EXPECT_EQ("BAR", Environment(Envp2).lookup("FOO"));
+
+ const char *Envp3[] = {"FOO=BAR", "FOO=BAZ", nullptr};
+ EXPECT_EQ("BAR", Environment(Envp3).lookup("FOO"));
+
+ const char *Envp4[] = {"FOO=", "BAR", nullptr};
+ Environment Env4(Envp4);
+ ASSERT_EQ(2u, Env4.size());
+ EXPECT_EQ("", Environment(Envp4).find("FOO")->second);
+ EXPECT_EQ("", Environment(Envp4).find("BAR")->second);
+
+ const char *Envp5[] = {"FOO=BAR=BAZ", nullptr};
+ EXPECT_EQ("BAR=BAZ", Environment(Envp5).lookup("FOO"));
+}
+
+TEST(EnvironmentTest, EnvpConversion) {
+ std::string FOO_EQ_BAR("FOO=BAR");
+ std::string BAR_EQ_BAZ("BAR=BAZ");
+
+ Environment Env;
+ Env.insert(FOO_EQ_BAR);
+ Env.insert(BAR_EQ_BAZ);
+ Environment::Envp Envp = Env.getEnvp();
+ const char *const *Envp_ = Envp;
+
+ EXPECT_TRUE(FOO_EQ_BAR == Envp_[0] || FOO_EQ_BAR == Envp_[1]);
+ EXPECT_TRUE(BAR_EQ_BAZ == Envp_[0] || BAR_EQ_BAZ == Envp_[1]);
+ EXPECT_EQ(nullptr, Envp_[2]);
+}
diff --git a/lldb/unittests/tools/lldb-server/tests/TestClient.cpp b/lldb/unittests/tools/lldb-server/tests/TestClient.cpp
index 4653c2df1ce..f309e62dbd5 100644
--- a/lldb/unittests/tools/lldb-server/tests/TestClient.cpp
+++ b/lldb/unittests/tools/lldb-server/tests/TestClient.cpp
@@ -91,10 +91,7 @@ Expected<std::unique_ptr<TestClient>> TestClient::launchCustom(StringRef Log, Ar
ProcessLaunchInfo Info;
Info.SetArchitecture(arch_spec);
Info.SetArguments(args, true);
-
- StringList Env;
- Host::GetEnvironment(Env);
- Info.GetEnvironmentEntries() = Args(Env);
+ Info.GetEnvironment() = Host::GetEnvironment();
status = Host::LaunchProcess(Info);
if (status.Fail())
@@ -114,14 +111,9 @@ Expected<std::unique_ptr<TestClient>> TestClient::launchCustom(StringRef Log, Ar
}
Error TestClient::SetInferior(llvm::ArrayRef<std::string> inferior_args) {
- StringList env;
- Host::GetEnvironment(env);
- for (size_t i = 0; i < env.GetSize(); ++i) {
- if (SendEnvironmentPacket(env[i].c_str()) != 0) {
- return make_error<StringError>(
- formatv("Failed to set environment variable: {0}", env[i]).str(),
- inconvertibleErrorCode());
- }
+ if (SendEnvironment(Host::GetEnvironment()) != 0) {
+ return make_error<StringError>("Failed to set launch environment",
+ inconvertibleErrorCode());
}
std::stringstream command;
command << "A";
OpenPOWER on IntegriCloud