]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
gdb: parse and set the inferior environment from core files
authorAndrew Burgess <aburgess@redhat.com>
Sat, 8 Jun 2024 10:06:02 +0000 (11:06 +0100)
committerAndrew Burgess <aburgess@redhat.com>
Tue, 24 Dec 2024 14:15:24 +0000 (14:15 +0000)
Extend the core file context parsing mechanism added in the previous
commit to also store the environment parsed from the core file.

This environment can then be injected into the inferior object.

The benefit of this is that when examining a core file in GDB, the
'show environment' command will now show the environment extracted
from a core file.

Consider this example:

  $ env -i GDB_TEST_VAR=FOO ./gen-core
  Segmentation fault (core dumped)
  $ gdb -c ./core.1669829
  ...
  [New LWP 1669829]
  Core was generated by `./gen-core'.
  Program terminated with signal SIGSEGV, Segmentation fault.
  #0  0x0000000000401111 in ?? ()
  (gdb) show environment
  GDB_TEST_VAR=foo
  (gdb)

There's a new test for this functionality.

gdb/arch-utils.c
gdb/arch-utils.h
gdb/corelow.c
gdb/linux-tdep.c
gdb/testsuite/gdb.base/corefile-exec-context.exp

index a2ed2a2c011810cbcb0e1aa524c1359010403892..3cc6d9912d5d7680105d43f280e198ec8a835f45 100644 (file)
@@ -1499,6 +1499,32 @@ gdbarch_initialized_p (gdbarch *arch)
   return arch->initialized_p;
 }
 
+/* See arch-utils.h.  */
+
+gdb_environ
+core_file_exec_context::environment () const
+{
+  gdb_environ e;
+
+  for (const auto &entry : m_environment)
+    {
+      char *eq = strchr (entry.get (), '=');
+
+      /* If there's no '=' character, then skip this entry.  */
+      if (eq == nullptr)
+       continue;
+
+      const char *value = eq + 1;
+      const char *var = entry.get ();
+
+      *eq = '\0';
+      e.set (var, value);
+      *eq = '=';
+    }
+
+  return e;
+}
+
 void _initialize_gdbarch_utils ();
 void
 _initialize_gdbarch_utils ()
index 00ec8476289d211a0e1a5b7e904bb45582707d70..cae036315e21d234647bedd287e08cd961ed2a08 100644 (file)
@@ -21,6 +21,7 @@
 #define GDB_ARCH_UTILS_H
 
 #include "gdbarch.h"
+#include "gdbsupport/environ.h"
 
 class frame_info_ptr;
 struct minimal_symbol;
@@ -88,9 +89,11 @@ struct core_file_exec_context
      found but not ARGV then use the no-argument constructor to create an
      empty context object.  */
   core_file_exec_context (gdb::unique_xmalloc_ptr<char> exec_name,
-                         std::vector<gdb::unique_xmalloc_ptr<char>> argv)
+                         std::vector<gdb::unique_xmalloc_ptr<char>> argv,
+                         std::vector<gdb::unique_xmalloc_ptr<char>> envp)
     : m_exec_name (std::move (exec_name)),
-      m_arguments (std::move (argv))
+      m_arguments (std::move (argv)),
+      m_environment (std::move (envp))
   {
     gdb_assert (m_exec_name != nullptr);
   }
@@ -115,6 +118,9 @@ struct core_file_exec_context
   const std::vector<gdb::unique_xmalloc_ptr<char>> &args () const
   { return m_arguments; }
 
+  /* Return the environment variables from this context.  */
+  gdb_environ environment () const;
+
 private:
 
   /* The executable filename as reported in the core file.  Can be nullptr
@@ -124,6 +130,9 @@ private:
   /* List of arguments.  Doesn't include argv[0] which is the executable
      name, for this look at m_exec_name field.  */
   std::vector<gdb::unique_xmalloc_ptr<char>> m_arguments;
+
+  /* List of environment strings.  */
+  std::vector<gdb::unique_xmalloc_ptr<char>> m_environment;
 };
 
 /* Default implementation of gdbarch_displaced_hw_singlestep.  */
index 97ca48f5f2e5039ac575b9962a5a8415675ba3b9..7100399ae4e65f28a4c92c8c516830cd08d05aec 100644 (file)
@@ -1073,6 +1073,9 @@ core_target_open (const char *arg, int from_tty)
        argv.push_back (a.get ());
       gdb::array_view<char * const> view (argv.data (), argv.size ());
       current_inferior ()->set_args (view);
+
+      /* And now copy the environment.  */
+      current_inferior ()->environment = ctx.environment ();
     }
   else
     {
index 8d506fe3ce19337082a62e111c6ff42a89da0afa..6d90e89e3c41cd8c4d601a388b91057a154303ae 100644 (file)
@@ -2074,8 +2074,7 @@ linux_corefile_parse_exec_context_1 (struct gdbarch *gdbarch, bfd *cbfd)
      be pointing at the first environment string.  */
   ptr += ptr_bytes;
 
-  /* Parse the environment strings.  Nothing is done with this yet, but
-     will be in a later commit.  */
+  /* Parse the environment strings.  */
   std::vector<gdb::unique_xmalloc_ptr<char>> environment;
   while ((v = deref (ptr)) != 0)
     {
@@ -2092,7 +2091,8 @@ linux_corefile_parse_exec_context_1 (struct gdbarch *gdbarch, bfd *cbfd)
     return {};
 
   return core_file_exec_context (std::move (execfn),
-                                std::move (arguments));
+                                std::move (arguments),
+                                std::move (environment));
 }
 
 /* Parse and return execution context details from core file CBFD.  */
index b18a8104779d062e4bb851d7a6bda7a451725931..ac97754fe7136f367956e4c8b88cdf7e40c31366 100644 (file)
@@ -100,3 +100,66 @@ gdb_test_multiple "core-file $corefile_2" "load core file with args" {
 # Also, the argument list should be available through 'show args'.
 gdb_test "show args" \
     "Argument list to give program being debugged when it is started is \"$args\"\\."
+
+# Find the name of an environment variable that is not set.
+set env_var_base "GDB_TEST_ENV_VAR_"
+set env_var_name ""
+
+for { set i 0 } { $i < 10 } { incr i } {
+    set tmp_name ${env_var_base}${i}
+    if { ! [info exists ::env($tmp_name)] } {
+       set env_var_name $tmp_name
+       break
+    }
+}
+
+if { $env_var_name eq "" } {
+    unsupported "couldn't find suitable environment variable name"
+    return -1
+}
+
+# Generate a core file with this environment variable set.
+set env_var_value "TEST VALUE"
+save_vars { ::env($env_var_name) } {
+    setenv $env_var_name $env_var_value
+
+    set corefile [core_find $binfile {} $args]
+    if {$corefile == ""} {
+       untested "unable to create corefile"
+       return 0
+    }
+}
+set corefile_3 "$binfile.2.core"
+remote_exec build "mv $corefile $corefile_3"
+
+# Restart, load the core file, and check the environment variable
+# shows up.
+clean_restart $binfile
+
+# Check for environment variable VAR_NAME in the environment, its
+# value should be VAR_VALUE.
+proc check_for_env_var { var_name var_value } {
+    set saw_var false
+    gdb_test_multiple "show environment" "" {
+       -re "^$var_name=$var_value\r\n" {
+           set saw_var true
+           exp_continue
+       }
+       -re "^\[^\r\n\]*\r\n" {
+           exp_continue
+       }
+       -re "^$::gdb_prompt $" {
+       }
+    }
+    return $saw_var
+}
+
+gdb_assert { ![check_for_env_var $env_var_name $env_var_value] } \
+    "environment variable is not set before core file load"
+
+gdb_test "core-file $corefile_3" \
+    "Core was generated by `[string_to_regexp $binfile] $args'\\.\r\n.*" \
+    "load core file for environment test"
+
+gdb_assert { [check_for_env_var $env_var_name $env_var_value] } \
+    "environment variable is set after core file load"