[v3,8/9] compile: New compile printf

Message ID 20150411194429.29128.61494.stgit@host1.jankratochvil.net
State New, archived
Headers

Commit Message

Jan Kratochvil April 11, 2015, 7:44 p.m. UTC
  Hi,

command naming needs to follow what gets decided for 'compile print'.

This part sends the output to inferior stdout, only the next patch will
redirect it to GDB (so that for example it works for remote gdbserver).

It cannot work for core files as one cannot execute inferior code there.
There were some ideas such as compiling the entered sources into GCC
intermediate form (GIMPLE?) and interpret it by GDB on top of the core file.
That would be much more complicated, this implementation is made according to
Phil's specification.

Besides existing
	(gdb) set compile-args
there will be now also:
	(gdb) set compile-printf-args
Maybe it would be worth to start some set sub-category 'compile' such as:
	(gdb) set compile args
	(gdb) set compile printf-args
That would mean the whole process of deprecating 'set compile-args' etc.


Jan


gdb/ChangeLog
2015-04-06  Jan Kratochvil  <jan.kratochvil@redhat.com>

	* compile/compile-c-support.c (add_code_header, add_code_footer)
	(c_compute_program): Add COMPILE_I_PRINTF_SCOPE.
	* compile/compile-object-load.c (get_regs_type): Verify 2nd parameter
	type.
	(compile_object_load): Add COMPILE_I_PRINTF_SCOPE.
	* compile/compile.c (compile_print_command): Rename to ...
	(compile_print): ... here.
	(compile_print_command, compile_printf_command, compile_printf_args)
	(compile_printf_args_argv, set_compile_printf_args)
	(show_compile_printf_args): New.
	(get_args): Add COMPILE_I_PRINTF_SCOPE support.
	(_initialize_compile): Install compile_printf_command,
	set_compile_printf_args and show_compile_printf_args.  Set default
	COMPILE_PRINTF_ARGS.
	* defs.h (enum compile_i_scope_types): Add COMPILE_I_PRINTF_SCOPE.

gdb/doc/ChangeLog
2015-04-06  Jan Kratochvil  <jan.kratochvil@redhat.com>

	* gdb.texinfo (Compiling and Injecting Code): Add compile printf.

gdb/testsuite/ChangeLog
2015-04-06  Jan Kratochvil  <jan.kratochvil@redhat.com>

	* gdb.compile/compile-print.exp (compile printf "0x%x\n", varint)
	(compile printf "0x%x\n"): New.
  

Comments

Pedro Alves April 29, 2015, 3:52 p.m. UTC | #1
On 04/11/2015 08:44 PM, Jan Kratochvil wrote:
> Hi,
> 
> command naming needs to follow what gets decided for 'compile print'.
> 
> This part sends the output to inferior stdout, only the next patch will
> redirect it to GDB (so that for example it works for remote gdbserver).
> 
> It cannot work for core files as one cannot execute inferior code there.
> There were some ideas such as compiling the entered sources into GCC
> intermediate form (GIMPLE?) and interpret it by GDB on top of the core file.

Yeah, though that's a general idea for "compile print" as well, not
just printf.  I'd love to see us get there, but these new commands
are useful on their own as interim steps too.  The usefulness of "compile printf"
specifically isn't as immediately clear though.  I think the manual
should say something about why you want to use "compile printf" over
the alternatives.  (Edit: Ah, I see that's in the next patch.)

The main advantage is that after the next patch, the output always
appears in gdb's console, while "compile code printf" works just like
  (gdb) print printf (...)
meaning, in the "compile the output should go to the inferior's stdout.

Or is there another advantage I missed, perhaps?

> That would be much more complicated, this implementation is made according to
> Phil's specification.
> 
> Besides existing
> 	(gdb) set compile-args
> there will be now also:
> 	(gdb) set compile-printf-args
> Maybe it would be worth to start some set sub-category 'compile' such as:
> 	(gdb) set compile args
> 	(gdb) set compile printf-args

That'd be fine with me.

But can give an example of why you'd want to set "set compile-printf-args"
differently to "set compile-args" ?

> That would mean the whole process of deprecating 'set compile-args' etc.


> +  add_setshow_string_cmd ("compile-printf-args", class_support,
> +			  &compile_printf_args,
> +			  _("Set compile command GCC command-line arguments FIXME"),
> +			  _("Show compile command GCC command-line arguments FIXME"),

Some FIXMEs here.

Overall looks reasonable.

Thanks,
Pedro Alves
  
Jan Kratochvil May 3, 2015, 2:06 p.m. UTC | #2
On Wed, 29 Apr 2015 17:52:09 +0200, Pedro Alves wrote:
> The usefulness of "compile printf"
> specifically isn't as immediately clear though.  I think the manual
> should say something about why you want to use "compile printf" over
> the alternatives.  (Edit: Ah, I see that's in the next patch.)

I do not know, I have never used the existing GDB printf command myself.
GDB Manual could describe what the existing GDB printf command is good for.
IMO in the cases where one needs the printf command one already has to use
some extension language (such as Python) which can do that on its own.
This patch was created upon request by Phil.


> The main advantage is that after the next patch, the output always
> appears in gdb's console, while "compile code printf" works just like
>   (gdb) print printf (...)
> meaning, in the "compile the output should go to the inferior's stdout.
> 
> Or is there another advantage I missed, perhaps?

This patch is just to split it to two mails for review.  I do not think it
makes sense on its own, it messes up debugging output with inferior output.


> But can give an example of why you'd want to set "set compile-printf-args"
> differently to "set compile-args" ?

I do not know exactly myself but currently there is already:
	+  compile_printf_args = xstrdup ("-Werror=format");

so one may need to modify that for whatever reason.  I do not think there
should be non-overridable GCC options.


> Some FIXMEs here.

Fixed:
                          _("Set compile printf command "
                            "GCC command-line arguments"),
                          _("Show compile printf command "
                            "GCC command-line arguments"),


Thanks,
Jan
  
Pedro Alves May 6, 2015, 10:22 a.m. UTC | #3
On 05/03/2015 03:06 PM, Jan Kratochvil wrote:
> On Wed, 29 Apr 2015 17:52:09 +0200, Pedro Alves wrote:
>> The usefulness of "compile printf"
>> specifically isn't as immediately clear though.  I think the manual
>> should say something about why you want to use "compile printf" over
>> the alternatives.  (Edit: Ah, I see that's in the next patch.)
> 
> I do not know, I have never used the existing GDB printf command myself.
> GDB Manual could describe what the existing GDB printf command is good for.

It's useful for formatted output in user-defined commands, without
using extension languages.  But indeed it's not clear what
"compile printf" in its current form is really useful for.

> IMO in the cases where one needs the printf command one already has to use
> some extension language (such as Python) which can do that on its own.

(The printf command predates extensions languages.)

> This patch was created upon request by Phil.

I'm wondering / trying to understand why we're making
"compile printf" do the printf-ing in the inferior.  It seems we may
be making our lives harder for possibly no good reason.

Consider where we'll ideally be in the future:

 #0 - by default, the compiler outputs intermediate IR which is
      interpreted by gdb, instead of injecting and calling code
      in the inferior.

 #1 - all expression evaluation goes through the compiler.

 #2 - the user no longer needs to know to use "compile "
      prefixed commands.  Instead, "print" etc. just use the compiler
      when possible, or when the user asks for it with some option.

With these in mind, maybe a better direction is to make

  (gdb) compile printf "%s, %d", expr1, expr2

instead evaluate expr1 and expr2 using the "compile print"
mechanism to get the values of expr1 and expr2, and
then do the printf formatting all on the gdb side, just
like "(gdb) printf".  Basically, in the current
sequence for "printf":

  printf_command -> ui_printf -> parse_to_comma_and_eval

Make parse_to_comma_and_eval eval using the compiler.

This avoids all the complication related to calling printf
in the inferior, which would necessarily behave differently
with #0 above (gdb's printf vs inferior's printf).

> 
>> The main advantage is that after the next patch, the output always
>> appears in gdb's console, while "compile code printf" works just like
>>   (gdb) print printf (...)
>> meaning, in the "compile the output should go to the inferior's stdout.
>>
>> Or is there another advantage I missed, perhaps?
> 
> This patch is just to split it to two mails for review. 

I understand that.  But what I was asking is (after the series is wholly
pushed), what is the advantage of "(gdb) compile printf"
over "(gdb) compile print printf (...)" and "(gdb) call printf (...)".

> I do not think it
> makes sense on its own, it messes up debugging output with inferior output.
> 
> 
>> But can give an example of why you'd want to set "set compile-printf-args"
>> differently to "set compile-args" ?
> 
> I do not know exactly myself but currently there is already:
> 	+  compile_printf_args = xstrdup ("-Werror=format");
> 
> so one may need to modify that for whatever reason.  I do not think there
> should be non-overridable GCC options.

Agreed on the latter, but the question really is: why do we need
"set compile-printf-args" instead of using "set compile-args" for
all expression evaluation through the compiler?
Shouldn't "-Werror=format" be in "set compile-args" too?
The fewer knobs the user must learn the better, and I'd like to
avoid ending up with a bunch of "set compile-foo-args" knobs
if possible.

Thanks,
Pedro Alves
  
Jan Kratochvil May 6, 2015, 11:29 a.m. UTC | #4
On Wed, 06 May 2015 12:22:41 +0200, Pedro Alves wrote:
> I understand that.  But what I was asking is (after the series is wholly
> pushed), what is the advantage of "(gdb) compile printf"
> over "(gdb) compile print printf (...)" and "(gdb) call printf (...)".

This patch, that is
	[PATCH v3 8/9] compile: New compile printf
without the part
	[PATCH v3 9/9] compile: compile printf: gdbserver support
is really just that
	(gdb) compile print printf (...)
and the patch is also therefore very simple.

According to Phil - roughly, not citing - such 'compile printf' was simple
enough to code to make it worth such a feature, despite it has many
shortcomings.


> Agreed on the latter, but the question really is: why do we need
> "set compile-printf-args" instead of using "set compile-args" for
> all expression evaluation through the compiler?
> Shouldn't "-Werror=format" be in "set compile-args" too?

Why not, this is a matter of opinion.  IMO cc itself should have -Werror by
default as otherwise by default it is willing to knowingly produce crashing
programs.  The only safe warnings are -Wunused* ones and maybe few others.
So again, this patch tries to make minimal changes to what is the current
established wrong standard.


Jan
  
Pedro Alves May 6, 2015, 11:47 a.m. UTC | #5
On 05/06/2015 12:29 PM, Jan Kratochvil wrote:
> On Wed, 06 May 2015 12:22:41 +0200, Pedro Alves wrote:
>> I understand that.  But what I was asking is (after the series is wholly
>> pushed), what is the advantage of "(gdb) compile printf"
>> over "(gdb) compile print printf (...)" and "(gdb) call printf (...)".
> 
> This patch, that is
> 	[PATCH v3 8/9] compile: New compile printf
> without the part
> 	[PATCH v3 9/9] compile: compile printf: gdbserver support
> is really just that
> 	(gdb) compile print printf (...)
> and the patch is also therefore very simple.
> 
> According to Phil - roughly, not citing - such 'compile printf' was simple
> enough to code to make it worth such a feature, despite it has many
> shortcomings.

OK, since we don't have a real use case of calling the
inferior's printf (other than because it's seemingly simple), I'd
rather we avoid it and do as outlined in the previous email.

>> Agreed on the latter, but the question really is: why do we need
>> "set compile-printf-args" instead of using "set compile-args" for
>> all expression evaluation through the compiler?
>> Shouldn't "-Werror=format" be in "set compile-args" too?
> 
> Why not, this is a matter of opinion.  IMO cc itself should have -Werror by
> default as otherwise by default it is willing to knowingly produce crashing
> programs.  The only safe warnings are -Wunused* ones and maybe few others.
> So again, this patch tries to make minimal changes to what is the current
> established wrong standard.

The minimal change then is putting -Werror=format in "set compile-args".
Sounds like you're OK with that; let's do it.

Thanks,
Pedro Alves
  

Patch

diff --git a/gdb/compile/compile-c-support.c b/gdb/compile/compile-c-support.c
index 86b02cf..92c41b6 100644
--- a/gdb/compile/compile-c-support.c
+++ b/gdb/compile/compile-c-support.c
@@ -206,7 +206,17 @@  add_code_header (enum compile_i_scope_types type, struct ui_file *buf)
 			") {\n",
 			buf);
       break;
-
+    case COMPILE_I_PRINTF_SCOPE:
+      fputs_unfiltered ("#include <stdio.h>\n"
+			"void "
+			GCC_FE_WRAPPER_FUNCTION
+			" (struct "
+			COMPILE_I_SIMPLE_REGISTER_STRUCT_TAG
+			" *"
+			COMPILE_I_SIMPLE_REGISTER_ARG_NAME
+			") {\n",
+			buf);
+      break;
     case COMPILE_I_RAW_SCOPE:
       break;
     default:
@@ -226,6 +236,7 @@  add_code_footer (enum compile_i_scope_types type, struct ui_file *buf)
     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:
@@ -390,7 +401,8 @@  c_compute_program (struct compile_instance *inst,

   if (inst->scope == COMPILE_I_SIMPLE_SCOPE
       || inst->scope == COMPILE_I_PRINT_ADDRESS_SCOPE
-      || inst->scope == COMPILE_I_PRINT_VALUE_SCOPE)
+      || inst->scope == COMPILE_I_PRINT_VALUE_SCOPE
+      || inst->scope == COMPILE_I_PRINTF_SCOPE)
     {
       ui_file_put (var_stream, ui_file_write_for_put, buf);
       fputs_unfiltered ("#pragma GCC user_expression\n", buf);
@@ -418,6 +430,11 @@  c_compute_program (struct compile_instance *inst,
 			  (inst->scope == COMPILE_I_PRINT_ADDRESS_SCOPE
 			   ? "&" : ""));
       break;
+    case COMPILE_I_PRINTF_SCOPE:
+      fprintf_unfiltered (buf,
+"printf (%s);\n"
+			  , input);
+      break;
     default:
       fputs_unfiltered (input, buf);
       break;
diff --git a/gdb/compile/compile-object-load.c b/gdb/compile/compile-object-load.c
index e67e5ba..bc74590 100644
--- a/gdb/compile/compile-object-load.c
+++ b/gdb/compile/compile-object-load.c
@@ -470,7 +470,7 @@  static struct type *
 get_regs_type (struct symbol *func_sym, struct objfile *objfile)
 {
   struct type *func_type = SYMBOL_TYPE (func_sym);
-  struct type *regsp_type, *regs_type;
+  struct type *regsp_type, *regs_type, *void_type, *voidp_type;

   /* No register parameter present.  */
   if (TYPE_NFIELDS (func_type) == 0)
@@ -490,6 +490,18 @@  get_regs_type (struct symbol *func_sym, struct objfile *objfile)
 	   TYPE_CODE (regs_type), GCC_FE_WRAPPER_FUNCTION,
 	   objfile_name (objfile));

+  /* No register parameter present.  */
+  if (TYPE_NFIELDS (func_type) == 1)
+    return regs_type;
+
+  void_type = builtin_type (target_gdbarch ())->builtin_void;
+  voidp_type = lookup_pointer_type (void_type);
+  if (!types_deeply_equal (voidp_type, TYPE_FIELD_TYPE (func_type, 1)))
+    error (_("Invalid type of function \"%s\" parameter \"%s\" in compiled "
+	    "module \"%s\"."),
+	  GCC_FE_WRAPPER_FUNCTION, COMPILE_I_PRINT_OUT_ARG,
+	  objfile_name (objfile));
+
   return regs_type;
 }

@@ -637,6 +649,10 @@  compile_object_load (const char *object_file, const char *source_file,
       expect_parameters = 2;
       expect_return_type = builtin_type (target_gdbarch ())->builtin_void;
       break;
+    case COMPILE_I_PRINTF_SCOPE:
+      expect_parameters = 1;
+      expect_return_type = builtin_type (target_gdbarch ())->builtin_void;
+      break;
     default:
       internal_error (__FILE__, __LINE__, _("invalid scope %d"), scope);
     }
diff --git a/gdb/compile/compile.c b/gdb/compile/compile.c
index c4b8f2e..6bbe8df 100644
--- a/gdb/compile/compile.c
+++ b/gdb/compile/compile.c
@@ -174,17 +174,14 @@  compile_print_value (struct value *val, void *data_voidp)
   print_value (val, fmtp);
 }

-/* Handle the input from the 'compile print' command.  The "compile
-   print" command is used to evaluate and print an expression that may
-   contain calls to the GCC compiler.  The language expected in this
-   compile command is the language currently set in GDB.  */
+/* Implement 'compile print' and 'compile printf' command according
+   to SCOPE.  */

 static void
-compile_print_command (char *arg_param, int from_tty)
+compile_print (char *arg_param, enum compile_i_scope_types scope)
 {
   const char *arg = arg_param;
   struct cleanup *cleanup;
-  enum compile_i_scope_types scope = COMPILE_I_PRINT_ADDRESS_SCOPE;
   struct format_data *fmtp;

   cleanup = make_cleanup_restore_integer (&interpreter_async);
@@ -207,6 +204,25 @@  compile_print_command (char *arg_param, int from_tty)
   do_cleanups (cleanup);
 }

+/* Handle the input from the 'compile print' command.  The "compile
+   print" command is used to evaluate and print an expression that may
+   contain calls to the GCC compiler.  The language expected in this
+   compile command is the language currently set in GDB.  */
+
+static void
+compile_print_command (char *arg, int from_tty)
+{
+  compile_print (arg, COMPILE_I_PRINT_ADDRESS_SCOPE);
+}
+
+/* Handle the input from the 'compile printf' command.  */
+
+static void
+compile_printf_command (char *arg, int from_tty)
+{
+  compile_print (arg, COMPILE_I_PRINTF_SCOPE);
+}
+
 /* A cleanup function to remove a directory and all its contents.  */

 static void
@@ -308,6 +324,14 @@  static char *compile_args;
 static int compile_args_argc;
 static char **compile_args_argv;

+/* String for 'set compile-printf-args' and 'show compile-printf-args'.  */
+static char *compile_printf_args;
+
+/* Parsed form of COMPILE_PRINTF_ARGS.
+   COMPILE_PRINTF_ARGS_ARGV is NULL terminated.  */
+static int compile_printf_args_argc;
+static char **compile_printf_args_argv;
+
 /* Implement 'set compile-args'.  */

 static void
@@ -328,6 +352,27 @@  show_compile_args (struct ui_file *file, int from_tty,
 		    value);
 }

+/* Implement 'set compile-printf-args'.  */
+
+static void
+set_compile_printf_args (char *args, int from_tty, struct cmd_list_element *c)
+{
+  freeargv (compile_printf_args_argv);
+  build_argc_argv (compile_printf_args,
+		   &compile_printf_args_argc, &compile_printf_args_argv);
+}
+
+/* Implement 'show compile-printf-args'.  */
+
+static void
+show_compile_printf_args (struct ui_file *file, int from_tty,
+		   struct cmd_list_element *c, const char *value)
+{
+  fprintf_filtered (file, _("Compile printf command command-line arguments "
+			    "are \"%s\".\n"),
+		    value);
+}
+
 /* Append ARGC and ARGV (as parsed by build_argc_argv) to *ARGCP and *ARGVP.
    ARGCP+ARGVP can be zero+NULL and also ARGC+ARGV can be zero+NULL.  */

@@ -422,6 +467,10 @@  get_args (const struct compile_instance *compiler, struct gdbarch *gdbarch,
   freeargv (argv_compiler);

   append_args (argcp, argvp, compile_args_argc, compile_args_argv);
+
+  if (compiler->scope == COMPILE_I_PRINTF_SCOPE)
+    append_args (argcp, argvp,
+		 compile_printf_args_argc, compile_printf_args_argv);
 }

 /* A cleanup function to destroy a gdb_gcc_instance.  */
@@ -727,6 +776,24 @@  EXPR may be preceded with /FMT, where FMT is a format letter\n\
 but no count or size letter (see \"x\" command)."),
 	   &compile_command_list);

+  add_cmd ("printf", class_obscure, compile_printf_command,
+	   _("\
+Print formatted output with the compiler.\n\
+\n\
+Usage: compile printf \"printf format string\", arg1, arg2, arg3, ..., argn\n\
+\n\
+The arguments may be specified on the same line as the command, e.g.:\n\
+\n\
+    compile printf \"%d\\n\", i\n\
+\n\
+Alternatively, you can type the arguments interactively.\n\
+You can invoke this mode when no argument is given to the command\n\
+(i.e., \"compile printf\" is typed with nothing after it).  An\n\
+interactive prompt will be shown allowing you to enter multiple\n\
+lines of source code.  Type a line containing \"end\" to indicate\n\
+the end of the source code."),
+	   &compile_command_list);
+
   add_setshow_boolean_cmd ("compile", class_maintenance, &compile_debug, _("\
 Set compile command debugging."), _("\
 Show compile command debugging."), _("\
@@ -744,6 +811,15 @@  String quoting is parsed like in shell, for example:\n\
   -mno-align-double \"-I/dir with a space/include\""),
 			  set_compile_args, show_compile_args, &setlist, &showlist);

+  add_setshow_string_cmd ("compile-printf-args", class_support,
+			  &compile_printf_args,
+			  _("Set compile command GCC command-line arguments FIXME"),
+			  _("Show compile command GCC command-line arguments FIXME"),
+			  _("\
+Use options like -Werror which get added for 'compile printf' command."),
+			  set_compile_printf_args, show_compile_printf_args,
+			  &setlist, &showlist);
+
   /* Override flags possibly coming from DW_AT_producer.  */
   compile_args = xstrdup ("-O0 -gdwarf-4"
   /* We use -fPIE Otherwise GDB would need to reserve space large enough for
@@ -762,4 +838,7 @@  String quoting is parsed like in shell, for example:\n\
 			 " -fno-stack-protector"
   );
   set_compile_args (compile_args, 0, NULL);
+
+  compile_printf_args = xstrdup ("-Werror=format");
+  set_compile_printf_args (compile_printf_args, 0, NULL);
 }
diff --git a/gdb/defs.h b/gdb/defs.h
index 8da7d24..0bcb7f0 100644
--- a/gdb/defs.h
+++ b/gdb/defs.h
@@ -73,9 +73,16 @@  enum compile_i_scope_types

     /* A printable expression scope.  Wrap an expression into a scope
        suitable for the "compile print" command.  It uses the generic
-       function name "_gdb_expr". */
+       function name "_gdb_expr".  COMPILE_I_PRINT_ADDRESS_SCOPE variant
+       is the usual one, taking address of the object.
+       COMPILE_I_PRINT_VALUE_SCOPE is needed for arrays where the array
+       name already specifies its address.  */
     COMPILE_I_PRINT_ADDRESS_SCOPE,
     COMPILE_I_PRINT_VALUE_SCOPE,
+
+    /* Implement the "compile printf" command.  SCOPE_DATA contains
+       string containing the format string together with its arguments.  */
+    COMPILE_I_PRINTF_SCOPE,
   };

 /* Just in case they're not defined in stdio.h.  */
diff --git a/gdb/testsuite/gdb.compile/compile-print.exp b/gdb/testsuite/gdb.compile/compile-print.exp
index 92c6240..14fd489 100644
--- a/gdb/testsuite/gdb.compile/compile-print.exp
+++ b/gdb/testsuite/gdb.compile/compile-print.exp
@@ -56,3 +56,8 @@  gdb_test "compile print/x 256" " = 0x100"
 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/doc/gdb.texinfo |   14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/gdb/compile/compile-c-support.c b/gdb/compile/compile-c-support.c
index 86b02cf..92c41b6 100644
--- a/gdb/compile/compile-c-support.c
+++ b/gdb/compile/compile-c-support.c
@@ -206,7 +206,17 @@  add_code_header (enum compile_i_scope_types type, struct ui_file *buf)
 			") {\n",
 			buf);
       break;
-
+    case COMPILE_I_PRINTF_SCOPE:
+      fputs_unfiltered ("#include <stdio.h>\n"
+			"void "
+			GCC_FE_WRAPPER_FUNCTION
+			" (struct "
+			COMPILE_I_SIMPLE_REGISTER_STRUCT_TAG
+			" *"
+			COMPILE_I_SIMPLE_REGISTER_ARG_NAME
+			") {\n",
+			buf);
+      break;
     case COMPILE_I_RAW_SCOPE:
       break;
     default:
@@ -226,6 +236,7 @@  add_code_footer (enum compile_i_scope_types type, struct ui_file *buf)
     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:
@@ -390,7 +401,8 @@  c_compute_program (struct compile_instance *inst,
 
   if (inst->scope == COMPILE_I_SIMPLE_SCOPE
       || inst->scope == COMPILE_I_PRINT_ADDRESS_SCOPE
-      || inst->scope == COMPILE_I_PRINT_VALUE_SCOPE)
+      || inst->scope == COMPILE_I_PRINT_VALUE_SCOPE
+      || inst->scope == COMPILE_I_PRINTF_SCOPE)
     {
       ui_file_put (var_stream, ui_file_write_for_put, buf);
       fputs_unfiltered ("#pragma GCC user_expression\n", buf);
@@ -418,6 +430,11 @@  c_compute_program (struct compile_instance *inst,
 			  (inst->scope == COMPILE_I_PRINT_ADDRESS_SCOPE
 			   ? "&" : ""));
       break;
+    case COMPILE_I_PRINTF_SCOPE:
+      fprintf_unfiltered (buf,
+"printf (%s);\n"
+			  , input);
+      break;
     default:
       fputs_unfiltered (input, buf);
       break;
diff --git a/gdb/compile/compile-object-load.c b/gdb/compile/compile-object-load.c
index e67e5ba..bc74590 100644
--- a/gdb/compile/compile-object-load.c
+++ b/gdb/compile/compile-object-load.c
@@ -470,7 +470,7 @@  static struct type *
 get_regs_type (struct symbol *func_sym, struct objfile *objfile)
 {
   struct type *func_type = SYMBOL_TYPE (func_sym);
-  struct type *regsp_type, *regs_type;
+  struct type *regsp_type, *regs_type, *void_type, *voidp_type;
 
   /* No register parameter present.  */
   if (TYPE_NFIELDS (func_type) == 0)
@@ -490,6 +490,18 @@  get_regs_type (struct symbol *func_sym, struct objfile *objfile)
 	   TYPE_CODE (regs_type), GCC_FE_WRAPPER_FUNCTION,
 	   objfile_name (objfile));
 
+  /* No register parameter present.  */
+  if (TYPE_NFIELDS (func_type) == 1)
+    return regs_type;
+
+  void_type = builtin_type (target_gdbarch ())->builtin_void;
+  voidp_type = lookup_pointer_type (void_type);
+  if (!types_deeply_equal (voidp_type, TYPE_FIELD_TYPE (func_type, 1)))
+    error (_("Invalid type of function \"%s\" parameter \"%s\" in compiled "
+	    "module \"%s\"."),
+	  GCC_FE_WRAPPER_FUNCTION, COMPILE_I_PRINT_OUT_ARG,
+	  objfile_name (objfile));
+
   return regs_type;
 }
 
@@ -637,6 +649,10 @@  compile_object_load (const char *object_file, const char *source_file,
       expect_parameters = 2;
       expect_return_type = builtin_type (target_gdbarch ())->builtin_void;
       break;
+    case COMPILE_I_PRINTF_SCOPE:
+      expect_parameters = 1;
+      expect_return_type = builtin_type (target_gdbarch ())->builtin_void;
+      break;
     default:
       internal_error (__FILE__, __LINE__, _("invalid scope %d"), scope);
     }
diff --git a/gdb/compile/compile.c b/gdb/compile/compile.c
index 424a25b..0e92e27 100644
--- a/gdb/compile/compile.c
+++ b/gdb/compile/compile.c
@@ -174,17 +174,14 @@  compile_print_value (struct value *val, void *data_voidp)
   print_value (val, fmtp);
 }
 
-/* Handle the input from the 'compile print' command.  The "compile
-   print" command is used to evaluate and print an expression that may
-   contain calls to the GCC compiler.  The language expected in this
-   compile command is the language currently set in GDB.  */
+/* Implement 'compile print' and 'compile printf' command according
+   to SCOPE.  */
 
 static void
-compile_print_command (char *arg_param, int from_tty)
+compile_print (char *arg_param, enum compile_i_scope_types scope)
 {
   const char *arg = arg_param;
   struct cleanup *cleanup;
-  enum compile_i_scope_types scope = COMPILE_I_PRINT_ADDRESS_SCOPE;
   struct format_data *fmtp;
 
   cleanup = make_cleanup_restore_integer (&interpreter_async);
@@ -207,6 +204,25 @@  compile_print_command (char *arg_param, int from_tty)
   do_cleanups (cleanup);
 }
 
+/* Handle the input from the 'compile print' command.  The "compile
+   print" command is used to evaluate and print an expression that may
+   contain calls to the GCC compiler.  The language expected in this
+   compile command is the language currently set in GDB.  */
+
+static void
+compile_print_command (char *arg, int from_tty)
+{
+  compile_print (arg, COMPILE_I_PRINT_ADDRESS_SCOPE);
+}
+
+/* Handle the input from the 'compile printf' command.  */
+
+static void
+compile_printf_command (char *arg, int from_tty)
+{
+  compile_print (arg, COMPILE_I_PRINTF_SCOPE);
+}
+
 /* A cleanup function to remove a directory and all its contents.  */
 
 static void
@@ -308,6 +324,14 @@  static char *compile_args;
 static int compile_args_argc;
 static char **compile_args_argv;
 
+/* String for 'set compile-printf-args' and 'show compile-printf-args'.  */
+static char *compile_printf_args;
+
+/* Parsed form of COMPILE_PRINTF_ARGS.
+   COMPILE_PRINTF_ARGS_ARGV is NULL terminated.  */
+static int compile_printf_args_argc;
+static char **compile_printf_args_argv;
+
 /* Implement 'set compile-args'.  */
 
 static void
@@ -328,6 +352,27 @@  show_compile_args (struct ui_file *file, int from_tty,
 		    value);
 }
 
+/* Implement 'set compile-printf-args'.  */
+
+static void
+set_compile_printf_args (char *args, int from_tty, struct cmd_list_element *c)
+{
+  freeargv (compile_printf_args_argv);
+  build_argc_argv (compile_printf_args,
+		   &compile_printf_args_argc, &compile_printf_args_argv);
+}
+
+/* Implement 'show compile-printf-args'.  */
+
+static void
+show_compile_printf_args (struct ui_file *file, int from_tty,
+		   struct cmd_list_element *c, const char *value)
+{
+  fprintf_filtered (file, _("Compile printf command command-line arguments "
+			    "are \"%s\".\n"),
+		    value);
+}
+
 /* Append ARGC and ARGV (as parsed by build_argc_argv) to *ARGCP and *ARGVP.
    ARGCP+ARGVP can be zero+NULL and also ARGC+ARGV can be zero+NULL.  */
 
@@ -422,6 +467,10 @@  get_args (const struct compile_instance *compiler, struct gdbarch *gdbarch,
   freeargv (argv_compiler);
 
   append_args (argcp, argvp, compile_args_argc, compile_args_argv);
+
+  if (compiler->scope == COMPILE_I_PRINTF_SCOPE)
+    append_args (argcp, argvp,
+		 compile_printf_args_argc, compile_printf_args_argv);
 }
 
 /* A cleanup function to destroy a gdb_gcc_instance.  */
@@ -723,6 +772,24 @@  EXPR may be preceded with /FMT, where FMT is a format letter\n\
 but no count or size letter (see \"x\" command)."),
 	   &compile_command_list);
 
+  add_cmd ("printf", class_obscure, compile_printf_command,
+	   _("\
+Print formatted output with the compiler.\n\
+\n\
+Usage: compile printf \"printf format string\", arg1, arg2, arg3, ..., argn\n\
+\n\
+The arguments may be specified on the same line as the command, e.g.:\n\
+\n\
+    compile printf \"%d\\n\", i\n\
+\n\
+Alternatively, you can type the arguments interactively.\n\
+You can invoke this mode when no argument is given to the command\n\
+(i.e., \"compile printf\" is typed with nothing after it).  An\n\
+interactive prompt will be shown allowing you to enter multiple\n\
+lines of source code.  Type a line containing \"end\" to indicate\n\
+the end of the source code."),
+	   &compile_command_list);
+
   add_setshow_boolean_cmd ("compile", class_maintenance, &compile_debug, _("\
 Set compile command debugging."), _("\
 Show compile command debugging."), _("\
@@ -740,6 +807,15 @@  String quoting is parsed like in shell, for example:\n\
   -mno-align-double \"-I/dir with a space/include\""),
 			  set_compile_args, show_compile_args, &setlist, &showlist);
 
+  add_setshow_string_cmd ("compile-printf-args", class_support,
+			  &compile_printf_args,
+			  _("Set compile command GCC command-line arguments FIXME"),
+			  _("Show compile command GCC command-line arguments FIXME"),
+			  _("\
+Use options like -Werror which get added for 'compile printf' command."),
+			  set_compile_printf_args, show_compile_printf_args,
+			  &setlist, &showlist);
+
   /* Override flags possibly coming from DW_AT_producer.  */
   compile_args = xstrdup ("-O0 -gdwarf-4"
   /* We use -fPIE Otherwise GDB would need to reserve space large enough for
@@ -758,4 +834,7 @@  String quoting is parsed like in shell, for example:\n\
 			 " -fno-stack-protector"
   );
   set_compile_args (compile_args, 0, NULL);
+
+  compile_printf_args = xstrdup ("-Werror=format");
+  set_compile_printf_args (compile_printf_args, 0, NULL);
 }
diff --git a/gdb/defs.h b/gdb/defs.h
index 1c6f118..a62740a 100644
--- a/gdb/defs.h
+++ b/gdb/defs.h
@@ -79,6 +79,10 @@  enum compile_i_scope_types
        name already specifies its address.  */
     COMPILE_I_PRINT_ADDRESS_SCOPE,
     COMPILE_I_PRINT_VALUE_SCOPE,
+
+    /* Implement the "compile printf" command.  SCOPE_DATA contains
+       string containing the format string together with its arguments.  */
+    COMPILE_I_PRINTF_SCOPE,
   };
 
 /* Just in case they're not defined in stdio.h.  */
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 65357ae..6688674 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -17235,6 +17235,20 @@  command without any text following the command.  This will start the
 multiple-line editor.
 @end table
 
+@table @code
+@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}).
+
+@item compile printf
+@cindex reprint the last value
+Alternatively you can enter the template and expression (source code
+producing them) as multiple lines of text.  To enter this mode, invoke
+the @samp{compile printf} command without any text following the
+command.  This will start the multiple-line editor.
+@end table
+
 @noindent
 The process of compiling and injecting the code can be inspected using:
 
diff --git a/gdb/testsuite/gdb.compile/compile-print.exp b/gdb/testsuite/gdb.compile/compile-print.exp
index 92c6240..14fd489 100644
--- a/gdb/testsuite/gdb.compile/compile-print.exp
+++ b/gdb/testsuite/gdb.compile/compile-print.exp
@@ -56,3 +56,8 @@  gdb_test "compile print/x 256" " = 0x100"
 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\\."
+}