On 04/11/2015 08:44 PM, Jan Kratochvil wrote:
> Hi,
>
> former patch injects plain:
> printf (...);
> This patch injects gdbserver-compatible:
> f = open_memstream (&s, ...);
> fprintf (f, ...);
> fclose (f);
> return s;
(A more expanded explanation would have helped here. The first time I
skimmed this, I didn't really understand what this meant.)
So the issue here is that calling "printf" in the inferior ends up
with output sent to the inferior's stdout. If gdbserver is running on a
separate terminal (or machine), then the output of "compile printf" without
this patch goes to the inferior's terminal, unlike using "(gdb) printf ...".
That's not just an issue for gdbserver, actually. Even with the native target,
using "compile printf" without this patch against an inferior that gdb attached
to, with "attach PID" (a process that was already running on a separate
terminal), or if you use the "set inferior-tty" option, you get the exact
same problem.
> @@ -233,10 +241,15 @@ add_code_footer (enum compile_i_scope_types type, struct ui_file *buf)
> {
> switch (type)
> {
> + case COMPILE_I_PRINTF_SCOPE:
> + fputs_unfiltered ("\tif (fclose (__gdb_outf) != 0)\n"
> + "\t\treturn NULL;\n"
> + "\treturn __gdb_retval;\n",
> + buf);
> + // FALLTHRU
Please use /* */ comments, here and elsewhere.
(replying to the other mail)
Thanks,
Pedro Alves
@@ -208,13 +208,21 @@ add_code_header (enum compile_i_scope_types type, struct ui_file *buf)
break;
case COMPILE_I_PRINTF_SCOPE:
fputs_unfiltered ("#include <stdio.h>\n"
- "void "
+ "char *"
GCC_FE_WRAPPER_FUNCTION
" (struct "
COMPILE_I_SIMPLE_REGISTER_STRUCT_TAG
" *"
COMPILE_I_SIMPLE_REGISTER_ARG_NAME
- ") {\n",
+ ") {\n"
+ "\tchar *__gdb_retval;\n"
+ "\tsize_t __gdb_retval_size;\n"
+ "\tFILE *__gdb_outf;\n"
+ "\n"
+ "\t__gdb_outf = open_memstream (&__gdb_retval, "
+ "&__gdb_retval_size);\n"
+ "\tif (__gdb_outf == NULL)\n"
+ "\t\treturn NULL;\n",
buf);
break;
case COMPILE_I_RAW_SCOPE:
@@ -233,10 +241,15 @@ add_code_footer (enum compile_i_scope_types type, struct ui_file *buf)
{
switch (type)
{
+ case COMPILE_I_PRINTF_SCOPE:
+ fputs_unfiltered ("\tif (fclose (__gdb_outf) != 0)\n"
+ "\t\treturn NULL;\n"
+ "\treturn __gdb_retval;\n",
+ buf);
+ // FALLTHRU
case COMPILE_I_SIMPLE_SCOPE:
case COMPILE_I_PRINT_ADDRESS_SCOPE:
case COMPILE_I_PRINT_VALUE_SCOPE:
- case COMPILE_I_PRINTF_SCOPE:
fputs_unfiltered ("}\n", buf);
break;
case COMPILE_I_RAW_SCOPE:
@@ -432,7 +445,7 @@ c_compute_program (struct compile_instance *inst,
break;
case COMPILE_I_PRINTF_SCOPE:
fprintf_unfiltered (buf,
-"printf (%s);\n"
+"fprintf (__gdb_outf, %s);\n"
, input);
break;
default:
@@ -651,7 +651,8 @@ compile_object_load (const char *object_file, const char *source_file,
break;
case COMPILE_I_PRINTF_SCOPE:
expect_parameters = 1;
- expect_return_type = builtin_type (target_gdbarch ())->builtin_void;
+ expect_return_type = lookup_pointer_type
+ (builtin_type (target_gdbarch ())->builtin_char);
break;
default:
internal_error (__FILE__, __LINE__, _("invalid scope %d"), scope);
@@ -27,6 +27,7 @@
#include "block.h"
#include "valprint.h"
#include "compile.h"
+#include "gdbcore.h"
/* Helper for do_module_cleanup. */
@@ -99,6 +100,18 @@ do_module_cleanup (void *arg)
xfree (data);
}
+static void
+free_inferior_memory (CORE_ADDR addr)
+{
+ struct objfile *objf;
+ struct value *func_val = find_function_in_inferior ("free", &objf);
+ struct gdbarch *gdbarch = get_objfile_arch (objf);
+ struct type *addr_type = builtin_type (gdbarch)->builtin_data_ptr;
+ struct value *addr_val = value_from_pointer (addr_type, addr);
+
+ call_function_by_hand (func_val, 1, &addr_val);
+}
+
/* Perform inferior call of MODULE. This function may throw an error.
This function may leave files referenced by MODULE on disk until
the inferior call dummy frame is discarded. This function may throw errors.
@@ -117,6 +130,7 @@ compile_object_run (struct compile_module *module)
struct symbol *func_sym = module->func_sym;
CORE_ADDR regs_addr = module->regs_addr;
struct objfile *objfile = module->objfile;
+ enum compile_i_scope_types scope = module->scope;
data = xmalloc (sizeof (*data) + strlen (objfile_name_s));
data->executedp = &executed;
@@ -136,7 +150,7 @@ compile_object_run (struct compile_module *module)
struct type *func_type = SYMBOL_TYPE (func_sym);
htab_t copied_types;
int current_arg = 0;
- struct value **vargs;
+ struct value **vargs, *func_return_value;
/* OBJFILE may disappear while FUNC_TYPE still will be in use. */
copied_types = create_copied_types_hash (objfile);
@@ -163,8 +177,42 @@ compile_object_run (struct compile_module *module)
++current_arg;
}
gdb_assert (current_arg == TYPE_NFIELDS (func_type));
- call_function_by_hand_dummy (func_val, TYPE_NFIELDS (func_type), vargs,
- do_module_cleanup, data);
+ func_return_value = call_function_by_hand_dummy (func_val,
+ TYPE_NFIELDS (func_type),
+ vargs,
+ do_module_cleanup, data);
+
+ // DATA can be already freed now.
+ data = NULL;
+
+ if (scope == COMPILE_I_PRINTF_SCOPE)
+ {
+ struct value_print_options opts;
+ gdb_byte *buffer = NULL;
+ struct cleanup *old_chain;
+ int errcode, bytes_read;
+ struct type *retval_type = value_type (func_return_value);
+ struct type *char_type;
+
+ gdb_assert (TYPE_CODE (retval_type) == TYPE_CODE_PTR);
+ char_type = TYPE_TARGET_TYPE (retval_type);
+ gdb_assert (TYPE_CODE (char_type) == TYPE_CODE_INT);
+
+ get_user_print_options (&opts);
+ errcode = read_string (value_as_address (func_return_value), -1,
+ TYPE_LENGTH (char_type), opts.print_max,
+ gdbarch_byte_order (target_gdbarch ()),
+ &buffer, &bytes_read);
+ old_chain = make_cleanup (xfree, buffer);
+ if (errcode != 0)
+ memory_error (errcode, value_as_address (func_return_value));
+
+ while (bytes_read-- > 0)
+ putchar_filtered (*buffer++);
+ do_cleanups (old_chain);
+
+ free_inferior_memory (value_as_address (func_return_value));
+ }
}
CATCH (ex, RETURN_MASK_ERROR)
{
@@ -57,7 +57,5 @@ gdb_test {print $} " = 256"
gdb_test "compile print varobject" { = {field = 1}}
-if ![is_remote target] {
- gdb_test {compile printf "0x%x\n", varint} "\r\n0xa"
- gdb_test {compile printf "0x%x\n"} "\r\nCompilation failed\\."
-}
+gdb_test {compile printf "0x%x\n", varint} "\r\n0xa"
+gdb_test {compile printf "0x%x\n"} "\r\nCompilation failed\\."
---
gdb/doc/gdb.texinfo | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
@@ -208,13 +208,21 @@ add_code_header (enum compile_i_scope_types type, struct ui_file *buf)
break;
case COMPILE_I_PRINTF_SCOPE:
fputs_unfiltered ("#include <stdio.h>\n"
- "void "
+ "char *"
GCC_FE_WRAPPER_FUNCTION
" (struct "
COMPILE_I_SIMPLE_REGISTER_STRUCT_TAG
" *"
COMPILE_I_SIMPLE_REGISTER_ARG_NAME
- ") {\n",
+ ") {\n"
+ "\tchar *__gdb_retval;\n"
+ "\tsize_t __gdb_retval_size;\n"
+ "\tFILE *__gdb_outf;\n"
+ "\n"
+ "\t__gdb_outf = open_memstream (&__gdb_retval, "
+ "&__gdb_retval_size);\n"
+ "\tif (__gdb_outf == NULL)\n"
+ "\t\treturn NULL;\n",
buf);
break;
case COMPILE_I_RAW_SCOPE:
@@ -233,10 +241,15 @@ add_code_footer (enum compile_i_scope_types type, struct ui_file *buf)
{
switch (type)
{
+ case COMPILE_I_PRINTF_SCOPE:
+ fputs_unfiltered ("\tif (fclose (__gdb_outf) != 0)\n"
+ "\t\treturn NULL;\n"
+ "\treturn __gdb_retval;\n",
+ buf);
+ // FALLTHRU
case COMPILE_I_SIMPLE_SCOPE:
case COMPILE_I_PRINT_ADDRESS_SCOPE:
case COMPILE_I_PRINT_VALUE_SCOPE:
- case COMPILE_I_PRINTF_SCOPE:
fputs_unfiltered ("}\n", buf);
break;
case COMPILE_I_RAW_SCOPE:
@@ -432,7 +445,7 @@ c_compute_program (struct compile_instance *inst,
break;
case COMPILE_I_PRINTF_SCOPE:
fprintf_unfiltered (buf,
-"printf (%s);\n"
+"fprintf (__gdb_outf, %s);\n"
, input);
break;
default:
@@ -651,7 +651,8 @@ compile_object_load (const char *object_file, const char *source_file,
break;
case COMPILE_I_PRINTF_SCOPE:
expect_parameters = 1;
- expect_return_type = builtin_type (target_gdbarch ())->builtin_void;
+ expect_return_type = lookup_pointer_type
+ (builtin_type (target_gdbarch ())->builtin_char);
break;
default:
internal_error (__FILE__, __LINE__, _("invalid scope %d"), scope);
@@ -27,6 +27,7 @@
#include "block.h"
#include "valprint.h"
#include "compile.h"
+#include "gdbcore.h"
/* Helper for do_module_cleanup. */
@@ -99,6 +100,20 @@ do_module_cleanup (void *arg)
xfree (data);
}
+/* Call inferior function "free" for ADDR. */
+
+static void
+free_inferior_memory (CORE_ADDR addr)
+{
+ struct objfile *objf;
+ struct value *func_val = find_function_in_inferior ("free", &objf);
+ struct gdbarch *gdbarch = get_objfile_arch (objf);
+ struct type *addr_type = builtin_type (gdbarch)->builtin_data_ptr;
+ struct value *addr_val = value_from_pointer (addr_type, addr);
+
+ call_function_by_hand (func_val, 1, &addr_val);
+}
+
/* Perform inferior call of MODULE. This function may throw an error.
This function may leave files referenced by MODULE on disk until
the inferior call dummy frame is discarded. This function may throw errors.
@@ -117,6 +132,7 @@ compile_object_run (struct compile_module *module)
struct symbol *func_sym = module->func_sym;
CORE_ADDR regs_addr = module->regs_addr;
struct objfile *objfile = module->objfile;
+ enum compile_i_scope_types scope = module->scope;
data = xmalloc (sizeof (*data) + strlen (objfile_name_s));
data->executedp = &executed;
@@ -136,7 +152,7 @@ compile_object_run (struct compile_module *module)
struct type *func_type = SYMBOL_TYPE (func_sym);
htab_t copied_types;
int current_arg = 0;
- struct value **vargs;
+ struct value **vargs, *func_return_value;
/* OBJFILE may disappear while FUNC_TYPE still will be in use. */
copied_types = create_copied_types_hash (objfile);
@@ -163,8 +179,42 @@ compile_object_run (struct compile_module *module)
++current_arg;
}
gdb_assert (current_arg == TYPE_NFIELDS (func_type));
- call_function_by_hand_dummy (func_val, TYPE_NFIELDS (func_type), vargs,
- do_module_cleanup, data);
+ func_return_value = call_function_by_hand_dummy (func_val,
+ TYPE_NFIELDS (func_type),
+ vargs,
+ do_module_cleanup, data);
+
+ // DATA can be already freed now.
+ data = NULL;
+
+ if (scope == COMPILE_I_PRINTF_SCOPE)
+ {
+ struct value_print_options opts;
+ gdb_byte *buffer = NULL;
+ struct cleanup *old_chain;
+ int errcode, bytes_read;
+ struct type *retval_type = value_type (func_return_value);
+ struct type *char_type;
+
+ gdb_assert (TYPE_CODE (retval_type) == TYPE_CODE_PTR);
+ char_type = TYPE_TARGET_TYPE (retval_type);
+ gdb_assert (TYPE_CODE (char_type) == TYPE_CODE_INT);
+
+ get_user_print_options (&opts);
+ errcode = read_string (value_as_address (func_return_value), -1,
+ TYPE_LENGTH (char_type), opts.print_max,
+ gdbarch_byte_order (target_gdbarch ()),
+ &buffer, &bytes_read);
+ old_chain = make_cleanup (xfree, buffer);
+ if (errcode != 0)
+ memory_error (errcode, value_as_address (func_return_value));
+
+ while (bytes_read-- > 0)
+ putchar_filtered (*buffer++);
+ do_cleanups (old_chain);
+
+ free_inferior_memory (value_as_address (func_return_value));
+ }
}
CATCH (ex, RETURN_MASK_ERROR)
{
@@ -17239,7 +17239,9 @@ multiple-line editor.
@item compile printf @var{template}, @var{expressions}@dots{}
Compile and execute @code{printf} function call with the compiler
language found as the current language in @value{GDBN}
-(@pxref{Languages}).
+(@pxref{Languages}). The value is printed by @value{GDBN} and not the
+inferior, inferior does not execute specifically the function
+@code{printf}.
@item compile printf
@cindex reprint the last value
@@ -57,7 +57,5 @@ gdb_test {print $} " = 256"
gdb_test "compile print varobject" { = {field = 1}}
-if ![is_remote target] {
- gdb_test {compile printf "0x%x\n", varint} "\r\n0xa"
- gdb_test {compile printf "0x%x\n"} "\r\nCompilation failed\\."
-}
+gdb_test {compile printf "0x%x\n", varint} "\r\n0xa"
+gdb_test {compile printf "0x%x\n"} "\r\nCompilation failed\\."