[lldb/test] Add ability to specify environment when spawning processes
authorPavel Labath <pavel@labath.sk>
Mon, 27 Sep 2021 12:12:29 +0000 (14:12 +0200)
committerPavel Labath <pavel@labath.sk>
Tue, 28 Sep 2021 12:13:50 +0000 (14:13 +0200)
We only had that ability for regular debugger launches. This meant that
it was not possible to use the normal dlopen patterns in attach tests.
This fixes that.

lldb/packages/Python/lldbsuite/test/lldbtest.py
lldb/test/API/functionalities/load_after_attach/TestLoadAfterAttach.py
lldb/test/API/functionalities/load_after_attach/main.cpp

index a899b1b..db350ae 100644 (file)
@@ -360,7 +360,7 @@ class _BaseProcess(object):
         """Returns process PID if has been launched already."""
 
     @abc.abstractmethod
-    def launch(self, executable, args):
+    def launch(self, executable, args, extra_env):
         """Launches new process with given executable and args."""
 
     @abc.abstractmethod
@@ -379,13 +379,19 @@ class _LocalProcess(_BaseProcess):
     def pid(self):
         return self._proc.pid
 
-    def launch(self, executable, args):
+    def launch(self, executable, args, extra_env):
+        env=None
+        if extra_env:
+            env = dict(os.environ)
+            env.update([kv.split("=", 1) for kv in extra_env])
+
         self._proc = Popen(
             [executable] + args,
             stdout=open(
                 os.devnull) if not self._trace_on else None,
             stdin=PIPE,
-            preexec_fn=lldbplatformutil.enable_attach)
+            preexec_fn=lldbplatformutil.enable_attach,
+            env=env)
 
     def terminate(self):
         if self._proc.poll() is None:
@@ -424,7 +430,7 @@ class _RemoteProcess(_BaseProcess):
     def pid(self):
         return self._pid
 
-    def launch(self, executable, args):
+    def launch(self, executable, args, extra_env):
         if self._install_remote:
             src_path = executable
             dst_path = lldbutil.join_remote_paths(
@@ -450,6 +456,9 @@ class _RemoteProcess(_BaseProcess):
         launch_info.AddSuppressFileAction(1, False, True)
         launch_info.AddSuppressFileAction(2, False, True)
 
+        if extra_env:
+            launch_info.SetEnvironmentEntries(extra_env, True)
+
         err = lldb.remote_platform.Launch(launch_info)
         if err.Fail():
             raise Exception(
@@ -952,13 +961,13 @@ class Base(unittest2.TestCase):
             del p
         del self.subprocesses[:]
 
-    def spawnSubprocess(self, executable, args=[], install_remote=True):
+    def spawnSubprocess(self, executable, args=[], extra_env=None, install_remote=True):
         """ Creates a subprocess.Popen object with the specified executable and arguments,
             saves it in self.subprocesses, and returns the object.
         """
         proc = _RemoteProcess(
             install_remote) if lldb.remote_platform else _LocalProcess(self.TraceOn())
-        proc.launch(executable, args)
+        proc.launch(executable, args, extra_env=extra_env)
         self.subprocesses.append(proc)
         return proc
 
index 0e9b3c4..3b261e6 100644 (file)
@@ -6,6 +6,7 @@ from lldbsuite.test import lldbutil
 class TestCase(TestBase):
 
     mydir = TestBase.compute_mydir(__file__)
+    NO_DEBUG_INFO_TESTCASE = True
 
     @skipIfRemote
     def test_load_after_attach(self):
@@ -17,18 +18,19 @@ class TestCase(TestBase):
         exe = self.getBuildArtifact("a.out")
         lib = self.getBuildArtifact(lib_name)
 
+        target = self.dbg.CreateTarget(exe)
+        environment = self.registerSharedLibrariesWithTarget(target, ["lib_b"])
+
         # Spawn a new process.
         # use realpath to workaround llvm.org/pr48376
         # Pass path to solib for dlopen to properly locate the library.
-        popen = self.spawnSubprocess(os.path.realpath(exe), args = [os.path.realpath(lib)])
-        pid = popen.pid
+        popen = self.spawnSubprocess(os.path.realpath(exe), extra_env=environment)
 
         # Attach to the spawned process.
-        self.runCmd("process attach -p " + str(pid))
-
-        target = self.dbg.GetSelectedTarget()
-        process = target.GetProcess()
-        self.assertTrue(process, PROCESS_IS_VALID)
+        error = lldb.SBError()
+        process = target.AttachToProcessWithID(self.dbg.GetListener(),
+                popen.pid, error)
+        self.assertSuccess(error)
 
         # Continue until first breakpoint.
         breakpoint1 = self.target().BreakpointCreateBySourceRegex(
index d63bd7e..97eea20 100644 (file)
@@ -1,30 +1,10 @@
-#ifdef _WIN32
-#include <Windows.h>
-#else
-#include <dlfcn.h>
-#include <unistd.h>
-#endif
-
-#include <assert.h>
-#include <stdio.h>
+#include "dylib.h"
+#include <cassert>
+#include <cstdio>
 #include <thread>
 #include <chrono>
 
-// We do not use the dylib.h implementation, because
-// we need to pass full path to the dylib.
-void* dylib_open(const char* full_path) {
-#ifdef _WIN32
-  return LoadLibraryA(full_path);
-#else
-  return dlopen(full_path, RTLD_LAZY);
-#endif
-}
-
 int main(int argc, char* argv[]) {
-  assert(argc == 2 && "argv[1] must be the full path to lib_b library");
-  const char* dylib_full_path= argv[1];
-  printf("Using dylib at: %s\n", dylib_full_path);
-
   // Wait until debugger is attached.
   int main_thread_continue = 0;
   int i = 0;
@@ -38,7 +18,7 @@ int main(int argc, char* argv[]) {
   assert(i != timeout && "timed out waiting for debugger");
 
   // dlopen the 'liblib_b.so' shared library.
-  void* dylib_handle = dylib_open(dylib_full_path);
+  void* dylib_handle = dylib_open("lib_b");
   assert(dylib_handle && "dlopen failed");
 
   return i; // break after dlopen