-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.
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
#include "gdbtypes.h"
#include "value.h"
#include "language.h"
+#include "c-lang.h"
#include "expression.h"
#include "gdbcore.h"
#include "gdbcmd.h"
/* 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
/* 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, "");
+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.
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\]"
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}"
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}"
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" \
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 {} {
}
}
+# 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
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"
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