This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[RFC] Initial pass at supporting the Go language


Hi.

This patch is a first pass at supporting the Go language.
There's still lots to do, but this is a start.

I have a few things I'd like to clean up before checking in
but I don't plan on removing all FIXMEs.
And I still need to document Go specific features.

I also have a board file for running the testsuite with the 6g compiler.
I'll submit that separately.

2011-12-28  Doug Evans  <dje@google.com>

	Initial pass at Go language support.
	* NEWS: Mention Go.
	* Makefile.in (SFILES): Add go-exp.y, go-lang.c, go-typeprint.c,
	go-valprint.c.
	(COMMON_OBS): Add go-lang.o, go-val.print.o, go-typeprint.o.
	(YYFILES): Add go-exp.c.
	(YYOBJ): Add go-exp.o.
	(local-maintainer-clean): Delete go-exp.c.
	* defs.h (enum language): Add language_go.
	* dwarf2read.c: #include "go-lang.h".
	(fixup_go_packaging): New function.
	(process_full_comp_unit): Call it when processing Go CUs.
	(dwarf2_physname): Add Go support.
	(read_file_scope): Handle missing language spec for GNU Go.
	(set_cu_language): Handle DW_LANG_Go.
	* go-exp.y: New file.
	* go-lang.h: New file.
	* go-lang.c: New file.
	* go-typeprint.c: New file.
	* go-valprint.c: New file.
	* symtab.c: #include "go-lang.h".
	(symbol_set_language): Handle language_go.
	(symbol_find_demangled_name, symbol_set_names): Ditto.
	(symbol_natural_name, demangle_for_lookup, find_main_name): Ditto.

	testsuite/
	* configure.ac: Create gdb.go/Makefile.
	* configure: Regenerate.
	* gdb.base/default.exp: Add "go" to "set language" testing.
	* gdb.go/Makefile.in: New file.
	* gdb.go/basic-types.exp: New file.
	* gdb.go/chan.exp: New file.
	* gdb.go/chan.go: New file.
	* gdb.go/handcall.exp: New file.
	* gdb.go/handcall.go: New file.
	* gdb.go/hello.exp: New file.
	* gdb.go/hello.go: New file.
	* gdb.go/integers.exp: New file.
	* gdb.go/integers.go: New file.
	* gdb.go/methods.exp: New file.
	* gdb.go/methods.go: New file.
	* gdb.go/package.exp: New file.
	* gdb.go/package1.go: New file.
	* gdb.go/package2.go: New file.
	* gdb.go/print.exp: New file.
	* gdb.go/strings.exp: New file.
	* gdb.go/strings.go: New file.
	* gdb.go/types.exp: New file.
	* gdb.go/types.go: New file.
	* gdb.go/unsafe.exp: New file.
	* gdb.go/unsafe.go: New file.
	* lib/future.exp: Add Go support.
	(gdb_find_go, gdb_find_go_linker): New procs.
	(gdb_default_target_compile): Add Go support.
	* lib/gdb.exp (skip_go_tests): New proc.
	* lib/go.exp: New file.

	doc/
	* gdb.texinfo (Supported Languages): Add Go.
	(Go): New node.

Index: Makefile.in
===================================================================
RCS file: /cvs/src/src/gdb/Makefile.in,v
retrieving revision 1.1180
diff -u -p -r1.1180 Makefile.in
--- Makefile.in	23 Dec 2011 17:06:10 -0000	1.1180
+++ Makefile.in	28 Dec 2011 20:50:30 -0000
@@ -711,6 +711,7 @@ SFILES = ada-exp.y ada-lang.c ada-typepr
 	f-exp.y f-lang.c f-typeprint.c f-valprint.c filesystem.c \
 	findcmd.c findvar.c frame.c frame-base.c frame-unwind.c \
 	gdbarch.c arch-utils.c gdbtypes.c gnu-v2-abi.c gnu-v3-abi.c \
+	go-exp.y go-lang.c go-typeprint.c go-valprint.c \
 	inf-loop.c \
 	infcall.c \
 	infcmd.c inflow.c infrun.c \
@@ -790,6 +791,7 @@ ser-unix.h inf-ptrace.h terminal.h ui-ou
 f-lang.h dwarf2loc.h value.h sparc-tdep.h defs.h target-descriptions.h \
 objfiles.h vec.h disasm.h mips-tdep.h ser-base.h \
 gdb_curses.h bfd-target.h memattr.h inferior.h ax.h dummy-frame.h \
+go-lang.h \
 inflow.h fbsd-nat.h libunwind-frame.h completer.h inf-ttrace.h \
 solib-target.h gdb_vfork.h alpha-tdep.h dwarf2expr.h \
 m2-lang.h stack.h charset.h addrmap.h command.h solist.h source.h \
@@ -895,6 +897,7 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $
 	ada-tasks.o \
 	ui-out.o cli-out.o \
 	varobj.o vec.o wrapper.o \
+	go-lang.o go-valprint.o go-typeprint.o \
 	jv-lang.o jv-valprint.o jv-typeprint.o \
 	m2-lang.o opencl-lang.o p-lang.o p-typeprint.o p-valprint.o \
 	sentinel-frame.o \
@@ -939,13 +942,13 @@ YYFILES = c-exp.c \
 	ada-lex.c \
 	ada-exp.c \
 	jv-exp.c \
-	f-exp.c m2-exp.c p-exp.c
+	f-exp.c go-exp.c m2-exp.c p-exp.c
 YYOBJ = c-exp.o \
 	cp-name-parser.o \
 	objc-exp.o \
 	ada-exp.o \
 	jv-exp.o \
-	f-exp.o m2-exp.o p-exp.o
+	f-exp.o go-exp.o m2-exp.o p-exp.o
 
 # Things which need to be built when making a distribution.
 
@@ -1285,7 +1288,7 @@ local-maintainer-clean:
 		ada-lex.c ada-exp.c \
 	        objc-exp.c \
 		jv-exp.tab \
-		f-exp.c m2-exp.c p-exp.c
+		f-exp.c go-exp.c m2-exp.c p-exp.c
 	rm -f TAGS $(INFOFILES)
 	rm -f $(YYFILES)
 	rm -f nm.h config.status
Index: NEWS
===================================================================
RCS file: /cvs/src/src/gdb/NEWS,v
retrieving revision 1.477
diff -u -p -r1.477 NEWS
--- NEWS	23 Dec 2011 17:06:10 -0000	1.477
+++ NEWS	28 Dec 2011 20:50:30 -0000
@@ -3,6 +3,10 @@
 
 *** Changes since GDB 7.4
 
+* Go language support.
+  GDB now supports debugging programs written in the Go programming
+  language.
+
 * GDBserver now supports stdio connections.
   E.g. (gdb) target remote | ssh myhost gdbserver - hello
 
Index: defs.h
===================================================================
RCS file: /cvs/src/src/gdb/defs.h,v
retrieving revision 1.307
diff -u -p -r1.307 defs.h
--- defs.h	14 Dec 2011 20:53:56 -0000	1.307
+++ defs.h	28 Dec 2011 20:50:30 -0000
@@ -198,6 +198,7 @@ enum language
     language_c,			/* C */
     language_cplus,		/* C++ */
     language_d,			/* D */
+    language_go,		/* Go */
     language_objc,		/* Objective-C */
     language_java,		/* Java */
     language_fortran,		/* Fortran */
Index: dwarf2read.c
===================================================================
RCS file: /cvs/src/src/gdb/dwarf2read.c,v
retrieving revision 1.588
diff -u -p -r1.588 dwarf2read.c
--- dwarf2read.c	27 Dec 2011 23:41:59 -0000	1.588
+++ dwarf2read.c	28 Dec 2011 20:50:31 -0000
@@ -57,6 +57,7 @@
 #include "completer.h"
 #include "vec.h"
 #include "c-lang.h"
+#include "go-lang.h"
 #include "valprint.h"
 #include <ctype.h>
 
@@ -4836,6 +4837,78 @@ compute_delayed_physnames (struct dwarf2
     }
 }
 
+/* Go objects should be embedded in a DW_TAG_module DIE,
+   and it's not clear if/how imported objects will appear.
+   To keep Go support simple until that's worked out,
+   go back through what we've read and create something usable.
+   We could do this while processing each DIE, and feels kinda cleaner,
+   but that way is more invasive.
+   This is to, for example, allow the user to type "p var" or "b main"
+   without having to specify the package name, and allow lookups
+   of module.object to work in contexts that use the expression
+   parser.  */
+
+static void
+fixup_go_packaging (struct dwarf2_cu *cu)
+{
+  char *package_name = NULL;
+  struct pending *list;
+  int i;
+
+  for (list = global_symbols; list != NULL; list = list->next)
+    {
+      for (i = 0; i < list->nsyms; ++i)
+	{
+	  struct symbol *sym = list->symbol[i];
+
+	  if (SYMBOL_LANGUAGE (sym) == language_go
+	      && SYMBOL_CLASS (sym) == LOC_BLOCK)
+	    {
+	      char *this_package_name = go_symbol_package_name (sym);
+
+	      if (this_package_name == NULL)
+		continue;
+	      if (package_name == NULL)
+		package_name = this_package_name;
+	      else
+		{
+		  if (strcmp (package_name, this_package_name) != 0)
+		    complaint (&symfile_complaints,
+			       _("Symtab %s has objects from two different Go packages: %s and %s"),
+			       (sym->symtab && sym->symtab->filename
+				? sym->symtab->filename
+				: cu->objfile->name),
+			       this_package_name, package_name);
+		  xfree (this_package_name);
+		}
+	    }
+	}
+    }
+
+  if (package_name != NULL)
+    {
+      struct objfile *objfile = cu->objfile;
+      struct type *type = init_type (TYPE_CODE_MODULE, 0, 0,
+				     package_name, objfile);
+      struct symbol *sym;
+
+      TYPE_TAG_NAME (type) = TYPE_NAME (type);
+
+      sym = OBSTACK_ZALLOC (&objfile->objfile_obstack, struct symbol);
+      SYMBOL_SET_LANGUAGE (sym, language_go);
+      SYMBOL_SET_NAMES (sym, package_name, strlen (package_name), 1, objfile);
+      /* This is not VAR_DOMAIN because we want a way to ensure a lookup of,
+	 e.g., "main" finds the "main" module and not C's main().  */
+      SYMBOL_DOMAIN (sym) = STRUCT_DOMAIN;
+      SYMBOL_CLASS (sym) = LOC_TYPEDEF;
+      SYMBOL_TYPE (sym) = type;
+
+      add_symbol_to_list (sym, &global_symbols);
+
+      xfree (package_name);
+    }
+}
+
 /* Generate full symbol information for PST and CU, whose DIEs have
    already been loaded into memory.  */
 
@@ -4860,6 +4933,10 @@ process_full_comp_unit (struct dwarf2_pe
   /* Do line number decoding in read_file_scope () */
   process_die (cu->dies, cu);
 
+  /* For now fudge the Go package.  */
+  if (cu->language == language_go)
+    fixup_go_packaging (cu);
+
   /* Now that we have processed all the DIEs in the CU, all the types 
      should be complete, and it should now be safe to compute all of the
      physnames.  */
@@ -5067,8 +5144,14 @@ do_ui_file_peek_last (void *object, cons
 }
 
 /* Compute the fully qualified name of DIE in CU.  If PHYSNAME is nonzero,
-   compute the physname for the object, which include a method's
-   formal parameters (C++/Java) and return type (Java).
+   compute the physname for the object, which include a method's:
+   - formal parameters (C++/Java),
+   - receiver type (Go),
+   - return type (Java).
+
+   The term "physname" is a bit confusing.
+   For C++, for example, it is the demangled name.
+   For Go, for example, it's the mangled name.
 
    For Ada, return the DIE's linkage name rather than the fully qualified
    name.  PHYSNAME is ignored..
@@ -5362,10 +5445,27 @@ dwarf2_physname (char *name, struct die_
 	 variant `long name(params)' does not have the proper inferior type.
 	 */
 
-      demangled = cplus_demangle (mangled, (DMGL_PARAMS | DMGL_ANSI
-					    | (cu->language == language_java
-					       ? DMGL_JAVA | DMGL_RET_POSTFIX
-					       : DMGL_RET_DROP)));
+      /* FIXME(dje): This should always use la_demangle, if non-NULL, right?
+	 And if not, it should be clearly documented why not.
+	 OTOH, why are we demangling at all here?
+	 new_symbol_full assumes we return the mangled name.
+	 I realize things are changing in this area, I just forget how.  */
+      if (cu->language == language_go)
+	{
+#if 0
+	  demangled = cu->language_defn->la_demangle (mangled, 0);
+#else
+	  /* This is a lie, but we already lie to the caller new_symbol_full.
+	     This just undoes that lie until things are cleaned up.  */
+	  demangled = NULL;
+#endif
+	}
+      else
+	demangled = cplus_demangle (mangled,
+				    (DMGL_PARAMS | DMGL_ANSI
+				     | (cu->language == language_java
+					? DMGL_JAVA | DMGL_RET_POSTFIX
+					: DMGL_RET_DROP)));
       if (demangled)
 	{
 	  make_cleanup (xfree, demangled);
@@ -5692,6 +5792,10 @@ read_file_scope (struct die_info *die, s
   if (cu->producer && strstr (cu->producer, "IBM XL C for OpenCL") != NULL)
     cu->language = language_opencl;
 
+  /* Similar hack for Go.  */
+  if (cu->producer && strstr (cu->producer, "GNU Go ") != NULL)
+    set_cu_language (DW_LANG_Go, cu);
+
   /* We assume that we're processing GCC output.  */
   processing_gcc_compilation = 2;
 
@@ -5741,6 +5845,7 @@ read_file_scope (struct die_info *die, s
 			       &dwarf2_per_objfile->macinfo, 0);
 	}
     }
+
   do_cleanups (back_to);
 }
 
@@ -10713,6 +10830,9 @@ set_cu_language (unsigned int lang, stru
     case DW_LANG_Fortran95:
       cu->language = language_fortran;
       break;
+    case DW_LANG_Go:
+      cu->language = language_go;
+      break;
     case DW_LANG_Mips_Assembler:
       cu->language = language_asm;
       break;
@@ -12532,6 +12652,9 @@ determine_prefix (struct die_info *die, 
   struct type *parent_type;
   char *retval;
 
+  /* FIXME: Go may eventually need to do something here, but for now
+     objects already have the package name in their name.  */
+
   if (cu->language != language_cplus && cu->language != language_java
       && cu->language != language_fortran)
     return "";
Index: go-exp.y
===================================================================
RCS file: go-exp.y
diff -N go-exp.y
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ go-exp.y	28 Dec 2011 20:50:31 -0000
@@ -0,0 +1,1623 @@
+/* YACC parser for Go expressions, for GDB.
+   Copyright (C) 2011
+   Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/* This file is derived from c-exp.y, p-exp.y.  */
+
+/* Parse a Go expression from text in a string,
+   and return the result as a struct expression pointer.
+   That structure contains arithmetic operations in reverse polish,
+   with constants represented by operations that are followed by special data.
+   See expression.h for the details of the format.
+   What is important here is that it can be built up sequentially
+   during the process of parsing; the lower levels of the tree always
+   come first in the result.
+
+   Note that malloc's and realloc's in this file are transformed to
+   xmalloc and xrealloc respectively by the same sed command in the
+   makefile that remaps any other malloc/realloc inserted by the parser
+   generator.  Doing this with #defines and trying to control the interaction
+   with include files (<malloc.h> and <stdlib.h> for example) just became
+   too messy, particularly when such includes can be inserted at random
+   times by the parser generator.  */
+
+/* Known bugs or limitations:
+
+   - Unicode
+   - &^
+   - '_' (blank identifier)
+   - automatic deref of pointers
+   - method expressions
+   - interfaces, channels, etc.
+
+   And lots of other things.
+   I'm sure there's some cleanup to do.
+*/
+
+%{
+
+#include "defs.h"
+#include "gdb_string.h"
+#include <ctype.h>
+#include "expression.h"
+#include "value.h"
+#include "parser-defs.h"
+#include "language.h"
+#include "c-lang.h"
+#include "go-lang.h"
+#include "bfd.h" /* Required by objfiles.h.  */
+#include "symfile.h" /* Required by objfiles.h.  */
+#include "objfiles.h" /* For have_full_symbols and have_partial_symbols */
+#include "charset.h"
+#include "block.h"
+
+#define parse_type builtin_type (parse_gdbarch)
+
+/* Remap normal yacc parser interface names (yyparse, yylex, yyerror, etc),
+   as well as gratuitiously global symbol names, so we can have multiple
+   yacc generated parsers in gdb.  Note that these are only the variables
+   produced by yacc.  If other parser generators (bison, byacc, etc) produce
+   additional global names that conflict at link time, then those parser
+   generators need to be fixed instead of adding those names to this list.  */
+
+#define	yymaxdepth go_maxdepth
+#define	yyparse	go_parse_internal
+#define	yylex	go_lex
+#define	yyerror	go_error
+#define	yylval	go_lval
+#define	yychar	go_char
+#define	yydebug	go_debug
+#define	yypact	go_pact
+#define	yyr1	go_r1
+#define	yyr2	go_r2
+#define	yydef	go_def
+#define	yychk	go_chk
+#define	yypgo	go_pgo
+#define	yyact	go_act
+#define	yyexca	go_exca
+#define yyerrflag go_errflag
+#define yynerrs	go_nerrs
+#define	yyps	go_ps
+#define	yypv	go_pv
+#define	yys	go_s
+#define	yy_yys	go_yys
+#define	yystate	go_state
+#define	yytmp	go_tmp
+#define	yyv	go_v
+#define	yy_yyv	go_yyv
+#define	yyval	go_val
+#define	yylloc	go_lloc
+#define yyreds	go_reds		/* With YYDEBUG defined */
+#define yytoks	go_toks		/* With YYDEBUG defined */
+#define yyname	go_name		/* With YYDEBUG defined */
+#define yyrule	go_rule		/* With YYDEBUG defined */
+#define yylhs	go_yylhs
+#define yylen	go_yylen
+#define yydefred go_yydefred
+#define yydgoto	go_yydgoto
+#define yysindex go_yysindex
+#define yyrindex go_yyrindex
+#define yygindex go_yygindex
+#define yytable	 go_yytable
+#define yycheck	 go_yycheck
+
+#ifndef YYDEBUG
+#define	YYDEBUG 1		/* Default to yydebug support */
+#endif
+
+#define YYFPRINTF parser_fprintf
+
+int yyparse (void);
+
+static int yylex (void);
+
+void yyerror (char *);
+
+%}
+
+/* Although the yacc "value" of an expression is not used,
+   since the result is stored in the structure being created,
+   other node types do have values.  */
+
+%union
+  {
+    LONGEST lval;
+    struct {
+      LONGEST val;
+      struct type *type;
+    } typed_val_int;
+    struct {
+      DOUBLEST dval;
+      struct type *type;
+    } typed_val_float;
+    struct stoken sval;
+    struct symtoken ssym;
+    struct type *tval;
+    struct typed_stoken tsval;
+    struct ttype tsym;
+    int voidval;
+    enum exp_opcode opcode;
+    struct internalvar *ivar;
+    struct stoken_vector svec;
+  }
+
+%{
+/* YYSTYPE gets defined by %union.  */
+static int parse_number (char *, int, int, YYSTYPE *);
+static int parse_go_float (struct gdbarch *gdbarch, const char *p, int len,
+			   DOUBLEST *d, struct type **t);
+%}
+
+%type <voidval> exp exp1 type_exp start normal_start variable lcurly
+%type <lval> rcurly
+%type <tval> type
+
+%token <typed_val_int> INT
+%token <typed_val_float> FLOAT
+
+/* Both NAME and TYPENAME tokens represent symbols in the input,
+   and both convey their data as strings.
+   But a TYPENAME is a string that happens to be defined as a type
+   or builtin type name (such as int or char)
+   and a NAME is any other symbol.
+   Contexts where this distinction is not important can use the
+   nonterminal "name", which matches either NAME or TYPENAME.  */
+
+%token <tsval> RAW_STRING
+%token <tsval> STRING
+%token <tsval> CHAR
+%token <ssym> NAME
+%token <tsym> TYPENAME /* Not TYPE_NAME cus already taken.  */
+%token <voidval> COMPLETE
+/*%type <sval> name*/
+%type <svec> string_exp
+%type <ssym> name_not_typename
+
+/* A NAME_OR_INT is a symbol which is not known in the symbol table,
+   but which would parse as a valid number in the current input radix.
+   E.g. "c" when input_radix==16.  Depending on the parse, it will be
+   turned into a name or into a number.  */
+%token <ssym> NAME_OR_INT
+
+%token <lval> TRUE_KEYWORD FALSE_KEYWORD
+%token STRUCT_KEYWORD INTERFACE_KEYWORD TYPE_KEYWORD CHAN_KEYWORD
+%token SIZEOF_KEYWORD
+%token LEN_KEYWORD CAP_KEYWORD
+%token NEW_KEYWORD
+%token IOTA_KEYWORD NIL_KEYWORD
+%token CONST_KEYWORD
+%token DOTDOTDOT
+%token ENTRY
+%token ERROR
+
+/* Special type cases.  */
+%token BYTE_KEYWORD /* An alias of uint8.  */
+
+%token <sval> DOLLAR_VARIABLE
+
+%token <opcode> ASSIGN_MODIFY
+
+%left ','
+%left ABOVE_COMMA
+%right '=' ASSIGN_MODIFY
+%right '?'
+%left OROR
+%left ANDAND
+%left '|'
+%left '^'
+%left '&'
+%left ANDNOT
+%left EQUAL NOTEQUAL
+%left '<' '>' LEQ GEQ
+%left LSH RSH
+%left '@'
+%left '+' '-'
+%left '*' '/' '%'
+%right UNARY INCREMENT DECREMENT
+%right LEFT_ARROW '.' '[' '('
+
+
+%%
+
+start   :	{ /*FIXME*/ }
+		normal_start {}
+	;
+
+normal_start	:
+		exp1
+	|	type_exp
+	;
+
+type_exp:	type
+			{ write_exp_elt_opcode(OP_TYPE);
+			  write_exp_elt_type($1);
+			  write_exp_elt_opcode(OP_TYPE); }
+	;
+
+/* Expressions, including the comma operator.  */
+exp1	:	exp
+	|	exp1 ',' exp
+			{ write_exp_elt_opcode (BINOP_COMMA); }
+	;
+
+/* Expressions, not including the comma operator.  */
+exp	:	'*' exp    %prec UNARY
+			{ write_exp_elt_opcode (UNOP_IND); }
+	;
+
+exp	:	'&' exp    %prec UNARY
+			{ write_exp_elt_opcode (UNOP_ADDR); }
+	;
+
+exp	:	'-' exp    %prec UNARY
+			{ write_exp_elt_opcode (UNOP_NEG); }
+	;
+
+exp	:	'+' exp    %prec UNARY
+			{ write_exp_elt_opcode (UNOP_PLUS); }
+	;
+
+exp	:	'!' exp    %prec UNARY
+			{ write_exp_elt_opcode (UNOP_LOGICAL_NOT); }
+	;
+
+exp	:	'^' exp    %prec UNARY
+			{ write_exp_elt_opcode (UNOP_COMPLEMENT); }
+	;
+
+exp	:	exp INCREMENT    %prec UNARY
+			{ write_exp_elt_opcode (UNOP_POSTINCREMENT); }
+	;
+
+exp	:	exp DECREMENT    %prec UNARY
+			{ write_exp_elt_opcode (UNOP_POSTDECREMENT); }
+	;
+
+/* foo->bar is not in Go.  May want as a gdb extension.  Later.  */
+
+exp	:	exp '.' name_not_typename
+			{ write_exp_elt_opcode (STRUCTOP_STRUCT);
+			  write_exp_string ($3.stoken);
+			  write_exp_elt_opcode (STRUCTOP_STRUCT); }
+	;
+
+exp	:	exp '.' name_not_typename COMPLETE
+			{ mark_struct_expression ();
+			  write_exp_elt_opcode (STRUCTOP_STRUCT);
+			  write_exp_string ($3.stoken);
+			  write_exp_elt_opcode (STRUCTOP_STRUCT); }
+	;
+
+exp	:	exp '.' COMPLETE
+			{ struct stoken s;
+			  mark_struct_expression ();
+			  write_exp_elt_opcode (STRUCTOP_STRUCT);
+			  s.ptr = "";
+			  s.length = 0;
+			  write_exp_string (s);
+			  write_exp_elt_opcode (STRUCTOP_STRUCT); }
+	;
+
+exp	:	exp '[' exp1 ']'
+			{ write_exp_elt_opcode (BINOP_SUBSCRIPT); }
+	;
+
+exp	:	exp '('
+			/* This is to save the value of arglist_len
+			   being accumulated by an outer function call.  */
+			{ start_arglist (); }
+		arglist ')'	%prec LEFT_ARROW
+			{ write_exp_elt_opcode (OP_FUNCALL);
+			  write_exp_elt_longcst ((LONGEST) end_arglist ());
+			  write_exp_elt_opcode (OP_FUNCALL); }
+	;
+
+lcurly	:	'{'
+			{ start_arglist (); }
+	;
+
+arglist	:
+	;
+
+arglist	:	exp
+			{ arglist_len = 1; }
+	;
+
+arglist	:	arglist ',' exp   %prec ABOVE_COMMA
+			{ arglist_len++; }
+	;
+
+rcurly	:	'}'
+			{ $$ = end_arglist () - 1; }
+	;
+
+exp	:	lcurly type rcurly exp  %prec UNARY
+			{ write_exp_elt_opcode (UNOP_MEMVAL);
+			  write_exp_elt_type ($2);
+			  write_exp_elt_opcode (UNOP_MEMVAL); }
+	;
+
+exp	:	type '(' exp ')'  %prec UNARY
+			{ write_exp_elt_opcode (UNOP_CAST);
+			  write_exp_elt_type ($1);
+			  write_exp_elt_opcode (UNOP_CAST); }
+	;
+
+exp	:	'(' exp1 ')'
+			{ }
+	;
+
+/* Binary operators in order of decreasing precedence.  */
+
+exp	:	exp '@' exp
+			{ write_exp_elt_opcode (BINOP_REPEAT); }
+	;
+
+exp	:	exp '*' exp
+			{ write_exp_elt_opcode (BINOP_MUL); }
+	;
+
+exp	:	exp '/' exp
+			{ write_exp_elt_opcode (BINOP_DIV); }
+	;
+
+exp	:	exp '%' exp
+			{ write_exp_elt_opcode (BINOP_REM); }
+	;
+
+exp	:	exp '+' exp
+			{ write_exp_elt_opcode (BINOP_ADD); }
+	;
+
+exp	:	exp '-' exp
+			{ write_exp_elt_opcode (BINOP_SUB); }
+	;
+
+exp	:	exp LSH exp
+			{ write_exp_elt_opcode (BINOP_LSH); }
+	;
+
+exp	:	exp RSH exp
+			{ write_exp_elt_opcode (BINOP_RSH); }
+	;
+
+exp	:	exp EQUAL exp
+			{ write_exp_elt_opcode (BINOP_EQUAL); }
+	;
+
+exp	:	exp NOTEQUAL exp
+			{ write_exp_elt_opcode (BINOP_NOTEQUAL); }
+	;
+
+exp	:	exp LEQ exp
+			{ write_exp_elt_opcode (BINOP_LEQ); }
+	;
+
+exp	:	exp GEQ exp
+			{ write_exp_elt_opcode (BINOP_GEQ); }
+	;
+
+exp	:	exp '<' exp
+			{ write_exp_elt_opcode (BINOP_LESS); }
+	;
+
+exp	:	exp '>' exp
+			{ write_exp_elt_opcode (BINOP_GTR); }
+	;
+
+exp	:	exp '&' exp
+			{ write_exp_elt_opcode (BINOP_BITWISE_AND); }
+	;
+
+exp	:	exp '^' exp
+			{ write_exp_elt_opcode (BINOP_BITWISE_XOR); }
+	;
+
+exp	:	exp '|' exp
+			{ write_exp_elt_opcode (BINOP_BITWISE_IOR); }
+	;
+
+exp	:	exp ANDAND exp
+			{ write_exp_elt_opcode (BINOP_LOGICAL_AND); }
+	;
+
+exp	:	exp OROR exp
+			{ write_exp_elt_opcode (BINOP_LOGICAL_OR); }
+	;
+
+exp	:	exp '?' exp ':' exp	%prec '?'
+			{ write_exp_elt_opcode (TERNOP_COND); }
+	;
+
+exp	:	exp '=' exp
+			{ write_exp_elt_opcode (BINOP_ASSIGN); }
+	;
+
+exp	:	exp ASSIGN_MODIFY exp
+			{ write_exp_elt_opcode (BINOP_ASSIGN_MODIFY);
+			  write_exp_elt_opcode ($2);
+			  write_exp_elt_opcode (BINOP_ASSIGN_MODIFY); }
+	;
+
+exp	:	INT
+			{ write_exp_elt_opcode (OP_LONG);
+			  write_exp_elt_type ($1.type);
+			  write_exp_elt_longcst ((LONGEST)($1.val));
+			  write_exp_elt_opcode (OP_LONG); }
+	;
+
+exp	:	CHAR
+			{
+			  struct stoken_vector vec;
+			  vec.len = 1;
+			  vec.tokens = &$1;
+			  write_exp_string_vector ($1.type, &vec);
+			}
+	;
+
+exp	:	NAME_OR_INT
+			{ YYSTYPE val;
+			  parse_number ($1.stoken.ptr, $1.stoken.length,
+					0, &val);
+			  write_exp_elt_opcode (OP_LONG);
+			  write_exp_elt_type (val.typed_val_int.type);
+			  write_exp_elt_longcst ((LONGEST)
+						 val.typed_val_int.val);
+			  write_exp_elt_opcode (OP_LONG);
+			}
+	;
+
+
+exp	:	FLOAT
+			{ write_exp_elt_opcode (OP_DOUBLE);
+			  write_exp_elt_type ($1.type);
+			  write_exp_elt_dblcst ($1.dval);
+			  write_exp_elt_opcode (OP_DOUBLE); }
+	;
+
+exp	:	variable
+	;
+
+exp	:	DOLLAR_VARIABLE
+			{
+			  write_dollar_variable ($1);
+			}
+	;
+
+exp	:	SIZEOF_KEYWORD '(' type ')'  %prec UNARY
+			{
+			  /* TODO(dje): Go objects in structs.  */
+			  write_exp_elt_opcode (OP_LONG);
+			  /* TODO(dje): What's the right type here?  */
+			  write_exp_elt_type (parse_type->builtin_unsigned_int);
+			  CHECK_TYPEDEF ($3);
+			  write_exp_elt_longcst ((LONGEST) TYPE_LENGTH ($3));
+			  write_exp_elt_opcode (OP_LONG);
+			}
+	;
+
+exp	:	SIZEOF_KEYWORD  '(' exp ')'  %prec UNARY
+			{
+			  /* TODO(dje): Go objects in structs.  */
+			  write_exp_elt_opcode (UNOP_SIZEOF);
+			}
+
+string_exp:
+		STRING
+			{
+			  /* We copy the string here, and not in the
+			     lexer, to guarantee that we do not leak a
+			     string.  */
+			  /* Note that we NUL-terminate here, but just
+			     for convenience.  */
+			  struct typed_stoken *vec = XNEW (struct typed_stoken);
+			  $$.len = 1;
+			  $$.tokens = vec;
+
+			  vec->type = $1.type;
+			  vec->length = $1.length;
+			  vec->ptr = malloc ($1.length + 1);
+			  memcpy (vec->ptr, $1.ptr, $1.length + 1);
+			}
+
+	|	string_exp '+' STRING
+			{
+			  /* Note that we NUL-terminate here, but just
+			     for convenience.  */
+			  char *p;
+			  ++$$.len;
+			  $$.tokens = realloc ($$.tokens,
+					       $$.len * sizeof (struct typed_stoken));
+
+			  p = malloc ($3.length + 1);
+			  memcpy (p, $3.ptr, $3.length + 1);
+
+			  $$.tokens[$$.len - 1].type = $3.type;
+			  $$.tokens[$$.len - 1].length = $3.length;
+			  $$.tokens[$$.len - 1].ptr = p;
+			}
+	;
+
+exp	:	string_exp  %prec ABOVE_COMMA
+			{
+			  int i;
+
+			  write_exp_string_vector (0 /*always utf8*/, &$1);
+			  for (i = 0; i < $1.len; ++i)
+			    free ($1.tokens[i].ptr);
+			  free ($1.tokens);
+			}
+	;
+
+exp	:	TRUE_KEYWORD
+			{ write_exp_elt_opcode (OP_BOOL);
+			  write_exp_elt_longcst ((LONGEST) $1);
+			  write_exp_elt_opcode (OP_BOOL); }
+	;
+
+exp	:	FALSE_KEYWORD
+			{ write_exp_elt_opcode (OP_BOOL);
+			  write_exp_elt_longcst ((LONGEST) $1);
+			  write_exp_elt_opcode (OP_BOOL); }
+	;
+
+variable:	name_not_typename ENTRY
+			{ struct symbol *sym = $1.sym;
+
+			  if (sym == NULL
+			      || !SYMBOL_IS_ARGUMENT (sym)
+			      || !symbol_read_needs_frame (sym))
+			    error (_("@entry can be used only for function "
+				     "parameters, not for \"%s\""),
+				   copy_name ($1.stoken));
+
+			  write_exp_elt_opcode (OP_VAR_ENTRY_VALUE);
+			  write_exp_elt_sym (sym);
+			  write_exp_elt_opcode (OP_VAR_ENTRY_VALUE);
+			}
+	;
+
+variable:	name_not_typename
+			{ struct symbol *sym = $1.sym;
+
+			  if (sym)
+			    {
+			      if (symbol_read_needs_frame (sym))
+				{
+				  if (innermost_block == 0
+				      || contained_in (block_found,
+						       innermost_block))
+				    innermost_block = block_found;
+				}
+
+			      write_exp_elt_opcode (OP_VAR_VALUE);
+			      /* We want to use the selected frame, not
+				 another more inner frame which happens to
+				 be in the same block.  */
+			      write_exp_elt_block (NULL);
+			      write_exp_elt_sym (sym);
+			      write_exp_elt_opcode (OP_VAR_VALUE);
+			    }
+			  else if ($1.is_a_field_of_this)
+			    {
+			      /* TODO(dje): Can we get here?
+				 E.g., via a mix of c++ and go?  */
+			      gdb_assert_not_reached ("go with `this' field");
+			    }
+			  else
+			    {
+			      struct minimal_symbol *msymbol;
+			      char *arg = copy_name ($1.stoken);
+
+			      msymbol =
+				lookup_minimal_symbol (arg, NULL, NULL);
+			      if (msymbol != NULL)
+				write_exp_msymbol (msymbol);
+			      else if (!have_full_symbols ()
+				       && !have_partial_symbols ())
+				error (_("No symbol table is loaded.  "
+				       "Use the \"file\" command."));
+			      else
+				error (_("No symbol \"%s\" in current context."),
+				       copy_name ($1.stoken));
+			    }
+			}
+	;
+
+/* TODO
+method_exp: PACKAGENAME '.' name '.' name
+			{
+			}
+	;
+*/
+
+type  /* Implements (approximately): [*] type-specifier */
+	:	'*' type
+			{ $$ = lookup_pointer_type ($2); }
+	|	TYPENAME
+			{ $$ = $1.type; }
+/*
+	|	STRUCT_KEYWORD name
+			{ $$ = lookup_struct (copy_name ($2),
+					      expression_context_block); }
+*/
+	|	BYTE_KEYWORD
+			{ $$ = builtin_go_type (parse_gdbarch)
+			    ->builtin_uint8; }
+	;
+
+/* TODO
+name	:	NAME { $$ = $1.stoken; }
+	|	TYPENAME { $$ = $1.stoken; }
+	|	NAME_OR_INT  { $$ = $1.stoken; }
+	;
+*/
+
+name_not_typename
+	:	NAME
+/* These would be useful if name_not_typename was useful, but it is just
+   a fake for "variable", so these cause reduce/reduce conflicts because
+   the parser can't tell whether NAME_OR_INT is a name_not_typename (=variable,
+   =exp) or just an exp.  If name_not_typename was ever used in an lvalue
+   context where only a name could occur, this might be useful.
+	|	NAME_OR_INT
+*/
+	;
+
+%%
+
+/* Wrapper on parse_c_float to get the type right for Go.  */
+
+static int
+parse_go_float (struct gdbarch *gdbarch, const char *p, int len,
+		DOUBLEST *d, struct type **t)
+{
+  int result = parse_c_float (gdbarch, p, len, d, t);
+  const struct builtin_type *builtin_types = builtin_type (gdbarch);
+  const struct builtin_go_type *builtin_go_types = builtin_go_type (gdbarch);
+
+  if (*t == builtin_types->builtin_float)
+    *t = builtin_go_types->builtin_float32;
+  else if (*t == builtin_types->builtin_double)
+    *t = builtin_go_types->builtin_float64;
+
+  return result;
+}
+
+/* Take care of parsing a number (anything that starts with a digit).
+   Set yylval and return the token type; update lexptr.
+   LEN is the number of characters in it.  */
+
+/* FIXME: Needs some error checking for the float case.  */
+/* FIXME: IWBN to use c-exp.y's parse_number if we could.  */
+
+static int
+parse_number (char *p, int len, int parsed_float, YYSTYPE *putithere)
+{
+  /* FIXME: Shouldn't these be unsigned?  We don't deal with negative values
+     here, and we do kind of silly things like cast to unsigned.  */
+  LONGEST n = 0;
+  LONGEST prevn = 0;
+  ULONGEST un;
+
+  int i = 0;
+  int c;
+  int base = input_radix;
+  int unsigned_p = 0;
+
+  /* Number of "L" suffixes encountered.  */
+  int long_p = 0;
+
+  /* We have found a "L" or "U" suffix.  */
+  int found_suffix = 0;
+
+  ULONGEST high_bit;
+  struct type *signed_type;
+  struct type *unsigned_type;
+
+  if (parsed_float)
+    {
+      if (! parse_go_float (parse_gdbarch, p, len,
+			    &putithere->typed_val_float.dval,
+			    &putithere->typed_val_float.type))
+	return ERROR;
+      return FLOAT;
+    }
+
+  /* Handle base-switching prefixes 0x, 0t, 0d, 0.  */
+  if (p[0] == '0')
+    switch (p[1])
+      {
+      case 'x':
+      case 'X':
+	if (len >= 3)
+	  {
+	    p += 2;
+	    base = 16;
+	    len -= 2;
+	  }
+	break;
+
+      case 'b':
+      case 'B':
+	if (len >= 3)
+	  {
+	    p += 2;
+	    base = 2;
+	    len -= 2;
+	  }
+	break;
+
+      case 't':
+      case 'T':
+      case 'd':
+      case 'D':
+	if (len >= 3)
+	  {
+	    p += 2;
+	    base = 10;
+	    len -= 2;
+	  }
+	break;
+
+      default:
+	base = 8;
+	break;
+      }
+
+  while (len-- > 0)
+    {
+      c = *p++;
+      if (c >= 'A' && c <= 'Z')
+	c += 'a' - 'A';
+      if (c != 'l' && c != 'u')
+	n *= base;
+      if (c >= '0' && c <= '9')
+	{
+	  if (found_suffix)
+	    return ERROR;
+	  n += i = c - '0';
+	}
+      else
+	{
+	  if (base > 10 && c >= 'a' && c <= 'f')
+	    {
+	      if (found_suffix)
+		return ERROR;
+	      n += i = c - 'a' + 10;
+	    }
+	  else if (c == 'l')
+	    {
+	      ++long_p;
+	      found_suffix = 1;
+	    }
+	  else if (c == 'u')
+	    {
+	      unsigned_p = 1;
+	      found_suffix = 1;
+	    }
+	  else
+	    return ERROR;	/* Char not a digit */
+	}
+      if (i >= base)
+	return ERROR;		/* Invalid digit in this base.  */
+
+      /* Portably test for overflow (only works for nonzero values, so make
+	 a second check for zero).  FIXME: Can't we just make n and prevn
+	 unsigned and avoid this?  */
+      if (c != 'l' && c != 'u' && (prevn >= n) && n != 0)
+	unsigned_p = 1;		/* Try something unsigned.  */
+
+      /* Portably test for unsigned overflow.
+	 FIXME: This check is wrong; for example it doesn't find overflow
+	 on 0x123456789 when LONGEST is 32 bits.  */
+      if (c != 'l' && c != 'u' && n != 0)
+	{
+	  if ((unsigned_p && (ULONGEST) prevn >= (ULONGEST) n))
+	    error (_("Numeric constant too large."));
+	}
+      prevn = n;
+    }
+
+  /* An integer constant is an int, a long, or a long long.  An L
+     suffix forces it to be long; an LL suffix forces it to be long
+     long.  If not forced to a larger size, it gets the first type of
+     the above that it fits in.  To figure out whether it fits, we
+     shift it right and see whether anything remains.  Note that we
+     can't shift sizeof (LONGEST) * HOST_CHAR_BIT bits or more in one
+     operation, because many compilers will warn about such a shift
+     (which always produces a zero result).  Sometimes gdbarch_int_bit
+     or gdbarch_long_bit will be that big, sometimes not.  To deal with
+     the case where it is we just always shift the value more than
+     once, with fewer bits each time.  */
+
+  un = (ULONGEST)n >> 2;
+  if (long_p == 0
+      && (un >> (gdbarch_int_bit (parse_gdbarch) - 2)) == 0)
+    {
+      high_bit = ((ULONGEST)1) << (gdbarch_int_bit (parse_gdbarch) - 1);
+
+      /* A large decimal (not hex or octal) constant (between INT_MAX
+	 and UINT_MAX) is a long or unsigned long, according to ANSI,
+	 never an unsigned int, but this code treats it as unsigned
+	 int.  This probably should be fixed.  GCC gives a warning on
+	 such constants.  */
+
+      unsigned_type = parse_type->builtin_unsigned_int;
+      signed_type = parse_type->builtin_int;
+    }
+  else if (long_p <= 1
+	   && (un >> (gdbarch_long_bit (parse_gdbarch) - 2)) == 0)
+    {
+      high_bit = ((ULONGEST)1) << (gdbarch_long_bit (parse_gdbarch) - 1);
+      unsigned_type = parse_type->builtin_unsigned_long;
+      signed_type = parse_type->builtin_long;
+    }
+  else
+    {
+      int shift;
+      if (sizeof (ULONGEST) * HOST_CHAR_BIT
+	  < gdbarch_long_long_bit (parse_gdbarch))
+	/* A long long does not fit in a LONGEST.  */
+	shift = (sizeof (ULONGEST) * HOST_CHAR_BIT - 1);
+      else
+	shift = (gdbarch_long_long_bit (parse_gdbarch) - 1);
+      high_bit = (ULONGEST) 1 << shift;
+      unsigned_type = parse_type->builtin_unsigned_long_long;
+      signed_type = parse_type->builtin_long_long;
+    }
+
+   putithere->typed_val_int.val = n;
+
+   /* If the high bit of the worked out type is set then this number
+      has to be unsigned.  */
+
+   if (unsigned_p || (n & high_bit))
+     {
+       putithere->typed_val_int.type = unsigned_type;
+     }
+   else
+     {
+       putithere->typed_val_int.type = signed_type;
+     }
+
+   return INT;
+}
+
+/* Temporary obstack used for holding strings.  */
+static struct obstack tempbuf;
+static int tempbuf_init;
+
+/* Parse a string or character literal from TOKPTR.  The string or
+   character may be wide or unicode.  *OUTPTR is set to just after the
+   end of the literal in the input string.  The resulting token is
+   stored in VALUE.  This returns a token value, either STRING or
+   CHAR, depending on what was parsed.  *HOST_CHARS is set to the
+   number of host characters in the literal.  */
+
+static int
+parse_string_or_char (char *tokptr, char **outptr, struct typed_stoken *value,
+		      int *host_chars)
+{
+  int quote;
+
+  /* Build the gdb internal form of the input string in tempbuf.  Note
+     that the buffer is null byte terminated *only* for the
+     convenience of debugging gdb itself and printing the buffer
+     contents when the buffer contains no embedded nulls.  Gdb does
+     not depend upon the buffer being null byte terminated, it uses
+     the length string instead.  This allows gdb to handle C strings
+     (as well as strings in other languages) with embedded null
+     bytes */
+
+  if (!tempbuf_init)
+    tempbuf_init = 1;
+  else
+    obstack_free (&tempbuf, NULL);
+  obstack_init (&tempbuf);
+
+  /* Skip the quote.  */
+  quote = *tokptr;
+  ++tokptr;
+
+  *host_chars = 0;
+
+  while (*tokptr)
+    {
+      char c = *tokptr;
+      if (c == '\\')
+	{
+	  ++tokptr;
+	  *host_chars += c_parse_escape (&tokptr, &tempbuf);
+	}
+      else if (c == quote)
+	break;
+      else
+	{
+	  obstack_1grow (&tempbuf, c);
+	  ++tokptr;
+	  /* FIXME: this does the wrong thing with multi-byte host
+	     characters.  We could use mbrlen here, but that would
+	     make "set host-charset" a bit less useful.  */
+	  ++*host_chars;
+	}
+    }
+
+  if (*tokptr != quote)
+    {
+      if (quote == '"')
+	error (_("Unterminated string in expression."));
+      else
+	error (_("Unmatched single quote."));
+    }
+  ++tokptr;
+
+  value->type = C_STRING | (quote == '\'' ? C_CHAR : 0); /*FIXME*/
+  value->ptr = obstack_base (&tempbuf);
+  value->length = obstack_object_size (&tempbuf);
+
+  *outptr = tokptr;
+
+  return quote == '\'' ? CHAR : STRING;
+}
+
+struct token
+{
+  char *operator;
+  int token;
+  enum exp_opcode opcode;
+};
+
+static const struct token tokentab3[] =
+  {
+    {">>=", ASSIGN_MODIFY, BINOP_RSH},
+    {"<<=", ASSIGN_MODIFY, BINOP_LSH},
+    /*{"&^=", ASSIGN_MODIFY, BINOP_BITWISE_ANDNOT}, TODO */
+    {"...", DOTDOTDOT, OP_NULL},
+  };
+
+static const struct token tokentab2[] =
+  {
+    {"+=", ASSIGN_MODIFY, BINOP_ADD},
+    {"-=", ASSIGN_MODIFY, BINOP_SUB},
+    {"*=", ASSIGN_MODIFY, BINOP_MUL},
+    {"/=", ASSIGN_MODIFY, BINOP_DIV},
+    {"%=", ASSIGN_MODIFY, BINOP_REM},
+    {"|=", ASSIGN_MODIFY, BINOP_BITWISE_IOR},
+    {"&=", ASSIGN_MODIFY, BINOP_BITWISE_AND},
+    {"^=", ASSIGN_MODIFY, BINOP_BITWISE_XOR},
+    {"++", INCREMENT, BINOP_END},
+    {"--", DECREMENT, BINOP_END},
+    /*{"->", RIGHT_ARROW, BINOP_END}, Doesn't exist in Go.  */
+    {"<-", LEFT_ARROW, BINOP_END},
+    {"&&", ANDAND, BINOP_END},
+    {"||", OROR, BINOP_END},
+    {"<<", LSH, BINOP_END},
+    {">>", RSH, BINOP_END},
+    {"==", EQUAL, BINOP_END},
+    {"!=", NOTEQUAL, BINOP_END},
+    {"<=", LEQ, BINOP_END},
+    {">=", GEQ, BINOP_END},
+    /*{"&^", ANDNOT, BINOP_END}, TODO */
+  };
+
+/* Identifier-like tokens.  */
+static const struct token ident_tokens[] =
+  {
+    {"true", TRUE_KEYWORD, OP_NULL},
+    {"false", FALSE_KEYWORD, OP_NULL},
+    {"nil", NIL_KEYWORD, OP_NULL},
+    {"const", CONST_KEYWORD, OP_NULL},
+    {"struct", STRUCT_KEYWORD, OP_NULL},
+    {"type", TYPE_KEYWORD, OP_NULL},
+    {"interface", INTERFACE_KEYWORD, OP_NULL},
+    {"chan", CHAN_KEYWORD, OP_NULL},
+    {"byte", BYTE_KEYWORD, OP_NULL}, /* An alias of uint8.  */
+    {"len", LEN_KEYWORD, OP_NULL},
+    {"cap", CAP_KEYWORD, OP_NULL},
+    {"new", NEW_KEYWORD, OP_NULL},
+    {"iota", IOTA_KEYWORD, OP_NULL},
+  };
+
+/* This is set if a NAME token appeared at the very end of the input
+   string, with no whitespace separating the name from the EOF.  This
+   is used only when parsing to do field name completion.  */
+static int saw_name_at_eof;
+
+/* This is set if the previously-returned token was a structure
+   operator -- either '.' or ARROW.  This is used only when parsing to
+   do field name completion.  */
+static int last_was_structop;
+
+/* Read one token, getting characters through lexptr.  */
+
+static int
+lex_one_token (void)
+{
+  int c;
+  int namelen;
+  unsigned int i;
+  char *tokstart;
+  int saw_structop = last_was_structop;
+  char *copy;
+
+  last_was_structop = 0;
+
+ retry:
+
+  prev_lexptr = lexptr;
+
+  tokstart = lexptr;
+  /* See if it is a special token of length 3.  */
+  for (i = 0; i < sizeof (tokentab3) / sizeof (tokentab3[0]); i++)
+    if (strncmp (tokstart, tokentab3[i].operator, 3) == 0)
+      {
+	lexptr += 3;
+	yylval.opcode = tokentab3[i].opcode;
+	return tokentab3[i].token;
+      }
+
+  /* See if it is a special token of length 2.  */
+  for (i = 0; i < sizeof (tokentab2) / sizeof (tokentab2[0]); i++)
+    if (strncmp (tokstart, tokentab2[i].operator, 2) == 0)
+      {
+	lexptr += 2;
+	yylval.opcode = tokentab2[i].opcode;
+#if 0 /* -> doesn't exist in Go.  */
+	if (in_parse_field && tokentab2[i].token == RIGHT_ARROW)
+	  last_was_structop = 1;
+#endif
+	return tokentab2[i].token;
+      }
+
+  switch (c = *tokstart)
+    {
+    case 0:
+      if (saw_name_at_eof)
+	{
+	  saw_name_at_eof = 0;
+	  return COMPLETE;
+	}
+      else if (saw_structop)
+	return COMPLETE;
+      else
+        return 0;
+
+    case ' ':
+    case '\t':
+    case '\n':
+      lexptr++;
+      goto retry;
+
+    case '[':
+    case '(':
+      paren_depth++;
+      lexptr++;
+      return c;
+
+    case ']':
+    case ')':
+      if (paren_depth == 0)
+	return 0;
+      paren_depth--;
+      lexptr++;
+      return c;
+
+    case ',':
+      if (comma_terminates
+          && paren_depth == 0)
+	return 0;
+      lexptr++;
+      return c;
+
+    case '.':
+      /* Might be a floating point number.  */
+      if (lexptr[1] < '0' || lexptr[1] > '9')
+	{
+	  if (in_parse_field)
+	    last_was_structop = 1;
+	  goto symbol;		/* Nope, must be a symbol. */
+	}
+      /* FALL THRU into number case.  */
+
+    case '0':
+    case '1':
+    case '2':
+    case '3':
+    case '4':
+    case '5':
+    case '6':
+    case '7':
+    case '8':
+    case '9':
+      {
+	/* It's a number.  */
+	int got_dot = 0, got_e = 0, toktype;
+	char *p = tokstart;
+	int hex = input_radix > 10;
+
+	if (c == '0' && (p[1] == 'x' || p[1] == 'X'))
+	  {
+	    p += 2;
+	    hex = 1;
+	  }
+
+	for (;; ++p)
+	  {
+	    /* This test includes !hex because 'e' is a valid hex digit
+	       and thus does not indicate a floating point number when
+	       the radix is hex.  */
+	    if (!hex && !got_e && (*p == 'e' || *p == 'E'))
+	      got_dot = got_e = 1;
+	    /* This test does not include !hex, because a '.' always indicates
+	       a decimal floating point number regardless of the radix.  */
+	    else if (!got_dot && *p == '.')
+	      got_dot = 1;
+	    else if (got_e && (p[-1] == 'e' || p[-1] == 'E')
+		     && (*p == '-' || *p == '+'))
+	      /* This is the sign of the exponent, not the end of the
+		 number.  */
+	      continue;
+	    /* We will take any letters or digits.  parse_number will
+	       complain if past the radix, or if L or U are not final.  */
+	    else if ((*p < '0' || *p > '9')
+		     && ((*p < 'a' || *p > 'z')
+				  && (*p < 'A' || *p > 'Z')))
+	      break;
+	  }
+	toktype = parse_number (tokstart, p - tokstart, got_dot|got_e, &yylval);
+        if (toktype == ERROR)
+	  {
+	    char *err_copy = (char *) alloca (p - tokstart + 1);
+
+	    memcpy (err_copy, tokstart, p - tokstart);
+	    err_copy[p - tokstart] = 0;
+	    error (_("Invalid number \"%s\"."), err_copy);
+	  }
+	lexptr = p;
+	return toktype;
+      }
+
+    case '@':
+      {
+	char *p = &tokstart[1];
+	size_t len = strlen ("entry");
+
+	while (isspace (*p))
+	  p++;
+	if (strncmp (p, "entry", len) == 0 && !isalnum (p[len])
+	    && p[len] != '_')
+	  {
+	    lexptr = &p[len];
+	    return ENTRY;
+	  }
+      }
+      /* FALLTHRU */
+    case '+':
+    case '-':
+    case '*':
+    case '/':
+    case '%':
+    case '|':
+    case '&':
+    case '^':
+    case '~':
+    case '!':
+    case '<':
+    case '>':
+    case '?':
+    case ':':
+    case '=':
+    case '{':
+    case '}':
+    symbol:
+      lexptr++;
+      return c;
+
+    case '\'':
+    case '"':
+    case '`':
+      {
+	int host_len;
+	int result = parse_string_or_char (tokstart, &lexptr, &yylval.tsval,
+					   &host_len);
+	if (result == CHAR)
+	  {
+	    if (host_len == 0)
+	      error (_("Empty character constant."));
+	    else if (host_len > 2 && c == '\'')
+	      {
+		++tokstart;
+		namelen = lexptr - tokstart - 1;
+		goto tryname;
+	      }
+	    else if (host_len > 1)
+	      error (_("Invalid character constant."));
+	  }
+	return result;
+      }
+    }
+
+  if (!(c == '_' || c == '$'
+	|| (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')))
+    /* We must have come across a bad character (e.g. ';').  */
+    error (_("Invalid character '%c' in expression."), c);
+
+  /* It's a name.  See how long it is.  */
+  namelen = 0;
+  for (c = tokstart[namelen];
+       (c == '_' || c == '$' || (c >= '0' && c <= '9')
+	|| (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'));)
+    {
+      c = tokstart[++namelen];
+    }
+
+  /* The token "if" terminates the expression and is NOT removed from
+     the input stream.  It doesn't count if it appears in the
+     expansion of a macro.  */
+  if (namelen == 2
+      && tokstart[0] == 'i'
+      && tokstart[1] == 'f')
+    {
+      return 0;
+    }
+
+  /* For the same reason (breakpoint conditions), "thread N"
+     terminates the expression.  "thread" could be an identifier, but
+     an identifier is never followed by a number without intervening
+     punctuation.
+     Handle abbreviations of these, similarly to
+     breakpoint.c:find_condition_and_thread.
+     TODO: Watch for "goroutine" here?  */
+  if (namelen >= 1
+      && strncmp (tokstart, "thread", namelen) == 0
+      && (tokstart[namelen] == ' ' || tokstart[namelen] == '\t'))
+    {
+      char *p = tokstart + namelen + 1;
+      while (*p == ' ' || *p == '\t')
+	p++;
+      if (*p >= '0' && *p <= '9')
+	return 0;
+    }
+
+  lexptr += namelen;
+
+  tryname:
+
+  yylval.sval.ptr = tokstart;
+  yylval.sval.length = namelen;
+
+  /* Catch specific keywords.  */
+  copy = copy_name (yylval.sval);
+  for (i = 0; i < sizeof (ident_tokens) / sizeof (ident_tokens[0]); i++)
+    if (strcmp (copy, ident_tokens[i].operator) == 0)
+      {
+	/* It is ok to always set this, even though we don't always
+	   strictly need to.  */
+	yylval.opcode = ident_tokens[i].opcode;
+	return ident_tokens[i].token;
+      }
+
+  if (*tokstart == '$')
+    return DOLLAR_VARIABLE;
+
+  if (in_parse_field && *lexptr == '\0')
+    saw_name_at_eof = 1;
+  return NAME;
+}
+
+/* An object of this type is pushed on a FIFO by the "outer" lexer.  */
+typedef struct
+{
+  int token;
+  YYSTYPE value;
+} token_and_value;
+
+DEF_VEC_O (token_and_value);
+
+/* A FIFO of tokens that have been read but not yet returned to the
+   parser.  */
+static VEC (token_and_value) *token_fifo;
+
+/* Non-zero if the lexer should return tokens from the FIFO.  */
+static int popping;
+
+/* Temporary storage for yylex; this holds symbol names as they are
+   built up.  */
+static struct obstack name_obstack;
+
+/* Build "package.name" in name_obstack.
+   For convenience of the caller, the name is NUL-terminated,
+   but the NUL is not included in the recorded length.  */
+
+static struct stoken
+build_packaged_name (const char *package, int package_len,
+		     const char *name, int name_len)
+{
+  struct stoken result;
+
+  obstack_free (&name_obstack, obstack_base (&name_obstack));
+  obstack_grow (&name_obstack, package, package_len);
+  obstack_grow_str (&name_obstack, ".");
+  obstack_grow (&name_obstack, name, name_len);
+  obstack_grow (&name_obstack, "", 1);
+  result.ptr = obstack_base (&name_obstack);
+  result.length = obstack_object_size (&name_obstack) - 1;
+
+  return result;
+}
+
+/* Return non-zero if NAME is a package name.
+   BLOCK is the scope in which to interpret NAME; this can be NULL
+   to mean the global scope.  */
+
+static int
+package_name_p (const char *name, struct block *block)
+{
+  struct symbol *sym;
+  int is_a_field_of_this;
+
+  sym = lookup_symbol (name, block, STRUCT_DOMAIN, &is_a_field_of_this);
+
+  if (sym
+      && SYMBOL_CLASS (sym) == LOC_TYPEDEF
+      && TYPE_CODE (SYMBOL_TYPE (sym)) == TYPE_CODE_MODULE)
+    return 1;
+
+  return 0;
+}
+
+/* Classify a (potential) function in the "unsafe" package.
+   We fold these into "keywords" to keep things simple, at least until
+   something more complex is warranted.  */
+
+static int
+classify_unsafe_function (struct stoken function_name)
+{
+  char *copy = copy_name (function_name);
+
+  if (strcmp (copy, "Sizeof") == 0)
+    {
+      yylval.sval = function_name;
+      return SIZEOF_KEYWORD;
+    }
+
+  error (_("Unknown function in `unsafe' package: %s"), copy);
+}
+
+/* Classify token(s) "name1.name2" where name1 is known to be a package.
+   The contents of the token are in `yylval'.
+   Updates yylval and returns the new token type.
+
+   The result is one of NAME, NAME_OR_INT, or TYPENAME.  */
+
+static int
+classify_packaged_name (struct block *block)
+{
+  char *copy;
+  struct symbol *sym;
+  int is_a_field_of_this = 0;
+
+  copy = copy_name (yylval.sval);
+
+  sym = lookup_symbol (copy, block, VAR_DOMAIN, &is_a_field_of_this);
+
+  if (sym)
+    {
+      yylval.ssym.sym = sym;
+      yylval.ssym.is_a_field_of_this = is_a_field_of_this;
+    }
+
+  return NAME;
+}
+
+/* Classify a NAME token.
+   The contents of the token are in `yylval'.
+   Updates yylval and returns the new token type.
+   BLOCK is the block in which lookups start; this can be NULL
+   to mean the global scope.
+
+   The result is one of NAME, NAME_OR_INT, or TYPENAME.  */
+
+static int
+classify_name (struct block *block)
+{
+  struct type *type;
+  struct symbol *sym;
+  char *copy;
+  int is_a_field_of_this = 0;
+
+  copy = copy_name (yylval.sval);
+
+  /* Try primitive types first so they win over bad/weird debug info.  */
+  type = language_lookup_primitive_type_by_name (parse_language,
+						 parse_gdbarch, copy);
+  if (type != NULL)
+    {
+      /* NOTE: We take advantage of the fact that yylval coming in was a
+	 NAME, and that struct ttype is a compatible extension of struct
+	 stoken, so yylval.tsym.stoken is already filled in.  */
+      yylval.tsym.type = type;
+      return TYPENAME;
+    }
+
+  /* TODO: What about other types?  */
+
+  sym = lookup_symbol (copy, block, VAR_DOMAIN, &is_a_field_of_this);
+
+  if (sym)
+    {
+      yylval.ssym.sym = sym;
+      yylval.ssym.is_a_field_of_this = is_a_field_of_this;
+      return NAME;
+    }
+
+  /* If we didn't find a symbol, look again in the current package.
+     This is to, e.g., make "p global_var" work without having to specify
+     the package name.  We intentionally only looks for objects in the
+     current package.  */
+
+  {
+    char *current_package_name = go_block_package_name (block);
+
+    if (current_package_name != NULL)
+      {
+	struct stoken sval =
+	  build_packaged_name (current_package_name,
+			       strlen (current_package_name),
+			       copy, strlen (copy));
+
+	xfree (current_package_name);
+	sym = lookup_symbol (sval.ptr, block, VAR_DOMAIN,
+			     &is_a_field_of_this);
+	if (sym)
+	  {
+	    yylval.sval = sval;
+	    yylval.ssym.sym = sym;
+	    yylval.ssym.is_a_field_of_this = is_a_field_of_this;
+	    return NAME;
+	  }
+      }
+  }
+
+  /* Input names that aren't symbols but ARE valid hex numbers, when
+     the input radix permits them, can be names or numbers depending
+     on the parse.  Note we support radixes > 16 here.  */
+  if ((copy[0] >= 'a' && copy[0] < 'a' + input_radix - 10)
+      || (copy[0] >= 'A' && copy[0] < 'A' + input_radix - 10))
+    {
+      YYSTYPE newlval;	/* Its value is ignored.  */
+      int hextype = parse_number (copy, yylval.sval.length, 0, &newlval);
+      if (hextype == INT)
+	return NAME_OR_INT;
+    }
+
+  return NAME;
+}
+
+/* This is taken from c-exp.y mostly to get something working.
+   The basic structure has been kept because we may yet need some of it.  */
+
+static int
+yylex (void)
+{
+  token_and_value current, next;
+
+  if (popping && !VEC_empty (token_and_value, token_fifo))
+    {
+      token_and_value tv = *VEC_index (token_and_value, token_fifo, 0);
+      VEC_ordered_remove (token_and_value, token_fifo, 0);
+      yylval = tv.value;
+      /* There's no need to fall through to handle package.name
+	 as that can never happen here.  In theory.  */
+      return tv.token;
+    }
+  popping = 0;
+
+  current.token = lex_one_token ();
+
+  /* TODO: Need a way to force specifying name1 as a package.
+     .name1.name2 ?  */
+
+  if (current.token != NAME)
+    return current.token;
+
+  /* See if we have "name1 . name2".  */
+
+  current.value = yylval;
+  next.token = lex_one_token ();
+  next.value = yylval;
+
+  if (next.token == '.')
+    {
+      token_and_value name2;
+
+      name2.token = lex_one_token ();
+      name2.value = yylval;
+
+      if (name2.token == NAME)
+	{
+	  /* Ok, we have "name1 . name2".  */
+	  int token;
+	  char *copy;
+
+	  copy = copy_name (current.value.sval);
+
+	  if (strcmp (copy, "unsafe") == 0)
+	    {
+	      popping = 1;
+	      return classify_unsafe_function (name2.value.sval);
+	    }
+
+	  if (package_name_p (copy, expression_context_block))
+	    {
+	      popping = 1;
+	      yylval.sval = build_packaged_name (current.value.sval.ptr,
+						 current.value.sval.length,
+						 name2.value.sval.ptr,
+						 name2.value.sval.length);
+	      return classify_packaged_name (expression_context_block);
+	    }
+	}
+
+      VEC_safe_push (token_and_value, token_fifo, &next);
+      VEC_safe_push (token_and_value, token_fifo, &name2);
+    }
+  else
+    {
+      VEC_safe_push (token_and_value, token_fifo, &next);
+    }
+
+  /* If we arrive here we don't have a package-qualified name.  */
+
+  popping = 1;
+  yylval = current.value;
+  return classify_name (expression_context_block);
+}
+
+int
+go_parse (void)
+{
+  int result;
+  struct cleanup *back_to = make_cleanup (null_cleanup, NULL);
+
+  make_cleanup_restore_integer (&yydebug);
+  yydebug = parser_debug;
+
+  /* Initialize some state used by the lexer.  */
+  last_was_structop = 0;
+  saw_name_at_eof = 0;
+
+  VEC_free (token_and_value, token_fifo);
+  popping = 0;
+  obstack_init (&name_obstack);
+  make_cleanup_obstack_free (&name_obstack);
+
+  result = yyparse ();
+  do_cleanups (back_to);
+  return result;
+}
+
+void
+yyerror (char *msg)
+{
+  if (prev_lexptr)
+    lexptr = prev_lexptr;
+
+  error (_("A %s in expression, near `%s'."), (msg ? msg : "error"), lexptr);
+}
Index: go-lang.c
===================================================================
RCS file: go-lang.c
diff -N go-lang.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ go-lang.c	28 Dec 2011 20:50:31 -0000
@@ -0,0 +1,638 @@
+/* Go language support routines for GDB, the GNU debugger.
+
+   Copyright (C) 2011
+   Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/* TODO:
+   - split stacks
+   - printing of native types
+   - goroutines
+   - lots more
+   - gccgo mangling needs redoing
+     It's too hard, for example, to know whether one is looking at a mangled
+     Go symbol or not, and their are ambiguities, e.g., the demangler may
+     get passed *any* symbol, including symbols from other languages
+     and including symbols that are already demangled.
+     One thought is to at least add an _G prefix.
+   - 6g mangling isn't supported yet
+*/
+
+#include "defs.h"
+#include "gdb_assert.h"
+#include "gdb_obstack.h"
+#include "gdb_string.h"
+#include "block.h"
+#include "symtab.h"
+#include "language.h"
+#include "go-lang.h"
+#include "c-lang.h"
+#include "parser-defs.h"
+
+#include <ctype.h>
+
+/* The main function in the main package.  */
+static const char GO_MAIN_MAIN[] = "main.main";
+
+/* Function returning the special symbol name used by Go for the main
+   procedure in the main program if it is found in minimal symbol list.
+   This function tries to find minimal symbols so that it finds them even
+   if the program was compiled without debugging information.  */
+
+const char *
+go_main_name (void)
+{
+  struct minimal_symbol *msym;
+
+  msym = lookup_minimal_symbol (GO_MAIN_MAIN, NULL, NULL);
+  if (msym != NULL)
+    return GO_MAIN_MAIN;
+
+  /* No known entry procedure found, the main program is probably not Go.  */
+  return NULL;
+}
+
+/* Classify the kind of Go object that TYPE is.
+   TYPE is a TYPE_CODE_STRUCT, used to represent a Go object.  */
+
+enum go_type
+go_classify_struct_type (struct type *type)
+{
+  CHECK_TYPEDEF (type);
+
+  /* TODO(dje): Update when gnugo emits a name for the struct(s).  */
+
+  if (TYPE_NFIELDS (type) == 2)
+    {
+      struct type *type0 = TYPE_FIELD_TYPE (type, 0);
+      struct type *type1 = TYPE_FIELD_TYPE (type, 1);
+
+      CHECK_TYPEDEF (type0);
+      CHECK_TYPEDEF (type1);
+
+      if (TYPE_CODE (type0) == TYPE_CODE_PTR
+	  && strcmp (TYPE_FIELD_NAME (type, 0), "__data") == 0
+	  && TYPE_CODE (type1) == TYPE_CODE_INT
+	  && strcmp (TYPE_FIELD_NAME (type, 1), "__length") == 0)
+	{
+	  struct type *target_type = TYPE_TARGET_TYPE (type0);
+
+	  if (TYPE_CODE (target_type) == TYPE_CODE_INT
+	      && TYPE_LENGTH (target_type) == 1
+	      && strcmp (TYPE_NAME (target_type), "uint8") == 0)
+	    return GO_TYPE_STRING;
+	}
+
+      /* Fall through.  */
+    }
+
+  return GO_TYPE_NONE;
+}
+
+/* Subroutine of unpack_mangled_go_symbol to simplify it.
+   Given "[foo.]bar.baz", store "bar" in *PACKAGEP and "baz" in *OBJECTP.
+   We stomp on the last '.' to nul-terminate "bar".
+   The caller is responsible for memory management.  */
+
+static void
+unpack_package_and_object (char *buf,
+			   const char **packagep, const char **objectp)
+{
+  char *last_dot;
+
+  last_dot = strrchr (buf, '.');
+  gdb_assert (last_dot != NULL);
+  *objectp = last_dot + 1;
+  *last_dot = '\0';
+  last_dot = strrchr (buf, '.');
+  if (last_dot != NULL)
+    *packagep = last_dot + 1;
+  else
+    *packagep = buf;
+}
+
+/* Given a mangled Go symbol, find its package name, object name, and
+   method type (if present).
+   E.g., for "libgo_net.textproto.String.N33_libgo_net.textproto.ProtocolError"
+   *PACKAGEP = "textproto"
+   *OBJECTP = "String"
+   *METHOD_TYPE_PACKAGEP = "textproto"
+   *METHOD_TYPE_OBJECTP = "ProtocolError"
+
+   Space for the resulting strings is malloc'd in one buffer.
+   PACKAGEP,OBJECTP,METHOD_TYPE* will (typically) point into this buffer.
+   [There are a few exceptions, but the caller is still responsible for
+   freeing the resulting pointer.]
+   A pointer to this buffer is returned, or NULL if symbol isn't a
+   mangled Go symbol.
+   The caller is responsible for freeing the result.
+
+   *METHOD_TYPE_IS_POINTERP is set to a boolean indicating if
+   the method type is a pointer.
+
+   There may be value in returning the outer container,
+   i.e., "net" in the above example, but for now it's not needed.
+   Plus it's currently not straightforward to compute,
+   it comes from -fgo-prefix, and there's no algorithm to compute it.
+
+   If we ever need to unpack the method type, this routine should work
+   for that too.
+
+   FIXME: Hacky, but until things solidify it's not worth much more.  */
+
+static char *
+unpack_mangled_go_symbol (const char *mangled_name,
+			  const char **packagep,
+			  const char **objectp,
+			  const char **method_type_packagep,
+			  const char **method_type_objectp,
+			  int *method_type_is_pointerp)
+{
+  char *buf;
+  char *p;
+  int len = strlen (mangled_name);
+  /* Pointer to last digit in "N<digit(s)>_".  */
+  char *saw_digit;
+  /* Pointer to "N" if valid "N<digit(s)>_" found.  */
+  char *method_type;
+  /* Pointer to the first '.'.  */
+  char *first_dot;
+  /* Pointer to the last '.'.  */
+  char *last_dot;
+  /* Non-zero if we saw a pointer indicator.  */
+  int saw_pointer;
+
+  *packagep = *objectp = NULL;
+  *method_type_packagep = *method_type_objectp = NULL;
+  *method_type_is_pointerp = 0;
+
+  /* main.init is mangled specially.  */
+  if (strcmp (mangled_name, "__go_init_main") == 0)
+    {
+      char *package = xstrdup ("main");
+
+      *packagep = package;
+      *objectp = "init";
+      return package;
+    }
+
+  /* main.main is mangled specially (missing prefix).  */
+  if (strcmp (mangled_name, "main.main") == 0)
+    {
+      char *package = xstrdup ("main");
+
+      *packagep = package;
+      *objectp = "main";
+      return package;
+    }
+
+  /* We may get passed, e.g., "main.T.Foo", which is *not* mangled.
+     Alas it looks exactly like "prefix.package.object."
+     To cope for now we only recognize the following prefixes:
+
+     go: the default
+     libgo_.*: used by gccgo's runtime
+
+     Thus we don't support -fgo-prefix (except as used by the runtime).  */
+  if (strncmp (mangled_name, "go.", 3) != 0
+      && strncmp (mangled_name, "libgo_", 6) != 0)
+    return NULL;
+
+  /* Quick check for whether a search may be fruitful.  */
+  /* Ignore anything with @plt, etc. in it.  */
+  if (strchr (mangled_name, '@') != NULL)
+    return NULL;
+  /* It must have at least two dots.  */
+  first_dot = strchr (mangled_name, '.');
+  if (first_dot == NULL)
+    return NULL;
+  /* Treat "foo.bar" as unmangled.  It can collide with lots of other
+     languages and it's not clear what the consequences are.
+     And except for main.main, all gccgo symbols are at least
+     prefix.package.object.  */
+  last_dot = strrchr (mangled_name, '.');
+  if (last_dot == first_dot)
+    return NULL;
+
+  /* More quick checks.  */
+  if (last_dot[1] == '\0' /* foo. */
+      || last_dot[-1] == '.') /* foo..bar */
+    return NULL;
+
+  /* At this point we've decided we have a mangled Go symbol.  */
+
+  buf = xstrdup (mangled_name);
+
+  /* Search backwards looking for "N<digit(s)>".  */
+  p = buf + len;
+  saw_digit = method_type = NULL;
+  saw_pointer = 0;
+  while (p > buf)
+    {
+      int current = *(const unsigned char *) --p;
+      int current_is_digit = isdigit (current);
+
+      if (saw_digit)
+	{
+	  if (current_is_digit)
+	    continue;
+	  if (current == 'N'
+	      && ((p > buf && p[-1] == '.')
+		  || (p > buf + 1 && p[-1] == 'p' && p[-2] == '.')))
+	    {
+	      if (atoi (p + 1) == strlen (saw_digit + 2))
+		{
+		  if (p[-1] == '.')
+		    method_type = p - 1;
+		  else
+		    {
+		      gdb_assert (p[-1] == 'p');
+		      saw_pointer = 1;
+		      method_type = p - 2;
+		    }
+		  break;
+		}
+	    }
+	  /* Not what we're looking for, reset and keep looking.  */
+	  saw_digit = NULL;
+	  saw_pointer = 0;
+	  continue;
+	}
+      if (current_is_digit && p[1] == '_')
+	{
+	  /* Possible start of method "this" [sic] type.  */
+	  saw_digit = p;
+	  continue;
+	}
+    }
+
+  if (method_type != NULL
+      /* Ensure not something like "..foo".  */
+      && (method_type > buf && method_type[-1] != '.'))
+    {
+      unpack_package_and_object (saw_digit + 2,
+				 method_type_packagep, method_type_objectp);
+      *method_type = '\0';
+      *method_type_is_pointerp = saw_pointer;
+    }
+
+  unpack_package_and_object (buf, packagep, objectp);
+  return buf;
+}
+
+/* Implements the la_demangle language_defn routine for language Go.
+
+   N.B. This may get passed *any* symbol, including symbols from other
+   languages and including symbols that are already demangled.
+   Both of these situations are kinda unfortunate, but that's how things
+   are today.
+
+   N.B. This currently only supports gccgo's mangling.
+
+   N.B. gccgo's mangling needs, I think, changing.
+   This demangler can't work in all situations,
+   thus not too much effort is currently put into it.  */
+
+char *
+go_demangle (const char *mangled_name, int options)
+{
+  struct obstack tempbuf;
+  char *result;
+  char *name_buf;
+  const char *package_name;
+  const char *object_name;
+  const char *method_type_package_name;
+  const char *method_type_object_name;
+  int method_type_is_pointer;
+
+  if (mangled_name == NULL)
+    return NULL;
+
+  name_buf = unpack_mangled_go_symbol (mangled_name,
+				       &package_name, &object_name,
+				       &method_type_package_name,
+				       &method_type_object_name,
+				       &method_type_is_pointer);
+  if (name_buf == NULL)
+    return NULL;
+
+  obstack_init (&tempbuf);
+
+  /* Print methods as they appear in "method expressions".  */
+  if (method_type_package_name != NULL)
+    {
+      /* FIXME: Seems like we should include package_name here somewhere.  */
+      if (method_type_is_pointer)
+	  obstack_grow_str (&tempbuf, "(*");
+      obstack_grow_str (&tempbuf, method_type_package_name);
+      obstack_grow_str (&tempbuf, ".");
+      obstack_grow_str (&tempbuf, method_type_object_name);
+      if (method_type_is_pointer)
+	obstack_grow_str (&tempbuf, ")");
+      obstack_grow_str (&tempbuf, ".");
+      obstack_grow_str (&tempbuf, object_name);
+    }
+  else
+    {
+      obstack_grow_str (&tempbuf, package_name);
+      obstack_grow_str (&tempbuf, ".");
+      obstack_grow_str (&tempbuf, object_name);
+    }
+  obstack_grow_str0 (&tempbuf, "");
+
+  result = xstrdup (obstack_finish (&tempbuf));
+  obstack_free (&tempbuf, NULL);
+  xfree (name_buf);
+  return result;
+}
+
+/* Given a Go symbol, return its package or NULL if unknown.
+   Space for the result is malloc'd, caller must free.  */
+
+char *
+go_symbol_package_name (const struct symbol *sym)
+{
+  const char *mangled_name = SYMBOL_LINKAGE_NAME (sym);
+  const char *package_name;
+  const char *object_name;
+  const char *method_type_package_name;
+  const char *method_type_object_name;
+  int method_type_is_pointer;
+  char *name_buf;
+  char *result;
+
+  gdb_assert (SYMBOL_LANGUAGE (sym) == language_go);
+  name_buf = unpack_mangled_go_symbol (mangled_name,
+				       &package_name, &object_name,
+				       &method_type_package_name,
+				       &method_type_object_name,
+				       &method_type_is_pointer);
+  /* Some Go symbols don't have mangled form we interpret (yet).  */
+  if (name_buf == NULL)
+    return NULL;
+  result = xstrdup (package_name);
+  xfree (name_buf);
+  return result;
+}
+
+/* Return the package that BLOCK is in, or NULL if there isn't one.
+   Space for the result is malloc'd, caller must free.  */
+
+char *
+go_block_package_name (const struct block *block)
+{
+  while (block != NULL)
+    {
+      struct symbol *function = BLOCK_FUNCTION (block);
+
+      if (function != NULL)
+	{
+	  char *package_name = go_symbol_package_name (function);
+
+	  if (package_name != NULL)
+	    return package_name;
+
+	  /* Stop looking if we find a function without a package name.
+	     We're most likely outside of Go and thus the concept of the
+	     "current" package is gone.  */
+	  return NULL;
+	}
+
+      block = BLOCK_SUPERBLOCK (block);
+    }
+
+  return NULL;
+}
+
+/* Table mapping opcodes into strings for printing operators
+   and precedences of the operators.
+   TODO(dje): &^ ?  */
+
+static const struct op_print go_op_print_tab[] =
+{
+  {",", BINOP_COMMA, PREC_COMMA, 0},
+  {"=", BINOP_ASSIGN, PREC_ASSIGN, 1},
+  {"||", BINOP_LOGICAL_OR, PREC_LOGICAL_OR, 0},
+  {"&&", BINOP_LOGICAL_AND, PREC_LOGICAL_AND, 0},
+  {"|", BINOP_BITWISE_IOR, PREC_BITWISE_IOR, 0},
+  {"^", BINOP_BITWISE_XOR, PREC_BITWISE_XOR, 0},
+  {"&", BINOP_BITWISE_AND, PREC_BITWISE_AND, 0},
+  {"==", BINOP_EQUAL, PREC_EQUAL, 0},
+  {"!=", BINOP_NOTEQUAL, PREC_EQUAL, 0},
+  {"<=", BINOP_LEQ, PREC_ORDER, 0},
+  {">=", BINOP_GEQ, PREC_ORDER, 0},
+  {">", BINOP_GTR, PREC_ORDER, 0},
+  {"<", BINOP_LESS, PREC_ORDER, 0},
+  {">>", BINOP_RSH, PREC_SHIFT, 0},
+  {"<<", BINOP_LSH, PREC_SHIFT, 0},
+  {"+", BINOP_ADD, PREC_ADD, 0},
+  {"-", BINOP_SUB, PREC_ADD, 0},
+  {"*", BINOP_MUL, PREC_MUL, 0},
+  {"/", BINOP_DIV, PREC_MUL, 0},
+  {"%", BINOP_REM, PREC_MUL, 0},
+  {"@", BINOP_REPEAT, PREC_REPEAT, 0},
+  {"-", UNOP_NEG, PREC_PREFIX, 0},
+  {"!", UNOP_LOGICAL_NOT, PREC_PREFIX, 0},
+  {"^", UNOP_COMPLEMENT, PREC_PREFIX, 0},
+  {"*", UNOP_IND, PREC_PREFIX, 0},
+  {"&", UNOP_ADDR, PREC_PREFIX, 0},
+  {"unsafe.Sizeof ", UNOP_SIZEOF, PREC_PREFIX, 0},
+  {"++", UNOP_POSTINCREMENT, PREC_SUFFIX, 0},
+  {"--", UNOP_POSTDECREMENT, PREC_SUFFIX, 0},
+  {NULL, 0, 0, 0}
+};
+
+enum go_primitive_types {
+  go_primitive_type_void,
+  go_primitive_type_char,
+  go_primitive_type_bool,
+  go_primitive_type_int,
+  go_primitive_type_uint,
+  go_primitive_type_uintptr,
+  go_primitive_type_int8,
+  go_primitive_type_int16,
+  go_primitive_type_int32,
+  go_primitive_type_int64,
+  go_primitive_type_uint8,
+  go_primitive_type_uint16,
+  go_primitive_type_uint32,
+  go_primitive_type_uint64,
+  go_primitive_type_float32,
+  go_primitive_type_float64,
+  go_primitive_type_complex64,
+  go_primitive_type_complex128,
+  nr_go_primitive_types
+};
+
+static void
+go_language_arch_info (struct gdbarch *gdbarch,
+		       struct language_arch_info *lai)
+{
+  const struct builtin_go_type *builtin = builtin_go_type (gdbarch);
+
+  lai->string_char_type = builtin->builtin_char;
+
+  lai->primitive_type_vector
+    = GDBARCH_OBSTACK_CALLOC (gdbarch, nr_go_primitive_types + 1,
+			      struct type *);
+
+  lai->primitive_type_vector [go_primitive_type_void]
+    = builtin->builtin_void;
+  lai->primitive_type_vector [go_primitive_type_char]
+    = builtin->builtin_char;
+  lai->primitive_type_vector [go_primitive_type_bool]
+    = builtin->builtin_bool;
+  lai->primitive_type_vector [go_primitive_type_int]
+    = builtin->builtin_int;
+  lai->primitive_type_vector [go_primitive_type_uint]
+    = builtin->builtin_uint;
+  lai->primitive_type_vector [go_primitive_type_uintptr]
+    = builtin->builtin_uintptr;
+  lai->primitive_type_vector [go_primitive_type_int8]
+    = builtin->builtin_int8;
+  lai->primitive_type_vector [go_primitive_type_int16]
+    = builtin->builtin_int16;
+  lai->primitive_type_vector [go_primitive_type_int32]
+    = builtin->builtin_int32;
+  lai->primitive_type_vector [go_primitive_type_int64]
+    = builtin->builtin_int64;
+  lai->primitive_type_vector [go_primitive_type_uint8]
+    = builtin->builtin_uint8;
+  lai->primitive_type_vector [go_primitive_type_uint16]
+    = builtin->builtin_uint16;
+  lai->primitive_type_vector [go_primitive_type_uint32]
+    = builtin->builtin_uint32;
+  lai->primitive_type_vector [go_primitive_type_uint64]
+    = builtin->builtin_uint64;
+  lai->primitive_type_vector [go_primitive_type_float32]
+    = builtin->builtin_float32;
+  lai->primitive_type_vector [go_primitive_type_float64]
+    = builtin->builtin_float64;
+  lai->primitive_type_vector [go_primitive_type_complex64]
+    = builtin->builtin_complex64;
+  lai->primitive_type_vector [go_primitive_type_complex128]
+    = builtin->builtin_complex128;
+
+  lai->bool_type_symbol = "bool";
+  lai->bool_type_default = builtin->builtin_bool;
+}
+
+static const struct language_defn go_language_defn =
+{
+  "go",
+  language_go,
+  range_check_off,
+  type_check_off,
+  case_sensitive_on,
+  array_row_major,
+  macro_expansion_no,
+  &exp_descriptor_c,
+  go_parse,
+  go_error,
+  null_post_parser,
+  c_printchar,			/* Print a character constant.  */
+  c_printstr,			/* Function to print string constant.  */
+  c_emit_char,			/* Print a single char.  */
+  go_print_type,		/* Print a type using appropriate syntax.  */
+  c_print_typedef,		/* Print a typedef using appropriate
+				   syntax.  */
+  go_val_print,			/* Print a value using appropriate syntax.  */
+  c_value_print,		/* Print a top-level value.  */
+  NULL,				/* Language specific skip_trampoline.  */
+  NULL,				/* name_of_this */
+  basic_lookup_symbol_nonlocal, 
+  basic_lookup_transparent_type,
+  go_demangle,			/* Language specific symbol demangler.  */
+  NULL,				/* Language specific
+				   class_name_from_physname.  */
+  go_op_print_tab,		/* Expression operators for printing.  */
+  1,				/* C-style arrays.  */
+  0,				/* String lower bound.  */
+  default_word_break_characters,
+  default_make_symbol_completion_list,
+  go_language_arch_info,
+  default_print_array_index,
+  default_pass_by_reference,
+  c_get_string,
+  strcmp_iw_ordered,
+  iterate_over_symbols,
+  LANG_MAGIC
+};
+
+static void *
+build_go_types (struct gdbarch *gdbarch)
+{
+  struct builtin_go_type *builtin_go_type
+    = GDBARCH_OBSTACK_ZALLOC (gdbarch, struct builtin_go_type);
+
+  builtin_go_type->builtin_void
+    = arch_type (gdbarch, TYPE_CODE_VOID, 1, "void");
+  builtin_go_type->builtin_char
+    = arch_character_type (gdbarch, 8, 1, "char");
+  builtin_go_type->builtin_bool
+    = arch_boolean_type (gdbarch, 8, 0, "bool");
+  builtin_go_type->builtin_int
+    = arch_integer_type (gdbarch, gdbarch_int_bit (gdbarch), 0, "int");
+  builtin_go_type->builtin_uint
+    = arch_integer_type (gdbarch, gdbarch_int_bit (gdbarch), 1, "uint");
+  builtin_go_type->builtin_uintptr
+    = arch_integer_type (gdbarch, gdbarch_ptr_bit (gdbarch), 1, "uintptr");
+  builtin_go_type->builtin_int8
+    = arch_integer_type (gdbarch, 8, 0, "int8");
+  builtin_go_type->builtin_int16
+    = arch_integer_type (gdbarch, 16, 0, "int16");
+  builtin_go_type->builtin_int32
+    = arch_integer_type (gdbarch, 32, 0, "int32");
+  builtin_go_type->builtin_int64
+    = arch_integer_type (gdbarch, 64, 0, "int64");
+  builtin_go_type->builtin_uint8
+    = arch_integer_type (gdbarch, 8, 1, "uint8");
+  builtin_go_type->builtin_uint16
+    = arch_integer_type (gdbarch, 16, 1, "uint16");
+  builtin_go_type->builtin_uint32
+    = arch_integer_type (gdbarch, 32, 1, "uint32");
+  builtin_go_type->builtin_uint64
+    = arch_integer_type (gdbarch, 64, 1, "uint64");
+  builtin_go_type->builtin_float32
+    = arch_float_type (gdbarch, 32, "float32", NULL);
+  builtin_go_type->builtin_float64
+    = arch_float_type (gdbarch, 64, "float64", NULL);
+  builtin_go_type->builtin_complex64
+    = arch_complex_type (gdbarch, "complex64",
+			 builtin_go_type->builtin_float32);
+  builtin_go_type->builtin_complex128
+    = arch_complex_type (gdbarch, "complex128",
+			 builtin_go_type->builtin_float64);
+
+  return builtin_go_type;
+}
+
+static struct gdbarch_data *go_type_data;
+
+const struct builtin_go_type *
+builtin_go_type (struct gdbarch *gdbarch)
+{
+  return gdbarch_data (gdbarch, go_type_data);
+}
+
+void
+_initialize_go_language (void)
+{
+  go_type_data = gdbarch_data_register_post_init (build_go_types);
+
+  add_language (&go_language_defn);
+}
Index: go-lang.h
===================================================================
RCS file: go-lang.h
diff -N go-lang.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ go-lang.h	28 Dec 2011 20:50:31 -0000
@@ -0,0 +1,89 @@
+/* Go language support definitions for GDB, the GNU debugger.
+
+   Copyright (C) 2011
+   Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#if !defined (GO_LANG_H)
+#define GO_LANG_H 1
+
+#include "gdbtypes.h"
+#include "symtab.h"
+#include "value.h"
+
+struct builtin_go_type
+{
+  struct type *builtin_void;
+  struct type *builtin_char;
+  struct type *builtin_bool;
+  struct type *builtin_int;
+  struct type *builtin_uint;
+  struct type *builtin_uintptr;
+  struct type *builtin_int8;
+  struct type *builtin_int16;
+  struct type *builtin_int32;
+  struct type *builtin_int64;
+  struct type *builtin_uint8;
+  struct type *builtin_uint16;
+  struct type *builtin_uint32;
+  struct type *builtin_uint64;
+  struct type *builtin_float32;
+  struct type *builtin_float64;
+  struct type *builtin_complex64;
+  struct type *builtin_complex128;
+};
+
+enum go_type
+{
+  GO_TYPE_NONE, /* Not a Go object.  */
+  GO_TYPE_STRING
+};
+
+/* Defined in go-exp.y.  */
+
+extern int go_parse (void);
+
+extern void go_error (char *);
+
+/* Defined in go-lang.c.  */
+
+extern const char *go_main_name (void);
+
+extern enum go_type go_classify_struct_type (struct type *type);
+
+extern char *go_demangle (const char *mangled, int options);
+
+extern char *go_symbol_package_name (const struct symbol *sym);
+
+extern char *go_block_package_name (const struct block *block);
+
+extern const struct builtin_go_type *builtin_go_type (struct gdbarch *);
+
+/* Defined in go-typeprint.c.  */
+
+extern void go_print_type (struct type *type, const char *varstring,
+			   struct ui_file *stream, int show, int level);
+
+/* Defined in go-valprint.c.  */
+
+extern int go_val_print (struct type *type, const gdb_byte *valaddr,
+			int embedded_offset, CORE_ADDR address,
+			struct ui_file *stream, int recurse,
+			const struct value *val,
+			const struct value_print_options *options);
+
+#endif /* !defined (GO_LANG_H) */
Index: go-typeprint.c
===================================================================
RCS file: go-typeprint.c
diff -N go-typeprint.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ go-typeprint.c	28 Dec 2011 20:50:31 -0000
@@ -0,0 +1,61 @@
+/* Support for printing Go types for GDB, the GNU debugger.
+   Copyright (C) 2011 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/* TODO:
+   - lots
+   - if the more complex types get Python pretty-printers, we'll
+     want a Python API for type printing
+*/
+
+#include "defs.h"
+#include "gdbtypes.h"
+#include "c-lang.h"
+#include "go-lang.h"
+
+/* Print a description of a type TYPE.
+   Output goes to STREAM (via stdio).
+   If VARSTRING is a non-empty string, print as an Ada variable/field
+       declaration.
+   SHOW+1 is the maximum number of levels of internal type structure
+      to show (this applies to record types, enumerated types, and
+      array types).
+   SHOW is the number of levels of internal type structure to show
+      when there is a type name for the SHOWth deepest level (0th is
+      outer level).
+   When SHOW<0, no inner structure is shown.
+   LEVEL indicates level of recursion (for nested definitions).  */
+
+void
+go_print_type (struct type *type, const char *varstring,
+	       struct ui_file *stream, int show, int level)
+{
+  /* Borrowed from c-typeprint.c.  */
+  if (show > 0)
+    CHECK_TYPEDEF (type);
+
+  /* Print the type of "abc" as "string", not char[4].  */
+  if (TYPE_CODE (type) == TYPE_CODE_ARRAY
+      && TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_CHAR)
+    {
+      fputs_filtered ("string", stream);
+      return;
+    }
+
+  /* Punt the rest to C for now.  */
+  c_print_type (type, varstring, stream, show, level);
+}
Index: go-valprint.c
===================================================================
RCS file: go-valprint.c
diff -N go-valprint.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ go-valprint.c	28 Dec 2011 20:50:31 -0000
@@ -0,0 +1,117 @@
+/* Support for printing Go values for GDB, the GNU debugger.
+
+   Copyright (C) 2011 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+   NOTE: This currently only provides special support for printing gccgo
+   strings.  6g objects are handled in Python.
+   The remaining gccgo types may also be handled in Python.
+   Strings are handled specially here, at least for now, in case the Python
+   support is unavailable.  */
+
+#include "defs.h"
+#include "gdbtypes.h"
+#include "gdbcore.h"
+#include "go-lang.h"
+#include "c-lang.h"
+#include "valprint.h"
+
+/* Print a Go string.
+
+   Note: We assume
+   gdb_assert (go_classify_struct_type (type) == GO_TYPE_STRING).  */
+
+static int
+print_go_string (struct type *type, const gdb_byte *valaddr,
+		 int embedded_offset, CORE_ADDR address,
+		 struct ui_file *stream, int recurse,
+		 const struct value *val,
+		 const struct value_print_options *options)
+{
+  struct gdbarch *gdbarch = get_type_arch (type);
+  int i; /* Number of characters printed.  */
+  struct type *elt_ptr_type = TYPE_FIELD_TYPE (type, 0);
+  struct type *elt_type = TYPE_TARGET_TYPE (elt_ptr_type);
+  LONGEST length;
+  /* TODO(dje): The encapsulation of what a pointer is belongs in value.c.
+     I.e. If there's going to be unpack_pointer, there should be
+     unpack_value_field_as_pointer.  Do this until we can get
+     unpack_value_field_as_pointer.  */
+  LONGEST addr;
+
+  gdb_assert (valaddr == value_contents_for_printing_const (val));
+
+  if (! unpack_value_field_as_long (type, valaddr, embedded_offset, 0,
+				    val, &addr))
+    error (_("Unable to read string address"));
+
+  if (! unpack_value_field_as_long (type, valaddr, embedded_offset, 1,
+				    val, &length))
+    error (_("Unable to read string length"));
+
+  if (length < 0)
+    error (_("Invalid length"));
+
+  /* TODO(dje): Print address of struct or actual string?  */
+  if (options->addressprint)
+    fputs_filtered (paddress (gdbarch, addr), stream);
+
+  /* TODO(dje): Perhaps we should pass "UTF8" for ENCODING.
+     The target encoding is a global switch.
+     Either choice is problematic.  */
+  i = val_print_string (elt_type, NULL, addr, length, stream, options);
+
+  return i;
+}
+
+/* Implements the la_val_print routine for language Go.  */
+
+int
+go_val_print (struct type *type, const gdb_byte *valaddr, int embedded_offset,
+	      CORE_ADDR address, struct ui_file *stream, int recurse,
+	      const struct value *val,
+	      const struct value_print_options *options)
+{
+  int ret;
+
+  CHECK_TYPEDEF (type);
+
+  switch (TYPE_CODE (type))
+    {
+      case TYPE_CODE_STRUCT:
+	{
+	  enum go_type go_type = go_classify_struct_type (type);
+
+	  switch (go_type)
+	    {
+	    case GO_TYPE_STRING:
+	      return print_go_string (type, valaddr, embedded_offset, address,
+				      stream, recurse, val, options);
+	    default:
+	      break;
+	    }
+	}
+	/* Fall through.  */
+
+      default:
+	ret = c_val_print (type, valaddr, embedded_offset, address, stream,
+			   recurse, val, options);
+	break;
+    }
+
+  return ret;
+}
Index: symtab.c
===================================================================
RCS file: /cvs/src/src/gdb/symtab.c,v
retrieving revision 1.288
diff -u -p -r1.288 symtab.c
--- symtab.c	6 Dec 2011 18:54:39 -0000	1.288
+++ symtab.c	28 Dec 2011 20:50:31 -0000
@@ -41,6 +41,7 @@
 #include "objc-lang.h"
 #include "d-lang.h"
 #include "ada-lang.h"
+#include "go-lang.h"
 #include "p-lang.h"
 #include "addrmap.h"
 
@@ -464,6 +465,7 @@ symbol_set_language (struct general_symb
 {
   gsymbol->language = language;
   if (gsymbol->language == language_d
+      || gsymbol->language == language_go
       || gsymbol->language == language_java
       || gsymbol->language == language_objc
       || gsymbol->language == language_fortran)
@@ -582,6 +584,22 @@ symbol_find_demangled_name (struct gener
 	  return demangled;
 	}
     }
+  /* FIXME(dje): Continually adding languages here is clumsy.
+     Better to just call la_demangle if !auto, and if auto then call
+     a utility routine that tries successive languages in turn and reports
+     which one it finds.  I realize the la_demangle options may be different
+     for different languages but there's already a FIXME for that.  */
+  if (gsymbol->language == language_go
+      || gsymbol->language == language_auto)
+    {
+      demangled = go_demangle (mangled, 0);
+      if (demangled != NULL)
+	{
+	  gsymbol->language = language_go;
+	  return demangled;
+	}
+    }
+
   /* We could support `gsymbol->language == language_fortran' here to provide
      module namespaces also for inferiors with only minimal symbol table (ELF
      symbols).  Just the mangling standard is not standardized across compilers
@@ -702,7 +720,11 @@ symbol_set_names (struct general_symbol_
 			  &entry, INSERT));
 
   /* If this name is not in the hash table, add it.  */
-  if (*slot == NULL)
+  if (*slot == NULL
+      /* A C version of the symbol may have already snuck into the table.
+	 This happens to, e.g., main.init (__go_init_main).  Cope.  */
+      || (gsymbol->language == language_go
+	  && (*slot)->demangled[0] == '\0'))
     {
       char *demangled_name = symbol_find_demangled_name (gsymbol,
 							 linkage_name_copy);
@@ -764,6 +786,7 @@ symbol_natural_name (const struct genera
     {
     case language_cplus:
     case language_d:
+    case language_go:
     case language_java:
     case language_objc:
     case language_fortran:
@@ -784,6 +807,7 @@ symbol_natural_name (const struct genera
 
 /* Return the demangled name for a symbol based on the language for
    that symbol.  If no demangled name exists, return NULL.  */
+
 char *
 symbol_demangled_name (const struct general_symbol_info *gsymbol)
 {
@@ -791,6 +815,7 @@ symbol_demangled_name (const struct gene
     {
     case language_cplus:
     case language_d:
+    case language_go:
     case language_java:
     case language_objc:
     case language_fortran:
@@ -1080,7 +1105,7 @@ demangle_for_lookup (const char *name, e
 
   modified_name = name;
 
-  /* If we are using C++, D, or Java, demangle the name before doing a
+  /* If we are using C++, D, Go, or Java, demangle the name before doing a
      lookup, so we can always binary search.  */
   if (lang == language_cplus)
     {
@@ -1121,6 +1146,15 @@ demangle_for_lookup (const char *name, e
 	  make_cleanup (xfree, demangled_name);
 	}
     }
+  else if (lang == language_go)
+    {
+      demangled_name = go_demangle (name, 0);
+      if (demangled_name)
+	{
+	  modified_name = demangled_name;
+	  make_cleanup (xfree, demangled_name);
+	}
+    }
 
   *result_name = modified_name;
   return cleanup;
@@ -4745,6 +4779,13 @@ find_main_name (void)
       return;
     }
 
+  new_main_name = go_main_name ();
+  if (new_main_name != NULL)
+    {
+      set_main_name (new_main_name);
+      return;
+    }
+
   new_main_name = pascal_main_name ();
   if (new_main_name != NULL)
     {
Index: doc/gdb.texinfo
===================================================================
RCS file: /cvs/src/src/gdb/doc/gdb.texinfo,v
retrieving revision 1.908
diff -u -p -r1.908 gdb.texinfo
--- doc/gdb.texinfo	23 Dec 2011 17:06:13 -0000	1.908
+++ doc/gdb.texinfo	28 Dec 2011 20:50:34 -0000
@@ -12192,8 +12192,8 @@ being set automatically by @value{GDBN}.
 @node Supported Languages
 @section Supported Languages
 
-@value{GDBN} supports C, C@t{++}, D, Objective-C, Fortran, Java, OpenCL C, Pascal,
-assembly, Modula-2, and Ada.
+@value{GDBN} supports C, C@t{++}, D, Go, Objective-C, Fortran, Java,
+OpenCL C, Pascal, assembly, Modula-2, and Ada.
 @c This is false ...
 Some @value{GDBN} features may be used in expressions regardless of the
 language you use: the @value{GDBN} @code{@@} and @code{::} operators,
@@ -12212,6 +12212,7 @@ language reference or tutorial.
 @menu
 * C::                           C and C@t{++}
 * D::                           D
+* Go::                          Go
 * Objective-C::                 Objective-C
 * OpenCL C::                    OpenCL C
 * Fortran::                     Fortran
@@ -12758,6 +12759,14 @@ See @ref{PowerPC,,PowerPC} for more deta
 GDC, LDC or DMD compilers. Currently @value{GDBN} supports only one D
 specific feature --- dynamic arrays.
 
+@node Go
+@subsection Go
+
+@cindex Go
+@value{GDBN} can be used to debug programs written in Go and compiled with
+@file{gccgo} or @file{6g} compilers.
+Support for Go specific features is still work-in-progress.
+
 @node Objective-C
 @subsection Objective-C
 
Index: testsuite/configure
===================================================================
RCS file: /cvs/src/src/gdb/testsuite/configure,v
retrieving revision 1.38
diff -u -p -r1.38 configure
--- testsuite/configure	6 Dec 2011 18:54:41 -0000	1.38
+++ testsuite/configure	28 Dec 2011 20:50:34 -0000
@@ -3448,7 +3448,7 @@ done
 
 
 
-ac_config_files="$ac_config_files Makefile gdb.ada/Makefile gdb.arch/Makefile gdb.asm/Makefile gdb.base/Makefile gdb.cell/Makefile gdb.cp/Makefile gdb.disasm/Makefile gdb.dwarf2/Makefile gdb.fortran/Makefile gdb.server/Makefile gdb.java/Makefile gdb.hp/Makefile gdb.hp/gdb.objdbg/Makefile gdb.hp/gdb.base-hp/Makefile gdb.hp/gdb.aCC/Makefile gdb.hp/gdb.compat/Makefile gdb.hp/gdb.defects/Makefile gdb.linespec/Makefile gdb.mi/Makefile gdb.modula2/Makefile gdb.multi/Makefile gdb.objc/Makefile gdb.opencl/Makefile gdb.opt/Makefile gdb.pascal/Makefile gdb.python/Makefile gdb.reverse/Makefile gdb.stabs/Makefile gdb.threads/Makefile gdb.trace/Makefile gdb.xml/Makefile"
+ac_config_files="$ac_config_files Makefile gdb.ada/Makefile gdb.arch/Makefile gdb.asm/Makefile gdb.base/Makefile gdb.cell/Makefile gdb.cp/Makefile gdb.disasm/Makefile gdb.dwarf2/Makefile gdb.fortran/Makefile gdb.go/Makefile gdb.server/Makefile gdb.java/Makefile gdb.hp/Makefile gdb.hp/gdb.objdbg/Makefile gdb.hp/gdb.base-hp/Makefile gdb.hp/gdb.aCC/Makefile gdb.hp/gdb.compat/Makefile gdb.hp/gdb.defects/Makefile gdb.linespec/Makefile gdb.mi/Makefile gdb.modula2/Makefile gdb.multi/Makefile gdb.objc/Makefile gdb.opencl/Makefile gdb.opt/Makefile gdb.pascal/Makefile gdb.python/Makefile gdb.reverse/Makefile gdb.stabs/Makefile gdb.threads/Makefile gdb.trace/Makefile gdb.xml/Makefile"
 
 cat >confcache <<\_ACEOF
 # This file is a shell script that caches the results of configure
@@ -4158,6 +4158,7 @@ do
     "gdb.disasm/Makefile") CONFIG_FILES="$CONFIG_FILES gdb.disasm/Makefile" ;;
     "gdb.dwarf2/Makefile") CONFIG_FILES="$CONFIG_FILES gdb.dwarf2/Makefile" ;;
     "gdb.fortran/Makefile") CONFIG_FILES="$CONFIG_FILES gdb.fortran/Makefile" ;;
+    "gdb.go/Makefile") CONFIG_FILES="$CONFIG_FILES gdb.go/Makefile" ;;
     "gdb.server/Makefile") CONFIG_FILES="$CONFIG_FILES gdb.server/Makefile" ;;
     "gdb.java/Makefile") CONFIG_FILES="$CONFIG_FILES gdb.java/Makefile" ;;
     "gdb.hp/Makefile") CONFIG_FILES="$CONFIG_FILES gdb.hp/Makefile" ;;
Index: testsuite/configure.ac
===================================================================
RCS file: /cvs/src/src/gdb/testsuite/configure.ac,v
retrieving revision 1.21
diff -u -p -r1.21 configure.ac
--- testsuite/configure.ac	6 Dec 2011 18:54:41 -0000	1.21
+++ testsuite/configure.ac	28 Dec 2011 20:50:34 -0000
@@ -92,7 +92,7 @@ AC_OUTPUT([Makefile \
   gdb.ada/Makefile \
   gdb.arch/Makefile gdb.asm/Makefile gdb.base/Makefile \
   gdb.cell/Makefile gdb.cp/Makefile gdb.disasm/Makefile gdb.dwarf2/Makefile \
-  gdb.fortran/Makefile gdb.server/Makefile gdb.java/Makefile \
+  gdb.fortran/Makefile gdb.go/Makefile gdb.server/Makefile gdb.java/Makefile \
   gdb.hp/Makefile gdb.hp/gdb.objdbg/Makefile gdb.hp/gdb.base-hp/Makefile \
   gdb.hp/gdb.aCC/Makefile gdb.hp/gdb.compat/Makefile \
   gdb.hp/gdb.defects/Makefile gdb.linespec/Makefile \
Index: testsuite/gdb.base/default.exp
===================================================================
RCS file: /cvs/src/src/gdb/testsuite/gdb.base/default.exp,v
retrieving revision 1.51
diff -u -p -r1.51 default.exp
--- testsuite/gdb.base/default.exp	3 Dec 2011 20:20:29 -0000	1.51
+++ testsuite/gdb.base/default.exp	28 Dec 2011 20:50:34 -0000
@@ -533,7 +533,7 @@ gdb_test "set history size" "Argument re
 #test set history
 gdb_test "set history" "\"set history\" must be followed by the name of a history subcommand.(\[^\r\n\]*\[\r\n\])+List of set history subcommands:(\[^\r\n\]*\[\r\n\])+set history expansion -- Set history expansion on command input(\[^\r\n\]*\[\r\n\])+set history filename -- Set the filename in which to record the command history(\[^\r\n\]*\[\r\n\])+set history save -- Set saving of the history record on exit(\[^\r\n\]*\[\r\n\])+set history size -- Set the size of the command history(\[^\r\n\]*\[\r\n\])+Type \"help set history\" followed by set history subcommand name for full documentation.(\[^\r\n\]*\[\r\n\])+Command name abbreviations are allowed if unambiguous." "set history"
 #test set language
-gdb_test "set language" "Requires an argument. Valid arguments are auto, local, unknown, ada, c, c.., asm, minimal, d, fortran, objective-c, java, modula-2, opencl, pascal." "set language"
+gdb_test "set language" "Requires an argument. Valid arguments are auto, local, unknown, ada, c, c.., asm, minimal, d, fortran, objective-c, go, java, modula-2, opencl, pascal." "set language"
 #test set listsize
 gdb_test "set listsize" "Argument required .integer to set it to.*" "set listsize"
 #test set print "p" abbreviation
Index: testsuite/gdb.go/Makefile.in
===================================================================
RCS file: testsuite/gdb.go/Makefile.in
diff -N testsuite/gdb.go/Makefile.in
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ testsuite/gdb.go/Makefile.in	28 Dec 2011 20:50:34 -0000
@@ -0,0 +1,20 @@
+VPATH = @srcdir@
+srcdir = @srcdir@
+
+EXECUTABLES = \
+	chan handcall hello integers methods package \
+	strings types unsafe
+
+all info install-info dvi install uninstall installcheck check:
+	@echo "Nothing to be done for $@..."
+
+clean mostlyclean:
+	-find . -name '*.o' -print | xargs rm -f
+	-find . -name '*.ali' -print | xargs rm -f
+	-rm -f *~ a.out
+	-rm -f core core.coremaker coremaker.core corefile $(EXECUTABLES)
+
+distclean maintainer-clean realclean: clean
+	-rm -f Makefile config.status config.log
+	-rm -f *-init.exp gdb.log gdb.sum
+	-rm -fr *.log summary detail *.plog *.sum *.psum site.*
Index: testsuite/gdb.go/basic-types.exp
===================================================================
RCS file: testsuite/gdb.go/basic-types.exp
diff -N testsuite/gdb.go/basic-types.exp
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ testsuite/gdb.go/basic-types.exp	28 Dec 2011 20:50:34 -0000
@@ -0,0 +1,118 @@
+# This testcase is part of GDB, the GNU debugger.
+
+# Copyright 2011 Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Test basic builtin types.
+# NOTE: The tests here intentionally do not require a go compiler.
+
+load_lib "go.exp"
+
+if { [skip_go_tests] } { continue }
+
+proc test_integer_literal_types_accepted {} {
+    # Test various decimal values.
+
+    gdb_test "pt 123" "type = int" 
+
+    gdb_test "pt void(42)" "type = void"
+    gdb_test "pt byte(42)" "type = uint8"
+    gdb_test "pt int(42)" "type = int"
+    gdb_test "pt uint(42)" "type = uint"
+    gdb_test "pt uintptr(42)" "type = uintptr"
+
+    gdb_test "pt int8(42)" "type = int8"
+    gdb_test "pt int16(42)" "type = int16"
+    gdb_test "pt int32(42)" "type = int32"
+    gdb_test "pt int64(42)" "type = int64"
+
+    gdb_test "pt uint8(42)" "type = uint8"
+    gdb_test "pt uint16(42)" "type = uint16"
+    gdb_test "pt uint32(42)" "type = uint32"
+    gdb_test "pt uint64(42)" "type = uint64"
+}
+
+proc test_logical_literal_types_accepted {} {
+    # Test the only possible values for a logical, TRUE and FALSE.
+
+    gdb_test "pt true" "type = bool"
+    gdb_test "pt false" "type = bool"
+
+    gdb_test "pt bool(0)" "type = bool"
+    gdb_test "pt bool(1)" "type = bool"
+}
+
+proc test_character_literal_types_accepted {} {
+    # Test various character values.
+
+    gdb_test "pt 'a'" "type = char"
+
+    # FIXME: Need more.
+}
+
+proc test_string_literal_types_accepted {} {
+    # Test various character values.
+
+    gdb_test "pt \"a simple string\"" "type = string"
+    gdb_test "pt `a simple raw string`" "type = string"
+
+    # FIXME: Need more.
+}
+
+proc test_float_literal_types_accepted {} {
+    # Test various floating point formats.
+
+    gdb_test "pt .44" "type = float64"
+    gdb_test "pt 44.0" "type = float64"
+    gdb_test "pt 10e20" "type = float64"
+    gdb_test "pt 10E20" "type = float64"
+
+    gdb_test "pt float32(.42)" "type = float32"
+
+    gdb_test "pt float64(.42)" "type = float64"
+}
+
+proc test_complex_literal_types_accepted {} {
+    # Test various complex formats.
+
+    gdb_test "pt complex64(.42)" "type = complex64"
+    setup_xfail "*-*-*"
+    gdb_test "pt complex64(.42i1.0)" "type = complex64"
+    setup_xfail "*-*-*"
+    gdb_test "pt complex64(i1.0)" "type = complex64"
+
+    gdb_test "pt complex128(.42)" "type = complex128"
+    setup_xfail "*-*-*"
+    gdb_test "pt complex128(.42i1.0)" "type = complex128"
+    setup_xfail "*-*-*"
+    gdb_test "pt complex128(i1.0)" "type = complex128"
+}
+
+# Start with a fresh gdb.
+
+gdb_exit
+gdb_start
+gdb_reinitialize_dir $srcdir/$subdir
+
+if [set_lang_go] {
+    test_integer_literal_types_accepted
+    test_logical_literal_types_accepted
+    test_character_literal_types_accepted
+    test_string_literal_types_accepted
+    test_float_literal_types_accepted
+    test_complex_literal_types_accepted
+} else {
+    warning "Go type tests suppressed."
+}
Index: testsuite/gdb.go/chan.exp
===================================================================
RCS file: testsuite/gdb.go/chan.exp
diff -N testsuite/gdb.go/chan.exp
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ testsuite/gdb.go/chan.exp	28 Dec 2011 20:50:34 -0000
@@ -0,0 +1,52 @@
+# This testcase is part of GDB, the GNU debugger.
+
+# Copyright 2011 Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Basic channel tests.
+# This is very much a work-in-progress.
+
+load_lib "go.exp"
+
+if { [skip_go_tests] } { continue }
+
+set testfile "chan"
+set srcfile ${testfile}.go
+
+if { [prepare_for_testing ${testfile}.exp ${testfile} ${srcfile} {debug go}] } {
+    return -1
+}
+
+set bp_location1 [gdb_get_line_number "set breakpoint 1 here"]
+set bp_location2 [gdb_get_line_number "set breakpoint 2 here"]
+
+if { [go_runto_main] < 0 } {
+    untested $testfile
+    return -1
+}
+
+if { [gdb_breakpoint ${srcfile}:${bp_location1}] } {
+    pass "setting breakpoint 1"
+}
+
+gdb_test "cont" "Breakpoint .*:${bp_location1}.*" "Going to first breakpoint"
+
+gdb_test_no_output "disable"
+
+if { [gdb_breakpoint ${srcfile}:${bp_location2}] } {
+    pass "setting breakpoint 2"
+}
+
+gdb_test "cont" "Breakpoint .*:${bp_location2}.*" "Going to second breakpoint"
Index: testsuite/gdb.go/chan.go
===================================================================
RCS file: testsuite/gdb.go/chan.go
diff -N testsuite/gdb.go/chan.go
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ testsuite/gdb.go/chan.go	28 Dec 2011 20:50:34 -0000
@@ -0,0 +1,35 @@
+// Copyright 2011 Free Software Foundation, Inc.
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+package main
+
+import "fmt"
+
+func generate() chan int {
+    ch := make(chan int)
+    go func() {
+        for i := 0; ; i++ {
+            ch <- i // set breakpoint 1 here
+        }
+    }()
+    return ch
+}
+
+func main() {
+    integers := generate()
+    for i := 0; i < 100; i++ { // Print the first hundred integers.
+        fmt.Println(<-integers) // set breakpoint 2 here
+    }
+}
Index: testsuite/gdb.go/handcall.exp
===================================================================
RCS file: testsuite/gdb.go/handcall.exp
diff -N testsuite/gdb.go/handcall.exp
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ testsuite/gdb.go/handcall.exp	28 Dec 2011 20:50:34 -0000
@@ -0,0 +1,45 @@
+# This testcase is part of GDB, the GNU debugger.
+
+# Copyright 2011 Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Test hand-calling go functions.
+
+load_lib "go.exp"
+
+if { [skip_go_tests] } { continue }
+
+set testfile "handcall"
+set srcfile ${testfile}.go
+
+if { [prepare_for_testing ${testfile}.exp ${testfile} ${srcfile} {debug go}] } {
+    return -1
+}
+
+set bp_location1 [gdb_get_line_number "set breakpoint 1 here"]
+
+if { [go_runto_main] < 0 } {
+    untested $testfile
+    return -1
+}
+
+if { [gdb_breakpoint ${srcfile}:${bp_location1}] } {
+    pass "setting breakpoint 1"
+}
+
+gdb_test "cont" "Breakpoint .*:${bp_location1}.*" "Going to first breakpoint"
+
+gdb_test "print add (1, 2)" " = 3"
+gdb_test "print main.add (1, 2)" " = 3"
Index: testsuite/gdb.go/handcall.go
===================================================================
RCS file: testsuite/gdb.go/handcall.go
diff -N testsuite/gdb.go/handcall.go
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ testsuite/gdb.go/handcall.go	28 Dec 2011 20:50:34 -0000
@@ -0,0 +1,30 @@
+// Copyright 2011 Free Software Foundation, Inc.
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+package main
+
+func add (a,b int) (int) {
+  return a + b
+}
+
+func sub (a,b int) (int) {
+  return a - b
+}
+
+var v_int int
+
+func main () {
+  v_int = 42 // set breakpoint 1 here
+}
Index: testsuite/gdb.go/hello.exp
===================================================================
RCS file: testsuite/gdb.go/hello.exp
diff -N testsuite/gdb.go/hello.exp
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ testsuite/gdb.go/hello.exp	28 Dec 2011 20:50:34 -0000
@@ -0,0 +1,57 @@
+# This testcase is part of GDB, the GNU debugger.
+
+# Copyright 2011 Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Basic tests.
+
+load_lib "go.exp"
+
+if { [skip_go_tests] } { continue }
+
+set testfile "hello"
+set srcfile ${testfile}.go
+
+if { [prepare_for_testing ${testfile}.exp ${testfile} ${srcfile} {debug go}] } {
+    return -1
+}
+
+set bp_location1 [gdb_get_line_number "set breakpoint 1 here"]
+set bp_location2 [gdb_get_line_number "set breakpoint 2 here"]
+
+if { [go_runto_main] < 0 } {
+    untested $testfile
+    return -1
+}
+
+if { [gdb_breakpoint ${srcfile}:${bp_location1}] } {
+    pass "setting breakpoint 1"
+}
+
+gdb_test "cont" "Breakpoint .*:${bp_location1}.*" "Going to first breakpoint"
+
+gdb_test "print st" \
+    ".* = $hex \"\"" \
+    "Starting string check"
+
+if { [gdb_breakpoint ${srcfile}:${bp_location2}] } {
+    pass "setting breakpoint 2"
+}
+
+gdb_test "cont" "Breakpoint .*:${bp_location2}.*" "Going to second breakpoint"
+
+gdb_test "print st" \
+    ".* = $hex \"Hello, world!\"" \
+    "String after assignment check"
Index: testsuite/gdb.go/hello.go
===================================================================
RCS file: testsuite/gdb.go/hello.go
diff -N testsuite/gdb.go/hello.go
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ testsuite/gdb.go/hello.go	28 Dec 2011 20:50:34 -0000
@@ -0,0 +1,11 @@
+package main
+
+import "fmt"
+
+var st = "Shall we?"
+
+func main () {
+  fmt.Println ("Before assignment") // set breakpoint 1 here
+  st := "Hello, world!" // this intentionally shadows the global "st"
+  fmt.Println (st) // set breakpoint 2 here
+}
Index: testsuite/gdb.go/integers.exp
===================================================================
RCS file: testsuite/gdb.go/integers.exp
diff -N testsuite/gdb.go/integers.exp
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ testsuite/gdb.go/integers.exp	28 Dec 2011 20:50:34 -0000
@@ -0,0 +1,116 @@
+# This testcase is part of GDB, the GNU debugger.
+
+# Copyright 2011 Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Test integer expressions.
+
+load_lib "go.exp"
+
+if { [skip_go_tests] } { continue }
+
+set testfile "integers"
+set srcfile ${testfile}.go
+
+if { [prepare_for_testing ${testfile}.exp ${testfile} ${srcfile} {debug go}] } {
+    return -1
+}
+
+set bp_location1 [gdb_get_line_number "set breakpoint 1 here"]
+set bp_location2 [gdb_get_line_number "set breakpoint 2 here"]
+
+if { [go_runto_main] < 0 } {
+    untested $testfile
+    return -1
+}
+
+if { [gdb_breakpoint ${srcfile}:${bp_location1}] } {
+    pass "setting breakpoint 1"
+}
+
+gdb_test "cont" "Breakpoint .*:${bp_location1}.*" "Going to first breakpoint"
+
+gdb_test "print i" ".* = 0" "Print i before assigned to 1"
+
+gdb_test "next" "i = 1" "Next to 'i = 1' line"
+gdb_test "next" "j = 2" "Next to 'j = 2' line"
+# At that point, 
+# i should be equal to 1
+gdb_test "print i" " = 1" 
+# but j should still be equal to zero
+gdb_test "print j" " = 0" "Test j value before assignment"
+
+gdb_test "next" "k = 3" "Next to 'k = 3' line"
+gdb_test "next" "l = k" "Next to 'l = k' line"
+
+#j should be equal to 2
+gdb_test "print j" " = 2"
+# k should be equal to 3
+gdb_test "print k" " = 3"
+# But l should still be zero
+gdb_test "print l" " = 0"
+
+# Test addition
+gdb_test "print i + j" " = 3"
+gdb_test "print i + k" " = 4"
+gdb_test "print j + k" " = 5"
+gdb_test "print i + j + k" " = 6"
+
+# Test substraction
+gdb_test "print j - i" " = 1"
+gdb_test "print i - j" "= -1"
+gdb_test "print k -i -j" " = 0"
+gdb_test "print k -(i + j)" " = 0"
+
+# Test unany minus
+gdb_test "print -i" " = -1"
+gdb_test "print (-i)" " = -1"
+gdb_test "print -(i)" " = -1"
+gdb_test "print -(i+j)" " = -3"
+
+# Test boolean operators =, <>, <, <=, > and >=
+gdb_test "print i + 1 == j" " = true"
+gdb_test "print i + 1 != j" " = false"
+gdb_test "print i + 1 < j" " = false"
+gdb_test "print i + 1 <= j" " = true"
+gdb_test "print i + 1 > j" " = false"
+gdb_test "print i + 1 >= j" " = true"
+
+# Test multiplication
+gdb_test "print 2 * i" " = 2"
+gdb_test "print j * k" " = 6"
+gdb_test "print 3000*i" " = 3000"
+
+#Test div and mod operators
+gdb_test "print 35 / 2" " = 17"
+gdb_test "print 35 % 2" " = 1"
+
+# Test several operators together
+gdb_test "print i+10*j+100*k" " = 321"
+gdb_test " print (i + 5) * (j + 7)" " = 54"
+
+gdb_test "set var i = 2" " = 2"
+gdb_test "print i" " = 2" "Testing new i value"
+
+if { [gdb_breakpoint ${srcfile}:${bp_location2}] } {
+    pass "setting breakpoint 2"
+}
+
+gdb_test "cont" \
+	 "Breakpoint .*:${bp_location2}.*" \
+	 "Going to second breakpoint"
+gdb_test "print i" \
+	 ".* = 5.*" \
+	 "Value of i after assignment"
Index: testsuite/gdb.go/integers.go
===================================================================
RCS file: testsuite/gdb.go/integers.go
diff -N testsuite/gdb.go/integers.go
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ testsuite/gdb.go/integers.go	28 Dec 2011 20:50:34 -0000
@@ -0,0 +1,37 @@
+// Copyright 2011 Free Software Foundation, Inc.
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+package main
+
+var i = 0
+var j = 0
+var k = 0
+var l = 0
+
+func main () {
+  i = 0
+  j = 0
+  k = 0
+  l = 0 // set breakpoint 1 here
+  i = 1
+  j = 2
+  k = 3
+  l = k
+
+  i = j + k
+
+  j = 0 // set breakpoint 2 here
+  k = 0
+}
Index: testsuite/gdb.go/methods.exp
===================================================================
RCS file: testsuite/gdb.go/methods.exp
diff -N testsuite/gdb.go/methods.exp
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ testsuite/gdb.go/methods.exp	28 Dec 2011 20:50:34 -0000
@@ -0,0 +1,50 @@
+# This testcase is part of GDB, the GNU debugger.
+
+# Copyright 2011 Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Test various aspects of methods.
+
+load_lib "go.exp"
+
+if { [skip_go_tests] } { continue }
+
+set testfile "methods"
+set srcfile ${testfile}.go
+
+if { [prepare_for_testing ${testfile}.exp ${testfile} ${srcfile} {debug go}] } {
+    return -1
+}
+
+set bp_location1 {main.T.Foo}
+set bp_location2 {(*main.T).Bar}
+set bp_location2_regexp {\(*main.T\).Bar}
+
+if { [go_runto_main] < 0 } {
+    untested $testfile
+    return -1
+}
+
+if { [gdb_breakpoint ${bp_location1}] } {
+    pass "setting breakpoint 1"
+}
+setup_xfail "*-*-*" ;# mangling issues IIRC
+gdb_test "cont" "Breakpoint .*:${bp_location1}.*" "Going to first breakpoint"
+
+if { [gdb_breakpoint ${bp_location2}] } {
+    pass "setting breakpoint 2"
+}
+setup_xfail "*-*-*" ;# mangling issues IIRC
+gdb_test "cont" "Breakpoint .*:${bp_location2_regexp}.*" "Going to second breakpoint"
Index: testsuite/gdb.go/methods.go
===================================================================
RCS file: testsuite/gdb.go/methods.go
diff -N testsuite/gdb.go/methods.go
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ testsuite/gdb.go/methods.go	28 Dec 2011 20:50:34 -0000
@@ -0,0 +1,21 @@
+package main
+
+import "fmt"
+
+type T struct { i int }
+
+func (t T) Foo () {
+  fmt.Println (t.i)
+}
+
+func (t *T) Bar () {
+  fmt.Println (t.i)
+}
+
+func main () {
+  fmt.Println ("Shall we?")
+  var t T
+  t.Foo ()
+  var pt = new (T)
+  pt.Bar ()
+}
Index: testsuite/gdb.go/package.exp
===================================================================
RCS file: testsuite/gdb.go/package.exp
diff -N testsuite/gdb.go/package.exp
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ testsuite/gdb.go/package.exp	28 Dec 2011 20:50:34 -0000
@@ -0,0 +1,50 @@
+# This testcase is part of GDB, the GNU debugger.
+
+# Copyright 2011 Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Test various aspects of packages.
+
+load_lib "go.exp"
+
+if { [skip_go_tests] } { continue }
+
+set testfile "package"
+set binfile ${objdir}/${subdir}/${testfile}
+
+if  { [gdb_compile "${srcdir}/${subdir}/${testfile}2.go" "${binfile}2.o" object {debug go}] != "" } {
+    untested $testfile
+    return -1
+}
+
+if  { [gdb_compile "${srcdir}/${subdir}/${testfile}1.go ${binfile}2.o" "${binfile}" executable "debug go libdir=${objdir}/${subdir}"] != "" } {
+    untested $testfile
+    return -1
+}
+
+clean_restart $testfile
+
+if { [go_runto_main] < 0 } {
+    untested methods
+    return -1
+}
+
+set bp_location1 {package2.Foo}
+set bp_location1_regexp {package2[.]Foo.*package2[.]go:}
+
+if { [gdb_breakpoint ${bp_location1}] } {
+    pass "setting breakpoint 1"
+}
+gdb_test "cont" "Breakpoint .*${bp_location1_regexp}.*" "Going to first breakpoint"
Index: testsuite/gdb.go/package1.go
===================================================================
RCS file: testsuite/gdb.go/package1.go
diff -N testsuite/gdb.go/package1.go
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ testsuite/gdb.go/package1.go	28 Dec 2011 20:50:34 -0000
@@ -0,0 +1,11 @@
+package main
+
+import (
+  "fmt"
+  "package2"
+)
+
+func main () {
+  fmt.Println ("Shall we?")
+  package2.Foo ()
+}
Index: testsuite/gdb.go/package2.go
===================================================================
RCS file: testsuite/gdb.go/package2.go
diff -N testsuite/gdb.go/package2.go
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ testsuite/gdb.go/package2.go	28 Dec 2011 20:50:34 -0000
@@ -0,0 +1,7 @@
+package package2
+
+import "fmt"
+
+func Foo () {
+  fmt.Println ("Hi, I'm package2.Foo.")
+}
Index: testsuite/gdb.go/print.exp
===================================================================
RCS file: testsuite/gdb.go/print.exp
diff -N testsuite/gdb.go/print.exp
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ testsuite/gdb.go/print.exp	28 Dec 2011 20:50:34 -0000
@@ -0,0 +1,70 @@
+# This testcase is part of GDB, the GNU debugger.
+
+# Copyright 2011 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Test printing of various values.
+# NOTE: The tests here intentionally do not require a go compiler.
+
+load_lib "go.exp"
+
+if { [skip_go_tests] } { continue }
+
+proc test_float_accepted {} {
+    global gdb_prompt
+
+    # Test parsing of fp value with legit text following.
+    gdb_test "p 1234.5+1" " = 1235.5" "check fp + text"
+
+    # Test all the suffixes (including no suffix).
+    gdb_test "p 1." " = 1"
+    gdb_test "p 1.5" " = 1.5"
+    gdb_test "p 1.f" " = 1"
+    gdb_test "p 1.5f" " = 1.5"
+    gdb_test "p 1.l" " = 1"
+    gdb_test "p 1.5l" " = 1.5"
+
+    # Test hexadecimal floating point.
+    set test "p 0x1.1"
+    gdb_test_multiple $test $test {
+	-re " = 1\\.0625\r\n$gdb_prompt $" {
+	    pass $test
+	}
+	-re "Invalid number \"0x1\\.1\"\\.\r\n$gdb_prompt $" {
+	    # Older glibc does not support hex float, newer does.
+	    xfail $test
+	}
+    }
+}
+
+proc test_float_rejected {} {
+    # Test bad suffixes.
+    test_print_reject "p 1.1x"
+    test_print_reject "p 1.1ff"
+    test_print_reject "p 1.1ll"
+}
+
+# Start with a fresh gdb.
+
+gdb_exit
+gdb_start
+gdb_reinitialize_dir $srcdir/$subdir
+
+if [set_lang_go] {
+    test_float_accepted
+    test_float_rejected
+} else {
+    warning "Go print tests suppressed"
+}
Index: testsuite/gdb.go/strings.exp
===================================================================
RCS file: testsuite/gdb.go/strings.exp
diff -N testsuite/gdb.go/strings.exp
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ testsuite/gdb.go/strings.exp	28 Dec 2011 20:50:34 -0000
@@ -0,0 +1,42 @@
+# This testcase is part of GDB, the GNU debugger.
+
+# Copyright 2011 Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+load_lib "go.exp"
+
+if { [skip_go_tests] } { continue }
+
+set testfile "strings"
+set srcfile ${testfile}.go
+
+if { [prepare_for_testing ${testfile}.exp ${testfile} ${srcfile} {debug go}] } {
+    return -1
+}
+
+set bp_location1 [gdb_get_line_number "set breakpoint 1 here"]
+
+if { [go_runto_main] < 0 } {
+    untested $testfile
+    return -1
+}
+
+if { [gdb_breakpoint ${srcfile}:${bp_location1}] } {
+    pass "setting breakpoint 1"
+}
+
+gdb_test "cont" "Breakpoint .*:${bp_location1}.*" "Going to first breakpoint"
+
+gdb_test {print "abc" + "def"} {.* = "abcdef"}
Index: testsuite/gdb.go/strings.go
===================================================================
RCS file: testsuite/gdb.go/strings.go
diff -N testsuite/gdb.go/strings.go
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ testsuite/gdb.go/strings.go	28 Dec 2011 20:50:34 -0000
@@ -0,0 +1,10 @@
+package main
+
+import "fmt"
+
+var v_string string = "foo"
+
+func main () {
+  fmt.Println ("hello") // set breakpoint 1 here
+  fmt.Printf ("%s\n", v_string)
+}
Index: testsuite/gdb.go/types.exp
===================================================================
RCS file: testsuite/gdb.go/types.exp
diff -N testsuite/gdb.go/types.exp
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ testsuite/gdb.go/types.exp	28 Dec 2011 20:50:34 -0000
@@ -0,0 +1,51 @@
+# This testcase is part of GDB, the GNU debugger.
+
+# Copyright 2011 Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Various experiments with types.
+
+load_lib "go.exp"
+
+if { [skip_go_tests] } { continue }
+
+set testfile "types"
+set srcfile ${testfile}.go
+
+if { [prepare_for_testing ${testfile}.exp ${testfile} ${srcfile} {debug go}] } {
+    return -1
+}
+
+if { [go_runto_main] < 0 } {
+    untested $testfile
+    return -1
+}
+
+# It's not clear yet what GCC will emit.
+# Pick something and xfail it until GCC solidifies.
+# And we still need to finish go-typeprint.c.
+
+setup_xfail "*-*-*"
+gdb_test "ptype T" "type T *T"
+
+setup_xfail "*-*-*"
+gdb_test "ptype T1" "type T1 *T2"
+setup_xfail "*-*-*"
+gdb_test "ptype T2" "type T2 *T1"
+
+setup_xfail "*-*-*"
+gdb_test "ptype S1" "type S1 struct {.*p_s2 *S2.*}"
+setup_xfail "*-*-*"
+gdb_test "ptype S2" "type S2 struct {.*p_s1 *S1.*}"
Index: testsuite/gdb.go/types.go
===================================================================
RCS file: testsuite/gdb.go/types.go
diff -N testsuite/gdb.go/types.go
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ testsuite/gdb.go/types.go	28 Dec 2011 20:50:34 -0000
@@ -0,0 +1,24 @@
+package main
+
+import "fmt"
+
+// Self-referential type.
+type T *T
+
+// Mutually recursive types.
+type T1 *T2
+type T2 *T1
+
+// Mutually recursive struct types.
+type S1 struct { p_s2 *S2 }
+type S2 struct { p_s1 *S1 }
+
+func main () {
+  fmt.Println ("Shall we?")
+  var t T
+  fmt.Println (t)
+  var s1 S1
+  var s2 S2
+  fmt.Println (s1)
+  fmt.Println (s2)
+}
Index: testsuite/gdb.go/unsafe.exp
===================================================================
RCS file: testsuite/gdb.go/unsafe.exp
diff -N testsuite/gdb.go/unsafe.exp
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ testsuite/gdb.go/unsafe.exp	28 Dec 2011 20:50:34 -0000
@@ -0,0 +1,44 @@
+# This testcase is part of GDB, the GNU debugger.
+
+# Copyright 2011 Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Test package "unsafe".
+
+load_lib "go.exp"
+
+if { [skip_go_tests] } { continue }
+
+set testfile "unsafe"
+set srcfile ${testfile}.go
+
+if { [prepare_for_testing ${testfile}.exp ${testfile} ${srcfile} {debug go}] } {
+    return -1
+}
+
+set bp_location1 [gdb_get_line_number "set breakpoint 1 here"]
+
+if { [go_runto_main] < 0 } {
+    untested $testfile
+    return -1
+}
+
+if { [gdb_breakpoint ${srcfile}:${bp_location1}] } {
+    pass "setting breakpoint 1"
+}
+
+gdb_test "cont" "Breakpoint .*:${bp_location1}.*" "Going to first breakpoint"
+
+gdb_test "print unsafe.Sizeof(42)" ".* = 4"
Index: testsuite/gdb.go/unsafe.go
===================================================================
RCS file: testsuite/gdb.go/unsafe.go
diff -N testsuite/gdb.go/unsafe.go
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ testsuite/gdb.go/unsafe.go	28 Dec 2011 20:50:34 -0000
@@ -0,0 +1,8 @@
+package main
+
+import ("fmt"
+        "unsafe")
+
+func main () {
+  fmt.Printf ("%d\n", unsafe.Sizeof (42)) // set breakpoint 1 here
+}
Index: testsuite/lib/future.exp
===================================================================
RCS file: /cvs/src/src/gdb/testsuite/lib/future.exp,v
retrieving revision 1.1
diff -u -p -r1.1 future.exp
--- testsuite/lib/future.exp	29 Jun 2011 14:44:45 -0000	1.1
+++ testsuite/lib/future.exp	28 Dec 2011 20:50:34 -0000
@@ -60,6 +60,30 @@ proc gdb_find_gfortran {} {
     return $CC
 }
 
+proc gdb_find_go {} {
+    global tool_root_dir
+
+    set GO ""
+
+    if {![is_remote host]} {
+	set file [lookfor_file $tool_root_dir gccgo]
+	if { $file != "" } {
+	    set root [file dirname $file]
+	    set GO "$file -B$root/gcc/"
+	}
+    }
+
+    if { $GO == "" } {
+	set GO [transform gccgo]
+    }
+
+    return $GO
+}
+
+proc gdb_find_go_linker {} {
+    return [find_go]
+}
+
 proc gdb_default_target_compile {source destfile type options} {
     global target_triplet
     global tool_root_dir
@@ -74,6 +98,11 @@ proc gdb_default_target_compile {source 
     set libs ""
     set compiler_type "c"
     set compiler ""
+    set linker ""
+    # linker_opts_order is one of "sources-then-flags", "flags-then-sources".
+    # The order shouldn't matter.  It's done this way to preserve
+    # existing behavior.
+    set linker_opts_order "sources-then-flags"
     set ldflags ""
     set dest [target_info name]
 
@@ -138,6 +167,26 @@ proc gdb_default_target_compile {source 
 	    }
 	}
 
+	if { $i == "go" } {
+	    set compiler_type "go"
+	    if {[board_info $dest exists goflags]} {
+		append add_flags " [target_info goflags]"
+	    }
+	    if {[board_info $dest exists gocompiler]} {
+		set compiler [target_info gocompiler]
+	    } else {
+		set compiler [find_go]
+	    }
+	    if {[board_info $dest exists golinker]} {
+		set linker [target_info golinker]
+	    } else {
+		set linker [find_go_linker]
+	    }
+	    if {[board_info $dest exists golinker_opts_order]} {
+		set linker_opts_order [target_info golinker_opts_order]
+	    }
+	}
+
 	if {[regexp "^dest=" $i]} {
 	    regsub "^dest=" $i "" tmp
 	    if {[board_info $tmp exists name]} {
@@ -193,6 +242,8 @@ proc gdb_default_target_compile {source 
     global F77_FOR_TARGET
     global F90_FOR_TARGET
     global GNATMAKE_FOR_TARGET
+    global GO_FOR_TARGET
+    global GO_LD_FOR_TARGET
 
     if {[info exists GNATMAKE_FOR_TARGET]} {
 	if { $compiler_type == "ada" } {
@@ -224,6 +275,19 @@ proc gdb_default_target_compile {source 
 	}
     }
 
+    if { $compiler_type == "go" } {
+	if {[info exists GO_FOR_TARGET]} {
+	    set compiler $GO_FOR_TARGET
+	}
+	if {[info exists GO_LD_FOR_TARGET]} {
+	    set linker $GO_LD_FOR_TARGET
+	}
+    }
+
+    if { $type == "executable" && $linker != "" } {
+	set compiler $linker
+    }
+
     if { $compiler == "" } {
 	set compiler [board_info $dest compiler]
 	if { $compiler == "" } {
@@ -366,10 +430,26 @@ proc gdb_default_target_compile {source 
     # This is obscure: we put SOURCES at the end when building an
     # object, because otherwise, in some situations, libtool will
     # become confused about the name of the actual source file.
-    if {$type == "object"} {
-	set opts "$add_flags $sources"
-    } else {
-	set opts "$sources $add_flags"
+    switch $type {
+	"object" {
+	    set opts "$add_flags $sources"
+	}
+	"executable" {
+	    switch $linker_opts_order {
+		"flags-then-sources" {
+		    set opts "$add_flags $sources"
+		}
+		"sources-then-flags" {
+		    set opts "$sources $add_flags"
+		}
+		default {
+		    error "Invalid value for board_info linker_opts_order"
+		}
+	    }
+	}
+	default {
+	    set opts "$sources $add_flags"
+	}
     }
 
     if {[is_remote host]} {
@@ -431,6 +511,12 @@ if {[info procs find_gfortran] == ""} {
     set use_gdb_compile 1
 }
 
+if {[info procs find_go_linker] == ""} {
+    rename gdb_find_go find_go
+    rename gdb_find_go_linker find_go_linker
+    # No need to set use_gdb_compile.
+}
+
 if {$use_gdb_compile} {
     catch {rename default_target_compile {}}
     rename gdb_default_target_compile default_target_compile
Index: testsuite/lib/gdb.exp
===================================================================
RCS file: /cvs/src/src/gdb/testsuite/lib/gdb.exp,v
retrieving revision 1.198
diff -u -p -r1.198 gdb.exp
--- testsuite/lib/gdb.exp	14 Dec 2011 19:50:18 -0000	1.198
+++ testsuite/lib/gdb.exp	28 Dec 2011 20:50:34 -0000
@@ -1439,6 +1439,12 @@ proc skip_ada_tests {} {
     return 0
 }
 
+# Return a 1 if I don't even want to try to test GO.
+
+proc skip_go_tests {} {
+    return 0
+}
+
 # Return a 1 if I don't even want to try to test java.
 
 proc skip_java_tests {} {
Index: testsuite/lib/go.exp
===================================================================
RCS file: testsuite/lib/go.exp
diff -N testsuite/lib/go.exp
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ testsuite/lib/go.exp	28 Dec 2011 20:50:34 -0000
@@ -0,0 +1,37 @@
+# Copyright 2011 Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# FIXME: Presumably skip_go_tests should be defined here,
+# but for consistency with other languages it currently lives in gdb.exp.
+
+# Auxiliary function to set the language to Go.
+# The result is 1 (true) for success, 0 (false) for failure.
+
+proc set_lang_go {} {
+    if [gdb_test_no_output "set language go"] {
+	return 0
+    }
+    if [gdb_test "show language" ".* source language is \"go\"." \
+	   "set language to \"go\""] {
+	return 0
+    }
+    return 1
+}
+
+# Go version of runto_main.
+
+proc go_runto_main { } {
+    return [runto main.main]
+}


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]