From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 26798 invoked by alias); 16 Jun 2014 09:55:21 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Received: (qmail 26784 invoked by uid 89); 16 Jun 2014 09:55:19 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-1.2 required=5.0 tests=AWL,BAYES_50,KAM_STOCKGEN,RP_MATCHES_RCVD,SPF_HELO_PASS,SPF_PASS,UNSUBSCRIBE_BODY autolearn=no version=3.3.2 X-HELO: mx1.redhat.com Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Mon, 16 Jun 2014 09:55:05 +0000 Received: from int-mx14.intmail.prod.int.phx2.redhat.com (int-mx14.intmail.prod.int.phx2.redhat.com [10.5.11.27]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id s5G9t1Am005721 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Mon, 16 Jun 2014 05:55:01 -0400 Received: from localhost.localdomain (ovpn-112-24.ams2.redhat.com [10.36.112.24]) by int-mx14.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id s5G9sweR024384; Mon, 16 Jun 2014 05:54:59 -0400 Message-ID: <539EBEF2.5010703@redhat.com> Date: Mon, 16 Jun 2014 09:55:00 -0000 From: Phil Muldoon MIME-Version: 1.0 To: gdb-patches@sourceware.org CC: Tom Tromey , "eliz@gnu.org" Subject: Re: (Doc ping [for news and manual]) -- [PATCH 14/14] the "compile" command References: <1400253995-12333-1-git-send-email-tromey@redhat.com> <1400253995-12333-15-git-send-email-tromey@redhat.com> In-Reply-To: <1400253995-12333-15-git-send-email-tromey@redhat.com> Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit X-IsSubscribed: yes X-SW-Source: 2014-06/txt/msg00547.txt.bz2 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 > Jan Kratochvil > Tom Tromey > > * NEWS: Update. > * symtab.h (struct symbol_computed_ops) : 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_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) : New constant. > (struct command_line) : 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 > > * gdb.texinfo (Altering): Update. > (Compiling and Injecting Code): New node. > > 2014-05-16 Phil Muldoon > Jan Kratochvil > Tom Tromey > > * 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 . */ > + > +#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 . */ > + > + > +#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 . */ > + > + > +#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 . */ > + > +#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 . */ > + > +#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 . */ > + > +#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 . */ > + > +#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 . */ > + > +#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 . */ > + > +#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 . */ > + > +#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 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 . */ > + > +#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 > #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 . */ > + > +// 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 . */ > + > +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 . */ > + > +// 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 . */ > + > +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 . */ > + > +#include > +#include > +#include > + > +// 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 . */ > + > +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 . > + > +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 . */ > + > +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 . */ > + > +#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 . > + > +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 \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 . > + > +# 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 . */ > + > +#include > + > +__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 . */ > + > +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. >