public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
From: "Peikes, Wendy" <Wendy.Peikes@netapp.com>
To: "gdb-patches@sourceware.org" <gdb-patches@sourceware.org>
Cc: "Peikes, Wendy" <Wendy.Peikes@netapp.com>
Subject: [PATCH] gdb: allow env var specifications in cmds 'set log', 'source', 'shell'
Date: Wed, 5 Oct 2022 23:19:27 +0000	[thread overview]
Message-ID: <BYAPR06MB61177EF001EF3D6D4B4C0720E55D9@BYAPR06MB6117.namprd06.prod.outlook.com> (raw)
Message-ID: <20221005231927.SYcBO16oPGI2wb_AyWSJx_qy2VNHh5eglcQRR-BPkxQ@z> (raw)
In-Reply-To: <BYAPR06MB611721469E1454F0CD94259DE55D9@BYAPR06MB6117.namprd06.prod.outlook.com>

[-- Attachment #1: Type: text/plain, Size: 7085 bytes --]


Rationale:

We at NetApp added a gdb feature allowing users to specify environment variable names when invoking gdb commands 'set logging file', 'source' & 'shell'.

This has been a big help especially in gdb macros since it allows macro writers to customize macro
behavior with environment var settings.

We've implemented this feature for the above three gdb commands but it can easily be  extended to other commands such as 'set substitute-path'

Usage example below.

setenv LOG_DIR /tmp
setenv SCRIPT_DIR "."

I've created a script 'macroScript' in the current directory ("."); it is referenced in the gdb session.

Now, run the gdb with the new env var feature:

gdbWithEnvVarFeature
....
GNU gdb (GDB) 9.1
Copyright (C) 2020 Free Software Foundation, Inc.
...

(gdb) shell head ${SCRIPT_DIR}/macroScript
define macro1
       echo macro1\n
end
define macro2
       echo macro2\n
end
macro1
macro2


gdb) source ${SCRIPT_DIR}/macroScript
macro1
macro2
(gdb) set logging file ${LOG_DIR}/logFile
(gdb) show logging file
The current logfile is "${LOG_DIR}/logFile".
(gdb) set logging on
Copying output to /tmp/logFile.
Copying debug output to /tmp/logFile.

(gdb) help set
Evaluate expression EXP and assign result to variable VAR.
Usage: set VAR = EXP
This uses assignment syntax appropriate for the current language
(VAR = EXP or VAR := EXP for example)
...
set architecture -- Set architecture of target.
...

(gdb) set var $i = 1

(gdb) printf "i:%d\n", $i
i:1
(gdb) shell tail ${LOG_DIR}/logFile
set watchdog -- Set watchdog timer.
set width -- Set number of characters where GDB should wrap lines of its output.
set write -- Set writing into executable and core files.
....
Command name abbreviations are allowed if unambiguous.
...
i:1

The patch to gdb9.1 is here; the changed lines are bracket by
#if defined ALLOW_ENV_VARS
#endif

patch:

*** fsf/cli-cmds.c      2022-09-22 15:59:17.238371000 -0700
--- modifiedFsf/cli-cmds.c      2022-09-22 16:29:59.506242000 -0700
***************
*** 660,665 ****
--- 660,744 ----
    script_from_file (stream, file);
  }

+ #define ALLOW_ENV_VARS 1
+ #if defined ALLOW_ENV_VARS
+ /* return true if s uses one or more env vars, specified as ${VARNAME} */
+ extern int
+ contains_env_var(const char *s0)
+ {
+   return s0 && (strlen (s0) > 1) && (strstr(s0, "${") != NULL) &&
+         (strchr(s0, '}') != NULL);
+ }
+
+ /* substitute_env_var - given a string, return a copy of the string with
+    env vars interpolated (if any).  env vars are recognized by the
+    syntax ...${VARNAME}...
+ */
+
+
+ extern char *
+ substitute_env_var(const char *s0, const char* msg, const int from_tty)
+ {
+     int slen, i;
+
+     char *s = xstrdup(s0);
+     slen = strlen(s);
+
+     for (i=0; i<slen; i++)
+       {
+       // find the lead-in for an environment variable
+       if ((s[i] == '$') && (s[i+1] == '{'))
+         {
+           char *endbrace = index(s+i+2, '}');
+           if (endbrace == NULL)
+             {
+               break;
+             }
+           else
+             {
+               int e = endbrace - s;
+
+               //    ...${X}...
+               //       ^  ^
+               //       i  e
+
+               int varname_len = e-(i+2);
+               char *varname = xstrndup(s+i+2, varname_len);
+               char *var_value = getenv(varname);
+               if (var_value == NULL)
+                 {
+                   if (from_tty)
+                   {
+                     fprintf_unfiltered
+                       (gdb_stderr,
+                        "Env var '%s' not set but used in '%s'.\n", varname, s0);
+                   }
+                   var_value = (char*)"";
+                 }
+               xfree(varname);
+               {
+                 // resize s to hold the substitution of varname
+                 int delta = strlen(var_value) - (e-i+1);
+
+                 // new_s may be shorter than s
+                 char *new_s = (char*) xmalloc(slen+delta+1);
+                 memcpy(new_s, s, i);
+                 memcpy(new_s+i, var_value, strlen(var_value));
+                 memmove(new_s+e+1+delta, s+e+1, slen-(e+1)+1);  // include \0
+
+                 // Skip ahead to new string at pos right after replacement so
+                 // we don't try recursive replacement so avoid infinite loops.
+                 i += strlen(var_value) - 1;  // -1 to offset i++ in for()
+                 slen += delta;
+                 xfree(s);
+                 s = new_s;
+               }
+             }
+         }
+       }
+     return s;
+ }
+ #endif // ALLOW_ENV_VARS
+
  /* Worker to perform the "source" command.
     Load script FILE.
     If SEARCH_PATH is non-zero, and the file isn't found in cwd,
***************
*** 672,677 ****
--- 751,764 ----
    if (file == NULL || *file == 0)
      error (_("source command requires file name of file to source."));

+ #if defined ALLOW_ENV_VARS
+   /* support env var interpolation in source filename in user/kernel/native*/
+   if (contains_env_var(file))
+     {
+       file = substitute_env_var(file, "'source'-ing", from_tty);
+     }
+ #endif
+
    gdb::optional<open_script> opened = find_and_open_script (file, search_path);
    if (!opened)
      {
***************
*** 844,849 ****
--- 931,945 ----
        if (!arg)
        execl (user_shell, p, (char *) 0);
        else
+ #if defined ALLOW_ENV_VARS
+       /* support interpolation of env vars in shell arg */
+       if (contains_env_var(arg))
+         {
+           char* newArg = substitute_env_var(arg, "exec'ing cmd", from_tty);
+           execl (user_shell, p, "-c", newArg, (char *) 0); //do as usual
+           xfree(newArg);
+         } else
+ #endif //ALLOW_ENV_VARS
        execl (user_shell, p, "-c", arg, (char *) 0);

        fprintf_unfiltered (gdb_stderr, "Cannot execute %s: %s\n", user_shell,

*** fsf/cli-logging.c   2022-09-22 15:59:17.250302000 -0700
--- modifiedFsf/cli-logging.c   2022-09-22 16:26:12.482260000 -0700
***************
*** 139,144 ****
--- 139,151 ----
      current_uiout->redirect (gdb_stdout);
  }

+ #define ALLOW_ENV_VARS 1
+ #if defined (ALLOW_ENV_VARS)
+ extern int contains_env_var(const char *s0);
+ extern char * substitute_env_var
+ (const char *s0, const char* msg, const int from_tty);
+ #endif
+
  static void
  set_logging_on (const char *args, int from_tty)
  {
***************
*** 149,154 ****
--- 156,173 ----
        xfree (logging_filename);
        logging_filename = xstrdup (rest);
      }
+
+ #if defined (ALLOW_ENV_VARS)
+   // recognize ${<envVariable>} in log file name
+   else
+     {
+       if (contains_env_var(logging_filename))
+       {
+         logging_filename = substitute_env_var
+           (logging_filename, "Logging to", from_tty);
+       }
+     }
+ #endif // ALLOW_ENV_VARS
    handle_redirections (from_tty);
  }



       reply	other threads:[~2022-10-05 23:19 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <BYAPR06MB6117A6A68D09026F27C310D4E54C9@BYAPR06MB6117.namprd06.prod.outlook.com>
     [not found] ` <BYAPR06MB611721469E1454F0CD94259DE55D9@BYAPR06MB6117.namprd06.prod.outlook.com>
2022-10-05 23:19   ` Peikes, Wendy [this message]
2022-10-05 23:19     ` Peikes, Wendy
2022-10-06 19:34     ` Keith Seitz
2022-10-26  0:25       ` Peikes, Wendy
2023-01-25 19:38         ` [RFC PATCH 0/2] Command expression evaulation substitution Keith Seitz
2023-01-25 19:38           ` [RFC PATCH 1/2] Add $_env convenience function Keith Seitz
2023-02-03 17:18             ` Andrew Burgess
2023-02-03 18:34               ` Keith Seitz
2023-01-25 19:38           ` [RFC PATCH 2/2] Allow and evaluate expressions in command arguments Keith Seitz
2023-02-03 17:22             ` Andrew Burgess
2023-02-03 18:49               ` Keith Seitz
2023-02-17 22:31             ` Pedro Alves
2023-01-25 20:21           ` [RFC PATCH 0/2] Command expression evaulation substitution Peikes, Wendy

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=BYAPR06MB61177EF001EF3D6D4B4C0720E55D9@BYAPR06MB6117.namprd06.prod.outlook.com \
    --to=wendy.peikes@netapp.com \
    --cc=gdb-patches@sourceware.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).