Discussion:
[PATCH 0/5] let gdb reuse gcc'c C compiler
Tom Tromey
2014-05-16 15:26:36 UTC
Permalink
Hi!

This patch series is half of a project to let gdb reuse gcc (which
half depends on which list you are seeing this on), so that users can
compile small snippets of code and evaluate them in the current
context of the inferior.

This first series implements this idea for C. A user can compile a
code snippet and it will be inserted into the inferior and evaluated.
Declarations needed by the snippet are supplied by gdb, and there is a
bit of magic so that the snippets can refer to local variables in the
current frame.

The new command allows for arbitrary code to be inserted -- not just
expressions. For example:

(gdb) compile code int i; for (i = 0; i < 3; ++i) printf ("#%d\n", i)
#0
#1
#2

This series supplies a gcc plugin to do most of the work, so that any
gcc crashes -- seen during development due to translation bugs -- do
not also crash gdb.

The interface between gdb and gcc is defined by a few files added to
include/.

There is a new shared library which gdb loads in order to communicate
with the gcc plugin. This library communicates with the gcc plugin
using a simple, ad-hoc RPC mechanism.

This shared library exports a single public function which is used to
instantiate any needed objects. This makes it simple to version the
API and avoid undue synchronization between gcc and gdb.

We think the plugin is best suited to be put into the gcc repository
because it is coupled more tightly to gcc than to gdb.

To try it out, just build gcc and gdb with the patches applied. Then
set your PATH and LD_LIBRARY_PATH to point to the right subdirectories
of the new gcc install directory.

In later series we plan to extend this functionality; either on the
gcc side, say by writing a similar plugin for C++; or on the gdb side,
say by making it possible to compile breakpoint conditions. However,
we haven't yet decided exactly which future projects we will tackle or
in what order.
Tom Tromey
2014-05-16 15:26:37 UTC
Permalink
The gdb plugin handles some aspects of type layout on its own. It
does this because it knows the layout of types, but not the path by
which the layout was determined -- so normal gcc things like
TYPE_PACKED cannot be used.

This patch exposes one bit of stor-layout so it can be used by the
plugin.

2014-05-16 Phil Muldoon <***@redhat.com>
Tom Tromey <***@redhat.com>

* stor-layout.c (finish_bitfield_layout): Now public. Change
argument type to 'tree'.
(finish_record_layout): Update.
* stor-layout.h (finish_bitfield_layout): Declare.
---
gcc/ChangeLog | 8 ++++++++
gcc/stor-layout.c | 12 ++++++------
gcc/stor-layout.h | 1 +
3 files changed, 15 insertions(+), 6 deletions(-)

diff --git a/gcc/stor-layout.c b/gcc/stor-layout.c
index 8fa4dc8..ad057d9 100644
--- a/gcc/stor-layout.c
+++ b/gcc/stor-layout.c
@@ -1931,10 +1931,10 @@ finish_bitfield_representative (tree repr, tree field)
}

/* Compute and set FIELD_DECLs for the underlying objects we should
- use for bitfield access for the structure laid out with RLI. */
+ use for bitfield access for the structure T. */

-static void
-finish_bitfield_layout (record_layout_info rli)
+void
+finish_bitfield_layout (tree t)
{
tree field, prev;
tree repr = NULL_TREE;
@@ -1943,10 +1943,10 @@ finish_bitfield_layout (record_layout_info rli)
we could use the underlying type as hint for the representative
if the bitfield would fit and the representative would not exceed
the union in size. */
- if (TREE_CODE (rli->t) != RECORD_TYPE)
+ if (TREE_CODE (t) != RECORD_TYPE)
return;

- for (prev = NULL_TREE, field = TYPE_FIELDS (rli->t);
+ for (prev = NULL_TREE, field = TYPE_FIELDS (t);
field; field = DECL_CHAIN (field))
{
if (TREE_CODE (field) != FIELD_DECL)
@@ -2033,7 +2033,7 @@ finish_record_layout (record_layout_info rli, int free_p)
finalize_type_size (rli->t);

/* Compute bitfield representatives. */
- finish_bitfield_layout (rli);
+ finish_bitfield_layout (rli->t);

/* Propagate TYPE_PACKED to variants. With C++ templates,
handle_packed_attribute is too early to do this. */
diff --git a/gcc/stor-layout.h b/gcc/stor-layout.h
index 0ff98f8..cd58672 100644
--- a/gcc/stor-layout.h
+++ b/gcc/stor-layout.h
@@ -35,6 +35,7 @@ extern tree rli_size_so_far (record_layout_info);
extern void normalize_rli (record_layout_info);
extern void place_field (record_layout_info, tree);
extern void compute_record_mode (tree);
+extern void finish_bitfield_layout (tree);
extern void finish_record_layout (record_layout_info, int);
extern unsigned int element_precision (const_tree);
extern void finalize_size_functions (void);
--
1.9.0
Jeff Law
2014-05-16 18:27:27 UTC
Permalink
Post by Tom Tromey
The gdb plugin handles some aspects of type layout on its own. It
does this because it knows the layout of types, but not the path by
which the layout was determined -- so normal gcc things like
TYPE_PACKED cannot be used.
This patch exposes one bit of stor-layout so it can be used by the
plugin.
* stor-layout.c (finish_bitfield_layout): Now public. Change
argument type to 'tree'.
(finish_record_layout): Update.
* stor-layout.h (finish_bitfield_layout): Declare.
OK. However, please hold off installing until the entire set is approved.



Jeff
Tom Tromey
2014-05-16 15:26:39 UTC
Permalink
gdb wants to supply any declarations that may be referred to by the
user's code. Hooking into symbol lookup was an efficient way to
accomplish this.

This patch introducing a "binding oracle" that is consulted whenever a
symbol binding is looked up for the first time. The oracle is just a
global function pointer. If it is NULL, no special work is done. It
is called with the identifier to supply and with an enum argument
indicating the kind of binding being requested. The oracle can then
call back into the C front end (via the new functions c_pushtag and
c_bind) to supply a binding; or it can silently do nothing if the
request could not be fulfilled.

The code caches Whether the oracle has been called to avoid repeated
useless queries.

There is a little hack in c_print_identifier to avoid calling the
binding oracle here. This makes debugging gcc in the presence of the
plugin remain relatively sane -- without this, calling debug_tree or
the like can confusingly call into the plugin.

2014-05-16 Phil Muldoon <***@redhat.com>
Tom Tromey <***@redhat.com>

* c-tree.h (enum c_oracle_request): New.
(c_binding_oracle_function): New typedef.
(c_binding_oracle, c_pushtag, c_bind): Declare.
* c-decl.c (c_binding_oracle): New global.
(I_SYMBOL_CHECKED): New macro.
(i_symbol_binding): New function.
(I_SYMBOL_BINDING, I_SYMBOL_DECL): Redefine.
(I_TAG_CHECKED): New macro.
(i_tag_binding): New function.
(I_TAG_BINDING, I_TAG_DECL): Redefine.
(I_LABEL_CHECKED): New macro.
(i_label_binding): New function.
(I_LABEL_BINDING, I_LABEL_DECL): Redefine.
(c_print_identifier): Save and restore c_binding_oracle.
(c_pushtag, c_bind): New functions.
---
gcc/c/ChangeLog | 19 +++++++
gcc/c/c-decl.c | 161 ++++++++++++++++++++++++++++++++++++++++++++++++++------
gcc/c/c-tree.h | 24 +++++++++
3 files changed, 189 insertions(+), 15 deletions(-)

diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c
index d52dcc9..b391add 100644
--- a/gcc/c/c-decl.c
+++ b/gcc/c/c-decl.c
@@ -215,21 +215,6 @@ struct GTY((chain_next ("%h.prev"))) c_binding {
#define B_IN_FILE_SCOPE(b) ((b)->depth == 1 /*file_scope->depth*/)
#define B_IN_EXTERNAL_SCOPE(b) ((b)->depth == 0 /*external_scope->depth*/)

-#define I_SYMBOL_BINDING(node) \
- (((struct lang_identifier *) IDENTIFIER_NODE_CHECK(node))->symbol_binding)
-#define I_SYMBOL_DECL(node) \
- (I_SYMBOL_BINDING(node) ? I_SYMBOL_BINDING(node)->decl : 0)
-
-#define I_TAG_BINDING(node) \
- (((struct lang_identifier *) IDENTIFIER_NODE_CHECK(node))->tag_binding)
-#define I_TAG_DECL(node) \
- (I_TAG_BINDING(node) ? I_TAG_BINDING(node)->decl : 0)
-
-#define I_LABEL_BINDING(node) \
- (((struct lang_identifier *) IDENTIFIER_NODE_CHECK(node))->label_binding)
-#define I_LABEL_DECL(node) \
- (I_LABEL_BINDING(node) ? I_LABEL_BINDING(node)->decl : 0)
-
/* Each C symbol points to three linked lists of c_binding structures.
These describe the values of the identifier in the three different
namespaces defined by the language. */
@@ -245,6 +230,96 @@ struct GTY(()) lang_identifier {
extern char C_SIZEOF_STRUCT_LANG_IDENTIFIER_isnt_accurate
[(sizeof(struct lang_identifier) == C_SIZEOF_STRUCT_LANG_IDENTIFIER) ? 1 : -1];

+/* The binding oracle; see c-tree.h. */
+void (*c_binding_oracle) (enum c_oracle_request, tree identifier);
+
+/* This flag is set on an identifier if we have previously asked the
+ binding oracle for this identifier's symbol binding. */
+#define I_SYMBOL_CHECKED(node) \
+ (TREE_LANG_FLAG_4 (IDENTIFIER_NODE_CHECK (node)))
+
+static inline struct c_binding* *
+i_symbol_binding (tree node)
+{
+ struct lang_identifier *lid
+ = (struct lang_identifier *) IDENTIFIER_NODE_CHECK (node);
+
+ if (lid->symbol_binding == NULL
+ && c_binding_oracle != NULL
+ && !I_SYMBOL_CHECKED (node))
+ {
+ /* Set the "checked" flag first, to avoid infinite recursion
+ when the binding oracle calls back into gcc. */
+ I_SYMBOL_CHECKED (node) = 1;
+ c_binding_oracle (C_ORACLE_SYMBOL, node);
+ }
+
+ return &lid->symbol_binding;
+}
+
+#define I_SYMBOL_BINDING(node) (*i_symbol_binding (node))
+
+#define I_SYMBOL_DECL(node) \
+ (I_SYMBOL_BINDING(node) ? I_SYMBOL_BINDING(node)->decl : 0)
+
+/* This flag is set on an identifier if we have previously asked the
+ binding oracle for this identifier's tag binding. */
+#define I_TAG_CHECKED(node) \
+ (TREE_LANG_FLAG_5 (IDENTIFIER_NODE_CHECK (node)))
+
+static inline struct c_binding **
+i_tag_binding (tree node)
+{
+ struct lang_identifier *lid
+ = (struct lang_identifier *) IDENTIFIER_NODE_CHECK (node);
+
+ if (lid->tag_binding == NULL
+ && c_binding_oracle != NULL
+ && !I_TAG_CHECKED (node))
+ {
+ /* Set the "checked" flag first, to avoid infinite recursion
+ when the binding oracle calls back into gcc. */
+ I_TAG_CHECKED (node) = 1;
+ c_binding_oracle (C_ORACLE_TAG, node);
+ }
+
+ return &lid->tag_binding;
+}
+
+#define I_TAG_BINDING(node) (*i_tag_binding (node))
+
+#define I_TAG_DECL(node) \
+ (I_TAG_BINDING(node) ? I_TAG_BINDING(node)->decl : 0)
+
+/* This flag is set on an identifier if we have previously asked the
+ binding oracle for this identifier's label binding. */
+#define I_LABEL_CHECKED(node) \
+ (TREE_LANG_FLAG_6 (IDENTIFIER_NODE_CHECK (node)))
+
+static inline struct c_binding **
+i_label_binding (tree node)
+{
+ struct lang_identifier *lid
+ = (struct lang_identifier *) IDENTIFIER_NODE_CHECK (node);
+
+ if (lid->label_binding == NULL
+ && c_binding_oracle != NULL
+ && !I_LABEL_CHECKED (node))
+ {
+ /* Set the "checked" flag first, to avoid infinite recursion
+ when the binding oracle calls back into gcc. */
+ I_LABEL_CHECKED (node) = 1;
+ c_binding_oracle (C_ORACLE_LABEL, node);
+ }
+
+ return &lid->label_binding;
+}
+
+#define I_LABEL_BINDING(node) (*i_label_binding (node))
+
+#define I_LABEL_DECL(node) \
+ (I_LABEL_BINDING(node) ? I_LABEL_BINDING(node)->decl : 0)
+
/* The resulting tree type. */

union GTY((desc ("TREE_CODE (&%h.generic) == IDENTIFIER_NODE"),
@@ -611,6 +686,12 @@ decl_jump_unsafe (tree decl)
void
c_print_identifier (FILE *file, tree node, int indent)
{
+ void (*save) (enum c_oracle_request, tree identifier);
+
+ // This makes debugging much more sane.
+ save = c_binding_oracle;
+ c_binding_oracle = NULL;
+
print_node (file, "symbol", I_SYMBOL_DECL (node), indent + 4);
print_node (file, "tag", I_TAG_DECL (node), indent + 4);
print_node (file, "label", I_LABEL_DECL (node), indent + 4);
@@ -621,6 +702,8 @@ c_print_identifier (FILE *file, tree node, int indent)
fprintf (file, "rid " HOST_PTR_PRINTF " \"%s\"",
(void *) rid, IDENTIFIER_POINTER (rid));
}
+
+ c_binding_oracle = save;
}

/* Establish a binding between NAME, an IDENTIFIER_NODE, and DECL,
@@ -1485,6 +1568,54 @@ pushtag (location_t loc, tree name, tree type)
}
}
}
+
+/* An exported interface to pushtag. This is used by the gdb plugin's
+ binding oracle to introduce a new tag binding. */
+
+void
+c_pushtag (location_t loc, tree name, tree type)
+{
+ pushtag (loc, name, type);
+}
+
+/* An exported interface to bind a declaration. LOC is the location
+ to use. DECL is the declaration to bind. The decl's name is used
+ to determine how it is bound. If DECL is a VAR_DECL, then
+ IS_GLOBAL determines whether the decl is put into the global (file
+ and external) scope or the current function's scope; if DECL is not
+ a VAR_DECL then it is always put into the file scope. */
+
+void
+c_bind (location_t loc, tree decl, bool is_global)
+{
+ struct c_scope *scope;
+ bool nested = false;
+
+ if (TREE_CODE (decl) != VAR_DECL || current_function_scope == NULL)
+ {
+ /* Types and functions are always considered to be global. */
+ scope = file_scope;
+ DECL_EXTERNAL (decl) = 1;
+ TREE_PUBLIC (decl) = 1;
+ }
+ else if (is_global)
+ {
+ /* Also bind it into the external scope. */
+ bind (DECL_NAME (decl), decl, external_scope, true, false, loc);
+ nested = true;
+ scope = file_scope;
+ DECL_EXTERNAL (decl) = 1;
+ TREE_PUBLIC (decl) = 1;
+ }
+ else
+ {
+ DECL_CONTEXT (decl) = current_function_decl;
+ TREE_PUBLIC (decl) = 0;
+ scope = current_function_scope;
+ }
+
+ bind (DECL_NAME (decl), decl, scope, false, nested, loc);
+}

/* Subroutine of compare_decls. Allow harmless mismatches in return
and argument types provided that the type modes match. This function
diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h
index e7dcb35..9370fa6 100644
--- a/gcc/c/c-tree.h
+++ b/gcc/c/c-tree.h
@@ -665,12 +665,36 @@ extern int current_function_returns_abnormally;
extern enum machine_mode c_default_pointer_mode;

/* In c-decl.c */
+
+/* Tell the binding oracle what kind of binding we are looking for. */
+
+enum c_oracle_request
+{
+ C_ORACLE_SYMBOL,
+ C_ORACLE_TAG,
+ C_ORACLE_LABEL
+};
+
+/* If this is non-NULL, then it is a "binding oracle" which can lazily
+ create bindings when needed by the C compiler. The oracle is told
+ the name and type of the binding to create. It can call pushdecl
+ or the like to ensure the binding is visible; or do nothing,
+ leaving the binding untouched. c-decl.c takes note of when the
+ oracle has been called and will not call it again if it fails to
+ create a given binding. */
+
+typedef void c_binding_oracle_function (enum c_oracle_request, tree identifier);
+
+extern c_binding_oracle_function *c_binding_oracle;
+
extern void c_finish_incomplete_decl (tree);
extern void c_write_global_declarations (void);
extern tree c_omp_reduction_id (enum tree_code, tree);
extern tree c_omp_reduction_decl (tree);
extern tree c_omp_reduction_lookup (tree, tree);
extern tree c_check_omp_declare_reduction_r (tree *, int *, void *);
+extern void c_pushtag (location_t, tree, tree);
+extern void c_bind (location_t, tree, bool);

/* In c-errors.c */
extern void pedwarn_c90 (location_t, int opt, const char *, ...) ATTRIBUTE_GCC_DIAG(3,4);
--
1.9.0
Jeff Law
2014-05-16 19:12:45 UTC
Permalink
Post by Tom Tromey
gdb wants to supply any declarations that may be referred to by the
user's code. Hooking into symbol lookup was an efficient way to
accomplish this.
This patch introducing a "binding oracle" that is consulted whenever a
symbol binding is looked up for the first time. The oracle is just a
global function pointer. If it is NULL, no special work is done. It
is called with the identifier to supply and with an enum argument
indicating the kind of binding being requested. The oracle can then
call back into the C front end (via the new functions c_pushtag and
c_bind) to supply a binding; or it can silently do nothing if the
request could not be fulfilled.
The code caches Whether the oracle has been called to avoid repeated
useless queries.
There is a little hack in c_print_identifier to avoid calling the
binding oracle here. This makes debugging gcc in the presence of the
plugin remain relatively sane -- without this, calling debug_tree or
the like can confusingly call into the plugin.
* c-tree.h (enum c_oracle_request): New.
(c_binding_oracle_function): New typedef.
(c_binding_oracle, c_pushtag, c_bind): Declare.
* c-decl.c (c_binding_oracle): New global.
(I_SYMBOL_CHECKED): New macro.
(i_symbol_binding): New function.
(I_SYMBOL_BINDING, I_SYMBOL_DECL): Redefine.
(I_TAG_CHECKED): New macro.
(i_tag_binding): New function.
(I_TAG_BINDING, I_TAG_DECL): Redefine.
(I_LABEL_CHECKED): New macro.
(i_label_binding): New function.
(I_LABEL_BINDING, I_LABEL_DECL): Redefine.
(c_print_identifier): Save and restore c_binding_oracle.
(c_pushtag, c_bind): New functions.
---
void
c_print_identifier (FILE *file, tree node, int indent)
{
+ void (*save) (enum c_oracle_request, tree identifier);
+
+ // This makes debugging much more sane.
+ save = c_binding_oracle;
+ c_binding_oracle = NULL;
+
Just a nit. C-style comment would be appreciated. It might also help
to clarify what "much more sane" really means here.

Otherwise, it looks OK to me.

jeff
Tom Tromey
2014-06-05 14:38:15 UTC
Permalink
Jeff> Just a nit. C-style comment would be appreciated. It might also help
Jeff> to clarify what "much more sane" really means here.

I made this change locally.
The new comment reads:

/* Temporarily hide any binding oracle. Without this, calls to
debug_tree from the debugger will end up calling into the oracle,
making for a confusing debug session. As the oracle isn't needed
here for normal operation, it's simplest to suppress it. */

Tom
Tom Tromey
2014-05-16 15:26:40 UTC
Permalink
The gcc plugin is split into two parts. One part is an ordinary gcc
plugin. The other part is a shared library that is loaded by gdb.

This patch adds some files that define the interface exported by this
shared library to gdb. These files also define the internal API by
which the gdb- and gcc-sides communicate.

These files will be kept in sync between gcc and gdb like much of
include/.

The exported API has been intentionally kept very simple. In
particular only a single function is exported from the gdb-side
library; symbol visibility is used to hide everything else. This
exported symbol is a function which is called to return a structure
holding function pointers that gdb then uses. This structure is
versioned so that changes can be made without necessarily requiring a
simultaneous gdb upgrade.

Note that the C compiler API is broken out separately. This lets us
extend it to other GCC front ends as desired. We plan to investigate
C++ in the future.

2014-05-16 Phil Muldoon <***@redhat.com>
Jan Kratochvil <***@redhat.com>
Tom Tromey <***@redhat.com>

* gcc-c-fe.def: New file.
* gcc-c-interface.h: New file.
* gcc-interface.h: New file.
---
include/ChangeLog | 8 ++
include/gcc-c-fe.def | 195 ++++++++++++++++++++++++++++++++++++++++
include/gcc-c-interface.h | 220 ++++++++++++++++++++++++++++++++++++++++++++++
include/gcc-interface.h | 120 +++++++++++++++++++++++++
4 files changed, 543 insertions(+)
create mode 100644 include/gcc-c-fe.def
create mode 100644 include/gcc-c-interface.h
create mode 100644 include/gcc-interface.h

diff --git a/include/gcc-c-fe.def b/include/gcc-c-fe.def
new file mode 100644
index 0000000..dc5a41a
--- /dev/null
+++ b/include/gcc-c-fe.def
@@ -0,0 +1,195 @@
+/* Interface between GCC C FE and GDB -*- c -*-
+
+ Copyright (C) 2014 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+
+
+/* Create a new "decl" in GCC. A decl is a declaration, basically a
+ kind of symbol.
+
+ NAME is the name of the new symbol. SYM_KIND is the kind of
+ symbol being requested. SYM_TYPE is the new symbol's C type;
+ except for labels, where this is not meaningful and should be
+ zero. If SUBSTITUTION_NAME is not NULL, then a reference to this
+ decl in the source will later be substituted with a dereference
+ of a variable of the given name. Otherwise, for symbols having
+ an address (e.g., functions), ADDRESS is the address. FILENAME
+ and LINE_NUMBER refer to the symbol's source location. If this
+ is not known, FILENAME can be NULL and LINE_NUMBER can be 0.
+ This function returns the new decl. */
+
+GCC_METHOD7 (gcc_decl, build_decl,
+ const char */* name */,
+ enum gcc_c_symbol_kind /* sym_kind */,
+ gcc_type /* sym_type */,
+ const char */* substitution_name */,
+ gcc_address /* address */,
+ const char */* filename */,
+ unsigned int /* line_number */)
+
+/* Insert a GCC decl into the symbol table. DECL is the decl to
+ insert. IS_GLOBAL is true if this is an outermost binding, and
+ false if it is a possibly-shadowing binding. */
+
+GCC_METHOD2 (int /* bool */, bind, gcc_decl /* decl */,
+ int /* bool */ /* is_global */)
+
+/* Insert a tagged type into the symbol table. NAME is the tag name
+ of the type and TAGGED_TYPE is the type itself. TAGGED_TYPE must
+ be either a struct, union, or enum type, as these are the only
+ types that have tags. FILENAME and LINE_NUMBER refer to the type's
+ source location. If this is not known, FILENAME can be NULL and
+ LINE_NUMBER can be 0. */
+
+GCC_METHOD4 (int /* bool */, tagbind,
+ const char */* name */,
+ gcc_type /* tagged_type */,
+ const char * /* filename */,
+ unsigned int /* line_number */)
+
+/* Return the type of a pointer to a given base type. */
+
+GCC_METHOD1 (gcc_type, build_pointer_type,
+ gcc_type /* base_type */)
+
+/* Create a new 'struct' type. Initially it has no fields. */
+
+GCC_METHOD0 (gcc_type, build_record_type)
+
+/* Create a new 'union' type. Initially it has no fields. */
+
+GCC_METHOD0 (gcc_type, build_union_type)
+
+/* Add a field to a struct or union type. FIELD_NAME is the field's
+ name. FIELD_TYPE is the type of the field. BITSIZE and BITPOS
+ indicate where in the struct the field occurs. */
+
+GCC_METHOD5 (int /* bool */, build_add_field,
+ gcc_type /* record_or_union_type */,
+ const char */* field_name */,
+ gcc_type /* field_type */,
+ unsigned long /* bitsize */,
+ unsigned long /* bitpos */)
+
+/* After all the fields have been added to a struct or union, the
+ struct or union type must be "finished". This does some final
+ cleanups in GCC. */
+
+GCC_METHOD2 (int /* bool */, finish_record_or_union,
+ gcc_type /* record_or_union_type */,
+ unsigned long /* size_in_bytes */)
+
+/* Create a new 'enum' type. The new type initially has no
+ associated constants. */
+
+GCC_METHOD1 (gcc_type, build_enum_type,
+ gcc_type /* underlying_int_type */)
+
+/* Add a new constant to an enum type. NAME is the constant's
+ name and VALUE is its value. */
+
+GCC_METHOD3 (int /* bool */, build_add_enum_constant,
+ gcc_type /* enum_type */,
+ const char */* name */,
+ unsigned long /* value */)
+
+/* After all the constants have been added to an enum, the type must
+ be "finished". This does some final cleanups in GCC. */
+
+GCC_METHOD1 (int /* bool */, finish_enum_type, gcc_type /* enum_type */)
+
+/* Create a new function type. RETURN_TYPE is the type returned by
+ the function, and ARGUMENT_TYPES is a vector, of length NARGS, of
+ the argument types. IS_VARARGS is true if the function is
+ varargs. */
+
+GCC_METHOD3 (gcc_type, build_function_type,
+ gcc_type /* return_type */,
+ const struct gcc_type_array * /* argument_types */,
+ int /* bool */ /* is_varargs */)
+
+/* Return an integer type with the given properties. */
+
+GCC_METHOD2 (gcc_type, int_type,
+ int /* bool */ /* is_unsigned */,
+ unsigned long /* size_in_bytes */)
+
+/* Return a floating point type with the given properties. */
+
+GCC_METHOD1 (gcc_type, float_type,
+ unsigned long /* size_in_bytes */)
+
+/* Return the 'void' type. */
+
+GCC_METHOD0 (gcc_type, void_type)
+
+/* Return the 'bool' type. */
+
+GCC_METHOD0 (gcc_type, bool_type)
+
+/* Create a new array type. If NUM_ELEMENTS is -1, then the array
+ is assumed to have an unknown length. */
+
+GCC_METHOD2 (gcc_type, build_array_type,
+ gcc_type /* element_type */,
+ int /* num_elements */)
+
+/* Create a new variably-sized array type. UPPER_BOUND_NAME is the
+ name of a local variable that holds the upper bound of the array;
+ it is one less than the array size. */
+
+GCC_METHOD2 (gcc_type, build_vla_array_type,
+ gcc_type /* element_type */,
+ const char * /* upper_bound_name */)
+
+/* Return a qualified variant of a given base type. QUALIFIERS says
+ which qualifiers to use; it is composed of or'd together
+ constants from 'enum gcc_qualifiers'. */
+
+GCC_METHOD2 (gcc_type, build_qualified_type,
+ gcc_type /* unqualified_type */,
+ enum gcc_qualifiers /* qualifiers */)
+
+/* Build a complex type given its element type. */
+
+GCC_METHOD1 (gcc_type, build_complex_type,
+ gcc_type /* element_type */)
+
+/* Build a vector type given its element type and number of
+ elements. */
+
+GCC_METHOD2 (gcc_type, build_vector_type,
+ gcc_type /* element_type */,
+ int /* num_elements */)
+
+/* Build a constant. NAME is the constant's name and VALUE is its
+ value. FILENAME and LINE_NUMBER refer to the type's source
+ location. If this is not known, FILENAME can be NULL and
+ LINE_NUMBER can be 0. */
+
+GCC_METHOD5 (int /* bool */, build_constant,
+ gcc_type /* type */,
+ const char */* name */,
+ unsigned long /* value */,
+ const char * /* filename */,
+ unsigned int /* line_number */)
+
+/* Emit an error and return an error type object. */
+
+GCC_METHOD1 (gcc_type, error,
+ const char */* message */)
diff --git a/include/gcc-c-interface.h b/include/gcc-c-interface.h
new file mode 100644
index 0000000..6cf81d2
--- /dev/null
+++ b/include/gcc-c-interface.h
@@ -0,0 +1,220 @@
+/* Interface between GCC C FE and GDB
+
+ Copyright (C) 2014 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifndef GCC_C_INTERFACE_H
+#define GCC_C_INTERFACE_H
+
+#include "gcc-interface.h"
+
+/* This header defines the interface to the GCC API. It must be both
+ valid C and valid C++, because it is included by both programs. */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Forward declaration. */
+
+struct gcc_c_context;
+
+/*
+ * Definitions and declarations for the C front end.
+ */
+
+/* Defined versions of the C front-end API. */
+
+enum gcc_c_api_version
+{
+ GCC_C_FE_VERSION_0 = 0
+};
+
+/* Qualifiers. */
+
+enum gcc_qualifiers
+{
+ GCC_QUALIFIER_CONST = 1,
+ GCC_QUALIFIER_VOLATILE = 2,
+ GCC_QUALIFIER_RESTRICT = 4
+};
+
+/* This enumerates the kinds of decls that GDB can create. */
+
+enum gcc_c_symbol_kind
+{
+ /* A function. */
+
+ GCC_C_SYMBOL_FUNCTION,
+
+ /* A variable. */
+
+ GCC_C_SYMBOL_VARIABLE,
+
+ /* A typedef. */
+
+ GCC_C_SYMBOL_TYPEDEF,
+
+ /* A label. */
+
+ GCC_C_SYMBOL_LABEL
+};
+
+/* This enumerates the types of symbols that GCC might request from
+ GDB. */
+
+enum gcc_c_oracle_request
+{
+ /* An ordinary symbol -- a variable, function, typedef, or enum
+ constant. */
+
+ GCC_C_ORACLE_SYMBOL,
+
+ /* A struct, union, or enum tag. */
+
+ GCC_C_ORACLE_TAG,
+
+ /* A label. */
+
+ GCC_C_ORACLE_LABEL
+};
+
+/* The type of the function called by GCC to ask GDB for a symbol's
+ definition. DATUM is an arbitrary value supplied when the oracle
+ function is registered. CONTEXT is the GCC context in which the
+ request is being made. REQUEST specifies what sort of symbol is
+ being requested, and IDENTIFIER is the name of the symbol. */
+
+typedef void gcc_c_oracle_function (void *datum,
+ struct gcc_c_context *context,
+ enum gcc_c_oracle_request request,
+ const char *identifier);
+
+/* The type of the function called by GCC to ask GDB for a symbol's
+ address. This should return 0 if the address is not known. */
+
+typedef gcc_address gcc_c_symbol_address_function (void *datum,
+ struct gcc_c_context *ctxt,
+ const char *identifier);
+
+/* An array of types used for creating a function type. */
+
+struct gcc_type_array
+{
+ /* Number of elements. */
+
+ int n_elements;
+
+ /* The elements. */
+
+ gcc_type *elements;
+};
+
+/* The vtable used by the C front end. */
+
+struct gcc_c_fe_vtable
+{
+ /* The version of the C interface. The value is one of the
+ gcc_c_api_version constants. */
+
+ unsigned int c_version;
+
+ /* Set the callbacks for this context.
+
+ The binding oracle is called whenever the C parser needs to look
+ up a symbol. This gives the caller a chance to lazily
+ instantiate symbols using other parts of the gcc_c_fe_interface
+ API.
+
+ The address oracle is called whenever the C parser needs to look
+ up a symbol. This is only called for symbols not provided by the
+ symbol oracle -- that is, just built-in functions where GCC
+ provides the declaration.
+
+ DATUM is an arbitrary piece of data that is passed back verbatim
+ to the callbakcs in requests. */
+
+ void (*set_callbacks) (struct gcc_c_context *self,
+ gcc_c_oracle_function *binding_oracle,
+ gcc_c_symbol_address_function *address_oracle,
+ void *datum);
+
+#define GCC_METHOD0(R, N) \
+ R (*N) (struct gcc_c_context *);
+#define GCC_METHOD1(R, N, A) \
+ R (*N) (struct gcc_c_context *, A);
+#define GCC_METHOD2(R, N, A, B) \
+ R (*N) (struct gcc_c_context *, A, B);
+#define GCC_METHOD3(R, N, A, B, C) \
+ R (*N) (struct gcc_c_context *, A, B, C);
+#define GCC_METHOD4(R, N, A, B, C, D) \
+ R (*N) (struct gcc_c_context *, A, B, C, D);
+#define GCC_METHOD5(R, N, A, B, C, D, E) \
+ R (*N) (struct gcc_c_context *, A, B, C, D, E);
+#define GCC_METHOD7(R, N, A, B, C, D, E, F, G) \
+ R (*N) (struct gcc_c_context *, A, B, C, D, E, F, G);
+
+#include "gcc-c-fe.def"
+
+#undef GCC_METHOD0
+#undef GCC_METHOD1
+#undef GCC_METHOD2
+#undef GCC_METHOD3
+#undef GCC_METHOD4
+#undef GCC_METHOD5
+#undef GCC_METHOD7
+
+};
+
+/* The C front end object. */
+
+struct gcc_c_context
+{
+ /* Base class. */
+
+ struct gcc_base_context base;
+
+ /* Our vtable. This is a separate field because this is simpler
+ than implementing a vtable inheritance scheme in C. */
+
+ const struct gcc_c_fe_vtable *c_ops;
+};
+
+/* The name of the .so that the compiler builds. We dlopen this
+ later. */
+
+#define GCC_C_FE_LIBCC libcc1.so
+
+/* The compiler exports a single initialization function. This macro
+ holds its name as a symbol. */
+
+#define GCC_C_FE_CONTEXT gcc_c_fe_context
+
+/* The type of the initialization function. The caller passes in the
+ desired base version and desired C-specific version. If the
+ request can be satisfied, a compatible gcc_context object will be
+ returned. Otherwise, the function returns NULL. */
+
+typedef struct gcc_c_context *gcc_c_fe_context_function
+ (enum gcc_base_api_version,
+ enum gcc_c_api_version);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GCC_C_INTERFACE_H */
diff --git a/include/gcc-interface.h b/include/gcc-interface.h
new file mode 100644
index 0000000..7131727
--- /dev/null
+++ b/include/gcc-interface.h
@@ -0,0 +1,120 @@
+/* Generic interface between GCC and GDB
+
+ Copyright (C) 2014 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifndef GCC_INTERFACE_H
+#define GCC_INTERFACE_H
+
+/* This header defines the interface to the GCC API. It must be both
+ valid C and valid C++, because it is included by both programs. */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Opaque typedefs for objects passed through the interface. */
+
+typedef unsigned long long gcc_type;
+typedef unsigned long long gcc_decl;
+
+/* An address in the inferior. */
+
+typedef unsigned long long gcc_address;
+
+/* Forward declaration. */
+
+struct gcc_base_context;
+
+/* Defined versions of the generic API. */
+
+enum gcc_base_api_version
+{
+ GCC_FE_VERSION_0 = 0
+};
+
+/* The operations defined by the GCC base API. This is the vtable for
+ the real context structure which is passed around.
+
+ The "base" API is concerned with basics shared by all compiler
+ front ends: setting command-line arguments, the file names, etc.
+
+ Front-end-specific interfaces inherit from this one. */
+
+struct gcc_base_vtable
+{
+ /* The actual version implemented in this interface. This field can
+ be relied on not to move, so users can always check it if they
+ desire. The value is one of the gcc_base_api_version constants.
+ */
+
+ unsigned int version;
+
+ /* Set the compiler's command-line options for the next compilation.
+ The arguments are copied by GCC. ARGV need not be
+ NULL-terminated. The arguments must be set separately for each
+ compilation; that is, after a compile is requested, the
+ previously-set arguments cannot be reused. */
+
+ void (*set_arguments) (struct gcc_base_context *self, int argc, char **argv);
+
+ /* Set the file name of the program to compile. The string is
+ copied by the method implementation, but the caller must
+ guarantee that the file exists through the compilation. */
+
+ void (*set_source_file) (struct gcc_base_context *self, const char *file);
+
+ /* Set a callback to use for printing error messages. DATUM is
+ passed through to the callback unchanged. */
+
+ void (*set_print_callback) (struct gcc_base_context *self,
+ void (*print_function) (void *datum,
+ const char *message),
+ void *datum);
+
+ /* Perform the compilation. FILENAME is the name of the resulting
+ object file. VERBOSE can be set to cause GCC to print some
+ information as it works. Returns true on success, false on
+ error. */
+
+ int /* bool */ (*compile) (struct gcc_base_context *self,
+ const char *filename,
+ int /* bool */ verbose);
+
+ /* Destroy this object. */
+
+ void (*destroy) (struct gcc_base_context *self);
+};
+
+/* The GCC object. */
+
+struct gcc_base_context
+{
+ /* The virtual table. */
+
+ const struct gcc_base_vtable *ops;
+};
+
+/* The name of the dummy wrapper function generated by gdb. */
+
+#define GCC_FE_WRAPPER_FUNCTION "_gdb_expr"
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GCC_INTERFACE_H */
--
1.9.0
Jeff Law
2014-05-22 12:52:05 UTC
Permalink
Post by Tom Tromey
* gcc-c-fe.def: New file.
* gcc-c-interface.h: New file.
* gcc-interface.h: New file.
---
+GCC_METHOD7 (gcc_decl, build_decl,
+ const char */* name */,
+ enum gcc_c_symbol_kind /* sym_kind */,
+ gcc_type /* sym_type */,
+ const char */* substitution_name */,
+ gcc_address /* address */,
+ const char */* filename */,
+ unsigned int /* line_number */)

I must say that I hate the embedded comments in the signatures.
Especially when you end up with something like:

const char */* name */,

My brain just doesn't parse it.

const char * /* name */

is marginally better, but I still don't like it.

const char *, /* name */

Parses better as long as every argument is on a separate line. But I
still don't like it...

I'm curious how others feel about this.

All these files say they're part of GDB, not sure if that was
intentional. Obviously a nit.

Otherwise it's pretty reasonable. If we could come up with a better way
to handle the signatures, then I think this part is good to go.

jeff
Jakub Jelinek
2014-05-22 13:16:35 UTC
Permalink
Post by Tom Tromey
Post by Tom Tromey
* gcc-c-fe.def: New file.
* gcc-c-interface.h: New file.
* gcc-interface.h: New file.
---
+GCC_METHOD7 (gcc_decl, build_decl,
+ const char */* name */,
+ enum gcc_c_symbol_kind /* sym_kind */,
+ gcc_type /* sym_type */,
+ const char */* substitution_name */,
+ gcc_address /* address */,
+ const char */* filename */,
+ unsigned int /* line_number */)
I must say that I hate the embedded comments in the signatures.
Why it can't be:
GCC_METHOD7 (gcc_decl, build_decl,
const char *name,
enum gfc_c_symbol_kind sym_kind,
...
i.e. provide comments in the form of argument names
(sure, you can't use bool for the name of the parameter then...).

Jakub
Jeff Law
2014-05-22 15:13:46 UTC
Permalink
Post by Tom Tromey
Post by Tom Tromey
Post by Tom Tromey
* gcc-c-fe.def: New file.
* gcc-c-interface.h: New file.
* gcc-interface.h: New file.
---
+GCC_METHOD7 (gcc_decl, build_decl,
+ const char */* name */,
+ enum gcc_c_symbol_kind /* sym_kind */,
+ gcc_type /* sym_type */,
+ const char */* substitution_name */,
+ gcc_address /* address */,
+ const char */* filename */,
+ unsigned int /* line_number */)
I must say that I hate the embedded comments in the signatures.
GCC_METHOD7 (gcc_decl, build_decl,
const char *name,
enum gfc_c_symbol_kind sym_kind,
...
i.e. provide comments in the form of argument names
(sure, you can't use bool for the name of the parameter then...).
No idea. I'd assumed they had it in a comment rather than in the
signature for a reason.

jeff
Tom Tromey
2014-06-04 20:39:29 UTC
Permalink
Post by Tom Tromey
+GCC_METHOD7 (gcc_decl, build_decl,
+ const char */* name */,
+ enum gcc_c_symbol_kind /* sym_kind */,
+ gcc_type /* sym_type */,
+ const char */* substitution_name */,
+ gcc_address /* address */,
+ const char */* filename */,
+ unsigned int /* line_number */)
I must say that I hate the embedded comments in the signatures.
It's not so bad with colorizing but not everybody likes fruit salad. I
can see how it would be pretty painful without.

Jakub> Why it can't be:
Jakub> GCC_METHOD7 (gcc_decl, build_decl,
Jakub> const char *name,
Jakub> enum gfc_c_symbol_kind sym_kind,
Jakub> ...
Jakub> i.e. provide comments in the form of argument names
Jakub> (sure, you can't use bool for the name of the parameter then...).

It's important that just the types are there.
For example the .def file is used to instantiate C++ templates:

#define GCC_METHOD7(R, N, A, B, C, D, E, F, G) \
rpc<R, cc1_plugin::N, A, B, C, D, E, F, G>,

Here we can't have a parameter name.


I chose this commenting approach since it named the parameters, albeit
in comments.

The "/* bool */" comments are there because gdb doesn't have a bool
type, but it still seemed worthwhile to document the intent.


I could drop the names and extend the various introductory comments to
explain argument ordering. What do you think of that?

Tom
Jeff Law
2014-06-05 19:23:37 UTC
Permalink
Post by Tom Tromey
Post by Tom Tromey
+GCC_METHOD7 (gcc_decl, build_decl,
+ const char */* name */,
+ enum gcc_c_symbol_kind /* sym_kind */,
+ gcc_type /* sym_type */,
+ const char */* substitution_name */,
+ gcc_address /* address */,
+ const char */* filename */,
+ unsigned int /* line_number */)
I must say that I hate the embedded comments in the signatures.
It's not so bad with colorizing but not everybody likes fruit salad. I
can see how it would be pretty painful without.
Yea, maybe I need different colors, but anytime something colorizes my
first reaction is to get annoyed because I can't find what I'm looking
for. Probably a consequence of my white-on-black terminals not playing
well with the default colors.

[ OK, not entirely true, when looking at diffs a trailing whitespace
gets colorized, so I tend not to have those leak through in my own
patches anymore. ]
Post by Tom Tromey
Jakub> GCC_METHOD7 (gcc_decl, build_decl,
Jakub> const char *name,
Jakub> enum gfc_c_symbol_kind sym_kind,
Jakub> ...
Jakub> i.e. provide comments in the form of argument names
Jakub> (sure, you can't use bool for the name of the parameter then...).
It's important that just the types are there.
#define GCC_METHOD7(R, N, A, B, C, D, E, F, G) \
rpc<R, cc1_plugin::N, A, B, C, D, E, F, G>,
Here we can't have a parameter name.
I chose this commenting approach since it named the parameters, albeit
in comments.
The "/* bool */" comments are there because gdb doesn't have a bool
type, but it still seemed worthwhile to document the intent.
I could drop the names and extend the various introductory comments to
explain argument ordering. What do you think of that?
Seems reasonable to me.

jeff
Jakub Jelinek
2014-06-05 19:30:39 UTC
Permalink
Post by Jeff Law
Post by Tom Tromey
+GCC_METHOD7 (gcc_decl, build_decl,
+ const char */* name */,
+ enum gcc_c_symbol_kind /* sym_kind */,
+ gcc_type /* sym_type */,
+ const char */* substitution_name */,
+ gcc_address /* address */,
+ const char */* filename */,
+ unsigned int /* line_number */)
[ OK, not entirely true, when looking at diffs a trailing whitespace
gets colorized, so I tend not to have those leak through in my own
patches anymore. ]
Another possibility would be to give the macros twice as many arguments
as there are parameters and just through the odd arguments away when
expanding to the template parameters. That would mean you write
GCC_METHOD7 (gcc_decl, build_decl,
const char *, name,
enum gcc_c_symbol_kind, sym_kind,
const char *, substitution_name,
gcc_address, address,
const char *, filename,
unsigned int, line_number);
though it isn't very nice either, guess I'm bikeshedding... ;)

Jakub
Tom Tromey
2014-06-06 01:54:30 UTC
Permalink
Jakub> Another possibility would be to give the macros twice as many arguments
Jakub> as there are parameters and just through the odd arguments away when
Jakub> expanding to the template parameters. That would mean you write
Jakub> GCC_METHOD7 (gcc_decl, build_decl,
Jakub> const char *, name,
Jakub> enum gcc_c_symbol_kind, sym_kind,
Jakub> const char *, substitution_name,
Jakub> gcc_address, address,
Jakub> const char *, filename,
Jakub> unsigned int, line_number);
Jakub> though it isn't very nice either, guess I'm bikeshedding... ;)

Bikeshed away, I don't mind ... in this case :)

I'm not super fond of this idea, though, I think because the names are
all "useless" -- they don't have any meaning to any of the actual uses,
they are just there for documentation purposes.

One other random idea was something like:

GCC_METHOD7 (gcc_decl, build_decl,
const char *, /* Argument NAME. */
enum gcc_c_symbol_kind, /* Argument SYM_KIND. */
...

Tom
Jakub Jelinek
2014-06-06 05:35:24 UTC
Permalink
Post by Tom Tromey
Jakub> Another possibility would be to give the macros twice as many arguments
Jakub> as there are parameters and just through the odd arguments away when
Jakub> expanding to the template parameters. That would mean you write
Jakub> GCC_METHOD7 (gcc_decl, build_decl,
Jakub> const char *, name,
Jakub> enum gcc_c_symbol_kind, sym_kind,
Jakub> const char *, substitution_name,
Jakub> gcc_address, address,
Jakub> const char *, filename,
Jakub> unsigned int, line_number);
Jakub> though it isn't very nice either, guess I'm bikeshedding... ;)
Bikeshed away, I don't mind ... in this case :)
I'm not super fond of this idea, though, I think because the names are
all "useless" -- they don't have any meaning to any of the actual uses,
they are just there for documentation purposes.
GCC_METHOD7 (gcc_decl, build_decl,
const char *, /* Argument NAME. */
enum gcc_c_symbol_kind, /* Argument SYM_KIND. */
LGTM.

Jakub
Jeff Law
2014-06-09 17:09:24 UTC
Permalink
Post by Tom Tromey
Jakub> Another possibility would be to give the macros twice as many arguments
Jakub> as there are parameters and just through the odd arguments away when
Jakub> expanding to the template parameters. That would mean you write
Jakub> GCC_METHOD7 (gcc_decl, build_decl,
Jakub> const char *, name,
Jakub> enum gcc_c_symbol_kind, sym_kind,
Jakub> const char *, substitution_name,
Jakub> gcc_address, address,
Jakub> const char *, filename,
Jakub> unsigned int, line_number);
Jakub> though it isn't very nice either, guess I'm bikeshedding... ;)
Bikeshed away, I don't mind ... in this case :)
I'm not super fond of this idea, though, I think because the names are
all "useless" -- they don't have any meaning to any of the actual uses,
they are just there for documentation purposes.
GCC_METHOD7 (gcc_decl, build_decl,
const char *, /* Argument NAME. */
enum gcc_c_symbol_kind, /* Argument SYM_KIND. */
Works for me.
jeff
Tom Tromey
2014-05-16 15:26:38 UTC
Permalink
In the typical case, when compiling a snippet of user code, gdb wraps
the user's text in a dummy function.

It's somewhat odd for users if an error in their code is mentioned as
coming from this dummy function.

This patch makes it possible to suppress the function-name display in
a straightforward way: it adds a new global which the plugin can set
to declare the name of the dummy function.

This patch seems like a bit of a hack, but there didn't seem to be a
notably cleaner approach.

2014-05-16 Phil Muldoon <***@redhat.com>
Tom Tromey <***@redhat.com>

* c-lang.c (c_diagnostic_ignored_function): New global.
(c_print_error_function): New function.
(LANG_HOOKS_PRINT_ERROR_FUNCTION): Define.
* c-lang.h (c_diagnostic_ignored_function): Declare.
---
gcc/c/ChangeLog | 8 ++++++++
gcc/c/c-lang.c | 22 ++++++++++++++++++++++
gcc/c/c-lang.h | 4 ++++
3 files changed, 34 insertions(+)

diff --git a/gcc/c/c-lang.c b/gcc/c/c-lang.c
index 97c0443..e563813 100644
--- a/gcc/c/c-lang.c
+++ b/gcc/c/c-lang.c
@@ -35,6 +35,26 @@ along with GCC; see the file COPYING3. If not see

enum c_language_kind c_language = clk_c;

+// If non-zero, this names a function which should not be reported in
+// a diagnostic. This is used by the gdb plugin to avoid showing the
+// generated function name to the user.
+const char *c_diagnostic_ignored_function;
+
+// An implementation of the print_error_function langhook that
+// respects C_DIAGNOSTIC_IGNORED_FUNCTION.
+static void
+c_print_error_function (diagnostic_context *context, const char *file,
+ diagnostic_info *diagnostic)
+{
+ if (c_diagnostic_ignored_function != NULL
+ && current_function_decl != NULL_TREE
+ && DECL_NAME (current_function_decl) != NULL_TREE
+ && strcmp (IDENTIFIER_POINTER (DECL_NAME (current_function_decl)),
+ c_diagnostic_ignored_function) == 0)
+ return;
+ lhd_print_error_function (context, file, diagnostic);
+}
+
/* Lang hooks common to C and ObjC are declared in c-objc-common.h;
consequently, there should be very few hooks below. */

@@ -44,6 +64,8 @@ enum c_language_kind c_language = clk_c;
#define LANG_HOOKS_INIT c_objc_common_init
#undef LANG_HOOKS_INIT_TS
#define LANG_HOOKS_INIT_TS c_common_init_ts
+#undef LANG_HOOKS_PRINT_ERROR_FUNCTION
+#define LANG_HOOKS_PRINT_ERROR_FUNCTION c_print_error_function

/* Each front end provides its own lang hook initializer. */
struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER;
diff --git a/gcc/c/c-lang.h b/gcc/c/c-lang.h
index 7fcf333..022206f 100644
--- a/gcc/c/c-lang.h
+++ b/gcc/c/c-lang.h
@@ -59,4 +59,8 @@ struct GTY(()) language_function {
attribute lists. */
extern GTY(()) int current_omp_declare_target_attribute;

+/* If non-zero, the name of a function whose name should not be
+ reported in a diagnostic. */
+extern const char *c_diagnostic_ignored_function;
+
#endif /* ! GCC_C_LANG_H */
--
1.9.0
Joseph S. Myers
2014-05-16 16:04:59 UTC
Permalink
Post by Tom Tromey
In the typical case, when compiling a snippet of user code, gdb wraps
the user's text in a dummy function.
It's somewhat odd for users if an error in their code is mentioned as
coming from this dummy function.
This patch makes it possible to suppress the function-name display in
a straightforward way: it adds a new global which the plugin can set
to declare the name of the dummy function.
This patch seems like a bit of a hack, but there didn't seem to be a
notably cleaner approach.
I'd say this global actually belongs somewhere in the diagnostic_context
(i.e., instead of the diagnostic_context_auxiliary_data (DC) actually
being a tree as it is at present, it should point to a structure with
whatever extra information clients wish to use to control aspects of
diagnostic reporting).
--
Joseph S. Myers
***@codesourcery.com
Jeff Law
2014-05-16 18:33:38 UTC
Permalink
Post by Tom Tromey
In the typical case, when compiling a snippet of user code, gdb wraps
the user's text in a dummy function.
It's somewhat odd for users if an error in their code is mentioned as
coming from this dummy function.
This patch makes it possible to suppress the function-name display in
a straightforward way: it adds a new global which the plugin can set
to declare the name of the dummy function.
This patch seems like a bit of a hack, but there didn't seem to be a
notably cleaner approach.
* c-lang.c (c_diagnostic_ignored_function): New global.
(c_print_error_function): New function.
(LANG_HOOKS_PRINT_ERROR_FUNCTION): Define.
* c-lang.h (c_diagnostic_ignored_function): Declare.
Just a few nites.

In c-lang.c, please use the old C-style comments. If for no other
reason than it's consistent with all the other nearby code. Consider
using non-NULL when referring to pointers rather than non-zero. */

Otherwise OK. Please wait to install until the entire kit is approved.

BTW, didn't see patch #5 of the series.

jeff
Tom Tromey
2014-05-16 18:42:31 UTC
Permalink
Jeff> BTW, didn't see patch #5 of the series.

Maybe it was too big.
I will try to resend it compressed.

Tom
Mike Stump
2014-05-16 16:29:28 UTC
Permalink
Post by Tom Tromey
This patch series is half of a project to let gdb reuse gcc (which
half depends on which list you are seeing this on), so that users can
compile small snippets of code and evaluate them in the current
context of the inferior.
Nice… I looked though it, nice and lightweight and seems like the api can hold up through time.
Manuel López-Ibáñez
2014-05-16 16:29:13 UTC
Permalink
Post by Tom Tromey
This patch makes it possible to suppress the function-name display in
a straightforward way: it adds a new global which the plugin can set
to declare the name of the dummy function.
This patch seems like a bit of a hack, but there didn't seem to be a
notably cleaner approach.
Can't you override the diagnostic_starter() in your plugin? This way
you can even customize it to print "gdb" in the prefix (if you wish to
provide a custom prefix). If that is possible, that seems way cleaner.
If not, I wonder why not.

Otherwise, why not override the lang_hook itself? This way the plugin
can provide its own lang_hook so that your proposed
c_print_error_function lives in the plugin itself.

I'm probably missing something obvious here.

Cheers,

Manuel.
Tom Tromey
2014-06-09 17:00:36 UTC
Permalink
Tom> This patch makes it possible to suppress the function-name display in
Tom> a straightforward way: it adds a new global which the plugin can set
Tom> to declare the name of the dummy function.

Manuel> Otherwise, why not override the lang_hook itself? This way the plugin
Manuel> can provide its own lang_hook so that your proposed
Manuel> c_print_error_function lives in the plugin itself.

I've changed my local tree to use this approach, as it seemed simplest.
Thanks for the suggestion.

Tom
Tom Tromey
2014-05-16 18:48:46 UTC
Permalink
Tom> This patch series is half of a project to let gdb reuse gcc (which
Tom> half depends on which list you are seeing this on), so that users can
Tom> compile small snippets of code and evaluate them in the current
Tom> context of the inferior.

Jeff noted that patch #5 didn't make it through.

I've edited this one down by removing the auto-generated stuff , and
then compressed it.

If anybody wants to apply this to try it out, it's all on github.

https://github.com/tromey/gcc
https://github.com/tromey/gdb

In each repository the branch named "submit/compile" holds the rebased
series that were submitted.

The development branches are both named "gdbjit". These are much
messier but not ever rebased, so perhaps safer to track.

Tom

This patch adds the plugin to the gcc tree and updates the top-level
configury.

It seems better to have this code in the gcc tree than in the gdb
tree, because it is bound more tightly to gcc. The gcc plugin makes
direct calls into various parts of gcc to do its work; whereas on the
gdb side everything is done via a relatively simple API, without any
direct connection to gdb internals. This breakdown made the most
sense because most calls are from gdb to gcc rather than vice versa.

The plugin itself consists of two parts. These parts communicate via
a simple ad hoc RPC system implemented in the plugin code.

2014-05-16 Phil Muldoon <***@redhat.com>
Tom Tromey <***@redhat.com>

* Makefile.def: Add libcc1 to host_modules.
* configure.ac (host_tools): Add libcc1.
* Makefile.in, configure: Rebuild.

2014-05-16 Phil Muldoon <***@redhat.com>
Jan Kratochvil <***@redhat.com>
Tom Tromey <***@redhat.com>

* aclocal.m4: New file.
* callbacks.cc: New file.
* callbacks.hh: New file.
* cc1plugin-config.h.in: New file.
* configure: New file.
* configure.ac: New file.
* connection.cc: New file.
* connection.hh: New file.
* libcc1.cc: New file.
* libcc1plugin.sym: New file.
* libcc1.sym: New file.
* Makefile.am: New file.
* Makefile.in: New file.
* marshall.cc: New file.
* marshall.hh: New file.
* names.cc: New file.
* names.hh: New file.
* plugin.cc: New file.
* rpc.hh: New file.
* status.hh: New file.
---
ChangeLog | 7 +
Makefile.def | 5 +
Makefile.in | 995 ++-
configure | 2 +-
configure.ac | 4 +-
libcc1/ChangeLog | 24 +
libcc1/Makefile.am | 42 +
libcc1/Makefile.in | 614 ++
libcc1/aclocal.m4 | 980 +++
libcc1/callbacks.cc | 90 +
libcc1/callbacks.hh | 64 +
libcc1/cc1plugin-config.h.in | 92 +
libcc1/configure | 16956 +++++++++++++++++++++++++++++++++++++++++
libcc1/configure.ac | 65 +
libcc1/connection.cc | 153 +
libcc1/connection.hh | 114 +
libcc1/libcc1.cc | 454 ++
libcc1/libcc1.sym | 1 +
libcc1/libcc1plugin.sym | 2 +
libcc1/marshall.cc | 166 +
libcc1/marshall.hh | 93 +
libcc1/names.cc | 46 +
libcc1/names.hh | 55 +
libcc1/plugin.cc | 895 +++
libcc1/rpc.hh | 486 ++
libcc1/status.hh | 33 +
26 files changed, 22430 insertions(+), 8 deletions(-)
create mode 100644 libcc1/ChangeLog
create mode 100644 libcc1/Makefile.am
create mode 100644 libcc1/Makefile.in
create mode 100644 libcc1/aclocal.m4
create mode 100644 libcc1/callbacks.cc
create mode 100644 libcc1/callbacks.hh
create mode 100644 libcc1/cc1plugin-config.h.in
create mode 100755 libcc1/configure
create mode 100644 libcc1/configure.ac
create mode 100644 libcc1/connection.cc
create mode 100644 libcc1/connection.hh
create mode 100644 libcc1/libcc1.cc
create mode 100644 libcc1/libcc1.sym
create mode 100644 libcc1/libcc1plugin.sym
create mode 100644 libcc1/marshall.cc
create mode 100644 libcc1/marshall.hh
create mode 100644 libcc1/names.cc
create mode 100644 libcc1/names.hh
create mode 100644 libcc1/plugin.cc
create mode 100644 libcc1/rpc.hh
create mode 100644 libcc1/status.hh
Joseph S. Myers
2014-05-16 20:29:05 UTC
Permalink
Post by Tom Tromey
This patch adds the plugin to the gcc tree and updates the top-level
configury.
I don't see anything obvious that would disable the plugin if plugins are
unsupported (e.g. on Windows host) or disabled (--disable-plugin).
Probably the relevant support from gcc/configure.ac needs to go somewhere
it can be used at toplevel.
Post by Tom Tromey
+ self->args.push_back ("gcc");
seems wrong - at least you should use the appropriate compiler name after
transformation for cross compilers / --program-transform-name. Though
really the *versioned* driver $(target_noncanonical)-gcc-$(version) is the
right one to use, in that the plugin should presumably be closely
associated with a particular compiler installation when e.g. a
distribution has multiple GCC versions packaged that can be installed
simultaneously. Having multiple copies of the plugin installed in the
same prefix for different targets should be supported. I'm not clear on
which library does what - does libcc1 depend in any way on the target or
GCC version?

How are the compiler multilib options (e.g. -m32 / -m64) specified? Is
that something GDB passes through, based on examining properties of the
binary being debugged? (Unfortunately there may not be a good way in
general for GDB to tell what the required options for a particular binary
are. It can at least reasonably default to using a copy of the plugin for
the same target triplet as GDB was configured for.)
--
Joseph S. Myers
***@codesourcery.com
Tom Tromey
2014-05-16 21:03:43 UTC
Permalink
Post by Tom Tromey
+ self->args.push_back ("gcc");
Joseph> seems wrong - at least you should use the appropriate compiler
Joseph> name after transformation for cross compilers /
Joseph> --program-transform-name.

Ok, we'll look into it.

Joseph> I'm not clear on which library does what - does libcc1 depend in
Joseph> any way on the target or GCC version?

It doesn't depend on the target at all. It does rely on the GCC plugin
using the same .def file -- in fact we should probably add a handshake
at the start so that we don't wind up with a version mismatch there.
The plugin is of course exposed to GCC internals changes as all plugins
are; but this is why we think it should be part of GCC.

Joseph> How are the compiler multilib options (e.g. -m32 / -m64)
Joseph> specified? Is that something GDB passes through, based on
Joseph> examining properties of the binary being debugged?
Joseph> (Unfortunately there may not be a good way in general for GDB to
Joseph> tell what the required options for a particular binary are. It
Joseph> can at least reasonably default to using a copy of the plugin
Joseph> for the same target triplet as GDB was configured for.)

gdb extracts some information from the debuginfo.
Some information is provided by a new gdbarch method; for example this
is where -m32 / -m64 / -m31 (hi S390) come from.

I am not sure if we can get the proper $(target_noncanonical) for a
given gdbarch. We'll look into it.

Tom
Mike Stump
2014-05-16 21:35:51 UTC
Permalink
Post by Tom Tromey
I've edited this one down by removing the auto-generated stuff , and
then compressed it.
+ // remove the "const" and handle deallcation from pointer types.

sp: deallocation
Mike Stump
2014-05-16 22:17:19 UTC
Permalink
Post by Tom Tromey
This patch adds the plugin to the gcc tree
So, this code isn’t as portable as gcc (I can run a native gcc bootstrap on my binutils sim simulator for my target, and I’m a newlib target), so it needs autoconf to explain if enough features are present; sockets I think would be one of the many things that would kill my build for example.
Tom Tromey
2014-06-05 19:34:35 UTC
Permalink
Post by Tom Tromey
This patch adds the plugin to the gcc tree
Mike> So, this code isn’t as portable as gcc (I can run a native gcc
Mike> bootstrap on my binutils sim simulator for my target, and I’m a newlib
Mike> target), so it needs autoconf to explain if enough features are
Mike> present; sockets I think would be one of the many things that would
Mike> kill my build for example.

If you could enumerate the things you think are necessary to check, I
can arrange for the plugin to not be built if those are not available.

I added a check like this for socketpair to my tree. I also plan to
deal with the lack of plugin functionality as Joseph pointed out.

I suppose I will add a check for fork. How about pipe? select?

Tom
Mike Stump
2014-06-05 21:35:02 UTC
Permalink
Post by Tom Tromey
If you could enumerate the things you think are necessary to check, I
can arrange for the plugin to not be built if those are not available.
So, I think it a single check on socketpair is likely good enough. If it is present, likely all the rest are, and if it isn’t turning it off likely is reasonable until someone wants to port more. It isn’t your job to do that port… the person who wants it will do it.
Jeff Law
2014-06-23 19:09:41 UTC
Permalink
Trevor> I'm curious, what is the reason you choose not to write this in C++11 or
Trevor> later? Its distributed with gcc, so the only case where you aren't
Trevor> building with the in tree compiler and libraries is when your cross
Trevor> compiling gcc, and it doesn't seem particularly important to support
Trevor> building the plugin or library in that configuration. So istm you could
Trevor> go all the way and assume you are being built with trunk gcc and
Trevor> libraries.
The plugin has to be ABI compatible with GCC itself, and my
understanding was that C++11 and "however GCC is built" are not
necessarily compatible.
Presumably you're referring to the upcoming abi breakage for C++ pair &
list.

There's ways around that with the ABI tagging we're using, but at least
for now, the safe thing to do for something that must be ABI compatibile
with GCC itself is to stick with C++03 mode.
Switching to C++11 would be an improvement -- variadic templates would
simplify the RPC code (with a complicated caveat). So if it is possible
I am interested.
There'll probably be a day when we can bless C++11 for building GCC
itself and any associated plugins, but we're not at that point right now.
Trevor> So can we add C++ stuff to libiberty and allow building
Trevor> libiberty without it for binutils / gdb, or can we do something
Trevor> else to avoid this kind of stuff?
One way would be to just make a new top-level directory for a new
library.
Seems like the easiest solution, at least for now.
Thanks. I changed it to do a NULL check. It's nothrow because nothing
in libcc1 or gdb is prepared for a C++ exception. While I like
exceptions (gdb uses its own longjmp-based exception system
extensively), my understanding is that they aren't currently used in
gcc.
Right. Or if we're using them in GCC, any such use is well buried in
non-critical , not widely known & marginally, if at all, tested code.

Jeff
Trevor Saunders
2014-06-24 03:12:31 UTC
Permalink
Post by Jeff Law
Trevor> I'm curious, what is the reason you choose not to write this in C++11 or
Trevor> later? Its distributed with gcc, so the only case where you aren't
Trevor> building with the in tree compiler and libraries is when your cross
Trevor> compiling gcc, and it doesn't seem particularly important to support
Trevor> building the plugin or library in that configuration. So istm you could
Trevor> go all the way and assume you are being built with trunk gcc and
Trevor> libraries.
The plugin has to be ABI compatible with GCC itself, and my
understanding was that C++11 and "however GCC is built" are not
necessarily compatible.
Presumably you're referring to the upcoming abi breakage for C++ pair &
list.
There's ways around that with the ABI tagging we're using, but at least for
now, the safe thing to do for something that must be ABI compatibile with
GCC itself is to stick with C++03 mode.
hrm, I know basically nothing about the upcoming changes, but I would
have expected linking c++03 code against c++11 code would be fine
especially when the interface doesn't involve any stl.
Post by Jeff Law
Switching to C++11 would be an improvement -- variadic templates would
simplify the RPC code (with a complicated caveat). So if it is possible
I am interested.
There'll probably be a day when we can bless C++11 for building GCC itself
and any associated plugins, but we're not at that point right now.
Trevor> So can we add C++ stuff to libiberty and allow building
Trevor> libiberty without it for binutils / gdb, or can we do something
Trevor> else to avoid this kind of stuff?
One way would be to just make a new top-level directory for a new
library.
Seems like the easiest solution, at least for now.
ugh more autotools, but wfm.
Post by Jeff Law
Thanks. I changed it to do a NULL check. It's nothrow because nothing
in libcc1 or gdb is prepared for a C++ exception. While I like
exceptions (gdb uses its own longjmp-based exception system
extensively), my understanding is that they aren't currently used in
gcc.
Right. Or if we're using them in GCC, any such use is well buried in
non-critical , not widely known & marginally, if at all, tested code.
Well, we build everything or at least everything I've seen with
-fno-exceptions, so if something does throw we'll just crash right?
istm we certainly write code calling the throwing new with that
expectation.

Trev
Post by Jeff Law
Jeff
Tom Tromey
2014-06-24 17:12:38 UTC
Permalink
Trevor> hrm, I know basically nothing about the upcoming changes, but I would
Trevor> have expected linking c++03 code against c++11 code would be fine
Trevor> especially when the interface doesn't involve any stl.

https://gcc.gnu.org/wiki/Cxx11AbiCompatibility

This warns against mixing with C++98, which seems to be how GCC is
built.

While I agree that in this specific case it is probably safe, since gcc
in general isn't a heavy user of libstdc++, I think it's reasonable to
simply follow gcc. This is safer in case gcc changes; and the benefit
from C++11 in libcc1 is modest, especially when you consider the extra
template magic we'd need in order to actually use variadic templates for
the RPC stuff.

Trevor> Well, we build everything or at least everything I've seen with
Trevor> -fno-exceptions, so if something does throw we'll just crash right?
Trevor> istm we certainly write code calling the throwing new with that
Trevor> expectation.

Gcc's coding conventions say that code ought to be exception-safe in
case exceptions are used in the future. Search for "Exceptions" here:

https://gcc.gnu.org/wiki/CppConventions

I think retaining the std::nothrow is safer in view of this, and doesn't
cause any problems.

Tom
Trevor Saunders
2014-06-24 18:10:13 UTC
Permalink
Post by Tom Tromey
Trevor> hrm, I know basically nothing about the upcoming changes, but I would
Trevor> have expected linking c++03 code against c++11 code would be fine
Trevor> especially when the interface doesn't involve any stl.
https://gcc.gnu.org/wiki/Cxx11AbiCompatibility
This warns against mixing with C++98, which seems to be how GCC is
built.
While I agree that in this specific case it is probably safe, since gcc
in general isn't a heavy user of libstdc++, I think it's reasonable to
simply follow gcc. This is safer in case gcc changes; and the benefit
yeah, I'm not disagreeing at this point.
Post by Tom Tromey
from C++11 in libcc1 is modest, especially when you consider the extra
template magic we'd need in order to actually use variadic templates for
the RPC stuff.
It would get a little more than that, actually deleting the copy ctors
and stuff you don't want people to call is one thing that comes to mind.
Post by Tom Tromey
Trevor> Well, we build everything or at least everything I've seen with
Trevor> -fno-exceptions, so if something does throw we'll just crash right?
Trevor> istm we certainly write code calling the throwing new with that
Trevor> expectation.
Gcc's coding conventions say that code ought to be exception-safe in
https://gcc.gnu.org/wiki/CppConventions
I think that's a good idea in general, mostly because it results in
simpler code, I think the idea gcc will be exception safe in a
reasonable amount of time is a bit of a pipe dream.
Post by Tom Tromey
I think retaining the std::nothrow is safer in view of this, and doesn't
cause any problems.
I think in general trying to handle allocator failure is a waste of
time, that is all the places we call the throwing new today we'd want
to keep doing that in a world with exceptions and just let the
exception kill us. So assuming you actually want to handle allocator
failure in this particular case for some reason that seems reasonable.

Trev
Post by Tom Tromey
Tom
Tom Tromey
2014-07-18 18:55:04 UTC
Permalink
Tom> I've edited this one down by removing the auto-generated stuff , and
Tom> then compressed it.

Tom> Here's a new version of patch #5.
Tom> I've removed the generated code; let's see if it gets through without
Tom> compression.

Here's another new revision.

Phil noticed that libcc1.so relies on some symbols from libiberty, and
these weren't available in some gdb builds. This version of the patch
changes the build so that libcc1 is linked against the pic libiberty in
the gcc build tree, which should fix the issue.

This version also addresses various comments made by Trevor Saunders,
though it doesn't switch the code to use C++11. I think it is best here
to follow the rest of gcc.

Tom

2014-06-19 Phil Muldoon <***@redhat.com>
Tom Tromey <***@redhat.com>

* Makefile.def: Add libcc1 to host_modules.
* configure.ac (host_tools): Add libcc1.
* Makefile.in, configure: Rebuild.

2014-06-19 Phil Muldoon <***@redhat.com>
Jan Kratochvil <***@redhat.com>
Tom Tromey <***@redhat.com>

* aclocal.m4: New file.
* callbacks.cc: New file.
* callbacks.hh: New file.
* cc1plugin-config.h.in: New file.
* configure: New file.
* configure.ac: New file.
* connection.cc: New file.
* connection.hh: New file.
* findcomp.cc: New file.
* findcomp.hh: New file.
* libcc1.cc: New file.
* libcc1plugin.sym: New file.
* libcc1.sym: New file.
* Makefile.am: New file.
* Makefile.in: New file.
* marshall.cc: New file.
* marshall.hh: New file.
* names.cc: New file.
* names.hh: New file.
* plugin.cc: New file.
* rpc.hh: New file.
* status.hh: New file.

diff --git a/Makefile.def b/Makefile.def
index 239ad36..ed9bac6 100644
--- a/Makefile.def
+++ b/Makefile.def
@@ -121,6 +121,8 @@ host_modules= { module= gnattools; };
host_modules= { module= lto-plugin; bootstrap=true;
extra_configure_flags='--enable-shared @extra_linker_plugin_flags@ @extra_linker_plugin_configure_flags@';
extra_make_flags='@extra_linker_plugin_flags@'; };
+host_modules= { module= libcc1; bootstrap=true;
+ extra_configure_flags=--enable-shared; };

target_modules = { module= libstdc++-v3;
bootstrap=true;
@@ -352,6 +354,9 @@ dependencies = { module=all-gnattools; on=all-target-libstdc++-v3; };
dependencies = { module=all-lto-plugin; on=all-libiberty; };
dependencies = { module=all-lto-plugin; on=all-libiberty-linker-plugin; };

+dependencies = { module=configure-libcc1; on=configure-gcc; };
+dependencies = { module=all-libcc1; on=all-gcc; };
+
dependencies = { module=all-utils; on=all-libiberty; };

dependencies = { module=configure-mpfr; on=all-gmp; };
diff --git a/configure.ac b/configure.ac
index 9048cd1..0388dc2 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,5 +1,5 @@
# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
-# 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
+# 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2014
# Free Software Foundation, Inc.
#
# This file is free software; you can redistribute it and/or modify it
@@ -141,7 +141,7 @@ host_libs="intl libiberty opcodes bfd readline tcl tk itcl libgui zlib libbacktr
# binutils, gas and ld appear in that order because it makes sense to run
# "make check" in that particular order.
# If --enable-gold is used, "gold" may replace "ld".
-host_tools="texinfo flex bison binutils gas ld fixincludes gcc cgen sid sim gdb gprof etc expect dejagnu m4 utils guile fastjar gnattools"
+host_tools="texinfo flex bison binutils gas ld fixincludes gcc cgen sid sim gdb gprof etc expect dejagnu m4 utils guile fastjar gnattools libcc1"

# libgcj represents the runtime libraries only used by gcj.
libgcj="target-libffi \
diff --git a/libcc1/Makefile.am b/libcc1/Makefile.am
new file mode 100644
index 0000000..b3040c5
--- /dev/null
+++ b/libcc1/Makefile.am
@@ -0,0 +1,55 @@
+## Copyright (C) 2014 Free Software Foundation, Inc.
+
+## This file is part of GCC.
+
+## GCC 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, or (at your option) any later
+## version.
+
+## GCC 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 GCC; see the file COPYING3. If not see
+## <http://www.gnu.org/licenses/>.
+
+ACLOCAL_AMFLAGS = -I .. -I ../config
+gcc_build_dir = ../$(host_subdir)/gcc
+AM_CPPFLAGS = -I $(srcdir)/../include -I $(srcdir)/../libgcc \
+ -I $(gcc_build_dir) -I$(srcdir)/../gcc \
+ -I $(srcdir)/../gcc/c -I $(srcdir)/../gcc/c-family \
+ -I $(srcdir)/../libcpp/include
+WERROR_FLAG = -Werror
+AM_CXXFLAGS = $(WARN_FLAGS) $(WERROR_FLAG) $(visibility)
+libiberty = ../libiberty/pic/libiberty.a
+
+
+plugindir = $(libdir)/gcc/$(target_noncanonical)/$(gcc_version)/plugin
+cc1libdir = $(libdir)/$(libsuffix)
+
+if ENABLE_PLUGIN
+plugin_LTLIBRARIES = libcc1plugin.la
+cc1lib_LTLIBRARIES = libcc1.la
+endif
+
+BUILT_SOURCES = compiler-name.h
+
+# Put this in a header so we don't run sed for each compilation. This
+# is also simpler to debug as one can easily see the constant.
+compiler-name.h: Makefile
+ echo "#define COMPILER_NAME \"`echo gcc | sed '$(transform)'`\"" > compiler-name.h
+
+
+shared_source = callbacks.cc callbacks.hh connection.cc connection.hh \
+ marshall.cc marshall.hh rpc.hh status.hh
+
+libcc1plugin_la_LDFLAGS = -module -export-symbols $(srcdir)/libcc1plugin.sym
+libcc1plugin_la_SOURCES = plugin.cc $(shared_source)
+libcc1plugin_la_LIBADD = $(libiberty)
+
+libcc1_la_LDFLAGS = -module -export-symbols $(srcdir)/libcc1.sym
+libcc1_la_SOURCES = findcomp.cc libcc1.cc names.cc names.hh $(shared_source)
+libcc1_la_LIBADD = $(libiberty)
diff --git a/libcc1/callbacks.cc b/libcc1/callbacks.cc
new file mode 100644
index 0000000..3c4eda6
--- /dev/null
+++ b/libcc1/callbacks.cc
@@ -0,0 +1,90 @@
+/* Callback management.
+ Copyright (C) 2014 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC 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, or (at your option) any later
+version.
+
+GCC 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 GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#include <cc1plugin-config.h>
+#include <string.h>
+#include <stdlib.h>
+#include "callbacks.hh"
+#include "libiberty.h"
+
+// An entry in the hash table.
+struct method
+{
+ const char *name;
+ cc1_plugin::callback_ftype *func;
+};
+
+// Hash function for struct method.
+static hashval_t
+hash_method (const void *a)
+{
+ const struct method *m = (const struct method *) a;
+
+ return htab_hash_string (m->name);
+}
+
+// Equality function for struct method.
+static int
+eq_method (const void *a, const void *b)
+{
+ const struct method *ma = (const struct method *) a;
+ const struct method *mb = (const struct method *) b;
+
+ return strcmp (ma->name, mb->name) == 0;
+}
+
+cc1_plugin::callbacks::callbacks ()
+ : m_registry (htab_create_alloc (10, hash_method, eq_method,
+ free, xcalloc, free))
+{
+}
+
+cc1_plugin::callbacks::~callbacks ()
+{
+ htab_delete (m_registry);
+}
+
+void
+cc1_plugin::callbacks::add_callback (const char *name,
+ cc1_plugin::callback_ftype *func)
+{
+ method m;
+ method **slot;
+
+ m.name = name;
+ m.func = func;
+
+ slot = (method **) htab_find_slot (m_registry, &m, INSERT);
+ *slot = XNEW (method);
+ **slot = m;
+}
+
+cc1_plugin::callback_ftype *
+cc1_plugin::callbacks::find_callback (const char *name)
+{
+ method m, *found;
+
+ m.name = name;
+
+ found = (method *) htab_find (m_registry, &m);
+ if (found == NULL)
+ return NULL;
+
+ return found->func;
+}
diff --git a/libcc1/callbacks.hh b/libcc1/callbacks.hh
new file mode 100644
index 0000000..bde1100
--- /dev/null
+++ b/libcc1/callbacks.hh
@@ -0,0 +1,64 @@
+/* Callback management
+ Copyright (C) 2014 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC 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, or (at your option) any later
+version.
+
+GCC 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 GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#ifndef CC1_PLUGIN_CALLBACKS_HH
+#define CC1_PLUGIN_CALLBACKS_HH
+
+#include "status.hh"
+#include "hashtab.h"
+
+namespace cc1_plugin
+{
+ class connection;
+
+ // The type of a callback method.
+ typedef status callback_ftype (connection *);
+
+ // This class manages callback functions. A callback has a name and
+ // an underlying function. When a query packet arrives, the name is
+ // inspected and the corresponding function is called. A callback
+ // function has to know how to decode its own arguments, but
+ // wrappers are provided elsewhere to automate this.
+ class callbacks
+ {
+ public:
+
+ callbacks ();
+ ~callbacks ();
+
+ // Add a callback named NAME. FUNC is the function to call when
+ // this method is invoked.
+ void add_callback (const char *name, callback_ftype *func);
+
+ // Look up a callback by name. Returns NULL if the method is not
+ // found.
+ callback_ftype *find_callback (const char *name);
+
+ private:
+
+ // Declared but not defined to avoid use.
+ callbacks (const callbacks &);
+ callbacks &operator= (const callbacks &);
+
+ // The mapping.
+ htab_t m_registry;
+ };
+};
+
+#endif // CC1_PLUGIN_CALLBACKS_HH
diff --git a/libcc1/configure.ac b/libcc1/configure.ac
new file mode 100644
index 0000000..7328977
--- /dev/null
+++ b/libcc1/configure.ac
@@ -0,0 +1,73 @@
+dnl Copyright (C) 2014 Free Software Foundation, Inc.
+dnl
+dnl This file is part of GCC.
+dnl
+dnl GCC is free software; you can redistribute it and/or modify it under
+dnl the terms of the GNU General Public License as published by the Free
+dnl Software Foundation; either version 3, or (at your option) any later
+dnl version.
+dnl
+dnl GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+dnl WARRANTY; without even the implied warranty of MERCHANTABILITY or
+dnl FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+dnl for more details.
+dnl
+dnl You should have received a copy of the GNU General Public License
+dnl along with GCC; see the file COPYING3. If not see
+dnl <http://www.gnu.org/licenses/>.
+
+AC_PREREQ(2.64)
+AC_INIT([libcc1], [version-unused])
+AC_CONFIG_SRCDIR([libcc1.cc])
+AC_CONFIG_HEADER(cc1plugin-config.h)
+
+AC_CANONICAL_SYSTEM
+AC_USE_SYSTEM_EXTENSIONS
+# Determine the noncanonical target name, for directory use.
+ACX_NONCANONICAL_TARGET
+GCC_TOPLEV_SUBDIRS
+
+# 1.11.1: Require that version of automake.
+# foreign: Don't require README, INSTALL, NEWS, etc.
+# no-define: Don't define PACKAGE and VERSION.
+# -Wall: Issue all automake warnings.
+# -Wno-portability: Don't warn about constructs supported by GNU make.
+# (because GCC requires GNU make anyhow).
+AM_INIT_AUTOMAKE([1.11.1 foreign no-dist no-define -Wall -Wno-portability])
+AM_MAINTAINER_MODE
+
+LT_INIT([disable-static])
+AM_PROG_LIBTOOL
+AC_PROG_CXX
+
+visibility=
+if test "$GXX" = yes; then
+ visibility=-fvisibility=hidden
+fi
+AC_SUBST(visibility)
+
+AC_CHECK_DECLS([basename])
+
+gcc_version=`cat $srcdir/../gcc/BASE-VER`
+AC_SUBST(gcc_version)
+
+ACX_PROG_CC_WARNING_OPTS([-W -Wall], [WARN_FLAGS])
+WARN_FLAGS="$WARN_FLAGS -Werror"
+AC_SUBST(WARN_FLAGS)
+
+libsuffix=
+if test "$GXX" = yes; then
+ libsuffix=`$CXX -print-multi-os-directory`
+fi
+AC_SUBST(libsuffix)
+
+# If any of these functions are missing, simply don't bother building
+# this plugin.
+GCC_ENABLE_PLUGINS
+AC_CHECK_FUNC(socketpair, , enable_plugin=no)
+AC_CHECK_FUNC(select, , enable_plugin=no)
+AC_CHECK_FUNC(fork, , enable_plugin=no)
+AM_CONDITIONAL(ENABLE_PLUGIN, test $enable_plugin = yes)
+
+AC_CONFIG_FILES([Makefile])
+AC_OUTPUT
diff --git a/libcc1/connection.cc b/libcc1/connection.cc
new file mode 100644
index 0000000..3e57bbc
--- /dev/null
+++ b/libcc1/connection.cc
@@ -0,0 +1,153 @@
+/* Connect implementation
+ Copyright (C) 2014 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC 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, or (at your option) any later
+version.
+
+GCC 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 GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#include <cc1plugin-config.h>
+#include <string>
+#include <unistd.h>
+#include <sys/types.h>
+#include <errno.h>
+#include "marshall.hh"
+#include "connection.hh"
+#include "rpc.hh"
+
+cc1_plugin::connection::~connection ()
+{
+}
+
+void
+cc1_plugin::connection::print (const char *)
+{
+}
+
+cc1_plugin::status
+cc1_plugin::connection::send (char c)
+{
+ if (write (m_fd, &c, 1) != 1)
+ return FAIL;
+ return OK;
+}
+
+cc1_plugin::status
+cc1_plugin::connection::send (const void *buf, int len)
+{
+ if (write (m_fd, buf, len) != len)
+ return FAIL;
+ return OK;
+}
+
+cc1_plugin::status
+cc1_plugin::connection::require (char c)
+{
+ char result;
+
+ if (read (m_fd, &result, 1) != 1
+ || result != c)
+ return FAIL;
+
+ return OK;
+}
+
+cc1_plugin::status
+cc1_plugin::connection::get (void *buf, int len)
+{
+ if (read (m_fd, buf, len) != len)
+ return FAIL;
+ return OK;
+}
+
+cc1_plugin::status
+cc1_plugin::connection::do_wait (bool want_result)
+{
+ while (true)
+ {
+ char result;
+ fd_set read_set;
+
+ FD_ZERO (&read_set);
+ FD_SET (m_fd, &read_set);
+ if (m_aux_fd != -1)
+ FD_SET (m_aux_fd, &read_set);
+
+ int nfds = select (FD_SETSIZE, &read_set, NULL, NULL, NULL);
+ if (nfds == -1)
+ {
+ if (errno == EINTR)
+ continue;
+ return FAIL;
+ }
+
+ // We have to check the stderr fd first, to avoid a possible
+ // blocking scenario when do_wait is called reentrantly. In
+ // such a call, if we handle the primary fd first, then we may
+ // re-enter this function, read from gcc's stderr, causing the
+ // outer invocation of this function to block when trying to
+ // read.
+ if (m_aux_fd != -1 && FD_ISSET (m_aux_fd, &read_set))
+ {
+ char buf[1024];
+ int n = read (m_aux_fd, buf, sizeof (buf) - 1);
+ if (n < 0)
+ return FAIL;
+ if (n > 0)
+ {
+ buf[n] = '\0';
+ print (buf);
+ }
+ }
+
+ if (FD_ISSET (m_fd, &read_set))
+ {
+ int n = read (m_fd, &result, 1);
+ if (n == 0)
+ return want_result ? FAIL : OK;
+ if (n != 1)
+ return FAIL;
+
+ switch (result)
+ {
+ case 'R':
+ // The reply is ready; the caller will unmarshall it.
+ return want_result ? OK : FAIL;
+
+ case 'Q':
+ // While waiting for a reply, the other side made a method
+ // call.
+ {
+ // Use an argument_wrapper here to simplify management
+ // of the string's lifetime.
+ argument_wrapper<char *> method_name;
+
+ if (!method_name.unmarshall (this))
+ return FAIL;
+
+ callback_ftype *callback
+ = m_callbacks.find_callback (method_name);
+ // The call to CALLBACK is where we may end up in a
+ // reentrant call.
+ if (callback == NULL || !callback (this))
+ return FAIL;
+ }
+ break;
+
+ default:
+ return FAIL;
+ }
+ }
+ }
+}
diff --git a/libcc1/connection.hh b/libcc1/connection.hh
new file mode 100644
index 0000000..242deec
--- /dev/null
+++ b/libcc1/connection.hh
@@ -0,0 +1,114 @@
+/* Plugin connection declarations
+ Copyright (C) 2014 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC 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, or (at your option) any later
+version.
+
+GCC 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 GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#ifndef CC1_PLUGIN_CONNECTION_HH
+#define CC1_PLUGIN_CONNECTION_HH
+
+#include "status.hh"
+#include "callbacks.hh"
+
+namespace cc1_plugin
+{
+ // The connection class represents one side of the connection
+ // between the gdb-side library and the gcc plugin. It handles the
+ // low-level details of reading and writing data.
+ class connection
+ {
+ public:
+
+ connection (int fd)
+ : m_fd (fd),
+ m_aux_fd (-1),
+ m_callbacks ()
+ {
+ }
+
+ connection (int fd, int aux_fd)
+ : m_fd (fd),
+ m_aux_fd (aux_fd),
+ m_callbacks ()
+ {
+ }
+
+ virtual ~connection ();
+
+ // Send a single character. This is used to introduce various
+ // higher-level protocol elements.
+ status send (char c);
+
+ // Send data in bulk.
+ status send (const void *buf, int len);
+
+ // Read a single byte from the connection and verify that it
+ // matches the argument C.
+ status require (char c);
+
+ // Read data in bulk.
+ status get (void *buf, int len);
+
+ // This is called after a query (remote function call) has been
+ // sent to the remote. It waits for a response packet. The
+ // response character is read before returning. Any query packets
+ // sent from the remote while waiting for a response are handled
+ // by this function.
+ status wait_for_result ()
+ {
+ return do_wait (true);
+ }
+
+ // Read and respond to query packets sent by the remote. This
+ // function returns when the connection is closed.
+ status wait_for_query ()
+ {
+ return do_wait (false);
+ }
+
+ // Register a callback with this connection. NAME is the name of
+ // the method being registered. FUNC is the function. It must
+ // know how to decode its own arguments. When a query packet is
+ // received by one of the wait_* methods, the corresponding
+ // callback is invoked.
+ void add_callback (const char *name, callback_ftype *func)
+ {
+ m_callbacks.add_callback (name, func);
+ }
+
+ virtual void print (const char *);
+
+ private:
+
+ // Declared but not defined, to prevent use.
+ connection (const connection &);
+ connection &operator= (const connection &);
+
+ // Helper function for the wait_* methods.
+ status do_wait (bool);
+
+ // The file descriptor.
+ int m_fd;
+
+ // An auxiliary file descriptor, or -1 if none.
+ int m_aux_fd;
+
+ // Callbacks associated with this connection.
+ callbacks m_callbacks;
+ };
+}
+
+#endif // CC1_PLUGIN_CONNECTION_HH
diff --git a/libcc1/findcomp.cc b/libcc1/findcomp.cc
new file mode 100644
index 0000000..f02b1df
--- /dev/null
+++ b/libcc1/findcomp.cc
@@ -0,0 +1,139 @@
+/* Find the correct compiler.
+ Copyright (C) 2014 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC 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, or (at your option) any later
+version.
+
+GCC 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 GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#include <config.h>
+#include <string>
+#include <dirent.h>
+#include <stdlib.h>
+
+#include "libiberty.h"
+#include "xregex.h"
+#include "findcomp.hh"
+
+class scanner
+{
+public:
+
+ scanner (const std::string &dir)
+ {
+ m_dir = opendir (dir.c_str ());
+ }
+
+ ~scanner ()
+ {
+ if (m_dir != NULL)
+ closedir (m_dir);
+ }
+
+ const char *next ()
+ {
+ if (m_dir == NULL)
+ return NULL;
+
+ struct dirent *entry = readdir (m_dir);
+ if (entry == NULL)
+ return NULL;
+
+ return entry->d_name;
+ }
+
+private:
+
+ DIR *m_dir;
+};
+
+static bool
+search_dir (const regex_t &regexp, const std::string &dir, std::string *result)
+{
+ scanner scan (dir);
+ const char *filename;
+
+ while ((filename = scan.next ()) != NULL)
+ {
+ if (regexec (&regexp, filename, 0, NULL, 0) == 0)
+ {
+ *result = filename;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+class tokenizer
+{
+public:
+
+ tokenizer (const char *str)
+ : m_str (str),
+ m_pos (0)
+ {
+ }
+
+ bool done () const
+ {
+ return m_pos == std::string::npos;
+ }
+
+ std::string next ()
+ {
+ std::string::size_type last_pos = m_pos;
+ std::string::size_type colon = m_str.find(':', last_pos);
+
+ std::string result;
+ if (colon == std::string::npos)
+ {
+ m_pos = colon;
+ result = m_str.substr(last_pos, colon);
+ }
+ else
+ {
+ m_pos = colon + 1;
+ result = m_str.substr(last_pos, colon - last_pos);
+ }
+ if (result == "")
+ result = ".";
+
+ return result;
+ }
+
+private:
+
+ std::string m_str;
+ std::string::size_type m_pos;
+};
+
+bool
+find_compiler (const regex_t &regexp, std::string *result)
+{
+ const char *cpath = getenv ("PATH");
+
+ if (cpath == NULL)
+ return false;
+
+ tokenizer dirs (cpath);
+ while (!dirs.done ())
+ {
+ std::string dir = dirs.next ();
+ if (search_dir (regexp, dir, result))
+ return true;
+ }
+
+ return false;
+}
diff --git a/libcc1/findcomp.hh b/libcc1/findcomp.hh
new file mode 100644
index 0000000..a55a283
--- /dev/null
+++ b/libcc1/findcomp.hh
@@ -0,0 +1,25 @@
+/* Find the correct compiler.
+ Copyright (C) 2014 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC 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, or (at your option) any later
+version.
+
+GCC 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 GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#ifndef CC1_PLUGIN_FINDCOMP_HH
+#define CC1_PLUGIN_FINDCOMP_HH
+
+extern bool find_compiler (const regex_t &regexp, std::string *result);
+
+#endif // CC1_PLUGIN_FINDCOMP_HH
diff --git a/libcc1/libcc1.cc b/libcc1/libcc1.cc
new file mode 100644
index 0000000..15320c2
--- /dev/null
+++ b/libcc1/libcc1.cc
@@ -0,0 +1,530 @@
+/* The library used by gdb.
+ Copyright (C) 2014 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC 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, or (at your option) any later
+version.
+
+GCC 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 GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#include <cc1plugin-config.h>
+#include <vector>
+#include <string>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <sys/wait.h>
+#include <stdio.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <sstream>
+#include "rpc.hh"
+#include "connection.hh"
+#include "names.hh"
+#include "callbacks.hh"
+#include "gcc-interface.h"
+#include "libiberty.h"
+#include "xregex.h"
+#include "findcomp.hh"
+#include "compiler-name.h"
+
+struct libcc1;
+
+class libcc1_connection;
+
+// The C compiler context that we hand back to our caller.
+struct libcc1 : public gcc_c_context
+{
+ libcc1 (const gcc_base_vtable *, const gcc_c_fe_vtable *);
+ ~libcc1 ();
+
+ // A convenience function to print something.
+ void print (const char *str)
+ {
+ this->print_function (this->print_datum, str);
+ }
+
+ libcc1_connection *connection;
+
+ gcc_c_oracle_function *binding_oracle;
+ gcc_c_symbol_address_function *address_oracle;
+ void *oracle_datum;
+
+ void (*print_function) (void *datum, const char *message);
+ void *print_datum;
+
+ std::vector<std::string> args;
+ std::string source_file;
+};
+
+// A local subclass of connection that holds a back-pointer to the
+// gcc_c_context object that we provide to our caller.
+class libcc1_connection : public cc1_plugin::connection
+{
+public:
+
+ libcc1_connection (int fd, int aux_fd, libcc1 *b)
+ : connection (fd, aux_fd),
+ back_ptr (b)
+ {
+ }
+
+ virtual void print (const char *buf)
+ {
+ back_ptr->print (buf);
+ }
+
+ libcc1 *back_ptr;
+};
+
+libcc1::libcc1 (const gcc_base_vtable *v,
+ const gcc_c_fe_vtable *cv)
+ : connection (NULL),
+ binding_oracle (NULL),
+ address_oracle (NULL),
+ oracle_datum (NULL),
+ print_function (NULL),
+ print_datum (NULL),
+ args (),
+ source_file ()
+{
+ base.ops = v;
+ c_ops = cv;
+}
+
+libcc1::~libcc1 ()
+{
+ delete connection;
+}
+
+
+
+// This is a wrapper function that is called by the RPC system and
+// that then forwards the call to the library user. Note that the
+// return value is not used; the type cannot be 'void' due to
+// limitations in our simple RPC.
+int
+call_binding_oracle (cc1_plugin::connection *conn,
+ enum gcc_c_oracle_request request,
+ const char *identifier)
+{
+ libcc1 *self = ((libcc1_connection *) conn)->back_ptr;
+
+ self->binding_oracle (self->oracle_datum, self, request, identifier);
+ return 1;
+}
+
+// This is a wrapper function that is called by the RPC system and
+// that then forwards the call to the library user.
+gcc_address
+call_symbol_address (cc1_plugin::connection *conn, const char *identifier)
+{
+ libcc1 *self = ((libcc1_connection *) conn)->back_ptr;
+
+ return self->address_oracle (self->oracle_datum, self, identifier);
+}
+
+
+
+static void
+set_callbacks (struct gcc_c_context *s,
+ gcc_c_oracle_function *binding_oracle,
+ gcc_c_symbol_address_function *address_oracle,
+ void *datum)
+{
+ libcc1 *self = (libcc1 *) s;
+
+ self->binding_oracle = binding_oracle;
+ self->address_oracle = address_oracle;
+ self->oracle_datum = datum;
+}
+
+// Instances of these rpc<> template functions are installed into the
+// "c_vtable". These functions are parameterized by type and method
+// name and forward the call via the connection.
+
+template<typename R, const char *&NAME>
+R rpc (struct gcc_c_context *s)
+{
+ libcc1 *self = (libcc1 *) s;
+ R result;
+
+ if (!cc1_plugin::call (self->connection, NAME, &result))
+ return 0;
+ return result;
+}
+
+template<typename R, const char *&NAME, typename A>
+R rpc (struct gcc_c_context *s, A arg)
+{
+ libcc1 *self = (libcc1 *) s;
+ R result;
+
+ if (!cc1_plugin::call (self->connection, NAME, &result, arg))
+ return 0;
+ return result;
+}
+
+template<typename R, const char *&NAME, typename A1, typename A2>
+R rpc (struct gcc_c_context *s, A1 arg1, A2 arg2)
+{
+ libcc1 *self = (libcc1 *) s;
+ R result;
+
+ if (!cc1_plugin::call (self->connection, NAME, &result, arg1, arg2))
+ return 0;
+ return result;
+}
+
+template<typename R, const char *&NAME, typename A1, typename A2, typename A3>
+R rpc (struct gcc_c_context *s, A1 arg1, A2 arg2, A3 arg3)
+{
+ libcc1 *self = (libcc1 *) s;
+ R result;
+
+ if (!cc1_plugin::call (self->connection, NAME, &result, arg1, arg2, arg3))
+ return 0;
+ return result;
+}
+
+template<typename R, const char *&NAME, typename A1, typename A2, typename A3,
+ typename A4>
+R rpc (struct gcc_c_context *s, A1 arg1, A2 arg2, A3 arg3, A4 arg4)
+{
+ libcc1 *self = (libcc1 *) s;
+ R result;
+
+ if (!cc1_plugin::call (self->connection, NAME, &result, arg1, arg2, arg3,
+ arg4))
+ return 0;
+ return result;
+}
+
+template<typename R, const char *&NAME, typename A1, typename A2, typename A3,
+ typename A4, typename A5>
+R rpc (struct gcc_c_context *s, A1 arg1, A2 arg2, A3 arg3, A4 arg4, A5 arg5)
+{
+ libcc1 *self = (libcc1 *) s;
+ R result;
+
+ if (!cc1_plugin::call (self->connection, NAME, &result, arg1, arg2, arg3,
+ arg4, arg5))
+ return 0;
+ return result;
+}
+
+template<typename R, const char *&NAME, typename A1, typename A2, typename A3,
+ typename A4, typename A5, typename A6, typename A7>
+R rpc (struct gcc_c_context *s, A1 arg1, A2 arg2, A3 arg3, A4 arg4, A5 arg5,
+ A6 arg6, A7 arg7)
+{
+ libcc1 *self = (libcc1 *) s;
+ R result;
+
+ if (!cc1_plugin::call (self->connection, NAME, &result, arg1, arg2, arg3,
+ arg4, arg5, arg6, arg7))
+ return 0;
+ return result;
+}
+
+static const struct gcc_c_fe_vtable c_vtable =
+{
+ GCC_C_FE_VERSION_0,
+ set_callbacks,
+
+#define GCC_METHOD0(R, N) \
+ rpc<R, cc1_plugin::N>,
+#define GCC_METHOD1(R, N, A) \
+ rpc<R, cc1_plugin::N, A>,
+#define GCC_METHOD2(R, N, A, B) \
+ rpc<R, cc1_plugin::N, A, B>,
+#define GCC_METHOD3(R, N, A, B, C) \
+ rpc<R, cc1_plugin::N, A, B, C>,
+#define GCC_METHOD4(R, N, A, B, C, D) \
+ rpc<R, cc1_plugin::N, A, B, C, D>,
+#define GCC_METHOD5(R, N, A, B, C, D, E) \
+ rpc<R, cc1_plugin::N, A, B, C, D, E>,
+#define GCC_METHOD7(R, N, A, B, C, D, E, F, G) \
+ rpc<R, cc1_plugin::N, A, B, C, D, E, F, G>,
+
+#include "gcc-c-fe.def"
+
+#undef GCC_METHOD0
+#undef GCC_METHOD1
+#undef GCC_METHOD2
+#undef GCC_METHOD3
+#undef GCC_METHOD4
+#undef GCC_METHOD5
+#undef GCC_METHOD7
+};
+
+
+
+// Construct an appropriate regexp to match the compiler name.
+static std::string
+make_regexp (const char *triplet_regexp, const char *compiler)
+{
+ std::stringstream buf;
+
+ buf << "^" << triplet_regexp << "-";
+
+ // Quote the compiler name in case it has something funny in it.
+ for (const char *p = compiler; *p; ++p)
+ {
+ switch (*p)
+ {
+ case '.':
+ case '^':
+ case '$':
+ case '*':
+ case '+':
+ case '?':
+ case '(':
+ case ')':
+ case '[':
+ case '{':
+ case '\\':
+ case '|':
+ buf << '\\';
+ break;
+ }
+ buf << *p;
+ }
+ buf << "$";
+
+ return buf.str ();
+}
+
+static char *
+libcc1_set_arguments (struct gcc_base_context *s,
+ const char *triplet_regexp,
+ int argc, char **argv)
+{
+ libcc1 *self = (libcc1 *) s;
+ regex_t triplet;
+ int code;
+
+ std::string rx = make_regexp (triplet_regexp, COMPILER_NAME);
+ code = regcomp (&triplet, rx.c_str (), REG_EXTENDED | REG_NOSUB);
+ if (code != 0)
+ {
+ size_t len = regerror (code, &triplet, NULL, 0);
+ char err[len];
+
+ regerror (code, &triplet, err, len);
+
+ return concat ("Could not compile regexp \"",
+ rx.c_str (),
+ "\": ",
+ err,
+ (char *) NULL);
+ }
+
+ std::string compiler;
+ if (!find_compiler (triplet, &compiler))
+ {
+ regfree (&triplet);
+ return concat ("Could not find a compiler matching \"",
+ rx.c_str (),
+ "\"",
+ (char *) NULL);
+ }
+ regfree (&triplet);
+
+ self->args.push_back (compiler);
+
+ for (int i = 0; i < argc; ++i)
+ self->args.push_back (argv[i]);
+
+ return NULL;
+}
+
+static void
+libcc1_set_source_file (struct gcc_base_context *s,
+ const char *file)
+{
+ libcc1 *self = (libcc1 *) s;
+
+ self->source_file = file;
+}
+
+static void
+libcc1_set_print_callback (struct gcc_base_context *s,
+ void (*print_function) (void *datum,
+ const char *message),
+ void *datum)
+{
+ libcc1 *self = (libcc1 *) s;
+
+ self->print_function = print_function;
+ self->print_datum = datum;
+}
+
+static int
+fork_exec (libcc1 *self, char **argv, int spair_fds[2], int stderr_fds[2])
+{
+ pid_t child_pid = fork ();
+
+ if (child_pid == -1)
+ {
+ close (spair_fds[0]);
+ close (spair_fds[1]);
+ close (stderr_fds[0]);
+ close (stderr_fds[1]);
+ return 0;
+ }
+
+ if (child_pid == 0)
+ {
+ // Child.
+ dup2 (stderr_fds[1], 1);
+ dup2 (stderr_fds[1], 2);
+ close (stderr_fds[0]);
+ close (stderr_fds[1]);
+ close (spair_fds[0]);
+
+ execvp (argv[0], argv);
+ _exit (127);
+ }
+ else
+ {
+ // Parent.
+ close (spair_fds[1]);
+ close (stderr_fds[1]);
+
+ cc1_plugin::status result = cc1_plugin::FAIL;
+ if (self->connection->send ('H')
+ && ::cc1_plugin::marshall (self->connection, GCC_C_FE_VERSION_0))
+ result = self->connection->wait_for_query ();
+
+ close (spair_fds[0]);
+ close (stderr_fds[0]);
+
+ while (true)
+ {
+ int status;
+
+ if (waitpid (child_pid, &status, 0) == -1)
+ {
+ if (errno != EINTR)
+ return 0;
+ }
+
+ if (!WIFEXITED (status) || WEXITSTATUS (status) != 0)
+ return 0;
+ break;
+ }
+
+ if (!result)
+ return 0;
+ return 1;
+ }
+}
+
+static int
+libcc1_compile (struct gcc_base_context *s,
+ const char *filename,
+ int verbose)
+{
+ libcc1 *self = (libcc1 *) s;
+
+ int fds[2];
+ if (socketpair (AF_LOCAL, SOCK_STREAM, 0, fds) != 0)
+ {
+ self->print ("could not create socketpair\n");
+ return 0;
+ }
+
+ int stderr_fds[2];
+ if (pipe (stderr_fds) != 0)
+ {
+ self->print ("could not create pipe\n");
+ close (fds[0]);
+ close (fds[1]);
+ return 0;
+ }
+
+ self->args.push_back ("-fplugin=libcc1plugin");
+ char buf[100];
+ if (snprintf (buf, sizeof (buf), "-fplugin-arg-libcc1plugin-fd=%d", fds[1])
+ >= (long) sizeof (buf))
+ abort ();
+ self->args.push_back (buf);
+
+ self->args.push_back (self->source_file);
+ self->args.push_back ("-c");
+ self->args.push_back ("-o");
+ self->args.push_back (filename);
+ if (verbose)
+ self->args.push_back ("-v");
+
+ self->connection = new libcc1_connection (fds[0], stderr_fds[0], self);
+
+ cc1_plugin::callback_ftype *fun
+ = cc1_plugin::callback<int,
+ enum gcc_c_oracle_request,
+ const char *,
+ call_binding_oracle>;
+ self->connection->add_callback ("binding_oracle", fun);
+
+ fun = cc1_plugin::callback<gcc_address,
+ const char *,
+ call_symbol_address>;
+ self->connection->add_callback ("address_oracle", fun);
+
+ char **argv = new (std::nothrow) char *[self->args.size () + 1];
+ if (argv == NULL)
+ return 0;
+
+ for (unsigned int i = 0; i < self->args.size (); ++i)
+ argv[i] = const_cast<char *> (self->args[i].c_str ());
+ argv[self->args.size ()] = NULL;
+
+ return fork_exec (self, argv, fds, stderr_fds);
+}
+
+static void
+libcc1_destroy (struct gcc_base_context *s)
+{
+ libcc1 *self = (libcc1 *) s;
+
+ delete self;
+}
+
+static const struct gcc_base_vtable vtable =
+{
+ GCC_FE_VERSION_0,
+ libcc1_set_arguments,
+ libcc1_set_source_file,
+ libcc1_set_print_callback,
+ libcc1_compile,
+ libcc1_destroy
+};
+
+extern "C" gcc_c_fe_context_function gcc_c_fe_context;
+
+#ifdef __GNUC__
+#pragma GCC visibility push(default)
+#endif
+
+extern "C"
+struct gcc_c_context *
+gcc_c_fe_context (enum gcc_base_api_version base_version,
+ enum gcc_c_api_version c_version)
+{
+ if (base_version != GCC_FE_VERSION_0 || c_version != GCC_C_FE_VERSION_0)
+ return NULL;
+
+ return new libcc1 (&vtable, &c_vtable);
+}
diff --git a/libcc1/libcc1.sym b/libcc1/libcc1.sym
new file mode 100644
index 0000000..86b1e3e
--- /dev/null
+++ b/libcc1/libcc1.sym
@@ -0,0 +1 @@
+gcc_c_fe_context
diff --git a/libcc1/libcc1plugin.sym b/libcc1/libcc1plugin.sym
new file mode 100644
index 0000000..05d0f7b
--- /dev/null
+++ b/libcc1/libcc1plugin.sym
@@ -0,0 +1,2 @@
+plugin_init
+plugin_is_GPL_compatible
diff --git a/libcc1/marshall.cc b/libcc1/marshall.cc
new file mode 100644
index 0000000..9119de6
--- /dev/null
+++ b/libcc1/marshall.cc
@@ -0,0 +1,166 @@
+/* Marshalling and unmarshalling.
+ Copyright (C) 2014 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC 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, or (at your option) any later
+version.
+
+GCC 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 GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#include <cc1plugin-config.h>
+#include <new>
+#include <string.h>
+#include "marshall.hh"
+#include "connection.hh"
+
+cc1_plugin::status
+cc1_plugin::unmarshall_check (connection *conn, unsigned long long check)
+{
+ unsigned long long r;
+
+ if (!unmarshall (conn, &r))
+ return FAIL;
+ return check == r ? OK : FAIL;
+}
+
+cc1_plugin::status
+cc1_plugin::marshall_intlike (connection *conn, unsigned long long val)
+{
+ if (!conn->send ('i'))
+ return FAIL;
+ return conn->send (&val, sizeof (val));
+}
+
+cc1_plugin::status
+cc1_plugin::unmarshall_intlike (connection *conn, unsigned long long *result)
+{
+ if (!conn->require ('i'))
+ return FAIL;
+ return conn->get (result, sizeof (*result));
+}
+
+cc1_plugin::status
+cc1_plugin::unmarshall (connection *conn, enum gcc_c_symbol_kind *result)
+{
+ protocol_int p;
+ if (!unmarshall_intlike (conn, &p))
+ return FAIL;
+ *result = (enum gcc_c_symbol_kind) p;
+ return OK;
+}
+
+cc1_plugin::status
+cc1_plugin::unmarshall (connection *conn, enum gcc_c_oracle_request *result)
+{
+ protocol_int p;
+ if (!unmarshall_intlike (conn, &p))
+ return FAIL;
+ *result = (enum gcc_c_oracle_request) p;
+ return OK;
+}
+
+cc1_plugin::status
+cc1_plugin::unmarshall (connection *conn, enum gcc_qualifiers *result)
+{
+ protocol_int p;
+ if (!unmarshall_intlike (conn, &p))
+ return FAIL;
+ *result = (enum gcc_qualifiers) p;
+ return OK;
+}
+
+cc1_plugin::status
+cc1_plugin::marshall (connection *conn, const char *str)
+{
+ if (!conn->send ('s'))
+ return FAIL;
+
+ unsigned long long len = str == NULL ? -1ULL : strlen (str);
+ if (!conn->send (&len, sizeof (len)))
+ return FAIL;
+
+ if (str == NULL)
+ return OK;
+
+ return conn->send (str, len);
+}
+
+cc1_plugin::status
+cc1_plugin::unmarshall (connection *conn, char **result)
+{
+ unsigned long long len;
+
+ if (!conn->require ('s'))
+ return FAIL;
+ if (!conn->get (&len, sizeof (len)))
+ return FAIL;
+
+ if (len == -1ULL)
+ {
+ *result = NULL;
+ return OK;
+ }
+
+ char *str = new (std::nothrow) char[len + 1];
+ if (str == NULL)
+ return FAIL;
+
+ if (!conn->get (str, len))
+ {
+ delete[] str;
+ return FAIL;
+ }
+
+ str[len] = '\0';
+ *result = str;
+
+ return OK;
+}
+
+cc1_plugin::status
+cc1_plugin::marshall (connection *conn, const gcc_type_array *a)
+{
+ if (!conn->send ('a'))
+ return FAIL;
+
+ unsigned long long r = a->n_elements;
+ if (!conn->send (&r, sizeof (r)))
+ return FAIL;
+
+ return conn->send (a->elements, r * sizeof (a->elements[0]));
+}
+
+cc1_plugin::status
+cc1_plugin::unmarshall (connection *conn, gcc_type_array **result)
+{
+ unsigned long long len;
+
+ if (!conn->require ('a'))
+ return FAIL;
+ if (!conn->get (&len, sizeof (len)))
+ return FAIL;
+
+ *result = new gcc_type_array;
+
+ (*result)->n_elements = len;
+ (*result)->elements = new gcc_type[len];
+
+ if (!conn->get ((*result)->elements, len * sizeof ((*result)->elements[0])))
+ {
+ delete[] (*result)->elements;
+ delete *result;
+ return FAIL;
+ }
+
+ return OK;
+}
diff --git a/libcc1/marshall.hh b/libcc1/marshall.hh
new file mode 100644
index 0000000..3f936e7
--- /dev/null
+++ b/libcc1/marshall.hh
@@ -0,0 +1,93 @@
+/* Marshalling and unmarshalling.
+ Copyright (C) 2014 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC 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, or (at your option) any later
+version.
+
+GCC 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 GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#ifndef CC1_PLUGIN_MARSHALL_HH
+#define CC1_PLUGIN_MARSHALL_HH
+
+#include "status.hh"
+#include "gcc-c-interface.h"
+
+namespace cc1_plugin
+{
+ class connection;
+
+ // Only a single kind of integer is ever sent over the wire, and
+ // this is it.
+ typedef unsigned long long protocol_int;
+
+ // Read an integer from the connection and verify that it has the
+ // value V.
+ status unmarshall_check (connection *, protocol_int v);
+
+ // Write an integer, prefixed with the integer type marker, to the
+ // connection.
+ status marshall_intlike (connection *, protocol_int);
+
+ // Read a type marker from the connection and verify that it is an
+ // integer type marker. If not, return FAIL. If so, read an
+ // integer store it in the out argument.
+ status unmarshall_intlike (connection *, protocol_int *);
+
+ // A template function that can handle marshalling various integer
+ // objects to the connection.
+ template<typename T>
+ status marshall (connection *conn, T scalar)
+ {
+ return marshall_intlike (conn, scalar);
+ }
+
+ // A template function that can handle unmarshalling various integer
+ // objects from the connection. Note that this can't be
+ // instantiated for enum types. Note also that there's no way at
+ // the protocol level to distinguish different int types.
+ template<typename T>
+ status unmarshall (connection *conn, T *scalar)
+ {
+ protocol_int result;
+
+ if (!unmarshall_intlike (conn, &result))
+ return FAIL;
+ *scalar = result;
+ return OK;
+ }
+
+ // Unmarshallers for some specific enum types. With C++11 we
+ // wouldn't need these, as we could add type traits to the scalar
+ // unmarshaller.
+ status unmarshall (connection *, enum gcc_c_symbol_kind *);
+ status unmarshall (connection *, enum gcc_qualifiers *);
+ status unmarshall (connection *, enum gcc_c_oracle_request *);
+
+ // Send a string type marker followed by a string.
+ status marshall (connection *, const char *);
+
+ // Read a string type marker followed by a string. The caller is
+ // responsible for freeing the resulting string using 'delete[]'.
+ status unmarshall (connection *, char **);
+
+ // Send a gcc_type_array marker followed by the array.
+ status marshall (connection *, const gcc_type_array *);
+
+ // Read a gcc_type_array marker, followed by a gcc_type_array. The
+ // resulting array must be freed by the caller, using 'delete[]' on
+ // the elements, and 'delete' on the array object itself.
+ status unmarshall (connection *, struct gcc_type_array **);
+};
+
+#endif // CC1_PLUGIN_MARSHALL_HH
diff --git a/libcc1/names.cc b/libcc1/names.cc
new file mode 100644
index 0000000..5ddfa7b
--- /dev/null
+++ b/libcc1/names.cc
@@ -0,0 +1,46 @@
+/* String definitions.
+ Copyright (C) 2014 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC 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, or (at your option) any later
+version.
+
+GCC 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 GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#include <cc1plugin-config.h>
+#include "names.hh"
+
+#define GCC_METHOD0(R, N) \
+ const char *cc1_plugin::N = # N;
+#define GCC_METHOD1(R, N, A) \
+ const char *cc1_plugin::N = # N;
+#define GCC_METHOD2(R, N, A, B) \
+ const char *cc1_plugin::N = # N;
+#define GCC_METHOD3(R, N, A, B, C) \
+ const char *cc1_plugin::N = # N;
+#define GCC_METHOD4(R, N, A, B, C, D) \
+ const char *cc1_plugin::N = # N;
+#define GCC_METHOD5(R, N, A, B, C, D, E) \
+ const char *cc1_plugin::N = # N;
+#define GCC_METHOD7(R, N, A, B, C, D, E, F, G) \
+ const char *cc1_plugin::N = # N;
+
+#include "gcc-c-fe.def"
+
+#undef GCC_METHOD0
+#undef GCC_METHOD1
+#undef GCC_METHOD2
+#undef GCC_METHOD3
+#undef GCC_METHOD4
+#undef GCC_METHOD5
+#undef GCC_METHOD7
diff --git a/libcc1/names.hh b/libcc1/names.hh
new file mode 100644
index 0000000..9bda8d5
--- /dev/null
+++ b/libcc1/names.hh
@@ -0,0 +1,55 @@
+/* String declarations.
+ Copyright (C) 2014 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC 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, or (at your option) any later
+version.
+
+GCC 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 GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#ifndef CC1_PLUGIN_NAMES_HH
+#define CC1_PLUGIN_NAMES_HH
+
+namespace cc1_plugin
+{
+ // This code defines global string constants, one for each method in
+ // gcc-c-fe.def. This is needed so that they can be used as
+ // template arguments elsewhere.
+
+#define GCC_METHOD0(R, N) \
+ extern const char *N;
+#define GCC_METHOD1(R, N, A) \
+ extern const char *N;
+#define GCC_METHOD2(R, N, A, B) \
+ extern const char *N;
+#define GCC_METHOD3(R, N, A, B, C) \
+ extern const char *N;
+#define GCC_METHOD4(R, N, A, B, C, D) \
+ extern const char *N;
+#define GCC_METHOD5(R, N, A, B, C, D, E) \
+ extern const char *N;
+#define GCC_METHOD7(R, N, A, B, C, D, E, F, G) \
+ extern const char *N;
+
+#include "gcc-c-fe.def"
+
+#undef GCC_METHOD0
+#undef GCC_METHOD1
+#undef GCC_METHOD2
+#undef GCC_METHOD3
+#undef GCC_METHOD4
+#undef GCC_METHOD5
+#undef GCC_METHOD7
+};
+
+#endif // CC1_PLUGIN_NAMES_HH
diff --git a/libcc1/plugin.cc b/libcc1/plugin.cc
new file mode 100644
index 0000000..fbb49d3
--- /dev/null
+++ b/libcc1/plugin.cc
@@ -0,0 +1,919 @@
+/* Library interface to C front end
+ Copyright (C) 2014 Free Software Foundation, Inc.
+
+ This file is part of GCC.
+
+ GCC 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, or (at your option) any later
+ version.
+
+ GCC 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 GCC; see the file COPYING3. If not see
+ <http://www.gnu.org/licenses/>. */
+
+#include <cc1plugin-config.h>
+
+#undef PACKAGE_NAME
+#undef PACKAGE_STRING
+#undef PACKAGE_TARNAME
+#undef PACKAGE_VERSION
+
+#include "../gcc/config.h"
+
+#undef PACKAGE_NAME
+#undef PACKAGE_STRING
+#undef PACKAGE_TARNAME
+#undef PACKAGE_VERSION
+
+#include "gcc-plugin.h"
+#include "system.h"
+#include "coretypes.h"
+#include "stringpool.h"
+
+#include "gcc-interface.h"
+#include "tree-core.h"
+#include "wide-int.h"
+#include "stor-layout.h"
+#include "c-tree.h"
+#include "toplev.h"
+#include "timevar.h"
+#include "hash-table.h"
+#include "tm.h"
+#include "c-family/c-pragma.h"
+#include "c-lang.h"
+#include "diagnostic.h"
+#include "langhooks.h"
+#include "langhooks-def.h"
+
+#include "callbacks.hh"
+#include "connection.hh"
+#include "rpc.hh"
+
+#include <string>
+
+#ifdef __GNUC__
+#pragma GCC visibility push(default)
+#endif
+int plugin_is_GPL_compatible;
+#ifdef __GNUC__
+#pragma GCC visibility pop
+#endif
+
+
+
+// This is put into the lang hooks when the plugin starts.
+
+static void
+plugin_print_error_function (diagnostic_context *context, const char *file,
+ diagnostic_info *diagnostic)
+{
+ if (current_function_decl != NULL_TREE
+ && DECL_NAME (current_function_decl) != NULL_TREE
+ && strcmp (IDENTIFIER_POINTER (DECL_NAME (current_function_decl)),
+ GCC_FE_WRAPPER_FUNCTION) == 0)
+ return;
+ lhd_print_error_function (context, file, diagnostic);
+}
+
+
+
+static unsigned long long
+convert_out (tree t)
+{
+ return (unsigned long long) (uintptr_t) t;
+}
+
+static tree
+convert_in (unsigned long long v)
+{
+ return (tree) (uintptr_t) v;
+}
+
+
+
+struct decl_addr_value
+{
+ tree decl;
+ tree address;
+};
+
+struct decl_addr_hasher : typed_free_remove<decl_addr_value>
+{
+ typedef decl_addr_value value_type;
+ typedef decl_addr_value compare_type;
+
+ static inline hashval_t hash (const value_type *);
+ static inline bool equal (const value_type *, const compare_type *);
+};
+
+inline hashval_t
+decl_addr_hasher::hash (const value_type *e)
+{
+ return IDENTIFIER_HASH_VALUE (DECL_NAME (e->decl));
+}
+
+inline bool
+decl_addr_hasher::equal (const value_type *p1, const compare_type *p2)
+{
+ return p1->decl == p2->decl;
+}
+
+
+
+struct string_hasher : typed_noop_remove<char>
+{
+ typedef char value_type;
+ typedef char compare_type;
+
+ static inline hashval_t hash (const value_type *s)
+ {
+ return htab_hash_string (s);
+ }
+
+ static inline bool equal (const value_type *p1, const value_type *p2)
+ {
+ return strcmp (p1, p2) == 0;
+ }
+};
+
+
+
+// A wrapper for pushdecl that doesn't let gdb have a chance to
+// instantiate a symbol.
+
+static void
+pushdecl_safe (tree decl)
+{
+ void (*save) (enum c_oracle_request, tree identifier);
+
+ save = c_binding_oracle;
+ c_binding_oracle = NULL;
+ pushdecl (decl);
+ c_binding_oracle = save;
+}
+
+
+
+struct plugin_context : public cc1_plugin::connection
+{
+ plugin_context (int fd);
+
+ // Map decls to addresses.
+ hash_table<decl_addr_hasher> address_map;
+
+ // A collection of trees that are preserved for the GC.
+ hash_table< pointer_hash<tree_node> > preserved;
+
+ // File name cache.
+ hash_table<string_hasher> file_names;
+
+ // Perform GC marking.
+ void mark ();
+
+ // Preserve a tree during the plugin's operation.
+ tree preserve (tree t)
+ {
+ tree_node **slot = preserved.find_slot (t, INSERT);
+ *slot = t;
+ return t;
+ }
+
+ source_location get_source_location (const char *filename,
+ unsigned int line_number)
+ {
+ if (filename == NULL)
+ return UNKNOWN_LOCATION;
+
+ filename = intern_filename (filename);
+ linemap_add (line_table, LC_ENTER, false, filename, line_number);
+ source_location loc = linemap_line_start (line_table, line_number, 0);
+ linemap_add (line_table, LC_LEAVE, false, NULL, 0);
+ return loc;
+ }
+
+private:
+
+ // Add a file name to FILE_NAMES and return the canonical copy.
+ const char *intern_filename (const char *filename)
+ {
+ char **slot = file_names.find_slot (filename, INSERT);
+ if (*slot == NULL)
+ {
+ /* The file name must live as long as the line map, which
+ effectively means as long as this compilation. So, we copy
+ the string here but never free it. */
+ *slot = xstrdup (filename);
+ }
+ return *slot;
+ }
+};
+
+static plugin_context *current_context;
+
+
+
+plugin_context::plugin_context (int fd)
+ : cc1_plugin::connection (fd),
+ address_map (),
+ preserved (),
+ file_names ()
+{
+ address_map.create (20);
+ preserved.create (20);
+ file_names.create (20);
+}
+
+void
+plugin_context::mark ()
+{
+ for (hash_table<decl_addr_hasher>::iterator it = address_map.begin ();
+ it != address_map.end ();
+ ++it)
+ {
+ ggc_mark ((*it).decl);
+ ggc_mark ((*it).address);
+ }
+
+ for (hash_table< pointer_hash<tree_node> >::iterator it = preserved.begin ();
+ it != preserved.end ();
+ ++it)
+ ggc_mark (&*it);
+}
+
+static void
+plugin_binding_oracle (enum c_oracle_request kind, tree identifier)
+{
+ enum gcc_c_oracle_request request;
+
+ gcc_assert (current_context != NULL);
+
+ switch (kind)
+ {
+ case C_ORACLE_SYMBOL:
+ request = GCC_C_ORACLE_SYMBOL;
+ break;
+ case C_ORACLE_TAG:
+ request = GCC_C_ORACLE_TAG;
+ break;
+ case C_ORACLE_LABEL:
+ request = GCC_C_ORACLE_LABEL;
+ break;
+ default:
+ abort ();
+ }
+
+ int ignore;
+ cc1_plugin::call (current_context, "binding_oracle", &ignore,
+ request, IDENTIFIER_POINTER (identifier));
+}
+
+static void
+plugin_pragma_user_expression (cpp_reader *)
+{
+ c_binding_oracle = plugin_binding_oracle;
+}
+
+static void
+plugin_init_extra_pragmas (void *, void *)
+{
+ c_register_pragma ("GCC", "user_expression", plugin_pragma_user_expression);
+}
+
+
+
+// Maybe rewrite a decl to its address.
+static tree
+address_rewriter (tree *in, int *walk_subtrees, void *arg)
+{
+ plugin_context *ctx = (plugin_context *) arg;
+
+ if (!DECL_P (*in) || DECL_NAME (*in) == NULL_TREE)
+ return NULL_TREE;
+
+ decl_addr_value value;
+ value.decl = *in;
+ decl_addr_value *found_value = ctx->address_map.find (&value);
+ if (found_value != NULL)
+ {
+ // At this point we don't need VLA sizes for gdb-supplied
+ // variables, and having them here confuses later passes, so we
+ // drop them.
+ if (C_TYPE_VARIABLE_SIZE (TREE_TYPE (*in)))
+ {
+ TREE_TYPE (*in)
+ = build_array_type_nelts (TREE_TYPE (TREE_TYPE (*in)), 1);
+ DECL_SIZE (*in) = TYPE_SIZE (TREE_TYPE (*in));
+ DECL_SIZE_UNIT (*in) = TYPE_SIZE_UNIT (TREE_TYPE (*in));
+ }
+ }
+ else if (DECL_IS_BUILTIN (*in))
+ {
+ gcc_address address;
+
+ if (!cc1_plugin::call (ctx, "address_oracle", &address,
+ IDENTIFIER_POINTER (DECL_NAME (*in))))
+ return NULL_TREE;
+ if (address == 0)
+ return NULL_TREE;
+
+ // Insert the decl into the address map in case it is referenced
+ // again.
+ value.address = build_int_cst_type (ptr_type_node, address);
+ decl_addr_value **slot = ctx->address_map.find_slot (&value, INSERT);
+ gcc_assert (*slot == NULL);
+ *slot
+ = static_cast<decl_addr_value *> (xmalloc (sizeof (decl_addr_value)));
+ **slot = value;
+ found_value = *slot;
+ }
+ else
+ return NULL_TREE;
+
+ if (found_value->address != error_mark_node)
+ {
+ // We have an address for the decl, so rewrite the tree.
+ tree ptr_type = build_pointer_type (TREE_TYPE (*in));
+ *in = fold_build1 (INDIRECT_REF, TREE_TYPE (*in),
+ fold_build1 (CONVERT_EXPR, ptr_type,
+ found_value->address));
+ }
+
+ *walk_subtrees = 0;
+
+ return NULL_TREE;
+}
+
+// When generating code for gdb, we want to be able to use absolute
+// addresses to refer to otherwise external objects that gdb knows
+// about. gdb passes in these addresses when building decls, and then
+// before gimplification we go through the trees, rewriting uses to
+// the equivalent of "*(TYPE *) ADDR".
+static void
+rewrite_decls_to_addresses (void *function_in, void *)
+{
+ tree function = (tree) function_in;
+
+ // Do nothing if we're not in gdb.
+ if (current_context == NULL)
+ return;
+
+ walk_tree (&DECL_SAVED_TREE (function), address_rewriter, current_context,
+ NULL);
+}
+
+
+
+gcc_decl
+plugin_build_decl (cc1_plugin::connection *self,
+ const char *name,
+ enum gcc_c_symbol_kind sym_kind,
+ gcc_type sym_type_in,
+ const char *substitution_name,
+ gcc_address address,
+ const char *filename,
+ unsigned int line_number)
+{
+ plugin_context *ctx = static_cast<plugin_context *> (self);
+ tree identifier = get_identifier (name);
+ enum tree_code code;
+ tree decl;
+ tree sym_type = convert_in (sym_type_in);
+
+ switch (sym_kind)
+ {
+ case GCC_C_SYMBOL_FUNCTION:
+ code = FUNCTION_DECL;
+ break;
+
+ case GCC_C_SYMBOL_VARIABLE:
+ code = VAR_DECL;
+ break;
+
+ case GCC_C_SYMBOL_TYPEDEF:
+ code = TYPE_DECL;
+ break;
+
+ case GCC_C_SYMBOL_LABEL:
+ // FIXME: we aren't ready to handle labels yet.
+ // It isn't clear how to translate them properly
+ // and in any case a "goto" isn't likely to work.
+ return convert_out (error_mark_node);
+
+ default:
+ abort ();
+ }
+
+ source_location loc = ctx->get_source_location (filename, line_number);
+
+ decl = build_decl (loc, code, identifier, sym_type);
+ TREE_USED (decl) = 1;
+ TREE_ADDRESSABLE (decl) = 1;
+
+ if (sym_kind != GCC_C_SYMBOL_TYPEDEF)
+ {
+ decl_addr_value value;
+
+ value.decl = decl;
+ if (substitution_name != NULL)
+ {
+ // If the translator gave us a name without a binding,
+ // we can just substitute error_mark_node, since we know the
+ // translator will be reporting an error anyhow.
+ value.address
+ = lookup_name (get_identifier (substitution_name));
+ if (value.address == NULL_TREE)
+ value.address = error_mark_node;
+ }
+ else
+ value.address = build_int_cst_type (ptr_type_node, address);
+ decl_addr_value **slot = ctx->address_map.find_slot (&value, INSERT);
+ gcc_assert (*slot == NULL);
+ *slot
+ = static_cast<decl_addr_value *> (xmalloc (sizeof (decl_addr_value)));
+ **slot = value;
+ }
+
+ return convert_out (ctx->preserve (decl));
+}
+
+int
+plugin_bind (cc1_plugin::connection *,
+ gcc_decl decl_in, int is_global)
+{
+ tree decl = convert_in (decl_in);
+ c_bind (DECL_SOURCE_LOCATION (decl), decl, is_global);
+ rest_of_decl_compilation (decl, is_global, 0);
+ return 1;
+}
+
+int
+plugin_tagbind (cc1_plugin::connection *self,
+ const char *name, gcc_type tagged_type,
+ const char *filename, unsigned int line_number)
+{
+ plugin_context *ctx = static_cast<plugin_context *> (self);
+ c_pushtag (ctx->get_source_location (filename, line_number),
+ get_identifier (name), convert_in (tagged_type));
+ return 1;
+}
+
+gcc_type
+plugin_build_pointer_type (cc1_plugin::connection *,
+ gcc_type base_type)
+{
+ // No need to preserve a pointer type as the base type is preserved.
+ return convert_out (build_pointer_type (convert_in (base_type)));
+}
+
+gcc_type
+plugin_build_record_type (cc1_plugin::connection *self)
+{
+ plugin_context *ctx = static_cast<plugin_context *> (self);
+ return convert_out (ctx->preserve (make_node (RECORD_TYPE)));
+}
+
+gcc_type
+plugin_build_union_type (cc1_plugin::connection *self)
+{
+ plugin_context *ctx = static_cast<plugin_context *> (self);
+ return convert_out (ctx->preserve (make_node (UNION_TYPE)));
+}
+
+int
+plugin_build_add_field (cc1_plugin::connection *,
+ gcc_type record_or_union_type_in,
+ const char *field_name,
+ gcc_type field_type_in,
+ unsigned long bitsize,
+ unsigned long bitpos)
+{
+ tree record_or_union_type = convert_in (record_or_union_type_in);
+ tree field_type = convert_in (field_type_in);
+
+ gcc_assert (TREE_CODE (record_or_union_type) == RECORD_TYPE
+ || TREE_CODE (record_or_union_type) == UNION_TYPE);
+
+ /* Note that gdb does not preserve the location of field decls, so
+ we can't provide a decent location here. */
+ tree decl = build_decl (BUILTINS_LOCATION, FIELD_DECL,
+ get_identifier (field_name), field_type);
+ DECL_FIELD_CONTEXT (decl) = record_or_union_type;
+
+ if (TREE_CODE (field_type) == INTEGER_TYPE
+ && TYPE_PRECISION (field_type) != bitsize)
+ {
+ DECL_BIT_FIELD_TYPE (decl) = field_type;
+ TREE_TYPE (decl)
+ = c_build_bitfield_integer_type (bitsize, TYPE_UNSIGNED (field_type));
+ }
+
+ DECL_MODE (decl) = TYPE_MODE (TREE_TYPE (decl));
+
+ // There's no way to recover this from DWARF.
+ SET_DECL_OFFSET_ALIGN (decl, TYPE_PRECISION (pointer_sized_int_node));
+
+ tree pos = bitsize_int (bitpos);
+ pos_from_bit (&DECL_FIELD_OFFSET (decl), &DECL_FIELD_BIT_OFFSET (decl),
+ DECL_OFFSET_ALIGN (decl), pos);
+
+ DECL_SIZE (decl) = bitsize_int (bitsize);
+ DECL_SIZE_UNIT (decl) = size_int ((bitsize + BITS_PER_UNIT - 1)
+ / BITS_PER_UNIT);
+
+ DECL_CHAIN (decl) = TYPE_FIELDS (record_or_union_type);
+ TYPE_FIELDS (record_or_union_type) = decl;
+
+ return 1;
+}
+
+int
+plugin_finish_record_or_union (cc1_plugin::connection *,
+ gcc_type record_or_union_type_in,
+ unsigned long size_in_bytes)
+{
+ tree record_or_union_type = convert_in (record_or_union_type_in);
+
+ gcc_assert (TREE_CODE (record_or_union_type) == RECORD_TYPE
+ || TREE_CODE (record_or_union_type) == UNION_TYPE);
+
+ /* We built the field list in reverse order, so fix it now. */
+ TYPE_FIELDS (record_or_union_type)
+ = nreverse (TYPE_FIELDS (record_or_union_type));
+
+ if (TREE_CODE (record_or_union_type) == UNION_TYPE)
+ {
+ /* Unions can just be handled by the generic code. */
+ layout_type (record_or_union_type);
+ }
+ else
+ {
+ // FIXME there's no way to get this from DWARF,
+ // or even, it seems, a particularly good way to deduce it.
+ TYPE_ALIGN (record_or_union_type)
+ = TYPE_PRECISION (pointer_sized_int_node);
+
+ TYPE_SIZE (record_or_union_type) = bitsize_int (size_in_bytes
+ * BITS_PER_UNIT);
+ TYPE_SIZE_UNIT (record_or_union_type) = size_int (size_in_bytes);
+
+ compute_record_mode (record_or_union_type);
+ finish_bitfield_layout (record_or_union_type);
+ // FIXME we have no idea about TYPE_PACKED
+ }
+
+ return 1;
+}
+
+gcc_type
+plugin_build_enum_type (cc1_plugin::connection *self,
+ gcc_type underlying_int_type_in)
+{
+ tree underlying_int_type = convert_in (underlying_int_type_in);
+
+ if (underlying_int_type == error_mark_node)
+ return convert_out (error_mark_node);
+
+ tree result = make_node (ENUMERAL_TYPE);
+
+ TYPE_PRECISION (result) = TYPE_PRECISION (underlying_int_type);
+ TYPE_UNSIGNED (result) = TYPE_UNSIGNED (underlying_int_type);
+
+ plugin_context *ctx = static_cast<plugin_context *> (self);
+ return convert_out (ctx->preserve (result));
+}
+
+int
+plugin_build_add_enum_constant (cc1_plugin::connection *,
+ gcc_type enum_type_in,
+ const char *name,
+ unsigned long value)
+{
+ tree cst, decl, cons;
+ tree enum_type = convert_in (enum_type_in);
+
+ gcc_assert (TREE_CODE (enum_type) == ENUMERAL_TYPE);
+
+ cst = build_int_cst (enum_type, value);
+ /* Note that gdb does not preserve the location of enum constants,
+ so we can't provide a decent location here. */
+ decl = build_decl (BUILTINS_LOCATION, CONST_DECL,
+ get_identifier (name), enum_type);
+ DECL_INITIAL (decl) = cst;
+ pushdecl_safe (decl);
+
+ cons = tree_cons (DECL_NAME (decl), cst, TYPE_VALUES (enum_type));
+ TYPE_VALUES (enum_type) = cons;
+
+ return 1;
+}
+
+int
+plugin_finish_enum_type (cc1_plugin::connection *,
+ gcc_type enum_type_in)
+{
+ tree enum_type = convert_in (enum_type_in);
+ tree minnode, maxnode, iter;
+
+ iter = TYPE_VALUES (enum_type);
+ minnode = maxnode = TREE_VALUE (iter);
+ for (iter = TREE_CHAIN (iter);
+ iter != NULL_TREE;
+ iter = TREE_CHAIN (iter))
+ {
+ tree value = TREE_VALUE (iter);
+ if (tree_int_cst_lt (maxnode, value))
+ maxnode = value;
+ if (tree_int_cst_lt (value, minnode))
+ minnode = value;
+ }
+ TYPE_MIN_VALUE (enum_type) = minnode;
+ TYPE_MAX_VALUE (enum_type) = maxnode;
+
+ layout_type (enum_type);
+
+ return 1;
+}
+
+gcc_type
+plugin_build_function_type (cc1_plugin::connection *self,
+ gcc_type return_type_in,
+ const struct gcc_type_array *argument_types_in,
+ int is_varargs)
+{
+ tree *argument_types;
+ tree return_type = convert_in (return_type_in);
+ tree result;
+
+ argument_types = new tree[argument_types_in->n_elements];
+ for (int i = 0; i < argument_types_in->n_elements; ++i)
+ argument_types[i] = convert_in (argument_types_in->elements[i]);
+
+ if (is_varargs)
+ result = build_varargs_function_type_array (return_type,
+ argument_types_in->n_elements,
+ argument_types);
+ else
+ result = build_function_type_array (return_type,
+ argument_types_in->n_elements,
+ argument_types);
+
+ delete[] argument_types;
+
+ plugin_context *ctx = static_cast<plugin_context *> (self);
+ return convert_out (ctx->preserve (result));
+}
+
+gcc_type
+plugin_int_type (cc1_plugin::connection *self,
+ int is_unsigned, unsigned long size_in_bytes)
+{
+ tree result = c_common_type_for_size (BITS_PER_UNIT * size_in_bytes,
+ is_unsigned);
+ if (result == NULL_TREE)
+ result = error_mark_node;
+ else
+ {
+ plugin_context *ctx = static_cast<plugin_context *> (self);
+ ctx->preserve (result);
+ }
+ return convert_out (result);
+}
+
+gcc_type
+plugin_float_type (cc1_plugin::connection *,
+ unsigned long size_in_bytes)
+{
+ if (BITS_PER_UNIT * size_in_bytes == TYPE_PRECISION (float_type_node))
+ return convert_out (float_type_node);
+ if (BITS_PER_UNIT * size_in_bytes == TYPE_PRECISION (double_type_node))
+ return convert_out (double_type_node);
+ if (BITS_PER_UNIT * size_in_bytes == TYPE_PRECISION (long_double_type_node))
+ return convert_out (long_double_type_node);
+ return convert_out (error_mark_node);
+}
+
+gcc_type
+plugin_void_type (cc1_plugin::connection *)
+{
+ return convert_out (void_type_node);
+}
+
+gcc_type
+plugin_bool_type (cc1_plugin::connection *)
+{
+ return convert_out (boolean_type_node);
+}
+
+gcc_type
+plugin_build_array_type (cc1_plugin::connection *self,
+ gcc_type element_type_in, int num_elements)
+{
+ tree element_type = convert_in (element_type_in);
+ tree result;
+
+ if (num_elements == -1)
+ result = build_array_type (element_type, NULL_TREE);
+ else
+ result = build_array_type_nelts (element_type, num_elements);
+
+ plugin_context *ctx = static_cast<plugin_context *> (self);
+ return convert_out (ctx->preserve (result));
+}
+
+gcc_type
+plugin_build_vla_array_type (cc1_plugin::connection *self,
+ gcc_type element_type_in,
+ const char *upper_bound_name)
+{
+ tree element_type = convert_in (element_type_in);
+ tree upper_bound = lookup_name (get_identifier (upper_bound_name));
+ tree range = build_index_type (upper_bound);
+
+ tree result = build_array_type (element_type, range);
+ C_TYPE_VARIABLE_SIZE (result) = 1;
+
+ plugin_context *ctx = static_cast<plugin_context *> (self);
+ return convert_out (ctx->preserve (result));
+}
+
+gcc_type
+plugin_build_qualified_type (cc1_plugin::connection *,
+ gcc_type unqualified_type_in,
+ enum gcc_qualifiers qualifiers)
+{
+ tree unqualified_type = convert_in (unqualified_type_in);
+ int quals = 0;
+
+ if ((qualifiers & GCC_QUALIFIER_CONST) != 0)
+ quals |= TYPE_QUAL_CONST;
+ if ((qualifiers & GCC_QUALIFIER_VOLATILE) != 0)
+ quals |= TYPE_QUAL_VOLATILE;
+ if ((qualifiers & GCC_QUALIFIER_RESTRICT) != 0)
+ quals |= TYPE_QUAL_RESTRICT;
+
+ return convert_out (build_qualified_type (unqualified_type, quals));
+}
+
+gcc_type
+plugin_build_complex_type (cc1_plugin::connection *self,
+ gcc_type base_type)
+{
+ plugin_context *ctx = static_cast<plugin_context *> (self);
+ return convert_out (ctx->preserve (build_complex_type (convert_in (base_type))));
+}
+
+gcc_type
+plugin_build_vector_type (cc1_plugin::connection *self,
+ gcc_type base_type, int nunits)
+{
+ plugin_context *ctx = static_cast<plugin_context *> (self);
+ return convert_out (ctx->preserve (build_vector_type (convert_in (base_type),
+ nunits)));
+}
+
+int
+plugin_build_constant (cc1_plugin::connection *self, gcc_type type_in,
+ const char *name, unsigned long value,
+ const char *filename, unsigned int line_number)
+{
+ plugin_context *ctx = static_cast<plugin_context *> (self);
+ tree cst, decl;
+ tree type = convert_in (type_in);
+
+ cst = build_int_cst (type, value);
+ decl = build_decl (ctx->get_source_location (filename, line_number),
+ CONST_DECL, get_identifier (name), type);
+ DECL_INITIAL (decl) = cst;
+ pushdecl_safe (decl);
+
+ return 1;
+}
+
+gcc_type
+plugin_error (cc1_plugin::connection *,
+ const char *message)
+{
+ error ("%s", message);
+ return convert_out (error_mark_node);
+}
+
+
+
+// Perform GC marking.
+
+static void
+gc_mark (void *, void *)
+{
+ if (current_context != NULL)
+ current_context->mark ();
+}
+
+#ifdef __GNUC__
+#pragma GCC visibility push(default)
+#endif
+
+int
+plugin_init (struct plugin_name_args *plugin_info,
+ struct plugin_gcc_version *)
+{
+ long fd = -1;
+ for (int i = 0; i < plugin_info->argc; ++i)
+ {
+ if (strcmp (plugin_info->argv[i].key, "fd") == 0)
+ {
+ char *tail;
+ errno = 0;
+ fd = strtol (plugin_info->argv[i].value, &tail, 0);
+ if (*tail != '\0' || errno != 0)
+ fatal_error ("%s: invalid file descriptor argument to plugin",
+ plugin_info->base_name);
+ break;
+ }
+ }
+ if (fd == -1)
+ fatal_error ("%s: required plugin argument %<fd%> is missing",
+ plugin_info->base_name);
+
+ current_context = new plugin_context (fd);
+
+ // Handshake.
+ cc1_plugin::protocol_int version;
+ if (!current_context->require ('H')
+ || ! ::cc1_plugin::unmarshall (current_context, &version))
+ fatal_error ("%s: handshake failed", plugin_info->base_name);
+ if (version != GCC_C_FE_VERSION_0)
+ fatal_error ("%s: unknown version in handshake", plugin_info->base_name);
+
+ register_callback (plugin_info->base_name, PLUGIN_PRAGMAS,
+ plugin_init_extra_pragmas, NULL);
+ register_callback (plugin_info->base_name, PLUGIN_PRE_GENERICIZE,
+ rewrite_decls_to_addresses, NULL);
+ register_callback (plugin_info->base_name, PLUGIN_GGC_MARKING,
+ gc_mark, NULL);
+
+ lang_hooks.print_error_function = plugin_print_error_function;
+
+#define GCC_METHOD0(R, N) \
+ { \
+ cc1_plugin::callback_ftype *fun \
+ = cc1_plugin::callback<R, plugin_ ## N>; \
+ current_context->add_callback (# N, fun); \
+ }
+#define GCC_METHOD1(R, N, A) \
+ { \
+ cc1_plugin::callback_ftype *fun \
+ = cc1_plugin::callback<R, A, plugin_ ## N>; \
+ current_context->add_callback (# N, fun); \
+ }
+#define GCC_METHOD2(R, N, A, B) \
+ { \
+ cc1_plugin::callback_ftype *fun \
+ = cc1_plugin::callback<R, A, B, plugin_ ## N>; \
+ current_context->add_callback (# N, fun); \
+ }
+#define GCC_METHOD3(R, N, A, B, C) \
+ { \
+ cc1_plugin::callback_ftype *fun \
+ = cc1_plugin::callback<R, A, B, C, plugin_ ## N>; \
+ current_context->add_callback (# N, fun); \
+ }
+#define GCC_METHOD4(R, N, A, B, C, D) \
+ { \
+ cc1_plugin::callback_ftype *fun \
+ = cc1_plugin::callback<R, A, B, C, D, \
+ plugin_ ## N>; \
+ current_context->add_callback (# N, fun); \
+ }
+#define GCC_METHOD5(R, N, A, B, C, D, E) \
+ { \
+ cc1_plugin::callback_ftype *fun \
+ = cc1_plugin::callback<R, A, B, C, D, E, \
+ plugin_ ## N>; \
+ current_context->add_callback (# N, fun); \
+ }
+#define GCC_METHOD7(R, N, A, B, C, D, E, F, G) \
+ { \
+ cc1_plugin::callback_ftype *fun \
+ = cc1_plugin::callback<R, A, B, C, D, E, F, G, \
+ plugin_ ## N>; \
+ current_context->add_callback (# N, fun); \
+ }
+
+#include "gcc-c-fe.def"
+
+#undef GCC_METHOD0
+#undef GCC_METHOD1
+#undef GCC_METHOD2
+#undef GCC_METHOD3
+#undef GCC_METHOD4
+#undef GCC_METHOD5
+#undef GCC_METHOD7
+
+ return 0;
+}
diff --git a/libcc1/rpc.hh b/libcc1/rpc.hh
new file mode 100644
index 0000000..58758d3
--- /dev/null
+++ b/libcc1/rpc.hh
@@ -0,0 +1,486 @@
+/* RPC call and callback templates
+ Copyright (C) 2014 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC 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, or (at your option) any later
+version.
+
+GCC 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 GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#ifndef CC1_PLUGIN_RPC_HH
+#define CC1_PLUGIN_RPC_HH
+
+#include "status.hh"
+#include "marshall.hh"
+#include "connection.hh"
+
+namespace cc1_plugin
+{
+ // The plugin API may contain some "const" method parameters.
+ // However, when unmarshalling we cannot unmarshall into a const
+ // object; and furthermore we want to be able to deallocate pointers
+ // when finished with them. This wrapper class lets us properly
+ // remove the "const" and handle deallocation from pointer types.
+
+ template<typename T>
+ class argument_wrapper
+ {
+ public:
+
+ argument_wrapper () { }
+ ~argument_wrapper () { }
+
+ operator T () const { return m_object; }
+
+ status unmarshall (connection *conn)
+ {
+ return ::cc1_plugin::unmarshall (conn, &m_object);
+ }
+
+ private:
+
+ T m_object;
+
+ // No copying or assignment allowed.
+ argument_wrapper (const argument_wrapper &);
+ argument_wrapper &operator= (const argument_wrapper &);
+ };
+
+ // Specialization for any kind of pointer. This is declared but not
+ // defined to avoid bugs if a new pointer type is introduced into
+ // the API. Instead you will just get a compilation error.
+ template<typename T>
+ class argument_wrapper<const T *>;
+
+ // Specialization for string types.
+ template<>
+ class argument_wrapper<const char *>
+ {
+ public:
+ argument_wrapper () : m_object (NULL) { }
+ ~argument_wrapper ()
+ {
+ delete[] m_object;
+ }
+
+ operator const char * () const
+ {
+ return m_object;
+ }
+
+ status unmarshall (connection *conn)
+ {
+ return ::cc1_plugin::unmarshall (conn, &m_object);
+ }
+
+ private:
+
+ char *m_object;
+
+ // No copying or assignment allowed.
+ argument_wrapper (const argument_wrapper &);
+ argument_wrapper &operator= (const argument_wrapper &);
+ };
+
+ // Specialization for gcc_type_array.
+ template<>
+ class argument_wrapper<const gcc_type_array *>
+ {
+ public:
+ argument_wrapper () : m_object (NULL) { }
+ ~argument_wrapper ()
+ {
+ // It would be nicer if gcc_type_array could have a destructor.
+ // But, it is in code shared with gdb and cannot.
+ if (m_object != NULL)
+ delete[] m_object->elements;
+ delete m_object;
+ }
+
+ operator const gcc_type_array * () const
+ {
+ return m_object;
+ }
+
+ status unmarshall (connection *conn)
+ {
+ return ::cc1_plugin::unmarshall (conn, &m_object);
+ }
+
+ private:
+
+ gcc_type_array *m_object;
+
+ // No copying or assignment allowed.
+ argument_wrapper (const argument_wrapper &);
+ argument_wrapper &operator= (const argument_wrapper &);
+ };
+
+ // There are two kinds of template functions here: "call" and
+ // "callback". They are each repeated multiple times to handle
+ // different numbers of arguments. (This would be improved with
+ // C++11, though applying a call is still tricky until C++14 can be
+ // used.)
+
+ // The "call" template is used for making a remote procedure call.
+ // It starts a query ('Q') packet, marshalls its arguments, waits
+ // for a result, and finally reads and returns the result via an
+ // "out" parameter.
+
+ // The "callback" template is used when receiving a remote procedure
+ // call. This template function is suitable for use with the
+ // "callbacks" and "connection" classes. It decodes incoming
+ // arguments, passes them to the wrapped function, and finally
+ // marshalls a reply packet.
+
+ template<typename R>
+ status
+ call (connection *conn, const char *method, R *result)
+ {
+ if (!conn->send ('Q'))
+ return FAIL;
+ if (!marshall (conn, method))
+ return FAIL;
+ if (!marshall (conn, 0))
+ return FAIL;
+ if (!conn->wait_for_result ())
+ return FAIL;
+ if (!unmarshall (conn, result))
+ return FAIL;
+ return OK;
+ }
+
+ template<typename R, R (*func) (connection *)>
+ status
+ callback (connection *conn)
+ {
+ R result;
+
+ if (!unmarshall_check (conn, 0))
+ return FAIL;
+ result = func (conn);
+ if (!conn->send ('R'))
+ return FAIL;
+ return marshall (conn, result);
+ }
+
+ template<typename R, typename A>
+ status
+ call (connection *conn, const char *method, R *result, A arg)
+ {
+ if (!conn->send ('Q'))
+ return FAIL;
+ if (!marshall (conn, method))
+ return FAIL;
+ if (!marshall (conn, 1))
+ return FAIL;
+ if (!marshall (conn, arg))
+ return FAIL;
+ if (!conn->wait_for_result ())
+ return FAIL;
+ if (!unmarshall (conn, result))
+ return FAIL;
+ return OK;
+ }
+
+ template<typename R, typename A, R (*func) (connection *, A)>
+ status
+ callback (connection *conn)
+ {
+ argument_wrapper<A> arg;
+ R result;
+
+ if (!unmarshall_check (conn, 1))
+ return FAIL;
+ if (!arg.unmarshall (conn))
+ return FAIL;
+ result = func (conn, arg);
+ if (!conn->send ('R'))
+ return FAIL;
+ return marshall (conn, result);
+ }
+
+ template<typename R, typename A1, typename A2>
+ status
+ call (connection *conn, const char *method, R *result, A1 arg1, A2 arg2)
+ {
+ if (!conn->send ('Q'))
+ return FAIL;
+ if (!marshall (conn, method))
+ return FAIL;
+ if (!marshall (conn, 2))
+ return FAIL;
+ if (!marshall (conn, arg1))
+ return FAIL;
+ if (!marshall (conn, arg2))
+ return FAIL;
+ if (!conn->wait_for_result ())
+ return FAIL;
+ if (!unmarshall (conn, result))
+ return FAIL;
+ return OK;
+ }
+
+ template<typename R, typename A1, typename A2, R (*func) (connection *,
+ A1, A2)>
+ status
+ callback (connection *conn)
+ {
+ argument_wrapper<A1> arg1;
+ argument_wrapper<A2> arg2;
+ R result;
+
+ if (!unmarshall_check (conn, 2))
+ return FAIL;
+ if (!arg1.unmarshall (conn))
+ return FAIL;
+ if (!arg2.unmarshall (conn))
+ return FAIL;
+ result = func (conn, arg1, arg2);
+ if (!conn->send ('R'))
+ return FAIL;
+ return marshall (conn, result);
+ }
+
+ template<typename R, typename A1, typename A2, typename A3>
+ status
+ call (connection *conn, const char *method, R *result, A1 arg1, A2 arg2,
+ A3 arg3)
+ {
+ if (!conn->send ('Q'))
+ return FAIL;
+ if (!marshall (conn, method))
+ return FAIL;
+ if (!marshall (conn, 3))
+ return FAIL;
+ if (!marshall (conn, arg1))
+ return FAIL;
+ if (!marshall (conn, arg2))
+ return FAIL;
+ if (!marshall (conn, arg3))
+ return FAIL;
+ if (!conn->wait_for_result ())
+ return FAIL;
+ if (!unmarshall (conn, result))
+ return FAIL;
+ return OK;
+ }
+
+ template<typename R, typename A1, typename A2, typename A3,
+ R (*func) (connection *, A1, A2, A3)>
+ status
+ callback (connection *conn)
+ {
+ argument_wrapper<A1> arg1;
+ argument_wrapper<A2> arg2;
+ argument_wrapper<A3> arg3;
+ R result;
+
+ if (!unmarshall_check (conn, 3))
+ return FAIL;
+ if (!arg1.unmarshall (conn))
+ return FAIL;
+ if (!arg2.unmarshall (conn))
+ return FAIL;
+ if (!arg3.unmarshall (conn))
+ return FAIL;
+ result = func (conn, arg1, arg2, arg3);
+ if (!conn->send ('R'))
+ return FAIL;
+ return marshall (conn, result);
+ }
+
+ template<typename R, typename A1, typename A2, typename A3, typename A4>
+ status
+ call (connection *conn, const char *method, R *result, A1 arg1, A2 arg2,
+ A3 arg3, A4 arg4)
+ {
+ if (!conn->send ('Q'))
+ return FAIL;
+ if (!marshall (conn, method))
+ return FAIL;
+ if (!marshall (conn, 4))
+ return FAIL;
+ if (!marshall (conn, arg1))
+ return FAIL;
+ if (!marshall (conn, arg2))
+ return FAIL;
+ if (!marshall (conn, arg3))
+ return FAIL;
+ if (!marshall (conn, arg4))
+ return FAIL;
+ if (!conn->wait_for_result ())
+ return FAIL;
+ if (!unmarshall (conn, result))
+ return FAIL;
+ return OK;
+ }
+
+ template<typename R, typename A1, typename A2, typename A3, typename A4,
+ R (*func) (connection *, A1, A2, A3, A4)>
+ status
+ callback (connection *conn)
+ {
+ argument_wrapper<A1> arg1;
+ argument_wrapper<A2> arg2;
+ argument_wrapper<A3> arg3;
+ argument_wrapper<A4> arg4;
+ R result;
+
+ if (!unmarshall_check (conn, 4))
+ return FAIL;
+ if (!arg1.unmarshall (conn))
+ return FAIL;
+ if (!arg2.unmarshall (conn))
+ return FAIL;
+ if (!arg3.unmarshall (conn))
+ return FAIL;
+ if (!arg4.unmarshall (conn))
+ return FAIL;
+ result = func (conn, arg1, arg2, arg3, arg4);
+ if (!conn->send ('R'))
+ return FAIL;
+ return marshall (conn, result);
+ }
+
+ template<typename R, typename A1, typename A2, typename A3, typename A4,
+ typename A5>
+ status
+ call (connection *conn, const char *method, R *result, A1 arg1, A2 arg2,
+ A3 arg3, A4 arg4, A5 arg5)
+ {
+ if (!conn->send ('Q'))
+ return FAIL;
+ if (!marshall (conn, method))
+ return FAIL;
+ if (!marshall (conn, 5))
+ return FAIL;
+ if (!marshall (conn, arg1))
+ return FAIL;
+ if (!marshall (conn, arg2))
+ return FAIL;
+ if (!marshall (conn, arg3))
+ return FAIL;
+ if (!marshall (conn, arg4))
+ return FAIL;
+ if (!marshall (conn, arg5))
+ return FAIL;
+ if (!conn->wait_for_result ())
+ return FAIL;
+ if (!unmarshall (conn, result))
+ return FAIL;
+ return OK;
+ }
+
+ template<typename R, typename A1, typename A2, typename A3, typename A4,
+ typename A5, R (*func) (connection *, A1, A2, A3, A4, A5)>
+ status
+ callback (connection *conn)
+ {
+ argument_wrapper<A1> arg1;
+ argument_wrapper<A2> arg2;
+ argument_wrapper<A3> arg3;
+ argument_wrapper<A4> arg4;
+ argument_wrapper<A5> arg5;
+ R result;
+
+ if (!unmarshall_check (conn, 5))
+ return FAIL;
+ if (!arg1.unmarshall (conn))
+ return FAIL;
+ if (!arg2.unmarshall (conn))
+ return FAIL;
+ if (!arg3.unmarshall (conn))
+ return FAIL;
+ if (!arg4.unmarshall (conn))
+ return FAIL;
+ if (!arg5.unmarshall (conn))
+ return FAIL;
+ result = func (conn, arg1, arg2, arg3, arg4, arg5);
+ if (!conn->send ('R'))
+ return FAIL;
+ return marshall (conn, result);
+ }
+
+ template<typename R, typename A1, typename A2, typename A3, typename A4,
+ typename A5, typename A6, typename A7>
+ status
+ call (connection *conn, const char *method, R *result, A1 arg1, A2 arg2,
+ A3 arg3, A4 arg4, A5 arg5, A6 arg6, A7 arg7)
+ {
+ if (!conn->send ('Q'))
+ return FAIL;
+ if (!marshall (conn, method))
+ return FAIL;
+ if (!marshall (conn, 7))
+ return FAIL;
+ if (!marshall (conn, arg1))
+ return FAIL;
+ if (!marshall (conn, arg2))
+ return FAIL;
+ if (!marshall (conn, arg3))
+ return FAIL;
+ if (!marshall (conn, arg4))
+ return FAIL;
+ if (!marshall (conn, arg5))
+ return FAIL;
+ if (!marshall (conn, arg6))
+ return FAIL;
+ if (!marshall (conn, arg7))
+ return FAIL;
+ if (!conn->wait_for_result ())
+ return FAIL;
+ if (!unmarshall (conn, result))
+ return FAIL;
+ return OK;
+ }
+
+ template<typename R, typename A1, typename A2, typename A3, typename A4,
+ typename A5, typename A6, typename A7,
+ R (*func) (connection *, A1, A2, A3, A4, A5, A6, A7)>
+ status
+ callback (connection *conn)
+ {
+ argument_wrapper<A1> arg1;
+ argument_wrapper<A2> arg2;
+ argument_wrapper<A3> arg3;
+ argument_wrapper<A4> arg4;
+ argument_wrapper<A5> arg5;
+ argument_wrapper<A6> arg6;
+ argument_wrapper<A7> arg7;
+ R result;
+
+ if (!unmarshall_check (conn, 7))
+ return FAIL;
+ if (!arg1.unmarshall (conn))
+ return FAIL;
+ if (!arg2.unmarshall (conn))
+ return FAIL;
+ if (!arg3.unmarshall (conn))
+ return FAIL;
+ if (!arg4.unmarshall (conn))
+ return FAIL;
+ if (!arg5.unmarshall (conn))
+ return FAIL;
+ if (!arg6.unmarshall (conn))
+ return FAIL;
+ if (!arg7.unmarshall (conn))
+ return FAIL;
+ result = func (conn, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
+ if (!conn->send ('R'))
+ return FAIL;
+ return marshall (conn, result);
+ }
+};
+
+#endif // CC1_PLUGIN_RPC_HH
diff --git a/libcc1/status.hh b/libcc1/status.hh
new file mode 100644
index 0000000..764c7ff
--- /dev/null
+++ b/libcc1/status.hh
@@ -0,0 +1,33 @@
+/* status type definition
+ Copyright (C) 2014 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC 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, or (at your option) any later
+version.
+
+GCC 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 GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#ifndef CC1_PLUGIN_STATUS_HH
+#define CC1_PLUGIN_STATUS_HH
+
+namespace cc1_plugin
+{
+ // The status returned by various connection functions.
+ enum status
+ {
+ FAIL = 0,
+ OK = 1
+ };
+}
+
+#endif // CC1_PLUGIN_STATUS_HH
Jeff Law
2014-07-31 04:47:55 UTC
Permalink
Post by Tom Tromey
Tom> I've edited this one down by removing the auto-generated stuff , and
Tom> then compressed it.
Here's a new version of patch #5.
I've removed the generated code; let's see if it gets through without
compression.
* It uses gcc-plugin.m4 to disable the plugin
* It does some configure checks for needed functionality, and disables
the plugin if they are not found
* libcc1 and the plugin now do a protocol version handshake at
startup
* The diagnostic overriding code is now in the plugin, not in gcc proper
* gdb now tells libcc1 about the target triplet, and libcc1 uses
this to invoke the proper GCC. This is done by (ewww) searching $PATH.
Tom
* Makefile.def: Add libcc1 to host_modules.
* configure.ac (host_tools): Add libcc1.
* Makefile.in, configure: Rebuild.
* aclocal.m4: New file.
* callbacks.cc: New file.
* callbacks.hh: New file.
* cc1plugin-config.h.in: New file.
* configure: New file.
* configure.ac: New file.
* connection.cc: New file.
* connection.hh: New file.
* findcomp.cc: New file.
* findcomp.hh: New file.
* libcc1.cc: New file.
* libcc1plugin.sym: New file.
* libcc1.sym: New file.
* Makefile.am: New file.
* Makefile.in: New file.
* marshall.cc: New file.
* marshall.hh: New file.
* names.cc: New file.
* names.hh: New file.
* plugin.cc: New file.
* rpc.hh: New file.
* status.hh: New file.
So my biggest concern here is long term maintenance -- who's going to
own care and feeding of these bits over time.

My inclination is to go ahead and approve, but explicitly note that if
the bits do start to rot that we'll be fairly aggressive at
disabling/removing them.

Now that my position is out there for everyone to see, give the other
maintainers a few days (say until Monday) to chime in with any objections.

Obviously if there are no objections and you check in the change, please
be on the lookout for any fallout. I'm particularly concerned about
AIX, Solaris and other non-linux platforms.

Does this deserve a mention in the news file?

Jeff
Richard Biener
2014-07-31 08:01:15 UTC
Permalink
Post by Tom Tromey
Tom> I've edited this one down by removing the auto-generated stuff , and
Tom> then compressed it.
Here's a new version of patch #5.
I've removed the generated code; let's see if it gets through without
compression.
* It uses gcc-plugin.m4 to disable the plugin
* It does some configure checks for needed functionality, and disables
the plugin if they are not found
* libcc1 and the plugin now do a protocol version handshake at
startup
* The diagnostic overriding code is now in the plugin, not in gcc proper
* gdb now tells libcc1 about the target triplet, and libcc1 uses
this to invoke the proper GCC. This is done by (ewww) searching $PATH.
Tom
* Makefile.def: Add libcc1 to host_modules.
* configure.ac (host_tools): Add libcc1.
* Makefile.in, configure: Rebuild.
* aclocal.m4: New file.
* callbacks.cc: New file.
* callbacks.hh: New file.
* cc1plugin-config.h.in: New file.
* configure: New file.
* configure.ac: New file.
* connection.cc: New file.
* connection.hh: New file.
* findcomp.cc: New file.
* findcomp.hh: New file.
* libcc1.cc: New file.
* libcc1plugin.sym: New file.
* libcc1.sym: New file.
* Makefile.am: New file.
* Makefile.in: New file.
* marshall.cc: New file.
* marshall.hh: New file.
* names.cc: New file.
* names.hh: New file.
* plugin.cc: New file.
* rpc.hh: New file.
* status.hh: New file.
So my biggest concern here is long term maintenance -- who's going to own
care and feeding of these bits over time.
My inclination is to go ahead and approve, but explicitly note that if the
bits do start to rot that we'll be fairly aggressive at disabling/removing
them.
Now that my position is out there for everyone to see, give the other
maintainers a few days (say until Monday) to chime in with any objections.
Obviously if there are no objections and you check in the change, please be
on the lookout for any fallout. I'm particularly concerned about AIX,
Solaris and other non-linux platforms.
Does this deserve a mention in the news file?
Can you briefly elaborate on how this relates to the JIT work from
David Malcom?

Also during the GCC Summit we talked about JIT and plugins and
I mentioned that the JIT API is actually a kind of "stable plugin API"
for IL creation.

We've also elaborated on why the JIT cannot be a "plugin" at the
moment - which is at least partly because we cannot have
"frontend plugins". This is because compilation is currently
driven by the frontend which "owns" main() even though it immediately
calls into the middle-end and only gets control back via langhooks.
So a quite obvious cleanup of the program flow of GCC would be
to drive things from a middle-end main() - which would allow
a plugin to take over the frontend parts (and which would allow
making all frontends shared objects, aka "plugins" to a common
middle-end "driver").

Just throwing in my mental notes from the Summit here. I really
wonder how libcc1 falls in into this picture and if it would stand
in the way of re-organizing main program flow and/or making
frontends shared objects.

[ideally both frontends and targets would be shared objects, but of
course even frontends have target dependencies pulled in via
target macros at the moment...]

Richard.
Jeff
Trevor Saunders
2014-07-31 10:44:55 UTC
Permalink
Post by Richard Biener
Post by Tom Tromey
Tom> I've edited this one down by removing the auto-generated stuff , and
Tom> then compressed it.
Here's a new version of patch #5.
I've removed the generated code; let's see if it gets through without
compression.
* It uses gcc-plugin.m4 to disable the plugin
* It does some configure checks for needed functionality, and disables
the plugin if they are not found
* libcc1 and the plugin now do a protocol version handshake at
startup
* The diagnostic overriding code is now in the plugin, not in gcc proper
* gdb now tells libcc1 about the target triplet, and libcc1 uses
this to invoke the proper GCC. This is done by (ewww) searching $PATH.
Tom
* Makefile.def: Add libcc1 to host_modules.
* configure.ac (host_tools): Add libcc1.
* Makefile.in, configure: Rebuild.
* aclocal.m4: New file.
* callbacks.cc: New file.
* callbacks.hh: New file.
* cc1plugin-config.h.in: New file.
* configure: New file.
* configure.ac: New file.
* connection.cc: New file.
* connection.hh: New file.
* findcomp.cc: New file.
* findcomp.hh: New file.
* libcc1.cc: New file.
* libcc1plugin.sym: New file.
* libcc1.sym: New file.
* Makefile.am: New file.
* Makefile.in: New file.
* marshall.cc: New file.
* marshall.hh: New file.
* names.cc: New file.
* names.hh: New file.
* plugin.cc: New file.
* rpc.hh: New file.
* status.hh: New file.
So my biggest concern here is long term maintenance -- who's going to own
care and feeding of these bits over time.
My inclination is to go ahead and approve, but explicitly note that if the
bits do start to rot that we'll be fairly aggressive at disabling/removing
them.
Now that my position is out there for everyone to see, give the other
maintainers a few days (say until Monday) to chime in with any objections.
Obviously if there are no objections and you check in the change, please be
on the lookout for any fallout. I'm particularly concerned about AIX,
Solaris and other non-linux platforms.
Does this deserve a mention in the news file?
Can you briefly elaborate on how this relates to the JIT work from
David Malcom?
I don't think the JIT work helps much here because this library wants to
feed gcc source not IL, so it needs a front end not just the back.
Post by Richard Biener
Also during the GCC Summit we talked about JIT and plugins and
I mentioned that the JIT API is actually a kind of "stable plugin API"
for IL creation.
good point.
Post by Richard Biener
We've also elaborated on why the JIT cannot be a "plugin" at the
moment - which is at least partly because we cannot have
"frontend plugins". This is because compilation is currently
driven by the frontend which "owns" main() even though it immediately
calls into the middle-end and only gets control back via langhooks.
So a quite obvious cleanup of the program flow of GCC would be
to drive things from a middle-end main() - which would allow
a plugin to take over the frontend parts (and which would allow
making all frontends shared objects, aka "plugins" to a common
middle-end "driver").
sounds nice
Post by Richard Biener
Just throwing in my mental notes from the Summit here. I really
wonder how libcc1 falls in into this picture and if it would stand
in the way of re-organizing main program flow and/or making
frontends shared objects.
so the interesting bit of libcc1 is just a plugin, which means it won't
add any extra work past making plugins work. On the other hand if you
could load a library that included the driver and front ends then you'd
basically have a much simpler libcc1, so I think that work would make
libcc1 a bit nicer.

Trev
Post by Richard Biener
[ideally both frontends and targets would be shared objects, but of
course even frontends have target dependencies pulled in via
target macros at the moment...]
Richard.
Jeff
Richard Biener
2014-07-31 11:05:44 UTC
Permalink
Post by Trevor Saunders
Post by Richard Biener
Post by Tom Tromey
Tom> I've edited this one down by removing the auto-generated stuff , and
Tom> then compressed it.
Here's a new version of patch #5.
I've removed the generated code; let's see if it gets through without
compression.
* It uses gcc-plugin.m4 to disable the plugin
* It does some configure checks for needed functionality, and disables
the plugin if they are not found
* libcc1 and the plugin now do a protocol version handshake at
startup
* The diagnostic overriding code is now in the plugin, not in gcc proper
* gdb now tells libcc1 about the target triplet, and libcc1 uses
this to invoke the proper GCC. This is done by (ewww) searching $PATH.
Tom
* Makefile.def: Add libcc1 to host_modules.
* configure.ac (host_tools): Add libcc1.
* Makefile.in, configure: Rebuild.
* aclocal.m4: New file.
* callbacks.cc: New file.
* callbacks.hh: New file.
* cc1plugin-config.h.in: New file.
* configure: New file.
* configure.ac: New file.
* connection.cc: New file.
* connection.hh: New file.
* findcomp.cc: New file.
* findcomp.hh: New file.
* libcc1.cc: New file.
* libcc1plugin.sym: New file.
* libcc1.sym: New file.
* Makefile.am: New file.
* Makefile.in: New file.
* marshall.cc: New file.
* marshall.hh: New file.
* names.cc: New file.
* names.hh: New file.
* plugin.cc: New file.
* rpc.hh: New file.
* status.hh: New file.
So my biggest concern here is long term maintenance -- who's going to own
care and feeding of these bits over time.
My inclination is to go ahead and approve, but explicitly note that if the
bits do start to rot that we'll be fairly aggressive at disabling/removing
them.
Now that my position is out there for everyone to see, give the other
maintainers a few days (say until Monday) to chime in with any objections.
Obviously if there are no objections and you check in the change, please be
on the lookout for any fallout. I'm particularly concerned about AIX,
Solaris and other non-linux platforms.
Does this deserve a mention in the news file?
Can you briefly elaborate on how this relates to the JIT work from
David Malcom?
I don't think the JIT work helps much here because this library wants to
feed gcc source not IL, so it needs a front end not just the back.
Ah, ok ...
Post by Trevor Saunders
Post by Richard Biener
Also during the GCC Summit we talked about JIT and plugins and
I mentioned that the JIT API is actually a kind of "stable plugin API"
for IL creation.
good point.
Post by Richard Biener
We've also elaborated on why the JIT cannot be a "plugin" at the
moment - which is at least partly because we cannot have
"frontend plugins". This is because compilation is currently
driven by the frontend which "owns" main() even though it immediately
calls into the middle-end and only gets control back via langhooks.
So a quite obvious cleanup of the program flow of GCC would be
to drive things from a middle-end main() - which would allow
a plugin to take over the frontend parts (and which would allow
making all frontends shared objects, aka "plugins" to a common
middle-end "driver").
sounds nice
Actually after looking again I was wrong. main.c and toplev.c
are the "driver". So if we can make all frontends shared objects
with their only interface being their lang_hooks that would be nice
(of course the middle-end still needs to make gazillions of symbols
available to that "plugin").

Of course it won't really help libcc1 as libcc1 isn't a frontend
itself.
Post by Trevor Saunders
Post by Richard Biener
Just throwing in my mental notes from the Summit here. I really
wonder how libcc1 falls in into this picture and if it would stand
in the way of re-organizing main program flow and/or making
frontends shared objects.
so the interesting bit of libcc1 is just a plugin, which means it won't
add any extra work past making plugins work. On the other hand if you
could load a library that included the driver and front ends then you'd
basically have a much simpler libcc1, so I think that work would make
libcc1 a bit nicer.
Trev
Post by Richard Biener
[ideally both frontends and targets would be shared objects, but of
course even frontends have target dependencies pulled in via
target macros at the moment...]
Richard.
Jeff
Joseph S. Myers
2014-07-31 15:04:44 UTC
Permalink
Post by Richard Biener
Actually after looking again I was wrong. main.c and toplev.c
are the "driver". So if we can make all frontends shared objects
with their only interface being their lang_hooks that would be nice
(of course the middle-end still needs to make gazillions of symbols
available to that "plugin").
As far as I know, the main non-lang-hook interface provided by front ends
is the "convert" function (and there aren't that many places outside the
front ends that still use it). So it shouldn't be hard to get to the
state where each front end is only used by its langhooks. (That's a long
way from any sort of independent buildability, though; everything still
embeds global information about such things as command-line options for
all available front ends, and tree codes likewise.)

I don't personally like the relics of other such magic-named functions in
the form of langhooks-def.h defaulting to a langhook having a particular
name that a front end can provide

#define LANG_HOOKS_GLOBAL_BINDINGS_P global_bindings_p
#define LANG_HOOKS_PUSHDECL pushdecl
#define LANG_HOOKS_GETDECLS getdecls

and think it would be better for each front end to have unique names for
these, with no such default.

I think there are a few more cases where C and C++ provide different
implementations of a function with the same name for use by c-family code
(and ObjC / ObjC++ issues as well, of course).
--
Joseph S. Myers
***@codesourcery.com
Tom Tromey
2014-07-31 19:12:54 UTC
Permalink
Richard> Can you briefly elaborate on how this relates to the JIT work from
Richard> David Malcom?

I think Trevor answered this bit well but I had a bit more to add...

Richard> Just throwing in my mental notes from the Summit here. I really
Richard> wonder how libcc1 falls in into this picture and if it would stand
Richard> in the way of re-organizing main program flow and/or making
Richard> frontends shared objects.

FWIW the plugin is really quite small. It uses just a few things from
the C front end. Earlier patches in the series also add a couple of ad
hoc hooks to the C front end so that the plugin can insert itself.
However it really isn't much -- primarily I think due to the simplicity
of C; I expect hooking into g++ will be trickier.

I don't think this plugin will be much of a barrier to anything in gcc.
It hooks in to gcc in the same way as any other plugin (aside from those
ad hoc hooks). You can look through plugin.cc in the patch to see what
parts of gcc's internals uses.

One way of looking at it is -- if gcc changes break this plugin, they'll
probably break every plugin. So it's a good thing :)

Richard> [ideally both frontends and targets would be shared objects, but of
Richard> course even frontends have target dependencies pulled in via
Richard> target macros at the moment...]

We actually started development with this approach. Our first working
version of this project was based on David Malcolm's JIT branch. We
turned cc1 into a .so and had gdb dlopen it. Then we did the
compilation parts in-process.

We ended up going with the plugin approach because it has better fault
tolerance. With the cc1.so approach, if we could provoke a crash -- not
uncommon given that we were calling gcc internals in a new and exciting
way -- then the whole debug session came down.

Using a plugin avoids this. If gcc crashes, gdb can report an error and
continue on. This is much friendlier for users, making it worth the
extra effort of dealing with multiple processes, RPC, etc. Also, our
fears about the performance of this approach were unfounded, I imagine
because we're generally dealing with very small inputs.

Tom
Jakub Jelinek
2014-07-31 19:20:21 UTC
Permalink
Post by Tom Tromey
Richard> [ideally both frontends and targets would be shared objects, but of
Richard> course even frontends have target dependencies pulled in via
Richard> target macros at the moment...]
We actually started development with this approach. Our first working
version of this project was based on David Malcolm's JIT branch. We
turned cc1 into a .so and had gdb dlopen it. Then we did the
compilation parts in-process.
We ended up going with the plugin approach because it has better fault
tolerance. With the cc1.so approach, if we could provoke a crash -- not
uncommon given that we were calling gcc internals in a new and exciting
way -- then the whole debug session came down.
Using a plugin avoids this. If gcc crashes, gdb can report an error and
continue on. This is much friendlier for users, making it worth the
extra effort of dealing with multiple processes, RPC, etc. Also, our
fears about the performance of this approach were unfounded, I imagine
because we're generally dealing with very small inputs.
Given that what GDB wants is not a JIT, but reuse the C (and later on C++)
FEs, I think the plugin approach is just fine for this.

Jakub
Trevor Saunders
2014-07-31 19:43:04 UTC
Permalink
Post by Tom Tromey
Richard> Can you briefly elaborate on how this relates to the JIT work from
Richard> David Malcom?
I think Trevor answered this bit well but I had a bit more to add...
Richard> Just throwing in my mental notes from the Summit here. I really
Richard> wonder how libcc1 falls in into this picture and if it would stand
Richard> in the way of re-organizing main program flow and/or making
Richard> frontends shared objects.
FWIW the plugin is really quite small. It uses just a few things from
the C front end. Earlier patches in the series also add a couple of ad
hoc hooks to the C front end so that the plugin can insert itself.
However it really isn't much -- primarily I think due to the simplicity
of C; I expect hooking into g++ will be trickier.
I don't think this plugin will be much of a barrier to anything in gcc.
It hooks in to gcc in the same way as any other plugin (aside from those
ad hoc hooks). You can look through plugin.cc in the patch to see what
parts of gcc's internals uses.
the plugin part seems fine, but I do find my self wondering if there's a
better way of doing the hooks into C, if they can be more genrally
useful. I'm not complaining about them at all it just seems like its
worth thinking about what they tell us we should make better in the
future.
Post by Tom Tromey
One way of looking at it is -- if gcc changes break this plugin, they'll
probably break every plugin. So it's a good thing :)
Richard> [ideally both frontends and targets would be shared objects, but of
Richard> course even frontends have target dependencies pulled in via
Richard> target macros at the moment...]
We actually started development with this approach. Our first working
version of this project was based on David Malcolm's JIT branch. We
turned cc1 into a .so and had gdb dlopen it. Then we did the
compilation parts in-process.
We ended up going with the plugin approach because it has better fault
tolerance. With the cc1.so approach, if we could provoke a crash -- not
uncommon given that we were calling gcc internals in a new and exciting
way -- then the whole debug session came down.
out of process seems very reasonable, but I do hope we'll fix the
crashes since there's any number of other uses for cc1 as a library.

Trev
Post by Tom Tromey
Using a plugin avoids this. If gcc crashes, gdb can report an error and
continue on. This is much friendlier for users, making it worth the
extra effort of dealing with multiple processes, RPC, etc. Also, our
fears about the performance of this approach were unfounded, I imagine
because we're generally dealing with very small inputs.
Tom
Tom Tromey
2014-07-31 19:51:45 UTC
Permalink
Trevor> the plugin part seems fine, but I do find my self wondering if there's a
Trevor> better way of doing the hooks into C, if they can be more genrally
Trevor> useful.

There's just one now, the binding oracle.
(There used to be two but we reimplemented the second one by overriding
a langhook from the plugin.)

The binding oracle could perhaps be redone as an ordinary plugin event.
It didn't seem that worthwhile to me, but if someone else has a use, it
seems doable.

Trevor> out of process seems very reasonable, but I do hope we'll fix the
Trevor> crashes since there's any number of other uses for cc1 as a library.

The ones I recall were all things like the plugin making a tree
incorrectly. This could still be an issue but it is one unlikely to be
hit in ordinary uses of the compiler. I agree any such things are bugs
though.

Tom
Trevor Saunders
2014-08-01 02:16:21 UTC
Permalink
Post by Tom Tromey
Trevor> the plugin part seems fine, but I do find my self wondering if there's a
Trevor> better way of doing the hooks into C, if they can be more genrally
Trevor> useful.
There's just one now, the binding oracle.
ah, that seems reasonable enough.
Post by Tom Tromey
(There used to be two but we reimplemented the second one by overriding
a langhook from the plugin.)
hm, I think langhooks should eventually become an interface with virtual
functions to help seperate front ends, and that may be interesting with
plugins that over ride lang hooks from the front end, but we need to
cross that bridge anyway I guess.
Post by Tom Tromey
The binding oracle could perhaps be redone as an ordinary plugin event.
It didn't seem that worthwhile to me, but if someone else has a use, it
seems doable.
Trevor> out of process seems very reasonable, but I do hope we'll fix the
Trevor> crashes since there's any number of other uses for cc1 as a library.
The ones I recall were all things like the plugin making a tree
incorrectly. This could still be an issue but it is one unlikely to be
hit in ordinary uses of the compiler. I agree any such things are bugs
though.
Then that seems fine.

So as far as I'm concerned please lets go forward with this and clean up
later as needed.

Trev
Post by Tom Tromey
Tom
Mike Stump
2014-07-31 21:09:20 UTC
Permalink
So my biggest concern here is long term maintenance -- who's going to own care and feeding of these bits over time.
My inclination is to go ahead and approve, but explicitly note that if the bits do start to rot that we'll be fairly aggressive at disabling/removing them.
So the normal way to do this would be to make the plugin front-end non-default and then never gate any release decisions upon the state of the that front-end. If it works, ship it, if it doesn’t ship it. If people want it to build, the contribute patches, if they don’t care, oh well…

That said, changes that ripple across front-ends generally need to be built with all (really all) built and are generally rejected if they break the build.

Given my experience with lessor front-ends (Objective-C and Objective-C++), I think we do a good job and the maintenance is fairly low. Others can disabuse me of this opinion if they want. My expectation is that this frontend will be easy to maintain and will be a non-issue. Everyone and then someone won’t test with it, they will break it, someone will notice, someone will contribute the 2 line patch that also makes it work, and life goes on. This is my experience with Objective-C++ (a non-default language).
Tom Tromey
2014-08-04 14:22:57 UTC
Permalink
Mike> So the normal way to do this would be to make the plugin front-end
Mike> non-default and then never gate any release decisions upon the state
Mike> of the that front-end.

Not sure if this is overly pedantic, but the plugin is just a library,
not a front end. It works with the existing C front end.

I think the main issue arising here is that the plugin doesn't have any
in-tree tests. You have to have gdb to test it.

Tom
Tom Tromey
2014-08-05 19:34:00 UTC
Permalink
Jeff> Obviously if there are no objections and you check in the change,
Jeff> please be on the lookout for any fallout. I'm particularly concerned
Jeff> about AIX, Solaris and other non-linux platforms.

I did a build on the AIX box (gcc111) in the compile farm and didn't
have any issues. The plugin isn't built there as plugin support seems
to be disabled.

Jeff> Does this deserve a mention in the news file?

I suppose so, I will get someone here to write it.

Tom
Jan Kratochvil
2014-08-08 12:15:39 UTC
Permalink
Post by Tom Tromey
Jeff> Does this deserve a mention in the news file?
I suppose so, I will get someone here to write it.
Attached (based on Tom's PATCH 0/5 mail).


Jan
Gerald Pfeifer
2014-08-31 15:12:30 UTC
Permalink
Hi Jan,
Post by Jan Kratochvil
Post by Jeff Law
Does this deserve a mention in the news file?
Attached (based on Tom's PATCH 0/5 mail).
Index: htdocs/gcc-5/changes.html
===================================================================
+<h3 id="c">C</h3>
+ <ul>
+ <li>GDB evaluation of a block of source code is now provided by new GCC
+ plugin.<br />

How does one obtain/install/trigger this plugin? Where are more details
documented? This is information I'd add here.

+ A user can compile a code snippet and it will be inserted into the inferior
+ and evaluated. Declarations needed by the snippet are supplied by GDB, and
+ there is a GDB--GCC interface so that the snippets can refer to local
+ variables in the current inferior frame.

The validator probably is going to complain that this needs to be within
<p>...</p> markers.

In HTML, I'd just say GDB-GCC (one dash).

I'm good with this patch modulo these suggestion, but perhaps Jeff or
Tom have some further input?

Gerald
Manuel López-Ibáñez
2014-09-14 15:07:05 UTC
Permalink
What happened with this? I don't see any libcc1 in the gcc repository
and this patch was never committed.

Cheers,

Manuel.
Post by Gerald Pfeifer
Hi Jan,
Post by Jan Kratochvil
Post by Jeff Law
Does this deserve a mention in the news file?
Attached (based on Tom's PATCH 0/5 mail).
Index: htdocs/gcc-5/changes.html
===================================================================
+<h3 id="c">C</h3>
+ <ul>
+ <li>GDB evaluation of a block of source code is now provided by new GCC
+ plugin.<br />
How does one obtain/install/trigger this plugin? Where are more details
documented? This is information I'd add here.
+ A user can compile a code snippet and it will be inserted into the inferior
+ and evaluated. Declarations needed by the snippet are supplied by GDB, and
+ there is a GDB--GCC interface so that the snippets can refer to local
+ variables in the current inferior frame.
The validator probably is going to complain that this needs to be within
<p>...</p> markers.
In HTML, I'd just say GDB-GCC (one dash).
I'm good with this patch modulo these suggestion, but perhaps Jeff or
Tom have some further input?
Gerald
Jan Kratochvil
2014-09-17 14:14:12 UTC
Permalink
Post by Manuel López-Ibáñez
What happened with this? I don't see any libcc1 in the gcc repository
and this patch was never committed.
It was discussed internally and the patches are going to be updated, rebased
and later checked in.


Thanks,
Jan
Phil Muldoon
2014-10-09 09:07:23 UTC
Permalink
Post by Tom Tromey
Here's a new version of patch #5.
I've removed the generated code; let's see if it gets through without
compression.
* It uses gcc-plugin.m4 to disable the plugin
* It does some configure checks for needed functionality, and disables
the plugin if they are not found
* libcc1 and the plugin now do a protocol version handshake at
startup
* The diagnostic overriding code is now in the plugin, not in gcc proper
* gdb now tells libcc1 about the target triplet, and libcc1 uses
this to invoke the proper GCC. This is done by (ewww) searching $PATH.
Tom
So my biggest concern here is long term maintenance -- who's going to own care and feeding of these bits over time.
Sorry for taking so long to reply. We've talked, on irc and elsewhere
a little (some at the Cauldron too!). I think the consensus is as
nobody has explicitly mentioned anything, this is OK to go in? So to
be a pain, I think we should get an archivable "OK to check-in" and
that I, or other members of the Red Hat team (or anyone else that
comes along that is interested), will maintain this. FWIW, I don't
really see bit-rot as an issue because 1) I'll be around and so will
other hackers working on this -- I think it is very important to GDB;
2) It's not really a patch-set I think is horribly susceptible to bit
rot anyway.
My inclination is to go ahead and approve, but explicitly note that if the bits do start to rot that we'll be fairly aggressive at disabling/removing them.
That's a fair condition and I can happily live with that. Agreed on
the conditional here.
Now that my position is out there for everyone to see, give the other maintainers a few days (say until Monday) to chime in with any objections.
Well it's been a few months, so Monday has long gone ;)
Obviously if there are no objections and you check in the change, please be on the lookout for any fallout. I'm particularly concerned about AIX, Solaris and other non-linux platforms.
Noted.
Does this deserve a mention in the news file?
I am not sure. All the interface to this is really through GDB.
I'll let someone else tell me yes or no for news. The patch set I have on my
desk is ready to go, and I believe all alterations have been approved
in previous email threads.

Cheers,

Phil
Jakub Jelinek
2014-10-09 09:12:08 UTC
Permalink
Post by Phil Muldoon
So my biggest concern here is long term maintenance -- who's going to own care and feeding of these bits over time.
Sorry for taking so long to reply. We've talked, on irc and elsewhere
a little (some at the Cauldron too!). I think the consensus is as
nobody has explicitly mentioned anything, this is OK to go in? So to
be a pain, I think we should get an archivable "OK to check-in" and
that I, or other members of the Red Hat team (or anyone else that
The series is ok for trunk. Please retest it before checking in.
Post by Phil Muldoon
Does this deserve a mention in the news file?
I am not sure. All the interface to this is really through GDB.
I'll let someone else tell me yes or no for news. The patch set I have on my
desk is ready to go, and I believe all alterations have been approved
in previous email threads.
Yeah, I think it belongs into GDB news file probably, because that is the
place where it is user visible.

Jakub

Tom Tromey
2014-07-30 16:09:57 UTC
Permalink
Tom> This patch series is half of a project to let gdb reuse gcc (which
Tom> half depends on which list you are seeing this on), so that users can
Tom> compile small snippets of code and evaluate them in the current
Tom> context of the inferior.

[ ... later ... ]
Tom> I believe we've addressed all the review comments.

Ping.
I think at least the final patch has never been approved.

Tom
Loading...