aboutsummaryrefslogtreecommitdiff
path: root/gdb/printcmd.c
diff options
context:
space:
mode:
authorPhilippe Waroquiers <philippe.waroquiers@skynet.be>2019-06-10 21:41:51 +0200
committerPhilippe Waroquiers <philippe.waroquiers@skynet.be>2019-07-08 23:31:54 +0200
commit1f6f6e21fa86dc3411a6498608f32e9eb24b7851 (patch)
tree37520dd0294952b805f1358230555b20e89bd4a9 /gdb/printcmd.c
parentea142fbfc9c1708a83d3532257d6728e1f5c142e (diff)
downloadgdb-1f6f6e21fa86dc3411a6498608f32e9eb24b7851.zip
gdb-1f6f6e21fa86dc3411a6498608f32e9eb24b7851.tar.gz
gdb-1f6f6e21fa86dc3411a6498608f32e9eb24b7851.tar.bz2
Ensure GDB printf command can print convenience var strings without a target.
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 running 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-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. gdb/testsuite/ChangeLog 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.
Diffstat (limited to 'gdb/printcmd.c')
-rw-r--r--gdb/printcmd.c140
1 files changed, 88 insertions, 52 deletions
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, "");