/* Go language support routines for GDB, the GNU debugger.
- Copyright (C) 2012-2017 Free Software Foundation, Inc.
+ Copyright (C) 2012-2023 Free Software Foundation, Inc.
This file is part of GDB.
*/
#include "defs.h"
-#include "gdb_obstack.h"
+#include "gdbsupport/gdb_obstack.h"
#include "block.h"
#include "symtab.h"
#include "language.h"
#include "go-lang.h"
#include "c-lang.h"
#include "parser-defs.h"
+#include "gdbarch.h"
#include <ctype.h>
{
/* gccgo strings don't necessarily have a name we can use. */
- if (TYPE_NFIELDS (type) == 2)
+ if (type->num_fields () == 2)
{
- struct type *type0 = TYPE_FIELD_TYPE (type, 0);
- struct type *type1 = TYPE_FIELD_TYPE (type, 1);
+ struct type *type0 = type->field (0).type ();
+ struct type *type1 = type->field (1).type ();
type0 = check_typedef (type0);
type1 = 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)
+ if (type0->code () == TYPE_CODE_PTR
+ && strcmp (type->field (0).name (), "__data") == 0
+ && type1->code () == TYPE_CODE_INT
+ && strcmp (type->field (1).name (), "__length") == 0)
{
- struct type *target_type = TYPE_TARGET_TYPE (type0);
+ struct type *target_type = type0->target_type ();
target_type = check_typedef (target_type);
- if (TYPE_CODE (target_type) == TYPE_CODE_INT
- && TYPE_LENGTH (target_type) == 1
- && strcmp (TYPE_NAME (target_type), "uint8") == 0)
+ if (target_type->code () == TYPE_CODE_INT
+ && target_type->length () == 1
+ && strcmp (target_type->name (), "uint8") == 0)
return 1;
}
}
static int
sixg_string_p (struct type *type)
{
- if (TYPE_NFIELDS (type) == 2
- && TYPE_TAG_NAME (type) != NULL
- && strcmp (TYPE_TAG_NAME (type), "string") == 0)
+ if (type->num_fields () == 2
+ && type->name () != NULL
+ && strcmp (type->name (), "string") == 0)
return 1;
return 0;
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.
If we ever need to unpack the method type, this routine should work
for that too. */
-static char *
+static gdb::unique_xmalloc_ptr<char>
unpack_mangled_go_symbol (const char *mangled_name,
const char **packagep,
const char **objectp,
/* main.init is mangled specially. */
if (strcmp (mangled_name, "__go_init_main") == 0)
{
- char *package = xstrdup ("main");
+ gdb::unique_xmalloc_ptr<char> package
+ = make_unique_xstrdup ("main");
- *packagep = package;
+ *packagep = package.get ();
*objectp = "init";
return package;
}
/* main.main is mangled specially (missing prefix). */
if (strcmp (mangled_name, "main.main") == 0)
{
- char *package = xstrdup ("main");
+ gdb::unique_xmalloc_ptr<char> package
+ = make_unique_xstrdup ("main");
- *packagep = package;
+ *packagep = package.get ();
*objectp = "main";
return package;
}
libgo_.*: used by gccgo's runtime
Thus we don't support -fgo-prefix (except as used by the runtime). */
- if (!startswith (mangled_name, "go.")
- && !startswith (mangled_name, "libgo_"))
+ bool v3;
+ if (startswith (mangled_name, "go_0"))
+ /* V3 mangling detected, see
+ https://go-review.googlesource.com/c/gofrontend/+/271726 . */
+ v3 = true;
+ else if (startswith (mangled_name, "go.")
+ || startswith (mangled_name, "libgo_"))
+ v3 = false;
+ else
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 (v3)
+ first_dot = strchr (mangled_name, '0');
+ else
+ first_dot = strchr (mangled_name, '.');
+
if (first_dot == NULL)
return NULL;
/* Treat "foo.bar" as unmangled. It can collide with lots of other
/* At this point we've decided we have a mangled Go symbol. */
- buf = xstrdup (mangled_name);
+ gdb::unique_xmalloc_ptr<char> result = make_unique_xstrdup (mangled_name);
+ buf = result.get ();
+
+ if (v3)
+ {
+ /* Replace "go_0" with "\0go.". */
+ buf[0] = '\0';
+ buf[1] = 'g';
+ buf[2] = 'o';
+ buf[3] = '.';
+
+ /* Skip the '\0'. */
+ buf++;
+ }
/* Search backwards looking for "N<digit(s)>". */
p = buf + len;
}
unpack_package_and_object (buf, packagep, objectp);
- return buf;
+ return result;
}
/* Implements the la_demangle language_defn routine for language Go.
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)
+gdb::unique_xmalloc_ptr<char>
+go_language::demangle_symbol (const char *mangled_name, int options) const
{
- struct obstack tempbuf;
- char *result;
- char *name_buf;
const char *package_name;
const char *object_name;
const char *method_type_package_name;
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);
+ gdb::unique_xmalloc_ptr<char> 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);
+ auto_obstack tempbuf;
/* Print methods as they appear in "method expressions". */
if (method_type_package_name != NULL)
}
obstack_grow_str0 (&tempbuf, "");
- result = xstrdup ((const char *) obstack_finish (&tempbuf));
- obstack_free (&tempbuf, NULL);
- xfree (name_buf);
- return result;
+ return make_unique_xstrdup ((const char *) obstack_finish (&tempbuf));
}
-/* la_sniff_from_mangled_name for Go. */
+/* See go-lang.h. */
-static int
-go_sniff_from_mangled_name (const char *mangled, char **demangled)
-{
- *demangled = go_demangle (mangled, 0);
- return *demangled != NULL;
-}
-
-/* Given a Go symbol, return its package or NULL if unknown.
- Space for the result is malloc'd, caller must free. */
-
-char *
+gdb::unique_xmalloc_ptr<char>
go_symbol_package_name (const struct symbol *sym)
{
- const char *mangled_name = SYMBOL_LINKAGE_NAME (sym);
+ const char *mangled_name = sym->linkage_name ();
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::unique_xmalloc_ptr<char> name_buf;
- gdb_assert (SYMBOL_LANGUAGE (sym) == language_go);
+ if (sym->language () != language_go)
+ return nullptr;
name_buf = unpack_mangled_go_symbol (mangled_name,
&package_name, &object_name,
&method_type_package_name,
/* 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 make_unique_xstrdup (package_name);
}
-/* Return the package that BLOCK is in, or NULL if there isn't one.
- Space for the result is malloc'd, caller must free. */
+/* See go-lang.h. */
-char *
+gdb::unique_xmalloc_ptr<char>
go_block_package_name (const struct block *block)
{
while (block != NULL)
{
- struct symbol *function = BLOCK_FUNCTION (block);
+ struct symbol *function = block->function ();
if (function != NULL)
{
- char *package_name = go_symbol_package_name (function);
+ gdb::unique_xmalloc_ptr<char> package_name
+ = go_symbol_package_name (function);
if (package_name != NULL)
return package_name;
return NULL;
}
- block = BLOCK_SUPERBLOCK (block);
+ block = block->superblock ();
}
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, OP_NULL, PREC_SUFFIX, 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
-};
+/* See language.h. */
-static void
-go_language_arch_info (struct gdbarch *gdbarch,
- struct language_arch_info *lai)
+void
+go_language::language_arch_info (struct gdbarch *gdbarch,
+ struct language_arch_info *lai) const
{
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;
+ /* Helper function to allow shorter lines below. */
+ auto add = [&] (struct type * t) -> struct type *
+ {
+ lai->add_primitive_type (t);
+ return t;
+ };
+
+ add (builtin->builtin_void);
+ add (builtin->builtin_char);
+ add (builtin->builtin_bool);
+ add (builtin->builtin_int);
+ add (builtin->builtin_uint);
+ add (builtin->builtin_uintptr);
+ add (builtin->builtin_int8);
+ add (builtin->builtin_int16);
+ add (builtin->builtin_int32);
+ add (builtin->builtin_int64);
+ add (builtin->builtin_uint8);
+ add (builtin->builtin_uint16);
+ add (builtin->builtin_uint32);
+ add (builtin->builtin_uint64);
+ add (builtin->builtin_float32);
+ add (builtin->builtin_float64);
+ add (builtin->builtin_complex64);
+ add (builtin->builtin_complex128);
+
+ lai->set_string_char_type (builtin->builtin_char);
+ lai->set_bool_type (builtin->builtin_bool, "bool");
}
-extern const struct language_defn go_language_defn =
-{
- "go",
- "Go",
- language_go,
- range_check_off,
- case_sensitive_on,
- array_row_major,
- macro_expansion_no,
- NULL,
- &exp_descriptor_c,
- go_parse,
- go_yyerror,
- 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. */
- default_read_var_value, /* la_read_var_value */
- NULL, /* Language specific skip_trampoline. */
- NULL, /* name_of_this */
- basic_lookup_symbol_nonlocal,
- basic_lookup_transparent_type,
- go_demangle, /* Language specific symbol demangler. */
- go_sniff_from_mangled_name,
- 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_collect_symbol_completion_matches,
- go_language_arch_info,
- default_print_array_index,
- default_pass_by_reference,
- c_get_string,
- c_watch_location_expression,
- NULL, /* la_get_symbol_name_cmp */
- iterate_over_symbols,
- &default_varobj_ops,
- NULL,
- NULL,
- LANG_MAGIC
-};
-
-static void *
+/* Single instance of the Go language class. */
+
+static go_language go_language_defn;
+
+static struct builtin_go_type *
build_go_types (struct gdbarch *gdbarch)
{
- struct builtin_go_type *builtin_go_type
- = GDBARCH_OBSTACK_ZALLOC (gdbarch, struct builtin_go_type);
+ struct builtin_go_type *builtin_go_type = new struct builtin_go_type;
- builtin_go_type->builtin_void
- = arch_type (gdbarch, TYPE_CODE_VOID, 1, "void");
+ type_allocator alloc (gdbarch);
+ builtin_go_type->builtin_void = builtin_type (gdbarch)->builtin_void;
builtin_go_type->builtin_char
- = arch_character_type (gdbarch, 8, 1, "char");
+ = init_character_type (alloc, 8, 1, "char");
builtin_go_type->builtin_bool
- = arch_boolean_type (gdbarch, 8, 0, "bool");
+ = init_boolean_type (alloc, 8, 0, "bool");
builtin_go_type->builtin_int
- = arch_integer_type (gdbarch, gdbarch_int_bit (gdbarch), 0, "int");
+ = init_integer_type (alloc, gdbarch_int_bit (gdbarch), 0, "int");
builtin_go_type->builtin_uint
- = arch_integer_type (gdbarch, gdbarch_int_bit (gdbarch), 1, "uint");
+ = init_integer_type (alloc, gdbarch_int_bit (gdbarch), 1, "uint");
builtin_go_type->builtin_uintptr
- = arch_integer_type (gdbarch, gdbarch_ptr_bit (gdbarch), 1, "uintptr");
+ = init_integer_type (alloc, gdbarch_ptr_bit (gdbarch), 1, "uintptr");
builtin_go_type->builtin_int8
- = arch_integer_type (gdbarch, 8, 0, "int8");
+ = init_integer_type (alloc, 8, 0, "int8");
builtin_go_type->builtin_int16
- = arch_integer_type (gdbarch, 16, 0, "int16");
+ = init_integer_type (alloc, 16, 0, "int16");
builtin_go_type->builtin_int32
- = arch_integer_type (gdbarch, 32, 0, "int32");
+ = init_integer_type (alloc, 32, 0, "int32");
builtin_go_type->builtin_int64
- = arch_integer_type (gdbarch, 64, 0, "int64");
+ = init_integer_type (alloc, 64, 0, "int64");
builtin_go_type->builtin_uint8
- = arch_integer_type (gdbarch, 8, 1, "uint8");
+ = init_integer_type (alloc, 8, 1, "uint8");
builtin_go_type->builtin_uint16
- = arch_integer_type (gdbarch, 16, 1, "uint16");
+ = init_integer_type (alloc, 16, 1, "uint16");
builtin_go_type->builtin_uint32
- = arch_integer_type (gdbarch, 32, 1, "uint32");
+ = init_integer_type (alloc, 32, 1, "uint32");
builtin_go_type->builtin_uint64
- = arch_integer_type (gdbarch, 64, 1, "uint64");
+ = init_integer_type (alloc, 64, 1, "uint64");
builtin_go_type->builtin_float32
- = arch_float_type (gdbarch, 32, "float32", floatformats_ieee_single);
+ = init_float_type (alloc, 32, "float32", floatformats_ieee_single);
builtin_go_type->builtin_float64
- = arch_float_type (gdbarch, 64, "float64", floatformats_ieee_double);
+ = init_float_type (alloc, 64, "float64", floatformats_ieee_double);
builtin_go_type->builtin_complex64
- = arch_complex_type (gdbarch, "complex64",
- builtin_go_type->builtin_float32);
+ = init_complex_type ("complex64", builtin_go_type->builtin_float32);
builtin_go_type->builtin_complex128
- = arch_complex_type (gdbarch, "complex128",
- builtin_go_type->builtin_float64);
+ = init_complex_type ("complex128", builtin_go_type->builtin_float64);
return builtin_go_type;
}
-static struct gdbarch_data *go_type_data;
+static const registry<gdbarch>::key<struct builtin_go_type> go_type_data;
const struct builtin_go_type *
builtin_go_type (struct gdbarch *gdbarch)
{
- return (const struct builtin_go_type *) gdbarch_data (gdbarch, go_type_data);
-}
+ struct builtin_go_type *result = go_type_data.get (gdbarch);
+ if (result == nullptr)
+ {
+ result = build_go_types (gdbarch);
+ go_type_data.set (gdbarch, result);
+ }
-void
-_initialize_go_language (void)
-{
- go_type_data = gdbarch_data_register_post_init (build_go_types);
+ return result;
}