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