This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
Re: (Doc ping [for news and manual]) -- [PATCH 14/14] the "compile" command
- From: Phil Muldoon <pmuldoon at redhat dot com>
- To: gdb-patches at sourceware dot org
- Cc: Tom Tromey <tromey at redhat dot com>, "eliz at gnu dot org" <eliz at gnu dot org>
- Date: Mon, 16 Jun 2014 10:54:58 +0100
- Subject: Re: (Doc ping [for news and manual]) -- [PATCH 14/14] the "compile" command
- Authentication-results: sourceware.org; auth=none
- References: <1400253995-12333-1-git-send-email-tromey at redhat dot com> <1400253995-12333-15-git-send-email-tromey at redhat dot com>
On 16/05/14 16:26, Tom Tromey wrote:
> This final patch adds the new "compile" command and subcommands, and
> all the machinery needed to make it work.
>
> A shared library supplied by gcc is used for all communications with
> gcc. Types and most aspects of symbols are provided directly by gdb
> to the compiler using this library.
>
> gdb provides some information about the user's code using plain text.
> Macros are emitted this way, and DWARF location expressions (and
> bounds for VLA) are compiled to C code.
>
> This hybrid approach was taken because, on the one hand, it is better
> to provide global declarations and such on demand; but on the other
> hand, for local variables, translating DWARF location expressions to C
> was much simpler than exporting a full compiler API to gdb -- the same
> result, only easier to implement, understand, and debug.
>
> In the ordinary mode, the user's expression is wrapped in a dummy
> function. After compilation, gdb inserts the resulting object code
> into the inferior, then calls this function.
>
> Access to local variables is provided by noting which registers are
> used by location expressions, and passing a structure of register
> values into the function. Writes to registers are supported by
> copying out these values after the function returns.
>
> This approach was taken so that we could eventually implement other
> more interesting features based on this same infrastructure; for
> example, we're planning to investigate inferior-side breakpoint
> conditions.
>
> 2014-05-16 Phil Muldoon <pmuldoon@redhat.com>
> Jan Kratochvil <jan.kratochvil@redhat.com>
> Tom Tromey <tromey@redhat.com>
>
> * NEWS: Update.
> * symtab.h (struct symbol_computed_ops) <generate_c_location>: New
> field.
> * p-lang.c (pascal_language_defn): Update.
> * opencl-lang.c (opencl_language_defn): Update.
> * objc-lang.c (objc_language_defn): Update.
> * m2-lang.c (m2_language_defn): Update.
> * language.h (struct language_defn) <la_get_compile_instance,
> la_compute_program>: New fields.
> * language.c (unknown_language_defn, auto_language_defn)
> (local_language_defn): Update.
> * jv-lang.c (java_language_defn): Update.
> * go-lang.c (go_language_defn): Update.
> * f-lang.c (f_language_defn): Update.
> * dwarf2loc.h (dwarf2_compile_property_to_c): Declare.
> * dwarf2loc.c (dwarf2_compile_property_to_c)
> (locexpr_generate_c_location, loclist_generate_c_location): New
> functions.
> (dwarf2_locexpr_funcs, dwarf2_loclist_funcs): Update.
> * defs.h (enum compile_i_scope_types): New.
> (enum command_control_type) <compile_control>: New constant.
> (struct command_line) <control_u>: New field.
> * d-lang.c (d_language_defn): Update.
> * compile/compile.c: New file.
> * compile/compile-c-support.c: New file.
> * compile/compile-c-symbols.c: New file.
> * compile/compile-c-types.c: New file.
> * compile/compile.h: New file.
> * compile/compile-internal.h: New file.
> * compile/compile-loc2c.c: New file.
> * compile/compile-object-load.c: New file.
> * compile/compile-object-load.h: New file.
> * compile/compile-object-run.c: New file.
> * compile/compile-object-run.h: New file.
> * cli/cli-script.c (multi_line_command_p, print_command_lines)
> (execute_control_command, process_next_line)
> (recurse_read_control_structure): Handle compile_control.
> * c-lang.h (c_get_compile_context, c_compute_program): Declare.
> * c-lang.c (c_language_defn, cplus_language_defn)
> (asm_language_defn, minimal_language_defn): Update.
> * ada-lang.c (ada_language_defn): Update.
> * Makefile.in (SUBDIR_GCC_COMPILE_OBS, SUBDIR_GCC_COMPILE_SRCS):
> New variables.
> (SFILES): Add SUBDIR_GCC_COMPILE_SRCS.
> (HFILES_NO_SRCDIR): Add compile.h.
> (COMMON_OBS): Add SUBDIR_GCC_COMPILE_OBS.
> (INIT_FILES): Add SUBDIR_GCC_COMPILE_SRCS.
> (compile.o, compile-c-types.o, compile-c-symbols.o)
> (compile-object-load.o, compile-object-run.o, compile-loc2c.o)
> (compile-c-support.o): New targets.
>
> 2014-05-16 Phil Muldoon <pmuldoon@redhat.com>
>
> * gdb.texinfo (Altering): Update.
> (Compiling and Injecting Code): New node.
>
> 2014-05-16 Phil Muldoon <pmuldoon@redhat.com>
> Jan Kratochvil <jan.kratochvil@redhat.com>
> Tom Tromey <tromey@redhat.com>
>
> * gdb.dwarf2/compile-ops.exp: New file.
> * gdb.threads/compile-tls.c: New file.
> * gdb.threads/compile-tls.exp: New file.
> * gdb.base/compile-constvar.S: New file.
> * gdb.base/compile-constvar.c: New file.
> * gdb.base/compile-mod.c: New file.
> * gdb.base/compile-nodebug.c: New file.
> * gdb.base/compile-setjmp-mod.c: New file.
> * gdb.base/compile-setjmp.c: New file.
> * gdb.base/compile-setjmp.exp: New file.
> * gdb.base/compile-shlib.c: New file.
> * gdb.base/compile.c: New file.
> * gdb.base/compile.exp: New file.
> * lib/gdb.exp (skip_compile_feature_tests): New proc.
> ---
> gdb/ChangeLog | 55 ++
> gdb/Makefile.in | 61 +-
> gdb/NEWS | 32 +
> gdb/ada-lang.c | 2 +
> gdb/c-lang.c | 8 +
> gdb/c-lang.h | 19 +
> gdb/cli/cli-script.c | 31 +-
> gdb/compile/compile-c-support.c | 396 +++++++++
> gdb/compile/compile-c-symbols.c | 759 ++++++++++++++++++
> gdb/compile/compile-c-types.c | 438 ++++++++++
> gdb/compile/compile-internal.h | 147 ++++
> gdb/compile/compile-loc2c.c | 1147 +++++++++++++++++++++++++++
> gdb/compile/compile-object-load.c | 570 +++++++++++++
> gdb/compile/compile-object-load.h | 39 +
> gdb/compile/compile-object-run.c | 138 ++++
> gdb/compile/compile-object-run.h | 24 +
> gdb/compile/compile.c | 623 +++++++++++++++
> gdb/compile/compile.h | 102 +++
> gdb/d-lang.c | 2 +
> gdb/defs.h | 28 +
> gdb/doc/ChangeLog | 5 +
> gdb/doc/gdb.texinfo | 242 ++++++
> gdb/dwarf2loc.c | 86 +-
> gdb/dwarf2loc.h | 21 +
> gdb/f-lang.c | 2 +
> gdb/go-lang.c | 2 +
> gdb/jv-lang.c | 2 +
> gdb/language.c | 6 +
> gdb/language.h | 31 +
> gdb/m2-lang.c | 2 +
> gdb/objc-lang.c | 2 +
> gdb/opencl-lang.c | 2 +
> gdb/p-lang.c | 2 +
> gdb/symtab.h | 15 +
> gdb/testsuite/ChangeLog | 19 +
> gdb/testsuite/gdb.base/compile-constvar.S | 95 +++
> gdb/testsuite/gdb.base/compile-constvar.c | 18 +
> gdb/testsuite/gdb.base/compile-mod.c | 26 +
> gdb/testsuite/gdb.base/compile-nodebug.c | 24 +
> gdb/testsuite/gdb.base/compile-setjmp-mod.c | 46 ++
> gdb/testsuite/gdb.base/compile-setjmp.c | 24 +
> gdb/testsuite/gdb.base/compile-setjmp.exp | 34 +
> gdb/testsuite/gdb.base/compile-shlib.c | 26 +
> gdb/testsuite/gdb.base/compile.c | 130 +++
> gdb/testsuite/gdb.base/compile.exp | 357 +++++++++
> gdb/testsuite/gdb.dwarf2/compile-ops.exp | 424 ++++++++++
> gdb/testsuite/gdb.threads/compile-tls.c | 40 +
> gdb/testsuite/gdb.threads/compile-tls.exp | 42 +
> gdb/testsuite/lib/gdb.exp | 17 +
> 49 files changed, 6356 insertions(+), 7 deletions(-)
> create mode 100644 gdb/compile/compile-c-support.c
> create mode 100644 gdb/compile/compile-c-symbols.c
> create mode 100644 gdb/compile/compile-c-types.c
> create mode 100644 gdb/compile/compile-internal.h
> create mode 100644 gdb/compile/compile-loc2c.c
> create mode 100644 gdb/compile/compile-object-load.c
> create mode 100644 gdb/compile/compile-object-load.h
> create mode 100644 gdb/compile/compile-object-run.c
> create mode 100644 gdb/compile/compile-object-run.h
> create mode 100644 gdb/compile/compile.c
> create mode 100644 gdb/compile/compile.h
> create mode 100644 gdb/testsuite/gdb.base/compile-constvar.S
> create mode 100644 gdb/testsuite/gdb.base/compile-constvar.c
> create mode 100644 gdb/testsuite/gdb.base/compile-mod.c
> create mode 100644 gdb/testsuite/gdb.base/compile-nodebug.c
> create mode 100644 gdb/testsuite/gdb.base/compile-setjmp-mod.c
> create mode 100644 gdb/testsuite/gdb.base/compile-setjmp.c
> create mode 100644 gdb/testsuite/gdb.base/compile-setjmp.exp
> create mode 100644 gdb/testsuite/gdb.base/compile-shlib.c
> create mode 100644 gdb/testsuite/gdb.base/compile.c
> create mode 100644 gdb/testsuite/gdb.base/compile.exp
> create mode 100644 gdb/testsuite/gdb.dwarf2/compile-ops.exp
> create mode 100644 gdb/testsuite/gdb.threads/compile-tls.c
> create mode 100644 gdb/testsuite/gdb.threads/compile-tls.exp
>
> diff --git a/gdb/Makefile.in b/gdb/Makefile.in
> index 3efedc8..30cee39 100644
> --- a/gdb/Makefile.in
> +++ b/gdb/Makefile.in
> @@ -280,6 +280,24 @@ SUBDIR_TUI_LDFLAGS=
> SUBDIR_TUI_CFLAGS= \
> -DTUI=1
>
> +#
> +# GCC Compile support sub-directory definitions
> +#
> +SUBDIR_GCC_COMPILE_OBS = \
> + compile.o compile-c-symbols.o compile-c-types.o \
> + compile-object-load.o compile-object-run.o \
> + compile-loc2c.o compile-c-support.o
> +SUBDIR_GCC_COMPILE_SRCS = \
> + compile/compile.c \
> + compile/compile-c-symbols.c \
> + compile/compile-c-types.c \
> + compile/compile-object-load.c \
> + compile/compile-object-load.h \
> + compile/compile-object-run.c \
> + compile/compile-object-run.h \
> + compile/compile-loc2c.c \
> + compile/compile-c-support.c
> +
> # Guile sub directory definitons for guile support.
>
> SUBDIR_GUILE_OBS = \
> @@ -840,7 +858,8 @@ SFILES = ada-exp.y ada-lang.c ada-typeprint.c ada-valprint.c ada-tasks.c \
> common/gdb_vecs.c common/common-utils.c common/xml-utils.c \
> common/ptid.c common/buffer.c gdb-dlfcn.c common/agent.c \
> common/format.c common/filestuff.c btrace.c record-btrace.c ctf.c \
> - target/waitstatus.c common/print-utils.c common/rsp-low.c
> + target/waitstatus.c common/print-utils.c common/rsp-low.c \
> + $(SUBDIR_GCC_COMPILE_SRCS)
>
> LINTFILES = $(SFILES) $(YYFILES) $(CONFIG_SRCS) init.c
>
> @@ -861,7 +880,7 @@ ia64-tdep.h ada-lang.h varobj.h frv-tdep.h nto-tdep.h serial.h \
> c-lang.h d-lang.h go-lang.h frame.h event-loop.h block.h cli/cli-setshow.h \
> cli/cli-decode.h cli/cli-cmds.h cli/cli-utils.h \
> cli/cli-script.h macrotab.h symtab.h common/version.h \
> -gnulib/import/string.in.h gnulib/import/str-two-way.h \
> +compile/compile.h gnulib/import/string.in.h gnulib/import/str-two-way.h \
> gnulib/import/stdint.in.h remote.h remote-notif.h gdb.h sparc-nat.h \
> gdbthread.h dwarf2-frame.h dwarf2-frame-tailcall.h nbsd-nat.h dcache.h \
> amd64-nat.h s390-linux-tdep.h arm-linux-tdep.h exceptions.h macroscope.h \
> @@ -1022,7 +1041,8 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \
> gdb_vecs.o jit.o progspace.o skip.o probe.o \
> common-utils.o buffer.o ptid.o gdb-dlfcn.o common-agent.o \
> format.o registry.o btrace.o record-btrace.o waitstatus.o \
> - print-utils.o rsp-low.o
> + print-utils.o rsp-low.o \
> + $(SUBDIR_GCC_COMPILE_OBS)
>
> TSOBS = inflow.o
>
> @@ -1257,7 +1277,7 @@ test-cp-name-parser$(EXEEXT): test-cp-name-parser.o $(LIBIBERTY)
> # duplicates. Files in the gdb/ directory can end up appearing in
> # COMMON_OBS (as a .o file) and CONFIG_SRCS (as a .c file).
>
> -INIT_FILES = $(COMMON_OBS) $(TSOBS) $(CONFIG_SRCS)
> +INIT_FILES = $(COMMON_OBS) $(TSOBS) $(CONFIG_SRCS) $(SUBDIR_GCC_COMPILE_SRCS)
> init.c: $(INIT_FILES)
> @echo Making init.c
> @rm -f init.c-tmp init.l-tmp
> @@ -1890,6 +1910,39 @@ cli-utils.o: $(srcdir)/cli/cli-utils.c
> $(COMPILE) $(srcdir)/cli/cli-utils.c
> $(POSTCOMPILE)
>
> +# GCC Compile support dependencies
> +#
> +# Need to explicitly specify the compile rule as make will do nothing
> +# or try to compile the object file into the sub-directory.
> +
> +compile.o: $(srcdir)/compile/compile.c
> + $(COMPILE) $(srcdir)/compile/compile.c
> + $(POSTCOMPILE)
> +
> +compile-c-types.o: $(srcdir)/compile/compile-c-types.c
> + $(COMPILE) $(srcdir)/compile/compile-c-types.c
> + $(POSTCOMPILE)
> +
> +compile-c-symbols.o: $(srcdir)/compile/compile-c-symbols.c
> + $(COMPILE) $(srcdir)/compile/compile-c-symbols.c
> + $(POSTCOMPILE)
> +
> +compile-object-load.o: $(srcdir)/compile/compile-object-load.c
> + $(COMPILE) $(srcdir)/compile/compile-object-load.c
> + $(POSTCOMPILE)
> +
> +compile-object-run.o: $(srcdir)/compile/compile-object-run.c
> + $(COMPILE) $(srcdir)/compile/compile-object-run.c
> + $(POSTCOMPILE)
> +
> +compile-loc2c.o: $(srcdir)/compile/compile-loc2c.c
> + $(COMPILE) $(srcdir)/compile/compile-loc2c.c
> + $(POSTCOMPILE)
> +
> +compile-c-support.o: $(srcdir)/compile/compile-c-support.c
> + $(COMPILE) $(srcdir)/compile/compile-c-support.c
> + $(POSTCOMPILE)
> +
>
> #
> # GDBTK sub-directory
> diff --git a/gdb/NEWS b/gdb/NEWS
> index d0c44ea..6829f5b 100644
> --- a/gdb/NEWS
> +++ b/gdb/NEWS
> @@ -3,6 +3,16 @@
>
> *** Changes since GDB 7.7
>
> +* GDB now supports the compilation and injection of source code into
> + the inferior. GDB will use a feature-capable compiler to compile
> + the source code to object code, and if successful, inject and
> + execute that code within the current context of the inferior.
> + Currently the "C" language is supported. The commands used to
> + interface with this new feature are:
> +
> + compile code [-raw|-r] [--] [source code]
> + compile file [-raw|-r] filename
> +
> * GDB supports printing and modifying of variable length automatic arrays
> as specified in ISO C99.
>
> @@ -26,6 +36,28 @@ guile-repl
> gr
> Start a Guile interactive prompt (or "repl" for "read-eval-print loop").
>
> +compile code [-r|-raw] [--] [source code]
> + Compile and inject into the inferior the executable object code
> + produced by compiling the provided source code. This resulting
> + object code will be executed within the current context of the
> + inferior, allowing access to variables, types and other elements
> + that are currently within scope. The -raw option will prevent GDB
> + automatically wrapping the source code into a callable scope (this
> + will have to be provided in the source code, and is considered
> + expert level usage). The "--" option indicates that all text to the
> + right of the "--" is to be considered as source code, and will not
> + be considered for option parsing.
> +
> +compile file [-r|-raw] filename
> + Compile and inject into the inferior the executable object code
> + produced by compiling the source code stored in the filename
> + provided. This resulting object code will be executed within the
> + current context of the inferior, allowing access to variables, types
> + and other elements that are currently within scope. The -raw option
> + will prevent GDB automatically wrapping the source code into a
> + callable scope (this will have to be provided in the source code,
> + and is considered expert level usage).
> +
> info auto-load guile-scripts [regexp]
> Print the list of automatically loaded Guile scripts.
>
> diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
> index 38972c6..95fe14f 100644
> --- a/gdb/ada-lang.c
> +++ b/gdb/ada-lang.c
> @@ -13521,6 +13521,8 @@ const struct language_defn ada_language_defn = {
> ada_get_symbol_name_cmp, /* la_get_symbol_name_cmp */
> ada_iterate_over_symbols,
> &ada_varobj_ops,
> + NULL,
> + NULL,
> LANG_MAGIC
> };
>
> diff --git a/gdb/c-lang.c b/gdb/c-lang.c
> index 765a6b0..078b170 100644
> --- a/gdb/c-lang.c
> +++ b/gdb/c-lang.c
> @@ -868,6 +868,8 @@ const struct language_defn c_language_defn =
> NULL, /* la_get_symbol_name_cmp */
> iterate_over_symbols,
> &c_varobj_ops,
> + c_get_compile_context,
> + c_compute_program,
> LANG_MAGIC
> };
>
> @@ -993,6 +995,8 @@ const struct language_defn cplus_language_defn =
> NULL, /* la_get_symbol_name_cmp */
> iterate_over_symbols,
> &cplus_varobj_ops,
> + NULL,
> + NULL,
> LANG_MAGIC
> };
>
> @@ -1036,6 +1040,8 @@ const struct language_defn asm_language_defn =
> NULL, /* la_get_symbol_name_cmp */
> iterate_over_symbols,
> &default_varobj_ops,
> + NULL,
> + NULL,
> LANG_MAGIC
> };
>
> @@ -1084,6 +1090,8 @@ const struct language_defn minimal_language_defn =
> NULL, /* la_get_symbol_name_cmp */
> iterate_over_symbols,
> &default_varobj_ops,
> + NULL,
> + NULL,
> LANG_MAGIC
> };
>
> diff --git a/gdb/c-lang.h b/gdb/c-lang.h
> index 76bd426..5a2f878 100644
> --- a/gdb/c-lang.h
> +++ b/gdb/c-lang.h
> @@ -141,5 +141,24 @@ extern int cp_is_vtbl_member (struct type *);
>
> extern int c_textual_element_type (struct type *, char);
>
> +/* Create a new instance of the C compiler and return it. The new
> + compiler is owned by the caller and must be freed using the destroy
> + method. This function never returns NULL, but rather throws an
> + exception on failure. This is suitable for use as the
> + la_get_compile_instance language method. */
> +
> +extern struct compile_instance *c_get_compile_context (void);
> +
> +/* This takes the user-supplied text and returns a newly malloc'd bit
> + of code to compile.
> +
> + This is used as the la_compute_program language method; see that
> + for a description of the arguments. */
> +
> +extern char *c_compute_program (struct compile_instance *inst,
> + const char *input,
> + struct gdbarch *gdbarch,
> + const struct block *expr_block,
> + CORE_ADDR expr_pc);
>
> #endif /* !defined (C_LANG_H) */
> diff --git a/gdb/cli/cli-script.c b/gdb/cli/cli-script.c
> index 7dc1ba4..5e473b2 100644
> --- a/gdb/cli/cli-script.c
> +++ b/gdb/cli/cli-script.c
> @@ -34,6 +34,7 @@
>
> #include "extension.h"
> #include "interps.h"
> +#include "compile/compile.h"
>
> /* Prototypes for local functions. */
>
> @@ -90,6 +91,7 @@ multi_line_command_p (enum command_control_type type)
> case while_control:
> case while_stepping_control:
> case commands_control:
> + case compile_control:
> case python_control:
> case guile_control:
> return 1;
> @@ -275,6 +277,19 @@ print_command_lines (struct ui_out *uiout, struct command_line *cmd,
> continue;
> }
>
> + if (list->control_type == compile_control)
> + {
> + ui_out_field_string (uiout, NULL, "compile expression");
> + ui_out_text (uiout, "\n");
> + print_command_lines (uiout, *list->body_list, 0);
> + if (depth)
> + ui_out_spaces (uiout, 2 * depth);
> + ui_out_field_string (uiout, NULL, "end");
> + ui_out_text (uiout, "\n");
> + list = list->next;
> + continue;
> + }
> +
> if (list->control_type == guile_control)
> {
> ui_out_field_string (uiout, NULL, "guile");
> @@ -602,6 +617,11 @@ execute_control_command (struct command_line *cmd)
> break;
> }
>
> + case compile_control:
> + eval_compile_command (cmd, NULL, cmd->control_u.compile.scope);
> + ret = simple_control;
> + break;
> +
> case python_control:
> case guile_control:
> {
> @@ -1043,6 +1063,14 @@ process_next_line (char *p, struct command_line **command, int parse_commands,
> here. */
> *command = build_command_line (python_control, "");
> }
> + else if (p_end - p == 6 && !strncmp (p, "compile", 7))
> + {
> + /* Note that we ignore the inline "compile command" form
> + here. */
> + *command = build_command_line (compile_control, "");
> + (*command)->control_u.compile.scope = COMPILE_I_INVALID_SCOPE;
> + }
> +
> else if (p_end - p == 5 && !strncmp (p, "guile", 5))
> {
> /* Note that we ignore the inline "guile command" form here. */
> @@ -1136,7 +1164,8 @@ recurse_read_control_structure (char * (*read_next_line_func) (void),
> next = NULL;
> val = process_next_line (read_next_line_func (), &next,
> current_cmd->control_type != python_control
> - && current_cmd->control_type != guile_control,
> + && current_cmd->control_type != guile_control
> + && current_cmd->control_type != compile_control,
> validator, closure);
>
> /* Just skip blanks and comments. */
> diff --git a/gdb/compile/compile-c-support.c b/gdb/compile/compile-c-support.c
> new file mode 100644
> index 0000000..f0fa999
> --- /dev/null
> +++ b/gdb/compile/compile-c-support.c
> @@ -0,0 +1,396 @@
> +/* C language support for compilation.
> +
> + Copyright (C) 2014 Free Software Foundation, Inc.
> +
> + This file is part of GDB.
> +
> + This program is free software; you can redistribute it and/or modify
> + it under the terms of the GNU General Public License as published by
> + the Free Software Foundation; either version 3 of the License, or
> + (at your option) any later version.
> +
> + This program is distributed in the hope that it will be useful,
> + but WITHOUT ANY WARRANTY; without even the implied warranty of
> + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + GNU General Public License for more details.
> +
> + You should have received a copy of the GNU General Public License
> + along with this program. If not, see <http://www.gnu.org/licenses/>. */
> +
> +#include "defs.h"
> +#include "compile-internal.h"
> +#include "compile.h"
> +#include "gdb-dlfcn.h"
> +#include "c-lang.h"
> +#include "macrotab.h"
> +#include "macroscope.h"
> +#include "regcache.h"
> +
> +/* See compile-internal.h. */
> +
> +const char *
> +c_get_mode_for_size (int size)
> +{
> + const char *mode = NULL;
> +
> + switch (size)
> + {
> + case 1:
> + mode = "QI";
> + break;
> + case 2:
> + mode = "HI";
> + break;
> + case 4:
> + mode = "SI";
> + break;
> + case 8:
> + mode = "DI";
> + break;
> + }
> +
> + return mode;
> +}
> +
> +/* See compile-internal.h. */
> +
> +char *
> +c_get_range_decl_name (const struct dynamic_prop *prop)
> +{
> + return xstrprintf ("__gdb_prop_%s", host_address_to_string (prop));
> +}
> +
> +
> +
> +#define STR(x) #x
> +#define STRINGIFY(x) STR(x)
> +
> +/* Helper function for c_get_compile_context. Open the GCC front-end
> + shared library and return the symbol specified by the current
> + GCC_C_FE_CONTEXT. */
> +
> +static gcc_c_fe_context_function *
> +load_libcc (void)
> +{
> + void *handle;
> + gcc_c_fe_context_function *func;
> +
> + /* gdb_dlopen will call error () on an error, so no need to check
> + value. */
> + handle = gdb_dlopen (STRINGIFY (GCC_C_FE_LIBCC));
> + func = (gcc_c_fe_context_function *) gdb_dlsym (handle,
> + STRINGIFY (GCC_C_FE_CONTEXT));
> +
> + if (func == NULL)
> + error (_("could not find symbol %s in library %s"),
> + STRINGIFY (GCC_C_FE_CONTEXT),
> + STRINGIFY (GCC_C_FE_LIBCC));
> + return func;
> +}
> +
> +/* Return the compile instance associated with the current context.
> + This function calls the symbol returned from the load_libcc
> + function. This will provide the gcc_c_context. */
> +
> +struct compile_instance *
> +c_get_compile_context (void)
> +{
> + static gcc_c_fe_context_function *func;
> +
> + struct gcc_c_context *context;
> +
> + if (func == NULL)
> + {
> + func = load_libcc ();
> + gdb_assert (func != NULL);
> + }
> +
> + context = (*func) (GCC_FE_VERSION_0, GCC_C_FE_VERSION_0);
> + if (context == NULL)
> + error (_("The loaded version of GCC does not support the required version "
> + "of the API."));
> +
> + return new_compile_instance (context);
> +}
> +
> +
> +
> +/* Write one macro definition. */
> +
> +static void
> +print_one_macro (const char *name, const struct macro_definition *macro,
> + struct macro_source_file *source, int line,
> + void *user_data)
> +{
> + struct ui_file *file = user_data;
> +
> + /* Don't print command-line defines. They will be supplied another
> + way. */
> + if (line == 0)
> + return;
> +
> + fprintf_filtered (file, "#define %s", name);
> +
> + if (macro->kind == macro_function_like)
> + {
> + int i;
> +
> + fputs_filtered ("(", file);
> + for (i = 0; i < macro->argc; i++)
> + {
> + fputs_filtered (macro->argv[i], file);
> + if (i + 1 < macro->argc)
> + fputs_filtered (", ", file);
> + }
> + fputs_filtered (")", file);
> + }
> +
> + fprintf_filtered (file, " %s\n", macro->replacement);
> +}
> +
> +/* Write macro definitions at PC to FILE. */
> +
> +static void
> +write_macro_definitions (const struct block *block, CORE_ADDR pc,
> + struct ui_file *file)
> +{
> + struct macro_scope *scope;
> +
> + if (block != NULL)
> + scope = sal_macro_scope (find_pc_line (pc, 0));
> + else
> + scope = default_macro_scope ();
> + if (scope == NULL)
> + scope = user_macro_scope ();
> +
> + if (scope != NULL && scope->file != NULL && scope->file->table != NULL)
> + macro_for_each_in_scope (scope->file, scope->line, print_one_macro, file);
> +}
> +
> +/* Helper function to construct a header scope for a block of code.
> + Takes a scope argument which selects the correct header to
> + insert into BUF. */
> +
> +static void
> +add_code_header (enum compile_i_scope_types type, struct ui_file *buf)
> +{
> + switch (type)
> + {
> + case COMPILE_I_SIMPLE_SCOPE:
> + fputs_unfiltered ("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:
> + gdb_assert_not_reached (_("Unknown compiler scope reached."));
> + }
> +}
> +
> +/* Helper function to construct a footer scope for a block of code.
> + Takes a scope argument which selects the correct footer to
> + insert into BUF. */
> +
> +static void
> +add_code_footer (enum compile_i_scope_types type, struct ui_file *buf)
> +{
> + switch (type)
> + {
> + case COMPILE_I_SIMPLE_SCOPE:
> + fputs_unfiltered ("}\n", buf);
> + break;
> + case COMPILE_I_RAW_SCOPE:
> + break;
> + default:
> + gdb_assert_not_reached (_("Unknown compiler scope reached."));
> + }
> +}
> +
> +/* Generate a structure holding all the registers used by the function
> + we're generating. */
> +
> +static void
> +generate_register_struct (struct ui_file *stream, struct gdbarch *gdbarch,
> + const unsigned char *registers_used)
> +{
> + int i;
> + int seen = 0;
> +
> + fputs_unfiltered ("struct " COMPILE_I_SIMPLE_REGISTER_STRUCT_TAG " {\n",
> + stream);
> +
> + if (registers_used != NULL)
> + for (i = 0; i < gdbarch_num_regs (gdbarch); ++i)
> + {
> + if (registers_used[i])
> + {
> + struct type *regtype = check_typedef (register_type (gdbarch, i));
> + char *regname = compile_register_name_mangled (gdbarch, i);
> + struct cleanup *cleanups = make_cleanup (xfree, regname);
> +
> + seen = 1;
> +
> + /* You might think we could use type_print here. However,
> + target descriptions often use types with names like
> + "int64_t", which may not be defined in the inferior
> + (and in any case would not be looked up due to the
> + #pragma business). So, we take a much simpler
> + approach: for pointer- or integer-typed registers, emit
> + the field in the most direct way; and for other
> + register types (typically flags or vectors), emit a
> + maximally-aligned array of the correct size. */
> +
> + fputs_unfiltered (" ", stream);
> + switch (TYPE_CODE (regtype))
> + {
> + case TYPE_CODE_PTR:
> + fprintf_filtered (stream, "void *%s", regname);
> + break;
> +
> + case TYPE_CODE_INT:
> + {
> + const char *mode
> + = c_get_mode_for_size (TYPE_LENGTH (regtype));
> +
> + if (mode != NULL)
> + {
> + if (TYPE_UNSIGNED (regtype))
> + fputs_unfiltered ("unsigned ", stream);
> + fprintf_unfiltered (stream,
> + "int %s"
> + " __attribute__ ((__mode__(__%s__)))",
> + regname,
> + mode);
> + break;
> + }
> + }
> +
> + /* Fall through. */
> +
> + default:
> + fprintf_unfiltered (stream,
> + " unsigned char %s[%d]"
> + " __attribute__((__aligned__("
> + "__BIGGEST_ALIGNMENT__)))",
> + regname,
> + TYPE_LENGTH (regtype));
> + }
> + fputs_unfiltered (";\n", stream);
> +
> + do_cleanups (cleanups);
> + }
> + }
> +
> + if (!seen)
> + fputs_unfiltered (" char " COMPILE_I_SIMPLE_REGISTER_DUMMY ";\n",
> + stream);
> +
> + fputs_unfiltered ("};\n\n", stream);
> +}
> +
> +/* Take the source code provided by the user with the 'compile'
> + command, and compute the additional wrapping, macro, variable and
> + register operations needed. INPUT is the source code derived from
> + the 'compile' command, GDBARCH is the architecture to use when
> + computing above, EXPR_BLOCK denotes the block relevant contextually
> + to the inferior when the expression was created, and EXPR_PC
> + indicates the value of $PC. */
> +
> +char *
> +c_compute_program (struct compile_instance *inst,
> + const char *input,
> + struct gdbarch *gdbarch,
> + const struct block *expr_block,
> + CORE_ADDR expr_pc)
> +{
> + struct ui_file *buf, *var_stream = NULL;
> + char *code;
> + struct cleanup *cleanup;
> + struct compile_c_instance *context = (struct compile_c_instance *) inst;
> +
> + buf = mem_fileopen ();
> + cleanup = make_cleanup_ui_file_delete (buf);
> +
> + write_macro_definitions (expr_block, expr_pc, buf);
> +
> + /* Do not generate local variable information for "raw"
> + compilations. In this case we aren't emitting our own function
> + and the user's code may only refer to globals. */
> + if (inst->scope != COMPILE_I_RAW_SCOPE)
> + {
> + unsigned char *registers_used;
> + int i;
> +
> + /* Generate the code to compute variable locations, but do it
> + before generating the function header, so we can define the
> + register struct before the function body. This requires a
> + temporary stream. */
> + var_stream = mem_fileopen ();
> + make_cleanup_ui_file_delete (var_stream);
> + registers_used = generate_c_for_variable_locations (context,
> + var_stream, gdbarch,
> + expr_block, expr_pc);
> + make_cleanup (xfree, registers_used);
> +
> + generate_register_struct (buf, gdbarch, registers_used);
> +
> + fputs_unfiltered ("typedef unsigned int"
> + " __attribute__ ((__mode__(__pointer__)))"
> + " __gdb_uintptr;\n",
> + buf);
> + fputs_unfiltered ("typedef int"
> + " __attribute__ ((__mode__(__pointer__)))"
> + " __gdb_intptr;\n",
> + buf);
> +
> + for (i = 0; i < 4; ++i)
> + {
> + const char *mode = c_get_mode_for_size (1 << i);
> +
> + gdb_assert (mode != NULL);
> + fprintf_unfiltered (buf,
> + "typedef int"
> + " __attribute__ ((__mode__(__%s__)))"
> + " __gdb_int_%s;\n",
> + mode, mode);
> + }
> + }
> +
> + add_code_header (inst->scope, buf);
> +
> + if (inst->scope == COMPILE_I_SIMPLE_SCOPE)
> + {
> + ui_file_put (var_stream, ui_file_write_for_put, buf);
> + fputs_unfiltered ("#pragma GCC user_expression\n", buf);
> + }
> +
> + /* The user expression has to be in its own scope, so that "extern"
> + works properly. Otherwise gcc thinks that the "extern"
> + declaration is in the same scope as the declaration provided by
> + gdb. */
> + if (inst->scope != COMPILE_I_RAW_SCOPE)
> + fputs_unfiltered ("{\n", buf);
> +
> + fputs_unfiltered ("#line 1 \"gdb command line\"\n", buf);
> + fputs_unfiltered (input, buf);
> + fputs_unfiltered ("\n", buf);
> +
> + /* For larger user expressions the automatic semicolons may be
> + confusing. */
> + if (strchr (input, '\n') == NULL)
> + fputs_unfiltered (";\n", buf);
> +
> + if (inst->scope != COMPILE_I_RAW_SCOPE)
> + fputs_unfiltered ("}\n", buf);
> +
> + add_code_footer (inst->scope, buf);
> + code = ui_file_xstrdup (buf, NULL);
> + do_cleanups (cleanup);
> + return code;
> +}
> diff --git a/gdb/compile/compile-c-symbols.c b/gdb/compile/compile-c-symbols.c
> new file mode 100644
> index 0000000..a9e381f
> --- /dev/null
> +++ b/gdb/compile/compile-c-symbols.c
> @@ -0,0 +1,759 @@
> +/* Convert symbols from GDB to GCC
> +
> + Copyright (C) 2014 Free Software Foundation, Inc.
> +
> + This file is part of GDB.
> +
> + This program is free software; you can redistribute it and/or modify
> + it under the terms of the GNU General Public License as published by
> + the Free Software Foundation; either version 3 of the License, or
> + (at your option) any later version.
> +
> + This program is distributed in the hope that it will be useful,
> + but WITHOUT ANY WARRANTY; without even the implied warranty of
> + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + GNU General Public License for more details.
> +
> + You should have received a copy of the GNU General Public License
> + along with this program. If not, see <http://www.gnu.org/licenses/>. */
> +
> +
> +#include "defs.h"
> +#include "compile-internal.h"
> +#include "gdb_assert.h"
> +#include "symtab.h"
> +#include "parser-defs.h"
> +#include "block.h"
> +#include "objfiles.h"
> +#include "compile.h"
> +#include "value.h"
> +#include "exceptions.h"
> +#include "gdbtypes.h"
> +#include "dwarf2loc.h"
> +
> +
> +
> +/* Object of this type are stored in the compiler's symbol_err_map. */
> +
> +struct symbol_error
> +{
> + /* The symbol. */
> +
> + const struct symbol *sym;
> +
> + /* The error message to emit. This is malloc'd and owned by the
> + hash table. */
> +
> + char *message;
> +};
> +
> +/* Hash function for struct symbol_error. */
> +
> +static hashval_t
> +hash_symbol_error (const void *a)
> +{
> + const struct symbol_error *se = a;
> +
> + return htab_hash_pointer (se->sym);
> +}
> +
> +/* Equality function for struct symbol_error. */
> +
> +static int
> +eq_symbol_error (const void *a, const void *b)
> +{
> + const struct symbol_error *sea = a;
> + const struct symbol_error *seb = b;
> +
> + return sea->sym == seb->sym;
> +}
> +
> +/* Deletion function for struct symbol_error. */
> +
> +static void
> +del_symbol_error (void *a)
> +{
> + struct symbol_error *se = a;
> +
> + xfree (se->message);
> + xfree (se);
> +}
> +
> +/* Associate SYMBOL with some error text. */
> +
> +static void
> +insert_symbol_error (htab_t hash, const struct symbol *sym, const char *text)
> +{
> + struct symbol_error e;
> + void **slot;
> +
> + e.sym = sym;
> + slot = htab_find_slot (hash, &e, INSERT);
> + if (*slot == NULL)
> + {
> + struct symbol_error *e = XNEW (struct symbol_error);
> +
> + e->sym = sym;
> + e->message = xstrdup (text);
> + *slot = e;
> + }
> +}
> +
> +/* Emit the error message corresponding to SYM, if one exists, and
> + arrange for it not to be emitted again. */
> +
> +static void
> +error_symbol_once (struct compile_c_instance *context,
> + const struct symbol *sym)
> +{
> + struct symbol_error search;
> + struct symbol_error *err;
> + char *message;
> +
> + if (context->symbol_err_map == NULL)
> + return;
> +
> + search.sym = sym;
> + err = htab_find (context->symbol_err_map, &search);
> + if (err == NULL || err->message == NULL)
> + return;
> +
> + message = err->message;
> + err->message = NULL;
> + make_cleanup (xfree, message);
> + error (_("%s"), message);
> +}
> +
> +
> +
> +/* Compute the name of the pointer representing a local symbol's
> + address. */
> +
> +static char *
> +symbol_substitution_name (struct symbol *sym)
> +{
> + return concat ("__", SYMBOL_NATURAL_NAME (sym), "_ptr", (char *) NULL);
> +}
> +
> +/* Convert a given symbol, SYM, to the compiler's representation.
> + CONTEXT is the compiler instance. IS_GLOBAL is true if the
> + symbol came from the global scope. IS_LOCAL is true if the symbol
> + came from a local scope. (Note that the two are not strictly
> + inverses because the symbol might have come from the static
> + scope.) */
> +
> +static void
> +convert_one_symbol (struct compile_c_instance *context,
> + struct symbol *sym,
> + int is_global,
> + int is_local)
> +{
> + gcc_type sym_type;
> + const char *filename = SYMBOL_SYMTAB (sym)->filename;
> + unsigned short line = SYMBOL_LINE (sym);
> +
> + error_symbol_once (context, sym);
> +
> + if (SYMBOL_CLASS (sym) == LOC_LABEL)
> + sym_type = 0;
> + else
> + sym_type = convert_type (context, SYMBOL_TYPE (sym));
> +
> + if (SYMBOL_DOMAIN (sym) == STRUCT_DOMAIN)
> + {
> + /* Binding a tag, so we don't need to build a decl. */
> + C_CTX (context)->c_ops->tagbind (C_CTX (context),
> + SYMBOL_NATURAL_NAME (sym),
> + sym_type, filename, line);
> + }
> + else
> + {
> + gcc_decl decl;
> + enum gcc_c_symbol_kind kind;
> + CORE_ADDR addr = 0;
> + char *symbol_name = NULL;
> +
> + switch (SYMBOL_CLASS (sym))
> + {
> + case LOC_TYPEDEF:
> + kind = GCC_C_SYMBOL_TYPEDEF;
> + break;
> +
> + case LOC_LABEL:
> + kind = GCC_C_SYMBOL_LABEL;
> + addr = SYMBOL_VALUE_ADDRESS (sym);
> + break;
> +
> + case LOC_BLOCK:
> + kind = GCC_C_SYMBOL_FUNCTION;
> + addr = BLOCK_START (SYMBOL_BLOCK_VALUE (sym));
> + break;
> +
> + case LOC_CONST:
> + if (TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_ENUM)
> + {
> + /* Already handled by convert_enum. */
> + return;
> + }
> + C_CTX (context)->c_ops->build_constant (C_CTX (context), sym_type,
> + SYMBOL_NATURAL_NAME (sym),
> + SYMBOL_VALUE (sym),
> + filename, line);
> + return;
> +
> + case LOC_CONST_BYTES:
> + error (_("Unsupported LOC_CONST_BYTES for symbol \"%s\"."),
> + SYMBOL_PRINT_NAME (sym));
> +
> + case LOC_UNDEF:
> + internal_error (__FILE__, __LINE__, _("LOC_UNDEF found for \"%s\"."),
> + SYMBOL_PRINT_NAME (sym));
> +
> + case LOC_COMMON_BLOCK:
> + error (_("Fortran common block is unsupported for compilation "
> + "evaluaton of symbol \"%s\"."),
> + SYMBOL_PRINT_NAME (sym));
> +
> + case LOC_OPTIMIZED_OUT:
> + error (_("Symbol \"%s\" cannot be used for compilation evaluation "
> + "as it is optimized out."),
> + SYMBOL_PRINT_NAME (sym));
> +
> + case LOC_COMPUTED:
> + if (is_local)
> + goto substitution;
> + /* Probably TLS here. */
> + warning (_("Symbol \"%s\" is thread-local and currently can only "
> + "be referenced from the current thread in "
> + "compiled code."),
> + SYMBOL_PRINT_NAME (sym));
> + /* FALLTHROUGH */
> + case LOC_UNRESOLVED:
> + /* 'symbol_name' cannot be used here as that one is used only for
> + local variables from compile_dwarf_expr_to_c.
> + Global variables can be accessed by GCC only by their address, not
> + by their name. */
> + {
> + struct value *val;
> + struct frame_info *frame = NULL;
> +
> + if (symbol_read_needs_frame (sym))
> + {
> + frame = get_selected_frame (NULL);
> + if (frame == NULL)
> + error (_("Symbol \"%s\" cannot be used because "
> + "there is no selected frame"),
> + SYMBOL_PRINT_NAME (sym));
> + }
> +
> + val = read_var_value (sym, frame);
> + if (VALUE_LVAL (val) != lval_memory)
> + error (_("Symbol \"%s\" cannot be used for compilation "
> + "evaluation as its address has not been found."),
> + SYMBOL_PRINT_NAME (sym));
> +
> + kind = GCC_C_SYMBOL_VARIABLE;
> + addr = value_address (val);
> + }
> + break;
> +
> +
> + case LOC_REGISTER:
> + case LOC_ARG:
> + case LOC_REF_ARG:
> + case LOC_REGPARM_ADDR:
> + case LOC_LOCAL:
> + substitution:
> + kind = GCC_C_SYMBOL_VARIABLE;
> + symbol_name = symbol_substitution_name (sym);
> + break;
> +
> + case LOC_STATIC:
> + kind = GCC_C_SYMBOL_VARIABLE;
> + addr = SYMBOL_VALUE_ADDRESS (sym);
> + break;
> +
> + case LOC_FINAL_VALUE:
> + default:
> + gdb_assert_not_reached ("Unreachable case in convert_one_symbol.");
> +
> + }
> +
> + /* Don't emit local variable decls for a raw expression. */
> + if (context->base.scope != COMPILE_I_RAW_SCOPE
> + || symbol_name == NULL)
> + {
> + decl = C_CTX (context)->c_ops->build_decl (C_CTX (context),
> + SYMBOL_NATURAL_NAME (sym),
> + kind,
> + sym_type,
> + symbol_name, addr,
> + filename, line);
> +
> + C_CTX (context)->c_ops->bind (C_CTX (context), decl, is_global);
> + }
> +
> + xfree (symbol_name);
> + }
> +}
> +
> +/* Convert a full symbol to its gcc form. CONTEXT is the compiler to
> + use, IDENTIFIER is the name of the symbol, SYM is the symbol
> + itself, and DOMAIN is the domain which was searched. */
> +
> +static void
> +convert_symbol_sym (struct compile_c_instance *context, const char *identifier,
> + struct symbol *sym, domain_enum domain)
> +{
> + const struct block *static_block, *found_block;
> + int is_local_symbol;
> +
> + found_block = block_found;
> +
> + /* If we found a symbol and it is not in the static or global
> + scope, then we should first convert any static or global scope
> + symbol of the same name. This lets this unusual case work:
> +
> + int x; // Global.
> + int func(void)
> + {
> + int x;
> + // At this spot, evaluate "extern int x; x"
> + }
> + */
> +
> + static_block = block_static_block (found_block);
> + /* STATIC_BLOCK is NULL if FOUND_BLOCK is the global block. */
> + is_local_symbol = (found_block != static_block && static_block != NULL);
> + if (is_local_symbol)
> + {
> + struct symbol *global_sym;
> +
> + global_sym = lookup_symbol (identifier, NULL, domain, NULL);
> + /* If the outer symbol is in the static block, we ignore it, as
> + it cannot be referenced. */
> + if (global_sym != NULL
> + && block_found != block_static_block (block_found))
> + {
> + if (compile_debug)
> + fprintf_unfiltered (gdb_stdout,
> + "gcc_convert_symbol \"%s\": global symbol\n",
> + identifier);
> + convert_one_symbol (context, global_sym, 1, 0);
> + }
> + }
> +
> + if (compile_debug)
> + fprintf_unfiltered (gdb_stdout,
> + "gcc_convert_symbol \"%s\": local symbol\n",
> + identifier);
> + convert_one_symbol (context, sym, 0, is_local_symbol);
> +}
> +
> +/* Convert a minimal symbol to its gcc form. CONTEXT is the compiler
> + to use and BMSYM is the minimal symbol to convert. */
> +
> +static void
> +convert_symbol_bmsym (struct compile_c_instance *context,
> + struct bound_minimal_symbol bmsym)
> +{
> + struct minimal_symbol *msym = bmsym.minsym;
> + struct objfile *objfile = bmsym.objfile;
> + struct type *type;
> + enum gcc_c_symbol_kind kind;
> + gcc_type sym_type;
> + gcc_decl decl;
> + CORE_ADDR addr;
> +
> + /* Conversion copied from write_exp_msymbol. */
> + switch (MSYMBOL_TYPE (msym))
> + {
> + case mst_text:
> + case mst_file_text:
> + case mst_solib_trampoline:
> + type = objfile_type (objfile)->nodebug_text_symbol;
> + kind = GCC_C_SYMBOL_FUNCTION;
> + break;
> +
> + case mst_text_gnu_ifunc:
> + type = objfile_type (objfile)->nodebug_text_gnu_ifunc_symbol;
> + kind = GCC_C_SYMBOL_FUNCTION;
> + break;
> +
> + case mst_data:
> + case mst_file_data:
> + case mst_bss:
> + case mst_file_bss:
> + type = objfile_type (objfile)->nodebug_data_symbol;
> + kind = GCC_C_SYMBOL_VARIABLE;
> + break;
> +
> + case mst_slot_got_plt:
> + type = objfile_type (objfile)->nodebug_got_plt_symbol;
> + kind = GCC_C_SYMBOL_FUNCTION;
> + break;
> +
> + default:
> + type = objfile_type (objfile)->nodebug_unknown_symbol;
> + kind = GCC_C_SYMBOL_VARIABLE;
> + break;
> + }
> +
> + sym_type = convert_type (context, type);
> + addr = MSYMBOL_VALUE_ADDRESS (objfile, msym);
> + decl = C_CTX (context)->c_ops->build_decl (C_CTX (context),
> + MSYMBOL_NATURAL_NAME (msym),
> + kind, sym_type, NULL, addr,
> + NULL, 0);
> + C_CTX (context)->c_ops->bind (C_CTX (context), decl, 1 /* is_global */);
> +}
> +
> +/* See compile-internal.h. */
> +
> +void
> +gcc_convert_symbol (void *datum,
> + struct gcc_c_context *gcc_context,
> + enum gcc_c_oracle_request request,
> + const char *identifier)
> +{
> + struct compile_c_instance *context = datum;
> + domain_enum domain;
> + volatile struct gdb_exception e;
> + int found = 0;
> +
> + switch (request)
> + {
> + case GCC_C_ORACLE_SYMBOL:
> + domain = VAR_DOMAIN;
> + break;
> + case GCC_C_ORACLE_TAG:
> + domain = STRUCT_DOMAIN;
> + break;
> + case GCC_C_ORACLE_LABEL:
> + domain = LABEL_DOMAIN;
> + break;
> + default:
> + gdb_assert_not_reached ("Unrecognized oracle request.");
> + }
> +
> + /* We can't allow exceptions to escape out of this callback. Safest
> + is to simply emit a gcc error. */
> + TRY_CATCH (e, RETURN_MASK_ERROR)
> + {
> + struct symbol *sym;
> +
> + sym = lookup_symbol (identifier, context->base.block, domain, NULL);
> + if (sym != NULL)
> + {
> + convert_symbol_sym (context, identifier, sym, domain);
> + found = 1;
> + }
> + else if (domain == VAR_DOMAIN)
> + {
> + struct bound_minimal_symbol bmsym;
> +
> + bmsym = lookup_minimal_symbol (identifier, NULL, NULL);
> + if (bmsym.minsym != NULL)
> + {
> + convert_symbol_bmsym (context, bmsym);
> + found = 1;
> + }
> + }
> + }
> +
> + if (e.reason < 0)
> + C_CTX (context)->c_ops->error (C_CTX (context), e.message);
> +
> + if (compile_debug && !found)
> + fprintf_unfiltered (gdb_stdout,
> + "gcc_convert_symbol \"%s\": lookup_symbol failed\n",
> + identifier);
> + return;
> +}
> +
> +/* See compile-internal.h. */
> +
> +gcc_address
> +gcc_symbol_address (void *datum, struct gcc_c_context *gcc_context,
> + const char *identifier)
> +{
> + struct compile_c_instance *context = datum;
> + volatile struct gdb_exception e;
> + gcc_address result = 0;
> + int found = 0;
> +
> + /* We can't allow exceptions to escape out of this callback. Safest
> + is to simply emit a gcc error. */
> + TRY_CATCH (e, RETURN_MASK_ERROR)
> + {
> + struct symbol *sym;
> +
> + /* We only need global functions here. */
> + sym = lookup_symbol (identifier, NULL, VAR_DOMAIN, NULL);
> + if (sym != NULL && SYMBOL_CLASS (sym) == LOC_BLOCK)
> + {
> + if (compile_debug)
> + fprintf_unfiltered (gdb_stdout,
> + "gcc_symbol_address \"%s\": full symbol\n",
> + identifier);
> + result = BLOCK_START (SYMBOL_BLOCK_VALUE (sym));
> + found = 1;
> + }
> + else
> + {
> + struct bound_minimal_symbol msym;
> +
> + msym = lookup_bound_minimal_symbol (identifier);
> + if (msym.minsym != NULL)
> + {
> + if (compile_debug)
> + fprintf_unfiltered (gdb_stdout,
> + "gcc_symbol_address \"%s\": minimal "
> + "symbol\n",
> + identifier);
> + result = BMSYMBOL_VALUE_ADDRESS (msym);
> + found = 1;
> + }
> + }
> + }
> +
> + if (e.reason < 0)
> + C_CTX (context)->c_ops->error (C_CTX (context), e.message);
> +
> + if (compile_debug && !found)
> + fprintf_unfiltered (gdb_stdout,
> + "gcc_symbol_address \"%s\": failed\n",
> + identifier);
> + return result;
> +}
> +
> +
> +
> +/* A hash function for symbol names. */
> +
> +static hashval_t
> +hash_symname (const void *a)
> +{
> + const struct symbol *sym = a;
> +
> + return htab_hash_string (SYMBOL_NATURAL_NAME (sym));
> +}
> +
> +/* A comparison function for hash tables that just looks at symbol
> + names. */
> +
> +static int
> +eq_symname (const void *a, const void *b)
> +{
> + const struct symbol *syma = a;
> + const struct symbol *symb = b;
> +
> + return strcmp (SYMBOL_NATURAL_NAME (syma), SYMBOL_NATURAL_NAME (symb)) == 0;
> +}
> +
> +/* If a symbol with the same name as SYM is already in HASHTAB, return
> + 1. Otherwise, add SYM to HASHTAB and return 0. */
> +
> +static int
> +symbol_seen (htab_t hashtab, struct symbol *sym)
> +{
> + void **slot;
> +
> + slot = htab_find_slot (hashtab, sym, INSERT);
> + if (*slot != NULL)
> + return 1;
> +
> + *slot = sym;
> + return 0;
> +}
> +
> +/* Generate C code to compute the length of a VLA. */
> +
> +static void
> +generate_vla_size (struct compile_c_instance *compiler,
> + struct ui_file *stream,
> + struct gdbarch *gdbarch,
> + unsigned char *registers_used,
> + CORE_ADDR pc,
> + struct type *type,
> + struct symbol *sym)
> +{
> + type = check_typedef (type);
> +
> + if (TYPE_CODE (type) == TYPE_CODE_REF)
> + type = check_typedef (TYPE_TARGET_TYPE (type));
> +
> + switch (TYPE_CODE (type))
> + {
> + case TYPE_CODE_RANGE:
> + {
> + if (TYPE_HIGH_BOUND_KIND (type) == PROP_LOCEXPR
> + || TYPE_HIGH_BOUND_KIND (type) == PROP_LOCLIST)
> + {
> + const struct dynamic_prop *prop = &TYPE_RANGE_DATA (type)->high;
> + char *name = c_get_range_decl_name (prop);
> + struct cleanup *cleanup = make_cleanup (xfree, name);
> +
> + dwarf2_compile_property_to_c (stream, name,
> + gdbarch, registers_used,
> + prop, pc, sym);
> + do_cleanups (cleanup);
> + }
> + }
> + break;
> +
> + case TYPE_CODE_ARRAY:
> + generate_vla_size (compiler, stream, gdbarch, registers_used, pc,
> + TYPE_INDEX_TYPE (type), sym);
> + generate_vla_size (compiler, stream, gdbarch, registers_used, pc,
> + TYPE_TARGET_TYPE (type), sym);
> + break;
> +
> + case TYPE_CODE_UNION:
> + case TYPE_CODE_STRUCT:
> + {
> + int i;
> +
> + for (i = 0; i < TYPE_NFIELDS (type); ++i)
> + if (!field_is_static (&TYPE_FIELD (type, i)))
> + generate_vla_size (compiler, stream, gdbarch, registers_used, pc,
> + TYPE_FIELD_TYPE (type, i), sym);
> + }
> + break;
> + }
> +}
> +
> +/* Generate C code to compute the address of SYM. */
> +
> +static void
> +generate_c_for_for_one_variable (struct compile_c_instance *compiler,
> + struct ui_file *stream,
> + struct gdbarch *gdbarch,
> + unsigned char *registers_used,
> + CORE_ADDR pc,
> + struct symbol *sym)
> +{
> + volatile struct gdb_exception e;
> +
> + TRY_CATCH (e, RETURN_MASK_ERROR)
> + {
> + if (is_dynamic_type (SYMBOL_TYPE (sym)))
> + {
> + struct ui_file *size_file = mem_fileopen ();
> + struct cleanup *cleanup = make_cleanup_ui_file_delete (size_file);
> +
> + generate_vla_size (compiler, size_file, gdbarch, registers_used, pc,
> + SYMBOL_TYPE (sym), sym);
> + ui_file_put (size_file, ui_file_write_for_put, stream);
> +
> + do_cleanups (cleanup);
> + }
> +
> + if (SYMBOL_COMPUTED_OPS (sym) != NULL)
> + {
> + char *generated_name = symbol_substitution_name (sym);
> + struct cleanup *cleanup = make_cleanup (xfree, generated_name);
> + /* We need to emit to a temporary buffer in case an error
> + occurs in the middle. */
> + struct ui_file *local_file = mem_fileopen ();
> +
> + make_cleanup_ui_file_delete (local_file);
> + SYMBOL_COMPUTED_OPS (sym)->generate_c_location (sym, local_file,
> + gdbarch,
> + registers_used,
> + pc, generated_name);
> + ui_file_put (local_file, ui_file_write_for_put, stream);
> +
> + do_cleanups (cleanup);
> + }
> + else
> + {
> + switch (SYMBOL_CLASS (sym))
> + {
> + case LOC_REGISTER:
> + case LOC_ARG:
> + case LOC_REF_ARG:
> + case LOC_REGPARM_ADDR:
> + case LOC_LOCAL:
> + error (_("Local symbol unhandled when generating C code."));
> +
> + case LOC_COMPUTED:
> + gdb_assert_not_reached (_("LOC_COMPUTED variable "
> + "missing a method."));
> +
> + default:
> + /* Nothing to do for all other cases, as they don't represent
> + local variables. */
> + break;
> + }
> + }
> + }
> +
> + if (e.reason >= 0)
> + return;
> +
> + if (compiler->symbol_err_map == NULL)
> + compiler->symbol_err_map = htab_create_alloc (10,
> + hash_symbol_error,
> + eq_symbol_error,
> + del_symbol_error,
> + xcalloc,
> + xfree);
> + insert_symbol_error (compiler->symbol_err_map, sym, e.message);
> +}
> +
> +/* See compile-internal.h. */
> +
> +unsigned char *
> +generate_c_for_variable_locations (struct compile_c_instance *compiler,
> + struct ui_file *stream,
> + struct gdbarch *gdbarch,
> + const struct block *block,
> + CORE_ADDR pc)
> +{
> + struct cleanup *cleanup, *outer;
> + htab_t symhash;
> + const struct block *static_block = block_static_block (block);
> + unsigned char *registers_used;
> +
> + /* If we're already in the static or global block, there is nothing
> + to write. */
> + if (static_block == NULL || block == static_block)
> + return NULL;
> +
> + registers_used = XCNEWVEC (unsigned char, gdbarch_num_regs (gdbarch));
> + outer = make_cleanup (xfree, registers_used);
> +
> + /* Ensure that a given name is only entered once. This reflects the
> + reality of shadowing. */
> + symhash = htab_create_alloc (1, hash_symname, eq_symname, NULL,
> + xcalloc, xfree);
> + cleanup = make_cleanup_htab_delete (symhash);
> +
> + while (1)
> + {
> + struct symbol *sym;
> + struct block_iterator iter;
> +
> + /* Iterate over symbols in this block, generating code to
> + compute the location of each local variable. */
> + for (sym = block_iterator_first (block, &iter);
> + sym != NULL;
> + sym = block_iterator_next (&iter))
> + {
> + if (!symbol_seen (symhash, sym))
> + generate_c_for_for_one_variable (compiler, stream, gdbarch,
> + registers_used, pc, sym);
> + }
> +
> + /* If we just finished the outermost block of a function, we're
> + done. */
> + if (BLOCK_FUNCTION (block) != NULL)
> + break;
> + block = BLOCK_SUPERBLOCK (block);
> + }
> +
> + do_cleanups (cleanup);
> + discard_cleanups (outer);
> + return registers_used;
> +}
> diff --git a/gdb/compile/compile-c-types.c b/gdb/compile/compile-c-types.c
> new file mode 100644
> index 0000000..78ae9a8
> --- /dev/null
> +++ b/gdb/compile/compile-c-types.c
> @@ -0,0 +1,438 @@
> +/* Convert types from GDB to GCC
> +
> + Copyright (C) 2014 Free Software Foundation, Inc.
> +
> + This file is part of GDB.
> +
> + This program is free software; you can redistribute it and/or modify
> + it under the terms of the GNU General Public License as published by
> + the Free Software Foundation; either version 3 of the License, or
> + (at your option) any later version.
> +
> + This program is distributed in the hope that it will be useful,
> + but WITHOUT ANY WARRANTY; without even the implied warranty of
> + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + GNU General Public License for more details.
> +
> + You should have received a copy of the GNU General Public License
> + along with this program. If not, see <http://www.gnu.org/licenses/>. */
> +
> +
> +#include "defs.h"
> +#include "gdbtypes.h"
> +#include "compile-internal.h"
> +#include "gdb_assert.h"
> +
> +/* An object that maps a gdb type to a gcc type. */
> +
> +struct type_map_instance
> +{
> + /* The gdb type. */
> +
> + struct type *type;
> +
> + /* The corresponding gcc type handle. */
> +
> + gcc_type gcc_type;
> +};
> +
> +/* Hash a type_map_instance. */
> +
> +static hashval_t
> +hash_type_map_instance (const void *p)
> +{
> + const struct type_map_instance *inst = p;
> +
> + return htab_hash_pointer (inst->type);
> +}
> +
> +/* Check two type_map_instance objects for equality. */
> +
> +static int
> +eq_type_map_instance (const void *a, const void *b)
> +{
> + const struct type_map_instance *insta = a;
> + const struct type_map_instance *instb = b;
> +
> + return insta->type == instb->type;
> +}
> +
> +
> +
> +/* Insert an entry into the type map associated with CONTEXT that maps
> + from the gdb type TYPE to the gcc type GCC_TYPE. It is ok for a
> + given type to be inserted more than once, provided that the exact
> + same association is made each time. This simplifies how type
> + caching works elsewhere in this file -- see how struct type caching
> + is handled. */
> +
> +static void
> +insert_type (struct compile_c_instance *context, struct type *type,
> + gcc_type gcc_type)
> +{
> + struct type_map_instance inst, *add;
> + void **slot;
> +
> + inst.type = type;
> + inst.gcc_type = gcc_type;
> + slot = htab_find_slot (context->type_map, &inst, INSERT);
> +
> + add = *slot;
> + /* The type might have already been inserted in order to handle
> + recursive types. */
> + gdb_assert (add == NULL || add->gcc_type == gcc_type);
> +
> + if (add == NULL)
> + {
> + add = XNEW (struct type_map_instance);
> + *add = inst;
> + *slot = add;
> + }
> +}
> +
> +/* Convert a pointer type to its gcc representation. */
> +
> +static gcc_type
> +convert_pointer (struct compile_c_instance *context, struct type *type)
> +{
> + gcc_type target = convert_type (context, TYPE_TARGET_TYPE (type));
> +
> + return C_CTX (context)->c_ops->build_pointer_type (C_CTX (context),
> + target);
> +}
> +
> +/* Convert an array type to its gcc representation. */
> +
> +static gcc_type
> +convert_array (struct compile_c_instance *context, struct type *type)
> +{
> + gcc_type element_type;
> + struct type *range = TYPE_INDEX_TYPE (type);
> +
> + element_type = convert_type (context, TYPE_TARGET_TYPE (type));
> +
> + if (TYPE_LOW_BOUND_KIND (range) != PROP_CONST)
> + return C_CTX (context)->c_ops->error (C_CTX (context),
> + _("array type with non-constant"
> + " lower bound is not supported"));
> + if (TYPE_LOW_BOUND (range) != 0)
> + return C_CTX (context)->c_ops->error (C_CTX (context),
> + _("cannot convert array type with "
> + "non-zero lower bound to C"));
> +
> + if (TYPE_HIGH_BOUND_KIND (range) == PROP_LOCEXPR
> + || TYPE_HIGH_BOUND_KIND (range) == PROP_LOCLIST)
> + {
> + gcc_type result;
> + char *upper_bound;
> +
> + if (TYPE_VECTOR (type))
> + return C_CTX (context)->c_ops->error (C_CTX (context),
> + _("variably-sized vector type"
> + " is not supported"));
> +
> + upper_bound = c_get_range_decl_name (&TYPE_RANGE_DATA (range)->high);
> + result = C_CTX (context)->c_ops->build_vla_array_type (C_CTX (context),
> + element_type,
> + upper_bound);
> + xfree (upper_bound);
> + return result;
> + }
> + else
> + {
> + LONGEST low_bound, high_bound, count;
> +
> + if (get_array_bounds (type, &low_bound, &high_bound) == 0)
> + count = -1;
> + else
> + {
> + gdb_assert (low_bound == 0); /* Ensured above. */
> + count = high_bound + 1;
> + }
> +
> + if (TYPE_VECTOR (type))
> + return C_CTX (context)->c_ops->build_vector_type (C_CTX (context),
> + element_type,
> + count);
> + return C_CTX (context)->c_ops->build_array_type (C_CTX (context),
> + element_type, count);
> + }
> +}
> +
> +/* Convert a struct or union type to its gcc representation. */
> +
> +static gcc_type
> +convert_struct_or_union (struct compile_c_instance *context, struct type *type)
> +{
> + int i;
> + gcc_type result;
> +
> + /* First we create the resulting type and enter it into our hash
> + table. This lets recursive types work. */
> + if (TYPE_CODE (type) == TYPE_CODE_STRUCT)
> + result = C_CTX (context)->c_ops->build_record_type (C_CTX (context));
> + else
> + {
> + gdb_assert (TYPE_CODE (type) == TYPE_CODE_UNION);
> + result = C_CTX (context)->c_ops->build_union_type (C_CTX (context));
> + }
> + insert_type (context, type, result);
> +
> + for (i = 0; i < TYPE_NFIELDS (type); ++i)
> + {
> + gcc_type field_type;
> + unsigned long bitsize = TYPE_FIELD_BITSIZE (type, i);
> +
> + field_type = convert_type (context, TYPE_FIELD_TYPE (type, i));
> + if (bitsize == 0)
> + bitsize = 8 * TYPE_LENGTH (TYPE_FIELD_TYPE (type, i));
> + C_CTX (context)->c_ops->build_add_field (C_CTX (context), result,
> + TYPE_FIELD_NAME (type, i),
> + field_type,
> + bitsize,
> + TYPE_FIELD_BITPOS (type, i));
> + }
> +
> + C_CTX (context)->c_ops->finish_record_or_union (C_CTX (context), result,
> + TYPE_LENGTH (type));
> + return result;
> +}
> +
> +/* Convert an enum type to its gcc representation. */
> +
> +static gcc_type
> +convert_enum (struct compile_c_instance *context, struct type *type)
> +{
> + gcc_type int_type, result;
> + int i;
> + struct gcc_c_context *ctx = C_CTX (context);
> +
> + int_type = ctx->c_ops->int_type (ctx,
> + TYPE_UNSIGNED (type),
> + TYPE_LENGTH (type));
> +
> + result = ctx->c_ops->build_enum_type (ctx, int_type);
> + for (i = 0; i < TYPE_NFIELDS (type); ++i)
> + {
> + ctx->c_ops->build_add_enum_constant (ctx,
> + result,
> + TYPE_FIELD_NAME (type, i),
> + TYPE_FIELD_ENUMVAL (type, i));
> + }
> +
> + ctx->c_ops->finish_enum_type (ctx, result);
> +
> + return result;
> +}
> +
> +/* Convert a function type to its gcc representation. */
> +
> +static gcc_type
> +convert_func (struct compile_c_instance *context, struct type *type)
> +{
> + int i;
> + gcc_type result, return_type;
> + struct gcc_type_array array;
> + int is_varargs = TYPE_VARARGS (type) || !TYPE_PROTOTYPED (type);
> +
> + /* This approach means we can't make self-referential function
> + types. Those are impossible in C, though. */
> + return_type = convert_type (context, TYPE_TARGET_TYPE (type));
> +
> + array.n_elements = TYPE_NFIELDS (type);
> + array.elements = XNEWVEC (gcc_type, TYPE_NFIELDS (type));
> + for (i = 0; i < TYPE_NFIELDS (type); ++i)
> + array.elements[i] = convert_type (context, TYPE_FIELD_TYPE (type, i));
> +
> + result = C_CTX (context)->c_ops->build_function_type (C_CTX (context),
> + return_type,
> + &array, is_varargs);
> + xfree (array.elements);
> +
> + return result;
> +}
> +
> +/* Convert an integer type to its gcc representation. */
> +
> +static gcc_type
> +convert_int (struct compile_c_instance *context, struct type *type)
> +{
> + return C_CTX (context)->c_ops->int_type (C_CTX (context),
> + TYPE_UNSIGNED (type),
> + TYPE_LENGTH (type));
> +}
> +
> +/* Convert a floating-point type to its gcc representation. */
> +
> +static gcc_type
> +convert_float (struct compile_c_instance *context, struct type *type)
> +{
> + return C_CTX (context)->c_ops->float_type (C_CTX (context),
> + TYPE_LENGTH (type));
> +}
> +
> +/* Convert the 'void' type to its gcc representation. */
> +
> +static gcc_type
> +convert_void (struct compile_c_instance *context, struct type *type)
> +{
> + return C_CTX (context)->c_ops->void_type (C_CTX (context));
> +}
> +
> +/* Convert a boolean type to its gcc representation. */
> +
> +static gcc_type
> +convert_bool (struct compile_c_instance *context, struct type *type)
> +{
> + return C_CTX (context)->c_ops->bool_type (C_CTX (context));
> +}
> +
> +/* Convert a qualified type to its gcc representation. */
> +
> +static gcc_type
> +convert_qualified (struct compile_c_instance *context, struct type *type)
> +{
> + struct type *unqual = make_unqualified_type (type);
> + gcc_type unqual_converted;
> + int quals = 0;
> +
> + unqual_converted = convert_type (context, unqual);
> +
> + if (TYPE_CONST (type))
> + quals |= GCC_QUALIFIER_CONST;
> + if (TYPE_VOLATILE (type))
> + quals |= GCC_QUALIFIER_VOLATILE;
> + if (TYPE_RESTRICT (type))
> + quals |= GCC_QUALIFIER_RESTRICT;
> +
> + return C_CTX (context)->c_ops->build_qualified_type (C_CTX (context),
> + unqual_converted,
> + quals);
> +}
> +
> +/* Convert a complex type to its gcc representation. */
> +
> +static gcc_type
> +convert_complex (struct compile_c_instance *context, struct type *type)
> +{
> + gcc_type base = convert_type (context, TYPE_TARGET_TYPE (type));
> +
> + return C_CTX (context)->c_ops->build_complex_type (C_CTX (context), base);
> +}
> +
> +/* A helper function which knows how to convert most types from their
> + gdb representation to the corresponding gcc form. This examines
> + the TYPE and dispatches to the appropriate conversion function. It
> + returns the gcc type. */
> +
> +static gcc_type
> +convert_type_basic (struct compile_c_instance *context, struct type *type)
> +{
> + /* If we are converting a qualified type, first convert the
> + unqualified type and then apply the qualifiers. */
> + if ((TYPE_INSTANCE_FLAGS (type) & (TYPE_INSTANCE_FLAG_CONST
> + | TYPE_INSTANCE_FLAG_VOLATILE
> + | TYPE_INSTANCE_FLAG_RESTRICT)) != 0)
> + return convert_qualified (context, type);
> +
> + switch (TYPE_CODE (type))
> + {
> + case TYPE_CODE_PTR:
> + return convert_pointer (context, type);
> +
> + case TYPE_CODE_ARRAY:
> + return convert_array (context, type);
> +
> + case TYPE_CODE_STRUCT:
> + case TYPE_CODE_UNION:
> + return convert_struct_or_union (context, type);
> +
> + case TYPE_CODE_ENUM:
> + return convert_enum (context, type);
> +
> + case TYPE_CODE_FUNC:
> + return convert_func (context, type);
> +
> + case TYPE_CODE_INT:
> + return convert_int (context, type);
> +
> + case TYPE_CODE_FLT:
> + return convert_float (context, type);
> +
> + case TYPE_CODE_VOID:
> + return convert_void (context, type);
> +
> + case TYPE_CODE_BOOL:
> + return convert_bool (context, type);
> +
> + case TYPE_CODE_COMPLEX:
> + return convert_complex (context, type);
> + }
> +
> + return C_CTX (context)->c_ops->error (C_CTX (context),
> + _("cannot convert gdb type "
> + "to gcc type"));
> +}
> +
> +/* See compile-internal.h. */
> +
> +gcc_type
> +convert_type (struct compile_c_instance *context, struct type *type)
> +{
> + struct type_map_instance inst, *found;
> + gcc_type result;
> +
> + /* We don't ever have to deal with typedefs in this code, because
> + those are only needed as symbols by the C compiler. */
> + CHECK_TYPEDEF (type);
> +
> + inst.type = type;
> + found = htab_find (context->type_map, &inst);
> + if (found != NULL)
> + return found->gcc_type;
> +
> + result = convert_type_basic (context, type);
> + insert_type (context, type, result);
> + return result;
> +}
> +
> +
> +
> +/* Delete the compiler instance C. */
> +
> +static void
> +delete_instance (struct compile_instance *c)
> +{
> + struct compile_c_instance *context = (struct compile_c_instance *) c;
> +
> + context->base.fe->ops->destroy (context->base.fe);
> + htab_delete (context->type_map);
> + if (context->symbol_err_map != NULL)
> + htab_delete (context->symbol_err_map);
> + xfree (context);
> +}
> +
> +/* See compile-internal.h. */
> +
> +struct compile_instance *
> +new_compile_instance (struct gcc_c_context *fe)
> +{
> + struct compile_c_instance *result = XCNEW (struct compile_c_instance);
> +
> + result->base.fe = &fe->base;
> + result->base.destroy = delete_instance;
> + result->base.gcc_target_options = ("-std=gnu11"
> + /* Otherwise the .o file may need
> + "_Unwind_Resume" and
> + "__gcc_personality_v0". */
> + " -fno-exceptions");
> +
> + result->type_map = htab_create_alloc (10, hash_type_map_instance,
> + eq_type_map_instance,
> + xfree, xcalloc, xfree);
> +
> + fe->c_ops->set_callbacks (fe, gcc_convert_symbol,
> + gcc_symbol_address, result);
> +
> + return &result->base;
> +}
> diff --git a/gdb/compile/compile-internal.h b/gdb/compile/compile-internal.h
> new file mode 100644
> index 0000000..cb8d3d1
> --- /dev/null
> +++ b/gdb/compile/compile-internal.h
> @@ -0,0 +1,147 @@
> +/* Header file for GDB compile command and supporting functions.
> + Copyright (C) 2014 Free Software Foundation, Inc.
> +
> + This program is free software; you can redistribute it and/or modify
> + it under the terms of the GNU General Public License as published by
> + the Free Software Foundation; either version 3 of the License, or
> + (at your option) any later version.
> +
> + This program is distributed in the hope that it will be useful,
> + but WITHOUT ANY WARRANTY; without even the implied warranty of
> + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + GNU General Public License for more details.
> +
> + You should have received a copy of the GNU General Public License
> + along with this program. If not, see <http://www.gnu.org/licenses/>. */
> +
> +#ifndef GDB_COMPILE_INTERNAL_H
> +#define GDB_COMPILE_INTERNAL_H
> +
> +#include "hashtab.h"
> +#include "gcc-c-interface.h"
> +
> +/* Debugging flag for the "compile" family of commands. */
> +
> +extern int compile_debug;
> +
> +struct block;
> +
> +/* An object of this type holds state associated with a given
> + compilation job. */
> +
> +struct compile_instance
> +{
> + /* The GCC front end. */
> +
> + struct gcc_base_context *fe;
> +
> + /* The "scope" of this compilation. */
> +
> + enum compile_i_scope_types scope;
> +
> + /* The block in which an expression is being parsed. */
> +
> + const struct block *block;
> +
> + /* Specify "-std=gnu11", "-std=gnu++11" or similar. These options are put
> + after CU's DW_AT_producer compilation options to override them. */
> +
> + const char *gcc_target_options;
> +
> + /* How to destroy this object. */
> +
> + void (*destroy) (struct compile_instance *);
> +};
> +
> +/* A subclass of compile_instance that is specific to the C front
> + end. */
> +struct compile_c_instance
> +{
> + /* Base class. Note that the base class vtable actually points to a
> + gcc_c_fe_vtable. */
> +
> + struct compile_instance base;
> +
> + /* Map from gdb types to gcc types. */
> +
> + htab_t type_map;
> +
> + /* Map from gdb symbols to gcc error messages to emit. */
> +
> + htab_t symbol_err_map;
> +};
> +
> +/* A helper macro that takes a compile_c_instance and returns its
> + corresponding gcc_c_context. */
> +
> +#define C_CTX(I) ((struct gcc_c_context *) ((I)->base.fe))
> +
> +/* Define header and footers for different scopes. */
> +
> +/* A simple scope just declares a function named "_gdb_expr", takes no
> + arguments and returns no value. */
> +
> +#define COMPILE_I_SIMPLE_REGISTER_STRUCT_TAG "__gdb_regs"
> +#define COMPILE_I_SIMPLE_REGISTER_ARG_NAME "__regs"
> +#define COMPILE_I_SIMPLE_REGISTER_DUMMY "_dummy"
> +
> +/* Call gdbarch_register_name (GDBARCH, REGNUM) and convert its result
> + to a form suitable for the compiler source. The register names
> + should not clash with inferior defined macros. Returned pointer is
> + never NULL. Returned pointer needs to be deallocated by xfree. */
> +
> +extern char *compile_register_name_mangled (struct gdbarch *gdbarch,
> + int regnum);
> +
> +/* Convert compiler source register name to register number of
> + GDBARCH. Returned value is always >= 0, function throws an error
> + for non-matching REG_NAME. */
> +
> +extern int compile_register_name_demangle (struct gdbarch *gdbarch,
> + const char *reg_name);
> +
> +/* Convert a gdb type, TYPE, to a GCC type. CONTEXT is used to do the
> + actual conversion. The new GCC type is returned. */
> +
> +struct type;
> +extern gcc_type convert_type (struct compile_c_instance *context,
> + struct type *type);
> +
> +/* A callback suitable for use as the GCC C symbol oracle. */
> +
> +extern gcc_c_oracle_function gcc_convert_symbol;
> +
> +/* A callback suitable for use as the GCC C address oracle. */
> +
> +extern gcc_c_symbol_address_function gcc_symbol_address;
> +
> +/* Instantiate a GDB object holding state for the GCC context FE. The
> + new object is returned. */
> +
> +extern struct compile_instance *new_compile_instance (struct gcc_c_context *fe);
> +
> +/* Emit code to compute the address for all the local variables in
> + scope at PC in BLOCK. Returns a malloc'd vector, indexed by gdb
> + register number, where each element indicates if the corresponding
> + register is needed to compute a local variable. */
> +
> +extern unsigned char *generate_c_for_variable_locations
> + (struct compile_c_instance *compiler,
> + struct ui_file *stream,
> + struct gdbarch *gdbarch,
> + const struct block *block,
> + CORE_ADDR pc);
> +
> +/* Get the GCC mode attribute value for a given type size. */
> +
> +extern const char *c_get_mode_for_size (int size);
> +
> +/* Given a dynamic property, return an xmallocd name that is used to
> + represent its size. The result must be freed by the caller. The
> + contents of the resulting string will be the same each time for
> + each call with the same argument. */
> +
> +struct dynamic_prop;
> +extern char *c_get_range_decl_name (const struct dynamic_prop *prop);
> +
> +#endif /* GDB_COMPILE_INTERNAL_H */
> diff --git a/gdb/compile/compile-loc2c.c b/gdb/compile/compile-loc2c.c
> new file mode 100644
> index 0000000..9cfb5fb
> --- /dev/null
> +++ b/gdb/compile/compile-loc2c.c
> @@ -0,0 +1,1147 @@
> +/* Convert a DWARF location expression to C
> +
> + Copyright (C) 2014 Free Software Foundation, Inc.
> +
> + This file is part of GDB.
> +
> + This program is free software; you can redistribute it and/or modify
> + it under the terms of the GNU General Public License as published by
> + the Free Software Foundation; either version 3 of the License, or
> + (at your option) any later version.
> +
> + This program is distributed in the hope that it will be useful,
> + but WITHOUT ANY WARRANTY; without even the implied warranty of
> + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + GNU General Public License for more details.
> +
> + You should have received a copy of the GNU General Public License
> + along with this program. If not, see <http://www.gnu.org/licenses/>. */
> +
> +#include "defs.h"
> +#include "dwarf2.h"
> +#include "dwarf2expr.h"
> +#include "dwarf2loc.h"
> +#include "ui-file.h"
> +#include "utils.h"
> +#include "compile-internal.h"
> +#include "compile.h"
> +#include "block.h"
> +#include "dwarf2-frame.h"
> +#include "gdb_vecs.h"
> +#include "value.h"
> +
> +
> +
> +/* Information about a given instruction. */
> +
> +struct insn_info
> +{
> + /* Stack depth at entry. */
> +
> + unsigned int depth;
> +
> + /* Whether this instruction has been visited. */
> +
> + unsigned int visited : 1;
> +
> + /* Whether this instruction needs a label. */
> +
> + unsigned int label : 1;
> +
> + /* Whether this instruction is DW_OP_GNU_push_tls_address. This is
> + a hack until we can add a feature to glibc to let us properly
> + generate code for TLS. */
> +
> + unsigned int is_tls : 1;
> +};
> +
> +/* A helper function for compute_stack_depth that does the work. This
> + examines the DWARF expression starting from START and computes
> + stack effects.
> +
> + NEED_TEMPVAR is an out parameter which is set if this expression
> + needs a special temporary variable to be emitted (see the code
> + generator).
> + INFO is an array of insn_info objects, indexed by offset from the
> + start of the DWARF expression.
> + TO_DO is a list of bytecodes which must be examined; it may be
> + added to by this function.
> + BYTE_ORDER and ADDR_SIZE describe this bytecode in the obvious way.
> + OP_PTR and OP_END are the bounds of the DWARF expression. */
> +
> +static void
> +compute_stack_depth_worker (int start, int *need_tempvar,
> + struct insn_info *info,
> + VEC (int) **to_do,
> + enum bfd_endian byte_order, unsigned int addr_size,
> + const gdb_byte *op_ptr, const gdb_byte *op_end)
> +{
> + const gdb_byte * const base = op_ptr;
> + int stack_depth;
> +
> + op_ptr += start;
> + gdb_assert (info[start].visited);
> + stack_depth = info[start].depth;
> +
> + while (op_ptr < op_end)
> + {
> + enum dwarf_location_atom op = *op_ptr;
> + uint64_t reg;
> + int64_t offset;
> + int ndx = op_ptr - base;
> +
> +#define SET_CHECK_DEPTH(WHERE) \
> + if (info[WHERE].visited) \
> + { \
> + if (info[WHERE].depth != stack_depth) \
> + error (_("inconsistent stack depths")); \
> + } \
> + else \
> + { \
> + /* Stack depth not set, so set it. */ \
> + info[WHERE].visited = 1; \
> + info[WHERE].depth = stack_depth; \
> + }
> +
> + SET_CHECK_DEPTH (ndx);
> +
> + ++op_ptr;
> +
> + switch (op)
> + {
> + case DW_OP_lit0:
> + case DW_OP_lit1:
> + case DW_OP_lit2:
> + case DW_OP_lit3:
> + case DW_OP_lit4:
> + case DW_OP_lit5:
> + case DW_OP_lit6:
> + case DW_OP_lit7:
> + case DW_OP_lit8:
> + case DW_OP_lit9:
> + case DW_OP_lit10:
> + case DW_OP_lit11:
> + case DW_OP_lit12:
> + case DW_OP_lit13:
> + case DW_OP_lit14:
> + case DW_OP_lit15:
> + case DW_OP_lit16:
> + case DW_OP_lit17:
> + case DW_OP_lit18:
> + case DW_OP_lit19:
> + case DW_OP_lit20:
> + case DW_OP_lit21:
> + case DW_OP_lit22:
> + case DW_OP_lit23:
> + case DW_OP_lit24:
> + case DW_OP_lit25:
> + case DW_OP_lit26:
> + case DW_OP_lit27:
> + case DW_OP_lit28:
> + case DW_OP_lit29:
> + case DW_OP_lit30:
> + case DW_OP_lit31:
> + ++stack_depth;
> + break;
> +
> + case DW_OP_addr:
> + op_ptr += addr_size;
> + ++stack_depth;
> + break;
> +
> + case DW_OP_const1u:
> + case DW_OP_const1s:
> + op_ptr += 1;
> + ++stack_depth;
> + break;
> + case DW_OP_const2u:
> + case DW_OP_const2s:
> + op_ptr += 2;
> + ++stack_depth;
> + break;
> + case DW_OP_const4u:
> + case DW_OP_const4s:
> + op_ptr += 4;
> + ++stack_depth;
> + break;
> + case DW_OP_const8u:
> + case DW_OP_const8s:
> + op_ptr += 8;
> + ++stack_depth;
> + break;
> + case DW_OP_constu:
> + case DW_OP_consts:
> + op_ptr = safe_read_sleb128 (op_ptr, op_end, &offset);
> + ++stack_depth;
> + break;
> +
> + case DW_OP_reg0:
> + case DW_OP_reg1:
> + case DW_OP_reg2:
> + case DW_OP_reg3:
> + case DW_OP_reg4:
> + case DW_OP_reg5:
> + case DW_OP_reg6:
> + case DW_OP_reg7:
> + case DW_OP_reg8:
> + case DW_OP_reg9:
> + case DW_OP_reg10:
> + case DW_OP_reg11:
> + case DW_OP_reg12:
> + case DW_OP_reg13:
> + case DW_OP_reg14:
> + case DW_OP_reg15:
> + case DW_OP_reg16:
> + case DW_OP_reg17:
> + case DW_OP_reg18:
> + case DW_OP_reg19:
> + case DW_OP_reg20:
> + case DW_OP_reg21:
> + case DW_OP_reg22:
> + case DW_OP_reg23:
> + case DW_OP_reg24:
> + case DW_OP_reg25:
> + case DW_OP_reg26:
> + case DW_OP_reg27:
> + case DW_OP_reg28:
> + case DW_OP_reg29:
> + case DW_OP_reg30:
> + case DW_OP_reg31:
> + ++stack_depth;
> + break;
> +
> + case DW_OP_regx:
> + op_ptr = safe_read_uleb128 (op_ptr, op_end, ®);
> + ++stack_depth;
> + break;
> +
> + case DW_OP_breg0:
> + case DW_OP_breg1:
> + case DW_OP_breg2:
> + case DW_OP_breg3:
> + case DW_OP_breg4:
> + case DW_OP_breg5:
> + case DW_OP_breg6:
> + case DW_OP_breg7:
> + case DW_OP_breg8:
> + case DW_OP_breg9:
> + case DW_OP_breg10:
> + case DW_OP_breg11:
> + case DW_OP_breg12:
> + case DW_OP_breg13:
> + case DW_OP_breg14:
> + case DW_OP_breg15:
> + case DW_OP_breg16:
> + case DW_OP_breg17:
> + case DW_OP_breg18:
> + case DW_OP_breg19:
> + case DW_OP_breg20:
> + case DW_OP_breg21:
> + case DW_OP_breg22:
> + case DW_OP_breg23:
> + case DW_OP_breg24:
> + case DW_OP_breg25:
> + case DW_OP_breg26:
> + case DW_OP_breg27:
> + case DW_OP_breg28:
> + case DW_OP_breg29:
> + case DW_OP_breg30:
> + case DW_OP_breg31:
> + op_ptr = safe_read_sleb128 (op_ptr, op_end, &offset);
> + ++stack_depth;
> + break;
> + case DW_OP_bregx:
> + {
> + op_ptr = safe_read_uleb128 (op_ptr, op_end, ®);
> + op_ptr = safe_read_sleb128 (op_ptr, op_end, &offset);
> + ++stack_depth;
> + }
> + break;
> + case DW_OP_fbreg:
> + op_ptr = safe_read_sleb128 (op_ptr, op_end, &offset);
> + ++stack_depth;
> + break;
> +
> + case DW_OP_dup:
> + ++stack_depth;
> + break;
> +
> + case DW_OP_drop:
> + --stack_depth;
> + break;
> +
> + case DW_OP_pick:
> + ++op_ptr;
> + ++stack_depth;
> + break;
> +
> + case DW_OP_rot:
> + case DW_OP_swap:
> + *need_tempvar = 1;
> + break;
> +
> + case DW_OP_over:
> + ++stack_depth;
> + break;
> +
> + case DW_OP_abs:
> + case DW_OP_neg:
> + case DW_OP_not:
> + case DW_OP_deref:
> + break;
> +
> + case DW_OP_deref_size:
> + ++op_ptr;
> + break;
> +
> + case DW_OP_plus_uconst:
> + op_ptr = safe_read_uleb128 (op_ptr, op_end, ®);
> + break;
> +
> + case DW_OP_div:
> + case DW_OP_shra:
> + case DW_OP_and:
> + case DW_OP_minus:
> + case DW_OP_mod:
> + case DW_OP_mul:
> + case DW_OP_or:
> + case DW_OP_plus:
> + case DW_OP_shl:
> + case DW_OP_shr:
> + case DW_OP_xor:
> + case DW_OP_le:
> + case DW_OP_ge:
> + case DW_OP_eq:
> + case DW_OP_lt:
> + case DW_OP_gt:
> + case DW_OP_ne:
> + --stack_depth;
> + break;
> +
> + case DW_OP_call_frame_cfa:
> + ++stack_depth;
> + break;
> +
> + case DW_OP_GNU_push_tls_address:
> + info[ndx].is_tls = 1;
> + break;
> +
> + case DW_OP_skip:
> + offset = extract_signed_integer (op_ptr, 2, byte_order);
> + op_ptr += 2;
> + offset = op_ptr + offset - base;
> + /* If the destination has not been seen yet, add it to the
> + to-do list. */
> + if (!info[offset].visited)
> + VEC_safe_push (int, *to_do, offset);
> + SET_CHECK_DEPTH (offset);
> + info[offset].label = 1;
> + /* We're done with this line of code. */
> + return;
> +
> + case DW_OP_bra:
> + offset = extract_signed_integer (op_ptr, 2, byte_order);
> + op_ptr += 2;
> + offset = op_ptr + offset - base;
> + --stack_depth;
> + /* If the destination has not been seen yet, add it to the
> + to-do list. */
> + if (!info[offset].visited)
> + VEC_safe_push (int, *to_do, offset);
> + SET_CHECK_DEPTH (offset);
> + info[offset].label = 1;
> + break;
> +
> + case DW_OP_nop:
> + break;
> +
> + default:
> + error (_("unhandled DWARF op: %s"), get_DW_OP_name (op));
> + }
> + }
> +
> + gdb_assert (op_ptr == op_end);
> +
> +#undef SET_CHECK_DEPTH
> +}
> +
> +/* Compute the maximum needed stack depth of a DWARF expression, and
> + some other information as well.
> +
> + BYTE_ORDER and ADDR_SIZE describe this bytecode in the obvious way.
> + NEED_TEMPVAR is an out parameter which is set if this expression
> + needs a special temporary variable to be emitted (see the code
> + generator).
> + IS_TLS is an out parameter which is set if this expression refers
> + to a TLS variable.
> + OP_PTR and OP_END are the bounds of the DWARF expression.
> + INITIAL_DEPTH is the initial depth of the DWARF expression stack.
> + INFO is an array of insn_info objects, indexed by offset from the
> + start of the DWARF expression.
> +
> + This returns the maximum stack depth. */
> +
> +static int
> +compute_stack_depth (enum bfd_endian byte_order, unsigned int addr_size,
> + int *need_tempvar, int *is_tls,
> + const gdb_byte *op_ptr, const gdb_byte *op_end,
> + int initial_depth,
> + struct insn_info **info)
> +{
> + unsigned char *set;
> + struct cleanup *outer_cleanup, *cleanup;
> + VEC (int) *to_do = NULL;
> + int stack_depth, i;
> +
> + *info = XCNEWVEC (struct insn_info, op_end - op_ptr);
> + outer_cleanup = make_cleanup (xfree, *info);
> +
> + cleanup = make_cleanup (VEC_cleanup (int), &to_do);
> +
> + VEC_safe_push (int, to_do, 0);
> + (*info)[0].depth = initial_depth;
> + (*info)[0].visited = 1;
> +
> + while (!VEC_empty (int, to_do))
> + {
> + int ndx = VEC_pop (int, to_do);
> +
> + compute_stack_depth_worker (ndx, need_tempvar, *info, &to_do,
> + byte_order, addr_size,
> + op_ptr, op_end);
> + }
> +
> + stack_depth = 0;
> + *is_tls = 0;
> + for (i = 0; i < op_end - op_ptr; ++i)
> + {
> + if ((*info)[i].depth > stack_depth)
> + stack_depth = (*info)[i].depth;
> + if ((*info)[i].is_tls)
> + *is_tls = 1;
> + }
> +
> + do_cleanups (cleanup);
> + discard_cleanups (outer_cleanup);
> + return stack_depth + 1;
> +}
> +
> +
> +
> +#define GCC_UINTPTR "__gdb_uintptr"
> +#define GCC_INTPTR "__gdb_intptr"
> +
> +/* Emit code to push a constant. */
> +
> +static void
> +push (int indent, struct ui_file *stream, ULONGEST l)
> +{
> + fprintfi_filtered (indent, stream, "__gdb_stack[++__gdb_tos] = %s;\n",
> + hex_string (l));
> +}
> +
> +/* Emit code to push an arbitrary expression. This works like
> + printf. */
> +
> +static void
> +pushf (int indent, struct ui_file *stream, const char *format, ...)
> +{
> + va_list args;
> +
> + fprintfi_filtered (indent, stream, "__gdb_stack[__gdb_tos + 1] = ");
> + va_start (args, format);
> + vfprintf_filtered (stream, format, args);
> + va_end (args);
> + fprintf_filtered (stream, ";\n");
> +
> + fprintfi_filtered (indent, stream, "++__gdb_tos;\n");
> +}
> +
> +/* Emit code for a unary expression -- one which operates in-place on
> + the top-of-stack. This works like printf. */
> +
> +static void
> +unary (int indent, struct ui_file *stream, const char *format, ...)
> +{
> + va_list args;
> +
> + fprintfi_filtered (indent, stream, "__gdb_stack[__gdb_tos] = ");
> + va_start (args, format);
> + vfprintf_filtered (stream, format, args);
> + va_end (args);
> + fprintf_filtered (stream, ";\n");
> +}
> +
> +/* Emit code for a unary expression -- one which uses the top two
> + stack items, popping the topmost one. This works like printf. */
> +
> +static void
> +binary (int indent, struct ui_file *stream, const char *format, ...)
> +{
> + va_list args;
> +
> + fprintfi_filtered (indent, stream, "__gdb_stack[__gdb_tos - 1] = ");
> + va_start (args, format);
> + vfprintf_filtered (stream, format, args);
> + va_end (args);
> + fprintf_filtered (stream, ";\n");
> + fprintfi_filtered (indent, stream, "--__gdb_tos;\n");
> +}
> +
> +/* Print the name of a label given its "SCOPE", an arbitrary integer
> + used for uniqueness, and its TARGET, the bytecode offset
> + corresponding to the label's point of definition. */
> +
> +static void
> +print_label (struct ui_file *stream, unsigned int scope, int target)
> +{
> + fprintf_filtered (stream, "__label_%u_%s",
> + scope, pulongest (target));
> +}
> +
> +/* Emit code that pushes a register's address on the stack.
> + REGISTERS_USED is an out parameter which is updated to note which
> + register was needed by this expression. */
> +
> +static void
> +pushf_register_address (int indent, struct ui_file *stream,
> + unsigned char *registers_used,
> + struct gdbarch *gdbarch, int regnum)
> +{
> + char *regname = compile_register_name_mangled (gdbarch, regnum);
> + struct cleanup *cleanups = make_cleanup (xfree, regname);
> +
> + registers_used[regnum] = 1;
> + pushf (indent, stream, "&" COMPILE_I_SIMPLE_REGISTER_ARG_NAME "->%s",
> + regname);
> +
> + do_cleanups (cleanups);
> +}
> +
> +/* Emit code that pushes a register's value on the stack.
> + REGISTERS_USED is an out parameter which is updated to note which
> + register was needed by this expression. OFFSET is added to the
> + register's value before it is pushed. */
> +
> +static void
> +pushf_register (int indent, struct ui_file *stream,
> + unsigned char *registers_used,
> + struct gdbarch *gdbarch, int regnum, uint64_t offset)
> +{
> + char *regname = compile_register_name_mangled (gdbarch, regnum);
> + struct cleanup *cleanups = make_cleanup (xfree, regname);
> +
> + registers_used[regnum] = 1;
> + if (offset == 0)
> + pushf (indent, stream, COMPILE_I_SIMPLE_REGISTER_ARG_NAME "->%s",
> + regname);
> + else
> + pushf (indent, stream, COMPILE_I_SIMPLE_REGISTER_ARG_NAME "->%s + %s",
> + regname, hex_string (offset));
> +
> + do_cleanups (cleanups);
> +}
> +
> +/* Compile a DWARF expression to C code.
> +
> + INDENT is the indentation level to use.
> + STREAM is the stream where the code should be written.
> +
> + TYPE_NAME names the type of the result of the DWARF expression.
> + For locations this is "void *" but for array bounds it will be an
> + integer type.
> +
> + RESULT_NAME is the name of a variable in the resulting C code. The
> + result of the expression will be assigned to this variable.
> +
> + SYM is the symbol corresponding to this expression.
> + PC is the location at which the expression is being evaluated.
> + ARCH is the architecture to use.
> +
> + REGISTERS_USED is an out parameter which is updated to note which
> + registers were needed by this expression.
> +
> + ADDR_SIZE is the DWARF address size to use.
> +
> + OPT_PTR and OP_END are the bounds of the DWARF expression.
> +
> + If non-NULL, INITIAL points to an initial value to write to the
> + stack. If NULL, no initial value is written.
> +
> + PER_CU is the per-CU object used for looking up various other
> + things. */
> +
> +static void
> +do_compile_dwarf_expr_to_c (int indent, struct ui_file *stream,
> + const char *type_name,
> + const char *result_name,
> + struct symbol *sym, CORE_ADDR pc,
> + struct gdbarch *arch,
> + unsigned char *registers_used,
> + unsigned int addr_size,
> + const gdb_byte *op_ptr, const gdb_byte *op_end,
> + CORE_ADDR *initial,
> + struct dwarf2_per_cu_data *per_cu)
> +{
> + /* We keep a counter so that labels and other objects we create have
> + unique names. */
> + static unsigned int scope;
> +
> + enum bfd_endian byte_order = gdbarch_byte_order (arch);
> + const gdb_byte * const base = op_ptr;
> + int need_tempvar = 0;
> + int is_tls = 0;
> + struct cleanup *cleanup;
> + struct insn_info *info;
> + int stack_depth;
> +
> + ++scope;
> +
> + fprintfi_filtered (indent, stream, "%s%s;\n", type_name, result_name);
> + fprintfi_filtered (indent, stream, "{\n");
> + indent += 2;
> +
> + stack_depth = compute_stack_depth (byte_order, addr_size,
> + &need_tempvar, &is_tls,
> + op_ptr, op_end, initial != NULL,
> + &info);
> + cleanup = make_cleanup (xfree, info);
> +
> + /* This is a hack until we can add a feature to glibc to let us
> + properly generate code for TLS. You might think we could emit
> + the address in the ordinary course of translating
> + DW_OP_GNU_push_tls_address, but since the operand appears on the
> + stack, it is relatively hard to find, and the idea of calling
> + target_translate_tls_address with OFFSET==0 and then adding the
> + offset by hand seemed too hackish. */
> + if (is_tls)
> + {
> + struct frame_info *frame = get_selected_frame (NULL);
> + struct value *val;
> +
> + if (frame == NULL)
> + error (_("Symbol \"%s\" cannot be used because "
> + "there is no selected frame"),
> + SYMBOL_PRINT_NAME (sym));
> +
> + val = read_var_value (sym, frame);
> + if (VALUE_LVAL (val) != lval_memory)
> + error (_("Symbol \"%s\" cannot be used for compilation evaluation "
> + "as its address has not been found."),
> + SYMBOL_PRINT_NAME (sym));
> +
> + warning (_("Symbol \"%s\" is thread-local and currently can only "
> + "be referenced from the current thread in "
> + "compiled code."),
> + SYMBOL_PRINT_NAME (sym));
> +
> + fprintfi_filtered (indent, stream, "%s = %s;\n",
> + result_name,
> + core_addr_to_string (value_address (val)));
> + fprintfi_filtered (indent - 2, stream, "}\n");
> + do_cleanups (cleanup);
> + return;
> + }
> +
> + fprintfi_filtered (indent, stream, GCC_UINTPTR " __gdb_stack[%d];\n",
> + stack_depth);
> +
> + if (need_tempvar)
> + fprintfi_filtered (indent, stream, GCC_UINTPTR " __gdb_tmp;\n");
> + fprintfi_filtered (indent, stream, "int __gdb_tos = -1;\n");
> +
> + if (initial != NULL)
> + pushf (indent, stream, core_addr_to_string (*initial));
> +
> + while (op_ptr < op_end)
> + {
> + enum dwarf_location_atom op = *op_ptr;
> + uint64_t uoffset, reg;
> + int64_t offset;
> +
> + print_spaces (indent - 2, stream);
> + if (info[op_ptr - base].label)
> + {
> + print_label (stream, scope, op_ptr - base);
> + fprintf_filtered (stream, ":;");
> + }
> + fprintf_filtered (stream, "/* %s */\n", get_DW_OP_name (op));
> +
> + /* This is handy for debugging the generated code:
> + fprintf_filtered (stream, "if (__gdb_tos != %d) abort ();\n",
> + (int) info[op_ptr - base].depth - 1);
> + */
> +
> + ++op_ptr;
> +
> + switch (op)
> + {
> + case DW_OP_lit0:
> + case DW_OP_lit1:
> + case DW_OP_lit2:
> + case DW_OP_lit3:
> + case DW_OP_lit4:
> + case DW_OP_lit5:
> + case DW_OP_lit6:
> + case DW_OP_lit7:
> + case DW_OP_lit8:
> + case DW_OP_lit9:
> + case DW_OP_lit10:
> + case DW_OP_lit11:
> + case DW_OP_lit12:
> + case DW_OP_lit13:
> + case DW_OP_lit14:
> + case DW_OP_lit15:
> + case DW_OP_lit16:
> + case DW_OP_lit17:
> + case DW_OP_lit18:
> + case DW_OP_lit19:
> + case DW_OP_lit20:
> + case DW_OP_lit21:
> + case DW_OP_lit22:
> + case DW_OP_lit23:
> + case DW_OP_lit24:
> + case DW_OP_lit25:
> + case DW_OP_lit26:
> + case DW_OP_lit27:
> + case DW_OP_lit28:
> + case DW_OP_lit29:
> + case DW_OP_lit30:
> + case DW_OP_lit31:
> + push (indent, stream, op - DW_OP_lit0);
> + break;
> +
> + case DW_OP_addr:
> + op_ptr += addr_size;
> + /* Some versions of GCC emit DW_OP_addr before
> + DW_OP_GNU_push_tls_address. In this case the value is an
> + index, not an address. We don't support things like
> + branching between the address and the TLS op. */
> + if (op_ptr >= op_end || *op_ptr != DW_OP_GNU_push_tls_address)
> + uoffset += dwarf2_per_cu_text_offset (per_cu);
> + push (indent, stream, uoffset);
> + break;
> +
> + case DW_OP_const1u:
> + push (indent, stream,
> + extract_unsigned_integer (op_ptr, 1, byte_order));
> + op_ptr += 1;
> + break;
> + case DW_OP_const1s:
> + push (indent, stream,
> + extract_signed_integer (op_ptr, 1, byte_order));
> + op_ptr += 1;
> + break;
> + case DW_OP_const2u:
> + push (indent, stream,
> + extract_unsigned_integer (op_ptr, 2, byte_order));
> + op_ptr += 2;
> + break;
> + case DW_OP_const2s:
> + push (indent, stream,
> + extract_signed_integer (op_ptr, 2, byte_order));
> + op_ptr += 2;
> + break;
> + case DW_OP_const4u:
> + push (indent, stream,
> + extract_unsigned_integer (op_ptr, 4, byte_order));
> + op_ptr += 4;
> + break;
> + case DW_OP_const4s:
> + push (indent, stream,
> + extract_signed_integer (op_ptr, 4, byte_order));
> + op_ptr += 4;
> + break;
> + case DW_OP_const8u:
> + push (indent, stream,
> + extract_unsigned_integer (op_ptr, 8, byte_order));
> + op_ptr += 8;
> + break;
> + case DW_OP_const8s:
> + push (indent, stream,
> + extract_signed_integer (op_ptr, 8, byte_order));
> + op_ptr += 8;
> + break;
> + case DW_OP_constu:
> + op_ptr = safe_read_uleb128 (op_ptr, op_end, &uoffset);
> + push (indent, stream, uoffset);
> + break;
> + case DW_OP_consts:
> + op_ptr = safe_read_sleb128 (op_ptr, op_end, &offset);
> + push (indent, stream, offset);
> + break;
> +
> + case DW_OP_reg0:
> + case DW_OP_reg1:
> + case DW_OP_reg2:
> + case DW_OP_reg3:
> + case DW_OP_reg4:
> + case DW_OP_reg5:
> + case DW_OP_reg6:
> + case DW_OP_reg7:
> + case DW_OP_reg8:
> + case DW_OP_reg9:
> + case DW_OP_reg10:
> + case DW_OP_reg11:
> + case DW_OP_reg12:
> + case DW_OP_reg13:
> + case DW_OP_reg14:
> + case DW_OP_reg15:
> + case DW_OP_reg16:
> + case DW_OP_reg17:
> + case DW_OP_reg18:
> + case DW_OP_reg19:
> + case DW_OP_reg20:
> + case DW_OP_reg21:
> + case DW_OP_reg22:
> + case DW_OP_reg23:
> + case DW_OP_reg24:
> + case DW_OP_reg25:
> + case DW_OP_reg26:
> + case DW_OP_reg27:
> + case DW_OP_reg28:
> + case DW_OP_reg29:
> + case DW_OP_reg30:
> + case DW_OP_reg31:
> + dwarf_expr_require_composition (op_ptr, op_end, "DW_OP_regx");
> + pushf_register_address (indent, stream, registers_used, arch,
> + dwarf2_reg_to_regnum_or_error (arch,
> + op - DW_OP_reg0));
> + break;
> +
> + case DW_OP_regx:
> + op_ptr = safe_read_uleb128 (op_ptr, op_end, ®);
> + dwarf_expr_require_composition (op_ptr, op_end, "DW_OP_regx");
> + pushf_register_address (indent, stream, registers_used, arch,
> + dwarf2_reg_to_regnum_or_error (arch, reg));
> + break;
> +
> + case DW_OP_breg0:
> + case DW_OP_breg1:
> + case DW_OP_breg2:
> + case DW_OP_breg3:
> + case DW_OP_breg4:
> + case DW_OP_breg5:
> + case DW_OP_breg6:
> + case DW_OP_breg7:
> + case DW_OP_breg8:
> + case DW_OP_breg9:
> + case DW_OP_breg10:
> + case DW_OP_breg11:
> + case DW_OP_breg12:
> + case DW_OP_breg13:
> + case DW_OP_breg14:
> + case DW_OP_breg15:
> + case DW_OP_breg16:
> + case DW_OP_breg17:
> + case DW_OP_breg18:
> + case DW_OP_breg19:
> + case DW_OP_breg20:
> + case DW_OP_breg21:
> + case DW_OP_breg22:
> + case DW_OP_breg23:
> + case DW_OP_breg24:
> + case DW_OP_breg25:
> + case DW_OP_breg26:
> + case DW_OP_breg27:
> + case DW_OP_breg28:
> + case DW_OP_breg29:
> + case DW_OP_breg30:
> + case DW_OP_breg31:
> + op_ptr = safe_read_sleb128 (op_ptr, op_end, &offset);
> + pushf_register (indent, stream, registers_used, arch,
> + dwarf2_reg_to_regnum_or_error (arch,
> + op - DW_OP_breg0),
> + offset);
> + break;
> + case DW_OP_bregx:
> + {
> + op_ptr = safe_read_uleb128 (op_ptr, op_end, ®);
> + op_ptr = safe_read_sleb128 (op_ptr, op_end, &offset);
> + pushf_register (indent, stream, registers_used, arch,
> + dwarf2_reg_to_regnum_or_error (arch, reg), offset);
> + }
> + break;
> + case DW_OP_fbreg:
> + {
> + const gdb_byte *datastart;
> + size_t datalen;
> + struct block *b;
> + struct symbol *framefunc;
> + char fb_name[50];
> +
> + b = block_for_pc (pc);
> +
> + if (!b)
> + error (_("No block found for address"));
> +
> + framefunc = block_linkage_function (b);
> +
> + if (!framefunc)
> + error (_("No function found for block"));
> +
> + dwarf_expr_frame_base_1 (framefunc, pc, &datastart, &datalen);
> +
> + op_ptr = safe_read_sleb128 (op_ptr, op_end, &offset);
> +
> + /* Generate a unique-enough name, in case the frame base
> + is computed multiple times in this expression. */
> + xsnprintf (fb_name, sizeof (fb_name), "__frame_base_%ld",
> + (long) (op_ptr - base));
> +
> + do_compile_dwarf_expr_to_c (indent, stream,
> + "void *", fb_name,
> + sym, pc,
> + arch, registers_used, addr_size,
> + datastart, datastart + datalen,
> + NULL, per_cu);
> +
> + pushf (indent, stream, "%s + %s", fb_name, hex_string (offset));
> + }
> + break;
> +
> + case DW_OP_dup:
> + pushf (indent, stream, "__gdb_stack[__gdb_tos]");
> + break;
> +
> + case DW_OP_drop:
> + fprintfi_filtered (indent, stream, "--__gdb_tos;\n");
> + break;
> +
> + case DW_OP_pick:
> + offset = *op_ptr++;
> + pushf (indent, stream, "__gdb_stack[__gdb_tos - %d]", offset);
> + break;
> +
> + case DW_OP_swap:
> + fprintfi_filtered (indent, stream,
> + "__gdb_tmp = __gdb_stack[__gdb_tos - 1];\n");
> + fprintfi_filtered (indent, stream,
> + "__gdb_stack[__gdb_tos - 1] = "
> + "__gdb_stack[__gdb_tos];\n");
> + fprintfi_filtered (indent, stream, ("__gdb_stack[__gdb_tos] = "
> + "__gdb_tmp;\n"));
> + break;
> +
> + case DW_OP_over:
> + pushf (indent, stream, "__gdb_stack[__gdb_tos - 1]");
> + break;
> +
> + case DW_OP_rot:
> + fprintfi_filtered (indent, stream, ("__gdb_tmp = "
> + "__gdb_stack[__gdb_tos];\n"));
> + fprintfi_filtered (indent, stream,
> + "__gdb_stack[__gdb_tos] = "
> + "__gdb_stack[__gdb_tos - 1];\n");
> + fprintfi_filtered (indent, stream,
> + "__gdb_stack[__gdb_tos - 1] = "
> + "__gdb_stack[__gdb_tos -2];\n");
> + fprintfi_filtered (indent, stream, "__gdb_stack[__gdb_tos - 2] = "
> + "__gdb_tmp;\n");
> + break;
> +
> + case DW_OP_deref:
> + case DW_OP_deref_size:
> + {
> + int size;
> + const char *mode;
> +
> + if (op == DW_OP_deref_size)
> + size = *op_ptr++;
> + else
> + size = addr_size;
> +
> + mode = c_get_mode_for_size (size);
> + if (mode == NULL)
> + error (_("Unsupported size %d in %s"),
> + size, get_DW_OP_name (op));
> +
> + /* Cast to a pointer of the desired type, then
> + dereference. */
> + fprintfi_filtered (indent, stream,
> + "__gdb_stack[__gdb_tos] = "
> + "*((__gdb_int_%s *) "
> + "__gdb_stack[__gdb_tos]);\n",
> + mode);
> + }
> + break;
> +
> + case DW_OP_abs:
> + unary (indent, stream,
> + "((" GCC_INTPTR ") __gdb_stack[__gdb_tos]) < 0 ? "
> + "-__gdb_stack[__gdb_tos] : __gdb_stack[__gdb_tos]");
> + break;
> +
> + case DW_OP_neg:
> + unary (indent, stream, "-__gdb_stack[__gdb_tos]");
> + break;
> +
> + case DW_OP_not:
> + unary (indent, stream, "~__gdb_stack[__gdb_tos]");
> + break;
> +
> + case DW_OP_plus_uconst:
> + op_ptr = safe_read_uleb128 (op_ptr, op_end, ®);
> + unary (indent, stream, "__gdb_stack[__gdb_tos] + %s",
> + hex_string (reg));
> + break;
> +
> + case DW_OP_div:
> + binary (indent, stream, ("((" GCC_INTPTR
> + ") __gdb_stack[__gdb_tos-1]) / (("
> + GCC_INTPTR ") __gdb_stack[__gdb_tos])"));
> + break;
> +
> + case DW_OP_shra:
> + binary (indent, stream,
> + "((" GCC_INTPTR ") __gdb_stack[__gdb_tos-1]) >> "
> + "__gdb_stack[__gdb_tos]");
> + break;
> +
> +#define BINARY(OP) \
> + binary (indent, stream, ("__gdb_stack[__gdb_tos-1] " #OP \
> + " __gdb_stack[__gdb_tos]")); \
> + break
> +
> + case DW_OP_and:
> + BINARY (&);
> + case DW_OP_minus:
> + BINARY (-);
> + case DW_OP_mod:
> + BINARY (%);
> + case DW_OP_mul:
> + BINARY (*);
> + case DW_OP_or:
> + BINARY (|);
> + case DW_OP_plus:
> + BINARY (+);
> + case DW_OP_shl:
> + BINARY (<<);
> + case DW_OP_shr:
> + BINARY (>>);
> + case DW_OP_xor:
> + BINARY (^);
> +#undef BINARY
> +
> +#define COMPARE(OP) \
> + binary (indent, stream, \
> + "(((" GCC_INTPTR ") __gdb_stack[__gdb_tos-1]) " #OP \
> + " ((" GCC_INTPTR \
> + ") __gdb_stack[__gdb_tos]))"); \
> + break
> +
> + case DW_OP_le:
> + COMPARE (<=);
> + case DW_OP_ge:
> + COMPARE (>=);
> + case DW_OP_eq:
> + COMPARE (==);
> + case DW_OP_lt:
> + COMPARE (<);
> + case DW_OP_gt:
> + COMPARE (>);
> + case DW_OP_ne:
> + COMPARE (!=);
> +#undef COMPARE
> +
> + case DW_OP_call_frame_cfa:
> + {
> + int regnum;
> + CORE_ADDR text_offset;
> + LONGEST off;
> + const gdb_byte *cfa_start, *cfa_end;
> +
> + if (dwarf2_fetch_cfa_info (arch, pc, per_cu,
> + ®num, &off,
> + &text_offset, &cfa_start, &cfa_end))
> + {
> + /* Register. */
> + pushf_register (indent, stream, registers_used, arch, regnum,
> + off);
> + }
> + else
> + {
> + /* Another expression. */
> + char cfa_name[50];
> +
> + /* Generate a unique-enough name, in case the CFA is
> + computed multiple times in this expression. */
> + xsnprintf (cfa_name, sizeof (cfa_name),
> + "__cfa_%ld", (long) (op_ptr - base));
> +
> + do_compile_dwarf_expr_to_c (indent, stream,
> + "void *", cfa_name,
> + sym, pc, arch, registers_used,
> + addr_size,
> + cfa_start, cfa_end,
> + &text_offset, per_cu);
> + pushf (indent, stream, cfa_name);
> + }
> + }
> +
> + break;
> +
> + case DW_OP_skip:
> + offset = extract_signed_integer (op_ptr, 2, byte_order);
> + op_ptr += 2;
> + fprintfi_filtered (indent, stream, "goto ");
> + print_label (stream, scope, op_ptr + offset - base);
> + fprintf_filtered (stream, ";\n");
> + break;
> +
> + case DW_OP_bra:
> + offset = extract_signed_integer (op_ptr, 2, byte_order);
> + op_ptr += 2;
> + fprintfi_filtered (indent, stream,
> + "if ((( " GCC_INTPTR
> + ") __gdb_stack[__gdb_tos--]) != 0) goto ");
> + print_label (stream, scope, op_ptr + offset - base);
> + fprintf_filtered (stream, ";\n");
> + break;
> +
> + case DW_OP_nop:
> + break;
> +
> + default:
> + error (_("unhandled DWARF op: %s"), get_DW_OP_name (op));
> + }
> + }
> +
> + fprintfi_filtered (indent, stream, "%s = (%s) __gdb_stack[__gdb_tos];\n",
> + result_name, type_name);
> + fprintfi_filtered (indent - 2, stream, "}\n");
> +
> + do_cleanups (cleanup);
> +}
> +
> +/* See compile.h. */
> +
> +void
> +compile_dwarf_expr_to_c (struct ui_file *stream, const char *result_name,
> + struct symbol *sym, CORE_ADDR pc,
> + struct gdbarch *arch, unsigned char *registers_used,
> + unsigned int addr_size,
> + const gdb_byte *op_ptr, const gdb_byte *op_end,
> + struct dwarf2_per_cu_data *per_cu)
> +{
> + do_compile_dwarf_expr_to_c (2, stream, "void *", result_name, sym, pc,
> + arch, registers_used, addr_size, op_ptr, op_end,
> + NULL, per_cu);
> +}
> +
> +/* See compile.h. */
> +
> +void
> +compile_dwarf_bounds_to_c (struct ui_file *stream,
> + const char *result_name,
> + const struct dynamic_prop *prop,
> + struct symbol *sym, CORE_ADDR pc,
> + struct gdbarch *arch, unsigned char *registers_used,
> + unsigned int addr_size,
> + const gdb_byte *op_ptr, const gdb_byte *op_end,
> + struct dwarf2_per_cu_data *per_cu)
> +{
> + do_compile_dwarf_expr_to_c (2, stream, "unsigned long ", result_name,
> + sym, pc, arch, registers_used,
> + addr_size, op_ptr, op_end, NULL, per_cu);
> +}
> diff --git a/gdb/compile/compile-object-load.c b/gdb/compile/compile-object-load.c
> new file mode 100644
> index 0000000..abf5b43
> --- /dev/null
> +++ b/gdb/compile/compile-object-load.c
> @@ -0,0 +1,570 @@
> +/* Load module for 'compile' command.
> +
> + Copyright (C) 2014 Free Software Foundation, Inc.
> +
> + This file is part of GDB.
> +
> + This program is free software; you can redistribute it and/or modify
> + it under the terms of the GNU General Public License as published by
> + the Free Software Foundation; either version 3 of the License, or
> + (at your option) any later version.
> +
> + This program is distributed in the hope that it will be useful,
> + but WITHOUT ANY WARRANTY; without even the implied warranty of
> + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + GNU General Public License for more details.
> +
> + You should have received a copy of the GNU General Public License
> + along with this program. If not, see <http://www.gnu.org/licenses/>. */
> +
> +#include "defs.h"
> +#include "compile-object-load.h"
> +#include "compile-internal.h"
> +#include "command.h"
> +#include "objfiles.h"
> +#include "gdbcore.h"
> +#include "readline/tilde.h"
> +#include "bfdlink.h"
> +#include "gdbcmd.h"
> +#include "regcache.h"
> +#include "inferior.h"
> +#include "compile.h"
> +
> +/* Helper data for setup_sections. */
> +
> +struct setup_sections_data
> +{
> + /* Size of all recent sections with matching LAST_PROT. */
> + CORE_ADDR last_size;
> +
> + /* First section matching LAST_PROT. */
> + asection *last_section_first;
> +
> + /* Memory protection like the prot parameter of gdbarch_infcall_mmap. */
> + unsigned last_prot;
> +
> + /* Maximum of alignments of all sections matching LAST_PROT.
> + This value is always at least 1. This value is always a power of 2. */
> + CORE_ADDR last_max_alignment;
> +};
> +
> +/* Place all ABFD sections next to each other obeying all constraints. */
> +
> +static void
> +setup_sections (bfd *abfd, asection *sect, void *data_voidp)
> +{
> + struct setup_sections_data *data = data_voidp;
> + CORE_ADDR alignment;
> + unsigned prot;
> +
> + if (sect != NULL)
> + {
> + /* It is required by later bfd_get_relocated_section_contents. */
> + if (sect->output_section == NULL)
> + sect->output_section = sect;
> +
> + if ((bfd_get_section_flags (abfd, sect) & SEC_ALLOC) == 0)
> + return;
> +
> + // Make the memory always readable.
> + prot = 4;
> + if ((bfd_get_section_flags (abfd, sect) & SEC_READONLY) == 0)
> + prot |= 2;
> + if ((bfd_get_section_flags (abfd, sect) & SEC_CODE) != 0)
> + prot |= 1;
> +
> + if (compile_debug)
> + fprintf_unfiltered (gdb_stdout,
> + "module \"%s\" section \"%s\" size %s prot %u\n",
> + bfd_get_filename (abfd),
> + bfd_get_section_name (abfd, sect),
> + paddress (target_gdbarch (),
> + bfd_get_section_size (sect)),
> + prot);
> + }
> + else
> + prot = -1;
> +
> + if (sect == NULL
> + || (data->last_prot != prot && bfd_get_section_size (sect) != 0))
> + {
> + CORE_ADDR addr;
> + asection *sect_iter;
> +
> + if (data->last_size != 0)
> + {
> + addr = gdbarch_infcall_mmap (target_gdbarch (), data->last_size,
> + data->last_prot);
> + if (compile_debug)
> + fprintf_unfiltered (gdb_stdout,
> + "allocated %s bytes at %s prot %u\n",
> + paddress (target_gdbarch (), data->last_size),
> + paddress (target_gdbarch (), addr),
> + data->last_prot);
> + }
> + else
> + addr = 0;
> +
> + if ((addr & (data->last_max_alignment - 1)) != 0)
> + error (_("Inferior compiled module address %s "
> + "is not aligned to BFD required %s."),
> + paddress (target_gdbarch (), addr),
> + paddress (target_gdbarch (), data->last_max_alignment));
> +
> + for (sect_iter = data->last_section_first; sect_iter != sect;
> + sect_iter = sect_iter->next)
> + if ((bfd_get_section_flags (abfd, sect_iter) & SEC_ALLOC) != 0)
> + bfd_set_section_vma (abfd, sect_iter,
> + addr + bfd_get_section_vma (abfd, sect_iter));
> +
> + data->last_size = 0;
> + data->last_section_first = sect;
> + data->last_prot = prot;
> + data->last_max_alignment = 1;
> + }
> +
> + if (sect == NULL)
> + return;
> +
> + alignment = ((CORE_ADDR) 1) << bfd_get_section_alignment (abfd, sect);
> + data->last_max_alignment = max (data->last_max_alignment, alignment);
> +
> + data->last_size = (data->last_size + alignment - 1) & -alignment;
> +
> + bfd_set_section_vma (abfd, sect, data->last_size);
> +
> + data->last_size += bfd_get_section_size (sect);
> + data->last_size = (data->last_size + alignment - 1) & -alignment;
> +}
> +
> +/* Helper for link_callbacks callbacks vector. */
> +
> +static bfd_boolean
> +link_callbacks_multiple_definition (struct bfd_link_info *link_info,
> + struct bfd_link_hash_entry *h, bfd *nbfd,
> + asection *nsec, bfd_vma nval)
> +{
> + bfd *abfd = link_info->input_bfds;
> +
> + if (link_info->allow_multiple_definition)
> + return TRUE;
> + warning (_("Compiled module \"%s\": multiple symbol definitions: %s\n"),
> + bfd_get_filename (abfd), h->root.string);
> + return FALSE;
> +}
> +
> +/* Helper for link_callbacks callbacks vector. */
> +
> +static bfd_boolean
> +link_callbacks_warning (struct bfd_link_info *link_info, const char *xwarning,
> + const char *symbol, bfd *abfd, asection *section,
> + bfd_vma address)
> +{
> + warning (_("Compiled module \"%s\" section \"%s\": warning: %s\n"),
> + bfd_get_filename (abfd), bfd_get_section_name (abfd, section),
> + xwarning);
> + /* Maybe permit running as a module? */
> + return FALSE;
> +}
> +
> +/* Helper for link_callbacks callbacks vector. */
> +
> +static bfd_boolean
> +link_callbacks_undefined_symbol (struct bfd_link_info *link_info,
> + const char *name, bfd *abfd, asection *section,
> + bfd_vma address, bfd_boolean is_fatal)
> +{
> + warning (_("Cannot resolve relocation to \"%s\" "
> + "from compiled module \"%s\" section \"%s\"."),
> + name, bfd_get_filename (abfd), bfd_get_section_name (abfd, section));
> + return FALSE;
> +}
> +
> +/* Helper for link_callbacks callbacks vector. */
> +
> +static bfd_boolean
> +link_callbacks_reloc_overflow (struct bfd_link_info *link_info,
> + struct bfd_link_hash_entry *entry,
> + const char *name, const char *reloc_name,
> + bfd_vma addend, bfd *abfd, asection *section,
> + bfd_vma address)
> +{
> + /* TRUE is required for intra-module relocations. */
> + return TRUE;
> +}
> +
> +/* Helper for link_callbacks callbacks vector. */
> +
> +static bfd_boolean
> +link_callbacks_reloc_dangerous (struct bfd_link_info *link_info,
> + const char *message, bfd *abfd,
> + asection *section, bfd_vma address)
> +{
> + warning (_("Compiled module \"%s\" section \"%s\": dangerous "
> + "relocation: %s\n"),
> + bfd_get_filename (abfd), bfd_get_section_name (abfd, section),
> + message);
> + return FALSE;
> +}
> +
> +/* Helper for link_callbacks callbacks vector. */
> +
> +static bfd_boolean
> +link_callbacks_unattached_reloc (struct bfd_link_info *link_info,
> + const char *name, bfd *abfd, asection *section,
> + bfd_vma address)
> +{
> + warning (_("Compiled module \"%s\" section \"%s\": unattached "
> + "relocation: %s\n"),
> + bfd_get_filename (abfd), bfd_get_section_name (abfd, section),
> + name);
> + return FALSE;
> +}
> +
> +/* Helper for link_callbacks callbacks vector. */
> +
> +static void
> +link_callbacks_einfo (const char *fmt, ...)
> +{
> + struct cleanup *cleanups;
> + va_list ap;
> + char *str;
> +
> + va_start (ap, fmt);
> + str = xstrvprintf (fmt, ap);
> + va_end (ap);
> + cleanups = make_cleanup (xfree, str);
> +
> + warning (_("Compile module: warning: %s\n"), str);
> +
> + do_cleanups (cleanups);
> +}
> +
> +/* Helper for bfd_get_relocated_section_contents.
> + Only these symbols are set by bfd_simple_get_relocated_section_contents
> + but bfd/ seems to use even the NULL ones without checking them first. */
> +
> +static const struct bfd_link_callbacks link_callbacks =
> +{
> + NULL, /* add_archive_element */
> + link_callbacks_multiple_definition, /* multiple_definition */
> + NULL, /* multiple_common */
> + NULL, /* add_to_set */
> + NULL, /* constructor */
> + link_callbacks_warning, /* warning */
> + link_callbacks_undefined_symbol, /* undefined_symbol */
> + link_callbacks_reloc_overflow, /* reloc_overflow */
> + link_callbacks_reloc_dangerous, /* reloc_dangerous */
> + link_callbacks_unattached_reloc, /* unattached_reloc */
> + NULL, /* notice */
> + link_callbacks_einfo, /* einfo */
> + NULL, /* info */
> + NULL, /* minfo */
> + NULL, /* override_segment_assignment */
> +};
> +
> +/* Cleanup callback for struct bfd_link_info. */
> +
> +static void
> +link_hash_table_free (void *data)
> +{
> + struct bfd_link_info *link_info = data;
> + bfd *abfd = link_info->input_bfds;
> +
> + bfd_link_hash_table_free (abfd, link_info->hash);
> +}
> +
> +/* Relocate and store into inferior memory each section SECT of ABFD. */
> +
> +static void
> +copy_sections (bfd *abfd, asection *sect, void *data)
> +{
> + asymbol **symbol_table = data;
> + bfd_byte *sect_data, *sect_data_got;
> + struct cleanup *cleanups;
> + struct bfd_link_info link_info;
> + struct bfd_link_order link_order;
> + CORE_ADDR inferior_addr;
> +
> + if ((bfd_get_section_flags (abfd, sect) & (SEC_ALLOC | SEC_LOAD))
> + != (SEC_ALLOC | SEC_LOAD))
> + return;
> +
> + if (bfd_get_section_size (sect) == 0)
> + return;
> +
> + /* Mostly a copy of bfd_simple_get_relocated_section_contents which GDB
> + cannot use as it does not report relocations to undefined symbols. */
> + memset (&link_info, 0, sizeof (link_info));
> + link_info.output_bfd = abfd;
> + link_info.input_bfds = abfd;
> + link_info.input_bfds_tail = &abfd->link_next;
> + link_info.hash = bfd_link_hash_table_create (abfd);
> + cleanups = make_cleanup (link_hash_table_free, &link_info);
> + link_info.callbacks = &link_callbacks;
> + memset (&link_order, 0, sizeof (link_order));
> + link_order.next = NULL;
> + link_order.type = bfd_indirect_link_order;
> + link_order.offset = 0;
> + link_order.size = bfd_get_section_size (sect);
> + link_order.u.indirect.section = sect;
> +
> + sect_data = xmalloc (bfd_get_section_size (sect));
> + make_cleanup (xfree, sect_data);
> +
> + sect_data_got = bfd_get_relocated_section_contents (abfd, &link_info,
> + &link_order, sect_data,
> + FALSE, symbol_table);
> + if (sect_data_got == NULL)
> + error (_("Cannot map compiled module \"%s\" section \"%s\": %s"),
> + bfd_get_filename (abfd), bfd_get_section_name (abfd, sect),
> + bfd_errmsg (bfd_get_error ()));
> + gdb_assert (sect_data_got == sect_data);
> +
> + inferior_addr = bfd_get_section_vma (abfd, sect);
> + if (0 != target_write_memory (inferior_addr, sect_data,
> + bfd_get_section_size (sect)))
> + error (_("Cannot write compiled module \"%s\" section \"%s\" "
> + "to inferior memory range %s-%s."),
> + bfd_get_filename (abfd), bfd_get_section_name (abfd, sect),
> + paddress (target_gdbarch (), inferior_addr),
> + paddress (target_gdbarch (),
> + inferior_addr + bfd_get_section_size (sect)));
> +
> + do_cleanups (cleanups);
> +}
> +
> +/* Fetch the type of first parameter of GCC_FE_WRAPPER_FUNCTION.
> + Return NULL if GCC_FE_WRAPPER_FUNCTION has no parameters.
> + Throw an error otherwise. */
> +
> +static struct type *
> +get_regs_type (struct objfile *objfile)
> +{
> + struct symbol *func_sym;
> + struct type *func_type, *regsp_type, *regs_type;
> +
> + func_sym = lookup_global_symbol_from_objfile (objfile,
> + GCC_FE_WRAPPER_FUNCTION,
> + VAR_DOMAIN);
> + if (func_sym == NULL)
> + error (_("Cannot find function \"%s\" in compiled module \"%s\"."),
> + GCC_FE_WRAPPER_FUNCTION, objfile_name (objfile));
> +
> + func_type = SYMBOL_TYPE (func_sym);
> + if (TYPE_CODE (func_type) != TYPE_CODE_FUNC)
> + error (_("Invalid type code %d of function \"%s\" in compiled "
> + "module \"%s\"."),
> + TYPE_CODE (func_type), GCC_FE_WRAPPER_FUNCTION,
> + objfile_name (objfile));
> +
> + /* No register parameter present. */
> + if (TYPE_NFIELDS (func_type) == 0)
> + return NULL;
> +
> + if (TYPE_NFIELDS (func_type) != 1)
> + error (_("Invalid %d parameters of function \"%s\" in compiled "
> + "module \"%s\"."),
> + TYPE_NFIELDS (func_type), GCC_FE_WRAPPER_FUNCTION,
> + objfile_name (objfile));
> +
> + regsp_type = check_typedef (TYPE_FIELD_TYPE (func_type, 0));
> + if (TYPE_CODE (regsp_type) != TYPE_CODE_PTR)
> + error (_("Invalid type code %d of first parameter of function \"%s\" "
> + "in compiled module \"%s\"."),
> + TYPE_CODE (regsp_type), GCC_FE_WRAPPER_FUNCTION,
> + objfile_name (objfile));
> +
> + regs_type = check_typedef (TYPE_TARGET_TYPE (regsp_type));
> + if (TYPE_CODE (regs_type) != TYPE_CODE_STRUCT)
> + error (_("Invalid type code %d of dereferenced first parameter "
> + "of function \"%s\" in compiled module \"%s\"."),
> + TYPE_CODE (regs_type), GCC_FE_WRAPPER_FUNCTION,
> + objfile_name (objfile));
> +
> + return regs_type;
> +}
> +
> +/* Store all inferior registers required by REGS_TYPE to inferior memory
> + starting at inferior address REGS_BASE. */
> +
> +static void
> +store_regs (struct type *regs_type, CORE_ADDR regs_base)
> +{
> + struct gdbarch *gdbarch = target_gdbarch ();
> + struct regcache *regcache = get_thread_regcache (inferior_ptid);
> + int fieldno;
> +
> + for (fieldno = 0; fieldno < TYPE_NFIELDS (regs_type); fieldno++)
> + {
> + const char *reg_name = TYPE_FIELD_NAME (regs_type, fieldno);
> + ULONGEST reg_bitpos = TYPE_FIELD_BITPOS (regs_type, fieldno);
> + ULONGEST reg_bitsize = TYPE_FIELD_BITSIZE (regs_type, fieldno);
> + ULONGEST reg_offset;
> + struct type *reg_type = check_typedef (TYPE_FIELD_TYPE (regs_type,
> + fieldno));
> + ULONGEST reg_size = TYPE_LENGTH (reg_type);
> + int regnum;
> + struct value *regval;
> + CORE_ADDR inferior_addr;
> +
> + if (strcmp (reg_name, COMPILE_I_SIMPLE_REGISTER_DUMMY) == 0)
> + continue;
> +
> + if ((reg_bitpos % 8) != 0 || reg_bitsize != 0)
> + error (_("Invalid register \"%s\" position %s bits or size %s bits"),
> + reg_name, pulongest (reg_bitpos), pulongest (reg_bitsize));
> + reg_offset = reg_bitpos / 8;
> +
> + if (TYPE_CODE (reg_type) != TYPE_CODE_INT
> + && TYPE_CODE (reg_type) != TYPE_CODE_PTR)
> + error (_("Invalid register \"%s\" type code %d"), reg_name,
> + TYPE_CODE (reg_type));
> +
> + regnum = compile_register_name_demangle (gdbarch, reg_name);
> +
> + regval = value_from_register (reg_type, regnum, get_current_frame ());
> + if (value_optimized_out (regval))
> + error (_("Register \"%s\" is optimized out."), reg_name);
> + if (!value_entirely_available (regval))
> + error (_("Register \"%s\" is not available."), reg_name);
> +
> + inferior_addr = regs_base + reg_offset;
> + if (0 != target_write_memory (inferior_addr, value_contents (regval),
> + reg_size))
> + error (_("Cannot write register \"%s\" to inferior memory at %s."),
> + reg_name, paddress (gdbarch, inferior_addr));
> + }
> +}
> +
> +/* Load OBJECT_FILE into inferior memory. Throw an error otherwise.
> + Caller must fully dispose the return value by calling compile_object_run.
> + SOURCE_FILE's copy is stored into the returned object.
> + Caller should free both OBJECT_FILE and SOURCE_FILE immediatelly after this
> + function returns. */
> +
> +struct compile_module *
> +compile_object_load (const char *object_file, const char *source_file)
> +{
> + struct cleanup *cleanups, *cleanups_free_objfile;
> + bfd *abfd;
> + struct setup_sections_data setup_sections_data;
> + CORE_ADDR addr, func_addr, regs_addr;
> + struct bound_minimal_symbol bmsym;
> + long storage_needed;
> + asymbol **symbol_table, **symp;
> + long number_of_symbols, missing_symbols;
> + struct type *dptr_type = builtin_type (target_gdbarch ())->builtin_data_ptr;
> + unsigned dptr_type_len = TYPE_LENGTH (dptr_type);
> + struct compile_module *retval;
> + struct type *regs_type;
> + char *filename, **matching;
> + struct objfile *objfile;
> +
> + filename = tilde_expand (object_file);
> + cleanups = make_cleanup (xfree, filename);
> +
> + abfd = gdb_bfd_open (filename, gnutarget, -1);
> + if (abfd == NULL)
> + error (_("\"%s\": could not open as compiled module: %s"),
> + filename, bfd_errmsg (bfd_get_error ()));
> + make_cleanup_bfd_unref (abfd);
> +
> + if (!bfd_check_format_matches (abfd, bfd_object, &matching))
> + error (_("\"%s\": not in loadable format: %s"),
> + filename, gdb_bfd_errmsg (bfd_get_error (), matching));
> +
> + if ((bfd_get_file_flags (abfd) & (EXEC_P | DYNAMIC)) != 0)
> + error (_("\"%s\": not in object format."), filename);
> +
> + setup_sections_data.last_size = 0;
> + setup_sections_data.last_section_first = abfd->sections;
> + setup_sections_data.last_prot = -1;
> + setup_sections_data.last_max_alignment = 1;
> + bfd_map_over_sections (abfd, setup_sections, &setup_sections_data);
> + setup_sections (abfd, NULL, &setup_sections_data);
> +
> + storage_needed = bfd_get_symtab_upper_bound (abfd);
> + if (storage_needed < 0)
> + error (_("Cannot read symbols of compiled module \"%s\": %s"),
> + filename, bfd_errmsg (bfd_get_error ()));
> +
> + /* SYMFILE_VERBOSE is not passed even if FROM_TTY, user is not interested in
> + "Reading symbols from ..." message for automatically generated file. */
> + objfile = symbol_file_add_from_bfd (abfd, filename, 0, NULL, 0, NULL);
> + cleanups_free_objfile = make_cleanup_free_objfile (objfile);
> +
> + bmsym = lookup_minimal_symbol_text (GCC_FE_WRAPPER_FUNCTION, objfile);
> + if (bmsym.minsym == NULL || MSYMBOL_TYPE (bmsym.minsym) == mst_file_text)
> + error (_("Could not find symbol \"%s\" of compiled module \"%s\"."),
> + GCC_FE_WRAPPER_FUNCTION, filename);
> + func_addr = BMSYMBOL_VALUE_ADDRESS (bmsym);
> +
> + /* The memory may be later needed
> + by bfd_generic_get_relocated_section_contents
> + called from default_symfile_relocate. */
> + symbol_table = obstack_alloc (&objfile->objfile_obstack, storage_needed);
> + number_of_symbols = bfd_canonicalize_symtab (abfd, symbol_table);
> + if (number_of_symbols < 0)
> + error (_("Cannot parse symbols of compiled module \"%s\": %s"),
> + filename, bfd_errmsg (bfd_get_error ()));
> +
> + missing_symbols = 0;
> + for (symp = symbol_table; symp < symbol_table + number_of_symbols; symp++)
> + {
> + asymbol *sym = *symp;
> +
> + if (sym->flags != 0)
> + continue;
> + if (compile_debug)
> + fprintf_unfiltered (gdb_stdout,
> + "lookup undefined ELF symbol \"%s\"\n",
> + sym->name);
> + sym->flags = BSF_GLOBAL;
> + sym->section = bfd_abs_section_ptr;
> + if (strcmp (sym->name, "_GLOBAL_OFFSET_TABLE_") == 0)
> + {
> + sym->value = 0;
> + continue;
> + }
> + bmsym = lookup_minimal_symbol (sym->name, NULL, NULL);
> + switch (bmsym.minsym == NULL
> + ? mst_unknown : MSYMBOL_TYPE (bmsym.minsym))
> + {
> + case mst_text:
> + sym->value = BMSYMBOL_VALUE_ADDRESS (bmsym);
> + break;
> + default:
> + warning (_("Could not find symbol \"%s\" "
> + "for compiled module \"%s\"."),
> + sym->name, filename);
> + missing_symbols++;
> + }
> + }
> + if (missing_symbols)
> + error (_("%ld symbols were missing, cannot continue."), missing_symbols);
> +
> + bfd_map_over_sections (abfd, copy_sections, symbol_table);
> +
> + regs_type = get_regs_type (objfile);
> + if (regs_type == NULL)
> + regs_addr = 0;
> + else
> + {
> + /* Use read-only non-executable memory protection. */
> + regs_addr = gdbarch_infcall_mmap (target_gdbarch (),
> + TYPE_LENGTH (regs_type), 4);
> + gdb_assert (regs_addr != 0);
> + store_regs (regs_type, regs_addr);
> + }
> +
> + discard_cleanups (cleanups_free_objfile);
> + do_cleanups (cleanups);
> +
> + retval = xmalloc (sizeof (*retval));
> + retval->objfile = objfile;
> + retval->source_file = xstrdup (source_file);
> + retval->func_addr = func_addr;
> + retval->regs_addr = regs_addr;
> + return retval;
> +}
> diff --git a/gdb/compile/compile-object-load.h b/gdb/compile/compile-object-load.h
> new file mode 100644
> index 0000000..850111e
> --- /dev/null
> +++ b/gdb/compile/compile-object-load.h
> @@ -0,0 +1,39 @@
> +/* Header file to load module for 'compile' command.
> + Copyright (C) 2014 Free Software Foundation, Inc.
> +
> + This program is free software; you can redistribute it and/or modify
> + it under the terms of the GNU General Public License as published by
> + the Free Software Foundation; either version 3 of the License, or
> + (at your option) any later version.
> +
> + This program is distributed in the hope that it will be useful,
> + but WITHOUT ANY WARRANTY; without even the implied warranty of
> + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + GNU General Public License for more details.
> +
> + You should have received a copy of the GNU General Public License
> + along with this program. If not, see <http://www.gnu.org/licenses/>. */
> +
> +#ifndef GDB_COMPILE_OBJECT_LOAD_H
> +#define GDB_COMPILE_OBJECT_LOAD_H
> +
> +struct compile_module
> +{
> + /* objfile for the compiled module. */
> + struct objfile *objfile;
> +
> + /* .c file OBJFILE was built from. It needs to be xfree-d. */
> + char *source_file;
> +
> + /* Inferior function address. */
> + CORE_ADDR func_addr;
> +
> + /* Inferior registers address or NULL if the inferior function does not
> + require any. */
> + CORE_ADDR regs_addr;
> +};
> +
> +extern struct compile_module *compile_object_load (const char *object_file,
> + const char *source_file);
> +
> +#endif /* GDB_COMPILE_OBJECT_LOAD_H */
> diff --git a/gdb/compile/compile-object-run.c b/gdb/compile/compile-object-run.c
> new file mode 100644
> index 0000000..b7c4c4d
> --- /dev/null
> +++ b/gdb/compile/compile-object-run.c
> @@ -0,0 +1,138 @@
> +/* Call module for 'compile' command.
> +
> + Copyright (C) 2014 Free Software Foundation, Inc.
> +
> + This file is part of GDB.
> +
> + This program is free software; you can redistribute it and/or modify
> + it under the terms of the GNU General Public License as published by
> + the Free Software Foundation; either version 3 of the License, or
> + (at your option) any later version.
> +
> + This program is distributed in the hope that it will be useful,
> + but WITHOUT ANY WARRANTY; without even the implied warranty of
> + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + GNU General Public License for more details.
> +
> + You should have received a copy of the GNU General Public License
> + along with this program. If not, see <http://www.gnu.org/licenses/>. */
> +
> +#include "defs.h"
> +#include "compile-object-run.h"
> +#include "value.h"
> +#include "infcall.h"
> +#include "objfiles.h"
> +#include "compile-internal.h"
> +#include "dummy-frame.h"
> +
> +/* Helper for do_module_cleanup. */
> +
> +struct do_module_cleanup
> +{
> + /* Boolean to set true upon a call of do_module_cleanup.
> + The pointer may be NULL. */
> + int *executedp;
> +
> + /* .c file OBJFILE was built from. It needs to be xfree-d. */
> + char *source_file;
> +
> + /* objfile_name of our objfile. */
> + char objfile_name_string[1];
> +};
> +
> +/* Cleanup everything after the inferior function dummy frame gets
> + discarded. */
> +
> +static dummy_frame_dtor_ftype do_module_cleanup;
> +static void
> +do_module_cleanup (void *arg)
> +{
> + struct do_module_cleanup *data = arg;
> + struct objfile *objfile;
> +
> + if (data->executedp != NULL)
> + *data->executedp = 1;
> +
> + ALL_OBJFILES (objfile)
> + if ((objfile->flags & OBJF_USERLOADED) == 0
> + && (strcmp (objfile_name (objfile), data->objfile_name_string) == 0))
> + {
> + free_objfile (objfile);
> +
> + /* It may be a bit too pervasive in this dummy_frame dtor callback. */
> + clear_symtab_users (0);
> +
> + break;
> + }
> +
> + /* Delete the .c file. */
> + unlink (data->source_file);
> + xfree (data->source_file);
> +
> + /* Delete the .o file. */
> + unlink (data->objfile_name_string);
> + xfree (data);
> +}
> +
> +/* 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.
> + Thrown errors and left MODULE files are unrelated events. Caller must no
> + longer touch MODULE's memory after this function has been called. */
> +
> +void
> +compile_object_run (struct compile_module *module)
> +{
> + struct value *func_val;
> + struct frame_id dummy_id;
> + struct cleanup *cleanups;
> + struct do_module_cleanup *data;
> + volatile struct gdb_exception ex;
> + const char *objfile_name_s = objfile_name (module->objfile);
> + int dtor_found, executed = 0;
> + CORE_ADDR func_addr = module->func_addr;
> + CORE_ADDR regs_addr = module->regs_addr;
> +
> + data = xmalloc (sizeof (*data) + strlen (objfile_name_s));
> + data->executedp = &executed;
> + data->source_file = xstrdup (module->source_file);
> + strcpy (data->objfile_name_string, objfile_name_s);
> +
> + xfree (module->source_file);
> + xfree (module);
> +
> + TRY_CATCH (ex, RETURN_MASK_ERROR)
> + {
> + func_val = value_from_pointer
> + (builtin_type (target_gdbarch ())->builtin_func_ptr,
> + func_addr);
> +
> + if (regs_addr == 0)
> + call_function_by_hand_dummy (func_val, 0, NULL,
> + do_module_cleanup, data);
> + else
> + {
> + struct value *arg_val;
> +
> + arg_val = value_from_pointer
> + (builtin_type (target_gdbarch ())->builtin_func_ptr,
> + regs_addr);
> + call_function_by_hand_dummy (func_val, 1, &arg_val,
> + do_module_cleanup, data);
> + }
> + }
> + dtor_found = find_dummy_frame_dtor (do_module_cleanup, data);
> + if (!executed)
> + data->executedp = NULL;
> + if (ex.reason >= 0)
> + gdb_assert (!dtor_found && executed);
> + else
> + {
> + /* In the case od DTOR_FOUND or in the case of EXECUTED nothing
> + needs to be done. */
> + gdb_assert (!(dtor_found && executed));
> + if (!dtor_found && !executed)
> + do_module_cleanup (data);
> + throw_exception (ex);
> + }
> +}
> diff --git a/gdb/compile/compile-object-run.h b/gdb/compile/compile-object-run.h
> new file mode 100644
> index 0000000..71ba077
> --- /dev/null
> +++ b/gdb/compile/compile-object-run.h
> @@ -0,0 +1,24 @@
> +/* Header file to call module for 'compile' command.
> + Copyright (C) 2014 Free Software Foundation, Inc.
> +
> + This program is free software; you can redistribute it and/or modify
> + it under the terms of the GNU General Public License as published by
> + the Free Software Foundation; either version 3 of the License, or
> + (at your option) any later version.
> +
> + This program is distributed in the hope that it will be useful,
> + but WITHOUT ANY WARRANTY; without even the implied warranty of
> + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + GNU General Public License for more details.
> +
> + You should have received a copy of the GNU General Public License
> + along with this program. If not, see <http://www.gnu.org/licenses/>. */
> +
> +#ifndef GDB_COMPILE_OBJECT_RUN_H
> +#define GDB_COMPILE_OBJECT_RUN_H
> +
> +#include "compile-object-load.h"
> +
> +extern void compile_object_run (struct compile_module *module);
> +
> +#endif /* GDB_COMPILE_OBJECT_RUN_H */
> diff --git a/gdb/compile/compile.c b/gdb/compile/compile.c
> new file mode 100644
> index 0000000..86571e8
> --- /dev/null
> +++ b/gdb/compile/compile.c
> @@ -0,0 +1,623 @@
> +/* General Compile and inject code
> +
> + Copyright (C) 2014 Free Software Foundation, Inc.
> +
> + This file is part of GDB.
> +
> + This program is free software; you can redistribute it and/or modify
> + it under the terms of the GNU General Public License as published by
> + the Free Software Foundation; either version 3 of the License, or
> + (at your option) any later version.
> +
> + This program is distributed in the hope that it will be useful,
> + but WITHOUT ANY WARRANTY; without even the implied warranty of
> + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + GNU General Public License for more details.
> +
> + You should have received a copy of the GNU General Public License
> + along with this program. If not, see <http://www.gnu.org/licenses/>. */
> +
> +#include "defs.h"
> +#include "interps.h"
> +#include "ui-out.h"
> +#include "command.h"
> +#include "cli/cli-script.h"
> +#include "cli/cli-utils.h"
> +#include "completer.h"
> +#include "gdbcmd.h"
> +#include "compile.h"
> +#include "compile-internal.h"
> +#include "compile-object-load.h"
> +#include "compile-object-run.h"
> +#include "language.h"
> +#include "frame.h"
> +#include "source.h"
> +#include "block.h"
> +#include "arch-utils.h"
> +#include "filestuff.h"
> +#include "target.h"
> +
> +
> +
> +/* Hold "compile" commands. */
> +
> +static struct cmd_list_element *compile_command_list;
> +
> +/* Debug flag for "compile" commands. */
> +
> +int compile_debug;
> +
> +/* Implement "show debug compile". */
> +
> +static void
> +show_compile_debug (struct ui_file *file, int from_tty,
> + struct cmd_list_element *c, const char *value)
> +{
> + fprintf_filtered (file, _("Compile debugging is %s.\n"), value);
> +}
> +
> +
> +
> +/* Check *ARG for a "-raw" or "-r" argument. Return 0 if not seen.
> + Return 1 if seen and update *ARG. */
> +
> +static int
> +check_raw_argument (char **arg)
> +{
> + *arg = skip_spaces (*arg);
> +
> + if (arg != NULL
> + && (check_for_argument (arg, "-raw", sizeof ("-raw") - 1)
> + || check_for_argument (arg, "-r", sizeof ("-r") - 1)))
> + return 1;
> + return 0;
> +}
> +
> +/* Handle the input from the 'compile file' command. The "compile
> + file" command is used to evaluate an expression contained in a file
> + that may contain calls to the GCC compiler. */
> +
> +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;
> +
> + /* Check the user did not just <enter> after command. */
> + if (arg == NULL)
> + error (_("You must provide a filename for this command."));
> +
> + /* Check if a raw (-r|-raw) argument is provided. */
> + if (arg != NULL && check_raw_argument (&arg))
> + {
> + scope = COMPILE_I_RAW_SCOPE;
> + arg = skip_spaces (arg);
> + }
> +
> + /* After processing arguments, check there is a filename at the end
> + of the command. */
> + if (arg[0] == '\0')
> + error (_("You must provide a filename with the raw option set."));
> +
> + if (arg[0] == '-')
> + 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);
> +}
> +
> +/* Handle the input from the 'compile code' command. The
> + "compile code" command is used to evaluate 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_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;
> +
> + if (arg != NULL && check_raw_argument (&arg))
> + {
> + scope = COMPILE_I_RAW_SCOPE;
> + arg = skip_spaces (arg);
> + }
> +
> + arg = skip_spaces (arg);
> +
> + if (arg != NULL && !check_for_argument (&arg, "--", sizeof ("--") - 1))
> + {
> + if (arg[0] == '-')
> + error (_("Unknown argument specified."));
> + }
> +
> + if (arg && *arg)
> + eval_compile_command (NULL, arg, scope);
> + else
> + {
> + struct command_line *l = get_command_line (compile_control, "");
> +
> + make_cleanup_free_command_lines (&l);
> + l->control_u.compile.scope = scope;
> + execute_control_command_untraced (l);
> + }
> +
> + do_cleanups (cleanup);
> +}
> +
> +/* A cleanup function to remove a directory and all its contents. */
> +
> +static void
> +do_rmdir (void *arg)
> +{
> + char *zap = concat ("rm -rf ", arg, (char *) NULL);
> +
> + system (zap);
> +}
> +
> +/* Return the name of the temporary directory to use for .o files, and
> + arrange for the directory to be removed at shutdown. */
> +
> +static const char *
> +get_compile_file_tempdir (void)
> +{
> + static char *tempdir_name;
> +
> +#define TEMPLATE "/tmp/gdbobj-XXXXXX"
> + char tname[sizeof (TEMPLATE)];
> +
> + if (tempdir_name != NULL)
> + return tempdir_name;
> +
> + strcpy (tname, TEMPLATE);
> +#undef TEMPLATE
> + tempdir_name = mkdtemp (tname);
> + if (tempdir_name == NULL)
> + perror_with_name (_("Could not make temporary directory"));
> +
> + tempdir_name = xstrdup (tempdir_name);
> + make_final_cleanup (do_rmdir, tempdir_name);
> + 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. */
> +
> +static void
> +get_new_file_names (char **source_file, char **object_file)
> +{
> + 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);
> +}
> +
> +/* Get the block and PC at which to evaluate an expression. */
> +
> +static const struct block *
> +get_expr_block_and_pc (CORE_ADDR *pc)
> +{
> + const struct block *block = get_selected_block (pc);
> +
> + if (block == NULL)
> + {
> + struct symtab_and_line cursal = get_current_source_symtab_and_line ();
> +
> + if (cursal.symtab)
> + block = BLOCKVECTOR_BLOCK (BLOCKVECTOR (cursal.symtab), STATIC_BLOCK);
> + if (block != NULL)
> + *pc = BLOCK_START (block);
> + }
> + else
> + *pc = BLOCK_START (block);
> +
> + 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. */
> +
> +static void
> +build_argc_argv (const char *s, int *argcp, char ***argvp)
> +{
> + *argvp = gdb_buildargv (s);
> + *argcp = countargv (*argvp);
> +}
> +
> +/* String for 'set compile-args' and 'show compile-args'. */
> +static char *compile_args;
> +
> +/* Parsed form of COMPILE_ARGS. COMPILE_ARGS_ARGV is NULL terminated. */
> +static int compile_args_argc;
> +static char **compile_args_argv;
> +
> +/* Implement 'set compile-args'. */
> +
> +static void
> +set_compile_args (char *args, int from_tty, struct cmd_list_element *c)
> +{
> + freeargv (compile_args_argv);
> + build_argc_argv (compile_args, &compile_args_argc, &compile_args_argv);
> +}
> +
> +/* Implement 'show compile-args'. */
> +
> +static void
> +show_compile_args (struct ui_file *file, int from_tty,
> + struct cmd_list_element *c, const char *value)
> +{
> + fprintf_filtered (file, _("Compile 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. */
> +
> +static void
> +append_args (int *argcp, char ***argvp, int argc, char **argv)
> +{
> + int argi;
> +
> + *argvp = xrealloc (*argvp, (*argcp + argc + 1) * sizeof (**argvp));
> +
> + for (argi = 0; argi < argc; argi++)
> + (*argvp)[(*argcp)++] = xstrdup (argv[argi]);
> + (*argvp)[(*argcp)] = NULL;
> +}
> +
> +/* Return DW_AT_producer parsed for get_selected_frame () (if any).
> + Return NULL otherwise.
> +
> + GCC already filters its command-line arguments only for the suitable ones to
> + put into DW_AT_producer - see GCC function gen_producer_string. */
> +
> +static const char *
> +get_selected_pc_producer_options (void)
> +{
> + CORE_ADDR pc = get_frame_pc (get_selected_frame (NULL));
> + struct symtab *symtab = find_pc_symtab (pc);
> + const char *cs;
> +
> + if (symtab == NULL || symtab->producer == NULL
> + || strncmp (symtab->producer, "GNU ", strlen ("GNU ")) != 0)
> + return NULL;
> +
> + cs = symtab->producer;
> + while (*cs != 0 && *cs != '-')
> + cs = skip_spaces_const (skip_to_space_const (cs));
> + if (*cs != '-')
> + return NULL;
> + return cs;
> +}
> +
> +/* Produce final vector of GCC compilation options. First element is target
> + size ("-m64", "-m32" etc.), optionally followed by DW_AT_producer options
> + and then compile-args string GDB variable. */
> +
> +static void
> +get_args (const struct compile_instance *compiler, int *argcp, char ***argvp)
> +{
> + const char *cs_producer_options;
> + int argc_compiler;
> + char **argv_compiler;
> +
> + build_argc_argv (gdbarch_gcc_target_options (target_gdbarch ()),
> + argcp, argvp);
> +
> + cs_producer_options = get_selected_pc_producer_options ();
> + if (cs_producer_options != NULL)
> + {
> + int argc_producer;
> + char **argv_producer;
> +
> + build_argc_argv (cs_producer_options, &argc_producer, &argv_producer);
> + append_args (argcp, argvp, argc_producer, argv_producer);
> + freeargv (argv_producer);
> + }
> +
> + build_argc_argv (compiler->gcc_target_options,
> + &argc_compiler, &argv_compiler);
> + append_args (argcp, argvp, argc_compiler, argv_compiler);
> + freeargv (argv_compiler);
> +
> + append_args (argcp, argvp, compile_args_argc, compile_args_argv);
> +}
> +
> +/* A cleanup function to destroy a gdb_gcc_instance. */
> +
> +static void
> +cleanup_compile_instance (void *arg)
> +{
> + struct compile_instance *inst = 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. */
> +
> +static void
> +print_callback (void *ignore, const char *message)
> +{
> + fputs_filtered (message, gdb_stderr);
> +}
> +
> +/* 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)
> +{
> + char *code;
> + char *source_file, *object_file;
> + struct compile_instance *compiler;
> + struct cleanup *cleanup, *inner_cleanup;
> + const struct block *expr_block;
> + CORE_ADDR trash_pc, expr_pc;
> + int argc;
> + char **argv;
> + int ok;
> + FILE *src;
> +
> + if (!target_has_execution)
> + error (_("The program must be running for the compile command to "\
> + "work."));
> +
> + expr_block = get_expr_block_and_pc (&trash_pc);
> + expr_pc = get_frame_address_in_block (get_selected_frame (NULL));
> +
> + /* Set up instance and context for the compiler. */
> + if (current_language->la_get_compile_instance == NULL)
> + error (_("No compiler support for this language."));
> + compiler = current_language->la_get_compile_instance ();
> + cleanup = make_cleanup (cleanup_compile_instance, compiler);
> +
> + compiler->fe->ops->set_print_callback (compiler->fe, print_callback, NULL);
> +
> + compiler->scope = scope;
> + compiler->block = expr_block;
> +
> + /* From the provided expression, build a scope to pass to the
> + compiler. */
> + 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);
> + }
> +
> + code = ui_file_xstrdup (stream, NULL);
> + make_cleanup (xfree, code);
> + }
> + else if (cmd_string != NULL)
> + code = cmd_string;
> + else
> + error (_("Neither a simple expression, or a multi-line specified."));
> +
> + code = current_language->la_compute_program (compiler, code,
> + get_current_arch (),
> + expr_block, expr_pc);
> + make_cleanup (xfree, code);
> + if (compile_debug)
> + fprintf_unfiltered (gdb_stdout, "debug output:\n\n%s", code);
> +
> + /* Set compiler command-line arguments. */
> + get_args (compiler, &argc, &argv);
> + compiler->fe->ops->set_arguments (compiler->fe, argc, argv);
> + if (compile_debug)
> + {
> + int argi;
> +
> + fprintf_unfiltered (gdb_stdout, "Passing %d compiler options:\n", argc);
> + for (argi = 0; argi < argc; argi++)
> + fprintf_unfiltered (gdb_stdout, "Compiler option %d: <%s>\n",
> + argi, argv[argi]);
> + }
> + freeargv (argv);
> +
> + get_new_file_names (&source_file, &object_file);
> + inner_cleanup = make_cleanup (xfree, source_file);
> + make_cleanup (xfree, object_file);
> +
> + 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);
> +
> + if (compile_debug)
> + fprintf_unfiltered (gdb_stdout, "source file produced: %s\n\n",
> + source_file);
> +
> + /* Call the compiler and start the compilation process. */
> + compiler->fe->ops->set_source_file (compiler->fe, source_file);
> +
> + if (!compiler->fe->ops->compile (compiler->fe, object_file,
> + compile_debug))
> + error (_("Compilation failed."));
> +
> + if (compile_debug)
> + fprintf_unfiltered (gdb_stdout, "object file produced: %s\n\n",
> + object_file);
> +
> + discard_cleanups (inner_cleanup);
> + do_cleanups (cleanup);
> + *source_filep = source_file;
> + return object_file;
> +}
> +
> +/* The "compile" prefix command. */
> +
> +static void
> +compile_command (char *args, int from_tty)
> +{
> + /* If a sub-command is not specified to the compile prefix command,
> + assume it is a direct code compilation. */
> + compile_code_command (args, from_tty);
> +}
> +
> +/* See compile.h. */
> +
> +void
> +eval_compile_command (struct command_line *cmd, char *cmd_string,
> + enum compile_i_scope_types scope)
> +{
> + char *object_file, *source_file;
> +
> + object_file = compile_to_object (cmd, cmd_string, scope, &source_file);
> + if (object_file != 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);
> + }
> +}
> +
> +/* See compile/compile-internal.h. */
> +
> +char *
> +compile_register_name_mangled (struct gdbarch *gdbarch, int regnum)
> +{
> + const char *regname = gdbarch_register_name (gdbarch, regnum);
> +
> + return xstrprintf ("__%s", regname);
> +}
> +
> +/* See compile/compile-internal.h. */
> +
> +int
> +compile_register_name_demangle (struct gdbarch *gdbarch,
> + const char *regname)
> +{
> + int regnum;
> +
> + if (regname[0] != '_' || regname[1] != '_')
> + error (_("Invalid register name \"%s\"."), regname);
> + regname += 2;
> +
> + for (regnum = 0; regnum < gdbarch_num_regs (gdbarch); regnum++)
> + if (strcmp (regname, gdbarch_register_name (gdbarch, regnum)) == 0)
> + return regnum;
> +
> + error (_("Cannot find gdbarch register \"%s\"."), regname);
> +}
> +
> +extern initialize_file_ftype _initialize_compile;
> +
> +void
> +_initialize_compile (void)
> +{
> + struct cmd_list_element *c = NULL;
> +
> + add_prefix_cmd ("compile", class_obscure, compile_command,
> + _("\
> +Command to compile source code and inject it into the inferior."),
> + &compile_command_list, "compile ", 1, &cmdlist);
> + add_com_alias ("expression", "compile", class_obscure, 0);
> +
> + add_cmd ("code", class_obscure, compile_code_command,
> + _("\
> +Evaluate a block of source code.\n\
> +\n\
> +Usage: code [-r|-raw] [--] [CODE]\n\
> +-r|-raw: Suppress automatic 'void _gdb_expr () { CODE }' wrapping.\n\
> +--: Do not parse any options beyond this delimiter. All text to the\n\
> + right will be treated as source code.\n\
> +\n\
> +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."),
> + &compile_command_list);
> +
> + c = add_cmd ("file", class_obscure, compile_file_command,
> + _("\
> +Evaluate a file containing source code.\n\
> +\n\
> +Usage: file [-r|-raw] [filename]\n\
> +-r|-raw: Suppress automatic 'void _gdb_expr () { CODE }' wrapping."),
> + &compile_command_list);
> + set_cmd_completer (c, filename_completer);
> +
> + add_setshow_boolean_cmd ("compile", class_maintenance, &compile_debug, _("\
> +Set compile command debugging."), _("\
> +Show compile command debugging."), _("\
> +When on, compile command debugging is enabled."),
> + NULL, show_compile_debug,
> + &setdebuglist, &showdebuglist);
> +
> + add_setshow_string_cmd ("compile-args", class_support,
> + &compile_args,
> + _("Set compile command GCC command-line arguments"),
> + _("Show compile command GCC command-line arguments"),
> + _("\
> +Use options like -I (include file directory) or ABI settings.\n\
> +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);
> +
> + /* Override flags possibly coming from DW_AT_producer. */
> + compile_args = xstrdup ("-O0 -gdwarf-4"
> + /* We use -fPIC to ensure that we can reference properly. Otherwise
> + on x86-64 a string constant's address might be truncated when gdb
> + loads the object; another approach would be -mcmodel=large, but
> + -fPIC seems more portable across back ends. */
> + " -fPIC"
> + /* We don't want warnings. */
> + " -w"
> + /* Override CU's possible -fstack-protector-strong. */
> + " -fno-stack-protector"
> + );
> + set_compile_args (compile_args, 0, NULL);
> +}
> diff --git a/gdb/compile/compile.h b/gdb/compile/compile.h
> new file mode 100644
> index 0000000..486361f
> --- /dev/null
> +++ b/gdb/compile/compile.h
> @@ -0,0 +1,102 @@
> +/* Header file for Compile and inject module.
> +
> + Copyright (C) 2014 Free Software Foundation, Inc.
> +
> + This program is free software; you can redistribute it and/or modify
> + it under the terms of the GNU General Public License as published by
> + the Free Software Foundation; either version 3 of the License, or
> + (at your option) any later version.
> +
> + This program is distributed in the hope that it will be useful,
> + but WITHOUT ANY WARRANTY; without even the implied warranty of
> + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + GNU General Public License for more details.
> +
> + You should have received a copy of the GNU General Public License
> + along with this program. If not, see <http://www.gnu.org/licenses/>. */
> +
> +#ifndef GDB_COMPILE_H
> +#define GDB_COMPILE_H
> +
> +struct ui_file;
> +struct gdbarch;
> +struct dwarf2_per_cu_data;
> +struct symbol;
> +struct dynamic_prop;
> +
> +/* Public function that is called from compile_control case in the
> + expression command. GDB returns either a CMD, or a CMD_STRING, but
> + never both. */
> +
> +extern void eval_compile_command (struct command_line *cmd, char *cmd_string,
> + enum compile_i_scope_types scope);
> +
> +/* Compile a DWARF location expression to C, suitable for use by the
> + compiler.
> +
> + STREAM is the stream where the code should be written.
> +
> + RESULT_NAME is the name of a variable in the resulting C code. The
> + result of the expression will be assigned to this variable.
> +
> + SYM is the symbol corresponding to this expression.
> + PC is the location at which the expression is being evaluated.
> + ARCH is the architecture to use.
> +
> + REGISTERS_USED is an out parameter which is updated to note which
> + registers were needed by this expression.
> +
> + ADDR_SIZE is the DWARF address size to use.
> +
> + OPT_PTR and OP_END are the bounds of the DWARF expression.
> +
> + PER_CU is the per-CU object used for looking up various other
> + things. */
> +
> +extern void compile_dwarf_expr_to_c (struct ui_file *stream,
> + const char *result_name,
> + struct symbol *sym,
> + CORE_ADDR pc,
> + struct gdbarch *arch,
> + unsigned char *registers_used,
> + unsigned int addr_size,
> + const gdb_byte *op_ptr,
> + const gdb_byte *op_end,
> + struct dwarf2_per_cu_data *per_cu);
> +
> +/* Compile a DWARF bounds expression to C, suitable for use by the
> + compiler.
> +
> + STREAM is the stream where the code should be written.
> +
> + RESULT_NAME is the name of a variable in the resulting C code. The
> + result of the expression will be assigned to this variable.
> +
> + PROP is the dynamic property for which we're compiling.
> +
> + SYM is the symbol corresponding to this expression.
> + PC is the location at which the expression is being evaluated.
> + ARCH is the architecture to use.
> +
> + REGISTERS_USED is an out parameter which is updated to note which
> + registers were needed by this expression.
> +
> + ADDR_SIZE is the DWARF address size to use.
> +
> + OPT_PTR and OP_END are the bounds of the DWARF expression.
> +
> + PER_CU is the per-CU object used for looking up various other
> + things. */
> +
> +extern void compile_dwarf_bounds_to_c (struct ui_file *stream,
> + const char *result_name,
> + const struct dynamic_prop *prop,
> + struct symbol *sym, CORE_ADDR pc,
> + struct gdbarch *arch,
> + unsigned char *registers_used,
> + unsigned int addr_size,
> + const gdb_byte *op_ptr,
> + const gdb_byte *op_end,
> + struct dwarf2_per_cu_data *per_cu);
> +
> +#endif /* GDB_COMPILE_H */
> diff --git a/gdb/d-lang.c b/gdb/d-lang.c
> index 434f30a..597f7d0 100644
> --- a/gdb/d-lang.c
> +++ b/gdb/d-lang.c
> @@ -259,6 +259,8 @@ static const struct language_defn d_language_defn =
> NULL, /* la_get_symbol_name_cmp */
> iterate_over_symbols,
> &default_varobj_ops,
> + NULL,
> + NULL,
> LANG_MAGIC
> };
>
> diff --git a/gdb/defs.h b/gdb/defs.h
> index 47da43a..70fcf71 100644
> --- a/gdb/defs.h
> +++ b/gdb/defs.h
> @@ -73,6 +73,24 @@
>
> #include "host-defs.h"
>
> +/* Scope types enumerator. List the types of scopes the compiler will
> + accept. */
> +
> +enum compile_i_scope_types
> + {
> + COMPILE_I_INVALID_SCOPE,
> +
> + /* A simple scope. Wrap an expression into a simple scope that
> + takes no arguments, returns no value, and uses the generic
> + function name "_gdb_expr". */
> +
> + COMPILE_I_SIMPLE_SCOPE,
> +
> + /* Do not wrap the expression,
> + it has to provide function "_gdb_expr" on its own. */
> + COMPILE_I_RAW_SCOPE,
> + };
> +
> /* Just in case they're not defined in stdio.h. */
>
> #ifndef SEEK_SET
> @@ -414,6 +432,7 @@ enum command_control_type
> if_control,
> commands_control,
> python_control,
> + compile_control,
> guile_control,
> while_stepping_control,
> invalid_control
> @@ -427,6 +446,15 @@ struct command_line
> struct command_line *next;
> char *line;
> enum command_control_type control_type;
> + union
> + {
> + struct
> + {
> + enum compile_i_scope_types scope;
> + }
> + compile;
> + }
> + control_u;
> /* * The number of elements in body_list. */
> int body_count;
> /* * For composite commands, the nested lists of commands. For
> diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
> index 2aff5e5..d6d5a42 100644
> --- a/gdb/doc/gdb.texinfo
> +++ b/gdb/doc/gdb.texinfo
> @@ -16311,6 +16311,7 @@ address, or even return prematurely from a function.
> * Returning:: Returning from a function
> * Calling:: Calling your program's functions
> * Patching:: Patching your program
> +* Compiling and Injecting Code:: Compiling and injecting code in GDB
> @end menu
>
> @node Assignment
> @@ -16700,6 +16701,247 @@ Display whether executable files and core files are opened for writing
> as well as reading.
> @end table
>
> +@node Compiling and Injecting Code
> +@section Compiling and injecting code in GDB
> +@cindex injecting code
> +@cindex writing into executables
> +@cindex compiling code
> +
> +@value{GDBN} supports on-demand compilation and code injection into
> +programs running under GDB. A suitable compiler must be installed for
> +this functionality to be enabled. This functionality is implemented
> +with the following commands.
> +
> +@table @code
> +@kindex compile code
> +@item compile code @var{source}
> +@itemx compile code -@var{raw} @var{--} @var{source}
> +Compile @var{source} using the language set in @value{GDBN}
> +(@pxref{Languages}), as the compilation language type. If compilation
> +and injection is not supported with the current language specified in
> +@value{GDBN}, or the compiler does not support this feature, an error
> +message will be printed and the command will exit. If @var{source}
> +compiles and links successfully, @value{GDBN} will load the object-code
> +emitted, and execute it within the context of the currently selected
> +inferior.
> +
> +The command allows you to specify source code in two ways. The simplest
> +method is to provide a single line of code to the command. E.g.:
> +
> +@smallexample
> +compile code printf ("hello world\n");
> +@end smallexample
> +
> +If you specify options on the command line as well as source code, they
> +may conflict. The @samp{@var{--}} delimiter can be used to separate options
> +from actual source code. E.g.:
> +
> +@smallexample
> +compile code -r -- printf ("hello world\n");
> +@end smallexample
> +
> +Alternatively you can enter source code as multiple lines of text. To
> +enter this mode, invoke the @samp{compile code} command without any text
> +following the command. This will start the multiple-line editor and
> +allow you to type as many lines of source code as required. When you
> +have completed typing, enter @samp{end} on its own line to exit the
> +editor.
> +
> +@smallexample
> +compile code
> +>printf ("hello\n");
> +>printf ("world\n");
> +>end
> +@end smallexample
> +
> +Specifying @samp{-@var{raw}}, prohibits @value{GDBN} from wrapping the
> +provided @var{source} in a callable scope. In this case, you must
> +specify the entry point of the code by defining a function named
> +@code{_gdb_expr_}. @samp{-@var{raw}} code does not automatically access
> +variables of the inferior, for their import you must use
> +the @samp{#pragma} line first:
> +
> +@smallexample
> +#pragma GCC user_expression
> +@end smallexample
> +
> +@samp{#include} lines are better to be placed before the @samp{#pragma}
> +line. The use of @var{raw} is considered to be expert usage, and care
> +should be taken when using it.
> +
> +@kindex compile file
> +@item compile file @var{filename}
> +@itemx compile file -@var{raw} @var{filename}
> +Load source code from the file specified by @var{filename}, and compile
> +it using the language set in @value{GDBN} (@pxref{Languages}), as the
> +compilation language type. If compilation and injection is not
> +supported with the current language specified in @value{GDBN}, or the
> +compiler does not support this feature, an error message will be printed
> +and the command will exit. If the source-code contained within
> +@var{filename} compiles and links successfully, @value{GDBN} will load
> +the object-code emitted, and execute it within the context of the
> +currently selected inferior.
> +
> +@smallexample
> +compile file /home/user/example.c
> +@end smallexample
> +
> +Specifying @samp{-@var{raw}}, prohibits @value{GDBN} from wrapping the
> +provided @var{source} in a callable scope. In this case, you must
> +specify the entry point of the code by defining a function named
> +@code{_gdb_expr_}. @samp{-@var{raw}} code does not automatically access
> +variables of the inferior, for their import you must use
> +the @samp{#pragma} line first:
> +
> +@smallexample
> +#pragma GCC user_expression
> +@end smallexample
> +
> +@samp{#include} lines are better to be placed before the @samp{#pragma}
> +line. The use of @var{raw} is considered to be expert usage, and care
> +should be taken when using it.
> +@end table
> +
> +There are a few caveats to keep in mind when using the compile command.
> +As the caveats are different per language, the table below highlights
> +specific issues on a per language basis.
> +
> +@table @code
> +@item C code examples and caveats
> +When the language in @value{GDBN} is set to @samp{C}, the compiler will
> +attempt to compile the source code with a @samp{C} compiler. The source
> +code provided to the @samp{compile} command will have much the same
> +access to variables and types as it normally would if it were part of
> +the program currently being debugged in @value{GDBN}.
> +
> +Below is a sample program that forms the basis of the examples that
> +follow. This program has been compiled and loaded into @value{GDBN},
> +much like any other normal debugging session.
> +
> +@smallexample
> +void function1 (void)
> +@{
> + int i = 42;
> + printf ("function 1\n");
> +@}
> +
> +void function2 (void)
> +@{
> + int j = 12;
> + function1 ();
> +@}
> +
> +int main(void)
> +@{
> + int k = 6;
> + int *p;
> + function2 ();
> + return 0;
> +@}
> +@end smallexample
> +
> +For the purposes of the examples in this section, the program above has
> +been compiled, loaded into @value{GDBN}, stopped at the function
> +@samp{main}, and @value{GDBN} is awaiting input from the user.
> +
> +To access variables and types for any program in @value{GDBN}, the
> +program must be compiled and packaged with debug information. The
> +@samp{compile} command is not an exception to this rule. Without debug
> +information, you can still use the @samp{compile} command, but you will
> +be very limited in what variables and types you can access.
> +
> +So with that in mind, the example above has been compiled with debug
> +information enabled. The @samp{compile} command will have access to all
> +variables and types (except those that may have been optimized out).
> +Currently, as @value{GDBN} has stopped the program in the @samp{main}
> +function, the @samp{compile} command would have access to the variable
> +@var{k}. You could invoke the @samp{compile} command and type some
> +source code to set the value of @var{k}. You can also read it, or do
> +anything with that variable you would normally do in @samp{C}. Be aware
> +that changes to variables you make in the @samp{compile} command are
> +persistent, so in the following example:
> +
> +@smallexample
> +compile code k = 3;
> +@end smallexample
> +
> +The variable @var{k} is now 3. It will remain that value until
> +something else in the example program changes it, or another
> +@samp{compile} command changes it.
> +
> +Normal scope and access rules apply to source code compiled and injected
> +by the @samp{compile} command. In the example, the variables @var{j}
> +and @var{k} are not accessible; subsequent execution will bring these
> +variables into scope, and later, code written and compiled with the
> +@samp{compile} command will be able to access them. At this point the
> +program is stopped in the @samp{main} function so the following example:
> +
> +@smallexample
> +compile code j = 3;
> +@end smallexample
> +
> +would result in a compilation error, and @value{GDBN} would print that
> +error to the console.
> +
> +You can create variables and types with the @samp{compile} command as
> +part of your source code. Variables and types that are created as part
> +of the @samp{compile} command are not persistent, and only exist as
> +long as the injected object code exists. This example is valid:
> +
> +@smallexample
> +compile code int ff = 5; printf ("ff is %d\n", ff);
> +@end smallexample
> +
> +However, if you were to type the following into @value{GDBN} after that
> +command has completed:
> +
> +@smallexample
> +compile code printf ("ff is %d\n'', ff);
> +@end smallexample
> +
> +A compiler error would be raised as the variable @var{ff} no longer
> +exists. Object code generated and injected by the @samp{compile}
> +command is removed on completion of the command. Caution is advised
> +when assigning variables belonging to the program with variables created
> +in the @samp{compile} command. This example is valid:
> +
> +@smallexample
> +compile code int ff = 5; k = ff;
> +@end smallexample
> +
> +The @var{k} variable is assigned to the value of @var{ff}. The variable
> +@var{k} does not require the existence of @var{ff} to maintain the value
> +it has been assigned. Pointers and other types of references require
> +particular care in assignment. If the source code compiled with the
> +@samp{compile} command changed the address of a pointer in the example
> +program, perhaps to a variable created in the @samp{compile} command,
> +that pointer would point to an invalid location when the command exits.
> +The following example would likely cause issues with your debugged
> +program:
> +
> +@smallexample
> +compile code int ff = 5; p = &ff;
> +@end smallexample
> +
> +In this example, @var{p} would point to @var{ff} when the @samp{compile}
> +command is executing the source code provided to it. However, as
> +variables in the (example) program persist with their assigned values, the
> +variable @samp{p} would point to an invalid location when the command
> +exists. A general rule should be followed in that you should either
> +assign NULL to any assigned pointers, or restore a valid location to the
> +pointer before the command exits.
> +
> +Similar caution must be exercised with any types defined in
> +@samp{compile} command. Types defined in the @samp{compile} are also
> +deleted when the command exits. Therefore, if you cast a variable to a
> +type defined in the @samp{compile} command, care must be taken to ensure
> +that any future need to resolve the type can be achieved.
> +
> +Variables that have been optimized away by the compiler are not
> +accessible to the @samp{compile} command. Access to those variables
> +will generate a compiler error which @value{GDBN} will print to the console.
> +@end table
> +
> @node GDB Files
> @chapter @value{GDBN} Files
>
> diff --git a/gdb/dwarf2loc.c b/gdb/dwarf2loc.c
> index 7bb4c48..dc3b9cc 100644
> --- a/gdb/dwarf2loc.c
> +++ b/gdb/dwarf2loc.c
> @@ -41,6 +41,7 @@
>
> #include <string.h>
> #include "gdb_assert.h"
> +#include "compile/compile.h"
>
> extern int dwarf2_always_disassemble;
>
> @@ -2545,6 +2546,42 @@ dwarf2_evaluate_property (const struct dynamic_prop *prop, CORE_ADDR *value)
> return 0;
> }
>
> +/* See dwarf2loc.h. */
> +
> +void
> +dwarf2_compile_property_to_c (struct ui_file *stream,
> + const char *result_name,
> + struct gdbarch *gdbarch,
> + unsigned char *registers_used,
> + const struct dynamic_prop *prop,
> + CORE_ADDR pc,
> + struct symbol *sym)
> +{
> + struct dwarf2_property_baton *baton = prop->data.baton;
> + const gdb_byte *data;
> + size_t size;
> + struct dwarf2_per_cu_data *per_cu;
> +
> + if (prop->kind == PROP_LOCEXPR)
> + {
> + data = baton->locexpr.data;
> + size = baton->locexpr.size;
> + per_cu = baton->locexpr.per_cu;
> + }
> + else
> + {
> + gdb_assert (prop->kind == PROP_LOCLIST);
> +
> + data = dwarf2_find_location_expression (&baton->loclist, &size, pc);
> + per_cu = baton->loclist.per_cu;
> + }
> +
> + compile_dwarf_bounds_to_c (stream, result_name, prop, sym, pc,
> + gdbarch, registers_used,
> + dwarf2_per_cu_addr_size (per_cu),
> + data, data + size, per_cu);
> +}
> +
>
> /* Helper functions and baton for dwarf2_loc_desc_needs_frame. */
>
> @@ -4198,6 +4235,26 @@ locexpr_tracepoint_var_ref (struct symbol *symbol, struct gdbarch *gdbarch,
> dlbaton->per_cu);
> }
>
> +/* symbol_computed_ops 'generate_c_location' method. */
> +
> +static void
> +locexpr_generate_c_location (struct symbol *sym, struct ui_file *stream,
> + struct gdbarch *gdbarch,
> + unsigned char *registers_used,
> + CORE_ADDR pc, const char *result_name)
> +{
> + struct dwarf2_locexpr_baton *dlbaton = SYMBOL_LOCATION_BATON (sym);
> + unsigned int addr_size = dwarf2_per_cu_addr_size (dlbaton->per_cu);
> +
> + if (dlbaton->size == 0)
> + error (_("symbol \"%s\" is optimized out"), SYMBOL_NATURAL_NAME (sym));
> +
> + compile_dwarf_expr_to_c (stream, result_name,
> + sym, pc, gdbarch, registers_used, addr_size,
> + dlbaton->data, dlbaton->data + dlbaton->size,
> + dlbaton->per_cu);
> +}
> +
> /* The set of location functions used with the DWARF-2 expression
> evaluator. */
> const struct symbol_computed_ops dwarf2_locexpr_funcs = {
> @@ -4206,7 +4263,8 @@ const struct symbol_computed_ops dwarf2_locexpr_funcs = {
> locexpr_read_needs_frame,
> locexpr_describe_location,
> 0, /* location_has_loclist */
> - locexpr_tracepoint_var_ref
> + locexpr_tracepoint_var_ref,
> + locexpr_generate_c_location
> };
>
>
> @@ -4377,6 +4435,29 @@ loclist_tracepoint_var_ref (struct symbol *symbol, struct gdbarch *gdbarch,
> dlbaton->per_cu);
> }
>
> +/* symbol_computed_ops 'generate_c_location' method. */
> +
> +static void
> +loclist_generate_c_location (struct symbol *sym, struct ui_file *stream,
> + struct gdbarch *gdbarch,
> + unsigned char *registers_used,
> + CORE_ADDR pc, const char *result_name)
> +{
> + struct dwarf2_loclist_baton *dlbaton = SYMBOL_LOCATION_BATON (sym);
> + unsigned int addr_size = dwarf2_per_cu_addr_size (dlbaton->per_cu);
> + const gdb_byte *data;
> + size_t size;
> +
> + data = dwarf2_find_location_expression (dlbaton, &size, pc);
> + if (size == 0)
> + error (_("symbol \"%s\" is optimized out"), SYMBOL_NATURAL_NAME (sym));
> +
> + compile_dwarf_expr_to_c (stream, result_name,
> + sym, pc, gdbarch, registers_used, addr_size,
> + data, data + size,
> + dlbaton->per_cu);
> +}
> +
> /* The set of location functions used with the DWARF-2 expression
> evaluator and location lists. */
> const struct symbol_computed_ops dwarf2_loclist_funcs = {
> @@ -4385,7 +4466,8 @@ const struct symbol_computed_ops dwarf2_loclist_funcs = {
> loclist_read_needs_frame,
> loclist_describe_location,
> 1, /* location_has_loclist */
> - loclist_tracepoint_var_ref
> + loclist_tracepoint_var_ref,
> + loclist_generate_c_location
> };
>
> /* Provide a prototype to silence -Wmissing-prototypes. */
> diff --git a/gdb/dwarf2loc.h b/gdb/dwarf2loc.h
> index bc7dfb7..36f5a59 100644
> --- a/gdb/dwarf2loc.h
> +++ b/gdb/dwarf2loc.h
> @@ -108,6 +108,27 @@ struct value *dwarf2_evaluate_loc_desc (struct type *type,
> int dwarf2_evaluate_property (const struct dynamic_prop *prop,
> CORE_ADDR *value);
>
> +/* A helper for the compiler interface that compiles a single dynamic
> + property to C code.
> +
> + STREAM is where the C code is to be written.
> + RESULT_NAME is the name of the generated variable.
> + GDBARCH is the architecture to use.
> + REGISTERS_USED is a bit-vector that is filled to note which
> + registers are required by the generated expression.
> + PROP is the property for which code is generated.
> + ADDRESS is the address at which the property is considered to be
> + evaluated.
> + SYM the originating symbol, used for error reporting. */
> +
> +void dwarf2_compile_property_to_c (struct ui_file *stream,
> + const char *result_name,
> + struct gdbarch *gdbarch,
> + unsigned char *registers_used,
> + const struct dynamic_prop *prop,
> + CORE_ADDR address,
> + struct symbol *sym);
> +
> CORE_ADDR dwarf2_read_addr_index (struct dwarf2_per_cu_data *per_cu,
> unsigned int addr_index);
>
> diff --git a/gdb/f-lang.c b/gdb/f-lang.c
> index bbfd89c..5243d35 100644
> --- a/gdb/f-lang.c
> +++ b/gdb/f-lang.c
> @@ -276,6 +276,8 @@ const struct language_defn f_language_defn =
> NULL, /* la_get_symbol_name_cmp */
> iterate_over_symbols,
> &default_varobj_ops,
> + NULL,
> + NULL,
> LANG_MAGIC
> };
>
> diff --git a/gdb/go-lang.c b/gdb/go-lang.c
> index 42535df..429bc4d 100644
> --- a/gdb/go-lang.c
> +++ b/gdb/go-lang.c
> @@ -599,6 +599,8 @@ static const struct language_defn go_language_defn =
> NULL,
> iterate_over_symbols,
> &default_varobj_ops,
> + NULL,
> + NULL,
> LANG_MAGIC
> };
>
> diff --git a/gdb/jv-lang.c b/gdb/jv-lang.c
> index 243a45a..fc28bd3 100644
> --- a/gdb/jv-lang.c
> +++ b/gdb/jv-lang.c
> @@ -1197,6 +1197,8 @@ const struct language_defn java_language_defn =
> NULL, /* la_get_symbol_name_cmp */
> iterate_over_symbols,
> &java_varobj_ops,
> + NULL,
> + NULL,
> LANG_MAGIC
> };
>
> diff --git a/gdb/language.c b/gdb/language.c
> index d5502f2..20d0c9b 100644
> --- a/gdb/language.c
> +++ b/gdb/language.c
> @@ -829,6 +829,8 @@ const struct language_defn unknown_language_defn =
> NULL, /* la_get_symbol_name_cmp */
> iterate_over_symbols,
> &default_varobj_ops,
> + NULL,
> + NULL,
> LANG_MAGIC
> };
>
> @@ -874,6 +876,8 @@ const struct language_defn auto_language_defn =
> NULL, /* la_get_symbol_name_cmp */
> iterate_over_symbols,
> &default_varobj_ops,
> + NULL,
> + NULL,
> LANG_MAGIC
> };
>
> @@ -917,6 +921,8 @@ const struct language_defn local_language_defn =
> NULL, /* la_get_symbol_name_cmp */
> iterate_over_symbols,
> &default_varobj_ops,
> + NULL,
> + NULL,
> LANG_MAGIC
> };
>
> diff --git a/gdb/language.h b/gdb/language.h
> index 73619ca..9ed7e22 100644
> --- a/gdb/language.h
> +++ b/gdb/language.h
> @@ -35,6 +35,7 @@ struct value_print_options;
> struct type_print_options;
> struct lang_varobj_ops;
> struct parser_state;
> +struct compile_instance;
>
> #define MAX_FORTRAN_DIMS 7 /* Maximum number of F77 array dims. */
>
> @@ -355,6 +356,36 @@ struct language_defn
> /* Various operations on varobj. */
> const struct lang_varobj_ops *la_varobj_ops;
>
> + /* If this language allows compilation from the gdb command line,
> + this method should be non-NULL. When called it should return
> + an instance of struct gcc_context appropriate to the language.
> + When defined this method must never return NULL; instead it
> + should throw an exception on failure. The returned compiler
> + instance is owned by its caller and must be deallocated by
> + calling its 'destroy' method. */
> +
> + struct compile_instance *(*la_get_compile_instance) (void);
> +
> + /* This method must be defined if 'la_get_gcc_context' is defined.
> + If 'la_get_gcc_context' is not defined, then this method is
> + ignored.
> +
> + This takes the user-supplied text and returns a newly malloc'd
> + bit of code to compile. The caller owns the result.
> +
> + INST is the compiler instance being used.
> + INPUT is the user's input text.
> + GDBARCH is the architecture to use.
> + EXPR_BLOCK is the block in which the expression is being
> + parsed.
> + EXPR_PC is the PC at which the expression is being parsed. */
> +
> + char *(*la_compute_program) (struct compile_instance *inst,
> + const char *input,
> + struct gdbarch *gdbarch,
> + const struct block *expr_block,
> + CORE_ADDR expr_pc);
> +
> /* Add fields above this point, so the magic number is always last. */
> /* Magic number for compat checking. */
>
> diff --git a/gdb/m2-lang.c b/gdb/m2-lang.c
> index 940cbcf..6a68520 100644
> --- a/gdb/m2-lang.c
> +++ b/gdb/m2-lang.c
> @@ -394,6 +394,8 @@ const struct language_defn m2_language_defn =
> NULL, /* la_get_symbol_name_cmp */
> iterate_over_symbols,
> &default_varobj_ops,
> + NULL,
> + NULL,
> LANG_MAGIC
> };
>
> diff --git a/gdb/objc-lang.c b/gdb/objc-lang.c
> index 68f0d10..1b83614 100644
> --- a/gdb/objc-lang.c
> +++ b/gdb/objc-lang.c
> @@ -392,6 +392,8 @@ const struct language_defn objc_language_defn = {
> NULL, /* la_get_symbol_name_cmp */
> iterate_over_symbols,
> &default_varobj_ops,
> + NULL,
> + NULL,
> LANG_MAGIC
> };
>
> diff --git a/gdb/opencl-lang.c b/gdb/opencl-lang.c
> index 2dd76fa..3770a22 100644
> --- a/gdb/opencl-lang.c
> +++ b/gdb/opencl-lang.c
> @@ -1139,6 +1139,8 @@ const struct language_defn opencl_language_defn =
> NULL, /* la_get_symbol_name_cmp */
> iterate_over_symbols,
> &default_varobj_ops,
> + NULL,
> + NULL,
> LANG_MAGIC
> };
>
> diff --git a/gdb/p-lang.c b/gdb/p-lang.c
> index 856beb3..a5a367b 100644
> --- a/gdb/p-lang.c
> +++ b/gdb/p-lang.c
> @@ -452,6 +452,8 @@ const struct language_defn pascal_language_defn =
> NULL, /* la_get_symbol_name_cmp */
> iterate_over_symbols,
> &default_varobj_ops,
> + NULL,
> + NULL,
> LANG_MAGIC
> };
>
> diff --git a/gdb/symtab.h b/gdb/symtab.h
> index efc3643..ce430a5 100644
> --- a/gdb/symtab.h
> +++ b/gdb/symtab.h
> @@ -641,6 +641,21 @@ struct symbol_computed_ops
>
> void (*tracepoint_var_ref) (struct symbol *symbol, struct gdbarch *gdbarch,
> struct agent_expr *ax, struct axs_value *value);
> +
> + /* Generate C code to compute the location of SYMBOL. The C code is
> + emitted to STREAM. GDBARCH is the current architecture and PC is
> + the PC at which SYMBOL's location should be evaluated.
> + REGISTERS_USED is a vector indexed by register number; the
> + generator function should set an element in this vector if the
> + corresponding register is needed by the location computation.
> + The generated C code must assign the location to a local
> + variable; this variable's name is RESULT_NAME. */
> +
> + void (*generate_c_location) (struct symbol *symbol, struct ui_file *stream,
> + struct gdbarch *gdbarch,
> + unsigned char *registers_used,
> + CORE_ADDR pc, const char *result_name);
> +
> };
>
> /* The methods needed to implement LOC_BLOCK for inferior functions.
> diff --git a/gdb/testsuite/gdb.base/compile-constvar.S b/gdb/testsuite/gdb.base/compile-constvar.S
> new file mode 100644
> index 0000000..55d81bc
> --- /dev/null
> +++ b/gdb/testsuite/gdb.base/compile-constvar.S
> @@ -0,0 +1,95 @@
> +/* This testcase is part of GDB, the GNU debugger.
> +
> + Copyright 2014 Free Software Foundation, Inc.
> +
> + This program is free software; you can redistribute it and/or modify
> + it under the terms of the GNU General Public License as published by
> + the Free Software Foundation; either version 3 of the License, or
> + (at your option) any later version.
> +
> + This program is distributed in the hope that it will be useful,
> + but WITHOUT ANY WARRANTY; without even the implied warranty of
> + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + GNU General Public License for more details.
> +
> + You should have received a copy of the GNU General Public License
> + along with this program. If not, see <http://www.gnu.org/licenses/>. */
> +
> +// gcc -o gdb.base/compile-constvar.S -dA -S -g gdb.base/compile-constvar.c
> +
> + .file "compile-constvar.c"
> + .file 1 "gdb.base/compile-constvar.c"
> + .section .debug_info,"",@progbits
> +.Ldebug_info0:
> + .long .Lend-.Lstart # Length of Compilation Unit Info
> +.Lstart:
> + .value 0x4 # DWARF version number
> + .long .Ldebug_abbrev0 # Offset Into Abbrev. Section
> + .byte 0x8 # Pointer Size (in bytes)
> + .uleb128 0x1 # (DIE (0xb) DW_TAG_compile_unit)
> + .long .LASF0 # DW_AT_producer: "GNU C 4.8.2 20131212 (Red Hat 4.8.2-7) -mtune=generic -march=x86-64 -g"
> + .byte 0x1 # DW_AT_language
> + .long .LASF1 # DW_AT_name: "gdb.base/compile-constvar.c"
> + .long .LASF2 # DW_AT_comp_dir: "/home/jkratoch/redhat/gdb-gdbjit/gdb/testsuite"
> + .uleb128 0x2 # (DIE (0x1d) DW_TAG_variable)
> + .long .LASF3 # DW_AT_name: "constvar"
> + .long .Linttype-.Ldebug_info0 # DW_AT_type
> + # DW_AT_external
> + .byte 0x3 # DW_AT_const_value
> +.Linttype:
> + .uleb128 0x3 # (DIE (0x32) DW_TAG_base_type)
> + .byte 0x4 # DW_AT_byte_size
> + .byte 0x5 # DW_AT_encoding
> + .ascii "int\0" # DW_AT_name
> + .byte 0 # end of children of DIE 0xb
> +.Lend:
> + .section .debug_abbrev,"",@progbits
> +.Ldebug_abbrev0:
> + .uleb128 0x1 # (abbrev code)
> + .uleb128 0x11 # (TAG: DW_TAG_compile_unit)
> + .byte 0x1 # DW_children_yes
> + .uleb128 0x25 # (DW_AT_producer)
> + .uleb128 0xe # (DW_FORM_strp)
> + .uleb128 0x13 # (DW_AT_language)
> + .uleb128 0xb # (DW_FORM_data1)
> + .uleb128 0x3 # (DW_AT_name)
> + .uleb128 0xe # (DW_FORM_strp)
> + .uleb128 0x1b # (DW_AT_comp_dir)
> + .uleb128 0xe # (DW_FORM_strp)
> + .byte 0
> + .byte 0
> + .uleb128 0x2 # (abbrev code)
> + .uleb128 0x34 # (TAG: DW_TAG_variable)
> + .byte 0 # DW_children_no
> + .uleb128 0x3 # (DW_AT_name)
> + .uleb128 0xe # (DW_FORM_strp)
> + .uleb128 0x49 # (DW_AT_type)
> + .uleb128 0x13 # (DW_FORM_ref4)
> + .uleb128 0x3f # (DW_AT_external)
> + .uleb128 0x19 # (DW_FORM_flag_present)
> + .uleb128 0x1c # (DW_AT_const_value)
> + .uleb128 0xb # (DW_FORM_data1)
> + .byte 0
> + .byte 0
> + .uleb128 0x3 # (abbrev code)
> + .uleb128 0x24 # (TAG: DW_TAG_base_type)
> + .byte 0 # DW_children_no
> + .uleb128 0xb # (DW_AT_byte_size)
> + .uleb128 0xb # (DW_FORM_data1)
> + .uleb128 0x3e # (DW_AT_encoding)
> + .uleb128 0xb # (DW_FORM_data1)
> + .uleb128 0x3 # (DW_AT_name)
> + .uleb128 0x8 # (DW_FORM_string)
> + .byte 0
> + .byte 0
> + .byte 0
> + .section .debug_str,"MS",@progbits,1
> +.LASF1:
> + .string "gdb.base/compile-constvar.c"
> +.LASF3:
> + .string "constvar"
> +.LASF2:
> + .string ""
> +.LASF0:
> + .string "GNU C 4.8.2 20131212 (Red Hat 4.8.2-7) -mtune=generic -march=x86-64 -g"
> + .ident "GCC: (GNU) 4.8.2 20131212 (Red Hat 4.8.2-7)"
> diff --git a/gdb/testsuite/gdb.base/compile-constvar.c b/gdb/testsuite/gdb.base/compile-constvar.c
> new file mode 100644
> index 0000000..3820b43
> --- /dev/null
> +++ b/gdb/testsuite/gdb.base/compile-constvar.c
> @@ -0,0 +1,18 @@
> +/* This testcase is part of GDB, the GNU debugger.
> +
> + Copyright 2014 Free Software Foundation, Inc.
> +
> + This program is free software; you can redistribute it and/or modify
> + it under the terms of the GNU General Public License as published by
> + the Free Software Foundation; either version 3 of the License, or
> + (at your option) any later version.
> +
> + This program is distributed in the hope that it will be useful,
> + but WITHOUT ANY WARRANTY; without even the implied warranty of
> + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + GNU General Public License for more details.
> +
> + You should have received a copy of the GNU General Public License
> + along with this program. If not, see <http://www.gnu.org/licenses/>. */
> +
> +int constvar = 5;
> diff --git a/gdb/testsuite/gdb.base/compile-mod.c b/gdb/testsuite/gdb.base/compile-mod.c
> new file mode 100644
> index 0000000..a6dbc32
> --- /dev/null
> +++ b/gdb/testsuite/gdb.base/compile-mod.c
> @@ -0,0 +1,26 @@
> +/* This testcase is part of GDB, the GNU debugger.
> +
> + Copyright 2014 Free Software Foundation, Inc.
> +
> + This program is free software; you can redistribute it and/or modify
> + it under the terms of the GNU General Public License as published by
> + the Free Software Foundation; either version 3 of the License, or
> + (at your option) any later version.
> +
> + This program is distributed in the hope that it will be useful,
> + but WITHOUT ANY WARRANTY; without even the implied warranty of
> + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + GNU General Public License for more details.
> +
> + You should have received a copy of the GNU General Public License
> + along with this program. If not, see <http://www.gnu.org/licenses/>. */
> +
> +// Make 'globalvar' lookup working.
> +#pragma GCC user_expression
> +
> +void
> +_gdb_expr (void)
> +{
> + globalvar = 3;
> + globalvar += 4;
> +}
> diff --git a/gdb/testsuite/gdb.base/compile-nodebug.c b/gdb/testsuite/gdb.base/compile-nodebug.c
> new file mode 100644
> index 0000000..4cc8bb3
> --- /dev/null
> +++ b/gdb/testsuite/gdb.base/compile-nodebug.c
> @@ -0,0 +1,24 @@
> +/* This testcase is part of GDB, the GNU debugger.
> +
> + Copyright 2014 Free Software Foundation, Inc.
> +
> + This program is free software; you can redistribute it and/or modify
> + it under the terms of the GNU General Public License as published by
> + the Free Software Foundation; either version 3 of the License, or
> + (at your option) any later version.
> +
> + This program is distributed in the hope that it will be useful,
> + but WITHOUT ANY WARRANTY; without even the implied warranty of
> + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + GNU General Public License for more details.
> +
> + You should have received a copy of the GNU General Public License
> + along with this program. If not, see <http://www.gnu.org/licenses/>. */
> +
> +int
> +func_nodebug (int neg)
> +{
> + return -neg;
> +}
> +
> +int unresolved = 20;
> diff --git a/gdb/testsuite/gdb.base/compile-setjmp-mod.c b/gdb/testsuite/gdb.base/compile-setjmp-mod.c
> new file mode 100644
> index 0000000..8a1c413
> --- /dev/null
> +++ b/gdb/testsuite/gdb.base/compile-setjmp-mod.c
> @@ -0,0 +1,46 @@
> +/* This testcase is part of GDB, the GNU debugger.
> +
> + Copyright 2014 Free Software Foundation, Inc.
> +
> + This program is free software; you can redistribute it and/or modify
> + it under the terms of the GNU General Public License as published by
> + the Free Software Foundation; either version 3 of the License, or
> + (at your option) any later version.
> +
> + This program is distributed in the hope that it will be useful,
> + but WITHOUT ANY WARRANTY; without even the implied warranty of
> + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + GNU General Public License for more details.
> +
> + You should have received a copy of the GNU General Public License
> + along with this program. If not, see <http://www.gnu.org/licenses/>. */
> +
> +#include <setjmp.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +
> +// Make 'done' lookup working.
> +#pragma GCC user_expression
> +
> +static void
> +foo ()
> +{
> + jmp_buf env;
> +
> + switch (setjmp (env))
> + {
> + case 2:
> + done = 1;
> + return;
> + case 0:
> + longjmp (env, 2);
> + break;
> + }
> + abort ();
> +}
> +
> +void
> +_gdb_expr (void)
> +{
> + foo ();
> +}
> diff --git a/gdb/testsuite/gdb.base/compile-setjmp.c b/gdb/testsuite/gdb.base/compile-setjmp.c
> new file mode 100644
> index 0000000..c462f48
> --- /dev/null
> +++ b/gdb/testsuite/gdb.base/compile-setjmp.c
> @@ -0,0 +1,24 @@
> +/* This testcase is part of GDB, the GNU debugger.
> +
> + Copyright 2014 Free Software Foundation, Inc.
> +
> + This program is free software; you can redistribute it and/or modify
> + it under the terms of the GNU General Public License as published by
> + the Free Software Foundation; either version 3 of the License, or
> + (at your option) any later version.
> +
> + This program is distributed in the hope that it will be useful,
> + but WITHOUT ANY WARRANTY; without even the implied warranty of
> + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + GNU General Public License for more details.
> +
> + You should have received a copy of the GNU General Public License
> + along with this program. If not, see <http://www.gnu.org/licenses/>. */
> +
> +static int done;
> +
> +int
> +main (void)
> +{
> + return 0;
> +}
> diff --git a/gdb/testsuite/gdb.base/compile-setjmp.exp b/gdb/testsuite/gdb.base/compile-setjmp.exp
> new file mode 100644
> index 0000000..557c1f0
> --- /dev/null
> +++ b/gdb/testsuite/gdb.base/compile-setjmp.exp
> @@ -0,0 +1,34 @@
> +# Copyright 2014 Free Software Foundation, Inc.
> +
> +# This program is free software; you can redistribute it and/or modify
> +# it under the terms of the GNU General Public License as published by
> +# the Free Software Foundation; either version 3 of the License, or
> +# (at your option) any later version.
> +#
> +# This program is distributed in the hope that it will be useful,
> +# but WITHOUT ANY WARRANTY; without even the implied warranty of
> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> +# GNU General Public License for more details.
> +#
> +# You should have received a copy of the GNU General Public License
> +# along with this program. If not, see <http://www.gnu.org/licenses/>.
> +
> +standard_testfile .c compile-setjmp-mod.c
> +
> +if { [prepare_for_testing ${testfile}.exp $testfile] } {
> + return -1
> +}
> +
> +if ![runto_main] {
> + return -1
> +}
> +
> +if {[skip_compile_feature_tests]} {
> + untested "could not find libcc1 shared library"
> + return -1
> +}
> +
> +gdb_test_no_output "compile file -r ${srcdir}/${subdir}/$srcfile2" \
> + "compile file -r"
> +
> +gdb_test "p done" " = 1"
> diff --git a/gdb/testsuite/gdb.base/compile-shlib.c b/gdb/testsuite/gdb.base/compile-shlib.c
> new file mode 100644
> index 0000000..6181af2
> --- /dev/null
> +++ b/gdb/testsuite/gdb.base/compile-shlib.c
> @@ -0,0 +1,26 @@
> +/* This testcase is part of GDB, the GNU debugger.
> +
> + Copyright 2014 Free Software Foundation, Inc.
> +
> + This program is free software; you can redistribute it and/or modify
> + it under the terms of the GNU General Public License as published by
> + the Free Software Foundation; either version 3 of the License, or
> + (at your option) any later version.
> +
> + This program is distributed in the hope that it will be useful,
> + but WITHOUT ANY WARRANTY; without even the implied warranty of
> + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + GNU General Public License for more details.
> +
> + You should have received a copy of the GNU General Public License
> + along with this program. If not, see <http://www.gnu.org/licenses/>. */
> +
> +extern int globalvar;
> +
> +int shlibvar = 10;
> +
> +void
> +shlib_func (void)
> +{
> + globalvar = 1;
> +}
> diff --git a/gdb/testsuite/gdb.base/compile.c b/gdb/testsuite/gdb.base/compile.c
> new file mode 100644
> index 0000000..b48acab
> --- /dev/null
> +++ b/gdb/testsuite/gdb.base/compile.c
> @@ -0,0 +1,130 @@
> +/* This testcase is part of GDB, the GNU debugger.
> +
> + Copyright 2014 Free Software Foundation, Inc.
> +
> + This program is free software; you can redistribute it and/or modify
> + it under the terms of the GNU General Public License as published by
> + the Free Software Foundation; either version 3 of the License, or
> + (at your option) any later version.
> +
> + This program is distributed in the hope that it will be useful,
> + but WITHOUT ANY WARRANTY; without even the implied warranty of
> + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + GNU General Public License for more details.
> +
> + You should have received a copy of the GNU General Public License
> + along with this program. If not, see <http://www.gnu.org/licenses/>. */
> +
> +#define SOME_MACRO 23
> +#define ARG_MACRO(X, Y) ((X) + (Y) - 1)
> +
> +
> +enum enum_type {
> + ONE = 1,
> + TWO = 2
> +};
> +
> +typedef int v4 __attribute__ ((vector_size (16)));
> +
> +union union_type;
> +
> +struct struct_type {
> + char charfield;
> + unsigned char ucharfield;
> + short shortfield;
> + unsigned short ushortfield;
> + int intfield;
> + unsigned int uintfield;
> + unsigned int bitfield : 3;
> + long longfield;
> + unsigned long ulongfield;
> + enum enum_type enumfield;
> + float floatfield;
> + double doublefield;
> + const union union_type *ptrfield;
> + struct struct_type *selffield;
> + int arrayfield[5];
> + _Complex double complexfield;
> + _Bool boolfield;
> + v4 vectorfield;
> +};
> +
> +typedef int inttypedef;
> +
> +union union_type {
> + int intfield;
> + inttypedef typedeffield;
> +};
> +
> +/* volatile provides some coverage of the conversion code. */
> +volatile struct struct_type struct_object;
> +
> +union union_type union_object;
> +
> +
> +enum ulonger_enum_type {
> + REALLY_MINUS_1 = -1UL,
> +};
> +
> +enum ulonger_enum_type ulonger;
> +
> +enum longer_enum_type {
> + MINUS_1 = -1,
> + FORCE_TO_LONG = 1L << ((8 * sizeof (long)) - 2)
> +};
> +
> +enum longer_enum_type longer;
> +
> +int globalvar = 10;
> +
> +static void
> +func_static (int addend)
> +{
> + globalvar += addend;
> +}
> +
> +void
> +func_global (int subtrahend)
> +{
> + globalvar -= subtrahend;
> +}
> +
> +void
> +no_args_or_locals (void)
> +{
> + /* no_args_or_locals breakpoint */
> +}
> +
> +int *intptr;
> +int globalshadow = 10;
> +static int staticshadow = 20;
> +int externed = 7;
> +
> +int
> +main (void)
> +{
> + int localvar = 50;
> + int shadowed = 51;
> + int bound = 3;
> + int unresolved = 10;
> + int globalshadow = 100;
> + int staticshadow = 200;
> + int externed = 9;
> + int f = 0;
> +
> + static int static_local = 77000;
> +
> + {
> + int another_local = 7;
> + int shadowed = 52;
> + extern int unresolved;
> + extern int externed;
> +
> + int vla[bound];
> +
> + func_static (0); /* break-here */
> + no_args_or_locals ();
> + }
> +
> + return 0;
> +}
> diff --git a/gdb/testsuite/gdb.base/compile.exp b/gdb/testsuite/gdb.base/compile.exp
> new file mode 100644
> index 0000000..d0dd791
> --- /dev/null
> +++ b/gdb/testsuite/gdb.base/compile.exp
> @@ -0,0 +1,357 @@
> +# Copyright 2014 Free Software Foundation, Inc.
> +
> +# This program is free software; you can redistribute it and/or modify
> +# it under the terms of the GNU General Public License as published by
> +# the Free Software Foundation; either version 3 of the License, or
> +# (at your option) any later version.
> +#
> +# This program is distributed in the hope that it will be useful,
> +# but WITHOUT ANY WARRANTY; without even the implied warranty of
> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> +# GNU General Public License for more details.
> +#
> +# You should have received a copy of the GNU General Public License
> +# along with this program. If not, see <http://www.gnu.org/licenses/>.
> +
> +standard_testfile .c compile-shlib.c compile-constvar.S compile-nodebug.c
> +
> +get_compiler_info
> +set options {}
> +if [test_compiler_info gcc*] {
> + lappend options additional_flags=-g3
> +}
> +
> +if { ![istarget x86_64-*-* ] || ![is_lp64_target] } {
> + verbose "Skipping x86_64 LOC_CONST test."
> + set srcfile3 ""
> +}
> +
> +set srcfilesoptions [list ${srcfile} ${options}]
> +if { $srcfile3 != "" } {
> + lappend srcfilesoptions $srcfile3 ${options}
> +}
> +lappend srcfilesoptions $srcfile4 "nodebug"
> +if { [eval build_executable_from_specs ${testfile}.exp $testfile {$options} ${srcfilesoptions}] } {
> + return -1
> +}
> +
> +clean_restart ${testfile}
> +
> +#
> +# Test command without an running inferior.
> +#
> +gdb_test "compile code int i=2;" \
> + "The program must be running for the compile command to work.*" \
> + "Test compile code command without running inferior"
> +
> +gdb_test "compile int i=2;" \
> + "The program must be running for the compile command to work.*" \
> + "Test compile command without running inferior"
> +
> +gdb_test "compile file -r ${srcdir}/${subdir}/${testfile}-mod.c" \
> + "The program must be running for the compile command to work.*" \
> + "Test compile file command without running inferior"
> +
> +if ![runto_main] {
> + return -1
> +}
> +
> +if {[skip_compile_feature_tests]} {
> + untested "could not find libcc1 shared library"
> + return -1
> +}
> +
> +#
> +# Test delimiter for code, and arguments.
> +#
> +
> +gdb_test_no_output "compile -- f = 10" \
> + "Test abbreviations and code delimiter"
> +
> +gdb_test "compile f = 10;" ".*= 10;: No such file.*" \
> + "Test abbreviations and code collision"
> +
> +gdb_test_no_output "compile -r -- _gdb_expr(){int i = 5;}" \
> + "Test delimiter with -r"
> +
> +gdb_test_no_output "compile -raw -- _gdb_expr(){int i = 5;}" \
> + "Test delimiter with -raw"
> +
> +gdb_test "compile -- -r _gdb_expr(){int i = 5;}" \
> + ".* error: 'r' undeclared \\(first use in this function\\).*" \
> + "Test delimiter with -r after it"
> +
> +gdb_test "p globalvar" " = 10" "expect 10"
> +
> +gdb_test_no_output "compile code globalvar = 11" \
> + "set variable without trailing semicolon"
> +gdb_test "p globalvar" " = 11" "check variable without trailing semicolon"
> +
> +gdb_test_no_output "compile code globalvar = SOME_MACRO;" \
> + "set variable from macro"
> +gdb_test "p globalvar" " = 23" "expect 23"
> +
> +gdb_test_no_output "compile code globalvar = ARG_MACRO(0, 0);" \
> + "set variable from function-like macro"
> +gdb_test "p globalvar" " = -1" "expect -1"
> +
> +gdb_test_no_output "compile code globalvar = 42;" "set variable"
> +gdb_test "p globalvar" " = 42" "expect 42"
> +
> +gdb_test_no_output "compile code globalvar *= 2;" "modify variable"
> +gdb_test "p globalvar" " = 84" "expect 84"
> +
> +gdb_test_multiple "compile code" "compile code multiline 1" { -re "\r\n>$" {} }
> +gdb_test_multiple "globalvar = 10;" "compile code multiline 2" { -re "\r\n>$" {} }
> +gdb_test_multiple "globalvar *= 2;" "compile code multiline 3" { -re "\r\n>$" {} }
> +gdb_test_no_output "end" "compile code multiline 4"
> +gdb_test "p globalvar" " = 20" "expect 20"
> +
> +gdb_test_no_output "compile file -r ${srcdir}/${subdir}/${testfile}-mod.c" \
> + "use external source file"
> +gdb_test "p globalvar" " = 7" "expect 7"
> +
> +gdb_test_no_output "compile code func_static (2);" "call static function"
> +gdb_test "p globalvar" " = 9" "expect 9"
> +gdb_test_no_output "compile code func_global (1);" "call global function"
> +gdb_test "p globalvar" " = 8" "expect 8"
> +
> +gdb_test_no_output \
> + "compile code globalvar = (sizeof (ulonger) == sizeof (long))" \
> + "compute size of ulonger"
> +gdb_test "p globalvar" " = 1" "check size of ulonger"
> +gdb_test_no_output \
> + "compile code globalvar = (sizeof (longer) == sizeof (long))" \
> + "compute size of longer"
> +gdb_test "p globalvar" " = 1" "check size of longer"
> +gdb_test_no_output "compile code globalvar = MINUS_1"
> +gdb_test "p globalvar" " = -1" "check MINUS_1"
> +
> +gdb_test_no_output "compile code globalvar = static_local"
> +gdb_test "p globalvar" " = 77000" "check static_local"
> +
> +gdb_test_no_output "compile code static int staticvar = 5; intptr = &staticvar" \
> + "keep jit in memory"
> +gdb_test "p *intptr" " = 5" "expect 5"
> +
> +gdb_test "compile code func_doesnotexist ();" "warning: Could not find symbol \"func_doesnotexist\" for .*"
> +
> +gdb_test "compile code *(volatile int *) 0 = 0;" \
> + "The program being debugged was signaled while in a function called from GDB\\.\r\nGDB remains in the frame where the signal was received\\.\r\n.*" \
> + "compile code segfault first"
> +gdb_test "bt" \
> + "\r\n#0 \[^\r\n\]* in _gdb_expr \[^\r\n\]*\r\n#1 <function called from gdb>\r\n.*"
> +
> +set test "p/x \$pc"
> +set infcall_pc 0
> +gdb_test_multiple $test $test {
> + -re " = (0x\[0-9a-f\]+)\r\n$gdb_prompt $" {
> + set infcall_pc $expect_out(1,string)
> + pass $test
> + }
> +}
> +
> +gdb_test "info sym $infcall_pc" "\r\n_gdb_expr .*" "info sym found"
> +gdb_test "return" "\r\n#0 main .*" "return" \
> + "Make _gdb_expr return now\\? \\(y or n\\) " "y"
> +gdb_test "info sym $infcall_pc" "\r\nNo symbol matches .*" "info sym not found"
> +
> +gdb_test_no_output "set unwindonsignal on"
> +gdb_test "compile code *(volatile int *) 0 = 0;" \
> + "The program being debugged was signaled while in a function called from GDB\\.\r\nGDB has restored the context to what it was before the call\\.\r\n.*" \
> + "compile code segfault second"
> +
> +gdb_breakpoint [gdb_get_line_number "break-here"]
> +gdb_continue_to_breakpoint "break-here" ".* break-here .*"
> +
> +gdb_test "p localvar" " = 50" "expect localvar 50"
> +
> +gdb_test_no_output "compile code localvar = 12;" "set localvar"
> +gdb_test "p localvar" " = 12" "expect 12"
> +
> +gdb_test_no_output "compile code localvar *= 2;" "modify localvar"
> +gdb_test "p localvar" " = 24" "expect 24"
> +
> +gdb_test_no_output "compile code localvar = shadowed" \
> + "test shadowing"
> +gdb_test "p localvar" " = 52" "expect 52"
> +
> +gdb_test_no_output "compile code localvar = externed"
> +gdb_test "p localvar" " = 7" "test extern in inner scope"
> +
> +gdb_test_no_output "compile code vla\[2\] = 7"
> +gdb_test "p vla\[2\]" " = 7"
> +gdb_test_no_output \
> + "compile code localvar = (sizeof (vla) == bound * sizeof (vla\[0\]))"
> +gdb_test "p localvar" " = 1"
> +
> +#
> +# Test setting fields and also many different types.
> +#
> +
> +gdb_test_no_output "compile code struct_object.selffield = &struct_object"
> +gdb_test "print struct_object.selffield == &struct_object" " = 1"
> +
> +gdb_test_no_output "compile code struct_object.charfield = 1"
> +gdb_test "print struct_object.charfield" " = 1 '\\\\001'"
> +gdb_test_no_output "compile code struct_object.ucharfield = 1"
> +gdb_test "print struct_object.ucharfield" " = 1 '\\\\001'"
> +
> +foreach {field value} {
> + shortfield -5
> + ushortfield 5
> + intfield -7
> + uintfield 7
> + bitfield 2
> + longfield -9
> + ulongfield 9
> + enumfield ONE
> + floatfield 1
> + doublefield 2
> +} {
> + gdb_test_no_output "compile code struct_object.$field = $value"
> + gdb_test "print struct_object.$field" " = $value"
> +}
> +
> +gdb_test_no_output "compile code struct_object.arrayfield\[2\] = 7"
> +gdb_test "print struct_object.arrayfield" \
> + " = \\{0, 0, 7, 0, 0\\}"
> +
> +gdb_test_no_output "compile code struct_object.complexfield = 7 + 5i"
> +gdb_test "print struct_object.complexfield" " = 7 \\+ 5 \\* I"
> +
> +gdb_test_no_output "compile code struct_object.boolfield = 1"
> +gdb_test "print struct_object.boolfield" " = true"
> +
> +gdb_test_no_output "compile code struct_object.vectorfield\[2\] = 7"
> +gdb_test "print struct_object.vectorfield" \
> + " = \\{0, 0, 7, 0\\}"
> +
> +gdb_test_no_output "compile code union_object.typedeffield = 7"
> +gdb_test "print union_object.typedeffield" " = 7"
> +gdb_test "print union_object.intfield" " = 7"
> +
> +
> +# LOC_UNRESOLVED tests.
> +
> +gdb_test "print unresolved" " = 20"
> +gdb_test "compile code globalvar = unresolved;"
> +gdb_test "print globalvar" " = 20" "print unresolved value"
> +
> +# Test shadowing with global and static variables.
> +
> +gdb_test_no_output "compile code globalshadow += 1;"
> +gdb_test "print globalshadow" " = 101"
> +gdb_test_no_output "compile code extern int globalshadow; globalshadow += 5;"
> +gdb_test "print 'compile.c'::globalshadow" " = 15"
> +gdb_test "print globalshadow" " = 101" "print globalshadow second time"
> +gdb_test_no_output "compile code staticshadow += 2;"
> +gdb_test "print staticshadow" " = 202"
> +# "extern int staticshadow;" cannot access static variable.
> +
> +# Raw code cannot refer to locals.
> +# As it references global variable we need the #pragma.
> +# For #pragma we need multiline input.
> +gdb_test_multiple "compile code -r" "compile code -r multiline 1" { -re "\r\n>$" {} }
> +gdb_test_multiple "#pragma GCC user_expression" "compile code -r multiline 2" { -re "\r\n>$" {} }
> +gdb_test_multiple "void _gdb_expr(void) { globalshadow = 77000; }" "compile code -r multiline 3" { -re "\r\n>$" {} }
> +gdb_test_no_output "end" "compile code -r multiline 4"
> +gdb_test "print 'compile.c'::globalshadow" " = 77000" \
> + "check globalshadow with -r"
> +
> +#
> +# Test the case where the registers structure would not normally have
> +# any fields.
> +#
> +
> +gdb_breakpoint [gdb_get_line_number "no_args_or_locals breakpoint"]
> +gdb_continue_to_breakpoint "no_args_or_locals"
> +
> +gdb_test_no_output "compile code globalvar = 77;" "set variable to 77"
> +gdb_test "p globalvar" " = 77" "expect 77"
> +
> +
> +# Test reference to minimal_symbol, not (full) symbol.
> +
> +gdb_test_no_output "compile code globalvar = func_nodebug (75);" \
> + "call func_nodebug"
> +gdb_test "p globalvar" " = -75" "expect -75"
> +gdb_test_no_output \
> + "compile code int (*funcp) (int) = func_nodebug; globalvar = funcp (76);" \
> + "call func_nodebug indirectly"
> +gdb_test "p globalvar" " = -76" "expect -76"
> +
> +
> +# Test compiled module memory protection.
> +
> +gdb_test_no_output "set debug compile on"
> +gdb_test "compile code static const int readonly = 1; *(int *) &readonly = 2;" \
> + "The program being debugged was signaled while in a function called from GDB\\.\r\nGDB has restored the context to what it was before the call\\.\r\n.*"
> +gdb_test_no_output "set debug compile off"
> +
> +
> +#
> +# Some simple coverage tests.
> +#
> +
> +gdb_test "show debug compile" "Compile debugging is .*"
> +gdb_test "show compile-args" \
> + "Compile command command-line arguments are .*"
> +gdb_test "compile code -z" "Unknown argument.*"
> +
> +gdb_test "set lang java" \
> + "Warning: the current language does not match this frame."
> +gdb_test "compile code globalvar" "No compiler support for this language\."
> +gdb_test_no_output "set lang auto"
> +
> +gdb_test_no_output "compile code union union_type newdecl_u"
> +gdb_test_no_output "compile code struct struct_type newdecl_s"
> +gdb_test_no_output "compile code inttypedef newdecl_i"
> +
> +gdb_test "compile file" \
> + "You must provide a filename for this command.*" \
> + "Test compile file without a filename"
> +gdb_test "compile file -r" \
> + "You must provide a filename with the raw option set.*" \
> + "Test compile file and raw option without a filename"
> +gdb_test "compile file -z" \
> + "Unknown argument.*" \
> + "Test compile file with unknown argument"
> +
> +
> +# LOC_CONST tests.
> +
> +if { $srcfile3 != "" } {
> + gdb_test "p constvar" " = 3"
> + gdb_test "info addr constvar" {Symbol "constvar" is constant\.}
> +
> + gdb_test "compile code globalvar = constvar;"
> + gdb_test "print globalvar" " = 3" "print constvar value"
> +} else {
> + untested "print constvar value"
> +}
> +
> +# Shared library tests.
> +
> +if {[skip_shlib_tests]} {
> + untested "skipping shlib tests"
> + return;
> +}
> +
> +set libbin [standard_output_file ${testfile}-shlib.so]
> +if { [gdb_compile_shlib ${srcdir}/${subdir}/${srcfile2} $libbin {debug}] != ""
> + || [build_executable $testfile ${testfile}-shlib $srcfile \
> + [list debug ldflags=$libbin]] == -1 } {
> + return -1
> +}
> +
> +clean_restart ${testfile}-shlib
> +if ![runto_main] {
> + return -1
> +}
> +
> +gdb_test_no_output "compile code shlib_func ();" "call shared library function"
> +gdb_test "p globalvar" " = 1" "expect 1"
> +
> +gdb_test_no_output "compile code shlibvar += 5;" "modify shared library variable"
> +gdb_test "p shlibvar" " = 15" "expect 15"
> diff --git a/gdb/testsuite/gdb.dwarf2/compile-ops.exp b/gdb/testsuite/gdb.dwarf2/compile-ops.exp
> new file mode 100644
> index 0000000..dd28083
> --- /dev/null
> +++ b/gdb/testsuite/gdb.dwarf2/compile-ops.exp
> @@ -0,0 +1,424 @@
> +# Copyright 2014 Free Software Foundation, Inc.
> +
> +# This program is free software; you can redistribute it and/or modify
> +# it under the terms of the GNU General Public License as published by
> +# the Free Software Foundation; either version 3 of the License, or
> +# (at your option) any later version.
> +#
> +# This program is distributed in the hope that it will be useful,
> +# but WITHOUT ANY WARRANTY; without even the implied warranty of
> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> +# GNU General Public License for more details.
> +#
> +# You should have received a copy of the GNU General Public License
> +# along with this program. If not, see <http://www.gnu.org/licenses/>.
> +
> +# Some coverage testing of DWARF operators for the compiler
> +# integration.
> +
> +load_lib dwarf.exp
> +
> +# This test can only be run on targets which support DWARF-2 and use gas.
> +if {![dwarf2_support]} {
> + return 0
> +}
> +
> +standard_testfile dw2-ifort-parameter.c gdbjit-ops.S
> +
> +#
> +# A port of the pr10770.c test code to the DWARF assembler format.
> +#
> +
> +set assert_tos_non0 {
> + bra 3
> + skip -3
> +}
> +
> +set assert_tos_0 [subst {
> + lit0
> + eq
> + $assert_tos_non0
> +}]
> +
> +set program [subst {
> + lit0
> + nop
> + $assert_tos_0
> + lit1
> + const1u 1
> + eq
> + $assert_tos_non0
> + lit16
> + const2u 16
> + eq
> + $assert_tos_non0
> + lit31
> + const4u 31
> + ne
> + $assert_tos_0
> + lit1
> + neg
> + const1s -1
> + eq
> + $assert_tos_non0
> + lit16
> + neg
> + const2s -16
> + ne
> + $assert_tos_0
> + lit31
> + const4s -31
> + neg
> + ne
> + $assert_tos_0
> + lit7
> + dup
> + plus_uconst 2
> + lit9
> + eq
> + $assert_tos_non0
> + lit7
> + eq
> + $assert_tos_non0
> + lit20
> + lit1
> + drop
> + lit20
> + eq
> + $assert_tos_non0
> + lit17
> + lit19
> + over
> + lit17
> + eq
> + $assert_tos_non0
> + lit19
> + eq
> + $assert_tos_non0
> + lit17
> + eq
> + $assert_tos_non0
> + lit1
> + lit2
> + lit3
> + lit4
> + pick 2
> + lit2
> + eq
> + $assert_tos_non0
> + lit4
> + eq
> + $assert_tos_non0
> + lit3
> + eq
> + $assert_tos_non0
> + pick 0
> + lit2
> + eq
> + $assert_tos_non0
> + lit2
> + eq
> + $assert_tos_non0
> + lit1
> + eq
> + $assert_tos_non0
> + lit6
> + lit12
> + swap
> + lit6
> + eq
> + $assert_tos_non0
> + lit12
> + eq
> + $assert_tos_non0
> + lit7
> + lit8
> + lit9
> + rot
> + lit8
> + eq
> + $assert_tos_non0
> + lit7
> + eq
> + $assert_tos_non0
> + lit9
> + eq
> + $assert_tos_non0
> + lit7
> + abs
> + lit7
> + eq
> + $assert_tos_non0
> + const1s -123
> + abs
> + const1u 123
> + eq
> + $assert_tos_non0
> + lit3
> + lit6
> + and
> + lit2
> + eq
> + $assert_tos_non0
> + lit3
> + lit6
> + or
> + lit7
> + eq
> + $assert_tos_non0
> + lit17
> + lit2
> + minus
> + lit15
> + eq
> + $assert_tos_non0
> + # Divide is signed truncating toward zero.
> + const1s -6
> + const1s -2
> + div
> + lit3
> + eq
> + $assert_tos_non0
> + const1s -7
> + const1s 3
> + div
> + const1s -2
> + eq
> + $assert_tos_non0
> + # Modulo is unsigned.
> + const1s -6
> + const1s -4
> + mod
> + const1s -6
> + eq
> + $assert_tos_non0
> + const1s -6
> + lit4
> + mod
> + lit2
> + eq
> + $assert_tos_non0
> + lit6
> + const1s -4
> + mod
> + lit6
> + eq
> + $assert_tos_non0
> + # Signed modulo can be implemented using 'over over div mul minus'.
> + const1s -6
> + const1s -4
> + over
> + over
> + div
> + mul
> + minus
> + const1s -2
> + eq
> + $assert_tos_non0
> + const1s -7
> + lit3
> + over
> + over
> + div
> + mul
> + minus
> + const1s -1
> + eq
> + $assert_tos_non0
> + lit7
> + const1s -3
> + over
> + over
> + div
> + mul
> + minus
> + lit1
> + eq
> + $assert_tos_non0
> + lit16
> + lit31
> + plus_uconst 1
> + mul
> + const2u 512
> + eq
> + $assert_tos_non0
> + lit5
> + not
> + lit31
> + and
> + lit26
> + eq
> + $assert_tos_non0
> + lit12
> + lit31
> + plus
> + const1u 43
> + eq
> + $assert_tos_non0
> + const1s -6
> + lit2
> + plus
> + const1s -4
> + eq
> + $assert_tos_non0
> + const1s -6
> + plus_uconst 3
> + const1s -3
> + eq
> + $assert_tos_non0
> + lit16
> + lit4
> + shl
> + const2u 256
> + eq
> + $assert_tos_non0
> + lit16
> + lit3
> + shr
> + lit2
> + eq
> + $assert_tos_non0
> + const1s -16
> + lit3
> + shra
> + const1s -2
> + eq
> + $assert_tos_non0
> + lit3
> + lit6
> + xor
> + lit5
> + eq
> + $assert_tos_non0
> + lit3
> + lit6
> + le
> + $assert_tos_non0
> + lit3
> + lit3
> + le
> + $assert_tos_non0
> + lit6
> + lit3
> + le
> + $assert_tos_0
> + lit3
> + lit6
> + lt
> + $assert_tos_non0
> + lit3
> + lit3
> + lt
> + $assert_tos_0
> + lit6
> + lit3
> + lt
> + $assert_tos_0
> + lit3
> + lit6
> + ge
> + $assert_tos_0
> + lit3
> + lit3
> + ge
> + $assert_tos_non0
> + lit6
> + lit3
> + ge
> + $assert_tos_non0
> + lit3
> + lit6
> + gt
> + $assert_tos_0
> + lit3
> + lit3
> + gt
> + $assert_tos_0
> + lit6
> + lit3
> + gt
> + $assert_tos_non0
> + const1s -6
> + lit1
> + shr
> + lit0
> + gt
> + $assert_tos_non0
> + const1s -6
> + lit1
> + shra
> + lit0
> + lt
> + $assert_tos_non0
> + # Finally some result.
> + addr ptr
> +}]
> +
> +# Make some DWARF for the test.
> +set asm_file [standard_output_file $srcfile2]
> +Dwarf::assemble $asm_file {
> + # Creating a CU with 4-byte addresses lets this test link on both
> + # 32- and 64-bit machines.
> + cu { addr_size 4 } {
> +
> + declare_labels int_label
> + extern func_start func_end ptr
> +
> + compile_unit {
> + {name file1.txt}
> + {language @DW_LANG_C}
> + {low_pc func_start addr}
> + {high_pc func_end addr}
> + } {
> + global program
> +
> + int_label: base_type {
> + {name int}
> + {byte_size 4 sdata}
> + {encoding @DW_ATE_signed}
> + }
> +
> + subprogram {
> + {external 1 flag}
> + {name func}
> + {low_pc func_start addr}
> + {high_pc func_end addr}
> + } {
> + formal_parameter {
> + {name param}
> + {variable_parameter 1 flag}
> + {type :$int_label}
> + {location $program SPECIAL_expr}
> + }
> +
> + formal_parameter {
> + {name optimized_out}
> + {variable_parameter 1 flag}
> + {type :$int_label}
> + }
> + }
> + }
> + }
> +}
> +
> +if { [prepare_for_testing ${testfile}.exp ${testfile} \
> + [list $srcfile $asm_file] {nodebug}] } {
> + return -1
> +}
> +
> +if ![runto func] {
> + return -1
> +}
> +
> +if {[skip_compile_feature_tests]} {
> + untested "could not find libcc1 shared library"
> + return -1
> +}
> +
> +# If we have a bug, this will hang.
> +gdb_test_no_output "compile code param"
> +
> +# We can't access optimized-out variables, but their presence should
> +# not affect compilations that don't refer to them.
> +gdb_test "compile code optimized_out" \
> + ".*optimized out.*Compilation failed."
> diff --git a/gdb/testsuite/gdb.threads/compile-tls.c b/gdb/testsuite/gdb.threads/compile-tls.c
> new file mode 100644
> index 0000000..6e08a30
> --- /dev/null
> +++ b/gdb/testsuite/gdb.threads/compile-tls.c
> @@ -0,0 +1,40 @@
> +/* This testcase is part of GDB, the GNU debugger.
> +
> + Copyright 2014 Free Software Foundation, Inc.
> +
> + This program is free software; you can redistribute it and/or modify
> + it under the terms of the GNU General Public License as published by
> + the Free Software Foundation; either version 3 of the License, or
> + (at your option) any later version.
> +
> + This program is distributed in the hope that it will be useful,
> + but WITHOUT ANY WARRANTY; without even the implied warranty of
> + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + GNU General Public License for more details.
> +
> + You should have received a copy of the GNU General Public License
> + along with this program. If not, see <http://www.gnu.org/licenses/>. */
> +
> +#include <pthread.h>
> +
> +__thread int global_scope;
> +
> +static __thread int static_scope;
> +
> +int foo ()
> +{
> + /* Ensure we link against pthreads even with --as-needed. */
> + pthread_testcancel();
> + return 27;
> +}
> +
> +int
> +main (void)
> +{
> + static __thread int local_scope;
> +
> + /* break-here */
> + foo ();
> +
> + return 0;
> +}
> diff --git a/gdb/testsuite/gdb.threads/compile-tls.exp b/gdb/testsuite/gdb.threads/compile-tls.exp
> new file mode 100644
> index 0000000..e9613f5
> --- /dev/null
> +++ b/gdb/testsuite/gdb.threads/compile-tls.exp
> @@ -0,0 +1,42 @@
> +# Copyright 2014 Free Software Foundation, Inc.
> +
> +# This program is free software; you can redistribute it and/or modify
> +# it under the terms of the GNU General Public License as published by
> +# the Free Software Foundation; either version 3 of the License, or
> +# (at your option) any later version.
> +#
> +# This program is distributed in the hope that it will be useful,
> +# but WITHOUT ANY WARRANTY; without even the implied warranty of
> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> +# GNU General Public License for more details.
> +#
> +# You should have received a copy of the GNU General Public License
> +# along with this program. If not, see <http://www.gnu.org/licenses/>. */
> +
> +standard_testfile .c
> +
> +if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" \
> + executable {debug}] != "" } {
> + return -1
> +}
> +
> +clean_restart ${binfile}
> +if ![runto_main] then {
> + fail "Can't run to main"
> + return 0
> +}
> +
> +if {[skip_compile_feature_tests]} {
> + untested "could not find libcc1 shared library"
> + return -1
> +}
> +
> +gdb_test "compile code local_scope = 1" \
> + "warning: .* compiled code."
> +gdb_test "print local_scope" " = 1"
> +gdb_test "compile code static_scope = 2" \
> + "warning: .* compiled code."
> +gdb_test "print static_scope" " = 2"
> +gdb_test "compile code global_scope = 3" \
> + "warning: .* compiled code."
> +gdb_test "print global_scope" " = 3"
> diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp
> index 3125e7a..0fa6ded 100644
> --- a/gdb/testsuite/lib/gdb.exp
> +++ b/gdb/testsuite/lib/gdb.exp
> @@ -2454,6 +2454,23 @@ proc skip_libstdcxx_probe_tests {} {
> return $ok
> }
>
> +# Return 1 if we should skip tests of the "compile" feature.
> +# This must be invoked after the inferior has been started.
> +
> +proc skip_compile_feature_tests {} {
> + global gdb_prompt
> +
> + set result 0
> + gdb_test_multiple "compile code -- ;" "check for working compile command" {
> + "Could not load libcc1.*\r\n$gdb_prompt $" {
> + set result 1
> + }
> + -re "\r\n$gdb_prompt $" {
> + }
> + }
> + return $result
> +}
> +
> # Check whether we're testing with the remote or extended-remote
> # targets.
>