7 changes: 4 additions & 3 deletions lldb/source/API/SBTarget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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());
Expand Down Expand Up @@ -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();
Expand All @@ -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");
Expand Down Expand Up @@ -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;
}

Expand Down
6 changes: 1 addition & 5 deletions lldb/source/Commands/CommandObjectProcess.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -205,11 +205,7 @@ class CommandObjectProcessLaunch : public CommandObjectProcessLaunchOrAttach {
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(
Expand Down
9 changes: 1 addition & 8 deletions lldb/source/Host/freebsd/Host.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down
11 changes: 2 additions & 9 deletions lldb/source/Host/linux/Host.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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");
Expand Down
73 changes: 30 additions & 43 deletions lldb/source/Host/macosx/Host.mm
Original file line number Diff line number Diff line change
Expand Up @@ -431,33 +431,16 @@ repeat with the_window in (get windows)\n\
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(" -- ");
Expand Down Expand Up @@ -641,14 +624,7 @@ repeat with the_window in (get windows)\n\
#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()) {
Expand Down Expand Up @@ -770,7 +746,7 @@ DataExtractor data(arg_data.GetBytes(), arg_data_size,
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;
Expand All @@ -785,7 +761,7 @@ DataExtractor data(arg_data.GetBytes(), arg_data_size,
llvm::Triple::MacOSX);
}

proc_env.AppendArgument(llvm::StringRef(cstr));
proc_env.insert(cstr);
}
return true;
}
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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]);
Expand All @@ -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]);
Expand Down
9 changes: 1 addition & 8 deletions lldb/source/Host/netbsd/Host.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
7 changes: 4 additions & 3 deletions lldb/source/Host/openbsd/Host.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
19 changes: 6 additions & 13 deletions lldb/source/Host/posix/ProcessLauncherPosixFork.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

Expand Down Expand Up @@ -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.
Expand All @@ -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) {
Expand All @@ -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

Expand Down
13 changes: 6 additions & 7 deletions lldb/source/Host/windows/Host.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
}
44 changes: 0 additions & 44 deletions lldb/source/Interpreter/Args.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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];
Expand Down
42 changes: 11 additions & 31 deletions lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 ||
Expand Down Expand Up @@ -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());
Expand Down Expand Up @@ -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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -478,26 +478,17 @@ static Status HandleFileAction(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;
Expand Down
8 changes: 4 additions & 4 deletions lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
2 changes: 1 addition & 1 deletion lldb/source/Plugins/Platform/POSIX/PlatformPOSIX.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ class PlatformPOSIX : public lldb_private::Platform {

const lldb::UnixSignalsSP &GetRemoteUnixSignals() override;

size_t GetEnvironment(lldb_private::StringList &environment) override;
lldb_private::Environment GetEnvironment() override;

bool IsConnected() const override;

Expand Down
8 changes: 4 additions & 4 deletions lldb/source/Plugins/Platform/Windows/PlatformWindows.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
2 changes: 1 addition & 1 deletion lldb/source/Plugins/Platform/Windows/PlatformWindows.h
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ class PlatformWindows : public Platform {

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 {}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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]) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ class GDBRemoteCommunicationClient : public GDBRemoteClientBase {
/// response was received.
//------------------------------------------------------------------
int SendEnvironmentPacket(char const *name_equal_value);
int SendEnvironment(const Environment &env);

int SendLaunchArchPacket(const char *arch);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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);
Expand Down
11 changes: 1 addition & 10 deletions lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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
Expand All @@ -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;
}
Expand Down
5 changes: 1 addition & 4 deletions lldb/source/Target/Platform.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
13 changes: 2 additions & 11 deletions lldb/source/Target/Process.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 = ");
Expand Down Expand Up @@ -529,7 +520,7 @@ Status ProcessLaunchCommandOptions::SetOptionValue(
break;

case 'v':
launch_info.GetEnvironmentEntries().AppendArgument(option_arg);
launch_info.GetEnvironment().insert(option_arg);
break;

default:
Expand Down
5 changes: 2 additions & 3 deletions lldb/source/Target/ProcessInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand All @@ -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,
Expand Down
63 changes: 24 additions & 39 deletions lldb/source/Target/Target.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3611,36 +3611,19 @@ class TargetOptionValueProperties : public OptionValueProperties {
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);
}
}
}
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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,
Expand Down
1 change: 1 addition & 0 deletions lldb/source/Utility/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ add_lldb_library(lldbUtility
DataBufferLLVM.cpp
DataEncoder.cpp
DataExtractor.cpp
Environment.cpp
FastDemangle.cpp
FileSpec.cpp
History.cpp
Expand Down
50 changes: 50 additions & 0 deletions lldb/source/Utility/Environment.cpp
Original file line number Diff line number Diff line change
@@ -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;
}
}
5 changes: 1 addition & 4 deletions lldb/tools/lldb-server/lldb-gdbserver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
6 changes: 6 additions & 0 deletions lldb/unittests/Host/HostTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"));
}
84 changes: 0 additions & 84 deletions lldb/unittests/Interpreter/TestArgs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}
1 change: 1 addition & 0 deletions lldb/unittests/Utility/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
add_lldb_unittest(UtilityTests
ArchSpecTest.cpp
ConstStringTest.cpp
EnvironmentTest.cpp
JSONTest.cpp
LogTest.cpp
NameMatchesTest.cpp
Expand Down
49 changes: 49 additions & 0 deletions lldb/unittests/Utility/EnvironmentTest.cpp
Original file line number Diff line number Diff line change
@@ -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]);
}
16 changes: 4 additions & 12 deletions lldb/unittests/tools/lldb-server/tests/TestClient.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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())
Expand All @@ -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";
Expand Down