public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* [RFC] Initial pass at supporting the Go language
@ 2011-12-28 21:13 Doug Evans
  2011-12-29  3:50 ` Eli Zaretskii
                   ` (3 more replies)
  0 siblings, 4 replies; 13+ messages in thread
From: Doug Evans @ 2011-12-28 21:13 UTC (permalink / raw)
  To: gdb-patches; +Cc: iant

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 '.' '[' '('
+
+\f
+%%
+
+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]
+}

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

* Re: [RFC] Initial pass at supporting the Go language
  2011-12-28 21:13 [RFC] Initial pass at supporting the Go language Doug Evans
@ 2011-12-29  3:50 ` Eli Zaretskii
  2011-12-29  5:17 ` Joel Brobecker
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 13+ messages in thread
From: Eli Zaretskii @ 2011-12-29  3:50 UTC (permalink / raw)
  To: Doug Evans; +Cc: gdb-patches, iant

> cc: iant@google.com
> Date: Wed, 28 Dec 2011 13:02:06 -0800 (PST)
> From: dje@google.com (Doug Evans)
> 
> This patch is a first pass at supporting the Go language.

Thanks.

The documentation parts are OK, except...

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

...for the last sentence.  Please remove it; it adds nothing to the
text, and will look real bad if inadvertently left there.

Btw, I suggest to use

 @cindex Go (programming language)

because just "Go" is ambiguous.

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

* Re: [RFC] Initial pass at supporting the Go language
  2011-12-28 21:13 [RFC] Initial pass at supporting the Go language Doug Evans
  2011-12-29  3:50 ` Eli Zaretskii
@ 2011-12-29  5:17 ` Joel Brobecker
  2012-01-03 17:38   ` Doug Evans
  2012-01-25 20:00   ` Doug Evans
  2012-01-02 19:13 ` Tom Tromey
  2015-01-20 17:34 ` golang compiler (6g) testsuite board file [Re: [RFC] Initial pass at supporting the Go language] Jan Kratochvil
  3 siblings, 2 replies; 13+ messages in thread
From: Joel Brobecker @ 2011-12-29  5:17 UTC (permalink / raw)
  To: Doug Evans; +Cc: gdb-patches, iant

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

I quickly skimmed through the patch, particularly the changes
in GDB. I like how you've nicely and consistently documented
your code. From the comments, I can see that you have a feature
that is similar to what we have in Ada, namely to be able to
use the unqualified name of an entity. For instance, if you have
a variable foo in package bar, you want to be able to write
either, you want to be able to use either "print bar" or
"print foo.bar". If that's correct, it's interesting how
you decided to side-step the problem (assuming I understood
your changes correctly).

(I even noticed that Ada is mentioned somewhere - didn't try
to understand why, though).

Just a tiny thing that sort of caught my attention while flash
forwarding the testing part of your code (nice number of tests!).

> +# Start with a fresh gdb.
> +
> +gdb_exit
> +gdb_start
> +gdb_reinitialize_dir $srcdir/$subdir

Use clean_restart?

Clearly a fair amount of work has already gone into that port.
I'm impressed.

-- 
Joel

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

* Re: [RFC] Initial pass at supporting the Go language
  2011-12-28 21:13 [RFC] Initial pass at supporting the Go language Doug Evans
  2011-12-29  3:50 ` Eli Zaretskii
  2011-12-29  5:17 ` Joel Brobecker
@ 2012-01-02 19:13 ` Tom Tromey
  2012-01-03  3:20   ` Joel Brobecker
                     ` (2 more replies)
  2015-01-20 17:34 ` golang compiler (6g) testsuite board file [Re: [RFC] Initial pass at supporting the Go language] Jan Kratochvil
  3 siblings, 3 replies; 13+ messages in thread
From: Tom Tromey @ 2012-01-02 19:13 UTC (permalink / raw)
  To: Doug Evans; +Cc: gdb-patches, iant, Keith Seitz

>>>>> "Doug" == Doug Evans <dje@google.com> writes:

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

Nice work.

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

A few notes below.

Doug> +/* Go objects should be embedded in a DW_TAG_module DIE,
Doug> +   and it's not clear if/how imported objects will appear.
Doug> +   To keep Go support simple until that's worked out,
Doug> +   go back through what we've read and create something usable.
Doug> +   We could do this while processing each DIE, and feels kinda cleaner,
Doug> +   but that way is more invasive.
Doug> +   This is to, for example, allow the user to type "p var" or "b main"
Doug> +   without having to specify the package name, and allow lookups
Doug> +   of module.object to work in contexts that use the expression
Doug> +   parser.  */

I think this over-exposes some buildsym details to dwarf2read.
How much more invasive is the alternative?

Doug> +	 And if not, it should be clearly documented why not.
Doug> +	 OTOH, why are we demangling at all here?
Doug> +	 new_symbol_full assumes we return the mangled name.
Doug> +	 I realize things are changing in this area, I just forget how.  */
Doug> +      if (cu->language == language_go)
Doug> +	{
Doug> +#if 0
Doug> +	  demangled = cu->language_defn->la_demangle (mangled, 0);
Doug> +#else
Doug> +	  /* This is a lie, but we already lie to the caller new_symbol_full.
Doug> +	     This just undoes that lie until things are cleaned up.  */
Doug> +	  demangled = NULL;
Doug> +#endif

I've CC'd Keith to see if he can clear this up.

Doug> +/* FIXME: IWBN to use c-exp.y's parse_number if we could.  */

You could export it as c_parse_number or something like that, I suppose.

Doug> +   FIXME: Hacky, but until things solidify it's not worth much more.  */

I think you could safely remove this FIXME.

Doug> +    /*{"->", RIGHT_ARROW, BINOP_END}, Doesn't exist in Go.  */

Doug> +#if 0 /* -> doesn't exist in Go.  */
Doug> +	if (in_parse_field && tokentab2[i].token == RIGHT_ARROW)
Doug> +	  last_was_structop = 1;
Doug> +#endif

I think you could zap this dead code.

Doug> +  /* TODO(dje): The encapsulation of what a pointer is belongs in value.c.
Doug> +     I.e. If there's going to be unpack_pointer, there should be
Doug> +     unpack_value_field_as_pointer.  Do this until we can get
Doug> +     unpack_value_field_as_pointer.  */
Doug> +  LONGEST addr;

Eventually I want us to get rid of val_print entirely and only have
value_print.  Then this won't be a problem; since you will just use the
value API to access fields.

Doug> +  /* TODO(dje): Perhaps we should pass "UTF8" for ENCODING.
Doug> +     The target encoding is a global switch.
Doug> +     Either choice is problematic.  */
Doug> +  i = val_print_string (elt_type, NULL, addr, length, stream, options);

What is the problem here?

Tom

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

* Re: [RFC] Initial pass at supporting the Go language
  2012-01-02 19:13 ` Tom Tromey
@ 2012-01-03  3:20   ` Joel Brobecker
  2012-01-03 18:12   ` Doug Evans
  2012-01-03 20:02   ` Keith Seitz
  2 siblings, 0 replies; 13+ messages in thread
From: Joel Brobecker @ 2012-01-03  3:20 UTC (permalink / raw)
  To: Tom Tromey; +Cc: Doug Evans, gdb-patches, iant, Keith Seitz

> Eventually I want us to get rid of val_print entirely and only have
> value_print.  Then this won't be a problem; since you will just use the
> value API to access fields.

I would like that too. I'm a little short on time to convert Ada
right now, but clearly something I want to look at, since I had
to start at the code a few days ago.

-- 
Joel

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

* Re: [RFC] Initial pass at supporting the Go language
  2011-12-29  5:17 ` Joel Brobecker
@ 2012-01-03 17:38   ` Doug Evans
  2012-01-03 17:52     ` Joel Brobecker
  2012-01-25 20:00   ` Doug Evans
  1 sibling, 1 reply; 13+ messages in thread
From: Doug Evans @ 2012-01-03 17:38 UTC (permalink / raw)
  To: Joel Brobecker; +Cc: gdb-patches, iant

On Wed, Dec 28, 2011 at 8:11 PM, Joel Brobecker <brobecker@adacore.com> wrote:
>> This patch is a first pass at supporting the Go language.
>> There's still lots to do, but this is a start.
>
> From the comments, I can see that you have a feature
> that is similar to what we have in Ada, namely to be able to
> use the unqualified name of an entity. For instance, if you have
> a variable foo in package bar, you want to be able to write
> either, you want to be able to use either "print bar" or
> "print foo.bar".

That's the intent.

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

* Re: [RFC] Initial pass at supporting the Go language
  2012-01-03 17:38   ` Doug Evans
@ 2012-01-03 17:52     ` Joel Brobecker
  0 siblings, 0 replies; 13+ messages in thread
From: Joel Brobecker @ 2012-01-03 17:52 UTC (permalink / raw)
  To: Doug Evans; +Cc: gdb-patches, iant

> > For instance, if you have a variable foo in package bar, you want to
> > be able to write either, you want to be able to use either "print
> > bar" or "print foo.bar".
> 
> That's the intent.

Joel does a little dance. Ada is no longer alone anymore :-).

-- 
Joel

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

* Re: [RFC] Initial pass at supporting the Go language
  2012-01-02 19:13 ` Tom Tromey
  2012-01-03  3:20   ` Joel Brobecker
@ 2012-01-03 18:12   ` Doug Evans
  2012-01-03 19:50     ` Tom Tromey
  2012-01-03 20:02   ` Keith Seitz
  2 siblings, 1 reply; 13+ messages in thread
From: Doug Evans @ 2012-01-03 18:12 UTC (permalink / raw)
  To: Tom Tromey; +Cc: gdb-patches, iant, Keith Seitz

On Mon, Jan 2, 2012 at 11:13 AM, Tom Tromey <tromey@redhat.com> wrote:
> Doug> +/* Go objects should be embedded in a DW_TAG_module DIE,
> Doug> +   and it's not clear if/how imported objects will appear.
> Doug> +   To keep Go support simple until that's worked out,
> Doug> +   go back through what we've read and create something usable.
> Doug> +   We could do this while processing each DIE, and feels kinda cleaner,
> Doug> +   but that way is more invasive.
> Doug> +   This is to, for example, allow the user to type "p var" or "b main"
> Doug> +   without having to specify the package name, and allow lookups
> Doug> +   of module.object to work in contexts that use the expression
> Doug> +   parser.  */
>
> I think this over-exposes some buildsym details to dwarf2read.

Sigh.
This is what I get for monkey-see-monkey-do hacking.
You can't trust any part of gdb to be what the powers-that-be find acceptable.
[The code in question is far from rare, and any details are certainly
not protected in a way that imposes or even suggests a proper API.  A
day I continue to wish for btw.]

> How much more invasive is the alternative?

I'd rather keep the hack as one call site at an outer level than embed
it into new_symbol or each die handler or some such.

> Doug> +  And if not, it should be clearly documented why not.
> Doug> +  OTOH, why are we demangling at all here?
> Doug> +  new_symbol_full assumes we return the mangled name.
> Doug> +  I realize things are changing in this area, I just forget how.  */
> Doug> +      if (cu->language == language_go)
> Doug> + {
> Doug> +#if 0
> Doug> +   demangled = cu->language_defn->la_demangle (mangled, 0);
> Doug> +#else
> Doug> +   /* This is a lie, but we already lie to the caller new_symbol_full.
> Doug> +      This just undoes that lie until things are cleaned up.  */
> Doug> +   demangled = NULL;
> Doug> +#endif
>
> I've CC'd Keith to see if he can clear this up.

Or I can.
This is one of the things I want to clean up before checking in.

> Doug> +/* FIXME: IWBN to use c-exp.y's parse_number if we could.  */
>
> You could export it as c_parse_number or something like that, I suppose.

I wasn't sure that would be acceptable.

> Doug> +   FIXME: Hacky, but until things solidify it's not worth much more.  */
>
> I think you could safely remove this FIXME.

I like it.  It reminds me Go's mangling needs to change.

> Doug> +    /*{"->", RIGHT_ARROW, BINOP_END}, Doesn't exist in Go.  */
>
> Doug> +#if 0 /* -> doesn't exist in Go.  */
> Doug> + if (in_parse_field && tokentab2[i].token == RIGHT_ARROW)
> Doug> +   last_was_structop = 1;
> Doug> +#endif
>
> I think you could zap this dead code.

I'll replace it with a similar comment.

> Doug> +  /* TODO(dje): The encapsulation of what a pointer is belongs in value.c.
> Doug> +     I.e. If there's going to be unpack_pointer, there should be
> Doug> +     unpack_value_field_as_pointer.  Do this until we can get
> Doug> +     unpack_value_field_as_pointer.  */
> Doug> +  LONGEST addr;
>
> Eventually I want us to get rid of val_print entirely and only have
> value_print.  Then this won't be a problem; since you will just use the
> value API to access fields.

I think that's the general consensus.

> Doug> +  /* TODO(dje): Perhaps we should pass "UTF8" for ENCODING.
> Doug> +     The target encoding is a global switch.
> Doug> +     Either choice is problematic.  */
> Doug> +  i = val_print_string (elt_type, NULL, addr, length, stream, options);
>
> What is the problem here?

The choice of what encoding to use is, ultimately, a property of the
thing you are printing, not any global state.  Plus Go generally uses
utf8; I wasn't willing to have the Go support change the target
encoding.

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

* Re: [RFC] Initial pass at supporting the Go language
  2012-01-03 18:12   ` Doug Evans
@ 2012-01-03 19:50     ` Tom Tromey
  0 siblings, 0 replies; 13+ messages in thread
From: Tom Tromey @ 2012-01-03 19:50 UTC (permalink / raw)
  To: Doug Evans; +Cc: gdb-patches, iant, Keith Seitz

>>>>> "Doug" == Doug Evans <dje@google.com> writes:

Tom> I think this over-exposes some buildsym details to dwarf2read.

Doug> Sigh.
Doug> This is what I get for monkey-see-monkey-do hacking.
Doug> You can't trust any part of gdb to be what the powers-that-be find acceptable.
Doug> [The code in question is far from rare, and any details are certainly
Doug> not protected in a way that imposes or even suggests a proper API.  A
Doug> day I continue to wish for btw.]

I don't insist on changing this.  In fact I thought it was reasonably
clear that I was approaching it as a tradeoff between ugly alternatives.
I grepped the tree looking for similar uses of struct pending, and
didn't find any.

Tom> What is the problem here?

Doug> The choice of what encoding to use is, ultimately, a property of the
Doug> thing you are printing, not any global state.  Plus Go generally uses
Doug> utf8; I wasn't willing to have the Go support change the target
Doug> encoding.

It seems to me that if a Go string is UTF-8, then it is friendliest to
the user to print it as such.  After all, you're already doing other
Go-specific decoding here.

If the user really needs to see the details, he can "set lang c" and see
the underlying representation.

That said, I don't mind either way here, either.  I don't actually know
much about Go.

Tom

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

* Re: [RFC] Initial pass at supporting the Go language
  2012-01-02 19:13 ` Tom Tromey
  2012-01-03  3:20   ` Joel Brobecker
  2012-01-03 18:12   ` Doug Evans
@ 2012-01-03 20:02   ` Keith Seitz
  2 siblings, 0 replies; 13+ messages in thread
From: Keith Seitz @ 2012-01-03 20:02 UTC (permalink / raw)
  To: gdb-patches

On 01/02/2012 11:13 AM, Tom Tromey wrote:
>>>>>> "Doug" == Doug Evans<dje@google.com>  writes:
> Doug>  +	 And if not, it should be clearly documented why not.
> Doug>  +	 OTOH, why are we demangling at all here?
> Doug>  +	 new_symbol_full assumes we return the mangled name.
> Doug>  +	 I realize things are changing in this area, I just forget how.  */
> Doug>  +      if (cu->language == language_go)
> Doug>  +	{
> Doug>  +#if 0
> Doug>  +	  demangled = cu->language_defn->la_demangle (mangled, 0);
> Doug>  +#else
> Doug>  +	  /* This is a lie, but we already lie to the caller new_symbol_full.
> Doug>  +	     This just undoes that lie until things are cleaned up.  */
> Doug>  +	  demangled = NULL;
> Doug>  +#endif
>
> I've CC'd Keith to see if he can clear this up.

I'm not sure what the question is...

This is the workaround to demangle DW_AT_[MIPS_]linkage_name if 
available instead of computing the physname. It should only be done for 
C++ and Java.

Did you want me to do something? Or ?

Keith

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

* Re: [RFC] Initial pass at supporting the Go language
  2011-12-29  5:17 ` Joel Brobecker
  2012-01-03 17:38   ` Doug Evans
@ 2012-01-25 20:00   ` Doug Evans
  1 sibling, 0 replies; 13+ messages in thread
From: Doug Evans @ 2012-01-25 20:00 UTC (permalink / raw)
  To: Joel Brobecker; +Cc: gdb-patches

On Wed, Dec 28, 2011 at 8:11 PM, Joel Brobecker <brobecker@adacore.com> wrote:
>> This patch is a first pass at supporting the Go language.
>> There's still lots to do, but this is a start.
>
> [...]
>
> Just a tiny thing that sort of caught my attention while flash
> forwarding the testing part of your code (nice number of tests!).
>
>> +# Start with a fresh gdb.
>> +
>> +gdb_exit
>> +gdb_start
>> +gdb_reinitialize_dir $srcdir/$subdir
>
> Use clean_restart?

[catching up on my go port ...]

clean_restart also does gdb_load and these tests run without any inferior.

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

* golang compiler (6g) testsuite board file  [Re: [RFC] Initial pass at supporting the Go language]
  2011-12-28 21:13 [RFC] Initial pass at supporting the Go language Doug Evans
                   ` (2 preceding siblings ...)
  2012-01-02 19:13 ` Tom Tromey
@ 2015-01-20 17:34 ` Jan Kratochvil
  2015-01-21 17:59   ` Doug Evans
  3 siblings, 1 reply; 13+ messages in thread
From: Jan Kratochvil @ 2015-01-20 17:34 UTC (permalink / raw)
  To: Doug Evans; +Cc: gdb-patches, iant

Hi Doug,

On Wed, 28 Dec 2011 22:02:06 +0100, Doug Evans wrote:
> I also have a board file for running the testsuite with the 6g compiler.
> I'll submit that separately.

I haven't found that file submitted, do you still have it?


Thanks,
Jan

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

* Re: golang compiler (6g) testsuite board file  [Re: [RFC] Initial pass at supporting the Go language]
  2015-01-20 17:34 ` golang compiler (6g) testsuite board file [Re: [RFC] Initial pass at supporting the Go language] Jan Kratochvil
@ 2015-01-21 17:59   ` Doug Evans
  0 siblings, 0 replies; 13+ messages in thread
From: Doug Evans @ 2015-01-21 17:59 UTC (permalink / raw)
  To: Jan Kratochvil; +Cc: gdb-patches, iant

Jan Kratochvil writes:
 > Hi Doug,
 > 
 > On Wed, 28 Dec 2011 22:02:06 +0100, Doug Evans wrote:
 > > I also have a board file for running the testsuite with the 6g compiler.
 > > I'll submit that separately.
 > 
 > I haven't found that file submitted, do you still have it?

Hi.

Here's what I have.
I haven't used it in awhile, and have spent no time cleaning it up,
so "heads up".

---
# Board description file for running the testsuite with the 6g compiler.
# The user is currently required to set GO_FOR_TARGET to the path of 6g.
# IWBN if all we had to do was set the path to the compiler.

# 6g doesn't treat -g like gcc does.
set_board_info debug_flags ""

#set GO_TOP "/g3/go/6g/go"
set GO_TOP "/g5/go/6g/go"

set_board_info gocompiler "$GO_TOP/pkg/tool/linux_amd64/6g"

# 6g uses a separate linker.
set_board_info golinker "$GO_TOP/pkg/tool/linux_amd64/6l"

# 6g doesn't have a -lm.
# FIXME: This affects all languages.
set_board_info mathlib ""

# 6l requires "-o foo.o foo" instead of "foo.o -o foo".
set_board_info golinker_opts_order "flags-then-sources"

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

end of thread, other threads:[~2015-01-21 17:59 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-12-28 21:13 [RFC] Initial pass at supporting the Go language Doug Evans
2011-12-29  3:50 ` Eli Zaretskii
2011-12-29  5:17 ` Joel Brobecker
2012-01-03 17:38   ` Doug Evans
2012-01-03 17:52     ` Joel Brobecker
2012-01-25 20:00   ` Doug Evans
2012-01-02 19:13 ` Tom Tromey
2012-01-03  3:20   ` Joel Brobecker
2012-01-03 18:12   ` Doug Evans
2012-01-03 19:50     ` Tom Tromey
2012-01-03 20:02   ` Keith Seitz
2015-01-20 17:34 ` golang compiler (6g) testsuite board file [Re: [RFC] Initial pass at supporting the Go language] Jan Kratochvil
2015-01-21 17:59   ` Doug Evans

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