compiler: rationalize external symbol names

Encode all external symbol names using only ASCII alphanumeric
    characters, underscore, and dot.  Use a scheme that can be reliably
    demangled to a somewhat readable version as described in the long
    comment in names.cc.
    
    A minor cleanup discovered during this was that we were treating
    function types as different if one had a NULL parameters_ field and
    another has a non-NULL parameters_ field that has no parameters.  This
    worked because we mangled them slightly differently.  We now mangle
    them the same, so we treat them as equal, as we should anyhow.
    
    Reviewed-on: https://go-review.googlesource.com/89555

	* go.go-torture/execute/names-1.go: New test.

From-SVN: r257033
This commit is contained in:
Ian Lance Taylor 2018-01-24 23:50:09 +00:00 committed by Ian Lance Taylor
parent d3719ee2c0
commit 4880b994d6
19 changed files with 923 additions and 375 deletions

View File

@ -1,4 +1,4 @@
3488a401e50835de5de5c4f153772ac2798d0e71
0bbc03f81c862fb35be3edee9824698a7892a17e
The first line of this file holds the git revision number of the last
merge done from the gofrontend repository.

View File

@ -686,8 +686,7 @@ debug_function_name(Named_object* fn)
if (!fn->is_function())
return Gogo::unpack_hidden_name(fn->name());
if (fn->func_value()->enclosing() == NULL)
{
std::string fnname = Gogo::unpack_hidden_name(fn->name());
if (fn->func_value()->is_method())
{
@ -712,16 +711,8 @@ debug_function_name(Named_object* fn)
break;
}
}
return fnname;
}
// Closures are named ".$nested#" where # is a global counter. Add outer
// function name for better distinguishing. This is also closer to what
// gc compiler prints, "outer.func#".
Named_object* enclosing = fn->func_value()->enclosing();
std::string name = Gogo::unpack_hidden_name(fn->name());
std::string outer_name = Gogo::unpack_hidden_name(enclosing->name());
return outer_name + "." + name;
return fnname;
}
// Return the name of the current function.

View File

@ -1310,6 +1310,16 @@ Func_descriptor_expression::do_get_backend(Translate_context* context)
&& Linemap::is_predeclared_location(no->location()))
is_descriptor = true;
// The runtime package implements some functions defined in the
// syscall package. Let the syscall package define the descriptor
// in this case.
if (gogo->compiling_runtime()
&& gogo->package_name() == "runtime"
&& no->is_function()
&& !no->func_value()->asm_name().empty()
&& no->func_value()->asm_name().compare(0, 8, "syscall.") == 0)
is_descriptor = true;
Btype* btype = this->type()->get_backend(gogo);
Bvariable* bvar;
@ -6845,7 +6855,8 @@ Bound_method_expression::create_thunk(Gogo* gogo, const Method* method,
if (orig_fntype == NULL || !orig_fntype->is_method())
{
ins.first->second = Named_object::make_erroneous_name(Gogo::thunk_name());
ins.first->second =
Named_object::make_erroneous_name(gogo->thunk_name());
return ins.first->second;
}
@ -6853,8 +6864,8 @@ Bound_method_expression::create_thunk(Gogo* gogo, const Method* method,
// The type here is wrong--it should be the C function type. But it
// doesn't really matter.
Type* vt = Type::make_pointer_type(Type::make_void_type());
sfl->push_back(Struct_field(Typed_identifier("fn.0", vt, loc)));
sfl->push_back(Struct_field(Typed_identifier("val.1",
sfl->push_back(Struct_field(Typed_identifier("fn", vt, loc)));
sfl->push_back(Struct_field(Typed_identifier("val",
orig_fntype->receiver()->type(),
loc)));
Struct_type* st = Type::make_struct_type(sfl, loc);
@ -6863,7 +6874,7 @@ Bound_method_expression::create_thunk(Gogo* gogo, const Method* method,
Function_type* new_fntype = orig_fntype->copy_with_names();
std::string thunk_name = Gogo::thunk_name();
std::string thunk_name = gogo->thunk_name();
Named_object* new_no = gogo->start_function(thunk_name, new_fntype,
false, loc);
@ -7009,10 +7020,10 @@ Bound_method_expression::do_flatten(Gogo* gogo, Named_object*,
// away with this.
Struct_field_list* fields = new Struct_field_list();
fields->push_back(Struct_field(Typed_identifier("fn.0",
fields->push_back(Struct_field(Typed_identifier("fn",
thunk->func_value()->type(),
loc)));
fields->push_back(Struct_field(Typed_identifier("val.1", val->type(), loc)));
fields->push_back(Struct_field(Typed_identifier("val", val->type(), loc)));
Struct_type* st = Type::make_struct_type(fields, loc);
st->set_is_struct_incomparable();
@ -11889,25 +11900,25 @@ Interface_field_reference_expression::create_thunk(Gogo* gogo,
const Typed_identifier* method_id = type->find_method(name);
if (method_id == NULL)
return Named_object::make_erroneous_name(Gogo::thunk_name());
return Named_object::make_erroneous_name(gogo->thunk_name());
Function_type* orig_fntype = method_id->type()->function_type();
if (orig_fntype == NULL)
return Named_object::make_erroneous_name(Gogo::thunk_name());
return Named_object::make_erroneous_name(gogo->thunk_name());
Struct_field_list* sfl = new Struct_field_list();
// The type here is wrong--it should be the C function type. But it
// doesn't really matter.
Type* vt = Type::make_pointer_type(Type::make_void_type());
sfl->push_back(Struct_field(Typed_identifier("fn.0", vt, loc)));
sfl->push_back(Struct_field(Typed_identifier("val.1", type, loc)));
sfl->push_back(Struct_field(Typed_identifier("fn", vt, loc)));
sfl->push_back(Struct_field(Typed_identifier("val", type, loc)));
Struct_type* st = Type::make_struct_type(sfl, loc);
st->set_is_struct_incomparable();
Type* closure_type = Type::make_pointer_type(st);
Function_type* new_fntype = orig_fntype->copy_with_names();
std::string thunk_name = Gogo::thunk_name();
std::string thunk_name = gogo->thunk_name();
Named_object* new_no = gogo->start_function(thunk_name, new_fntype,
false, loc);
@ -11995,10 +12006,10 @@ Interface_field_reference_expression::do_get_backend(Translate_context* context)
Location loc = this->location();
Struct_field_list* fields = new Struct_field_list();
fields->push_back(Struct_field(Typed_identifier("fn.0",
fields->push_back(Struct_field(Typed_identifier("fn",
thunk->func_value()->type(),
loc)));
fields->push_back(Struct_field(Typed_identifier("val.1",
fields->push_back(Struct_field(Typed_identifier("val",
this->expr_->type(),
loc)));
Struct_type* st = Type::make_struct_type(fields, loc);
@ -12247,7 +12258,7 @@ Selector_expression::lower_method_expression(Gogo* gogo)
return f;
}
Named_object* no = gogo->start_function(Gogo::thunk_name(), fntype, false,
Named_object* no = gogo->start_function(gogo->thunk_name(), fntype, false,
location);
Named_object* vno = gogo->lookup(receiver_name, NULL);

View File

@ -4,11 +4,16 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
#include "go-system.h"
#include "gogo.h"
#include "go-location.h"
#include "go-linemap.h"
#include "go-encode-id.h"
#include "lex.h"
// Return whether the character c is OK to use in the assembler.
// Return whether the character c is OK to use in the assembler. We
// only permit ASCII alphanumeric characters, underscore, and dot.
static bool
char_needs_encoding(char c)
@ -27,7 +32,7 @@ char_needs_encoding(char c)
case 'y': case 'z':
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
case '_': case '.': case '$': case '/':
case '_': case '.':
return false;
default:
return true;
@ -77,11 +82,25 @@ fetch_utf8_char(const char* p, unsigned int* pc)
return len;
}
// Encode an identifier using ASCII characters.
// Encode an identifier using ASCII characters. The encoding is
// described in detail near the end of the long comment at the start
// of names.cc. Short version: translate all non-ASCII-alphanumeric
// characters into ..uXXXX or ..UXXXXXXXX.
std::string
go_encode_id(const std::string &id)
{
if (Lex::is_invalid_identifier(id))
{
go_assert(saw_errors());
return id;
}
// The encoding is only unambiguous if the input string does not
// contain ..u or ..U.
go_assert(id.find("..u") == std::string::npos);
go_assert(id.find("..U") == std::string::npos);
std::string ret;
const char* p = id.c_str();
const char* pend = p + id.length();
@ -89,15 +108,24 @@ go_encode_id(const std::string &id)
{
unsigned int c;
size_t len = fetch_utf8_char(p, &c);
if (len == 1 && !char_needs_encoding(c))
if (len == 1)
{
// At this point we should only be seeing alphanumerics or
// underscore or dot.
go_assert(!char_needs_encoding(c));
ret += c;
}
else if (c < 0x10000)
{
char buf[16];
snprintf(buf, sizeof buf, "..u%04x", c);
ret += buf;
}
else
{
ret += "$U";
char buf[30];
snprintf(buf, sizeof buf, "%x", c);
char buf[16];
snprintf(buf, sizeof buf, "..U%08x", c);
ret += buf;
ret += "$";
}
p += len;
}
@ -111,3 +139,35 @@ go_selectively_encode_id(const std::string &id)
return go_encode_id(id);
return std::string();
}
// Encode a struct field tag. This is only used when we need to
// create a type descriptor for an anonymous struct type with field
// tags. This mangling is applied before go_encode_id. We skip
// alphanumerics and underscore, replace every other single byte
// character with .xNN, and leave larger UTF-8 characters for
// go_encode_id.
std::string
go_mangle_struct_tag(const std::string& tag)
{
std::string ret;
const char* p = tag.c_str();
const char* pend = p + tag.length();
while (p < pend)
{
unsigned int c;
size_t len = fetch_utf8_char(p, &c);
if (len > 1)
ret.append(p, len);
else if (!char_needs_encoding(c) && c != '.')
ret += c;
else
{
char buf[16];
snprintf(buf, sizeof buf, ".x%02x", c);
ret += buf;
}
p += len;
}
return ret;
}

View File

@ -9,10 +9,9 @@
#include "backend.h"
// Given an identifier corresponding to a function or variable,
// this helper returns TRUE if the identifier needs special
// encoding to be used as an ASM name (symbol), FALSE if the name
// is OK as is.
// Given an identifier that will appear in assembly code, this helper
// returns TRUE if the identifier needs special encoding to be used as
// an ASM name, FALSE if the name is OK as is.
extern bool
go_id_needs_encoding(const std::string& str);
@ -22,9 +21,12 @@ extern std::string
go_encode_id(const std::string &id);
// Returns the empty string if the specified name needs encoding,
// otherwise invokes go_encode_id() on the name and returns the
// result.
// otherwise invokes go_encode_id on the name and returns the result.
extern std::string
go_selectively_encode_id(const std::string &id);
// Encodes a struct tag that appears in a type literal encoding.
extern std::string
go_mangle_struct_tag(const std::string& tag);
#endif // !defined(GO_ENCODE_ID_H)

View File

@ -1758,7 +1758,7 @@ Gogo::start_function(const std::string& name, Function_type* type,
else
{
// Invent a name for a nested function.
nested_name = this->nested_function_name();
nested_name = this->nested_function_name(enclosing);
pname = &nested_name;
}
@ -4821,9 +4821,9 @@ Function::Function(Function_type* type, Named_object* enclosing, Block* block,
: type_(type), enclosing_(enclosing), results_(NULL),
closure_var_(NULL), block_(block), location_(location), labels_(),
local_type_count_(0), descriptor_(NULL), fndecl_(NULL), defer_stack_(NULL),
pragmas_(0), is_sink_(false), results_are_named_(false),
is_unnamed_type_stub_method_(false), calls_recover_(false),
is_recover_thunk_(false), has_recover_thunk_(false),
pragmas_(0), nested_functions_(0), is_sink_(false),
results_are_named_(false), is_unnamed_type_stub_method_(false),
calls_recover_(false), is_recover_thunk_(false), has_recover_thunk_(false),
calls_defer_retaddr_(false), is_type_specific_function_(false),
in_unique_section_(false)
{
@ -4948,7 +4948,7 @@ Function::set_closure_type()
// The first field of a closure is always a pointer to the function
// code.
Type* voidptr_type = Type::make_pointer_type(Type::make_void_type());
st->push_field(Struct_field(Typed_identifier(".$f", voidptr_type,
st->push_field(Struct_field(Typed_identifier(".f", voidptr_type,
this->location_)));
unsigned int index = 1;

View File

@ -801,7 +801,7 @@ class Gogo
// Return the name to use for a generated stub method.
std::string
stub_method_name(const std::string& method_name);
stub_method_name(const Package*, const std::string& method_name);
// Return the names of the hash and equality functions for TYPE.
void
@ -826,7 +826,7 @@ class Gogo
// Return a name to use for a thunk function. A thunk function is
// one we create during the compilation, for a go statement or a
// defer statement or a method expression.
static std::string
std::string
thunk_name();
// Return whether an object is a thunk.
@ -838,8 +838,8 @@ class Gogo
init_function_name();
// Return the name to use for a nested function.
static std::string
nested_function_name();
std::string
nested_function_name(Named_object* enclosing);
// Return the name to use for a sink funciton.
std::string
@ -887,6 +887,12 @@ class Gogo
std::string
interface_method_table_name(Interface_type*, Type*, bool is_pointer);
// Return whether NAME is a special name that can not be passed to
// unpack_hidden_name. This is needed because various special names
// use "..SUFFIX", but unpack_hidden_name just looks for '.'.
static bool
is_special_name(const std::string& name);
private:
// During parsing, we keep a stack of functions. Each function on
// the stack is one that we are currently parsing. For each
@ -1233,6 +1239,11 @@ class Function
results_are_named() const
{ return this->results_are_named_; }
// Return the assembler name.
const std::string&
asm_name() const
{ return this->asm_name_; }
// Set the assembler name.
void
set_asm_name(const std::string& asm_name)
@ -1250,6 +1261,14 @@ class Function
this->pragmas_ = pragmas;
}
// Return the index to use for a nested function.
unsigned int
next_nested_function_index()
{
++this->nested_functions_;
return this->nested_functions_;
}
// Whether this method should not be included in the type
// descriptor.
bool
@ -1510,6 +1529,8 @@ class Function
Temporary_statement* defer_stack_;
// Pragmas for this function. This is a set of GOPRAGMA bits.
unsigned int pragmas_;
// Number of nested functions defined within this function.
unsigned int nested_functions_;
// True if this function is sink-named. No code is generated.
bool is_sink_ : 1;
// True if the result variables are named.

View File

@ -2761,16 +2761,19 @@ bool
Lex::is_exported_name(const std::string& name)
{
unsigned char c = name[0];
if (c != '$')
if (c != '.')
return c >= 'A' && c <= 'Z';
else
{
const char* p = name.data();
size_t len = name.length();
if (len < 2 || p[1] != 'U')
if (len < 4 || p[1] != '.' || (p[2] != 'u' && p[2] != 'U'))
return false;
unsigned int ci = 0;
for (size_t i = 2; i < len && p[i] != '$'; ++i)
size_t want = (p[2] == 'u' ? 4 : 8);
if (len < want + 3)
return false;
for (size_t i = 3; i < want; ++i)
{
c = p[i];
if (!Lex::is_hex_digit(c))

File diff suppressed because it is too large Load Diff

View File

@ -2120,7 +2120,7 @@ Thunk_statement::simplify_statement(Gogo* gogo, Named_object* function,
fn = Expression::make_temporary_reference(fn_temp, location);
}
std::string thunk_name = Gogo::thunk_name();
std::string thunk_name = gogo->thunk_name();
// Build the thunk.
this->build_thunk(gogo, thunk_name);

View File

@ -2654,14 +2654,14 @@ Ptrmask::set_from(Gogo* gogo, Type* type, int64_t ptrsize, int64_t offset)
// Return a symbol name for this ptrmask. This is used to coalesce
// identical ptrmasks, which are common. The symbol name must use
// only characters that are valid in symbols. It's nice if it's
// short. We convert it to a base64 string.
// short. We convert it to a string that uses only 32 characters,
// avoiding digits and u and U.
std::string
Ptrmask::symname() const
{
const char chars[65] =
"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_.";
go_assert(chars[64] == '\0');
const char chars[33] = "abcdefghijklmnopqrstvwxyzABCDEFG";
go_assert(chars[32] == '\0');
std::string ret;
unsigned int b = 0;
int remaining = 0;
@ -2671,18 +2671,18 @@ Ptrmask::symname() const
{
b |= *p << remaining;
remaining += 8;
while (remaining >= 6)
while (remaining >= 5)
{
ret += chars[b & 0x3f];
b >>= 6;
remaining -= 6;
ret += chars[b & 0x1f];
b >>= 5;
remaining -= 5;
}
}
while (remaining > 0)
{
ret += chars[b & 0x3f];
b >>= 6;
remaining -= 6;
ret += chars[b & 0x1f];
b >>= 5;
remaining -= 5;
}
return ret;
}
@ -4447,7 +4447,11 @@ Function_type::is_identical(const Function_type* t, bool ignore_receiver,
}
const Typed_identifier_list* parms1 = this->parameters();
if (parms1 != NULL && parms1->empty())
parms1 = NULL;
const Typed_identifier_list* parms2 = t->parameters();
if (parms2 != NULL && parms2->empty())
parms2 = NULL;
if ((parms1 != NULL) != (parms2 != NULL))
{
if (reason != NULL)
@ -4492,7 +4496,11 @@ Function_type::is_identical(const Function_type* t, bool ignore_receiver,
}
const Typed_identifier_list* results1 = this->results();
if (results1 != NULL && results1->empty())
results1 = NULL;
const Typed_identifier_list* results2 = t->results();
if (results2 != NULL && results2->empty())
results2 = NULL;
if ((results1 != NULL) != (results2 != NULL))
{
if (reason != NULL)
@ -11144,7 +11152,7 @@ Type::build_stub_methods(Gogo* gogo, const Type* type, const Methods* methods,
package = NULL;
else
package = type->named_type()->named_object()->package();
std::string stub_name = gogo->stub_method_name(name);
std::string stub_name = gogo->stub_method_name(package, name);
Named_object* stub;
if (package != NULL)
stub = Named_object::make_function_declaration(stub_name, package,

View File

@ -1,3 +1,7 @@
2018-01-24 Ian Lance Taylor <iant@golang.org>
* go.go-torture/execute/names-1.go: New test.
2018-01-19 Jeff Law <law@redhat.com>
PR target/83994

View File

@ -0,0 +1,195 @@
// names-1 is a change detector for Go symbol names. We don't want
// the name mangling to change silently.
package main
import (
"bytes"
"debug/elf"
"debug/macho"
"debug/pe"
"debug/xcoff"
"fmt"
"os"
"strings"
)
type Type int
type Alias = int
//go:noinline
func Function1(out *bytes.Buffer) int {
var f2 func(int) int
f1 := func(i int) int {
if i == 0 {
return 0
}
type NestedType struct { a int }
t := NestedType{f2(i-1)}
fmt.Fprint(out, t)
return t.a
}
f2 = func(i int) int {
if i == 0 {
return 0
}
type NestedType struct { a int }
t := NestedType{f1(i-1)}
fmt.Fprint(out, t)
return t.a
}
return f1(10) + f2(10)
}
//go:noinline
func Function2(out *bytes.Buffer) {
{
type T struct { b int }
fmt.Fprint(out, T{1})
}
{
type T struct { b int }
fmt.Fprint(out, T{2})
}
}
func (t Type) M(bool, int8, float32, complex64, string, func(), func(int16) (float64, complex128), *byte, struct { f int "tag #$%^&{}: 世界" }, []int32, [24]int64, map[uint8]uint16, chan uint32, <-chan uint64, chan <- uintptr, Type, Alias) {
}
//go:noinline
func Function3(out *bytes.Buffer) {
fmt.Fprintf(out, "%T", Type(0))
}
func main() {
var b bytes.Buffer
Function1(&b)
Function2(&b)
Function3(&b)
_ = len(b.String())
for _, n := range []string{"/proc/self/exe", os.Args[0]} {
if f, err := os.Open(n); err == nil {
checkFile(f)
return
}
}
fmt.Println("checksyms: could not find executable")
fmt.Println("UNSUPPORTED: checksyms")
}
func checkFile(f *os.File) {
var syms []string
if ef, err := elf.NewFile(f); err == nil {
esyms, err := ef.Symbols()
if err != nil {
panic(err)
}
for _, esym := range esyms {
syms = append(syms, esym.Name)
}
} else if mf, err := macho.NewFile(f); err == nil {
for _, msym := range mf.Symtab.Syms {
syms = append(syms, msym.Name)
}
} else if pf, err := pe.NewFile(f); err == nil {
for _, psym := range pf.Symbols {
syms = append(syms, psym.Name)
}
} else if xf, err := xcoff.NewFile(f); err == nil {
for _, xsym := range xf.Symbols {
syms = append(syms, xsym.Name)
}
} else {
fmt.Println("checksyms: could not parse executable")
fmt.Println("UNSUPPORTED: checksyms")
return
}
checkSyms(syms)
}
var want = []string{
"main.Function1",
"main.Function1..f",
"main.Function1..func1",
"main.Function1..func1.main.NestedType..d",
"main.Function1..func2",
"main.Function1..func2.main.NestedType..d",
"main.Function2",
"main.Function2..f",
"main.Function2.main.T..d",
"main.Function2.main.T..i1..d",
"main.Function3",
"main.Function3..f",
"main.Type..d",
"main.Type.M",
"main.main",
"main.want",
"type...1.1main.Type", // Why is this here?
"type...1main.Function1..func1.NestedType",
"type...1main.Function1..func2.NestedType",
"type...1main.Function2.T",
"type...1main.Function2.T..i1",
"type...1main.Type",
"type..func.8.1main.Type.3bool.3int8.3float32.3complex64.3string.3func.8.9.8.9.3func.8int16.9.8float64.3complex128.9.3.1uint8.3struct.4.main.f.0int.4tag.x20.x23.x24.x25.x5e.x26.x7b.x7d.x3a.x20..u4e16..u754c.5.5.3.6.7int32.3.624.7int64.3map.6uint8.7uint16.3chan.0uint32.3.4.5chan.0uint64.3chan.4.5.0uintptr.3main.Type.3int.9.8.9",
"type..func.8bool.3int8.3float32.3complex64.3string.3func.8.9.8.9.3func.8int16.9.8float64.3complex128.9.3.1uint8.3struct.4.main.f.0int.4tag.x20.x23.x24.x25.x5e.x26.x7b.x7d.x3a.x20..u4e16..u754c.5.5.3.6.7int32.3.624.7int64.3map.6uint8.7uint16.3chan.0uint32.3.4.5chan.0uint64.3chan.4.5.0uintptr.3main.Type.3int.9.8.9",
"type..func.8main.Type.3bool.3int8.3float32.3complex64.3string.3func.8.9.8.9.3func.8int16.9.8float64.3complex128.9.3.1uint8.3struct.4.main.f.0int.4tag.x20.x23.x24.x25.x5e.x26.x7b.x7d.x3a.x20..u4e16..u754c.5.5.3.6.7int32.3.624.7int64.3map.6uint8.7uint16.3chan.0uint32.3.4.5chan.0uint64.3chan.4.5.0uintptr.3main.Type.3int.9.8.9",
"type..struct.4.main.f.0int.4tag.x20.x23.x24.x25.x5e.x26.x7b.x7d.x3a.x20..u4e16..u754c.5.5",
}
func checkSyms(syms []string) {
m := make(map[string]bool)
for _, sym := range syms {
if strings.Contains(sym, ".") {
m[sym] = true
}
}
ok := true
for _, w := range want {
if m[w] {
delete(m, w)
} else {
fmt.Printf("checksyms: missing expected symbol %q\n", w)
ok = false
}
}
for sym := range m {
if !strings.Contains(sym, "main") {
continue
}
// Skip some symbols we may see but know are unimportant.
if sym == "go-main.c" {
continue
}
if strings.HasPrefix(sym, "runtime.") {
continue
}
// We can see a lot of spurious .eq and .hash
// functions for types defined in other packages.
// This is a bug but skip them for now.
if strings.Contains(sym, "..eq") || strings.Contains(sym, "..hash") {
continue
}
// Skip closure types by skipping incomparable structs.
// This may be a bug, not sure.
if strings.Contains(sym, ".4x.5") {
continue
}
// These functions may be inlined.
if sym == "main.checkFile" || sym == "main.checkSyms" {
continue
}
fmt.Printf("checksyms: found unexpected symbol %q\n", sym)
ok = false
}
if !ok {
fmt.Println("FAIL: checksyms")
}
}

View File

@ -425,7 +425,7 @@ func TestPanicTraceback(t *testing.T) {
// Check functions in the traceback.
fns := []string{"main.pt1.func1", "panic", "main.pt2.func1", "panic", "main.pt2", "main.pt1"}
if runtime.Compiler == "gccgo" {
fns = []string{"main.$nested", "panic", "main.$nested", "panic", "main.pt2", "main.pt1"}
fns = []string{"main.pt1..func1", "panic", "main.pt2..func1", "panic", "main.pt2", "main.pt1"}
}
for _, fn := range fns {
var re *regexp.Regexp
@ -570,7 +570,7 @@ func TestPanicInlined(t *testing.T) {
buf = buf[:n]
want := []byte("(*point).negate(")
if runtime.Compiler == "gccgo" {
want = []byte("negate.pN18_runtime_test.point")
want = []byte("point.negate")
}
if !bytes.Contains(buf, want) {
t.Logf("%s", buf)

View File

@ -656,7 +656,7 @@ func canrecover(retaddr uintptr) bool {
}
// Ignore other functions in the reflect package.
if hasprefix(name, "reflect.") {
if hasprefix(name, "reflect.") || hasprefix(name, ".1reflect.") {
continue
}

View File

@ -730,7 +730,7 @@ func TestMutexProfile(t *testing.T) {
stks := stacks(p)
for _, want := range [][]string{
// {"sync.(*Mutex).Unlock", "pprof.blockMutex.func1"},
{"sync.Unlock.pN10_sync.Mutex", "pprof.$nested17"},
{".1sync.Mutex.Unlock", "pprof.blockMutex..func1"},
} {
if !containsStack(stks, want) {
t.Errorf("No matching stack entry for %+v", want)

View File

@ -17,7 +17,7 @@
#endif
extern _Bool Exited (uint32_t *w)
__asm__ (GOSYM_PREFIX "syscall.Exited.N18_syscall.WaitStatus");
__asm__ (GOSYM_PREFIX "syscall.WaitStatus.Exited");
_Bool
Exited (uint32_t *w)
@ -26,7 +26,7 @@ Exited (uint32_t *w)
}
extern _Bool Signaled (uint32_t *w)
__asm__ (GOSYM_PREFIX "syscall.Signaled.N18_syscall.WaitStatus");
__asm__ (GOSYM_PREFIX "syscall.WaitStatus.Signaled");
_Bool
Signaled (uint32_t *w)
@ -35,7 +35,7 @@ Signaled (uint32_t *w)
}
extern _Bool Stopped (uint32_t *w)
__asm__ (GOSYM_PREFIX "syscall.Stopped.N18_syscall.WaitStatus");
__asm__ (GOSYM_PREFIX "syscall.WaitStatus.Stopped");
_Bool
Stopped (uint32_t *w)
@ -44,7 +44,7 @@ Stopped (uint32_t *w)
}
extern _Bool Continued (uint32_t *w)
__asm__ (GOSYM_PREFIX "syscall.Continued.N18_syscall.WaitStatus");
__asm__ (GOSYM_PREFIX "syscall.WaitStatus.Continued");
_Bool
Continued (uint32_t *w)
@ -53,7 +53,7 @@ Continued (uint32_t *w)
}
extern _Bool CoreDump (uint32_t *w)
__asm__ (GOSYM_PREFIX "syscall.CoreDump.N18_syscall.WaitStatus");
__asm__ (GOSYM_PREFIX "syscall.WaitStatus.CoreDump");
_Bool
CoreDump (uint32_t *w)
@ -62,7 +62,7 @@ CoreDump (uint32_t *w)
}
extern int ExitStatus (uint32_t *w)
__asm__ (GOSYM_PREFIX "syscall.ExitStatus.N18_syscall.WaitStatus");
__asm__ (GOSYM_PREFIX "syscall.WaitStatus.ExitStatus");
int
ExitStatus (uint32_t *w)
@ -73,7 +73,7 @@ ExitStatus (uint32_t *w)
}
extern int Signal (uint32_t *w)
__asm__ (GOSYM_PREFIX "syscall.Signal.N18_syscall.WaitStatus");
__asm__ (GOSYM_PREFIX "syscall.WaitStatus.Signal");
int
Signal (uint32_t *w)
@ -84,7 +84,7 @@ Signal (uint32_t *w)
}
extern int StopSignal (uint32_t *w)
__asm__ (GOSYM_PREFIX "syscall.StopSignal.N18_syscall.WaitStatus");
__asm__ (GOSYM_PREFIX "syscall.WaitStatus.StopSignal");
int
StopSignal (uint32_t *w)
@ -95,7 +95,7 @@ StopSignal (uint32_t *w)
}
extern int TrapCause (uint32_t *w)
__asm__ (GOSYM_PREFIX "syscall.TrapCause.N18_syscall.WaitStatus");
__asm__ (GOSYM_PREFIX "syscall.WaitStatus.TrapCause");
int
TrapCause (uint32_t *w __attribute__ ((unused)))

View File

@ -68,13 +68,14 @@ callback (void *data, uintptr_t pc, const char *filename, int lineno,
{
const char *p;
p = __builtin_strchr (function, '.');
if (p != NULL && __builtin_strncmp (p + 1, "$thunk", 6) == 0)
p = function + __builtin_strlen (function);
while (p > function && p[-1] >= '0' && p[-1] <= '9')
--p;
if (p - function > 7 && __builtin_strncmp (p - 7, "..thunk", 7) == 0)
return 0;
p = __builtin_strrchr (function, '$');
if (p != NULL && __builtin_strcmp(p, "$recover") == 0)
if (p - function > 3 && __builtin_strcmp (p - 3, "..r") == 0)
return 0;
if (p != NULL && __builtin_strncmp(p, "$stub", 5) == 0)
if (p - function > 6 && __builtin_strcmp (p - 6, "..stub") == 0)
return 0;
}

View File

@ -15,10 +15,10 @@
descriptor. */
extern const struct __go_type_descriptor unsafe_Pointer
__asm__ (GOSYM_PREFIX "__go_tdn_unsafe.Pointer");
__asm__ (GOSYM_PREFIX "unsafe.Pointer..d");
extern const byte unsafe_Pointer_gc[]
__asm__ (GOSYM_PREFIX "__go_tdn_unsafe.Pointer$gc");
__asm__ (GOSYM_PREFIX "unsafe.Pointer..g");
/* Used to determine the field alignment. */
struct field_align
@ -38,9 +38,9 @@ static const String reflection_string =
const byte unsafe_Pointer_gc[] = { 1 };
extern const FuncVal runtime_pointerhash_descriptor
__asm__ (GOSYM_PREFIX "runtime.pointerhash$descriptor");
__asm__ (GOSYM_PREFIX "runtime.pointerhash..f");
extern const FuncVal runtime_pointerequal_descriptor
__asm__ (GOSYM_PREFIX "runtime.pointerequal$descriptor");
__asm__ (GOSYM_PREFIX "runtime.pointerequal..f");
const struct __go_type_descriptor unsafe_Pointer =
{
@ -75,7 +75,7 @@ const struct __go_type_descriptor unsafe_Pointer =
it to be defined elsewhere. */
extern const struct __go_ptr_type pointer_unsafe_Pointer
__asm__ (GOSYM_PREFIX "__go_td_pN14_unsafe.Pointer");
__asm__ (GOSYM_PREFIX "type...1unsafe.Pointer");
/* The reflection string. */
#define PREFLECTION "*unsafe.Pointer"
@ -86,7 +86,7 @@ static const String preflection_string =
};
extern const byte pointer_unsafe_Pointer_gc[]
__asm__ (GOSYM_PREFIX "__go_td_pN14_unsafe.Pointer$gc");
__asm__ (GOSYM_PREFIX "type...1unsafe.Pointer..g");
const byte pointer_unsafe_Pointer_gc[] = { 1 };