Added the ability for a process to inherit the current host environment. This
was done as an settings variable in the process for now. We will eventually
move all environment stuff over to the target, but we will leave it with the
process for now. The default setting is for a process to inherit the host
environment. This can be disabled by setting the "inherit-env" setting to
false in the process.




git-svn-id: https://llvm.org/svn/llvm-project/llvdb/trunk@120862 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/lldb/Host/Host.h b/include/lldb/Host/Host.h
index 4f64695..91cfee4 100644
--- a/include/lldb/Host/Host.h
+++ b/include/lldb/Host/Host.h
@@ -340,6 +340,9 @@
 
     static void
     Backtrace (Stream &strm, uint32_t max_frames);
+    
+    static size_t
+    GetEnvironment (StringList &env);
 };
 
 } // namespace lldb_private
diff --git a/include/lldb/Target/Process.h b/include/lldb/Target/Process.h
index 6f6add0..edae73a 100644
--- a/include/lldb/Target/Process.h
+++ b/include/lldb/Target/Process.h
@@ -88,19 +88,11 @@
         m_run_args = args;
     }
 
+    void
+    GetHostEnvironmentIfNeeded ();
+
     size_t
-    GetEnvironmentAsArgs (Args &env) const
-    {
-        dictionary::const_iterator pos, end = m_env_vars.end();
-        for (pos = m_env_vars.begin(); pos != end; ++pos)
-        {
-            std::string env_var_equal_value (pos->first);
-            env_var_equal_value.append(1, '=');
-            env_var_equal_value.append (pos->second);
-            env.AppendArgument (env_var_equal_value.c_str());
-        }
-        return env.GetArgumentCount();
-    }
+    GetEnvironmentAsArgs (Args &env);
 
     const char *
     GetStandardInputPath () const
@@ -205,6 +197,9 @@
     EnvVarsVarName ();
 
     static const ConstString &
+    InheritHostEnvVarName ();
+
+    static const ConstString &
     InputPathVarName ();
 
     static const ConstString &
@@ -233,6 +228,8 @@
     ProcessPlugins m_plugin;
     bool m_disable_aslr;
     bool m_disable_stdio;
+    bool m_inherit_host_env;
+    bool m_got_host_env;
 };
 
 
diff --git a/source/Core/Debugger.cpp b/source/Core/Debugger.cpp
index 8884c3c..c96cbdf 100644
--- a/source/Core/Debugger.cpp
+++ b/source/Core/Debugger.cpp
@@ -1318,7 +1318,7 @@
     bool live_instance,
     const char *name
 ) :
-    InstanceSettings (owner, (name == NULL ? InstanceSettings::InvalidName().AsCString() : name), live_instance),
+    InstanceSettings (owner, name ? name : InstanceSettings::InvalidName().AsCString(), live_instance),
     m_term_width (80),
     m_prompt (),
     m_frame_format (),
diff --git a/source/Host/common/Host.cpp b/source/Host/common/Host.cpp
index c00c87f..527d20a 100644
--- a/source/Host/common/Host.cpp
+++ b/source/Host/common/Host.cpp
@@ -409,6 +409,14 @@
     // TODO: Is there a way to backtrace the current process on linux?
 }
 
+
+size_t
+Host::GetEnvironment (StringList &env)
+{
+    // TODO: Is there a way to the host environment for this process on linux?
+    return 0;
+}
+
 #endif
 
 struct HostThreadCreateInfo
diff --git a/source/Host/macosx/Host.mm b/source/Host/macosx/Host.mm
index b9e1171..8476b98 100644
--- a/source/Host/macosx/Host.mm
+++ b/source/Host/macosx/Host.mm
@@ -9,6 +9,7 @@
 
 #include "lldb/Host/Host.h"
 
+#include <crt_externs.h>
 #include <execinfo.h>
 #include <libproc.h>
 #include <stdio.h>
@@ -805,3 +806,15 @@
         ::unlink (backtrace_path);
     }
 }
+
+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;
+        
+}
diff --git a/source/Target/Process.cpp b/source/Target/Process.cpp
index 6e3ff89..3690ca1 100644
--- a/source/Target/Process.cpp
+++ b/source/Target/Process.cpp
@@ -358,6 +358,51 @@
     return -1;
 }
 
+
+void
+Process::ProcessInstanceSettings::GetHostEnvironmentIfNeeded ()
+{
+    if (m_inherit_host_env && !m_got_host_env)
+    {
+        m_got_host_env = true;
+        StringList host_env;
+        const size_t host_env_count = Host::GetEnvironment (host_env);
+        for (size_t idx=0; idx<host_env_count; idx++)
+        {
+            const char *env_entry = host_env.GetStringAtIndex (idx);
+            if (env_entry)
+            {
+                char *equal_pos = ::strchr(env_entry, '=');
+                if (equal_pos)
+                {
+                    std::string key (env_entry, equal_pos - env_entry);
+                    std::string value (equal_pos + 1);
+                    if (m_env_vars.find (key) == m_env_vars.end())
+                        m_env_vars[key] = value;
+                }
+            }
+        }
+    }
+}
+
+
+size_t
+Process::ProcessInstanceSettings::GetEnvironmentAsArgs (Args &env)
+{
+    GetHostEnvironmentIfNeeded ();
+
+    dictionary::const_iterator pos, end = m_env_vars.end();
+    for (pos = m_env_vars.begin(); pos != end; ++pos)
+    {
+        std::string env_var_equal_value (pos->first);
+        env_var_equal_value.append(1, '=');
+        env_var_equal_value.append (pos->second);
+        env.AppendArgument (env_var_equal_value.c_str());
+    }
+    return env.GetArgumentCount();
+}
+
+
 const char *
 Process::GetExitDescription ()
 {
@@ -2569,7 +2614,8 @@
 Process::SettingsController::SettingsController () :
     UserSettingsController ("process", Target::GetSettingsController())
 {
-    m_default_settings.reset (new ProcessInstanceSettings (*this, false,
+    m_default_settings.reset (new ProcessInstanceSettings (*this, 
+                                                           false,
                                                            InstanceSettings::GetDefaultName().AsCString()));
 }
 
@@ -2591,9 +2637,13 @@
 // class ProcessInstanceSettings
 //--------------------------------------------------------------
 
-ProcessInstanceSettings::ProcessInstanceSettings (UserSettingsController &owner, bool live_instance, 
-                                                  const char *name) :
-    InstanceSettings (owner, (name == NULL ? InstanceSettings::InvalidName().AsCString() : name), live_instance), 
+ProcessInstanceSettings::ProcessInstanceSettings
+(
+    UserSettingsController &owner, 
+    bool live_instance, 
+    const char *name
+) :
+    InstanceSettings (owner, name ? name : InstanceSettings::InvalidName().AsCString(), live_instance), 
     m_run_args (),
     m_env_vars (),
     m_input_path (),
@@ -2601,7 +2651,9 @@
     m_error_path (),
     m_plugin (),
     m_disable_aslr (true),
-    m_disable_stdio (false)
+    m_disable_stdio (false),
+    m_inherit_host_env (true),
+    m_got_host_env (false)
 {
     // CopyInstanceSettings is a pure virtual function in InstanceSettings; it therefore cannot be called
     // until the vtables for ProcessInstanceSettings are properly set up, i.e. AFTER all the initializers.
@@ -2658,6 +2710,7 @@
         m_plugin = rhs.m_plugin;
         m_disable_aslr = rhs.m_disable_aslr;
         m_disable_stdio = rhs.m_disable_stdio;
+        m_inherit_host_env = rhs.m_inherit_host_env;
     }
 
     return *this;
@@ -2677,7 +2730,10 @@
     if (var_name == RunArgsVarName())
         UserSettingsController::UpdateStringArrayVariable (op, index_value, m_run_args, value, err);
     else if (var_name == EnvVarsVarName())
+    {
+        GetHostEnvironmentIfNeeded ();
         UserSettingsController::UpdateDictionaryVariable (op, index_value, m_env_vars, value, err);
+    }
     else if (var_name == InputPathVarName())
         UserSettingsController::UpdateStringVariable (op, m_input_path, value, err);
     else if (var_name == OutputPathVarName())
@@ -2686,6 +2742,8 @@
         UserSettingsController::UpdateStringVariable (op, m_error_path, value, err);
     else if (var_name == PluginVarName())
         UserSettingsController::UpdateEnumVariable (entry.enum_values, (int *) &m_plugin, value, err);
+    else if (var_name == InheritHostEnvVarName())
+        UserSettingsController::UpdateBooleanVariable (op, m_inherit_host_env, value, err);
     else if (var_name == DisableASLRVarName())
         UserSettingsController::UpdateBooleanVariable (op, m_disable_aslr, value, err);
     else if (var_name == DisableSTDIOVarName ())
@@ -2727,6 +2785,8 @@
     }
     else if (var_name == EnvVarsVarName())
     {
+        GetHostEnvironmentIfNeeded ();
+
         if (m_env_vars.size() > 0)
         {
             std::map<std::string, std::string>::iterator pos;
@@ -2807,6 +2867,14 @@
 }
 
 const ConstString &
+ProcessInstanceSettings::InheritHostEnvVarName ()
+{
+    static ConstString g_name ("inherit-env");
+
+    return g_name;
+}
+
+const ConstString &
 ProcessInstanceSettings::InputPathVarName ()
 {
   static ConstString input_path_var_name ("input-path");
@@ -2878,16 +2946,17 @@
 SettingEntry
 Process::SettingsController::instance_settings_table[] =
 {
-  //{ "var-name",    var-type,              "default",      enum-table, init'd, hidden, "help-text"},
-    { "run-args",    eSetVarTypeArray,       NULL,          NULL,       false,  false,  "A list containing all the arguments to be passed to the executable when it is run." },
-    { "env-vars",    eSetVarTypeDictionary,  NULL,          NULL,       false,  false,  "A list of all the environment variables to be passed to the executable's environment, and their values." },
-    { "input-path",  eSetVarTypeString,      "/dev/stdin",  NULL,       false,  false,  "The file/path to be used by the executable program for reading its input." },
-    { "output-path", eSetVarTypeString,      "/dev/stdout", NULL,       false,  false,  "The file/path to be used by the executable program for writing its output." },
-    { "error-path",  eSetVarTypeString,      "/dev/stderr", NULL,       false,  false,  "The file/path to be used by the executable program for writings its error messages." },
-    { "plugin",      eSetVarTypeEnum,        NULL         , g_plugins,  false,  false,  "The plugin to be used to run the process." }, 
-    { "disable-aslr", eSetVarTypeBoolean,       "true",     NULL,       false,  false,  "Disable Address Space Layout Randomization (ASLR)" },
-    { "disable-stdio",eSetVarTypeBoolean,       "false",    NULL,       false,  false,  "Disable stdin/stdout for process (e.g. for a GUI application)" },
-    {  NULL, eSetVarTypeNone, NULL, NULL, 0, 0, NULL }
+  //{ "var-name",       var-type,              "default",       enum-table, init'd, hidden, "help-text"},
+    { "run-args",       eSetVarTypeArray,       NULL,           NULL,       false,  false,  "A list containing all the arguments to be passed to the executable when it is run." },
+    { "env-vars",       eSetVarTypeDictionary,  NULL,           NULL,       false,  false,  "A list of all the environment variables to be passed to the executable's environment, and their values." },
+    { "inherit-env",    eSetVarTypeBoolean,     "true",         NULL,       false,  false,  "Inherit the environment from the process that is running LLDB." },
+    { "input-path",     eSetVarTypeString,      "/dev/stdin",   NULL,       false,  false,  "The file/path to be used by the executable program for reading its input." },
+    { "output-path",    eSetVarTypeString,      "/dev/stdout",  NULL,       false,  false,  "The file/path to be used by the executable program for writing its output." },
+    { "error-path",     eSetVarTypeString,      "/dev/stderr",  NULL,       false,  false,  "The file/path to be used by the executable program for writings its error messages." },
+    { "plugin",         eSetVarTypeEnum,        NULL         ,  g_plugins,  false,  false,  "The plugin to be used to run the process." }, 
+    { "disable-aslr",   eSetVarTypeBoolean,     "true",         NULL,       false,  false,  "Disable Address Space Layout Randomization (ASLR)" },
+    { "disable-stdio",  eSetVarTypeBoolean,     "false",        NULL,       false,  false,  "Disable stdin/stdout for process (e.g. for a GUI application)" },
+    {  NULL,            eSetVarTypeNone,        NULL,           NULL,       false,  false,  NULL }
 };
 
 
diff --git a/source/Target/Target.cpp b/source/Target/Target.cpp
index da66ee2..0dd1da3 100644
--- a/source/Target/Target.cpp
+++ b/source/Target/Target.cpp
@@ -938,9 +938,13 @@
 // class TargetInstanceSettings
 //--------------------------------------------------------------
 
-TargetInstanceSettings::TargetInstanceSettings (UserSettingsController &owner, bool live_instance, 
-                                                const char *name) :
-    InstanceSettings (owner, (name == NULL ? InstanceSettings::InvalidName().AsCString() : name), live_instance)
+TargetInstanceSettings::TargetInstanceSettings
+(
+    UserSettingsController &owner, 
+    bool live_instance, 
+    const char *name
+) :
+    InstanceSettings (owner, name ? name : InstanceSettings::InvalidName().AsCString(), live_instance)
 {
     // CopyInstanceSettings is a pure virtual function in InstanceSettings; it therefore cannot be called
     // until the vtables for TargetInstanceSettings are properly set up, i.e. AFTER all the initializers.
diff --git a/source/Target/Thread.cpp b/source/Target/Thread.cpp
index 0db16fe..ed74764 100644
--- a/source/Target/Thread.cpp
+++ b/source/Target/Thread.cpp
@@ -1045,7 +1045,7 @@
 //--------------------------------------------------------------
 
 ThreadInstanceSettings::ThreadInstanceSettings (UserSettingsController &owner, bool live_instance, const char *name) :
-    InstanceSettings (owner, (name == NULL ? InstanceSettings::InvalidName().AsCString() : name), live_instance), 
+    InstanceSettings (owner, name ? name : InstanceSettings::InvalidName().AsCString(), live_instance), 
     m_avoid_regexp_ap (),
     m_trace_enabled (false)
 {
diff --git a/tools/debugserver/debugserver.xcodeproj/project.pbxproj b/tools/debugserver/debugserver.xcodeproj/project.pbxproj
index 01d487b..3e8a4f8 100644
--- a/tools/debugserver/debugserver.xcodeproj/project.pbxproj
+++ b/tools/debugserver/debugserver.xcodeproj/project.pbxproj
@@ -372,6 +372,7 @@
 			isa = PBXProject;
 			buildConfigurationList = 1DEB914E08733D8E0010E9CD /* Build configuration list for PBXProject "debugserver" */;
 			compatibilityVersion = "Xcode 3.1";
+			developmentRegion = English;
 			hasScannedForEncodings = 1;
 			knownRegions = (
 				English,