diff options
-rw-r--r-- | gdb/ChangeLog | 11 | ||||
-rw-r--r-- | gdb/NEWS | 7 | ||||
-rw-r--r-- | gdb/printcmd.c | 140 | ||||
-rw-r--r-- | gdb/testsuite/ChangeLog | 6 | ||||
-rw-r--r-- | gdb/testsuite/gdb.base/printcmds.exp | 59 |
5 files changed, 165 insertions, 58 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 218bbf6..2f406ae 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,4 +1,13 @@ -2019-08-04 Alan Hayward <alan.hayward@arm.com> +2019-07-08 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-07-04 Alan Hayward <alan.hayward@arm.com> * symfile.c (symbol_file_command): Call solib_create_inferior_hook. @@ -118,6 +118,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 + string convenience variables without calling functions in the program. + This allows to do formatted printing of strings without having + a running 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 0509360..714a2e9 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" @@ -2222,42 +2223,64 @@ 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 either on the target or + 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; - } + size_t len = TYPE_LENGTH (value_type (value)); - /* This is a %s argument. Find the length of the string. */ - for (j = 0;; j++) - { - gdb_byte c; + /* Copy the internal var value to TEM_STR and append a terminating null + character. This protects against corrupted C-style strings that lack + the terminating null char. It also allows Ada-style strings (not + null terminated) to be printed without problems. */ + gdb_byte *tem_str = (gdb_byte *) alloca (len + 1); - QUIT; - read_memory (tem + j, &c, 1); - if (c == 0) - break; + memcpy (tem_str, value_contents (value), len); + tem_str [len] = 0; + str = tem_str; } + else + { + CORE_ADDR 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. */ + size_t len; + + for (len = 0;; len++) + { + gdb_byte c; - /* 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; + QUIT; + read_memory (tem + len, &c, 1); + if (c == 0) + break; + } + + /* Copy the string contents into a string inside GDB. */ + gdb_byte *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 @@ -2267,52 +2290,65 @@ printf_c_string (struct ui_file *stream, const char *format, /* 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 + 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; - int j; + const gdb_byte *str; + size_t len; 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); + len = 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; - } + CORE_ADDR tem = value_as_address (value); - /* 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); + 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. */ + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); + gdb_byte *buf = (gdb_byte *) alloca (wcwidth); + + for (len = 0;; len += wcwidth) + { + QUIT; + read_memory (tem + len, buf, wcwidth); + if (extract_unsigned_integer (buf, wcwidth, byte_order) == 0) + break; + } + + /* Copy the string contents into a string inside GDB. */ + gdb_byte *tem_str = (gdb_byte *) alloca (len + wcwidth); + + if (len != 0) + read_memory (tem, tem_str, len); + memset (&tem_str[len], 0, wcwidth); + str = tem_str; + } auto_obstack output; convert_between_encodings (target_wide_charset (gdbarch), host_charset (), - str, j, wcwidth, + str, len, wcwidth, &output, translit_char); obstack_grow_str0 (&output, ""); diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index a6d6843..f8ef540 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2019-07-08 Philippe Waroquiers <philippe.waroquiers@skynet.be> + + * gdb.base/printcmds.exp: Test printing C string and + C wide string convenience vars without transiting via the inferior. + Also make test names unique. + 2019-07-08 Alan Hayward <alan.hayward@arm.com> * gdb.base/break-idempotent.exp: Test both PIE and non PIE. diff --git a/gdb/testsuite/gdb.base/printcmds.exp b/gdb/testsuite/gdb.base/printcmds.exp index f2d6ee2..0e3126b 100644 --- a/gdb/testsuite/gdb.base/printcmds.exp +++ b/gdb/testsuite/gdb.base/printcmds.exp @@ -438,7 +438,7 @@ proc test_print_repeats_10 {} { global gdb_prompt decimal for { set x 1 } { $x <= 16 } { incr x } { - gdb_test_no_output "set print elements $x" + gdb_test_no_output "set print elements $x" "elements $x repeats" for { set e 1 } { $e <= 16 } {incr e } { set v [expr $e - 1] set command "p &ctable2\[${v}*16\]" @@ -596,7 +596,7 @@ proc test_print_strings {} { proc test_print_int_arrays {} { global gdb_prompt - gdb_test_no_output "set print elements 24" + gdb_test_no_output "set print elements 24" "elements 24 int arrays" gdb_test_escape_braces "p int1dim" \ " = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}" @@ -621,7 +621,7 @@ proc test_print_int_arrays {} { proc test_print_typedef_arrays {} { global gdb_prompt - gdb_test_no_output "set print elements 24" + gdb_test_no_output "set print elements 24" "elements 24 typedef_arrays" gdb_test_escape_braces "p a1" \ " = {2, 4, 6, 8, 10, 12, 14, 16, 18, 20}" @@ -666,7 +666,7 @@ proc test_print_char_arrays {} { global gdb_prompt global hex decimal - gdb_test_no_output "set print elements 24" + gdb_test_no_output "set print elements 24" "elements 24 char_arrays" gdb_test_no_output "set print address on" gdb_test "p arrays" \ @@ -684,7 +684,7 @@ proc test_print_char_arrays {} { gdb_test "p parrays->array5" " = \"hij\"" gdb_test "p &parrays->array5" " = \\(unsigned char \\(\\*\\)\\\[4\\\]\\) $hex <arrays\\+$decimal>" - gdb_test_no_output "set print address off" + gdb_test_no_output "set print address off" "address off char arrays" } proc test_print_string_constants {} { @@ -932,6 +932,42 @@ proc test_repeat_bytes {} { } } +# Test printf of convenience variables. +# These tests can be done with or without a running inferior. +# PREFIX ensures uniqueness of test names. +# DO_WSTRING 1 tells to test printf of wide strings. Wide strings tests +# must be skipped (DO_WSTRING 0) if the wchar_t type is not yet known by +# GDB, as this type is needed to create wide strings. + +proc test_printf_convenience_var {prefix do_wstring} { + + with_test_prefix "conv var: $prefix" { + gdb_test_no_output "set var \$cstr = \"abcde\"" "set \$cstr" + gdb_test "printf \"cstr val = %s\\n\", \$cstr" "cstr val = abcde" \ + "printf \$cstr" + gdb_test_no_output "set var \$abcde = \"ABCDE\"" "set \$abcde" + gdb_test "eval \"print \$%s\\n\", \$cstr" "= \"ABCDE\"" \ + "indirect print abcde" + # Without a target, the below produces no output + # but with a target, it gives a warning. + # So, use gdb_test expecting ".*" instead of gdb_test_no_output. + gdb_test "set language ada" ".*" "set language ada" + gdb_test_no_output "set var \$astr := \"fghij\"" "set \$astr" + gdb_test "printf \"astr val = %s\\n\", \$astr" "astr val = fghij" \ + "printf \$astr" + gdb_test_no_output "set language auto" "set language auto" + gdb_test "printf \"astr val = %s\\n\", \$astr" "astr val = fghij" \ + "printf \$astr, auto language" + if {$do_wstring} { + gdb_test_no_output "set var \$wstr = L\"facile\"" \ + "set \$wstr" + gdb_test "printf \"wstr val = %ls\\n\", \$wstr" \ + "wstr val = facile" "printf \$wstr" + } + } +} + + # Start with a fresh gdb. gdb_exit @@ -948,6 +984,11 @@ gdb_test "ptype \"abc\"" " = char \\\[4\\\]" gdb_test "print \$cvar = \"abc\"" " = \"abc\"" gdb_test "print sizeof (\$cvar)" " = 4" +# Similarly, printf of a string convenience var should work without a target. +# At this point, we cannot create a wide string convenience var, as the +# wchar_t type 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 +1018,14 @@ if ![runto_main] then { return 0 } +# With a running target, printf convenience vars should of course work. +test_printf_convenience_var "with target" 1 + +# 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 |