public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* Re: [PATCH 5/5] add libcc1
@ 2014-10-28  3:19 Dominique Dhumieres
  2014-10-28  8:36 ` Jakub Jelinek
  0 siblings, 1 reply; 71+ messages in thread
From: Dominique Dhumieres @ 2014-10-28  3:19 UTC (permalink / raw)
  To: gcc-patches; +Cc: tromey, jakub, law, pmuldoon

> This patch has now been committed.

It breaks bootstap on x86_64-apple-darwin14:

...
make[3]: Entering directory `/opt/gcc/p_build/libcc1'
make  all-am
make[4]: Entering directory `/opt/gcc/p_build/libcc1'
make[4]: *** No rule to make target `../libiberty/pic/libiberty.a', needed by `libcc1.la'.  Stop.
make[4]: Leaving directory `/opt/gcc/p_build/libcc1'
make[3]: *** [all] Error 2
make[3]: Leaving directory `/opt/gcc/p_build/libcc1'
make[2]: *** [all-stage1-libcc1] Error 2
make[2]: Leaving directory `/opt/gcc/p_build'
make[1]: *** [stage1-bubble] Error 2
make[1]: Leaving directory `/opt/gcc/p_build'
make: *** [all] Error 2

TIA

Dominique

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 5/5] add libcc1
  2014-10-28  3:19 [PATCH 5/5] add libcc1 Dominique Dhumieres
@ 2014-10-28  8:36 ` Jakub Jelinek
  2014-10-28  8:46   ` Phil Muldoon
  0 siblings, 1 reply; 71+ messages in thread
From: Jakub Jelinek @ 2014-10-28  8:36 UTC (permalink / raw)
  To: Dominique Dhumieres; +Cc: gcc-patches, tromey, law, pmuldoon

On Tue, Oct 28, 2014 at 01:05:00AM +0100, Dominique Dhumieres wrote:
> > This patch has now been committed.
> 
> It breaks bootstap on x86_64-apple-darwin14:
> 
> ...
> make[3]: Entering directory `/opt/gcc/p_build/libcc1'
> make  all-am
> make[4]: Entering directory `/opt/gcc/p_build/libcc1'
> make[4]: *** No rule to make target `../libiberty/pic/libiberty.a', needed by `libcc1.la'.  Stop.
> make[4]: Leaving directory `/opt/gcc/p_build/libcc1'
> make[3]: *** [all] Error 2
> make[3]: Leaving directory `/opt/gcc/p_build/libcc1'
> make[2]: *** [all-stage1-libcc1] Error 2
> make[2]: Leaving directory `/opt/gcc/p_build'
> make[1]: *** [stage1-bubble] Error 2
> make[1]: Leaving directory `/opt/gcc/p_build'
> make: *** [all] Error 2

There are other issues related to --with-build-config=bootstrap-{a,ub}san
in there too, my current WIP patch is but didn't get to test it yet.

--- libcc1/Makefile.am.jj	2014-10-27 19:41:13.000000000 +0100
+++ libcc1/Makefile.am	2014-10-28 09:07:57.443711725 +0100
@@ -24,8 +24,17 @@ AM_CPPFLAGS = -I $(srcdir)/../include -I
 	-I $(srcdir)/../libcpp/include
 WERROR_FLAG = -Werror
 AM_CXXFLAGS = $(WARN_FLAGS) $(WERROR_FLAG) $(visibility)
-libiberty = ../libiberty/pic/libiberty.a
-
+override CXXFLAGS := $(filter-out -fsanitize=address,$(CXXFLAGS))
+override LDFLAGS := $(filter-out -fsanitize=address,$(LDFLAGS))
+# Can be simplified when libiberty becomes a normal convenience library.
+libiberty_normal = ../libiberty/libiberty.a
+libiberty_noasan = ../libiberty/noasan/libiberty.a
+libiberty_pic = ../libiberty/pic/libiberty.a
+Wc=-Wc,
+libiberty = $(if $(wildcard $(libiberty_noasan)),$(Wc)$(libiberty_noasan), \
+	    $(if $(wildcard $(libiberty_pic)),$(Wc)$(libiberty_pic), \
+	    $(Wc)$(libiberty_normal)))
+libiberty_dep = $(patsubst $(Wc)%,%,$(libiberty))
 
 plugindir = $(libdir)/gcc/$(target_noncanonical)/$(gcc_version)/plugin
 cc1libdir = $(libdir)/$(libsuffix)
@@ -49,7 +58,16 @@ shared_source = callbacks.cc callbacks.h
 libcc1plugin_la_LDFLAGS = -module -export-symbols $(srcdir)/libcc1plugin.sym
 libcc1plugin_la_SOURCES = plugin.cc $(shared_source)
 libcc1plugin_la_LIBADD = $(libiberty)
+libcc1plugin_la_DEPENDENCIES = $(libiberty_dep)
+libcc1plugin_la_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+	$(CXXFLAGS) $(libcc1plugin_la_LDFLAGS) $(LTLDFLAGS) -o $@
 
+LTLDFLAGS = $(shell $(SHELL) $(top_srcdir)/../libtool-ldflags $(LDFLAGS))
 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)
+libcc1_la_DEPENDENCIES = $(libiberty_dep)
+libcc1_la_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+	$(CXXFLAGS) $(libcc1_la_LDFLAGS) $(LTLDFLAGS) -o $@
--- libcc1/Makefile.in.jj	2014-10-27 19:41:13.000000000 +0100
+++ libcc1/Makefile.in	2014-10-28 09:08:01.689922599 +0100
@@ -81,20 +81,12 @@ am__base_list = \
   sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
 am__installdirs = "$(DESTDIR)$(cc1libdir)" "$(DESTDIR)$(plugindir)"
 LTLIBRARIES = $(cc1lib_LTLIBRARIES) $(plugin_LTLIBRARIES)
-libcc1_la_DEPENDENCIES = $(libiberty)
 am__objects_1 = callbacks.lo connection.lo marshall.lo
 am_libcc1_la_OBJECTS = findcomp.lo libcc1.lo names.lo $(am__objects_1)
 libcc1_la_OBJECTS = $(am_libcc1_la_OBJECTS)
-libcc1_la_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \
-	$(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
-	$(CXXFLAGS) $(libcc1_la_LDFLAGS) $(LDFLAGS) -o $@
 @ENABLE_PLUGIN_TRUE@am_libcc1_la_rpath = -rpath $(cc1libdir)
-libcc1plugin_la_DEPENDENCIES = $(libiberty)
 am_libcc1plugin_la_OBJECTS = plugin.lo $(am__objects_1)
 libcc1plugin_la_OBJECTS = $(am_libcc1plugin_la_OBJECTS)
-libcc1plugin_la_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \
-	$(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
-	$(CXXFLAGS) $(libcc1plugin_la_LDFLAGS) $(LDFLAGS) -o $@
 @ENABLE_PLUGIN_TRUE@am_libcc1plugin_la_rpath = -rpath $(plugindir)
 DEFAULT_INCLUDES = -I.@am__isrc@
 depcomp = $(SHELL) $(top_srcdir)/../depcomp
@@ -259,7 +251,16 @@ AM_CPPFLAGS = -I $(srcdir)/../include -I
 
 WERROR_FLAG = -Werror
 AM_CXXFLAGS = $(WARN_FLAGS) $(WERROR_FLAG) $(visibility)
-libiberty = ../libiberty/pic/libiberty.a
+# Can be simplified when libiberty becomes a normal convenience library.
+libiberty_normal = ../libiberty/libiberty.a
+libiberty_noasan = ../libiberty/noasan/libiberty.a
+libiberty_pic = ../libiberty/pic/libiberty.a
+Wc = -Wc,
+libiberty = $(if $(wildcard $(libiberty_noasan)),$(Wc)$(libiberty_noasan), \
+	    $(if $(wildcard $(libiberty_pic)),$(Wc)$(libiberty_pic), \
+	    $(Wc)$(libiberty_normal)))
+
+libiberty_dep = $(patsubst $(Wc)%,%,$(libiberty))
 plugindir = $(libdir)/gcc/$(target_noncanonical)/$(gcc_version)/plugin
 cc1libdir = $(libdir)/$(libsuffix)
 @ENABLE_PLUGIN_TRUE@plugin_LTLIBRARIES = libcc1plugin.la
@@ -271,9 +272,20 @@ shared_source = callbacks.cc callbacks.h
 libcc1plugin_la_LDFLAGS = -module -export-symbols $(srcdir)/libcc1plugin.sym
 libcc1plugin_la_SOURCES = plugin.cc $(shared_source)
 libcc1plugin_la_LIBADD = $(libiberty)
+libcc1plugin_la_DEPENDENCIES = $(libiberty_dep)
+libcc1plugin_la_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+	$(CXXFLAGS) $(libcc1plugin_la_LDFLAGS) $(LTLDFLAGS) -o $@
+
+LTLDFLAGS = $(shell $(SHELL) $(top_srcdir)/../libtool-ldflags $(LDFLAGS))
 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)
+libcc1_la_DEPENDENCIES = $(libiberty_dep)
+libcc1_la_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+	$(CXXFLAGS) $(libcc1_la_LDFLAGS) $(LTLDFLAGS) -o $@
+
 all: $(BUILT_SOURCES) cc1plugin-config.h
 	$(MAKE) $(AM_MAKEFLAGS) all-am
 
@@ -619,6 +631,8 @@ uninstall-am: uninstall-cc1libLTLIBRARIE
 	pdf pdf-am ps ps-am tags uninstall uninstall-am \
 	uninstall-cc1libLTLIBRARIES uninstall-pluginLTLIBRARIES
 
+override CXXFLAGS := $(filter-out -fsanitize=address,$(CXXFLAGS))
+override LDFLAGS := $(filter-out -fsanitize=address,$(LDFLAGS))
 
 # 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.


	Jakub

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 5/5] add libcc1
  2014-10-28  8:36 ` Jakub Jelinek
@ 2014-10-28  8:46   ` Phil Muldoon
  2014-10-28  8:50     ` Christophe Lyon
  2014-10-28  9:09     ` Jakub Jelinek
  0 siblings, 2 replies; 71+ messages in thread
From: Phil Muldoon @ 2014-10-28  8:46 UTC (permalink / raw)
  To: Jakub Jelinek, Dominique Dhumieres; +Cc: gcc-patches, tromey, law

On 28/10/14 08:13, Jakub Jelinek wrote:
> On Tue, Oct 28, 2014 at 01:05:00AM +0100, Dominique Dhumieres wrote:
>>> This patch has now been committed.
>> It breaks bootstap on x86_64-apple-darwin14:
>>
>> ...
>> make[3]: Entering directory `/opt/gcc/p_build/libcc1'
>> make  all-am
>> make[4]: Entering directory `/opt/gcc/p_build/libcc1'
>> make[4]: *** No rule to make target `../libiberty/pic/libiberty.a', needed by `libcc1.la'.  Stop.
>> make[4]: Leaving directory `/opt/gcc/p_build/libcc1'
>> make[3]: *** [all] Error 2
>> make[3]: Leaving directory `/opt/gcc/p_build/libcc1'
>> make[2]: *** [all-stage1-libcc1] Error 2
>> make[2]: Leaving directory `/opt/gcc/p_build'
>> make[1]: *** [stage1-bubble] Error 2
>> make[1]: Leaving directory `/opt/gcc/p_build'
>> make: *** [all] Error 2
> There are other issues related to --with-build-config=bootstrap-{a,ub}san
> in there too, my current WIP patch is but didn't get to test it yet.

Apologies.  I am investigating the issue, though I am not entirely sure of why the issue with libiberty occurs.

Cheers

Phil

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 5/5] add libcc1
  2014-10-28  8:46   ` Phil Muldoon
@ 2014-10-28  8:50     ` Christophe Lyon
  2014-10-28  9:09     ` Jakub Jelinek
  1 sibling, 0 replies; 71+ messages in thread
From: Christophe Lyon @ 2014-10-28  8:50 UTC (permalink / raw)
  To: Phil Muldoon
  Cc: Jakub Jelinek, Dominique Dhumieres, gcc-patches, tromey, Jeff Law

On 28 October 2014 09:43, Phil Muldoon <pmuldoon@redhat.com> wrote:
> On 28/10/14 08:13, Jakub Jelinek wrote:
>> On Tue, Oct 28, 2014 at 01:05:00AM +0100, Dominique Dhumieres wrote:
>>>> This patch has now been committed.
>>> It breaks bootstap on x86_64-apple-darwin14:
>>>
>>> ...
>>> make[3]: Entering directory `/opt/gcc/p_build/libcc1'
>>> make  all-am
>>> make[4]: Entering directory `/opt/gcc/p_build/libcc1'
>>> make[4]: *** No rule to make target `../libiberty/pic/libiberty.a', needed by `libcc1.la'.  Stop.
>>> make[4]: Leaving directory `/opt/gcc/p_build/libcc1'
>>> make[3]: *** [all] Error 2
>>> make[3]: Leaving directory `/opt/gcc/p_build/libcc1'
>>> make[2]: *** [all-stage1-libcc1] Error 2
>>> make[2]: Leaving directory `/opt/gcc/p_build'
>>> make[1]: *** [stage1-bubble] Error 2
>>> make[1]: Leaving directory `/opt/gcc/p_build'
>>> make: *** [all] Error 2
>> There are other issues related to --with-build-config=bootstrap-{a,ub}san
>> in there too, my current WIP patch is but didn't get to test it yet.
>
> Apologies.  I am investigating the issue, though I am not entirely sure of why the issue with libiberty occurs.
>

I also breaks the build of cross compilers for arm* and aarch64*
targets (host RHEL5/x86_64):
cc1plus: warnings being treated as errors
/tmp/76611_16.tmpdir/aci-gcc-fsf/sources/gcc-fsf/gccsrc/libcc1/../gcc/hash-table.h:
In instantiation of ‘hash_table<pointer_hash<tree_node>, xcallocator,
true>’:
/tmp/76611_16.tmpdir/aci-gcc-fsf/sources/gcc-fsf/gccsrc/libcc1/plugin.cc:171:
  instantiated from here
/tmp/76611_16.tmpdir/aci-gcc-fsf/sources/gcc-fsf/gccsrc/libcc1/../gcc/hash-table.h:1161:
warning: lowering visibility of ‘void gt_ggc_mx(hash_table<T,
xcallocator, storage_test
er<T,void>::value>*) [with T = T, Descriptor =
pointer_hash<tree_node>, Allocator = xcallocator]’ to match its type
/tmp/76611_16.tmpdir/aci-gcc-fsf/sources/gcc-fsf/gccsrc/libcc1/../gcc/hash-table.h:1162:
warning: lowering visibility of ‘void gt_pch_nx(hash_table<T,
xcallocator, storage_test
er<T,void>::value>*) [with T = T, Descriptor =
pointer_hash<tree_node>, Allocator = xcallocator]’ to match its type
/tmp/76611_16.tmpdir/aci-gcc-fsf/sources/gcc-fsf/gccsrc/libcc1/../gcc/hash-table.h:1166:
warning: lowering visibility of ‘void gt_pch_nx(hash_map<T, U, V>*,
void (*)(void*, void*), void*) [with T = T, U = U, V = V, Descriptor =
pointer_hash<tree_node>, Allocator = xcallocator]’ to match its type
/tmp/76611_16.tmpdir/aci-gcc-fsf/sources/gcc-fsf/gccsrc/libcc1/../gcc/hash-table.h:1169:
warning: lowering visibility of ‘void gt_pch_nx(hash_set<T, U>*, void
(*)(void*, void*), void*) [with T = T, U = U, Descriptor =
pointer_hash<tree_node>, Allocator = xcallocator]’ to match its type
/tmp/76611_16.tmpdir/aci-gcc-fsf/sources/gcc-fsf/gccsrc/libcc1/../gcc/hash-table.h:1171:
warning: lowering visibility of ‘void gt_pch_nx(hash_table<T,
xcallocator, storage_tester<T,void>::value>*, void (*)(void*, void*),
void*) [with T = T, Descriptor = pointer_hash<tree_node>, Allocator =
xcallocator]’ to match its type
make[3]: *** [plugin.lo] Error 1

> Cheers
>
> Phil
>

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 5/5] add libcc1
  2014-10-28  8:46   ` Phil Muldoon
  2014-10-28  8:50     ` Christophe Lyon
@ 2014-10-28  9:09     ` Jakub Jelinek
  1 sibling, 0 replies; 71+ messages in thread
From: Jakub Jelinek @ 2014-10-28  9:09 UTC (permalink / raw)
  To: Phil Muldoon; +Cc: Dominique Dhumieres, gcc-patches, tromey, law

On Tue, Oct 28, 2014 at 08:43:35AM +0000, Phil Muldoon wrote:
> On 28/10/14 08:13, Jakub Jelinek wrote:
> > On Tue, Oct 28, 2014 at 01:05:00AM +0100, Dominique Dhumieres wrote:
> >>> This patch has now been committed.
> >> It breaks bootstap on x86_64-apple-darwin14:
> >>
> >> ...
> >> make[3]: Entering directory `/opt/gcc/p_build/libcc1'
> >> make  all-am
> >> make[4]: Entering directory `/opt/gcc/p_build/libcc1'
> >> make[4]: *** No rule to make target `../libiberty/pic/libiberty.a', needed by `libcc1.la'.  Stop.
> >> make[4]: Leaving directory `/opt/gcc/p_build/libcc1'
> >> make[3]: *** [all] Error 2
> >> make[3]: Leaving directory `/opt/gcc/p_build/libcc1'
> >> make[2]: *** [all-stage1-libcc1] Error 2
> >> make[2]: Leaving directory `/opt/gcc/p_build'
> >> make[1]: *** [stage1-bubble] Error 2
> >> make[1]: Leaving directory `/opt/gcc/p_build'
> >> make: *** [all] Error 2
> > There are other issues related to --with-build-config=bootstrap-{a,ub}san
> > in there too, my current WIP patch is but didn't get to test it yet.
> 
> Apologies.  I am investigating the issue, though I am not entirely sure of why the issue with libiberty occurs.

I think I have the libiberty issues solved in my patch, just hit another
issue (visibility related) in my -fsanitize=vptr patch which I've been
bootstrapping it with, so had to fix that and am now trying again.

The thing with libiberty is that we have one to 3 versions of libiberty,
e.g. on targets where there is no pic support or where -fpic is on by
default libiberty doesn't build the pic/ version, and the noasan/ version
is built for --with-build-config=bootstrap-asan builds, so that one can
choose libiberty instrumented -fsanitize=address (the normal one or pic if
the latter exists) and pic non-instrumented one (for use in lto-plugin and
supposedly libcc1 too), anything that can be loaded into some other program
than gcc should not be asan instrumented, because it requires the executable
to be linked that way too (e.g. linker or gdb).

	Jakub

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 5/5] add libcc1
  2014-10-30  8:56               ` Jakub Jelinek
@ 2014-10-30 10:43                 ` Thomas Schwinge
  0 siblings, 0 replies; 71+ messages in thread
From: Thomas Schwinge @ 2014-10-30 10:43 UTC (permalink / raw)
  To: Jakub Jelinek
  Cc: Uros Bizjak, gcc-patches, Tom Tromey, Jeff Law, Phil Muldoon

[-- Attachment #1: Type: text/plain, Size: 5105 bytes --]

Hi!

On Thu, 30 Oct 2014 09:51:59 +0100, Jakub Jelinek <jakub@redhat.com> wrote:
> On Thu, Oct 30, 2014 at 09:33:08AM +0100, Thomas Schwinge wrote:
> > Here is a patch that I'm testing; OK?  I didn't understand what the
> > conditions are that libcc1 might not be built as a shared library: is it
> > always built as one -- but is that really supported on all systems?  If
> 
> It is not unconditionally supported, libcc1/configure.ac uses
> GCC_ENABLE_PLUGINS and doesn't compile anything if gcc doesn't support
> plugins (one of the several tests of that is that -fPIC -shared is
> supported.

Ah, now I see.  Conceptually, as I understand it, that should be done in
the top-level build system, so that libcc1 (and, in case, the shared host
libiberty) isn't even attempted to be built if not supported.  But then,
I don't personally have to deal with hosts that don't support plugins.

> Your patch is ok with proper ChangeLog entry.

Committed in r216912:

commit 944792ef24b74c2b6f5e5d0763b7e5a4a361c3d4
Author: tschwinge <tschwinge@138bc75d-0d04-0410-961f-82ee72b054a4>
Date:   Thu Oct 30 10:06:37 2014 +0000

    Build a shared host libiberty also for libcc1's benefit.
    
    	* configure.ac (extra_host_libiberty_configure_flags): Add
    	--enable-shared also for libcc1's benefit.
    	* configure: Regenerate.
    
    git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@216912 138bc75d-0d04-0410-961f-82ee72b054a4
---
 ChangeLog    |  6 ++++++
 configure    | 16 ++++++++++++----
 configure.ac | 14 +++++++++++---
 3 files changed, 29 insertions(+), 7 deletions(-)

diff --git ChangeLog ChangeLog
index e3636c6..ebcae80 100644
--- ChangeLog
+++ ChangeLog
@@ -1,3 +1,9 @@
+2014-10-30  Thomas Schwinge  <thomas@codesourcery.com>
+
+	* configure.ac (extra_host_libiberty_configure_flags): Add
+	--enable-shared also for libcc1's benefit.
+	* configure: Regenerate.
+
 2014-10-29  Tristan Gingold  <gingold@adacore.com>
 
 	* MAINTAINERS: Change my email address.
diff --git configure configure
index 149acf6..3eab122 100755
--- configure
+++ configure
@@ -642,8 +642,8 @@ CXXFLAGS_FOR_TARGET
 CFLAGS_FOR_TARGET
 DEBUG_PREFIX_CFLAGS_FOR_TARGET
 SYSROOT_CFLAGS_FOR_TARGET
-stage1_languages
 extra_host_libiberty_configure_flags
+stage1_languages
 extra_linker_plugin_flags
 extra_linker_plugin_configure_flags
 clooginc
@@ -6259,7 +6259,6 @@ if test -d ${srcdir}/gcc; then
   new_enable_languages=,c,
 
   # If LTO is enabled, add the LTO front end.
-  extra_host_libiberty_configure_flags=
   if test "$enable_lto" = "yes" ; then
     case ,${enable_languages}, in
       *,lto,*) ;;
@@ -6267,11 +6266,9 @@ if test -d ${srcdir}/gcc; then
     esac
     if test "${build_lto_plugin}" = "yes" ; then
       configdirs="$configdirs lto-plugin"
-      extra_host_libiberty_configure_flags=--enable-shared
     fi
   fi
 
-
   missing_languages=`echo ",$enable_languages," | sed -e s/,all,/,/ -e s/,c,/,/ `
   potential_languages=,c,
 
@@ -6584,6 +6581,17 @@ then
   esac
 fi
 
+# Sometimes we have special requirements for the host libiberty.
+extra_host_libiberty_configure_flags=
+case " $configdirs " in
+  *" lto-plugin "* | *" libcc1 "*)
+    # When these are to be built as shared libraries, the same applies to
+    # libiberty.
+    extra_host_libiberty_configure_flags=--enable-shared
+    ;;
+esac
+
+
 # Produce a warning message for the subdirs we can't configure.
 # This isn't especially interesting in the Cygnus tree, but in the individual
 # FSF releases, it's important to let people know when their machine isn't
diff --git configure.ac configure.ac
index b62af38..d8262f8 100644
--- configure.ac
+++ configure.ac
@@ -1852,7 +1852,6 @@ if test -d ${srcdir}/gcc; then
   new_enable_languages=,c,
 
   # If LTO is enabled, add the LTO front end.
-  extra_host_libiberty_configure_flags=
   if test "$enable_lto" = "yes" ; then
     case ,${enable_languages}, in
       *,lto,*) ;;
@@ -1860,10 +1859,8 @@ if test -d ${srcdir}/gcc; then
     esac
     if test "${build_lto_plugin}" = "yes" ; then
       configdirs="$configdirs lto-plugin"
-      extra_host_libiberty_configure_flags=--enable-shared
     fi
   fi
-  AC_SUBST(extra_host_libiberty_configure_flags)
 
   missing_languages=`echo ",$enable_languages," | sed -e s/,all,/,/ -e s/,c,/,/ `
   potential_languages=,c,
@@ -2177,6 +2174,17 @@ then
   esac
 fi
 
+# Sometimes we have special requirements for the host libiberty.
+extra_host_libiberty_configure_flags=
+case " $configdirs " in
+  *" lto-plugin "* | *" libcc1 "*)
+    # When these are to be built as shared libraries, the same applies to
+    # libiberty.
+    extra_host_libiberty_configure_flags=--enable-shared
+    ;;
+esac
+AC_SUBST(extra_host_libiberty_configure_flags)
+
 # Produce a warning message for the subdirs we can't configure.
 # This isn't especially interesting in the Cygnus tree, but in the individual
 # FSF releases, it's important to let people know when their machine isn't


Grüße,
 Thomas

[-- Attachment #2: Type: application/pgp-signature, Size: 472 bytes --]

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 5/5] add libcc1
  2014-10-30  8:50             ` Thomas Schwinge
@ 2014-10-30  8:56               ` Jakub Jelinek
  2014-10-30 10:43                 ` Thomas Schwinge
  0 siblings, 1 reply; 71+ messages in thread
From: Jakub Jelinek @ 2014-10-30  8:56 UTC (permalink / raw)
  To: Thomas Schwinge
  Cc: Uros Bizjak, gcc-patches, Tom Tromey, Jeff Law, Phil Muldoon

On Thu, Oct 30, 2014 at 09:33:08AM +0100, Thomas Schwinge wrote:
> Here is a patch that I'm testing; OK?  I didn't understand what the
> conditions are that libcc1 might not be built as a shared library: is it
> always built as one -- but is that really supported on all systems?  If

It is not unconditionally supported, libcc1/configure.ac uses
GCC_ENABLE_PLUGINS and doesn't compile anything if gcc doesn't support
plugins (one of the several tests of that is that -fPIC -shared is
supported.

> that's indeed true, then this could be further simplified, and
> --enable-shared passed to the host libiberty unconditionally.

Your patch is ok with proper ChangeLog entry.

> --- configure.ac
> +++ configure.ac
> @@ -1865,7 +1865,6 @@ if test -d ${srcdir}/gcc; then
>    new_enable_languages=,c,
>  
>    # If LTO is enabled, add the LTO front end.
> -  extra_host_libiberty_configure_flags=
>    if test "$enable_lto" = "yes" ; then
>      case ,${enable_languages}, in
>        *,lto,*) ;;
> @@ -1873,10 +1872,8 @@ if test -d ${srcdir}/gcc; then
>      esac
>      if test "${build_lto_plugin}" = "yes" ; then
>        configdirs="$configdirs lto-plugin"
> -      extra_host_libiberty_configure_flags=--enable-shared
>      fi
>    fi
> -  AC_SUBST(extra_host_libiberty_configure_flags)
>  
>    missing_languages=`echo ",$enable_languages," | sed -e s/,all,/,/ -e s/,c,/,/ `
>    potential_languages=,c,
> @@ -2190,6 +2187,17 @@ then
>    esac
>  fi
>  
> +# Sometimes we have special requirements for the host libiberty.
> +extra_host_libiberty_configure_flags=
> +case " $configdirs " in
> +  *" lto-plugin "* | *" libcc1 "*)
> +    # When these are to be built as shared libraries, the same applies to
> +    # libiberty.
> +    extra_host_libiberty_configure_flags=--enable-shared
> +    ;;
> +esac
> +AC_SUBST(extra_host_libiberty_configure_flags)
> +
>  # Produce a warning message for the subdirs we can't configure.
>  # This isn't especially interesting in the Cygnus tree, but in the individual
>  # FSF releases, it's important to let people know when their machine isn't
> 
> 
> Grüße,
>  Thomas



	Jakub

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 5/5] add libcc1
  2014-10-28 12:24           ` Jakub Jelinek
  2014-10-30  5:16             ` Jeff Law
@ 2014-10-30  8:50             ` Thomas Schwinge
  2014-10-30  8:56               ` Jakub Jelinek
  1 sibling, 1 reply; 71+ messages in thread
From: Thomas Schwinge @ 2014-10-30  8:50 UTC (permalink / raw)
  To: Jakub Jelinek
  Cc: Uros Bizjak, gcc-patches, Tom Tromey, Jeff Law, Phil Muldoon

[-- Attachment #1: Type: text/plain, Size: 4498 bytes --]

Hi!

On Tue, 28 Oct 2014 13:23:50 +0100, Jakub Jelinek <jakub@redhat.com> wrote:
> On Tue, Oct 28, 2014 at 11:47:31AM +0000, Phil Muldoon wrote:
> > I think I have a solution.  Though my automake fu is very weak.  Does
> > this patch work for you?  I'm really not sure how to deal with the
> > three possible versions of libiberty any other way.
> 
> That is insufficient,
> a) you don't filter away -fsanitize=address, which would make it
> unusable in gdb
> b) without the -Wc, stuff, you get the ugly libtool warnings
> c) the LTLDFLAGS mess is needed for libtool not eating the -Wc, stuff

> So I'm proposing my patch (which is modeled after lto-plugin changes by
> myself and others), [...]

(Maybe we should now turn that into generic infrastructure?)

> 2014-10-28  Jakub Jelinek  <jakub@redhat.com>
> 
> 	* Makefile.am (CXXFLAGS, LDFLAGS): Filter out -fsanitize=address.
> 	(libiberty_normal, libiberty_noasan, libiberty_pic, libiberty_dep):
> 	New variables.
> 	(libiberty): Set to -Wc, followed by the first existing noasan/,
> 	pic/ or . libiberty.a.
> 	(libcc1plugin_la_DEPENDENCIES, libcc1plugin_la_LINK,
> 	libcc1_la_DEPENDENCIES, libcc1_la_LINK, LTLDFLAGS): New variables.
> 	* Makefile.in: Regenerated.

;-) To re-use your words: »That is insufficient«, d) in a configuration
where there is no lto-plugin built, we now try to link the shared libcc1
against a static libiberty:

    /bin/bash ./libtool --tag=CXX   --mode=link g++ -m64 [...] -module -export-symbols [...]/source-gcc/libcc1/libcc1.sym  -Xcompiler '-static-libstdc++' -Xcompiler '-static-libgcc' -o libcc1.la -rpath /lib/../lib64 findcomp.lo libcc1.lo names.lo callbacks.lo connection.lo marshall.lo   -Wc,../libiberty/libiberty.a 
    libtool: link: g++ -m64 [...] -shared -nostdlib [...]/crti.o [...]/crtbeginS.o  .libs/findcomp.o .libs/libcc1.o .libs/names.o .libs/callbacks.o .libs/connection.o .libs/marshall.o [...] -lstdc++ -lm -lc -lgcc_s [...]/crtendS.o [...]/crtn.o  -m64 [...] -static-libstdc++ -static-libgcc ../libiberty/libiberty.a   -Wl,-soname -Wl,libcc1.so.0 -Wl,-retain-symbols-file -Wl,[...]/source-gcc/libcc1/libcc1.sym -o .libs/libcc1.so.0.0.0
    [...]/ld: ../libiberty/libiberty.a(regex.o): relocation R_X86_64_32S against `.rodata' can not be used when making a shared object; recompile with -fPIC
    ../libiberty/libiberty.a: error adding symbols: Bad value
    collect2: error: ld returned 1 exit status
    make[3]: *** [libcc1.la] Error 1
    make[3]: Leaving directory `[...]/build-gcc/libcc1'
    make[2]: *** [all] Error 2
    make[2]: Leaving directory `[...]/build-gcc/libcc1'
    make[1]: *** [all-libcc1] Error 2
    make[1]: Leaving directory `[...]/build-gcc'
    make: *** [all] Error 2

Here is a patch that I'm testing; OK?  I didn't understand what the
conditions are that libcc1 might not be built as a shared library: is it
always built as one -- but is that really supported on all systems?  If
that's indeed true, then this could be further simplified, and
--enable-shared passed to the host libiberty unconditionally.

--- configure.ac
+++ configure.ac
@@ -1865,7 +1865,6 @@ if test -d ${srcdir}/gcc; then
   new_enable_languages=,c,
 
   # If LTO is enabled, add the LTO front end.
-  extra_host_libiberty_configure_flags=
   if test "$enable_lto" = "yes" ; then
     case ,${enable_languages}, in
       *,lto,*) ;;
@@ -1873,10 +1872,8 @@ if test -d ${srcdir}/gcc; then
     esac
     if test "${build_lto_plugin}" = "yes" ; then
       configdirs="$configdirs lto-plugin"
-      extra_host_libiberty_configure_flags=--enable-shared
     fi
   fi
-  AC_SUBST(extra_host_libiberty_configure_flags)
 
   missing_languages=`echo ",$enable_languages," | sed -e s/,all,/,/ -e s/,c,/,/ `
   potential_languages=,c,
@@ -2190,6 +2187,17 @@ then
   esac
 fi
 
+# Sometimes we have special requirements for the host libiberty.
+extra_host_libiberty_configure_flags=
+case " $configdirs " in
+  *" lto-plugin "* | *" libcc1 "*)
+    # When these are to be built as shared libraries, the same applies to
+    # libiberty.
+    extra_host_libiberty_configure_flags=--enable-shared
+    ;;
+esac
+AC_SUBST(extra_host_libiberty_configure_flags)
+
 # Produce a warning message for the subdirs we can't configure.
 # This isn't especially interesting in the Cygnus tree, but in the individual
 # FSF releases, it's important to let people know when their machine isn't


Grüße,
 Thomas

[-- Attachment #2: Type: application/pgp-signature, Size: 472 bytes --]

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 5/5] add libcc1
  2014-10-29 10:29                     ` Jakub Jelinek
  2014-10-29 10:45                       ` Paolo Bonzini
@ 2014-10-30  5:37                       ` Jeff Law
  1 sibling, 0 replies; 71+ messages in thread
From: Jeff Law @ 2014-10-30  5:37 UTC (permalink / raw)
  To: Jakub Jelinek, Phil Muldoon, Paolo Bonzini, DJ Delorie,
	Alexandre Oliva, Ralf Wildenhues
  Cc: Joseph S. Myers, gcc-patches

On 10/29/14 04:28, Jakub Jelinek wrote:
> On Tue, Oct 28, 2014 at 05:36:50PM +0000, Phil Muldoon wrote:
>> On 28/10/14 13:19, Joseph S. Myers wrote:
>>> I'm seeing a different bootstrap failure from those already discussed:
>>>
>>> In file included from
>>> /scratch/jmyers/fsf/gcc-mainline/libcc1/../gcc/gcc-plugin.h:28:0,
>>>                   from
>>> /scratch/jmyers/fsf/gcc-mainline/libcc1/plugin.cc:34:
>>> /scratch/jmyers/fsf/gcc-mainline/libcc1/../gcc/system.h:653:17: fatal error: gmp.h: No such file or directory
>>>
>>> It appears the build is ignoring the --with-gmp option passed to
>>> configure.  Since <gmp.h> is included in system.h, if you include system.h
>>> you have to pass the right -I option corresponding to --with-gmp /
>>> --with-gmp-include.  (There are several other such configure options for
>>> MPFR, MPC, CLooG, ISL, libiconv at least - whether they are relevant
>>> depends on whether your code ends up including the relevant headers.)
>>
>> Hi, sorry for the troubles! I am having difficulty seeing this fail on
>> my system.  I built gmp from upstream, installed it, and pointed to
>> the install location with --with-gmp. Which stage does your build fail
>> at?
>>
>> I am actually not totally sure how to respect the -with-gmp argument
>> in libcc1.  auto* tools are not my strongest skill. ;)
>>
>> I notice gcc/configure.ac I think just exports the variables to
>> Makefile.in from the main configure script.  That what we should do in
>> this case?
>
> Here is a patch I'm bootstrapping/regtesting now (but, with system gmp
> installed).  I've verified that with this patch stage1 libcc1 is built
> without -Werror in flags, while stage2 libcc1 is built with -Werror.
>
> If this passes bootstrap/regtest, is it ok for trunk (should fix
> two bootstrap issues)?  Is the
> https://gcc.gnu.org/ml/gcc-patches/2014-10/msg02936.html
> patch ok too (that one already tested; another bootstrap issue)?
>
> 2014-10-29  Jakub Jelinek  <jakub@redhat.com>
> 	    Phil Muldoon  <pmuldoon@redhat.com>
>
> 	* configure.ac: Remove -Werror addition to WARN_FLAGS.  Add
> 	ACX_PROG_CC_WARNINGS_ARE_ERRORS and AC_ARG_VAR for GMPINC.
> 	* Makefile.am (AM_CPPFLAGS): Add $(GMPINC).
> 	(WERROR_FLAG): Remove.
> 	(AM_CXXFLAGS): Use $(WERROR) instead of $(WERROR_FLAG).
> 	* configure: Regenerated.
> 	* Makefile.in: Regenerated.
So is this still relevant if we stop bootstrapping libcc1?

The patch is OK if it's still needed.

Thanks,
Jeff


^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 5/5] add libcc1
  2014-10-28 12:24           ` Jakub Jelinek
@ 2014-10-30  5:16             ` Jeff Law
  2014-10-30  8:50             ` Thomas Schwinge
  1 sibling, 0 replies; 71+ messages in thread
From: Jeff Law @ 2014-10-30  5:16 UTC (permalink / raw)
  To: Jakub Jelinek, Phil Muldoon; +Cc: Uros Bizjak, gcc-patches, Tom Tromey

On 10/28/14 06:23, Jakub Jelinek wrote:
> On Tue, Oct 28, 2014 at 11:47:31AM +0000, Phil Muldoon wrote:
>> I think I have a solution.  Though my automake fu is very weak.  Does
>> this patch work for you?  I'm really not sure how to deal with the
>> three possible versions of libiberty any other way.
>
> That is insufficient,
> a) you don't filter away -fsanitize=address, which would make it
> unusable in gdb
> b) without the -Wc, stuff, you get the ugly libtool warnings
> c) the LTLDFLAGS mess is needed for libtool not eating the -Wc, stuff
>
> I've in the mean time successfully bootstrapped/regtested my patch on
> i686-linux (--with-build-config=bootstrap-ubsan), that was build without
> ada, on x86_64-linux the build failed because of some recent ada vs.
> bootstrap-ubsan incompatibilities unrelated to libcc1 (but libcc1 built
> fine).
>
> So I'm proposing my patch (which is modeled after lto-plugin changes by
> myself and others), with the -Werror stuff handled separately as follow-up.
> Ok for trunk?
>
> 2014-10-28  Jakub Jelinek  <jakub@redhat.com>
>
> 	* Makefile.am (CXXFLAGS, LDFLAGS): Filter out -fsanitize=address.
> 	(libiberty_normal, libiberty_noasan, libiberty_pic, libiberty_dep):
> 	New variables.
> 	(libiberty): Set to -Wc, followed by the first existing noasan/,
> 	pic/ or . libiberty.a.
> 	(libcc1plugin_la_DEPENDENCIES, libcc1plugin_la_LINK,
> 	libcc1_la_DEPENDENCIES, libcc1_la_LINK, LTLDFLAGS): New variables.
> 	* Makefile.in: Regenerated.
Ick.    But OK I guess.

jeff


^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 5/5] add libcc1
  2014-10-29 11:03                             ` Jakub Jelinek
@ 2014-10-29 15:00                               ` Paolo Bonzini
  0 siblings, 0 replies; 71+ messages in thread
From: Paolo Bonzini @ 2014-10-29 15:00 UTC (permalink / raw)
  To: Jakub Jelinek
  Cc: Phil Muldoon, DJ Delorie, Alexandre Oliva, Ralf Wildenhues,
	Joseph S. Myers, gcc-patches

On 10/29/2014 11:59 AM, Jakub Jelinek wrote:
>> > Ah, got it.  Is it hard to move the inclusion to the actual users?
> I think it is hard.  I think it has been moved to system.h very much
> intentionally, as including gmp.h only in selected headers was causing lots
> of troubles, e.g. because of #pragma GCC poison at the end of system.h,
> I believe some gmp.h versions were using some poisoned symbols.
> system.h doesn't include gmp.h if -DGENERATOR_FILE, but libcc1 is not a
> generator, so that is not appropriate, it can use various other GCC headers
> that are not suitable for generators.  GMPINC has been suggested by Joseph,
> I'd think if we ever need also GMPLIB, we'd clearly see it as link failures
> of libcc1 first and could add it only when really needed.

Fair enough, thanks!

Paolo

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 5/5] add libcc1
  2014-10-29 10:59                           ` Paolo Bonzini
  2014-10-29 11:03                             ` Jakub Jelinek
  2014-10-29 11:10                             ` Phil Muldoon
@ 2014-10-29 11:42                             ` Phil Muldoon
  2 siblings, 0 replies; 71+ messages in thread
From: Phil Muldoon @ 2014-10-29 11:42 UTC (permalink / raw)
  To: Paolo Bonzini, Jakub Jelinek
  Cc: DJ Delorie, Alexandre Oliva, Ralf Wildenhues, Joseph S. Myers,
	gcc-patches

On 29/10/14 10:53, Paolo Bonzini wrote:
>
>
> On 10/29/2014 11:51 AM, Jakub Jelinek wrote:
>> On Wed, Oct 29, 2014 at 11:37:42AM +0100, Paolo Bonzini wrote:
>>>
>>>
>>> On 10/29/2014 11:28 AM, Jakub Jelinek wrote:
>>>> If this passes bootstrap/regtest, is it ok for trunk (should fix
>>>> two bootstrap issues)?  Is the
>>>> https://gcc.gnu.org/ml/gcc-patches/2014-10/msg02936.html
>>>> patch ok too (that one already tested; another bootstrap issue)?
>>>
>>> Both seem okay, though I'd have to look at the whole thread to
>>> understand what libcc1 is. :)
>>
>> It is a library for communication between the debugger and
>> a GCC plugin (and the plugin itself).  So, the library is
>> dlopened into GDB and the plugin that links against that library
>> is dlopened by GCC when GDB asks the library it dlopened to
>> run the compiler with the plugin.
>>

Adding on to what Jakub said, it allows GDB access to GCC's parser.
There are a number of reasons why, but right now that means we can
compile code snippets in GDB (without the source of the current
inferior), allow access to symbols of that inferior in that source
snippet, etc.  We then inject and execute it.

We are currently writing a wiki article about it.  Not required reading
or anything, but more information for the curious.

https://sourceware.org/gdb/wiki/GCCCompileAndExecute

(That is a work in progress).  There is also a video of a presentation
I did at Cauldron somewhere.

Cheers

Phil

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 5/5] add libcc1
  2014-10-29 10:59                           ` Paolo Bonzini
  2014-10-29 11:03                             ` Jakub Jelinek
@ 2014-10-29 11:10                             ` Phil Muldoon
  2014-10-29 11:42                             ` Phil Muldoon
  2 siblings, 0 replies; 71+ messages in thread
From: Phil Muldoon @ 2014-10-29 11:10 UTC (permalink / raw)
  To: Paolo Bonzini, Jakub Jelinek
  Cc: DJ Delorie, Alexandre Oliva, Ralf Wildenhues, Joseph S. Myers,
	gcc-patches

On 29/10/14 10:53, Paolo Bonzini wrote:
>>> 2) why is GMPLIB not handled in the same way?
>>
>> The only problem is that system.h includes gmp.h, so we need a way
>> to find that header.  I think libcc1 doesn't use any functions from gmp
>> itself, so if gmp.h can be included, GMPLIB isn't really needed.
>
> Ah, got it.  Is it hard to move the inclusion to the actual users?

We don't, I was looking at this issue today.  It is just as Jakub
explains.

Cheers

Phil

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 5/5] add libcc1
  2014-10-29 10:59                           ` Paolo Bonzini
@ 2014-10-29 11:03                             ` Jakub Jelinek
  2014-10-29 15:00                               ` Paolo Bonzini
  2014-10-29 11:10                             ` Phil Muldoon
  2014-10-29 11:42                             ` Phil Muldoon
  2 siblings, 1 reply; 71+ messages in thread
From: Jakub Jelinek @ 2014-10-29 11:03 UTC (permalink / raw)
  To: Paolo Bonzini
  Cc: Phil Muldoon, DJ Delorie, Alexandre Oliva, Ralf Wildenhues,
	Joseph S. Myers, gcc-patches

On Wed, Oct 29, 2014 at 11:53:28AM +0100, Paolo Bonzini wrote:
> >> 2) why is GMPLIB not handled in the same way?
> > 
> > The only problem is that system.h includes gmp.h, so we need a way
> > to find that header.  I think libcc1 doesn't use any functions from gmp
> > itself, so if gmp.h can be included, GMPLIB isn't really needed.
> 
> Ah, got it.  Is it hard to move the inclusion to the actual users?

I think it is hard.  I think it has been moved to system.h very much
intentionally, as including gmp.h only in selected headers was causing lots
of troubles, e.g. because of #pragma GCC poison at the end of system.h,
I believe some gmp.h versions were using some poisoned symbols.
system.h doesn't include gmp.h if -DGENERATOR_FILE, but libcc1 is not a
generator, so that is not appropriate, it can use various other GCC headers
that are not suitable for generators.  GMPINC has been suggested by Joseph,
I'd think if we ever need also GMPLIB, we'd clearly see it as link failures
of libcc1 first and could add it only when really needed.

	Jakub

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 5/5] add libcc1
  2014-10-29 10:58                         ` Jakub Jelinek
@ 2014-10-29 10:59                           ` Paolo Bonzini
  2014-10-29 11:03                             ` Jakub Jelinek
                                               ` (2 more replies)
  0 siblings, 3 replies; 71+ messages in thread
From: Paolo Bonzini @ 2014-10-29 10:59 UTC (permalink / raw)
  To: Jakub Jelinek
  Cc: Phil Muldoon, DJ Delorie, Alexandre Oliva, Ralf Wildenhues,
	Joseph S. Myers, gcc-patches



On 10/29/2014 11:51 AM, Jakub Jelinek wrote:
> On Wed, Oct 29, 2014 at 11:37:42AM +0100, Paolo Bonzini wrote:
>>
>>
>> On 10/29/2014 11:28 AM, Jakub Jelinek wrote:
>>> If this passes bootstrap/regtest, is it ok for trunk (should fix
>>> two bootstrap issues)?  Is the
>>> https://gcc.gnu.org/ml/gcc-patches/2014-10/msg02936.html
>>> patch ok too (that one already tested; another bootstrap issue)?
>>
>> Both seem okay, though I'd have to look at the whole thread to
>> understand what libcc1 is. :)
> 
> It is a library for communication between the debugger and
> a GCC plugin (and the plugin itself).  So, the library is
> dlopened into GDB and the plugin that links against that library
> is dlopened by GCC when GDB asks the library it dlopened to
> run the compiler with the plugin.
> 
>> Just two questions:
>>
>> 1) what's the issue that you need to disable asan for?
> 
> -fsanitize=address generally doesn't work or doesn't work too well,
> if the binary is not built with -fsanitize=address, but shared library
> dlopened into it is.  So, we want to avoid instrumenting plugins
> that way (we already don't instrument lto-plugin for that reason,
> because ld might not be asan instrumented, and libcc1 is similar case,
> when gdb dlopens the library, it might not be instrumented either).

Thanks for explaining.  I can see intuitively why that could be a problem...

>> 2) why is GMPLIB not handled in the same way?
> 
> The only problem is that system.h includes gmp.h, so we need a way
> to find that header.  I think libcc1 doesn't use any functions from gmp
> itself, so if gmp.h can be included, GMPLIB isn't really needed.

Ah, got it.  Is it hard to move the inclusion to the actual users?

Paolo

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 5/5] add libcc1
  2014-10-29 10:45                       ` Paolo Bonzini
@ 2014-10-29 10:58                         ` Jakub Jelinek
  2014-10-29 10:59                           ` Paolo Bonzini
  0 siblings, 1 reply; 71+ messages in thread
From: Jakub Jelinek @ 2014-10-29 10:58 UTC (permalink / raw)
  To: Paolo Bonzini
  Cc: Phil Muldoon, DJ Delorie, Alexandre Oliva, Ralf Wildenhues,
	Joseph S. Myers, gcc-patches

On Wed, Oct 29, 2014 at 11:37:42AM +0100, Paolo Bonzini wrote:
> 
> 
> On 10/29/2014 11:28 AM, Jakub Jelinek wrote:
> > If this passes bootstrap/regtest, is it ok for trunk (should fix
> > two bootstrap issues)?  Is the
> > https://gcc.gnu.org/ml/gcc-patches/2014-10/msg02936.html
> > patch ok too (that one already tested; another bootstrap issue)?
> 
> Both seem okay, though I'd have to look at the whole thread to
> understand what libcc1 is. :)

It is a library for communication between the debugger and
a GCC plugin (and the plugin itself).  So, the library is
dlopened into GDB and the plugin that links against that library
is dlopened by GCC when GDB asks the library it dlopened to
run the compiler with the plugin.

> Just two questions:
> 
> 1) what's the issue that you need to disable asan for?

-fsanitize=address generally doesn't work or doesn't work too well,
if the binary is not built with -fsanitize=address, but shared library
dlopened into it is.  So, we want to avoid instrumenting plugins
that way (we already don't instrument lto-plugin for that reason,
because ld might not be asan instrumented, and libcc1 is similar case,
when gdb dlopens the library, it might not be instrumented either).

> 2) why is GMPLIB not handled in the same way?

The only problem is that system.h includes gmp.h, so we need a way
to find that header.  I think libcc1 doesn't use any functions from gmp
itself, so if gmp.h can be included, GMPLIB isn't really needed.

	Jakub

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 5/5] add libcc1
  2014-10-29 10:29                     ` Jakub Jelinek
@ 2014-10-29 10:45                       ` Paolo Bonzini
  2014-10-29 10:58                         ` Jakub Jelinek
  2014-10-30  5:37                       ` Jeff Law
  1 sibling, 1 reply; 71+ messages in thread
From: Paolo Bonzini @ 2014-10-29 10:45 UTC (permalink / raw)
  To: Jakub Jelinek, Phil Muldoon, DJ Delorie, Alexandre Oliva,
	Ralf Wildenhues
  Cc: Joseph S. Myers, gcc-patches



On 10/29/2014 11:28 AM, Jakub Jelinek wrote:
> If this passes bootstrap/regtest, is it ok for trunk (should fix
> two bootstrap issues)?  Is the
> https://gcc.gnu.org/ml/gcc-patches/2014-10/msg02936.html
> patch ok too (that one already tested; another bootstrap issue)?

Both seem okay, though I'd have to look at the whole thread to
understand what libcc1 is. :)

Just two questions:

1) what's the issue that you need to disable asan for?

2) why is GMPLIB not handled in the same way?

Paolo

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 5/5] add libcc1
  2014-10-28 18:00                   ` Phil Muldoon
  2014-10-29  3:32                     ` Joseph S. Myers
@ 2014-10-29 10:29                     ` Jakub Jelinek
  2014-10-29 10:45                       ` Paolo Bonzini
  2014-10-30  5:37                       ` Jeff Law
  1 sibling, 2 replies; 71+ messages in thread
From: Jakub Jelinek @ 2014-10-29 10:29 UTC (permalink / raw)
  To: Phil Muldoon, Paolo Bonzini, DJ Delorie, Alexandre Oliva,
	Ralf Wildenhues
  Cc: Joseph S. Myers, gcc-patches

On Tue, Oct 28, 2014 at 05:36:50PM +0000, Phil Muldoon wrote:
> On 28/10/14 13:19, Joseph S. Myers wrote:
> > I'm seeing a different bootstrap failure from those already discussed:
> >
> > In file included from
> > /scratch/jmyers/fsf/gcc-mainline/libcc1/../gcc/gcc-plugin.h:28:0,
> >                  from
> > /scratch/jmyers/fsf/gcc-mainline/libcc1/plugin.cc:34:
> > /scratch/jmyers/fsf/gcc-mainline/libcc1/../gcc/system.h:653:17: fatal error: gmp.h: No such file or directory
> >
> > It appears the build is ignoring the --with-gmp option passed to
> > configure.  Since <gmp.h> is included in system.h, if you include system.h
> > you have to pass the right -I option corresponding to --with-gmp /
> > --with-gmp-include.  (There are several other such configure options for
> > MPFR, MPC, CLooG, ISL, libiconv at least - whether they are relevant
> > depends on whether your code ends up including the relevant headers.)
> 
> Hi, sorry for the troubles! I am having difficulty seeing this fail on
> my system.  I built gmp from upstream, installed it, and pointed to
> the install location with --with-gmp. Which stage does your build fail
> at?
> 
> I am actually not totally sure how to respect the -with-gmp argument
> in libcc1.  auto* tools are not my strongest skill. ;)
> 
> I notice gcc/configure.ac I think just exports the variables to
> Makefile.in from the main configure script.  That what we should do in
> this case?

Here is a patch I'm bootstrapping/regtesting now (but, with system gmp
installed).  I've verified that with this patch stage1 libcc1 is built
without -Werror in flags, while stage2 libcc1 is built with -Werror.

If this passes bootstrap/regtest, is it ok for trunk (should fix
two bootstrap issues)?  Is the
https://gcc.gnu.org/ml/gcc-patches/2014-10/msg02936.html
patch ok too (that one already tested; another bootstrap issue)?

2014-10-29  Jakub Jelinek  <jakub@redhat.com>
	    Phil Muldoon  <pmuldoon@redhat.com>

	* configure.ac: Remove -Werror addition to WARN_FLAGS.  Add
	ACX_PROG_CC_WARNINGS_ARE_ERRORS and AC_ARG_VAR for GMPINC.
	* Makefile.am (AM_CPPFLAGS): Add $(GMPINC).
	(WERROR_FLAG): Remove.
	(AM_CXXFLAGS): Use $(WERROR) instead of $(WERROR_FLAG).
	* configure: Regenerated.
	* Makefile.in: Regenerated.

--- libcc1/configure.ac.jj	2014-10-28 14:39:52.000000000 +0100
+++ libcc1/configure.ac	2014-10-29 10:01:36.515497687 +0100
@@ -52,8 +52,10 @@ 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)
+ACX_PROG_CC_WARNINGS_ARE_ERRORS([manual])
+
+AC_ARG_VAR(GMPINC,[How to find GMP include files])
 
 libsuffix=
 if test "$GXX" = yes; then
--- libcc1/Makefile.am.jj	2014-10-29 09:53:00.000000000 +0100
+++ libcc1/Makefile.am	2014-10-29 10:02:08.481885746 +0100
@@ -21,9 +21,8 @@ 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)
+	-I $(srcdir)/../libcpp/include $(GMPINC)
+AM_CXXFLAGS = $(WARN_FLAGS) $(WERROR) $(visibility)
 override CXXFLAGS := $(filter-out -fsanitize=address,$(CXXFLAGS))
 override LDFLAGS := $(filter-out -fsanitize=address,$(LDFLAGS))
 # Can be simplified when libiberty becomes a normal convenience library.
--- libcc1/configure.jj	2014-10-28 14:39:52.000000000 +0100
+++ libcc1/configure	2014-10-29 10:02:32.957419099 +0100
@@ -605,6 +605,8 @@ LIBOBJS
 ENABLE_PLUGIN_FALSE
 ENABLE_PLUGIN_TRUE
 libsuffix
+GMPINC
+WERROR
 WARN_FLAGS
 gcc_version
 visibility
@@ -743,6 +745,7 @@ with_pic
 enable_fast_install
 with_gnu_ld
 enable_libtool_lock
+enable_werror_always
 enable_plugin
 '
       ac_precious_vars='build_alias
@@ -757,7 +760,8 @@ CPP
 CXX
 CXXFLAGS
 CCC
-CXXCPP'
+CXXCPP
+GMPINC'
 
 
 # Initialize some variables set by options.
@@ -1387,6 +1391,7 @@ Optional Features:
   --enable-fast-install[=PKGS]
                           optimize for fast installation [default=yes]
   --disable-libtool-lock  avoid locking (might break parallel builds)
+  --enable-werror-always  enable -Werror despite compiler version
   --enable-plugin         enable plugin support
 
 Optional Packages:
@@ -1409,6 +1414,7 @@ Some influential environment variables:
   CXX         C++ compiler command
   CXXFLAGS    C++ compiler flags
   CXXCPP      C++ preprocessor
+  GMPINC      How to find GMP include files
 
 Use these variables to override the choices made by `configure' or to help
 it to find libraries and programs with nonstandard names/locations.
@@ -10530,7 +10536,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 10533 "configure"
+#line 10539 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -10636,7 +10642,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 10639 "configure"
+#line 10645 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -14342,7 +14348,21 @@ fi
   done
 CFLAGS="$save_CFLAGS"
 
-WARN_FLAGS="$WARN_FLAGS -Werror"
+
+WERROR=
+# Check whether --enable-werror-always was given.
+if test "${enable_werror_always+set}" = set; then :
+  enableval=$enable_werror_always;
+else
+  enable_werror_always=no
+fi
+
+if test $enable_werror_always = yes; then :
+  WERROR="$WERROR${WERROR:+ }-Werror"
+fi
+
+
+
 
 
 libsuffix=
--- libcc1/Makefile.in.jj	2014-10-29 09:53:00.000000000 +0100
+++ libcc1/Makefile.in	2014-10-29 10:02:35.739365984 +0100
@@ -140,6 +140,7 @@ ECHO_T = @ECHO_T@
 EGREP = @EGREP@
 EXEEXT = @EXEEXT@
 FGREP = @FGREP@
+GMPINC = @GMPINC@
 GREP = @GREP@
 INSTALL = @INSTALL@
 INSTALL_DATA = @INSTALL_DATA@
@@ -178,6 +179,7 @@ SHELL = @SHELL@
 STRIP = @STRIP@
 VERSION = @VERSION@
 WARN_FLAGS = @WARN_FLAGS@
+WERROR = @WERROR@
 abs_builddir = @abs_builddir@
 abs_srcdir = @abs_srcdir@
 abs_top_builddir = @abs_top_builddir@
@@ -247,10 +249,9 @@ 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
+	-I $(srcdir)/../libcpp/include $(GMPINC)
 
-WERROR_FLAG = -Werror
-AM_CXXFLAGS = $(WARN_FLAGS) $(WERROR_FLAG) $(visibility)
+AM_CXXFLAGS = $(WARN_FLAGS) $(WERROR) $(visibility)
 # Can be simplified when libiberty becomes a normal convenience library.
 libiberty_normal = ../libiberty/libiberty.a
 libiberty_noasan = ../libiberty/noasan/libiberty.a


	Jakub

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 5/5] add libcc1
  2014-10-28 18:00                   ` Phil Muldoon
@ 2014-10-29  3:32                     ` Joseph S. Myers
  2014-10-29 10:29                     ` Jakub Jelinek
  1 sibling, 0 replies; 71+ messages in thread
From: Joseph S. Myers @ 2014-10-29  3:32 UTC (permalink / raw)
  To: Phil Muldoon; +Cc: gcc-patches

On Tue, 28 Oct 2014, Phil Muldoon wrote:

> Joseph,
> 
> Hi, sorry for the troubles! I am having difficulty seeing this fail on
> my system.  I built gmp from upstream, installed it, and pointed to
> the install location with --with-gmp. Which stage does your build fail
> at?

To get the failure you need not to have GMP installed somewhere the 
bootstrap compiler would otherwise find (e.g. uninstall your system GMP 
package before testing).  The failure is building stage 1.

> I am actually not totally sure how to respect the -with-gmp argument
> in libcc1.  auto* tools are not my strongest skill. ;)
> 
> I notice gcc/configure.ac I think just exports the variables to
> Makefile.in from the main configure script.  That what we should do in
> this case?

Toplevel passes GMPINC down to subdirectories.  I think you should

(a) copy

AC_ARG_VAR(GMPINC,[How to find GMP include files])

from gcc/configure.ac;

(b) copy

GMPINC = @GMPINC@

from gcc/Makefile.in;

(c) add $(GMPINC) to AM_CPPFLAGS.

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 5/5] add libcc1
  2014-10-28 13:29                 ` Joseph S. Myers
@ 2014-10-28 18:00                   ` Phil Muldoon
  2014-10-29  3:32                     ` Joseph S. Myers
  2014-10-29 10:29                     ` Jakub Jelinek
  0 siblings, 2 replies; 71+ messages in thread
From: Phil Muldoon @ 2014-10-28 18:00 UTC (permalink / raw)
  To: Joseph S. Myers; +Cc: gcc-patches

On 28/10/14 13:19, Joseph S. Myers wrote:
> I'm seeing a different bootstrap failure from those already discussed:
>
> In file included from
> /scratch/jmyers/fsf/gcc-mainline/libcc1/../gcc/gcc-plugin.h:28:0,
>                  from
> /scratch/jmyers/fsf/gcc-mainline/libcc1/plugin.cc:34:
> /scratch/jmyers/fsf/gcc-mainline/libcc1/../gcc/system.h:653:17: fatal error: gmp.h: No such file or directory
>
> It appears the build is ignoring the --with-gmp option passed to
> configure.  Since <gmp.h> is included in system.h, if you include system.h
> you have to pass the right -I option corresponding to --with-gmp /
> --with-gmp-include.  (There are several other such configure options for
> MPFR, MPC, CLooG, ISL, libiconv at least - whether they are relevant
> depends on whether your code ends up including the relevant headers.)

Joseph,

Hi, sorry for the troubles! I am having difficulty seeing this fail on
my system.  I built gmp from upstream, installed it, and pointed to
the install location with --with-gmp. Which stage does your build fail
at?

I am actually not totally sure how to respect the -with-gmp argument
in libcc1.  auto* tools are not my strongest skill. ;)

I notice gcc/configure.ac I think just exports the variables to
Makefile.in from the main configure script.  That what we should do in
this case?

Cheers

Phil


^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 5/5] add libcc1
  2014-10-27 20:03               ` Phil Muldoon
@ 2014-10-28 13:29                 ` Joseph S. Myers
  2014-10-28 18:00                   ` Phil Muldoon
  0 siblings, 1 reply; 71+ messages in thread
From: Joseph S. Myers @ 2014-10-28 13:29 UTC (permalink / raw)
  To: Phil Muldoon; +Cc: gcc-patches

I'm seeing a different bootstrap failure from those already discussed:

In file included from 
/scratch/jmyers/fsf/gcc-mainline/libcc1/../gcc/gcc-plugin.h:28:0,
                 from 
/scratch/jmyers/fsf/gcc-mainline/libcc1/plugin.cc:34:
/scratch/jmyers/fsf/gcc-mainline/libcc1/../gcc/system.h:653:17: fatal error: gmp.h: No such file or directory

It appears the build is ignoring the --with-gmp option passed to 
configure.  Since <gmp.h> is included in system.h, if you include system.h 
you have to pass the right -I option corresponding to --with-gmp / 
--with-gmp-include.  (There are several other such configure options for 
MPFR, MPC, CLooG, ISL, libiconv at least - whether they are relevant 
depends on whether your code ends up including the relevant headers.)

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 5/5] add libcc1
  2014-10-28 11:53         ` Phil Muldoon
@ 2014-10-28 12:24           ` Jakub Jelinek
  2014-10-30  5:16             ` Jeff Law
  2014-10-30  8:50             ` Thomas Schwinge
  0 siblings, 2 replies; 71+ messages in thread
From: Jakub Jelinek @ 2014-10-28 12:24 UTC (permalink / raw)
  To: Phil Muldoon; +Cc: Uros Bizjak, gcc-patches, Tom Tromey, Jeff Law

On Tue, Oct 28, 2014 at 11:47:31AM +0000, Phil Muldoon wrote:
> I think I have a solution.  Though my automake fu is very weak.  Does
> this patch work for you?  I'm really not sure how to deal with the
> three possible versions of libiberty any other way.

That is insufficient,
a) you don't filter away -fsanitize=address, which would make it
unusable in gdb
b) without the -Wc, stuff, you get the ugly libtool warnings
c) the LTLDFLAGS mess is needed for libtool not eating the -Wc, stuff

I've in the mean time successfully bootstrapped/regtested my patch on
i686-linux (--with-build-config=bootstrap-ubsan), that was build without
ada, on x86_64-linux the build failed because of some recent ada vs.
bootstrap-ubsan incompatibilities unrelated to libcc1 (but libcc1 built
fine).

So I'm proposing my patch (which is modeled after lto-plugin changes by
myself and others), with the -Werror stuff handled separately as follow-up.
Ok for trunk?

2014-10-28  Jakub Jelinek  <jakub@redhat.com>

	* Makefile.am (CXXFLAGS, LDFLAGS): Filter out -fsanitize=address.
	(libiberty_normal, libiberty_noasan, libiberty_pic, libiberty_dep):
	New variables.
	(libiberty): Set to -Wc, followed by the first existing noasan/,
	pic/ or . libiberty.a.
	(libcc1plugin_la_DEPENDENCIES, libcc1plugin_la_LINK,
	libcc1_la_DEPENDENCIES, libcc1_la_LINK, LTLDFLAGS): New variables.
	* Makefile.in: Regenerated.

--- libcc1/Makefile.am.jj	2014-10-27 19:41:13.000000000 +0100
+++ libcc1/Makefile.am	2014-10-28 09:07:57.443711725 +0100
@@ -24,8 +24,17 @@ AM_CPPFLAGS = -I $(srcdir)/../include -I
 	-I $(srcdir)/../libcpp/include
 WERROR_FLAG = -Werror
 AM_CXXFLAGS = $(WARN_FLAGS) $(WERROR_FLAG) $(visibility)
-libiberty = ../libiberty/pic/libiberty.a
-
+override CXXFLAGS := $(filter-out -fsanitize=address,$(CXXFLAGS))
+override LDFLAGS := $(filter-out -fsanitize=address,$(LDFLAGS))
+# Can be simplified when libiberty becomes a normal convenience library.
+libiberty_normal = ../libiberty/libiberty.a
+libiberty_noasan = ../libiberty/noasan/libiberty.a
+libiberty_pic = ../libiberty/pic/libiberty.a
+Wc=-Wc,
+libiberty = $(if $(wildcard $(libiberty_noasan)),$(Wc)$(libiberty_noasan), \
+	    $(if $(wildcard $(libiberty_pic)),$(Wc)$(libiberty_pic), \
+	    $(Wc)$(libiberty_normal)))
+libiberty_dep = $(patsubst $(Wc)%,%,$(libiberty))
 
 plugindir = $(libdir)/gcc/$(target_noncanonical)/$(gcc_version)/plugin
 cc1libdir = $(libdir)/$(libsuffix)
@@ -49,7 +58,16 @@ shared_source = callbacks.cc callbacks.h
 libcc1plugin_la_LDFLAGS = -module -export-symbols $(srcdir)/libcc1plugin.sym
 libcc1plugin_la_SOURCES = plugin.cc $(shared_source)
 libcc1plugin_la_LIBADD = $(libiberty)
+libcc1plugin_la_DEPENDENCIES = $(libiberty_dep)
+libcc1plugin_la_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+	$(CXXFLAGS) $(libcc1plugin_la_LDFLAGS) $(LTLDFLAGS) -o $@
 
+LTLDFLAGS = $(shell $(SHELL) $(top_srcdir)/../libtool-ldflags $(LDFLAGS))
 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)
+libcc1_la_DEPENDENCIES = $(libiberty_dep)
+libcc1_la_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+	$(CXXFLAGS) $(libcc1_la_LDFLAGS) $(LTLDFLAGS) -o $@
--- libcc1/Makefile.in.jj	2014-10-27 19:41:13.000000000 +0100
+++ libcc1/Makefile.in	2014-10-28 09:08:01.689922599 +0100
@@ -81,20 +81,12 @@ am__base_list = \
   sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
 am__installdirs = "$(DESTDIR)$(cc1libdir)" "$(DESTDIR)$(plugindir)"
 LTLIBRARIES = $(cc1lib_LTLIBRARIES) $(plugin_LTLIBRARIES)
-libcc1_la_DEPENDENCIES = $(libiberty)
 am__objects_1 = callbacks.lo connection.lo marshall.lo
 am_libcc1_la_OBJECTS = findcomp.lo libcc1.lo names.lo $(am__objects_1)
 libcc1_la_OBJECTS = $(am_libcc1_la_OBJECTS)
-libcc1_la_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \
-	$(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
-	$(CXXFLAGS) $(libcc1_la_LDFLAGS) $(LDFLAGS) -o $@
 @ENABLE_PLUGIN_TRUE@am_libcc1_la_rpath = -rpath $(cc1libdir)
-libcc1plugin_la_DEPENDENCIES = $(libiberty)
 am_libcc1plugin_la_OBJECTS = plugin.lo $(am__objects_1)
 libcc1plugin_la_OBJECTS = $(am_libcc1plugin_la_OBJECTS)
-libcc1plugin_la_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \
-	$(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
-	$(CXXFLAGS) $(libcc1plugin_la_LDFLAGS) $(LDFLAGS) -o $@
 @ENABLE_PLUGIN_TRUE@am_libcc1plugin_la_rpath = -rpath $(plugindir)
 DEFAULT_INCLUDES = -I.@am__isrc@
 depcomp = $(SHELL) $(top_srcdir)/../depcomp
@@ -259,7 +251,16 @@ AM_CPPFLAGS = -I $(srcdir)/../include -I
 
 WERROR_FLAG = -Werror
 AM_CXXFLAGS = $(WARN_FLAGS) $(WERROR_FLAG) $(visibility)
-libiberty = ../libiberty/pic/libiberty.a
+# Can be simplified when libiberty becomes a normal convenience library.
+libiberty_normal = ../libiberty/libiberty.a
+libiberty_noasan = ../libiberty/noasan/libiberty.a
+libiberty_pic = ../libiberty/pic/libiberty.a
+Wc = -Wc,
+libiberty = $(if $(wildcard $(libiberty_noasan)),$(Wc)$(libiberty_noasan), \
+	    $(if $(wildcard $(libiberty_pic)),$(Wc)$(libiberty_pic), \
+	    $(Wc)$(libiberty_normal)))
+
+libiberty_dep = $(patsubst $(Wc)%,%,$(libiberty))
 plugindir = $(libdir)/gcc/$(target_noncanonical)/$(gcc_version)/plugin
 cc1libdir = $(libdir)/$(libsuffix)
 @ENABLE_PLUGIN_TRUE@plugin_LTLIBRARIES = libcc1plugin.la
@@ -271,9 +272,20 @@ shared_source = callbacks.cc callbacks.h
 libcc1plugin_la_LDFLAGS = -module -export-symbols $(srcdir)/libcc1plugin.sym
 libcc1plugin_la_SOURCES = plugin.cc $(shared_source)
 libcc1plugin_la_LIBADD = $(libiberty)
+libcc1plugin_la_DEPENDENCIES = $(libiberty_dep)
+libcc1plugin_la_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+	$(CXXFLAGS) $(libcc1plugin_la_LDFLAGS) $(LTLDFLAGS) -o $@
+
+LTLDFLAGS = $(shell $(SHELL) $(top_srcdir)/../libtool-ldflags $(LDFLAGS))
 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)
+libcc1_la_DEPENDENCIES = $(libiberty_dep)
+libcc1_la_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \
+	$(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+	$(CXXFLAGS) $(libcc1_la_LDFLAGS) $(LTLDFLAGS) -o $@
+
 all: $(BUILT_SOURCES) cc1plugin-config.h
 	$(MAKE) $(AM_MAKEFLAGS) all-am
 
@@ -619,6 +631,8 @@ uninstall-am: uninstall-cc1libLTLIBRARIE
 	pdf pdf-am ps ps-am tags uninstall uninstall-am \
 	uninstall-cc1libLTLIBRARIES uninstall-pluginLTLIBRARIES
 
+override CXXFLAGS := $(filter-out -fsanitize=address,$(CXXFLAGS))
+override LDFLAGS := $(filter-out -fsanitize=address,$(LDFLAGS))
 
 # 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.


	Jakub

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 5/5] add libcc1
  2014-10-28 10:56       ` Uros Bizjak
  2014-10-28 11:16         ` Phil Muldoon
@ 2014-10-28 11:53         ` Phil Muldoon
  2014-10-28 12:24           ` Jakub Jelinek
  1 sibling, 1 reply; 71+ messages in thread
From: Phil Muldoon @ 2014-10-28 11:53 UTC (permalink / raw)
  To: Uros Bizjak; +Cc: Jakub Jelinek, gcc-patches, Tom Tromey, Jeff Law

On 28/10/14 10:51, Uros Bizjak wrote:
> On Tue, Oct 28, 2014 at 11:35 AM, Phil Muldoon <pmuldoon@redhat.com> wrote:
>
>>>>>> This patch has now been committed.
>>>>>
>>>>> Also breaks bootstap on x86_64-linux-gnu, CentOS 5.11:
>>>>
>>>> For -Werror, I'd think that should fix that, WARN_FLAGS should
>>>> already contain -Werror during stage2/stage3 unless --disable-werror.
>>>> Untested though.
>>>
>>> No, it still fails, although with one -Werror less in the compile flags:
>>
>> Does removing it from configure.ac and regenerating configure work?
>>
>> I don't have access to a system compiler of the version you have, so I
>> am unable to test.
>
> Yes, this patch allows bootstrap to pass stage1, although with a new warning:
>
> *** Warning: Linking the shared library libcc1.la against the
> *** static library ../libiberty/pic/libiberty.a is not portable!
>
> Thanks,
> Uros.

I think I have a solution.  Though my automake fu is very weak.  Does
this patch work for you?  I'm really not sure how to deal with the
three possible versions of libiberty any other way.

Cheers

Phil

--



Index: Makefile.in
===================================================================
--- Makefile.in    (revision 216776)
+++ Makefile.in    (working copy)
@@ -81,7 +81,8 @@
   sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
 am__installdirs = "$(DESTDIR)$(cc1libdir)" "$(DESTDIR)$(plugindir)"
 LTLIBRARIES = $(cc1lib_LTLIBRARIES) $(plugin_LTLIBRARIES)
-libcc1_la_DEPENDENCIES = $(libiberty)
+libcc1_la_DEPENDENCIES = $(if $(wildcard $(libiberty_noasan)),, $(if \
+    $(wildcard $(libiberty_pic)),,$(libiberty)))
 am__objects_1 = callbacks.lo connection.lo marshall.lo
 am_libcc1_la_OBJECTS = findcomp.lo libcc1.lo names.lo $(am__objects_1)
 libcc1_la_OBJECTS = $(am_libcc1_la_OBJECTS)
@@ -89,7 +90,8 @@
     $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
     $(CXXFLAGS) $(libcc1_la_LDFLAGS) $(LDFLAGS) -o $@
 @ENABLE_PLUGIN_TRUE@am_libcc1_la_rpath = -rpath $(cc1libdir)
-libcc1plugin_la_DEPENDENCIES = $(libiberty)
+libcc1plugin_la_DEPENDENCIES = $(if $(wildcard $(libiberty_noasan)),, \
+    $(if $(wildcard $(libiberty_pic)),,$(libiberty)))
 am_libcc1plugin_la_OBJECTS = plugin.lo $(am__objects_1)
 libcc1plugin_la_OBJECTS = $(am_libcc1plugin_la_OBJECTS)
 libcc1plugin_la_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \
@@ -257,9 +259,10 @@
     -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
+AM_CXXFLAGS = $(WARN_FLAGS) $(visibility)
+libiberty = ../libiberty/libiberty.a
+libiberty_noasan = ../libiberty/noasan/libiberty.a
+libiberty_pic = ../libiberty/pic/libiberty.a
 plugindir = $(libdir)/gcc/$(target_noncanonical)/$(gcc_version)/plugin
 cc1libdir = $(libdir)/$(libsuffix)
 @ENABLE_PLUGIN_TRUE@plugin_LTLIBRARIES = libcc1plugin.la
@@ -270,10 +273,16 @@
 
 libcc1plugin_la_LDFLAGS = -module -export-symbols $(srcdir)/libcc1plugin.sym
 libcc1plugin_la_SOURCES = plugin.cc $(shared_source)
-libcc1plugin_la_LIBADD = $(libiberty)
+libcc1plugin_la_LIBADD = \
+    $(if $(wildcard $(libiberty_noasan)),, \
+    $(if $(wildcard $(libiberty_pic)),,$(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)
+libcc1_la_LIBADD = \
+    $(if $(wildcard $(libiberty_noasan)),, \
+    $(if $(wildcard $(libiberty_pic)),,$(libiberty)))
+
 all: $(BUILT_SOURCES) cc1plugin-config.h
     $(MAKE) $(AM_MAKEFLAGS) all-am
 
Index: Makefile.am
===================================================================
--- Makefile.am    (revision 216776)
+++ Makefile.am    (working copy)
@@ -22,10 +22,11 @@
     -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
+AM_CXXFLAGS = $(WARN_FLAGS) $(visibility)
 
+libiberty = ../libiberty/libiberty.a
+libiberty_noasan = ../libiberty/noasan/libiberty.a
+libiberty_pic = ../libiberty/pic/libiberty.a
 
 plugindir = $(libdir)/gcc/$(target_noncanonical)/$(gcc_version)/plugin
 cc1libdir = $(libdir)/$(libsuffix)
@@ -48,8 +49,13 @@
 
 libcc1plugin_la_LDFLAGS = -module -export-symbols $(srcdir)/libcc1plugin.sym
 libcc1plugin_la_SOURCES = plugin.cc $(shared_source)
-libcc1plugin_la_LIBADD = $(libiberty)
+libcc1plugin_la_LIBADD = \
+    $(if $(wildcard $(libiberty_noasan)),, \
+    $(if $(wildcard $(libiberty_pic)),,$(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)
+libcc1_la_LIBADD = \
+    $(if $(wildcard $(libiberty_noasan)),, \
+    $(if $(wildcard $(libiberty_pic)),,$(libiberty)))
+

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 5/5] add libcc1
  2014-10-28 10:56       ` Uros Bizjak
@ 2014-10-28 11:16         ` Phil Muldoon
  2014-10-28 11:53         ` Phil Muldoon
  1 sibling, 0 replies; 71+ messages in thread
From: Phil Muldoon @ 2014-10-28 11:16 UTC (permalink / raw)
  To: Uros Bizjak; +Cc: Jakub Jelinek, gcc-patches, Tom Tromey, Jeff Law

On 28/10/14 10:51, Uros Bizjak wrote:
> On Tue, Oct 28, 2014 at 11:35 AM, Phil Muldoon <pmuldoon@redhat.com> wrote:
>
>>>>>> This patch has now been committed.
>>>>> Also breaks bootstap on x86_64-linux-gnu, CentOS 5.11:
>>>> For -Werror, I'd think that should fix that, WARN_FLAGS should
>>>> already contain -Werror during stage2/stage3 unless --disable-werror.
>>>> Untested though.
>>> No, it still fails, although with one -Werror less in the compile flags:
>> Does removing it from configure.ac and regenerating configure work?
>>
>> I don't have access to a system compiler of the version you have, so I
>> am unable to test.
> Yes, this patch allows bootstrap to pass stage1, although with a new warning:
>
> *** Warning: Linking the shared library libcc1.la against the
> *** static library ../libiberty/pic/libiberty.a is not portable!
>
> Thanks,
> Uros.

Yeah there is a separate issue with the way we link libiberty in Makefile.am.  I am investigating and attempting to fix this right now.

Cheers

Phil

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 5/5] add libcc1
  2014-10-28 10:51     ` Phil Muldoon
@ 2014-10-28 10:56       ` Uros Bizjak
  2014-10-28 11:16         ` Phil Muldoon
  2014-10-28 11:53         ` Phil Muldoon
  0 siblings, 2 replies; 71+ messages in thread
From: Uros Bizjak @ 2014-10-28 10:56 UTC (permalink / raw)
  To: Phil Muldoon; +Cc: Jakub Jelinek, gcc-patches, Tom Tromey, Jeff Law

On Tue, Oct 28, 2014 at 11:35 AM, Phil Muldoon <pmuldoon@redhat.com> wrote:

>>>>> This patch has now been committed.
>>>>
>>>> Also breaks bootstap on x86_64-linux-gnu, CentOS 5.11:
>>>
>>> For -Werror, I'd think that should fix that, WARN_FLAGS should
>>> already contain -Werror during stage2/stage3 unless --disable-werror.
>>> Untested though.
>>
>> No, it still fails, although with one -Werror less in the compile flags:
>
> Does removing it from configure.ac and regenerating configure work?
>
> I don't have access to a system compiler of the version you have, so I
> am unable to test.

Yes, this patch allows bootstrap to pass stage1, although with a new warning:

*** Warning: Linking the shared library libcc1.la against the
*** static library ../libiberty/pic/libiberty.a is not portable!

Thanks,
Uros.

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 5/5] add libcc1
  2014-10-28  9:58   ` Uros Bizjak
@ 2014-10-28 10:51     ` Phil Muldoon
  2014-10-28 10:56       ` Uros Bizjak
  0 siblings, 1 reply; 71+ messages in thread
From: Phil Muldoon @ 2014-10-28 10:51 UTC (permalink / raw)
  To: Uros Bizjak, Jakub Jelinek; +Cc: gcc-patches, Tom Tromey, Jeff Law

On 28/10/14 09:57, Uros Bizjak wrote:
> On Tue, Oct 28, 2014 at 10:35 AM, Jakub Jelinek <jakub@redhat.com> wrote:
>> On Tue, Oct 28, 2014 at 09:36:45AM +0100, Uros Bizjak wrote:
>>>> This patch has now been committed.
>>>
>>> Also breaks bootstap on x86_64-linux-gnu, CentOS 5.11:
>>
>> For -Werror, I'd think that should fix that, WARN_FLAGS should
>> already contain -Werror during stage2/stage3 unless --disable-werror.
>> Untested though.
>
> No, it still fails, although with one -Werror less in the compile flags:

Does removing it from configure.ac and regenerating configure work?

I don't have access to a system compiler of the version you have, so I
am unable to test.

Cheers

Phil

--

Index: Makefile.am
===================================================================
--- Makefile.am    (revision 216776)
+++ Makefile.am    (working copy)
@@ -22,8 +22,7 @@
     -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)
+AM_CXXFLAGS = $(WARN_FLAGS) $(visibility)
 libiberty = ../libiberty/pic/libiberty.a
 
 
Index: Makefile.in
===================================================================
--- Makefile.in    (revision 216776)
+++ Makefile.in    (working copy)
@@ -257,8 +257,7 @@
     -I $(srcdir)/../gcc/c -I $(srcdir)/../gcc/c-family \
     -I $(srcdir)/../libcpp/include
 
-WERROR_FLAG = -Werror
-AM_CXXFLAGS = $(WARN_FLAGS) $(WERROR_FLAG) $(visibility)
+AM_CXXFLAGS = $(WARN_FLAGS) $(visibility)
 libiberty = ../libiberty/pic/libiberty.a
 plugindir = $(libdir)/gcc/$(target_noncanonical)/$(gcc_version)/plugin
 cc1libdir = $(libdir)/$(libsuffix)

Index: configure
===================================================================
--- configure    (revision 216776)
+++ configure    (working copy)
@@ -14342,7 +14342,7 @@
   done
 CFLAGS="$save_CFLAGS"
 
-WARN_FLAGS="$WARN_FLAGS -Werror"
+WARN_FLAGS="$WARN_FLAGS"
 
 
 libsuffix=

Index: configure.ac
===================================================================
--- configure.ac    (revision 216776)
+++ configure.ac    (working copy)
@@ -52,7 +52,7 @@
 AC_SUBST(gcc_version)
 
 ACX_PROG_CC_WARNING_OPTS([-W -Wall], [WARN_FLAGS])
-WARN_FLAGS="$WARN_FLAGS -Werror"
+WARN_FLAGS="$WARN_FLAGS"
 AC_SUBST(WARN_FLAGS)
 
 libsuffix=


^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 5/5] add libcc1
  2014-10-28  9:36 ` Jakub Jelinek
@ 2014-10-28  9:58   ` Uros Bizjak
  2014-10-28 10:51     ` Phil Muldoon
  0 siblings, 1 reply; 71+ messages in thread
From: Uros Bizjak @ 2014-10-28  9:58 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: gcc-patches, Tom Tromey, Jeff Law, Phil Muldoon

On Tue, Oct 28, 2014 at 10:35 AM, Jakub Jelinek <jakub@redhat.com> wrote:
> On Tue, Oct 28, 2014 at 09:36:45AM +0100, Uros Bizjak wrote:
>> > This patch has now been committed.
>>
>> Also breaks bootstap on x86_64-linux-gnu, CentOS 5.11:
>
> For -Werror, I'd think that should fix that, WARN_FLAGS should
> already contain -Werror during stage2/stage3 unless --disable-werror.
> Untested though.

No, it still fails, although with one -Werror less in the compile flags:

gmake[4]: Entering directory `/home/uros/gcc-build/libcc1'
/bin/sh ./libtool --tag=CXX   --mode=compile g++ -DHAVE_CONFIG_H -I.
-I../../gcc-svn/trunk/libcc1  -I ../../gcc-svn/trunk/libcc1/../include
-I ../../gcc-svn/trunk/libcc1/../libgcc -I .././gcc
-I../../gcc-svn/trunk/libcc1/../gcc -I
../../gcc-svn/trunk/libcc1/../gcc/c -I
../../gcc-svn/trunk/libcc1/../gcc/c-family -I
../../gcc-svn/trunk/libcc1/../libcpp/include  -W -Wall -Werror
-fvisibility=hidden -g -MT plugin.lo -MD -MP -MF .deps/plugin.Tpo -c
-o plugin.lo ../../gcc-svn/trunk/libcc1/plugin.cc
libtool: compile:  g++ -DHAVE_CONFIG_H -I.
-I../../gcc-svn/trunk/libcc1 -I ../../gcc-svn/trunk/libcc1/../include
-I ../../gcc-svn/trunk/libcc1/../libgcc -I .././gcc
-I../../gcc-svn/trunk/libcc1/../gcc -I
../../gcc-svn/trunk/libcc1/../gcc/c -I
../../gcc-svn/trunk/libcc1/../gcc/c-family -I
../../gcc-svn/trunk/libcc1/../libcpp/include -W -Wall -Werror
-fvisibility=hidden -g -MT plugin.lo -MD -MP -MF .deps/plugin.Tpo -c
../../gcc-svn/trunk/libcc1/plugin.cc  -fPIC -DPIC -o .libs/plugin.o
cc1plus: warnings being treated as errors
../../gcc-svn/trunk/libcc1/../gcc/hash-table.h: In instantiation of
‘hash_table<pointer_hash<tree_node>, xcallocator, true>’:
../../gcc-svn/trunk/libcc1/plugin.cc:171:   instantiated from here
../../gcc-svn/trunk/libcc1/../gcc/hash-table.h:1161: warning: lowering
visibility of ‘void gt_ggc_mx(hash_table<T, xcallocator,
storage_tester<T,void>::value>*) [with T = T, Descriptor =
pointer_hash<tree_node>, Allocator = xcallocator]’ to match its type
../../gcc-svn/trunk/libcc1/../gcc/hash-table.h:1162: warning: lowering
visibility of ‘void gt_pch_nx(hash_table<T, xcallocator,
storage_tester<T,void>::value>*) [with T = T, Descriptor =
pointer_hash<tree_node>, Allocator = xcallocator]’ to match its type
../../gcc-svn/trunk/libcc1/../gcc/hash-table.h:1166: warning: lowering
visibility of ‘void gt_pch_nx(hash_map<T, U, V>*, void (*)(void*,
void*), void*) [with T = T, U = U, V = V, Descriptor =
pointer_hash<tree_node>, Allocator = xcallocator]’ to match its type
../../gcc-svn/trunk/libcc1/../gcc/hash-table.h:1169: warning: lowering
visibility of ‘void gt_pch_nx(hash_set<T, U>*, void (*)(void*, void*),
void*) [with T = T, U = U, Descriptor = pointer_hash<tree_node>,
Allocator = xcallocator]’ to match its type
../../gcc-svn/trunk/libcc1/../gcc/hash-table.h:1171: warning: lowering
visibility of ‘void gt_pch_nx(hash_table<T, xcallocator,
storage_tester<T,void>::value>*, void (*)(void*, void*), void*) [with
T = T, Descriptor = pointer_hash<tree_node>, Allocator = xcallocator]’
to match its type
gmake[4]: *** [plugin.lo] Error 1
gmake[4]: Leaving directory `/home/uros/gcc-build/libcc1'
gmake[3]: *** [all] Error 2
gmake[3]: Leaving directory `/home/uros/gcc-build/libcc1'
gmake[2]: *** [all-stage1-libcc1] Error 2
gmake[2]: Leaving directory `/home/uros/gcc-build'
gmake[1]: *** [stage1-bubble] Error 2
gmake[1]: Leaving directory `/home/uros/gcc-build'
gmake: *** [all] Error 2

I wonder if at this point just compiled gcc/xg++ and not system
compiler should be used?

Uros.

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 5/5] add libcc1
  2014-10-28  8:43 Uros Bizjak
  2014-10-28  8:55 ` Phil Muldoon
@ 2014-10-28  9:36 ` Jakub Jelinek
  2014-10-28  9:58   ` Uros Bizjak
  1 sibling, 1 reply; 71+ messages in thread
From: Jakub Jelinek @ 2014-10-28  9:36 UTC (permalink / raw)
  To: Uros Bizjak; +Cc: gcc-patches, Tom Tromey, Jeff Law, pmuldoon

On Tue, Oct 28, 2014 at 09:36:45AM +0100, Uros Bizjak wrote:
> > This patch has now been committed.
> 
> Also breaks bootstap on x86_64-linux-gnu, CentOS 5.11:

For -Werror, I'd think that should fix that, WARN_FLAGS should
already contain -Werror during stage2/stage3 unless --disable-werror.
Untested though.

--- libcc1/Makefile.am	2014-10-28 09:07:57.443711725 +0100
+++ libcc1/Makefile.am	2014-10-28 10:32:09.712135034 +0100
@@ -22,8 +22,7 @@ AM_CPPFLAGS = -I $(srcdir)/../include -I
 	-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)
+AM_CXXFLAGS = $(WARN_FLAGS) $(visibility)
 override CXXFLAGS := $(filter-out -fsanitize=address,$(CXXFLAGS))
 override LDFLAGS := $(filter-out -fsanitize=address,$(LDFLAGS))
 # Can be simplified when libiberty becomes a normal convenience library.
--- libcc1/Makefile.in	2014-10-28 09:08:01.689922599 +0100
+++ libcc1/Makefile.in	2014-10-28 10:32:21.376918921 +0100
@@ -249,8 +249,7 @@ AM_CPPFLAGS = -I $(srcdir)/../include -I
 	-I $(srcdir)/../gcc/c -I $(srcdir)/../gcc/c-family \
 	-I $(srcdir)/../libcpp/include
 
-WERROR_FLAG = -Werror
-AM_CXXFLAGS = $(WARN_FLAGS) $(WERROR_FLAG) $(visibility)
+AM_CXXFLAGS = $(WARN_FLAGS) $(visibility)
 # Can be simplified when libiberty becomes a normal convenience library.
 libiberty_normal = ../libiberty/libiberty.a
 libiberty_noasan = ../libiberty/noasan/libiberty.a


	Jakub

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 5/5] add libcc1
  2014-10-28  8:55 ` Phil Muldoon
@ 2014-10-28  9:21   ` Uros Bizjak
  0 siblings, 0 replies; 71+ messages in thread
From: Uros Bizjak @ 2014-10-28  9:21 UTC (permalink / raw)
  To: Phil Muldoon; +Cc: gcc-patches, Tom Tromey, Jakub Jelinek, Jeff Law

On Tue, Oct 28, 2014 at 9:50 AM, Phil Muldoon <pmuldoon@redhat.com> wrote:
> On 28/10/14 08:36, Uros Bizjak wrote:
>>> This patch has now been committed.
>> Also breaks bootstap on x86_64-linux-gnu, CentOS 5.11:
>>
>> gmake[4]: Entering directory `/home/uros/gcc-build/libcc1'
>> /bin/sh ./libtool --tag=CXX   --mode=compile g++ -DHAVE_CONFIG_H -I.
>> -I../../gcc-svn/trunk/libcc1  -I ../../gcc-svn/trunk/libcc1/../include
>> -I ../../gcc-svn/trunk/libcc1/../libgcc -I .././gcc
>> -I../../gcc-svn/trunk/libcc1/../gcc -I
>
> Weird, I bootstrapped my build on x8664 Fedora 20 and saw no issues.  Can you please
> provide me your build/configure parameters?

This failure is in stage1 due to -Werror in combination with default
CentOS gcc-4.1.x compiler:

gcc version 4.1.2 20080704 (Red Hat 4.1.2-55)

Stage1 libraries should not be compiled with -Werror, since the
default system compiler can have issues with warnings.

Uros.

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 5/5] add libcc1
  2014-10-28  8:43 Uros Bizjak
@ 2014-10-28  8:55 ` Phil Muldoon
  2014-10-28  9:21   ` Uros Bizjak
  2014-10-28  9:36 ` Jakub Jelinek
  1 sibling, 1 reply; 71+ messages in thread
From: Phil Muldoon @ 2014-10-28  8:55 UTC (permalink / raw)
  To: Uros Bizjak, gcc-patches; +Cc: Tom Tromey, Jakub Jelinek, Jeff Law

On 28/10/14 08:36, Uros Bizjak wrote:
>> This patch has now been committed.
> Also breaks bootstap on x86_64-linux-gnu, CentOS 5.11:
>
> gmake[4]: Entering directory `/home/uros/gcc-build/libcc1'
> /bin/sh ./libtool --tag=CXX   --mode=compile g++ -DHAVE_CONFIG_H -I.
> -I../../gcc-svn/trunk/libcc1  -I ../../gcc-svn/trunk/libcc1/../include
> -I ../../gcc-svn/trunk/libcc1/../libgcc -I .././gcc
> -I../../gcc-svn/trunk/libcc1/../gcc -I

Weird, I bootstrapped my build on x8664 Fedora 20 and saw no issues.  Can you please
provide me your build/configure parameters?

Cheers

Phil

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 5/5] add libcc1
@ 2014-10-28  8:43 Uros Bizjak
  2014-10-28  8:55 ` Phil Muldoon
  2014-10-28  9:36 ` Jakub Jelinek
  0 siblings, 2 replies; 71+ messages in thread
From: Uros Bizjak @ 2014-10-28  8:43 UTC (permalink / raw)
  To: gcc-patches; +Cc: Tom Tromey, Jakub Jelinek, Jeff Law, pmuldoon

> This patch has now been committed.

Also breaks bootstap on x86_64-linux-gnu, CentOS 5.11:

gmake[4]: Entering directory `/home/uros/gcc-build/libcc1'
/bin/sh ./libtool --tag=CXX   --mode=compile g++ -DHAVE_CONFIG_H -I.
-I../../gcc-svn/trunk/libcc1  -I ../../gcc-svn/trunk/libcc1/../include
-I ../../gcc-svn/trunk/libcc1/../libgcc -I .././gcc
-I../../gcc-svn/trunk/libcc1/../gcc -I
../../gcc-svn/trunk/libcc1/../gcc/c -I
../../gcc-svn/trunk/libcc1/../gcc/c-family -I
../../gcc-svn/trunk/libcc1/../libcpp/include  -W -Wall -Werror -Werror
-fvisibility=hidden -g -MT plugin.lo -MD -MP -MF .deps/plugin.Tpo -c
-o plugin.lo ../../gcc-svn/trunk/libcc1/plugin.cc
libtool: compile:  g++ -DHAVE_CONFIG_H -I.
-I../../gcc-svn/trunk/libcc1 -I ../../gcc-svn/trunk/libcc1/../include
-I ../../gcc-svn/trunk/libcc1/../libgcc -I .././gcc
-I../../gcc-svn/trunk/libcc1/../gcc -I
../../gcc-svn/trunk/libcc1/../gcc/c -I
../../gcc-svn/trunk/libcc1/../gcc/c-family -I
../../gcc-svn/trunk/libcc1/../libcpp/include -W -Wall -Werror -Werror
-fvisibility=hidden -g -MT plugin.lo -MD -MP -MF .deps/plugin.Tpo -c
../../gcc-svn/trunk/libcc1/plugin.cc  -fPIC -DPIC -o .libs/plugin.o
cc1plus: warnings being treated as errors
../../gcc-svn/trunk/libcc1/../gcc/hash-table.h: In instantiation of
‘hash_table<pointer_hash<tree_node>, xcallocator, true>’:
../../gcc-svn/trunk/libcc1/plugin.cc:171:   instantiated from here
../../gcc-svn/trunk/libcc1/../gcc/hash-table.h:1161: warning: lowering
visibility of ‘void gt_ggc_mx(hash_table<T, xcallocator,
storage_tester<T,void>::value>*) [with T = T, Descriptor =
pointer_hash<tree_node>, Allocator = xcallocator]’ to match its type
../../gcc-svn/trunk/libcc1/../gcc/hash-table.h:1162: warning: lowering
visibility of ‘void gt_pch_nx(hash_table<T, xcallocator,
storage_tester<T,void>::value>*) [with T = T, Descriptor =
pointer_hash<tree_node>, Allocator = xcallocator]’ to match its type
../../gcc-svn/trunk/libcc1/../gcc/hash-table.h:1166: warning: lowering
visibility of ‘void gt_pch_nx(hash_map<T, U, V>*, void (*)(void*,
void*), void*) [with T = T, U = U, V = V, Descriptor =
pointer_hash<tree_node>, Allocator = xcallocator]’ to match its type
../../gcc-svn/trunk/libcc1/../gcc/hash-table.h:1169: warning: lowering
visibility of ‘void gt_pch_nx(hash_set<T, U>*, void (*)(void*, void*),
void*) [with T = T, U = U, Descriptor = pointer_hash<tree_node>,
Allocator = xcallocator]’ to match its type
../../gcc-svn/trunk/libcc1/../gcc/hash-table.h:1171: warning: lowering
visibility of ‘void gt_pch_nx(hash_table<T, xcallocator,
storage_tester<T,void>::value>*, void (*)(void*, void*), void*) [with
T = T, Descriptor = pointer_hash<tree_node>, Allocator = xcallocator]’
to match its type
gmake[4]: *** [plugin.lo] Error 1
gmake[4]: Leaving directory `/home/uros/gcc-build/libcc1'
gmake[3]: *** [all] Error 2
gmake[3]: Leaving directory `/home/uros/gcc-build/libcc1'
gmake[2]: *** [all-stage1-libcc1] Error 2
gmake[2]: Leaving directory `/home/uros/gcc-build'
gmake[1]: *** [stage1-bubble] Error 2
gmake[1]: Leaving directory `/home/uros/gcc-build'
gmake: *** [all] Error 2

Uros.

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 5/5] add libcc1
  2014-10-24 16:47             ` Jeff Law
@ 2014-10-27 20:03               ` Phil Muldoon
  2014-10-28 13:29                 ` Joseph S. Myers
  0 siblings, 1 reply; 71+ messages in thread
From: Phil Muldoon @ 2014-10-27 20:03 UTC (permalink / raw)
  To: gcc-patches; +Cc: Jeff Law, jakub, Tom Tromey, tom


> On 10/10/14 22:58, Jeff Law wrote:
>> On 10/09/14 03:07, Phil Muldoon wrote:

> Given the length of time since the original post and now, can you please do sanity bootstrap to make sure nothing's bitrotted before you commit?

>> I've built both pristine and patched branches with bootstrap enabled.
>> I ran both testsuites and used contrib/compare_tests to make sure
>> everything was as it should be.  compare_tests reports everything as
>> fine.  One minor change I found, was due to some ongoing work on
>> hash_tables.  It seems to parameterless constructor call for a new
>> hash table has been removed.  This was trivially fixed with the patch
>> attached.  Even though (to me) it is obvious, what do you think?

> Looks fine to me.
>
> jeff

> On 24/10/14 08:43, Jakub Jelinek wrote:

> So, if these are the only non-obvious changes you needed, please go
> ahead and commit.

>    Jakub

Thanks.  This patch has now been committed.  Bootstrap and
testsuite pre and post are as expected.  Thanks for your help
in getting this patch-series committed.

Cheers

Phil

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 5/5] add libcc1
  2014-10-24  7:43           ` Phil Muldoon
  2014-10-24  7:53             ` Jakub Jelinek
@ 2014-10-24 16:47             ` Jeff Law
  2014-10-27 20:03               ` Phil Muldoon
  1 sibling, 1 reply; 71+ messages in thread
From: Jeff Law @ 2014-10-24 16:47 UTC (permalink / raw)
  To: Phil Muldoon; +Cc: Tom Tromey, tom, gcc-patches

On 10/24/14 01:15, Phil Muldoon wrote:
> On 10/10/14 22:58, Jeff Law wrote:
>> On 10/09/14 03:07, Phil Muldoon wrote:
>>>
>>> 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?
>> Yes, please go ahead and check it in.  You'll be the first contact point if something goes wrong :-)
>>
>> Given the length of time since the original post and now, can you please do sanity bootstrap to make sure nothing's bitrotted before you commit?
>
> I rebased the patch on top of GCC head (from the git repository),
> updated the ChangeLogs, etc from two days ago (it takes two days to do
> a full rebase, pristine and patched bootstrap and testrun on my poor
> laptop ;).
Get a new laptop :-)  The process for getting one from corporate isn't 
bad.  In fact, I just got my refreshed laptop last week.

>
> I've built both pristine and patched branches with bootstrap enabled.
> I ran both testsuites and used contrib/compare_tests to make sure
> everything was as it should be.  compare_tests reports everything as
> fine.  One minor change I found, was due to some ongoing work on
> hash_tables.  It seems to parameterless constructor call for a new
> hash table has been removed.  This was trivially fixed with the patch
> attached.  Even though (to me) it is obvious, what do you think?
Looks fine to me.

jeff

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 5/5] add libcc1
  2014-10-24  7:43           ` Phil Muldoon
@ 2014-10-24  7:53             ` Jakub Jelinek
  2014-10-24 16:47             ` Jeff Law
  1 sibling, 0 replies; 71+ messages in thread
From: Jakub Jelinek @ 2014-10-24  7:53 UTC (permalink / raw)
  To: Phil Muldoon; +Cc: Jeff Law, Tom Tromey, tom, gcc-patches

On Fri, Oct 24, 2014 at 08:15:36AM +0100, Phil Muldoon wrote:
> On 10/10/14 22:58, Jeff Law wrote:
> > On 10/09/14 03:07, Phil Muldoon wrote:
> >>
> >> 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?
> > Yes, please go ahead and check it in.  You'll be the first contact point if something goes wrong :-)
> >
> > Given the length of time since the original post and now, can you please do sanity bootstrap to make sure nothing's bitrotted before you commit?
> 
> I rebased the patch on top of GCC head (from the git repository),
> updated the ChangeLogs, etc from two days ago (it takes two days to do
> a full rebase, pristine and patched bootstrap and testrun on my poor
> laptop ;).
> 
> I've built both pristine and patched branches with bootstrap enabled.
> I ran both testsuites and used contrib/compare_tests to make sure
> everything was as it should be.  compare_tests reports everything as
> fine.  One minor change I found, was due to some ongoing work on
> hash_tables.  It seems to parameterless constructor call for a new
> hash table has been removed.  This was trivially fixed with the patch
> attached.  Even though (to me) it is obvious, what do you think?

> --- a/libcc1/plugin.cc
> +++ b/libcc1/plugin.cc
> @@ -220,13 +220,10 @@ static plugin_context *current_context;
>  
>  plugin_context::plugin_context (int fd)
>    : cc1_plugin::connection (fd),
> -    address_map (),
> -    preserved (),
> -    file_names ()
> +    address_map (30),
> +    preserved (30),
> +    file_names (30)
>  {
> -  address_map.create (20);
> -  preserved.create (20);
> -  file_names.create (20);

This is http://gcc.gnu.org/r211936 , i.e.
https://gcc.gnu.org/ml/gcc-patches/2014-06/msg01598.html
so the changes are fine.

>  }
>  
>  void
> @@ -236,8 +233,8 @@ plugin_context::mark ()
>         it != address_map.end ();
>         ++it)
>      {
> -      ggc_mark ((*it).decl);
> -      ggc_mark ((*it).address);
> +      ggc_mark ((*it)->decl);
> +      ggc_mark ((*it)->address);
>      }

And this is http://gcc.gnu.org/r211937 , i.e.
https://gcc.gnu.org/ml/gcc-patches/2014-06/msg01599.html
in action. 

>    for (hash_table< pointer_hash<tree_node> >::iterator it = preserved.begin ();

So, if these are the only non-obvious changes you needed, please go ahead
and commit.

	Jakub

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 5/5] add libcc1
  2014-10-10 22:31         ` Jeff Law
@ 2014-10-24  7:43           ` Phil Muldoon
  2014-10-24  7:53             ` Jakub Jelinek
  2014-10-24 16:47             ` Jeff Law
  0 siblings, 2 replies; 71+ messages in thread
From: Phil Muldoon @ 2014-10-24  7:43 UTC (permalink / raw)
  To: Jeff Law; +Cc: Tom Tromey, tom, gcc-patches

On 10/10/14 22:58, Jeff Law wrote:
> On 10/09/14 03:07, Phil Muldoon wrote:
>>
>> 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?
> Yes, please go ahead and check it in.  You'll be the first contact point if something goes wrong :-)
>
> Given the length of time since the original post and now, can you please do sanity bootstrap to make sure nothing's bitrotted before you commit?

I rebased the patch on top of GCC head (from the git repository),
updated the ChangeLogs, etc from two days ago (it takes two days to do
a full rebase, pristine and patched bootstrap and testrun on my poor
laptop ;).

I've built both pristine and patched branches with bootstrap enabled.
I ran both testsuites and used contrib/compare_tests to make sure
everything was as it should be.  compare_tests reports everything as
fine.  One minor change I found, was due to some ongoing work on
hash_tables.  It seems to parameterless constructor call for a new
hash table has been removed.  This was trivially fixed with the patch
attached.  Even though (to me) it is obvious, what do you think?

Cheers

Phil

--

diff --git a/libcc1/plugin.cc b/libcc1/plugin.cc
index fbb49d3..5cdd19d 100644
--- a/libcc1/plugin.cc
+++ b/libcc1/plugin.cc
@@ -220,13 +220,10 @@ static plugin_context *current_context;
 
 plugin_context::plugin_context (int fd)
   : cc1_plugin::connection (fd),
-    address_map (),
-    preserved (),
-    file_names ()
+    address_map (30),
+    preserved (30),
+    file_names (30)
 {
-  address_map.create (20);
-  preserved.create (20);
-  file_names.create (20);
 }
 
 void
@@ -236,8 +233,8 @@ plugin_context::mark ()
        it != address_map.end ();
        ++it)
     {
-      ggc_mark ((*it).decl);
-      ggc_mark ((*it).address);
+      ggc_mark ((*it)->decl);
+      ggc_mark ((*it)->address);
     }
 
   for (hash_table< pointer_hash<tree_node> >::iterator it = preserved.begin ();

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 5/5] add libcc1
  2014-10-09  9:07       ` Phil Muldoon
  2014-10-09  9:12         ` Jakub Jelinek
  2014-10-09  9:18         ` Phil Muldoon
@ 2014-10-10 22:31         ` Jeff Law
  2014-10-24  7:43           ` Phil Muldoon
  2 siblings, 1 reply; 71+ messages in thread
From: Jeff Law @ 2014-10-10 22:31 UTC (permalink / raw)
  To: Phil Muldoon; +Cc: Tom Tromey, tom, gcc-patches

On 10/09/14 03:07, Phil Muldoon wrote:
>
> 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?
Yes, please go ahead and check it in.  You'll be the first contact point 
if something goes wrong :-)

Given the length of time since the original post and now, can you please 
do sanity bootstrap to make sure nothing's bitrotted before you commit?
>
>> 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.
>
I think someone mentioned it really deserved a news file mention in 
gdb's new file rather than gcc's.  That makes sense to me.
jeff

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 5/5] add libcc1
  2014-10-09  9:07       ` Phil Muldoon
  2014-10-09  9:12         ` Jakub Jelinek
@ 2014-10-09  9:18         ` Phil Muldoon
  2014-10-10 22:31         ` Jeff Law
  2 siblings, 0 replies; 71+ messages in thread
From: Phil Muldoon @ 2014-10-09  9:18 UTC (permalink / raw)
  To: gcc-patches; +Cc: Tom Tromey, tom, gcc-patches

On 31/07/14 05:47, Jeff Law wrote:
> On 06/19/14 14:52, Tom Tromey wrote:
>> Here's a new version of patch #5.
>> I've removed the generated code; let's see if it gets through without
>> compression.
>>
>> I think this addresses all the reviews:
>>
>> * 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
>>
>> 2014-06-19  Phil Muldoon  <pmuldoon@redhat.com>
>>         Tom Tromey  <tromey@redhat.com>

> 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


^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 5/5] add libcc1
  2014-10-09  9:07       ` Phil Muldoon
@ 2014-10-09  9:12         ` Jakub Jelinek
  2014-10-09  9:18         ` Phil Muldoon
  2014-10-10 22:31         ` Jeff Law
  2 siblings, 0 replies; 71+ messages in thread
From: Jakub Jelinek @ 2014-10-09  9:12 UTC (permalink / raw)
  To: Phil Muldoon; +Cc: Jeff Law, Tom Tromey, tom, gcc-patches

On Thu, Oct 09, 2014 at 10:07:23AM +0100, Phil Muldoon wrote:
> >> 2014-06-19  Phil Muldoon  <pmuldoon@redhat.com>
> >>         Tom Tromey  <tromey@redhat.com>
> 
> > 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.

> > 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

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 5/5] add libcc1
  2014-07-31  4:49     ` Jeff Law
                         ` (2 preceding siblings ...)
  2014-08-05 19:34       ` Tom Tromey
@ 2014-10-09  9:07       ` Phil Muldoon
  2014-10-09  9:12         ` Jakub Jelinek
                           ` (2 more replies)
  3 siblings, 3 replies; 71+ messages in thread
From: Phil Muldoon @ 2014-10-09  9:07 UTC (permalink / raw)
  To: Jeff Law; +Cc: Tom Tromey, tom, gcc-patches

On 31/07/14 05:47, Jeff Law wrote:
> On 06/19/14 14:52, Tom Tromey wrote:
>> Here's a new version of patch #5.
>> I've removed the generated code; let's see if it gets through without
>> compression.
>>
>> I think this addresses all the reviews:
>>
>> * 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
>>
>> 2014-06-19  Phil Muldoon  <pmuldoon@redhat.com>
>>         Tom Tromey  <tromey@redhat.com>

> 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

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 5/5] add libcc1
  2014-07-31  4:49     ` Jeff Law
  2014-07-31  8:15       ` Richard Biener
  2014-07-31 21:14       ` Mike Stump
@ 2014-08-05 19:34       ` Tom Tromey
  2014-10-09  9:07       ` Phil Muldoon
  3 siblings, 0 replies; 71+ messages in thread
From: Tom Tromey @ 2014-08-05 19:34 UTC (permalink / raw)
  To: Jeff Law; +Cc: gcc-patches

>>>>> "Jeff" == Jeff Law <law@redhat.com> writes:

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

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 5/5] add libcc1
  2014-07-31 21:14       ` Mike Stump
@ 2014-08-04 14:23         ` Tom Tromey
  0 siblings, 0 replies; 71+ messages in thread
From: Tom Tromey @ 2014-08-04 14:23 UTC (permalink / raw)
  To: Mike Stump; +Cc: Jeff Law, gcc-patches

>>>>> "Mike" == Mike Stump <mikestump@comcast.net> writes:

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

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 5/5] add libcc1
  2014-07-31 20:07             ` Tom Tromey
@ 2014-08-01  2:18               ` Trevor Saunders
  0 siblings, 0 replies; 71+ messages in thread
From: Trevor Saunders @ 2014-08-01  2:18 UTC (permalink / raw)
  To: Tom Tromey; +Cc: Richard Biener, Jeff Law, GCC Patches

On Thu, Jul 31, 2014 at 01:51:45PM -0600, Tom Tromey wrote:
> >>>>> "Trevor" == Trevor Saunders <tsaunders@mozilla.com> writes:
> 
> 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.

> (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.

> 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

> 
> Tom

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 5/5] add libcc1
  2014-07-31  4:49     ` Jeff Law
  2014-07-31  8:15       ` Richard Biener
@ 2014-07-31 21:14       ` Mike Stump
  2014-08-04 14:23         ` Tom Tromey
  2014-08-05 19:34       ` Tom Tromey
  2014-10-09  9:07       ` Phil Muldoon
  3 siblings, 1 reply; 71+ messages in thread
From: Mike Stump @ 2014-07-31 21:14 UTC (permalink / raw)
  To: Jeff Law; +Cc: Tom Tromey, gcc-patches

On Jul 30, 2014, at 9:47 PM, Jeff Law <law@redhat.com> wrote:
> 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).

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 5/5] add libcc1
  2014-07-31 19:51           ` Trevor Saunders
@ 2014-07-31 20:07             ` Tom Tromey
  2014-08-01  2:18               ` Trevor Saunders
  0 siblings, 1 reply; 71+ messages in thread
From: Tom Tromey @ 2014-07-31 20:07 UTC (permalink / raw)
  To: Trevor Saunders; +Cc: Richard Biener, Jeff Law, GCC Patches

>>>>> "Trevor" == Trevor Saunders <tsaunders@mozilla.com> writes:

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

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 5/5] add libcc1
  2014-07-31 19:20         ` Tom Tromey
  2014-07-31 19:21           ` Jakub Jelinek
@ 2014-07-31 19:51           ` Trevor Saunders
  2014-07-31 20:07             ` Tom Tromey
  1 sibling, 1 reply; 71+ messages in thread
From: Trevor Saunders @ 2014-07-31 19:51 UTC (permalink / raw)
  To: Tom Tromey; +Cc: Richard Biener, Jeff Law, GCC Patches

On Thu, Jul 31, 2014 at 01:12:54PM -0600, Tom Tromey wrote:
> 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.

> 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

> 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

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 5/5] add libcc1
  2014-07-31 19:20         ` Tom Tromey
@ 2014-07-31 19:21           ` Jakub Jelinek
  2014-07-31 19:51           ` Trevor Saunders
  1 sibling, 0 replies; 71+ messages in thread
From: Jakub Jelinek @ 2014-07-31 19:21 UTC (permalink / raw)
  To: Tom Tromey; +Cc: Richard Biener, Jeff Law, GCC Patches

On Thu, Jul 31, 2014 at 01:12:54PM -0600, Tom Tromey wrote:
> 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

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 5/5] add libcc1
  2014-07-31  8:15       ` Richard Biener
  2014-07-31 10:53         ` Trevor Saunders
@ 2014-07-31 19:20         ` Tom Tromey
  2014-07-31 19:21           ` Jakub Jelinek
  2014-07-31 19:51           ` Trevor Saunders
  1 sibling, 2 replies; 71+ messages in thread
From: Tom Tromey @ 2014-07-31 19:20 UTC (permalink / raw)
  To: Richard Biener; +Cc: Jeff Law, GCC Patches

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

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 5/5] add libcc1
  2014-07-31 11:28           ` Richard Biener
@ 2014-07-31 15:08             ` Joseph S. Myers
  0 siblings, 0 replies; 71+ messages in thread
From: Joseph S. Myers @ 2014-07-31 15:08 UTC (permalink / raw)
  To: Richard Biener; +Cc: Trevor Saunders, Jeff Law, Tom Tromey, GCC Patches

On Thu, 31 Jul 2014, Richard Biener wrote:

> 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
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 5/5] add libcc1
  2014-07-31 10:53         ` Trevor Saunders
@ 2014-07-31 11:28           ` Richard Biener
  2014-07-31 15:08             ` Joseph S. Myers
  0 siblings, 1 reply; 71+ messages in thread
From: Richard Biener @ 2014-07-31 11:28 UTC (permalink / raw)
  To: Trevor Saunders; +Cc: Jeff Law, Tom Tromey, GCC Patches

On Thu, Jul 31, 2014 at 12:44 PM, Trevor Saunders <tsaunders@mozilla.com> wrote:
> On Thu, Jul 31, 2014 at 10:01:15AM +0200, Richard Biener wrote:
>> On Thu, Jul 31, 2014 at 6:47 AM, Jeff Law <law@redhat.com> wrote:
>> > On 06/19/14 14:52, Tom Tromey wrote:
>> >>
>> >> 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.
>> >>
>> >> I think this addresses all the reviews:
>> >>
>> >> * 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
>> >>
>> >> 2014-06-19  Phil Muldoon  <pmuldoon@redhat.com>
>> >>             Tom Tromey  <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  <pmuldoon@redhat.com>
>> >>             Jan Kratochvil  <jan.kratochvil@redhat.com>
>> >>             Tom Tromey  <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.
>> >
>> > 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 ...

>> 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.
>
>> 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.

>> 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
>
>>
>> [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
>> >

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 5/5] add libcc1
  2014-07-31  8:15       ` Richard Biener
@ 2014-07-31 10:53         ` Trevor Saunders
  2014-07-31 11:28           ` Richard Biener
  2014-07-31 19:20         ` Tom Tromey
  1 sibling, 1 reply; 71+ messages in thread
From: Trevor Saunders @ 2014-07-31 10:53 UTC (permalink / raw)
  To: Richard Biener; +Cc: Jeff Law, Tom Tromey, GCC Patches

On Thu, Jul 31, 2014 at 10:01:15AM +0200, Richard Biener wrote:
> On Thu, Jul 31, 2014 at 6:47 AM, Jeff Law <law@redhat.com> wrote:
> > On 06/19/14 14:52, Tom Tromey wrote:
> >>
> >> 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.
> >>
> >> I think this addresses all the reviews:
> >>
> >> * 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
> >>
> >> 2014-06-19  Phil Muldoon  <pmuldoon@redhat.com>
> >>             Tom Tromey  <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  <pmuldoon@redhat.com>
> >>             Jan Kratochvil  <jan.kratochvil@redhat.com>
> >>             Tom Tromey  <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.
> >
> > 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.

> 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.

> 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

> 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

> 
> [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
> >

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 5/5] add libcc1
  2014-07-31  4:49     ` Jeff Law
@ 2014-07-31  8:15       ` Richard Biener
  2014-07-31 10:53         ` Trevor Saunders
  2014-07-31 19:20         ` Tom Tromey
  2014-07-31 21:14       ` Mike Stump
                         ` (2 subsequent siblings)
  3 siblings, 2 replies; 71+ messages in thread
From: Richard Biener @ 2014-07-31  8:15 UTC (permalink / raw)
  To: Jeff Law; +Cc: Tom Tromey, GCC Patches

On Thu, Jul 31, 2014 at 6:47 AM, Jeff Law <law@redhat.com> wrote:
> On 06/19/14 14:52, Tom Tromey wrote:
>>
>> 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.
>>
>> I think this addresses all the reviews:
>>
>> * 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
>>
>> 2014-06-19  Phil Muldoon  <pmuldoon@redhat.com>
>>             Tom Tromey  <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  <pmuldoon@redhat.com>
>>             Jan Kratochvil  <jan.kratochvil@redhat.com>
>>             Tom Tromey  <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.
>
> 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
>

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 5/5] add libcc1
  2014-06-19 20:52   ` Tom Tromey
                       ` (2 preceding siblings ...)
  2014-07-18 19:00     ` Tom Tromey
@ 2014-07-31  4:49     ` Jeff Law
  2014-07-31  8:15       ` Richard Biener
                         ` (3 more replies)
  3 siblings, 4 replies; 71+ messages in thread
From: Jeff Law @ 2014-07-31  4:49 UTC (permalink / raw)
  To: Tom Tromey, gcc-patches

On 06/19/14 14:52, Tom Tromey wrote:
> 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.
>
> I think this addresses all the reviews:
>
> * 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
>
> 2014-06-19  Phil Muldoon  <pmuldoon@redhat.com>
> 	    Tom Tromey  <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  <pmuldoon@redhat.com>
> 	    Jan Kratochvil  <jan.kratochvil@redhat.com>
> 	    Tom Tromey  <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.
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

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 5/5] add libcc1
  2014-06-19 20:52   ` Tom Tromey
  2014-06-19 21:45     ` Jakub Jelinek
  2014-06-20  3:11     ` Trevor Saunders
@ 2014-07-18 19:00     ` Tom Tromey
  2014-07-31  4:49     ` Jeff Law
  3 siblings, 0 replies; 71+ messages in thread
From: Tom Tromey @ 2014-07-18 19:00 UTC (permalink / raw)
  To: gcc-patches

>>>>> "Tom" == Tom Tromey <tromey@redhat.com> writes:

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  <pmuldoon@redhat.com>
	    Tom Tromey  <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  <pmuldoon@redhat.com>
	    Jan Kratochvil  <jan.kratochvil@redhat.com>
	    Tom Tromey  <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;
+}
+
+\f
+
+// 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);
+}
+
+\f
+
+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
+};
+
+\f
+
+// 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
+
+\f
+
+// 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);
+}
+
+\f
+
+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;
+}
+
+\f
+
+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;
+}
+
+\f
+
+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;
+  }
+};
+
+\f
+
+// 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;
+}
+
+\f
+
+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;
+
+\f
+
+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);
+}
+
+\f
+
+// 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);
+}
+
+\f
+
+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);
+}
+
+\f
+
+// 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

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 5/5] add libcc1
  2014-06-24 17:12             ` Tom Tromey
@ 2014-06-24 18:10               ` Trevor Saunders
  0 siblings, 0 replies; 71+ messages in thread
From: Trevor Saunders @ 2014-06-24 18:10 UTC (permalink / raw)
  To: Tom Tromey; +Cc: Jeff Law, gcc-patches

On Tue, Jun 24, 2014 at 11:12:38AM -0600, Tom Tromey wrote:
> 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.

> 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.

> 
> 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 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.

> 
> 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

> 
> Tom

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 5/5] add libcc1
  2014-06-24  3:13           ` Trevor Saunders
@ 2014-06-24 17:12             ` Tom Tromey
  2014-06-24 18:10               ` Trevor Saunders
  0 siblings, 1 reply; 71+ messages in thread
From: Tom Tromey @ 2014-06-24 17:12 UTC (permalink / raw)
  To: Trevor Saunders; +Cc: Jeff Law, gcc-patches

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

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 5/5] add libcc1
  2014-06-23 19:09         ` Jeff Law
@ 2014-06-24  3:13           ` Trevor Saunders
  2014-06-24 17:12             ` Tom Tromey
  0 siblings, 1 reply; 71+ messages in thread
From: Trevor Saunders @ 2014-06-24  3:13 UTC (permalink / raw)
  To: Jeff Law; +Cc: Tom Tromey, gcc-patches

On Mon, Jun 23, 2014 at 01:09:41PM -0600, Jeff Law wrote:
> On 06/20/14 09:33, Tom Tromey wrote:
> >>>>>>"Trevor" == Trevor Saunders <tsaunders@mozilla.com> writes:
> >
> >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.

> >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.

> >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

> 
> Jeff
> 

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 5/5] add libcc1
  2014-06-20 15:34       ` Tom Tromey
@ 2014-06-23 19:09         ` Jeff Law
  2014-06-24  3:13           ` Trevor Saunders
  0 siblings, 1 reply; 71+ messages in thread
From: Jeff Law @ 2014-06-23 19:09 UTC (permalink / raw)
  To: Tom Tromey, Trevor Saunders; +Cc: gcc-patches

On 06/20/14 09:33, Tom Tromey wrote:
>>>>>> "Trevor" == Trevor Saunders <tsaunders@mozilla.com> writes:
>
> 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

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 5/5] add libcc1
  2014-06-20  3:11     ` Trevor Saunders
@ 2014-06-20 15:34       ` Tom Tromey
  2014-06-23 19:09         ` Jeff Law
  0 siblings, 1 reply; 71+ messages in thread
From: Tom Tromey @ 2014-06-20 15:34 UTC (permalink / raw)
  To: Trevor Saunders; +Cc: gcc-patches

>>>>> "Trevor" == Trevor Saunders <tsaunders@mozilla.com> writes:

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.

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.

Trevor> I'm going to use this as an excuse to bring up something I've wanted to
Trevor> discuss for a while.

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.

Trevor> This question also arises in the case of templating splay_tree, and I
Trevor> imagine if gdb switches to C++ some day they'll want to reuse vec.h.

While I would like that to happen, I think the odds are very long now.

>> +    connection (int fd)
>> +      : m_fd (fd),
>> +	m_aux_fd (-1),
>> +	m_callbacks ()

Trevor>  Personally I'd leave that to the compiler to write, but I guess there's
Trevor>  something to be said for being explicit.

I can't recall if I did this in response to a warning or if it was just
because I wanted to be explicit.

I'm inclined to leave it, but I suppose only out of inertia.

>> +  void print (const char *buf)

Trevor> explicitly mark it as virtual?

Good idea, done.

>> +// 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.
>> +gcc_address

Trevor> looks like this one probably is used?

Thanks, fixed.

>> +  char **argv = new (std::nothrow) char *[self->args.size () + 1];

Trevor> What's the point of making this no throw? you don't null check it so
Trevor> you'll crash anyway afaict.

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.

>> +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];

Trevor> It'd be really nice if the type of the out arg forced the caller to deal
Trevor> with deleting the string like unique_ptr<char>, it would be even nicer
Trevor> if you could stick a random buffer in a std::string, but I guess you
Trevor> can't :(

Yeah, it's all quite simplistic.  I suppose it could be upgraded, there
just didn't seem to be a need.

Trevor> Also where does this array get deleted?

The unmarshalling methods are generally called via argument_wrappers.
An example is in connection.cc:

		// 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;

Then in rpc.hh:

  // Specialization for string types.
  template<>
  class argument_wrapper<const char *>
  {
  public:
    argument_wrapper () : m_object (NULL) { }
    ~argument_wrapper ()
    {
      delete[] m_object;
    }

Tom

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 5/5] add libcc1
  2014-06-19 20:52   ` Tom Tromey
  2014-06-19 21:45     ` Jakub Jelinek
@ 2014-06-20  3:11     ` Trevor Saunders
  2014-06-20 15:34       ` Tom Tromey
  2014-07-18 19:00     ` Tom Tromey
  2014-07-31  4:49     ` Jeff Law
  3 siblings, 1 reply; 71+ messages in thread
From: Trevor Saunders @ 2014-06-20  3:11 UTC (permalink / raw)
  To: Tom Tromey; +Cc: gcc-patches

[-- Attachment #1: Type: text/plain, Size: 101759 bytes --]

Hi,

I'm curious, what is the reason you choose not to write this in C++11 or
later?  Its distributed with gcc, so the only case where you aren't
building with the in tree compiler and libraries is when your cross
compiling gcc, and it doesn't seem particularly important to support
building the plugin or library in that configuration.  So istm you could
go all the way and assume you are being built with trunk gcc and
libraries.

Some more comments inline.

On Thu, Jun 19, 2014 at 02:52:12PM -0600, Tom Tromey wrote:
> 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.
> 
> I think this addresses all the reviews:
> 
> * 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
> 
> 2014-06-19  Phil Muldoon  <pmuldoon@redhat.com>
> 	    Tom Tromey  <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  <pmuldoon@redhat.com>
> 	    Jan Kratochvil  <jan.kratochvil@redhat.com>
> 	    Tom Tromey  <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.
> 
> ---
>  ChangeLog                    |     7 +
>  Makefile.def                 |     5 +
>  Makefile.in                  |   997 ++-
>  configure                    |     2 +-
>  configure.ac                 |     4 +-
>  libcc1/ChangeLog             |    26 +
>  libcc1/Makefile.am           |    52 +
>  libcc1/Makefile.in           |   627 ++
>  libcc1/aclocal.m4            |   981 +++
>  libcc1/callbacks.cc          |    90 +
>  libcc1/callbacks.hh          |    64 +
>  libcc1/cc1plugin-config.h.in |    92 +
>  libcc1/configure             | 17176 +++++++++++++++++++++++++++++++++++++++++
>  libcc1/configure.ac          |    73 +
>  libcc1/connection.cc         |   153 +
>  libcc1/connection.hh         |   114 +
>  libcc1/findcomp.cc           |   139 +
>  libcc1/findcomp.hh           |    25 +
>  libcc1/libcc1.cc             |   529 ++
>  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             |   922 +++
>  libcc1/rpc.hh                |   486 ++
>  libcc1/status.hh             |    33 +
>  28 files changed, 22952 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/findcomp.cc
>  create mode 100644 libcc1/findcomp.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
> 
> 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..574557a
> --- /dev/null
> +++ b/libcc1/Makefile.am
> @@ -0,0 +1,52 @@
> +## 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)
> +
> +
> +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)
> +
> +libcc1_la_LDFLAGS = -module -export-symbols $(srcdir)/libcc1.sym
> +libcc1_la_SOURCES = findcomp.cc libcc1.cc names.cc names.hh $(shared_source)
> 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

I'm going to use this as an excuse to bring up something I've wanted to
discuss for a while.  This class is yet another wrapper around htab.  It
sort of makes sense to do this because hash_table and pointer_map both
rely on code only in gcc.  istm the basic problem here is that gcc/ now
has C++ified data structures that are better than those in libiberty,
but it would be useful to be able to use them outside of gcc/ here, and
in libcpp at least.  So can we add C++ stuff to libiberty and allow
building libiberty without it for binutils / gdb, or can we do something
else to avoid this kind of stuff?

This question also arises in the case of templating splay_tree, and I
imagine if gdb switches to C++ some day they'll want to reuse vec.h.

> +  {
> +  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 ()

 Personally I'd leave that to the compiler to write, but I guess there's
 something to be said for being explicit.

> +    {
> +    }
> +
> +    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..7d3b9fe
> --- /dev/null
> +++ b/libcc1/libcc1.cc
> @@ -0,0 +1,529 @@
> +/* 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)
> +  {
> +  }
> +
> +  void print (const char *buf)

explicitly mark it as virtual?

> +  {
> +    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;
> +}
> +
> +\f
> +
> +// 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.  Note that the
> +// return value is not used; the type cannot be 'void' due to
> +// limitations in our simple RPC.
> +gcc_address

looks like this one probably is used?

> +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);
> +}
> +
> +\f
> +
> +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
> +};
> +
> +\f
> +
> +// 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];

What's the point of making this no throw? you don't null check it so
you'll crash anyway afaict.

> +  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];
It'd be really nice if the type of the out arg forced the caller to deal
with deleting the string like unique_ptr<char>, it would be even nicer
if you could stick a random buffer in a std::string, but I guess you
can't :(

Also where does this array get deleted?

> +  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..965e803
> --- /dev/null
> +++ b/libcc1/plugin.cc
> @@ -0,0 +1,922 @@
> +/* Library interface to C front end
> +   Copyright (C) 2014 Free Software Foundation, Inc.
> +
> +   Parser actions based on the old Bison parser; structure somewhat
> +   influenced by and fragments based on the C++ parser.
> +
> +   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
> +
> +\f
> +
> +// 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);
> +}
> +
> +\f
> +
> +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;
> +}
> +
> +\f
> +
> +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;
> +}
> +
> +\f
> +
> +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;
> +  }
> +};
> +
> +\f
> +
> +// 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;
> +}
> +
> +\f
> +
> +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;
> +
> +\f
> +
> +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);
> +}
> +
> +\f
> +
> +// 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);
> +}
> +
> +\f
> +
> +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);
> +}
> +
> +\f
> +
> +// 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
> -- 
> 1.9.3
> 

Trev


[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 5/5] add libcc1
  2014-06-19 21:45     ` Jakub Jelinek
@ 2014-06-19 22:22       ` Tom Tromey
  0 siblings, 0 replies; 71+ messages in thread
From: Tom Tromey @ 2014-06-19 22:22 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: gcc-patches

>>>>> "Jakub" == Jakub Jelinek <jakub@redhat.com> writes:

Jakub> If you plan to implement this for other frontends (cc1plus,
Jakub> f951?) in the future, would that be still libcc1 and perhaps new
Jakub> plugins in there, or are we going to have new toplevel
Jakub> directories for each such a plugin?

We're planning to do this for g++ but, as far as I know, not anything
else.  I was planning to put the C++ plugin into this same directory, as
I expect it to share a reasonable amount of code with the C plugin -- at
least all the RPC stuff.

Tom

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 5/5] add libcc1
  2014-06-19 20:52   ` Tom Tromey
@ 2014-06-19 21:45     ` Jakub Jelinek
  2014-06-19 22:22       ` Tom Tromey
  2014-06-20  3:11     ` Trevor Saunders
                       ` (2 subsequent siblings)
  3 siblings, 1 reply; 71+ messages in thread
From: Jakub Jelinek @ 2014-06-19 21:45 UTC (permalink / raw)
  To: Tom Tromey; +Cc: gcc-patches

On Thu, Jun 19, 2014 at 02:52:12PM -0600, Tom Tromey wrote:
> 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.
> 
> I think this addresses all the reviews:
> 
> * 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.

If you plan to implement this for other frontends (cc1plus, f951?) in the
future, would that be still libcc1 and perhaps new plugins in there, or are
we going to have new toplevel directories for each such a plugin?

	Jakub

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 5/5] add libcc1
  2014-05-16 18:48 ` [PATCH 5/5] add libcc1 Tom Tromey
                     ` (2 preceding siblings ...)
  2014-05-16 22:17   ` Mike Stump
@ 2014-06-19 20:52   ` Tom Tromey
  2014-06-19 21:45     ` Jakub Jelinek
                       ` (3 more replies)
  3 siblings, 4 replies; 71+ messages in thread
From: Tom Tromey @ 2014-06-19 20:52 UTC (permalink / raw)
  To: gcc-patches

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.

I think this addresses all the reviews:

* 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

2014-06-19  Phil Muldoon  <pmuldoon@redhat.com>
	    Tom Tromey  <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  <pmuldoon@redhat.com>
	    Jan Kratochvil  <jan.kratochvil@redhat.com>
	    Tom Tromey  <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.

---
 ChangeLog                    |     7 +
 Makefile.def                 |     5 +
 Makefile.in                  |   997 ++-
 configure                    |     2 +-
 configure.ac                 |     4 +-
 libcc1/ChangeLog             |    26 +
 libcc1/Makefile.am           |    52 +
 libcc1/Makefile.in           |   627 ++
 libcc1/aclocal.m4            |   981 +++
 libcc1/callbacks.cc          |    90 +
 libcc1/callbacks.hh          |    64 +
 libcc1/cc1plugin-config.h.in |    92 +
 libcc1/configure             | 17176 +++++++++++++++++++++++++++++++++++++++++
 libcc1/configure.ac          |    73 +
 libcc1/connection.cc         |   153 +
 libcc1/connection.hh         |   114 +
 libcc1/findcomp.cc           |   139 +
 libcc1/findcomp.hh           |    25 +
 libcc1/libcc1.cc             |   529 ++
 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             |   922 +++
 libcc1/rpc.hh                |   486 ++
 libcc1/status.hh             |    33 +
 28 files changed, 22952 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/findcomp.cc
 create mode 100644 libcc1/findcomp.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

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..574557a
--- /dev/null
+++ b/libcc1/Makefile.am
@@ -0,0 +1,52 @@
+## 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)
+
+
+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)
+
+libcc1_la_LDFLAGS = -module -export-symbols $(srcdir)/libcc1.sym
+libcc1_la_SOURCES = findcomp.cc libcc1.cc names.cc names.hh $(shared_source)
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..7d3b9fe
--- /dev/null
+++ b/libcc1/libcc1.cc
@@ -0,0 +1,529 @@
+/* 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)
+  {
+  }
+
+  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;
+}
+
+\f
+
+// 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.  Note that the
+// return value is not used; the type cannot be 'void' due to
+// limitations in our simple RPC.
+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);
+}
+
+\f
+
+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
+};
+
+\f
+
+// 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];
+  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..965e803
--- /dev/null
+++ b/libcc1/plugin.cc
@@ -0,0 +1,922 @@
+/* Library interface to C front end
+   Copyright (C) 2014 Free Software Foundation, Inc.
+
+   Parser actions based on the old Bison parser; structure somewhat
+   influenced by and fragments based on the C++ parser.
+
+   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
+
+\f
+
+// 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);
+}
+
+\f
+
+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;
+}
+
+\f
+
+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;
+}
+
+\f
+
+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;
+  }
+};
+
+\f
+
+// 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;
+}
+
+\f
+
+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;
+
+\f
+
+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);
+}
+
+\f
+
+// 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);
+}
+
+\f
+
+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);
+}
+
+\f
+
+// 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
-- 
1.9.3

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 5/5] add libcc1
  2014-05-16 20:29   ` Joseph S. Myers
  2014-05-16 21:03     ` Tom Tromey
  2014-06-18 21:07     ` Tom Tromey
@ 2014-06-19 20:47     ` Tom Tromey
  2 siblings, 0 replies; 71+ messages in thread
From: Tom Tromey @ 2014-06-19 20:47 UTC (permalink / raw)
  To: Joseph S. Myers; +Cc: gcc-patches

Joseph> I don't see anything obvious that would disable the plugin if
Joseph> plugins are unsupported (e.g. on Windows host) or disabled
Joseph> (--disable-plugin).  Probably the relevant support from
Joseph> gcc/configure.ac needs to go somewhere it can be used at
Joseph> toplevel.

Here's the patch to pull this out to a separate file.
I've omitted generated code from this mail.

Tom

b/config/ChangeLog:
2014-06-19  Tom Tromey  <tromey@redhat.com>

	* gcc-plugin.m4: New file.

b/gcc/ChangeLog:
2014-06-19  Tom Tromey  <tromey@redhat.com>

	* aclocal.m4, configure: Rebuild.
	* Makefile.in (aclocal_deps): Add gcc-plugin.m4.
	* configure.ac: Use GCC_ENABLE_PLUGINS.

---
 config/ChangeLog     |   4 ++
 config/gcc-plugin.m4 | 113 +++++++++++++++++++++++++++++++++
 gcc/ChangeLog        |   6 ++
 gcc/Makefile.in      |   1 +
 gcc/aclocal.m4       |  89 +-------------------------
 gcc/configure        | 172 +++++++++++++++++++++++++--------------------------
 gcc/configure.ac     | 100 +-----------------------------
 7 files changed, 212 insertions(+), 273 deletions(-)
 create mode 100644 config/gcc-plugin.m4

diff --git a/config/gcc-plugin.m4 b/config/gcc-plugin.m4
new file mode 100644
index 0000000..dd06a58
--- /dev/null
+++ b/config/gcc-plugin.m4
@@ -0,0 +1,113 @@
+# gcc-plugin.m4 -*- Autoconf -*-
+# Check whether GCC is able to be built with plugin support.
+
+dnl Copyright (C) 2014 Free Software Foundation, Inc.
+dnl This file is free software, distributed under the terms of the GNU
+dnl General Public License.  As a special exception to the GNU General
+dnl Public License, this file may be distributed as part of a program
+dnl that contains a configuration script generated by Autoconf, under
+dnl the same distribution terms as the rest of that program.
+
+# Check for plugin support.
+# Respects --enable-plugin.
+# Sets the shell variables enable_plugin and pluginlibs.
+AC_DEFUN([GCC_ENABLE_PLUGINS],
+  [# Check for plugin support
+   AC_ARG_ENABLE(plugin,
+   [AS_HELP_STRING([--enable-plugin], [enable plugin support])],
+   enable_plugin=$enableval,
+   enable_plugin=yes; default_plugin=yes)
+
+   pluginlibs=
+
+   case "${host}" in
+     *-*-darwin*)
+       if test x$build = x$host; then
+	 export_sym_check="nm${exeext} -g"
+       elif test x$host = x$target; then
+	 export_sym_check="$gcc_cv_nm -g"
+       else
+	 export_sym_check=
+       fi
+     ;;
+     *)
+       if test x$build = x$host; then
+	 export_sym_check="objdump${exeext} -T"
+       elif test x$host = x$target; then
+	 export_sym_check="$gcc_cv_objdump -T"
+       else
+	 export_sym_check=
+       fi
+     ;;
+   esac
+
+   if test x"$enable_plugin" = x"yes"; then
+
+     AC_MSG_CHECKING([for exported symbols])
+     if test "x$export_sym_check" != x; then
+       echo "int main() {return 0;} int foobar() {return 0;}" > conftest.c
+       ${CC} ${CFLAGS} ${LDFLAGS} conftest.c -o conftest$ac_exeext > /dev/null 2>&1
+       if $export_sym_check conftest$ac_exeext | grep -q foobar > /dev/null; then
+	 : # No need to use a flag
+	 AC_MSG_RESULT([yes])
+       else
+	 AC_MSG_RESULT([yes])
+	 AC_MSG_CHECKING([for -rdynamic])
+	 ${CC} ${CFLAGS} ${LDFLAGS} -rdynamic conftest.c -o conftest$ac_exeext > /dev/null 2>&1
+	 if $export_sym_check conftest$ac_exeext | grep -q foobar > /dev/null; then
+	   plugin_rdynamic=yes
+	   pluginlibs="-rdynamic"
+	 else
+	   plugin_rdynamic=no
+	   enable_plugin=no
+	 fi
+	 AC_MSG_RESULT([$plugin_rdynamic])
+       fi
+     else
+       AC_MSG_RESULT([unable to check])
+     fi
+
+     # Check -ldl
+     saved_LIBS="$LIBS"
+     AC_SEARCH_LIBS([dlopen], [dl])
+     if test x"$ac_cv_search_dlopen" = x"-ldl"; then
+       pluginlibs="$pluginlibs -ldl"
+     fi
+     LIBS="$saved_LIBS"
+
+     # Check that we can build shared objects with -fPIC -shared
+     saved_LDFLAGS="$LDFLAGS"
+     saved_CFLAGS="$CFLAGS"
+     case "${host}" in
+       *-*-darwin*)
+	 CFLAGS=`echo $CFLAGS | sed s/-mdynamic-no-pic//g`
+	 CFLAGS="$CFLAGS -fPIC"
+	 LDFLAGS="$LDFLAGS -shared -undefined dynamic_lookup"
+       ;;
+       *)
+	 CFLAGS="$CFLAGS -fPIC"
+	 LDFLAGS="$LDFLAGS -fPIC -shared"
+       ;;
+     esac
+     AC_MSG_CHECKING([for -fPIC -shared])
+     AC_TRY_LINK(
+       [extern int X;],[return X == 0;],
+       [AC_MSG_RESULT([yes]); have_pic_shared=yes],
+       [AC_MSG_RESULT([no]); have_pic_shared=no])
+     if test x"$have_pic_shared" != x"yes" -o x"$ac_cv_search_dlopen" = x"no"; then
+       pluginlibs=
+       enable_plugin=no
+     fi
+     LDFLAGS="$saved_LDFLAGS"
+     CFLAGS="$saved_CFLAGS"
+
+     # If plugin support had been requested but not available, fail.
+     if test x"$enable_plugin" = x"no" ; then
+       if test x"$default_plugin" != x"yes"; then
+	 AC_MSG_ERROR([
+   Building GCC with plugin support requires a host that supports
+   -fPIC, -shared, -ldl and -rdynamic.])
+       fi
+     fi
+   fi
+])
diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 5587b75..b17530a 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1672,6 +1672,7 @@ aclocal_deps = \
 	$(srcdir)/../config/codeset.m4 \
 	$(srcdir)/../config/extensions.m4 \
 	$(srcdir)/../config/gettext-sister.m4 \
+	$(srcdir)/../config/gcc-plugin.m4 \
 	$(srcdir)/../config/iconv.m4 \
 	$(srcdir)/../config/lcmessage.m4 \
 	$(srcdir)/../config/lib-ld.m4 \
diff --git a/gcc/configure.ac b/gcc/configure.ac
index a1cf901..b9eedc5 100644
--- a/gcc/configure.ac
+++ b/gcc/configure.ac
@@ -5443,105 +5443,7 @@ if test "x${CLOOGLIBS}" != "x" ; then
    AC_DEFINE(HAVE_cloog, 1, [Define if cloog is in use.])
 fi
 
-# Check for plugin support
-AC_ARG_ENABLE(plugin,
-[AS_HELP_STRING([--enable-plugin], [enable plugin support])],
-enable_plugin=$enableval,
-enable_plugin=yes; default_plugin=yes)
-
-pluginlibs=
-
-case "${host}" in
-  *-*-darwin*)
-    if test x$build = x$host; then
-      export_sym_check="nm${exeext} -g"
-    elif test x$host = x$target; then
-      export_sym_check="$gcc_cv_nm -g"
-    else
-      export_sym_check=
-    fi
-  ;;
-  *)
-    if test x$build = x$host; then
-      export_sym_check="objdump${exeext} -T"
-    elif test x$host = x$target; then
-      export_sym_check="$gcc_cv_objdump -T"
-    else
-      export_sym_check=
-    fi
-  ;;
-esac
-
-if test x"$enable_plugin" = x"yes"; then
-
-  AC_MSG_CHECKING([for exported symbols])
-  if test "x$export_sym_check" != x; then
-    echo "int main() {return 0;} int foobar() {return 0;}" > conftest.c
-    ${CC} ${CFLAGS} ${LDFLAGS} conftest.c -o conftest$ac_exeext > /dev/null 2>&1
-    if $export_sym_check conftest$ac_exeext | grep -q foobar > /dev/null; then
-      : # No need to use a flag
-      AC_MSG_RESULT([yes])
-    else
-      AC_MSG_RESULT([yes])
-      AC_MSG_CHECKING([for -rdynamic])
-      ${CC} ${CFLAGS} ${LDFLAGS} -rdynamic conftest.c -o conftest$ac_exeext > /dev/null 2>&1
-      if $export_sym_check conftest$ac_exeext | grep -q foobar > /dev/null; then
-        plugin_rdynamic=yes
-        pluginlibs="-rdynamic"
-      else
-        plugin_rdynamic=no
-        enable_plugin=no
-      fi
-      AC_MSG_RESULT([$plugin_rdynamic])
-    fi
-  else
-    AC_MSG_RESULT([unable to check])
-  fi
-
-  # Check -ldl
-  saved_LIBS="$LIBS"
-  AC_SEARCH_LIBS([dlopen], [dl])
-  if test x"$ac_cv_search_dlopen" = x"-ldl"; then
-    pluginlibs="$pluginlibs -ldl"
-  fi
-  LIBS="$saved_LIBS"
-
-  # Check that we can build shared objects with -fPIC -shared
-  saved_LDFLAGS="$LDFLAGS"
-  saved_CFLAGS="$CFLAGS"
-  case "${host}" in
-    *-*-darwin*)
-      CFLAGS=`echo $CFLAGS | sed s/-mdynamic-no-pic//g`
-      CFLAGS="$CFLAGS -fPIC"
-      LDFLAGS="$LDFLAGS -shared -undefined dynamic_lookup"
-    ;;
-    *)
-      CFLAGS="$CFLAGS -fPIC"
-      LDFLAGS="$LDFLAGS -fPIC -shared"
-    ;;
-  esac
-  AC_MSG_CHECKING([for -fPIC -shared])
-  AC_TRY_LINK(
-    [extern int X;],[return X == 0;],
-    [AC_MSG_RESULT([yes]); have_pic_shared=yes],
-    [AC_MSG_RESULT([no]); have_pic_shared=no])
-  if test x"$have_pic_shared" != x"yes" -o x"$ac_cv_search_dlopen" = x"no"; then
-    pluginlibs=
-    enable_plugin=no
-  fi
-  LDFLAGS="$saved_LDFLAGS"
-  CFLAGS="$saved_CFLAGS"
-
-  # If plugin support had been requested but not available, fail.
-  if test x"$enable_plugin" = x"no" ; then
-    if test x"$default_plugin" != x"yes"; then
-      AC_MSG_ERROR([
-Building GCC with plugin support requires a host that supports
--fPIC, -shared, -ldl and -rdynamic.])
-    fi
-  fi
-fi
-
+GCC_ENABLE_PLUGINS
 AC_SUBST(pluginlibs)
 AC_SUBST(enable_plugin)
 if test x"$enable_plugin" = x"yes"; then
-- 
1.9.3

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 5/5] add libcc1
  2014-05-16 20:29   ` Joseph S. Myers
  2014-05-16 21:03     ` Tom Tromey
@ 2014-06-18 21:07     ` Tom Tromey
  2014-06-19 20:47     ` Tom Tromey
  2 siblings, 0 replies; 71+ messages in thread
From: Tom Tromey @ 2014-06-18 21:07 UTC (permalink / raw)
  To: Joseph S. Myers; +Cc: gcc-patches

>>>>> "Joseph" == Joseph S Myers <joseph@codesourcery.com> writes:

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

Following up on your review.

Joseph> I don't see anything obvious that would disable the plugin if
Joseph> plugins are unsupported (e.g. on Windows host) or disabled
Joseph> (--disable-plugin).  Probably the relevant support from
Joseph> gcc/configure.ac needs to go somewhere it can be used at
Joseph> toplevel.

I've moved some relevant code to a new .m4 file in config and used it
from the plugin itself.  This seemed simpler than dealing with it at the
top level.  The plugin also self-disables if its configury needs are not
met.

Tom> +  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.  Though really the *versioned* driver
Joseph> $(target_noncanonical)-gcc-$(version) is the right one to use,

This turned out to be a pain :-) There are two basic problems.

First, gdb gets the names of its architectures from BFD, which doesn't
always use the same naming scheme as the GNU configury triplets.  It
does generally use the same names, but for x86 targets it differs quite
a bit.

Second, the configury triplets can vary in annoying ways that don't
really affect correct operation.  For example, "i586-" versus "i686-"
(there is a difference, but I think ignorable given the compiler flags
in the debuginfo, and anyway I suspect not discoverable by gdb); or
"-unknown-" versus "-pc-" (completely irrelevant AFAIK); or even
"x86_64-redhat-linux" versus "x86_64-unknown-linux-gnu" (seemingly
gratuitous).

In the end I added some code to gdb and to libcc1.so to construct a
regexp matching plausible results and then search $PATH for matches.
Which seems rather gross, but workable in reasonable scenarios.

I didn't try to apply the program transform name.  I suppose I could
apply it to the final "gcc" component of the name, though, without much
trouble.  I'll fix this up tomorrow.

Let me know if you have any issue with the above.  Barring that, I will
be resubmitting the series soon, most likely this week.

thanks,
Tom

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 5/5] add libcc1
  2014-06-05 19:34     ` Tom Tromey
@ 2014-06-05 21:35       ` Mike Stump
  0 siblings, 0 replies; 71+ messages in thread
From: Mike Stump @ 2014-06-05 21:35 UTC (permalink / raw)
  To: Tom Tromey; +Cc: gcc-patches

On Jun 5, 2014, at 12:34 PM, Tom Tromey <tromey@redhat.com> wrote:
> 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.

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 5/5] add libcc1
  2014-05-16 22:17   ` Mike Stump
@ 2014-06-05 19:34     ` Tom Tromey
  2014-06-05 21:35       ` Mike Stump
  0 siblings, 1 reply; 71+ messages in thread
From: Tom Tromey @ 2014-06-05 19:34 UTC (permalink / raw)
  To: Mike Stump; +Cc: gcc-patches

>>>>> "Mike" == Mike Stump <mikestump@comcast.net> writes:

Mike> On May 16, 2014, at 11:48 AM, Tom Tromey <tromey@redhat.com> wrote:
>> 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

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 5/5] add libcc1
  2014-05-16 18:48 ` [PATCH 5/5] add libcc1 Tom Tromey
  2014-05-16 20:29   ` Joseph S. Myers
  2014-05-16 21:36   ` Mike Stump
@ 2014-05-16 22:17   ` Mike Stump
  2014-06-05 19:34     ` Tom Tromey
  2014-06-19 20:52   ` Tom Tromey
  3 siblings, 1 reply; 71+ messages in thread
From: Mike Stump @ 2014-05-16 22:17 UTC (permalink / raw)
  To: Tom Tromey; +Cc: gcc-patches

On May 16, 2014, at 11:48 AM, Tom Tromey <tromey@redhat.com> wrote:
> 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.

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 5/5] add libcc1
  2014-05-16 18:48 ` [PATCH 5/5] add libcc1 Tom Tromey
  2014-05-16 20:29   ` Joseph S. Myers
@ 2014-05-16 21:36   ` Mike Stump
  2014-05-16 22:17   ` Mike Stump
  2014-06-19 20:52   ` Tom Tromey
  3 siblings, 0 replies; 71+ messages in thread
From: Mike Stump @ 2014-05-16 21:36 UTC (permalink / raw)
  To: Tom Tromey; +Cc: gcc-patches

On May 16, 2014, at 11:48 AM, Tom Tromey <tromey@redhat.com> wrote:
> 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

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 5/5] add libcc1
  2014-05-16 20:29   ` Joseph S. Myers
@ 2014-05-16 21:03     ` Tom Tromey
  2014-06-18 21:07     ` Tom Tromey
  2014-06-19 20:47     ` Tom Tromey
  2 siblings, 0 replies; 71+ messages in thread
From: Tom Tromey @ 2014-05-16 21:03 UTC (permalink / raw)
  To: Joseph S. Myers; +Cc: gcc-patches

>>>>> "Joseph" == Joseph S Myers <joseph@codesourcery.com> writes:

>> +  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

^ permalink raw reply	[flat|nested] 71+ messages in thread

* Re: [PATCH 5/5] add libcc1
  2014-05-16 18:48 ` [PATCH 5/5] add libcc1 Tom Tromey
@ 2014-05-16 20:29   ` Joseph S. Myers
  2014-05-16 21:03     ` Tom Tromey
                       ` (2 more replies)
  2014-05-16 21:36   ` Mike Stump
                     ` (2 subsequent siblings)
  3 siblings, 3 replies; 71+ messages in thread
From: Joseph S. Myers @ 2014-05-16 20:29 UTC (permalink / raw)
  To: Tom Tromey; +Cc: gcc-patches

On Fri, 16 May 2014, Tom Tromey wrote:

> 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.

> +  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
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 71+ messages in thread

* [PATCH 5/5] add libcc1
  2014-05-16 15:26 [PATCH 0/5] let gdb reuse gcc'c C compiler Tom Tromey
@ 2014-05-16 18:48 ` Tom Tromey
  2014-05-16 20:29   ` Joseph S. Myers
                     ` (3 more replies)
  0 siblings, 4 replies; 71+ messages in thread
From: Tom Tromey @ 2014-05-16 18:48 UTC (permalink / raw)
  To: gcc-patches

[-- Attachment #1: Type: text/plain, Size: 4263 bytes --]

>>>>> "Tom" == Tom Tromey <tromey@redhat.com> writes:

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  <pmuldoon@redhat.com>
	    Tom Tromey  <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  <pmuldoon@redhat.com>
	    Jan Kratochvil  <jan.kratochvil@redhat.com>
	    Tom Tromey  <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


[-- Attachment #2: the patch --]
[-- Type: application/gzip, Size: 15988 bytes --]

^ permalink raw reply	[flat|nested] 71+ messages in thread

end of thread, other threads:[~2014-10-30 10:11 UTC | newest]

Thread overview: 71+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-10-28  3:19 [PATCH 5/5] add libcc1 Dominique Dhumieres
2014-10-28  8:36 ` Jakub Jelinek
2014-10-28  8:46   ` Phil Muldoon
2014-10-28  8:50     ` Christophe Lyon
2014-10-28  9:09     ` Jakub Jelinek
  -- strict thread matches above, loose matches on Subject: below --
2014-10-28  8:43 Uros Bizjak
2014-10-28  8:55 ` Phil Muldoon
2014-10-28  9:21   ` Uros Bizjak
2014-10-28  9:36 ` Jakub Jelinek
2014-10-28  9:58   ` Uros Bizjak
2014-10-28 10:51     ` Phil Muldoon
2014-10-28 10:56       ` Uros Bizjak
2014-10-28 11:16         ` Phil Muldoon
2014-10-28 11:53         ` Phil Muldoon
2014-10-28 12:24           ` Jakub Jelinek
2014-10-30  5:16             ` Jeff Law
2014-10-30  8:50             ` Thomas Schwinge
2014-10-30  8:56               ` Jakub Jelinek
2014-10-30 10:43                 ` Thomas Schwinge
2014-05-16 15:26 [PATCH 0/5] let gdb reuse gcc'c C compiler Tom Tromey
2014-05-16 18:48 ` [PATCH 5/5] add libcc1 Tom Tromey
2014-05-16 20:29   ` Joseph S. Myers
2014-05-16 21:03     ` Tom Tromey
2014-06-18 21:07     ` Tom Tromey
2014-06-19 20:47     ` Tom Tromey
2014-05-16 21:36   ` Mike Stump
2014-05-16 22:17   ` Mike Stump
2014-06-05 19:34     ` Tom Tromey
2014-06-05 21:35       ` Mike Stump
2014-06-19 20:52   ` Tom Tromey
2014-06-19 21:45     ` Jakub Jelinek
2014-06-19 22:22       ` Tom Tromey
2014-06-20  3:11     ` Trevor Saunders
2014-06-20 15:34       ` Tom Tromey
2014-06-23 19:09         ` Jeff Law
2014-06-24  3:13           ` Trevor Saunders
2014-06-24 17:12             ` Tom Tromey
2014-06-24 18:10               ` Trevor Saunders
2014-07-18 19:00     ` Tom Tromey
2014-07-31  4:49     ` Jeff Law
2014-07-31  8:15       ` Richard Biener
2014-07-31 10:53         ` Trevor Saunders
2014-07-31 11:28           ` Richard Biener
2014-07-31 15:08             ` Joseph S. Myers
2014-07-31 19:20         ` Tom Tromey
2014-07-31 19:21           ` Jakub Jelinek
2014-07-31 19:51           ` Trevor Saunders
2014-07-31 20:07             ` Tom Tromey
2014-08-01  2:18               ` Trevor Saunders
2014-07-31 21:14       ` Mike Stump
2014-08-04 14:23         ` Tom Tromey
2014-08-05 19:34       ` Tom Tromey
2014-10-09  9:07       ` Phil Muldoon
2014-10-09  9:12         ` Jakub Jelinek
2014-10-09  9:18         ` Phil Muldoon
2014-10-10 22:31         ` Jeff Law
2014-10-24  7:43           ` Phil Muldoon
2014-10-24  7:53             ` Jakub Jelinek
2014-10-24 16:47             ` Jeff Law
2014-10-27 20:03               ` Phil Muldoon
2014-10-28 13:29                 ` Joseph S. Myers
2014-10-28 18:00                   ` Phil Muldoon
2014-10-29  3:32                     ` Joseph S. Myers
2014-10-29 10:29                     ` Jakub Jelinek
2014-10-29 10:45                       ` Paolo Bonzini
2014-10-29 10:58                         ` Jakub Jelinek
2014-10-29 10:59                           ` Paolo Bonzini
2014-10-29 11:03                             ` Jakub Jelinek
2014-10-29 15:00                               ` Paolo Bonzini
2014-10-29 11:10                             ` Phil Muldoon
2014-10-29 11:42                             ` Phil Muldoon
2014-10-30  5:37                       ` Jeff Law

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).