Rename _const functions to use overloading instead
[deliverable/binutils-gdb.git] / gdb / compile / compile.c
index c204a135ef2a8f865b8028e8d6fa2511d1d4f217..4a2f339373e5f5ae87f5a7008fcb025ad994cb1f 100644 (file)
@@ -1,6 +1,6 @@
 /* General Compile and inject code
 
-   Copyright (C) 2014-2015 Free Software Foundation, Inc.
+   Copyright (C) 2014-2017 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
@@ -18,7 +18,7 @@
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include "defs.h"
-#include "interps.h"
+#include "top.h"
 #include "ui-out.h"
 #include "command.h"
 #include "cli/cli-script.h"
@@ -38,6 +38,9 @@
 #include "target.h"
 #include "osabi.h"
 #include "gdb_wait.h"
+#include "valprint.h"
+#include "common/gdb_optional.h"
+#include "common/gdb_unlinker.h"
 
 \f
 
@@ -87,11 +90,8 @@ static void
 compile_file_command (char *arg, int from_tty)
 {
   enum compile_i_scope_types scope = COMPILE_I_SIMPLE_SCOPE;
-  char *buffer;
-  struct cleanup *cleanup;
 
-  cleanup = make_cleanup_restore_integer (&interpreter_async);
-  interpreter_async = 0;
+  scoped_restore save_async = make_scoped_restore (&current_ui->async, 0);
 
   /* Check the user did not just <enter> after command.  */
   if (arg == NULL)
@@ -113,12 +113,9 @@ compile_file_command (char *arg, int from_tty)
     error (_("Unknown argument specified."));
 
   arg = skip_spaces (arg);
-  arg = gdb_abspath (arg);
-  make_cleanup (xfree, arg);
-  buffer = xstrprintf ("#include \"%s\"\n", arg);
-  make_cleanup (xfree, buffer);
-  eval_compile_command (NULL, buffer, scope);
-  do_cleanups (cleanup);
+  gdb::unique_xmalloc_ptr<char> abspath = gdb_abspath (arg);
+  std::string buffer = string_printf ("#include \"%s\"\n", abspath.get ());
+  eval_compile_command (NULL, buffer.c_str (), scope, NULL);
 }
 
 /* Handle the input from the 'compile code' command.  The
@@ -129,11 +126,9 @@ compile_file_command (char *arg, int from_tty)
 static void
 compile_code_command (char *arg, int from_tty)
 {
-  struct cleanup *cleanup;
   enum compile_i_scope_types scope = COMPILE_I_SIMPLE_SCOPE;
 
-  cleanup = make_cleanup_restore_integer (&interpreter_async);
-  interpreter_async = 0;
+  scoped_restore save_async = make_scoped_restore (&current_ui->async, 0);
 
   if (arg != NULL && check_raw_argument (&arg))
     {
@@ -150,17 +145,54 @@ compile_code_command (char *arg, int from_tty)
     }
 
   if (arg && *arg)
-      eval_compile_command (NULL, arg, scope);
+    eval_compile_command (NULL, arg, scope, NULL);
   else
     {
-      struct command_line *l = get_command_line (compile_control, "");
+      command_line_up l = get_command_line (compile_control, "");
 
-      make_cleanup_free_command_lines (&l);
       l->control_u.compile.scope = scope;
-      execute_control_command_untraced (l);
+      execute_control_command_untraced (l.get ());
     }
+}
 
-  do_cleanups (cleanup);
+/* Callback for compile_print_command.  */
+
+void
+compile_print_value (struct value *val, void *data_voidp)
+{
+  const struct format_data *fmtp = (const struct format_data *) 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.  */
+
+static void
+compile_print_command (char *arg_param, int from_tty)
+{
+  const char *arg = arg_param;
+  enum compile_i_scope_types scope = COMPILE_I_PRINT_ADDRESS_SCOPE;
+  struct format_data fmt;
+
+  scoped_restore save_async = make_scoped_restore (&current_ui->async, 0);
+
+  /* Passing &FMT as SCOPE_DATA is safe as do_module_cleanup will not
+     touch the stale pointer if compile_object_run has already quit.  */
+  print_command_parse_format (&arg, "compile print", &fmt);
+
+  if (arg && *arg)
+    eval_compile_command (NULL, arg, scope, &fmt);
+  else
+    {
+      command_line_up l = get_command_line (compile_control, "");
+
+      l->control_u.compile.scope = scope;
+      l->control_u.compile.scope_data = &fmt;
+      execute_control_command_untraced (l.get ());
+    }
 }
 
 /* A cleanup function to remove a directory and all its contents.  */
@@ -168,11 +200,11 @@ compile_code_command (char *arg, int from_tty)
 static void
 do_rmdir (void *arg)
 {
-  const char *dir = arg;
+  const char *dir = (const char *) arg;
   char *zap;
   int wstat;
 
-  gdb_assert (strncmp (dir, TMP_PREFIX, strlen (TMP_PREFIX)) == 0);
+  gdb_assert (startswith (dir, TMP_PREFIX));
   zap = concat ("rm -rf ", dir, (char *) NULL);
   wstat = system (zap);
   if (wstat == -1 || !WIFEXITED (wstat) || WEXITSTATUS (wstat) != 0)
@@ -209,18 +241,20 @@ get_compile_file_tempdir (void)
   return tempdir_name;
 }
 
-/* Compute the names of source and object files to use.  The names are
-   allocated by malloc and should be freed by the caller.  */
+/* Compute the names of source and object files to use.  */
 
-static void
-get_new_file_names (char **source_file, char **object_file)
+static compile_file_names
+get_new_file_names ()
 {
   static int seq;
   const char *dir = get_compile_file_tempdir ();
 
   ++seq;
-  *source_file = xstrprintf ("%s%sout%d.c", dir, SLASH_STRING, seq);
-  *object_file = xstrprintf ("%s%sout%d.o", dir, SLASH_STRING, seq);
+
+  return compile_file_names (string_printf ("%s%sout%d.c",
+                                           dir, SLASH_STRING, seq),
+                            string_printf ("%s%sout%d.o",
+                                           dir, SLASH_STRING, seq));
 }
 
 /* Get the block and PC at which to evaluate an expression.  */
@@ -246,15 +280,17 @@ get_expr_block_and_pc (CORE_ADDR *pc)
   return block;
 }
 
-/* Call gdb_buildargv, set its result for S into *ARGVP but calculate also the
-   number of parsed arguments into *ARGCP.  If gdb_buildargv has returned NULL
-   then *ARGCP is set to zero.  */
+/* Call buildargv (via gdb_argv), set its result for S into *ARGVP but
+   calculate also the number of parsed arguments into *ARGCP.  If
+   buildargv has returned NULL then *ARGCP is set to zero.  */
 
 static void
 build_argc_argv (const char *s, int *argcp, char ***argvp)
 {
-  *argvp = gdb_buildargv (s);
-  *argcp = countargv (*argvp);
+  gdb_argv args (s);
+
+  *argcp = args.count ();
+  *argvp = args.release ();
 }
 
 /* String for 'set compile-args' and 'show compile-args'.  */
@@ -292,13 +328,26 @@ append_args (int *argcp, char ***argvp, int argc, char **argv)
 {
   int argi;
 
-  *argvp = xrealloc (*argvp, (*argcp + argc + 1) * sizeof (**argvp));
+  *argvp = XRESIZEVEC (char *, *argvp, (*argcp + argc + 1));
 
   for (argi = 0; argi < argc; argi++)
     (*argvp)[(*argcp)++] = xstrdup (argv[argi]);
   (*argvp)[(*argcp)] = NULL;
 }
 
+/* String for 'set compile-gcc' and 'show compile-gcc'.  */
+static char *compile_gcc;
+
+/* Implement 'show compile-gcc'.  */
+
+static void
+show_compile_gcc (struct ui_file *file, int from_tty,
+                 struct cmd_list_element *c, const char *value)
+{
+  fprintf_filtered (file, _("Compile command GCC driver filename is \"%s\".\n"),
+                   value);
+}
+
 /* Return DW_AT_producer parsed for get_selected_frame () (if any).
    Return NULL otherwise.
 
@@ -313,12 +362,12 @@ get_selected_pc_producer_options (void)
   const char *cs;
 
   if (symtab == NULL || symtab->producer == NULL
-      || strncmp (symtab->producer, "GNU ", strlen ("GNU ")) != 0)
+      || !startswith (symtab->producer, "GNU "))
     return NULL;
 
   cs = symtab->producer;
   while (*cs != 0 && *cs != '-')
-    cs = skip_spaces_const (skip_to_space_const (cs));
+    cs = skip_spaces (skip_to_space (cs));
   if (*cs != '-')
     return NULL;
   return cs;
@@ -385,21 +434,11 @@ get_args (const struct compile_instance *compiler, struct gdbarch *gdbarch,
 static void
 cleanup_compile_instance (void *arg)
 {
-  struct compile_instance *inst = arg;
+  struct compile_instance *inst = (struct compile_instance *) arg;
 
   inst->destroy (inst);
 }
 
-/* A cleanup function to unlink a file.  */
-
-static void
-cleanup_unlink_file (void *arg)
-{
-  const char *filename = arg;
-
-  unlink (filename);
-}
-
 /* A helper function suitable for use as the "print_callback" in the
    compiler object.  */
 
@@ -410,19 +449,15 @@ print_callback (void *ignore, const char *message)
 }
 
 /* Process the compilation request.  On success it returns the object
-   file name and *SOURCE_FILEP is set to source file name.  On an
-   error condition, error () is called.  The caller is responsible for
-   freeing both strings.  */
-
-static char *
-compile_to_object (struct command_line *cmd, char *cmd_string,
-                  enum compile_i_scope_types scope,
-                  char **source_filep)
+   and source file names.  On an error condition, error () is
+   called.  */
+
+static compile_file_names
+compile_to_object (struct command_line *cmd, const char *cmd_string,
+                  enum compile_i_scope_types scope)
 {
-  char *code;
-  char *source_file, *object_file;
   struct compile_instance *compiler;
-  struct cleanup *cleanup, *inner_cleanup;
+  struct cleanup *cleanup;
   const struct block *expr_block;
   CORE_ADDR trash_pc, expr_pc;
   int argc;
@@ -430,8 +465,6 @@ compile_to_object (struct command_line *cmd, char *cmd_string,
   int ok;
   FILE *src;
   struct gdbarch *gdbarch = get_current_arch ();
-  const char *os_rx;
-  const char *arch_rx;
   char *triplet_rx;
   char *error_message;
 
@@ -444,7 +477,8 @@ compile_to_object (struct command_line *cmd, char *cmd_string,
 
   /* Set up instance and context for the compiler.  */
   if (current_language->la_get_compile_instance == NULL)
-    error (_("No compiler support for this language."));
+    error (_("No compiler support for language %s."),
+          current_language->la_name);
   compiler = current_language->la_get_compile_instance ();
   cleanup = make_cleanup (cleanup_compile_instance, compiler);
 
@@ -455,43 +489,66 @@ compile_to_object (struct command_line *cmd, char *cmd_string,
 
   /* From the provided expression, build a scope to pass to the
      compiler.  */
+
+  string_file input_buf;
+  const char *input;
+
   if (cmd != NULL)
     {
-      struct ui_file *stream = mem_fileopen ();
       struct command_line *iter;
 
-      make_cleanup_ui_file_delete (stream);
       for (iter = cmd->body_list[0]; iter; iter = iter->next)
        {
-         fputs_unfiltered (iter->line, stream);
-         fputs_unfiltered ("\n", stream);
+         input_buf.puts (iter->line);
+         input_buf.puts ("\n");
        }
 
-      code = ui_file_xstrdup (stream, NULL);
-      make_cleanup (xfree, code);
+      input = input_buf.c_str ();
     }
   else if (cmd_string != NULL)
-    code = cmd_string;
+    input = cmd_string;
   else
     error (_("Neither a simple expression, or a multi-line specified."));
 
-  code = current_language->la_compute_program (compiler, code, gdbarch,
-                                              expr_block, expr_pc);
-  make_cleanup (xfree, code);
+  std::string code
+    = current_language->la_compute_program (compiler, input, gdbarch,
+                                           expr_block, expr_pc);
   if (compile_debug)
-    fprintf_unfiltered (gdb_stdout, "debug output:\n\n%s", code);
+    fprintf_unfiltered (gdb_stdlog, "debug output:\n\n%s", code.c_str ());
 
-  os_rx = osabi_triplet_regexp (gdbarch_osabi (gdbarch));
-  arch_rx = gdbarch_gnu_triplet_regexp (gdbarch);
-  triplet_rx = concat (arch_rx, "-[^-]*-", os_rx, (char *) NULL);
-  make_cleanup (xfree, triplet_rx);
+  if (compiler->fe->ops->version >= GCC_FE_VERSION_1)
+    compiler->fe->ops->set_verbose (compiler->fe, compile_debug);
+
+  if (compile_gcc[0] != 0)
+    {
+      if (compiler->fe->ops->version < GCC_FE_VERSION_1)
+       error (_("Command 'set compile-gcc' requires GCC version 6 or higher "
+                "(libcc1 interface version 1 or higher)"));
+
+      compiler->fe->ops->set_driver_filename (compiler->fe, compile_gcc);
+    }
+  else
+    {
+      const char *os_rx = osabi_triplet_regexp (gdbarch_osabi (gdbarch));
+      const char *arch_rx = gdbarch_gnu_triplet_regexp (gdbarch);
+
+      /* Allow triplets with or without vendor set.  */
+      triplet_rx = concat (arch_rx, "(-[^-]*)?-", os_rx, (char *) NULL);
+      make_cleanup (xfree, triplet_rx);
+
+      if (compiler->fe->ops->version >= GCC_FE_VERSION_1)
+       compiler->fe->ops->set_triplet_regexp (compiler->fe, triplet_rx);
+    }
 
   /* Set compiler command-line arguments.  */
   get_args (compiler, gdbarch, &argc, &argv);
-  make_cleanup_freeargv (argv);
+  gdb_argv argv_holder (argv);
 
-  error_message = compiler->fe->ops->set_arguments (compiler->fe, triplet_rx,
-                                                   argc, argv);
+  if (compiler->fe->ops->version >= GCC_FE_VERSION_1)
+    error_message = compiler->fe->ops->set_arguments (compiler->fe, argc, argv);
+  else
+    error_message = compiler->fe->ops->set_arguments_v0 (compiler->fe, triplet_rx,
+                                                        argc, argv);
   if (error_message != NULL)
     {
       make_cleanup (xfree, error_message);
@@ -502,43 +559,52 @@ compile_to_object (struct command_line *cmd, char *cmd_string,
     {
       int argi;
 
-      fprintf_unfiltered (gdb_stdout, "Passing %d compiler options:\n", argc);
+      fprintf_unfiltered (gdb_stdlog, "Passing %d compiler options:\n", argc);
       for (argi = 0; argi < argc; argi++)
-       fprintf_unfiltered (gdb_stdout, "Compiler option %d: <%s>\n",
+       fprintf_unfiltered (gdb_stdlog, "Compiler option %d: <%s>\n",
                            argi, argv[argi]);
     }
 
-  get_new_file_names (&source_file, &object_file);
-  inner_cleanup = make_cleanup (xfree, source_file);
-  make_cleanup (xfree, object_file);
+  compile_file_names fnames = get_new_file_names ();
+
+  gdb::optional<gdb::unlinker> source_remover;
+
+  {
+    gdb_file_up src = gdb_fopen_cloexec (fnames.source_file (), "w");
+    if (src == NULL)
+      perror_with_name (_("Could not open source file for writing"));
 
-  src = gdb_fopen_cloexec (source_file, "w");
-  if (src == NULL)
-    perror_with_name (_("Could not open source file for writing"));
-  make_cleanup (cleanup_unlink_file, source_file);
-  if (fputs (code, src) == EOF)
-    perror_with_name (_("Could not write to source file"));
-  fclose (src);
+    source_remover.emplace (fnames.source_file ());
+
+    if (fputs (code.c_str (), src.get ()) == EOF)
+      perror_with_name (_("Could not write to source file"));
+  }
 
   if (compile_debug)
-    fprintf_unfiltered (gdb_stdout, "source file produced: %s\n\n",
-                       source_file);
+    fprintf_unfiltered (gdb_stdlog, "source file produced: %s\n\n",
+                       fnames.source_file ());
 
   /* Call the compiler and start the compilation process.  */
-  compiler->fe->ops->set_source_file (compiler->fe, source_file);
+  compiler->fe->ops->set_source_file (compiler->fe, fnames.source_file ());
 
-  if (!compiler->fe->ops->compile (compiler->fe, object_file,
-                                  compile_debug))
+  if (compiler->fe->ops->version >= GCC_FE_VERSION_1)
+    ok = compiler->fe->ops->compile (compiler->fe, fnames.object_file ());
+  else
+    ok = compiler->fe->ops->compile_v0 (compiler->fe, fnames.object_file (),
+                                       compile_debug);
+  if (!ok)
     error (_("Compilation failed."));
 
   if (compile_debug)
-    fprintf_unfiltered (gdb_stdout, "object file produced: %s\n\n",
-                       object_file);
+    fprintf_unfiltered (gdb_stdlog, "object file produced: %s\n\n",
+                       fnames.object_file ());
+
+  /* Keep the source file.  */
+  source_remover->keep ();
 
-  discard_cleanups (inner_cleanup);
   do_cleanups (cleanup);
-  *source_filep = source_file;
-  return object_file;
+
+  return fnames;
 }
 
 /* The "compile" prefix command.  */
@@ -554,36 +620,40 @@ compile_command (char *args, int from_tty)
 /* See compile.h.  */
 
 void
-eval_compile_command (struct command_line *cmd, char *cmd_string,
-                     enum compile_i_scope_types scope)
+eval_compile_command (struct command_line *cmd, const char *cmd_string,
+                     enum compile_i_scope_types scope, void *scope_data)
 {
-  char *object_file, *source_file;
+  struct compile_module *compile_module;
+
+  compile_file_names fnames = compile_to_object (cmd, cmd_string, scope);
 
-  object_file = compile_to_object (cmd, cmd_string, scope, &source_file);
-  if (object_file != NULL)
+  gdb::unlinker object_remover (fnames.object_file ());
+  gdb::unlinker source_remover (fnames.source_file ());
+
+  compile_module = compile_object_load (fnames, scope, scope_data);
+  if (compile_module == NULL)
     {
-      struct cleanup *cleanup_xfree, *cleanup_unlink;
-      struct compile_module *compile_module;
-
-      cleanup_xfree = make_cleanup (xfree, object_file);
-      make_cleanup (xfree, source_file);
-      cleanup_unlink = make_cleanup (cleanup_unlink_file, object_file);
-      make_cleanup (cleanup_unlink_file, source_file);
-      compile_module = compile_object_load (object_file, source_file);
-      discard_cleanups (cleanup_unlink);
-      do_cleanups (cleanup_xfree);
-      compile_object_run (compile_module);
+      gdb_assert (scope == COMPILE_I_PRINT_ADDRESS_SCOPE);
+      eval_compile_command (cmd, cmd_string,
+                           COMPILE_I_PRINT_VALUE_SCOPE, scope_data);
+      return;
     }
+
+  /* Keep the files.  */
+  source_remover.keep ();
+  object_remover.keep ();
+
+  compile_object_run (compile_module);
 }
 
 /* See compile/compile-internal.h.  */
 
-char *
+std::string
 compile_register_name_mangled (struct gdbarch *gdbarch, int regnum)
 {
   const char *regname = gdbarch_register_name (gdbarch, regnum);
 
-  return xstrprintf ("__%s", regname);
+  return string_printf ("__%s", regname);
 }
 
 /* See compile/compile-internal.h.  */
@@ -605,8 +675,6 @@ compile_register_name_demangle (struct gdbarch *gdbarch,
   error (_("Cannot find gdbarch register \"%s\"."), regname);
 }
 
-extern initialize_file_ftype _initialize_compile;
-
 void
 _initialize_compile (void)
 {
@@ -631,12 +699,10 @@ The source code may be specified as a simple one line expression, e.g.:\n\
 \n\
     compile code printf(\"Hello world\\n\");\n\
 \n\
-Alternatively, you can type the source code interactively.\n\
-You can invoke this mode when no argument is given to the command\n\
-(i.e.,\"compile code\" 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."),
+Alternatively, you can type a multiline expression by invoking\n\
+this command with no argument.  GDB will then prompt for the\n\
+expression interactively; type a line containing \"end\" to\n\
+indicate the end of the expression."),
           &compile_command_list);
 
   c = add_cmd ("file", class_obscure, compile_file_command,
@@ -648,6 +714,25 @@ Usage: compile file [-r|-raw] [filename]\n\
               &compile_command_list);
   set_cmd_completer (c, filename_completer);
 
+  add_cmd ("print", class_obscure, compile_print_command,
+          _("\
+Evaluate EXPR by using the compiler and print result.\n\
+\n\
+Usage: compile print[/FMT] [EXPR]\n\
+\n\
+The expression may be specified on the same line as the command, e.g.:\n\
+\n\
+    compile print i\n\
+\n\
+Alternatively, you can type a multiline expression by invoking\n\
+this command with no argument.  GDB will then prompt for the\n\
+expression interactively; type a line containing \"end\" to\n\
+indicate the end of the expression.\n\
+\n\
+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_setshow_boolean_cmd ("compile", class_maintenance, &compile_debug, _("\
 Set compile command debugging."), _("\
 Show compile command debugging."), _("\
@@ -674,10 +759,26 @@ String quoting is parsed like in shell, for example:\n\
      absolute target address.
      -fPIC is not used at is would require from GDB to generate .got.  */
                         " -fPIE"
-  /* We don't want warnings.  */
-                        " -w"
+  /* We want warnings, except for some commonly happening for GDB commands.  */
+                        " -Wall "
+                        " -Wno-implicit-function-declaration"
+                        " -Wno-unused-but-set-variable"
+                        " -Wno-unused-variable"
   /* Override CU's possible -fstack-protector-strong.  */
                         " -fno-stack-protector"
   );
   set_compile_args (compile_args, 0, NULL);
+
+  add_setshow_optional_filename_cmd ("compile-gcc", class_support,
+                                    &compile_gcc,
+                                    _("Set compile command "
+                                      "GCC driver filename"),
+                                    _("Show compile command "
+                                      "GCC driver filename"),
+                                    _("\
+It should be absolute filename of the gcc executable.\n\
+If empty the default target triplet will be searched in $PATH."),
+                                    NULL, show_compile_gcc, &setlist,
+                                    &showlist);
+  compile_gcc = xstrdup ("");
 }
This page took 0.033858 seconds and 4 git commands to generate.