PING Re: [RFA] Ensure GDB printf command can print convenience var strings without a target.

Philippe Waroquiers philippe.waroquiers@skynet.be
Fri Jul 5 20:01:00 GMT 2019


Ping ?

Thanks

Philippe

On Mon, 2019-06-10 at 23:16 +0200, Philippe Waroquiers wrote:
> Without this patch, GDB printf command calls malloc on the target,
> writes the convenience var content to the target,
> re-reads the content from the target, and then locally printf the string.
> 
> This implies inferior calls, and does not work when there is no inferior,
> or when the inferior is a core dump.
> 
> With this patch, printf command can printf string convenience variables
> without inferior function calls.
> Ada string convenience variables can also be printed.
> 
> gdb/ChangeLog
> 
> 2019-06-10  Philippe Waroquiers  <philippe.waroquiers@skynet.be>
> 
> 	* NEWS: Mention that GDB printf and eval commands can now print
> 	C-style and Ada-style convenience var strings without
> 	calling the inferior.
> 	* printcmd.c (printf_c_string): Locally print GDB internal var
> 	instead of transiting via the inferior.
> 	(printf_wide_c_string): Likewise.
> 
> 2019-06-10  Philippe Waroquiers  <philippe.waroquiers@skynet.be>
> 
> 	* gdb.base/printcmds.exp: Test printing C strings and
> 	C wide strings convenience var without transiting via the inferior.
> ---
>  gdb/NEWS                             |   7 ++
>  gdb/printcmd.c                       | 143 +++++++++++++++++----------
>  gdb/testsuite/gdb.base/printcmds.exp |  39 ++++++++
>  3 files changed, 136 insertions(+), 53 deletions(-)
> 
> diff --git a/gdb/NEWS b/gdb/NEWS
> index 9e1462b6bf..9d6a2de661 100644
> --- a/gdb/NEWS
> +++ b/gdb/NEWS
> @@ -98,6 +98,13 @@ apropos [-v] REGEXP
>    of matching commands and to use the highlight style to mark
>    the documentation parts matching REGEXP.
>  
> +printf
> +eval
> +  The GDB printf and eval commands can now print C-style and Ada-style
> +  convenience variables without calling functions in the program.
> +  This allows to do formatted printing of strings without having
> +  an inferior, or when debugging a core dump.
> +
>  show style
>    The "show style" and its subcommands are now styling
>    a style name in their output using its own style, to help
> diff --git a/gdb/printcmd.c b/gdb/printcmd.c
> index 9e84594fe6..d7b8b9a1c1 100644
> --- a/gdb/printcmd.c
> +++ b/gdb/printcmd.c
> @@ -23,6 +23,7 @@
>  #include "gdbtypes.h"
>  #include "value.h"
>  #include "language.h"
> +#include "c-lang.h"
>  #include "expression.h"
>  #include "gdbcore.h"
>  #include "gdbcmd.h"
> @@ -2200,91 +2201,127 @@ print_variable_and_value (const char *name, struct symbol *var,
>  
>  /* Subroutine of ui_printf to simplify it.
>     Print VALUE to STREAM using FORMAT.
> -   VALUE is a C-style string on the target.  */
> +   VALUE is a C-style string on the target or a C-style string
> +   in a GDB internal variable.  */
>  
>  static void
>  printf_c_string (struct ui_file *stream, const char *format,
>  		 struct value *value)
>  {
> -  gdb_byte *str;
> -  CORE_ADDR tem;
> -  int j;
> +  const gdb_byte *str;
>  
> -  tem = value_as_address (value);
> -  if (tem == 0)
> +  if (VALUE_LVAL (value) == lval_internalvar
> +      && c_is_string_type_p (value_type (value)))
>      {
> -      DIAGNOSTIC_PUSH
> -      DIAGNOSTIC_IGNORE_FORMAT_NONLITERAL
> -      fprintf_filtered (stream, format, "(null)");
> -      DIAGNOSTIC_POP
> -      return;
> -    }
> +      gdb_byte *tem_str;
> +      size_t len  = TYPE_LENGTH (value_type (value));
>  
> -  /* This is a %s argument.  Find the length of the string.  */
> -  for (j = 0;; j++)
> +      /* Copy the internal var value to tem_str and append a terminating null
> +	 character.  This protects against corrupted C-style strings that lacks
> +	 the terminating null char.  It also allows Ada style strings (not not
> +	 null terminated) to be printed without problems.  */
> +      tem_str = (gdb_byte *) alloca (len + 1);
> +      memcpy (tem_str, value_contents (value), len);
> +      tem_str [len] = 0;
> +      str = tem_str;
> +    }
> +  else
>      {
> -      gdb_byte c;
> +      int len;
> +      CORE_ADDR tem;
> +      gdb_byte *tem_str;
>  
> -      QUIT;
> -      read_memory (tem + j, &c, 1);
> -      if (c == 0)
> -	break;
> -    }
> +      tem = value_as_address (value);
> +      if (tem == 0)
> +	{
> +	  DIAGNOSTIC_PUSH
> +	    DIAGNOSTIC_IGNORE_FORMAT_NONLITERAL
> +	    fprintf_filtered (stream, format, "(null)");
> +	  DIAGNOSTIC_POP
> +	    return;
> +	}
>  
> -  /* Copy the string contents into a string inside GDB.  */
> -  str = (gdb_byte *) alloca (j + 1);
> -  if (j != 0)
> -    read_memory (tem, str, j);
> -  str[j] = 0;
> +      /* This is a %s argument.  Find the length of the string.  */
> +      for (len = 0;; len++)
> +	{
> +	  gdb_byte c;
> +
> +	  QUIT;
> +	  read_memory (tem + len, &c, 1);
> +	  if (c == 0)
> +	    break;
> +	}
> +
> +      /* Copy the string contents into a string inside GDB.  */
> +      tem_str = (gdb_byte *) alloca (len + 1);
> +      if (len != 0)
> +	read_memory (tem, tem_str, len);
> +      tem_str[len] = 0;
> +      str = tem_str;
> +    }
>  
>    DIAGNOSTIC_PUSH
> -  DIAGNOSTIC_IGNORE_FORMAT_NONLITERAL
> -  fprintf_filtered (stream, format, (char *) str);
> +    DIAGNOSTIC_IGNORE_FORMAT_NONLITERAL
> +    fprintf_filtered (stream, format, (char *) str);
>    DIAGNOSTIC_POP
> -}
> +    }
>  
>  /* Subroutine of ui_printf to simplify it.
>     Print VALUE to STREAM using FORMAT.
> -   VALUE is a wide C-style string on the target.  */
> +   VALUE is a wide C-style string on the target or a wide C-style string
> +   in a GDB internal variable.  */
>  
>  static void
>  printf_wide_c_string (struct ui_file *stream, const char *format,
>  		      struct value *value)
>  {
> -  gdb_byte *str;
> -  CORE_ADDR tem;
> +  const gdb_byte *str;
>    int j;
>    struct gdbarch *gdbarch = get_type_arch (value_type (value));
> -  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
>    struct type *wctype = lookup_typename (current_language, gdbarch,
>  					 "wchar_t", NULL, 0);
>    int wcwidth = TYPE_LENGTH (wctype);
> -  gdb_byte *buf = (gdb_byte *) alloca (wcwidth);
>  
> -  tem = value_as_address (value);
> -  if (tem == 0)
> +  if (VALUE_LVAL (value) == lval_internalvar
> +      && c_is_string_type_p (value_type (value)))
>      {
> -      DIAGNOSTIC_PUSH
> -      DIAGNOSTIC_IGNORE_FORMAT_NONLITERAL
> -      fprintf_filtered (stream, format, "(null)");
> -      DIAGNOSTIC_POP
> -      return;
> +      str = value_contents (value);
> +      j = TYPE_LENGTH (value_type (value));
>      }
> -
> -  /* This is a %s argument.  Find the length of the string.  */
> -  for (j = 0;; j += wcwidth)
> +  else
>      {
> -      QUIT;
> -      read_memory (tem + j, buf, wcwidth);
> -      if (extract_unsigned_integer (buf, wcwidth, byte_order) == 0)
> -	break;
> -    }
> +      gdb_byte *tem_str;
> +      CORE_ADDR tem;
> +      gdb_byte *buf = (gdb_byte *) alloca (wcwidth);
>  
> -  /* Copy the string contents into a string inside GDB.  */
> -  str = (gdb_byte *) alloca (j + wcwidth);
> -  if (j != 0)
> -    read_memory (tem, str, j);
> -  memset (&str[j], 0, wcwidth);
> +      enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
> +
> +      tem = value_as_address (value);
> +      if (tem == 0)
> +	{
> +	  DIAGNOSTIC_PUSH
> +	    DIAGNOSTIC_IGNORE_FORMAT_NONLITERAL
> +	    fprintf_filtered (stream, format, "(null)");
> +	  DIAGNOSTIC_POP
> +	    return;
> +	}
> +
> +      /* This is a %s argument.  Find the length of the string.  */
> +      for (j = 0;; j += wcwidth)
> +	{
> +	  QUIT;
> +	  read_memory (tem + j, buf, wcwidth);
> +	  if (extract_unsigned_integer (buf, wcwidth, byte_order) == 0)
> +	    break;
> +	}
> +
> +      /* Copy the string contents into a string inside GDB.  */
> +      tem_str = (gdb_byte *) alloca (j + wcwidth);
> +      if (j != 0)
> +	read_memory (tem, tem_str, j);
> +      memset (&tem_str[j], 0, wcwidth);
> +      str = tem_str;
> +    }
>  
>    auto_obstack output;
>  
> diff --git a/gdb/testsuite/gdb.base/printcmds.exp b/gdb/testsuite/gdb.base/printcmds.exp
> index f2d6ee229d..3b6562426e 100644
> --- a/gdb/testsuite/gdb.base/printcmds.exp
> +++ b/gdb/testsuite/gdb.base/printcmds.exp
> @@ -932,6 +932,32 @@ proc test_repeat_bytes {} {
>      }
>  }
>  
> +proc test_printf_convenience_var {prefix do_wstring} {
> +
> +    with_test_prefix $prefix {
> +	gdb_test_no_output "set var \$cstr = \"abcde\"" "set \$cstr, conv var"
> +	gdb_test "printf \"cstr val = %s\\n\", \$cstr" "cstr val = abcde" \
> +	    "printf \$cstr, conv var"
> +	gdb_test_no_output "set var \$abcde = \"ABCDE\"" "set \$abcde, conv var"
> +	gdb_test "eval \"print \$%s\\n\", \$cstr" "= \"ABCDE\"" \
> +	    "indirect print abcde"
> +	gdb_test "set language ada" ".*" "set language ada, conv var"
> +	gdb_test_no_output "set var \$astr := \"fghij\"" "set \$astr, conv var"
> +	gdb_test "printf \"astr val = %s\\n\", \$astr" "astr val = fghij" \
> +	    "printf \$astr, conv var"
> +	gdb_test "set language auto" ".*" "set language auto, conv var"
> +	gdb_test "printf \"astr val = %s\\n\", \$astr" "astr val = fghij" \
> +	    "printf \$astr, conv var, auto language"
> +	if ($do_wstring) {
> +	    gdb_test_no_output "set var \$wstr = L\"facile\"" \
> +		"set \$wstr, conv var"
> +	    gdb_test "printf \"wstr val = %ls\\n\", \$wstr" \
> +		"wstr val = facile" "printf \$wstr, conv var"
> +	}
> +    }
> +}
> +
> +
>  # Start with a fresh gdb.
>  
>  gdb_exit
> @@ -948,6 +974,11 @@ gdb_test "ptype \"abc\"" " = char \\\[4\\\]"
>  gdb_test "print \$cvar = \"abc\"" " = \"abc\""
>  gdb_test "print sizeof (\$cvar)" " = 4"
>  
> +# Similarly, printf of convenience var should work without a target.
> +# At this point, we cannot create wide strings convenience var, as the
> +# type wchar_t is not yet known, so skip the wide string tests.
> +test_printf_convenience_var "no target" 0
> +
>  # GDB used to complete the explicit location options even when
>  # printing expressions.
>  gdb_test_no_output "complete p -function"
> @@ -977,6 +1008,14 @@ if ![runto_main] then {
>      return 0
>  }
>  
> +# With a target, printf convenience var should of course work.
> +test_printf_convenience_var "with target" 1
> +
> +# But it should also work when inferior function calls are forbidden.
> +gdb_test_no_output "set may-call-functions off"
> +test_printf_convenience_var "with target, may-call-functions off" 1
> +gdb_test_no_output "set may-call-functions on"
> +
>  test_integer_literals_accepted
>  test_integer_literals_rejected
>  test_float_accepted



More information about the Gdb-patches mailing list