X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;ds=sidebyside;f=gdb%2Fcompile%2Fcompile.c;h=4a2f339373e5f5ae87f5a7008fcb025ad994cb1f;hb=f1735a53a63040cc4b4a735bf18a3f20d308e519;hp=c204a135ef2a8f865b8028e8d6fa2511d1d4f217;hpb=a7606d8083c9e217294f6e47a8d2903716c6337c;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/compile/compile.c b/gdb/compile/compile.c index c204a135ef..4a2f339373 100644 --- a/gdb/compile/compile.c +++ b/gdb/compile/compile.c @@ -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 . */ #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" @@ -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 (¤t_ui->async, 0); /* Check the user did not just 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 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 (¤t_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 (¤t_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 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 (""); }