From patchwork Thu Oct 25 22:18:16 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Ian Lance Taylor X-Patchwork-Id: 989392 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=gcc.gnu.org (client-ip=209.132.180.131; helo=sourceware.org; envelope-from=gcc-patches-return-488330-incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=golang.org Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="aGvSq7ac"; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=golang-org.20150623.gappssmtp.com header.i=@golang-org.20150623.gappssmtp.com header.b="BOiHGYJ8"; dkim-atps=neutral Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 42h1js0XKtz9s9m for ; Fri, 26 Oct 2018 09:18:40 +1100 (AEDT) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender :mime-version:from:date:message-id:subject:to:content-type; q= dns; s=default; b=UiltSKj8IDMZyjNnj3DuI+Ob9BAI3CcyANnO/yRBgxr5pw qFuZuv6+e05N+HPy2qn9T+Abs99Fn139gcY8KANjWA8yezYzpp19Z78ghEpLHAZd bXir9hv+HQXunqnhG3qfHgBfGIa/hpUcJ04kbNjkzwCm/i6hPr58Boa1UzePM= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender :mime-version:from:date:message-id:subject:to:content-type; s= default; bh=VNSpScWU1LQeTggqsbKpTPMHsxM=; b=aGvSq7ach5s2AYw1AwPk uVBrkjxz3bCbrUoFCPJ+em9lXw641RJc9RKD32jFxrKLciBnBcX8cQZ95vblPJwg Yt4T/Xdg5YZoUI4X2Drsrn5BKF6CFnPmDHJzOPGUPG6pTcjcLl6ttT1o3Rmf4hxF 3oSyiN0432lazJCnjo65PV4= Received: (qmail 15940 invoked by alias); 25 Oct 2018 22:18:29 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 15918 invoked by uid 89); 25 Oct 2018 22:18:28 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-14.2 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_ASCII_DIVIDERS, KAM_STOCKGEN, RCVD_IN_DNSWL_NONE, SPF_PASS autolearn=ham version=3.3.2 spammy=namescc, UD:names.cc, names.cc, Equal X-HELO: mail-lj1-f182.google.com Received: from mail-lj1-f182.google.com (HELO mail-lj1-f182.google.com) (209.85.208.182) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Thu, 25 Oct 2018 22:18:20 +0000 Received: by mail-lj1-f182.google.com with SMTP id o14-v6so9732628ljj.2 for ; Thu, 25 Oct 2018 15:18:19 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=golang-org.20150623.gappssmtp.com; s=20150623; h=mime-version:from:date:message-id:subject:to; bh=pUDy9i7MmsqeOIfGCRLzYGy0hEM2z0/xYDLX3JyWsWA=; b=BOiHGYJ8+KH/vX5TQYKnu+EJe2y5d84uTcKZ1YHRyRDelzI6kSdFy+52AwqRLb5Eef wWuwOE6z5T1PZapihkDEAInwrd9xgsOtCU3tD7xjns/OOngvqlVRWT0hPnwuU5jpLuLA K2it113iy4N1hxZ3v8782DxTGyZd4Pt12edkyf/geQxD2Wbh1ijztekYB2yoccJ5CDyo 5OynpTdxJxQL57lvO7rbuSOENN4pwMjriUQABt2eIYG9gBSxJO4Cr1a713T6ppWsQCt+ J5ZPN+rYajknlR7Gh7Af/GE3tT/VPfKRnGIf+MSaxLjQakvHiyKl0DcEyDkYGPKGfBx8 iw+g== MIME-Version: 1.0 Received: by 2002:ab3:7d86:0:0:0:0:0 with HTTP; Thu, 25 Oct 2018 15:18:16 -0700 (PDT) From: Ian Lance Taylor Date: Thu, 25 Oct 2018 15:18:16 -0700 Message-ID: Subject: Go patch committed: Improve name mangling for package paths To: gcc-patches , gofrontend-dev@googlegroups.com This patch by Than McIntosh improves the mangling of package paths in the Go frontend. The current implementation of Gogo::pkgpath_for_symbol was written in a way that allowed two distinct package paths to map to the same symbol, which could cause collisions at link- time or compile-time. This patch switches to a better mangling scheme to ensure that we get a unique packagepath symbol for each package. In the new scheme instead of having separate mangling schemes for identifiers and package paths, the main identifier mangler ("go_encode_id") now handles mangling of both packagepath characters and identifier characters. The new mangling scheme is more intrusive: "foo/bar.Baz" is mangled as "foo..z2fbar.Baz" instead of "foo_bar.Baz". To mitigate this, this patch also adds a demangling capability so that function names returned from runtime.CallersFrames are converted back to their original unmangled form. Changing the pkgpath_for_symbol scheme requires updating a number of //go:linkname directives and C "__asm__" directives to match the new scheme, as well as updating the 'gotest' driver (which makes assumptions about the correct mapping from pkgpath symbol to package name). This fixes https://golang.org/issue/27534. Note that this changes the name mangling of many symbols in libgo. Bootstrapped and ran Go testsuite on x86_64-pc-linux-gnu. Committed to mainline. Ian Index: gcc/go/gofrontend/MERGE =================================================================== --- gcc/go/gofrontend/MERGE (revision 265460) +++ gcc/go/gofrontend/MERGE (working copy) @@ -1,4 +1,4 @@ -771668f7137e560b2ef32c8799e5f8b4c4ee14a9 +407a59831ea4fbfe03f0887c40497b73939e7c44 The first line of this file holds the git revision number of the last merge done from the gofrontend repository. Index: gcc/go/gofrontend/go-encode-id.cc =================================================================== --- gcc/go/gofrontend/go-encode-id.cc (revision 265460) +++ gcc/go/gofrontend/go-encode-id.cc (working copy) @@ -1,4 +1,4 @@ -// go-encode-id.cc -- Go identifier encoding hooks +// go-encode-id.cc -- Go identifier and packagepath encoding/decoding hooks // Copyright 2016 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style @@ -82,10 +82,10 @@ fetch_utf8_char(const char* p, unsigned return len; } -// 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. +// Encode an identifier using assembler-friendly 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, translate ASCII non-alphanumerics into ".zXX". std::string go_encode_id(const std::string &id) @@ -97,7 +97,8 @@ go_encode_id(const std::string &id) } // The encoding is only unambiguous if the input string does not - // contain ..u or ..U. + // contain ..z, ..u or ..U. + go_assert(id.find("..z") == std::string::npos); go_assert(id.find("..u") == std::string::npos); go_assert(id.find("..U") == std::string::npos); @@ -116,17 +117,16 @@ go_encode_id(const std::string &id) { unsigned int c; size_t len = fetch_utf8_char(p, &c); - if (len == 1) + if (len == 1 && !char_needs_encoding(c)) { - // At this point we should only be seeing alphanumerics or - // underscore or dot. - go_assert(!char_needs_encoding(c)); ret += c; } else { char buf[16]; - if (c < 0x10000) + if (len == 1) + snprintf(buf, sizeof buf, "..z%02x", c); + else if (c < 0x10000) snprintf(buf, sizeof buf, "..u%04x", c); else snprintf(buf, sizeof buf, "..U%08x", c); @@ -143,6 +143,77 @@ go_encode_id(const std::string &id) return ret; } +// Convert a hex digit string to a unicode codepoint. No checking +// to insure that the hex digit is meaningful. + +static unsigned +hex_digits_to_unicode_codepoint(const char *digits, unsigned ndig) +{ + unsigned result = 0; + for (unsigned i = 0; i < ndig; ++i) { + result <<= 4; + result |= Lex::hex_val(digits[i]); + } + return result; +} + +// Decode/demangle a mangled string produced by go_encode_id(). Returns +// empty string if demangling process fails in some way. At the moment +// this routine is unused; there is an equivalent routine in the runtime +// used for demangling symbols appearing in stack traces. + +std::string +go_decode_id(const std::string &encoded) +{ + std::string ret; + const char* p = encoded.c_str(); + const char* pend = p + encoded.length(); + const Location loc = Linemap::predeclared_location(); + + // Special case for initial "_", in case it was introduced + // as a way to prevent encoded symbol starting with ".". + if (*p == '_' && (strncmp(p+1, "..u", 3) == 0 || strncmp(p+1, "..U", 3) == 0)) + p++; + + while (p < pend) + { + if (strncmp(p, "..z", 3) == 0) + { + const char* digits = p+3; + if (strlen(digits) < 2) + return ""; + unsigned rune = hex_digits_to_unicode_codepoint(digits, 2); + Lex::append_char(rune, true, &ret, loc); + p += 5; + } + else if (strncmp(p, "..u", 3) == 0) + { + const char* digits = p+3; + if (strlen(digits) < 4) + return ""; + unsigned rune = hex_digits_to_unicode_codepoint(digits, 4); + Lex::append_char(rune, true, &ret, loc); + p += 7; + } + else if (strncmp(p, "..U", 3) == 0) + { + const char* digits = p+3; + if (strlen(digits) < 8) + return ""; + unsigned rune = hex_digits_to_unicode_codepoint(digits, 8); + Lex::append_char(rune, true, &ret, loc); + p += 11; + } + else + { + ret += *p; + p += 1; + } + } + + return ret; +} + std::string go_selectively_encode_id(const std::string &id) { Index: gcc/go/gofrontend/go-encode-id.h =================================================================== --- gcc/go/gofrontend/go-encode-id.h (revision 265460) +++ gcc/go/gofrontend/go-encode-id.h (working copy) @@ -20,6 +20,11 @@ go_id_needs_encoding(const std::string& extern std::string go_encode_id(const std::string &id); +// Decodes an encoded ID, returning the original string handed off to +// go_encode_id(). +extern std::string +go_decode_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. extern std::string Index: gcc/go/gofrontend/gogo.cc =================================================================== --- gcc/go/gofrontend/gogo.cc (revision 265460) +++ gcc/go/gofrontend/gogo.cc (working copy) @@ -256,26 +256,11 @@ Gogo::Gogo(Backend* backend, Linemap* li this->globals_->add_function_declaration("delete", NULL, delete_type, loc); } -// Convert a pkgpath into a string suitable for a symbol. Note that -// this transformation is convenient but imperfect. A -fgo-pkgpath -// option of a/b_c will conflict with a -fgo-pkgpath option of a_b/c, -// possibly leading to link time errors. - std::string Gogo::pkgpath_for_symbol(const std::string& pkgpath) { - std::string s = pkgpath; - for (size_t i = 0; i < s.length(); ++i) - { - char c = s[i]; - if ((c >= 'a' && c <= 'z') - || (c >= 'A' && c <= 'Z') - || (c >= '0' && c <= '9')) - ; - else - s[i] = '_'; - } - return s; + go_assert(!pkgpath.empty()); + return go_encode_id(pkgpath); } // Get the package path to use for type reflection data. This should @@ -319,6 +304,32 @@ Gogo::set_prefix(const std::string& arg) this->prefix_from_option_ = true; } +// Given a name which may or may not have been hidden, append the +// appropriate version of the name to the result string. Take care +// to avoid creating a sequence that will be rejected by go_encode_id +// (avoid ..u, ..U, ..z). +void +Gogo::append_possibly_hidden_name(std::string *result, const std::string& name) +{ + // FIXME: This adds in pkgpath twice for hidden symbols, which is + // less than ideal. + if (!Gogo::is_hidden_name(name)) + (*result) += name; + else + { + std::string n = "."; + std::string pkgpath = Gogo::hidden_name_pkgpath(name); + char lastR = result->at(result->length() - 1); + char firstP = pkgpath.at(0); + if (lastR == '.' && (firstP == 'u' || firstP == 'U' || firstP == 'z')) + n = "_."; + n.append(pkgpath); + n.append(1, '.'); + n.append(Gogo::unpack_hidden_name(name)); + (*result) += n; + } +} + // Munge name for use in an error message. std::string Index: gcc/go/gofrontend/gogo.h =================================================================== --- gcc/go/gofrontend/gogo.h (revision 265460) +++ gcc/go/gofrontend/gogo.h (working copy) @@ -199,26 +199,10 @@ class Gogo return name.substr(1, name.rfind('.') - 1); } - // Given a name which may or may not have been hidden, return the - // name to use within a mangled symbol name. - static std::string - mangle_possibly_hidden_name(const std::string& name) - { - // FIXME: This adds in pkgpath twice for hidden symbols, which is - // less than ideal. - std::string n; - if (!Gogo::is_hidden_name(name)) - n = name; - else - { - n = "."; - std::string pkgpath = Gogo::hidden_name_pkgpath(name); - n.append(Gogo::pkgpath_for_symbol(pkgpath)); - n.append(1, '.'); - n.append(Gogo::unpack_hidden_name(name)); - } - return n; - } + // Given a name which may or may not have been hidden, append the + // appropriate version of the name to the result string. + static void + append_possibly_hidden_name(std::string *result, const std::string& name); // Given a name which may or may not have been hidden, return the // name to use in an error message. Index: gcc/go/gofrontend/lex.h =================================================================== --- gcc/go/gofrontend/lex.h (revision 265460) +++ gcc/go/gofrontend/lex.h (working copy) @@ -440,6 +440,10 @@ class Lex static bool is_unicode_space(unsigned int c); + // Convert the specified hex char into an unsigned integer value. + static unsigned + hex_val(char c); + private: ssize_t get_line(); @@ -462,9 +466,6 @@ class Lex octal_value(char c) { return c - '0'; } - static unsigned - hex_val(char c); - Token make_invalid_token() { return Token::make_invalid_token(this->location()); } Index: gcc/go/gofrontend/names.cc =================================================================== --- gcc/go/gofrontend/names.cc (revision 265460) +++ gcc/go/gofrontend/names.cc (working copy) @@ -33,7 +33,7 @@ // variable, is simply "PKGPATH.NAME". Note that NAME is not the // packed form used for the "hidden" name internally in the compiler; // it is the name that appears in the source code. PKGPATH is the -// -fgo-pkgpath option as adjusted by Gogo::pkgpath_for_symbol. Note +// -fgo-pkgpath option as adjusted by Gogo::pkgpath_for_symbol. Note // that PKGPATH can not contain a dot and neither can NAME. Also, // NAME may not begin with a digit. NAME may require further encoding // for non-ASCII characters as described below, but until that @@ -188,12 +188,17 @@ // encoding unambiguous, we introduce it with two consecutive dots. // This is followed by the letter u and four hex digits or the letter // U and eight digits, just as in the language only using ..u and ..U -// instead of \u and \U. Since before this encoding names can never -// contain consecutive dots followed by 'u' or 'U', and after this -// encoding "..u" and "..U" are followed by a known number of +// instead of \u and \U. The compiler also produces identifiers that +// are qualified by package path, which means that there may also be ASCII +// characters that are not assembler-friendly (ex: '=', '/'). The encoding +// scheme translates such characters into the "..zNN" where NN is the +// hex value for the character. Since before this encoding names can never +// contain consecutive dots followed by 'z', 'u' or 'U', and after this +// encoding "..z", "..u" and "..U" are followed by a known number of // characters, this is unambiguous. // // Demangling these names is straightforward: +// - replace ..zXX with an ASCII character // - replace ..uXXXX with a unicode character // - replace ..UXXXXXXXX with a unicode character // - replace .D, where D is a digit, with the character from the above @@ -215,9 +220,9 @@ Gogo::function_asm_name(const std::strin if (rtype != NULL) ret = rtype->deref()->mangled_name(this); else if (package == NULL) - ret = this->pkgpath_symbol(); + ret = this->pkgpath(); else - ret = package->pkgpath_symbol(); + ret = package->pkgpath(); ret.push_back('.'); // Check for special names that will break if we use // Gogo::unpack_hidden_name. @@ -268,7 +273,7 @@ Gogo::stub_method_name(const Package* pa // We are creating a stub method for an unexported method of an // imported embedded type. We need to disambiguate the method name. - std::string ret = this->pkgpath_symbol_for_package(mpkgpath); + std::string ret = mpkgpath; ret.push_back('.'); ret.append(Gogo::unpack_hidden_name(mname)); ret.append("..stub"); @@ -302,9 +307,9 @@ Gogo::global_var_asm_name(const std::str { std::string ret; if (package == NULL) - ret = this->pkgpath_symbol(); + ret = this->pkgpath(); else - ret = package->pkgpath_symbol(); + ret = package->pkgpath(); ret.append(1, '.'); ret.append(Gogo::unpack_hidden_name(go_name)); return go_encode_id(ret); @@ -341,7 +346,7 @@ Gogo::thunk_name() char thunk_name[50]; snprintf(thunk_name, sizeof thunk_name, "..thunk%d", thunk_count); ++thunk_count; - std::string ret = this->pkgpath_symbol(); + std::string ret = this->pkgpath(); return ret + thunk_name; } @@ -370,7 +375,7 @@ Gogo::init_function_name() char buf[30]; snprintf(buf, sizeof buf, "..init%d", init_count); ++init_count; - std::string ret = this->pkgpath_symbol(); + std::string ret = this->pkgpath(); return ret + buf; } @@ -726,7 +731,7 @@ Struct_type::do_mangled_name(Gogo* gogo, if (!p->is_anonymous()) { - ret->append(Gogo::mangle_possibly_hidden_name(p->field_name())); + Gogo::append_possibly_hidden_name(ret, p->field_name()); ret->push_back(' '); } @@ -827,7 +832,7 @@ Interface_type::do_mangled_name(Gogo* go if (!p->name().empty()) { - ret->append(Gogo::mangle_possibly_hidden_name(p->name())); + Gogo::append_possibly_hidden_name(ret, p->name()); ret->push_back(' '); } @@ -854,9 +859,9 @@ Forward_declaration_type::do_mangled_nam { const Named_object* no = this->named_object(); if (no->package() == NULL) - ret->append(gogo->pkgpath_symbol()); + ret->append(gogo->pkgpath()); else - ret->append(no->package()->pkgpath_symbol()); + ret->append(no->package()->pkgpath()); ret->push_back('.'); ret->append(Gogo::unpack_hidden_name(no->name())); } @@ -894,18 +899,18 @@ Named_type::append_mangled_type_name(Gog if (rcvr != NULL) ret->append(rcvr->type()->deref()->mangled_name(gogo)); else if (this->in_function_->package() == NULL) - ret->append(gogo->pkgpath_symbol()); + ret->append(gogo->pkgpath()); else - ret->append(this->in_function_->package()->pkgpath_symbol()); + ret->append(this->in_function_->package()->pkgpath()); ret->push_back('.'); ret->append(Gogo::unpack_hidden_name(this->in_function_->name())); } else { if (no->package() == NULL) - ret->append(gogo->pkgpath_symbol()); + ret->append(gogo->pkgpath()); else - ret->append(no->package()->pkgpath_symbol()); + ret->append(no->package()->pkgpath()); } ret->push_back('.'); } @@ -951,22 +956,22 @@ Gogo::type_descriptor_name(Type* type, N if (rcvr != NULL) ret.append(rcvr->type()->deref()->mangled_name(this)); else if (in_function->package() == NULL) - ret.append(this->pkgpath_symbol()); + ret.append(this->pkgpath()); else - ret.append(in_function->package()->pkgpath_symbol()); + ret.append(in_function->package()->pkgpath()); ret.push_back('.'); ret.append(Gogo::unpack_hidden_name(in_function->name())); ret.push_back('.'); } if (no->package() == NULL) - ret.append(this->pkgpath_symbol()); + ret.append(this->pkgpath()); else - ret.append(no->package()->pkgpath_symbol()); + ret.append(no->package()->pkgpath()); ret.push_back('.'); } - ret.append(Gogo::mangle_possibly_hidden_name(no->name())); + Gogo::append_possibly_hidden_name(&ret, no->name()); if (in_function != NULL && index > 0) { Index: libgo/go/cmd/cgo/main.go =================================================================== --- libgo/go/cmd/cgo/main.go (revision 265460) +++ libgo/go/cmd/cgo/main.go (working copy) @@ -229,6 +229,8 @@ var exportHeader = flag.String("exporthe var gccgo = flag.Bool("gccgo", false, "generate files for use with gccgo") var gccgoprefix = flag.String("gccgoprefix", "", "-fgo-prefix option used with gccgo") var gccgopkgpath = flag.String("gccgopkgpath", "", "-fgo-pkgpath option used with gccgo") +var gccgoMangleCheckDone bool +var gccgoNewmanglingInEffect bool var importRuntimeCgo = flag.Bool("import_runtime_cgo", true, "import runtime/cgo in generated code") var importSyscall = flag.Bool("import_syscall", true, "import syscall in generated code") var goarch, goos string Index: libgo/go/cmd/cgo/out.go =================================================================== --- libgo/go/cmd/cgo/out.go (revision 265460) +++ libgo/go/cmd/cgo/out.go (working copy) @@ -15,7 +15,9 @@ import ( "go/printer" "go/token" "io" + "io/ioutil" "os" + "os/exec" "path/filepath" "regexp" "sort" @@ -1191,12 +1193,91 @@ func (p *Package) writeExportHeader(fgcc fmt.Fprintf(fgcch, "%s\n", p.gccExportHeaderProlog()) } -// Return the package prefix when using gccgo. -func (p *Package) gccgoSymbolPrefix() string { - if !*gccgo { - return "" +// gccgoUsesNewMangling returns whether gccgo uses the new collision-free +// packagepath mangling scheme (see determineGccgoManglingScheme for more +// info). +func gccgoUsesNewMangling() bool { + if !gccgoMangleCheckDone { + gccgoNewmanglingInEffect = determineGccgoManglingScheme() + gccgoMangleCheckDone = true + } + return gccgoNewmanglingInEffect +} + +const mangleCheckCode = ` +package läufer +func Run(x int) int { + return 1 +} +` + +// determineGccgoManglingScheme performs a runtime test to see which +// flavor of packagepath mangling gccgo is using. Older versions of +// gccgo use a simple mangling scheme where there can be collisions +// between packages whose paths are different but mangle to the same +// string. More recent versions of gccgo use a new mangler that avoids +// these collisions. Return value is whether gccgo uses the new mangling. +func determineGccgoManglingScheme() bool { + + // Emit a small Go file for gccgo to compile. + filepat := "*_gccgo_manglecheck.go" + var f *os.File + var err error + if f, err = ioutil.TempFile(*objDir, filepat); err != nil { + fatalf("%v", err) + } + gofilename := f.Name() + defer os.Remove(gofilename) + + if err = ioutil.WriteFile(gofilename, []byte(mangleCheckCode), 0666); err != nil { + fatalf("%v", err) + } + + // Compile with gccgo, capturing generated assembly. + gccgocmd := os.Getenv("GCCGO") + if gccgocmd == "" { + gpath, gerr := exec.LookPath("gccgo") + if gerr != nil { + fatalf("unable to locate gccgo: %v", gerr) + } + gccgocmd = gpath + } + cmd := exec.Command(gccgocmd, "-S", "-o", "-", gofilename) + buf, cerr := cmd.CombinedOutput() + if cerr != nil { + fatalf("%s", err) + } + + // New mangling: expect go.l..u00e4ufer.Run + // Old mangling: expect go.l__ufer.Run + return regexp.MustCompile(`go\.l\.\.u00e4ufer\.Run`).Match(buf) +} + +// gccgoPkgpathToSymbolNew converts a package path to a gccgo-style +// package symbol. +func gccgoPkgpathToSymbolNew(ppath string) string { + bsl := []byte{} + changed := false + for _, c := range []byte(ppath) { + switch { + case 'A' <= c && c <= 'Z', 'a' <= c && c <= 'z', + '0' <= c && c <= '9', '_' == c: + bsl = append(bsl, c) + default: + changed = true + encbytes := []byte(fmt.Sprintf("..z%02x", c)) + bsl = append(bsl, encbytes...) + } } + if !changed { + return ppath + } + return string(bsl) +} +// gccgoPkgpathToSymbolOld converts a package path to a gccgo-style +// package symbol using the older mangling scheme. +func gccgoPkgpathToSymbolOld(ppath string) string { clean := func(r rune) rune { switch { case 'A' <= r && r <= 'Z', 'a' <= r && r <= 'z', @@ -1205,14 +1286,32 @@ func (p *Package) gccgoSymbolPrefix() st } return '_' } + return strings.Map(clean, ppath) +} + +// gccgoPkgpathToSymbol converts a package path to a mangled packagepath +// symbol. +func gccgoPkgpathToSymbol(ppath string) string { + if gccgoUsesNewMangling() { + return gccgoPkgpathToSymbolNew(ppath) + } else { + return gccgoPkgpathToSymbolOld(ppath) + } +} + +// Return the package prefix when using gccgo. +func (p *Package) gccgoSymbolPrefix() string { + if !*gccgo { + return "" + } if *gccgopkgpath != "" { - return strings.Map(clean, *gccgopkgpath) + return gccgoPkgpathToSymbol(*gccgopkgpath) } if *gccgoprefix == "" && p.PackageName == "main" { return "main" } - prefix := strings.Map(clean, *gccgoprefix) + prefix := gccgoPkgpathToSymbol(*gccgoprefix) if prefix == "" { prefix = "go" } Index: libgo/go/internal/bytealg/bytealg.c =================================================================== --- libgo/go/internal/bytealg/bytealg.c (revision 265460) +++ libgo/go/internal/bytealg/bytealg.c (working copy) @@ -38,7 +38,7 @@ static const void *goMemmem(const void * #endif intgo Compare(struct __go_open_array, struct __go_open_array) - __asm__(GOSYM_PREFIX "internal_bytealg.Compare") + __asm__(GOSYM_PREFIX "internal..z2fbytealg.Compare") __attribute__((no_split_stack)); intgo Compare(struct __go_open_array a, struct __go_open_array b) @@ -67,7 +67,7 @@ intgo Compare(struct __go_open_array a, } _Bool Equal(struct __go_open_array, struct __go_open_array) - __asm__(GOSYM_PREFIX "internal_bytealg.Equal") + __asm__(GOSYM_PREFIX "internal..z2fbytealg.Equal") __attribute__((no_split_stack)); _Bool Equal(struct __go_open_array a, struct __go_open_array b) @@ -82,7 +82,7 @@ _Bool Equal(struct __go_open_array a, st } intgo IndexByte(struct __go_open_array, byte) - __asm__(GOSYM_PREFIX "internal_bytealg.IndexByte") + __asm__(GOSYM_PREFIX "internal..z2fbytealg.IndexByte") __attribute__((no_split_stack)); intgo IndexByte(struct __go_open_array b, byte c) @@ -98,7 +98,7 @@ intgo IndexByte(struct __go_open_array b intgo IndexByteString(String, byte) - __asm__(GOSYM_PREFIX "internal_bytealg.IndexByteString") + __asm__(GOSYM_PREFIX "internal..z2fbytealg.IndexByteString") __attribute__((no_split_stack)); intgo IndexByteString(String s, byte c) @@ -113,7 +113,7 @@ intgo IndexByteString(String s, byte c) } intgo Index(struct __go_open_array, struct __go_open_array) - __asm__(GOSYM_PREFIX "internal_bytealg.Index") + __asm__(GOSYM_PREFIX "internal..z2fbytealg.Index") __attribute__((no_split_stack)); intgo Index(struct __go_open_array a, struct __go_open_array b) @@ -128,7 +128,7 @@ intgo Index(struct __go_open_array a, st } intgo IndexString(String, String) - __asm__(GOSYM_PREFIX "internal_bytealg.IndexString") + __asm__(GOSYM_PREFIX "internal..z2fbytealg.IndexString") __attribute__((no_split_stack)); intgo IndexString(String a, String b) Index: libgo/go/internal/cpu/cpu_gccgo.c =================================================================== --- libgo/go/internal/cpu/cpu_gccgo.c (revision 265460) +++ libgo/go/internal/cpu/cpu_gccgo.c (working copy) @@ -21,7 +21,7 @@ struct cpuid_ret { }; struct cpuid_ret cpuid(uint32_t, uint32_t) - __asm__(GOSYM_PREFIX "internal_cpu.cpuid") + __asm__(GOSYM_PREFIX "internal..z2fcpu.cpuid") __attribute__((no_split_stack)); struct cpuid_ret cpuid(uint32_t eaxArg, uint32_t ecxArg) { @@ -45,7 +45,7 @@ struct xgetbv_ret { }; struct xgetbv_ret xgetbv(void) - __asm__(GOSYM_PREFIX "internal_cpu.xgetbv") + __asm__(GOSYM_PREFIX "internal..z2fcpu.xgetbv") __attribute__((no_split_stack)); #pragma GCC push_options Index: libgo/go/runtime/atomic_pointer.go =================================================================== --- libgo/go/runtime/atomic_pointer.go (revision 265460) +++ libgo/go/runtime/atomic_pointer.go (working copy) @@ -52,10 +52,10 @@ func casp(ptr *unsafe.Pointer, old, new // We cannot just call the runtime routines, because the race detector expects // to be able to intercept the sync/atomic forms but not the runtime forms. -//go:linkname sync_atomic_StoreUintptr sync_atomic.StoreUintptr +//go:linkname sync_atomic_StoreUintptr sync..z2fatomic.StoreUintptr func sync_atomic_StoreUintptr(ptr *uintptr, new uintptr) -//go:linkname sync_atomic_StorePointer sync_atomic.StorePointer +//go:linkname sync_atomic_StorePointer sync..z2fatomic.StorePointer //go:nosplit func sync_atomic_StorePointer(ptr *unsafe.Pointer, new unsafe.Pointer) { if writeBarrier.enabled { @@ -64,10 +64,10 @@ func sync_atomic_StorePointer(ptr *unsaf sync_atomic_StoreUintptr((*uintptr)(unsafe.Pointer(ptr)), uintptr(new)) } -//go:linkname sync_atomic_SwapUintptr sync_atomic.SwapUintptr +//go:linkname sync_atomic_SwapUintptr sync..z2fatomic.SwapUintptr func sync_atomic_SwapUintptr(ptr *uintptr, new uintptr) uintptr -//go:linkname sync_atomic_SwapPointer sync_atomic.SwapPointer +//go:linkname sync_atomic_SwapPointer sync..z2fatomic.SwapPointer //go:nosplit func sync_atomic_SwapPointer(ptr *unsafe.Pointer, new unsafe.Pointer) unsafe.Pointer { if writeBarrier.enabled { @@ -77,10 +77,10 @@ func sync_atomic_SwapPointer(ptr *unsafe return old } -//go:linkname sync_atomic_CompareAndSwapUintptr sync_atomic.CompareAndSwapUintptr +//go:linkname sync_atomic_CompareAndSwapUintptr sync..z2fatomic.CompareAndSwapUintptr func sync_atomic_CompareAndSwapUintptr(ptr *uintptr, old, new uintptr) bool -//go:linkname sync_atomic_CompareAndSwapPointer sync_atomic.CompareAndSwapPointer +//go:linkname sync_atomic_CompareAndSwapPointer sync..z2fatomic.CompareAndSwapPointer //go:nosplit func sync_atomic_CompareAndSwapPointer(ptr *unsafe.Pointer, old, new unsafe.Pointer) bool { if writeBarrier.enabled { Index: libgo/go/runtime/cpuprof.go =================================================================== --- libgo/go/runtime/cpuprof.go (revision 265460) +++ libgo/go/runtime/cpuprof.go (working copy) @@ -186,7 +186,7 @@ func CPUProfile() []byte { panic("CPUProfile no longer available") } -//go:linkname runtime_pprof_runtime_cyclesPerSecond runtime_pprof.runtime_cyclesPerSecond +//go:linkname runtime_pprof_runtime_cyclesPerSecond runtime..z2fpprof.runtime_cyclesPerSecond func runtime_pprof_runtime_cyclesPerSecond() int64 { return tickspersecond() } @@ -197,7 +197,7 @@ func runtime_pprof_runtime_cyclesPerSeco // on has been returned, readProfile returns eof=true. // The caller must save the returned data and tags before calling readProfile again. // -//go:linkname runtime_pprof_readProfile runtime_pprof.readProfile +//go:linkname runtime_pprof_readProfile runtime..z2fpprof.readProfile func runtime_pprof_readProfile() ([]uint64, []unsafe.Pointer, bool) { lock(&cpuprof.lock) log := cpuprof.log Index: libgo/go/runtime/debug/stack_test.go =================================================================== --- libgo/go/runtime/debug/stack_test.go (revision 265460) +++ libgo/go/runtime/debug/stack_test.go (working copy) @@ -51,10 +51,10 @@ func TestStack(t *testing.T) { n++ } n++ - frame("stack.go", "runtime_debug.Stack") + frame("stack.go", "debug.Stack") frame("stack_test.go", "ptrmethod") frame("stack_test.go", "method") - frame("stack_test.go", "runtime_debug_test.TestStack") + frame("stack_test.go", "test.TestStack") frame("testing.go", "") } Index: libgo/go/runtime/heapdump.go =================================================================== --- libgo/go/runtime/heapdump.go (revision 265460) +++ libgo/go/runtime/heapdump.go (working copy) @@ -16,7 +16,7 @@ import ( "unsafe" ) -//go:linkname runtime_debug_WriteHeapDump runtime_debug.WriteHeapDump +//go:linkname runtime_debug_WriteHeapDump runtime..z2fdebug.WriteHeapDump func runtime_debug_WriteHeapDump(fd uintptr) { stopTheWorld("write heap dump") Index: libgo/go/runtime/internal/atomic/atomic.c =================================================================== --- libgo/go/runtime/internal/atomic/atomic.c (revision 265460) +++ libgo/go/runtime/internal/atomic/atomic.c (working copy) @@ -7,7 +7,7 @@ #include "runtime.h" uint32_t Load (uint32_t *ptr) - __asm__ (GOSYM_PREFIX "runtime_internal_atomic.Load") + __asm__ (GOSYM_PREFIX "runtime..z2finternal..z2fatomic.Load") __attribute__ ((no_split_stack)); uint32_t @@ -17,7 +17,7 @@ Load (uint32_t *ptr) } void *Loadp (void *ptr) - __asm__ (GOSYM_PREFIX "runtime_internal_atomic.Loadp") + __asm__ (GOSYM_PREFIX "runtime..z2finternal..z2fatomic.Loadp") __attribute__ ((no_split_stack)); void * @@ -27,7 +27,7 @@ Loadp (void *ptr) } uint64_t Load64 (uint64_t *ptr) - __asm__ (GOSYM_PREFIX "runtime_internal_atomic.Load64") + __asm__ (GOSYM_PREFIX "runtime..z2finternal..z2fatomic.Load64") __attribute__ ((no_split_stack)); uint64_t @@ -39,7 +39,7 @@ Load64 (uint64_t *ptr) } uintptr_t Loaduintptr (uintptr_t *ptr) - __asm__ (GOSYM_PREFIX "runtime_internal_atomic.Loaduintptr") + __asm__ (GOSYM_PREFIX "runtime..z2finternal..z2fatomic.Loaduintptr") __attribute__ ((no_split_stack)); uintptr_t @@ -49,7 +49,7 @@ Loaduintptr (uintptr_t *ptr) } uintgo Loaduint (uintgo *ptr) - __asm__ (GOSYM_PREFIX "runtime_internal_atomic.Loaduint") + __asm__ (GOSYM_PREFIX "runtime..z2finternal..z2fatomic.Loaduint") __attribute__ ((no_split_stack)); uintgo @@ -59,7 +59,7 @@ Loaduint (uintgo *ptr) } int64_t Loadint64 (int64_t *ptr) - __asm__ (GOSYM_PREFIX "runtime_internal_atomic.Loadint64") + __asm__ (GOSYM_PREFIX "runtime..z2finternal..z2fatomic.Loadint64") __attribute__ ((no_split_stack)); int64_t @@ -71,7 +71,7 @@ Loadint64 (int64_t *ptr) } uint32_t Xadd (uint32_t *ptr, int32_t delta) - __asm__ (GOSYM_PREFIX "runtime_internal_atomic.Xadd") + __asm__ (GOSYM_PREFIX "runtime..z2finternal..z2fatomic.Xadd") __attribute__ ((no_split_stack)); uint32_t @@ -81,7 +81,7 @@ Xadd (uint32_t *ptr, int32_t delta) } uint64_t Xadd64 (uint64_t *ptr, int64_t delta) - __asm__ (GOSYM_PREFIX "runtime_internal_atomic.Xadd64") + __asm__ (GOSYM_PREFIX "runtime..z2finternal..z2fatomic.Xadd64") __attribute__ ((no_split_stack)); uint64_t @@ -93,7 +93,7 @@ Xadd64 (uint64_t *ptr, int64_t delta) } uintptr_t Xadduintptr (uintptr_t *ptr, uintptr_t delta) - __asm__ (GOSYM_PREFIX "runtime_internal_atomic.Xadduintptr") + __asm__ (GOSYM_PREFIX "runtime..z2finternal..z2fatomic.Xadduintptr") __attribute__ ((no_split_stack)); uintptr_t @@ -103,7 +103,7 @@ Xadduintptr (uintptr_t *ptr, uintptr_t d } int64_t Xaddint64 (int64_t *ptr, int64_t delta) - __asm__ (GOSYM_PREFIX "runtime_internal_atomic.Xaddint64") + __asm__ (GOSYM_PREFIX "runtime..z2finternal..z2fatomic.Xaddint64") __attribute__ ((no_split_stack)); int64_t @@ -115,7 +115,7 @@ Xaddint64 (int64_t *ptr, int64_t delta) } uint32_t Xchg (uint32_t *ptr, uint32_t new) - __asm__ (GOSYM_PREFIX "runtime_internal_atomic.Xchg") + __asm__ (GOSYM_PREFIX "runtime..z2finternal..z2fatomic.Xchg") __attribute__ ((no_split_stack)); uint32_t @@ -125,7 +125,7 @@ Xchg (uint32_t *ptr, uint32_t new) } uint64_t Xchg64 (uint64_t *ptr, uint64_t new) - __asm__ (GOSYM_PREFIX "runtime_internal_atomic.Xchg64") + __asm__ (GOSYM_PREFIX "runtime..z2finternal..z2fatomic.Xchg64") __attribute__ ((no_split_stack)); uint64_t @@ -137,7 +137,7 @@ Xchg64 (uint64_t *ptr, uint64_t new) } uintptr_t Xchguintptr (uintptr_t *ptr, uintptr_t new) - __asm__ (GOSYM_PREFIX "runtime_internal_atomic.Xchguintptr") + __asm__ (GOSYM_PREFIX "runtime..z2finternal..z2fatomic.Xchguintptr") __attribute__ ((no_split_stack)); uintptr_t @@ -147,7 +147,7 @@ Xchguintptr (uintptr_t *ptr, uintptr_t n } void And8 (uint8_t *ptr, uint8_t val) - __asm__ (GOSYM_PREFIX "runtime_internal_atomic.And8") + __asm__ (GOSYM_PREFIX "runtime..z2finternal..z2fatomic.And8") __attribute__ ((no_split_stack)); void @@ -157,7 +157,7 @@ And8 (uint8_t *ptr, uint8_t val) } void Or8 (uint8_t *ptr, uint8_t val) - __asm__ (GOSYM_PREFIX "runtime_internal_atomic.Or8") + __asm__ (GOSYM_PREFIX "runtime..z2finternal..z2fatomic.Or8") __attribute__ ((no_split_stack)); void @@ -167,7 +167,7 @@ Or8 (uint8_t *ptr, uint8_t val) } _Bool Cas (uint32_t *ptr, uint32_t old, uint32_t new) - __asm__ (GOSYM_PREFIX "runtime_internal_atomic.Cas") + __asm__ (GOSYM_PREFIX "runtime..z2finternal..z2fatomic.Cas") __attribute__ ((no_split_stack)); _Bool @@ -177,7 +177,7 @@ Cas (uint32_t *ptr, uint32_t old, uint32 } _Bool Cas64 (uint64_t *ptr, uint64_t old, uint64_t new) - __asm__ (GOSYM_PREFIX "runtime_internal_atomic.Cas64") + __asm__ (GOSYM_PREFIX "runtime..z2finternal..z2fatomic.Cas64") __attribute__ ((no_split_stack)); _Bool @@ -189,7 +189,7 @@ Cas64 (uint64_t *ptr, uint64_t old, uint } _Bool Casp1 (void **ptr, void *old, void *new) - __asm__ (GOSYM_PREFIX "runtime_internal_atomic.Casp1") + __asm__ (GOSYM_PREFIX "runtime..z2finternal..z2fatomic.Casp1") __attribute__ ((no_split_stack)); _Bool @@ -199,7 +199,7 @@ Casp1 (void **ptr, void *old, void *new) } _Bool Casuintptr (uintptr_t *ptr, uintptr_t old, uintptr_t new) - __asm__ (GOSYM_PREFIX "runtime_internal_atomic.Casuintptr") + __asm__ (GOSYM_PREFIX "runtime..z2finternal..z2fatomic.Casuintptr") __attribute__ ((no_split_stack)); _Bool @@ -209,7 +209,7 @@ Casuintptr (uintptr_t *ptr, uintptr_t ol } void Store (uint32_t *ptr, uint32_t val) - __asm__ (GOSYM_PREFIX "runtime_internal_atomic.Store") + __asm__ (GOSYM_PREFIX "runtime..z2finternal..z2fatomic.Store") __attribute__ ((no_split_stack)); void @@ -219,7 +219,7 @@ Store (uint32_t *ptr, uint32_t val) } void Store64 (uint64_t *ptr, uint64_t val) - __asm__ (GOSYM_PREFIX "runtime_internal_atomic.Store64") + __asm__ (GOSYM_PREFIX "runtime..z2finternal..z2fatomic.Store64") __attribute__ ((no_split_stack)); void @@ -231,7 +231,7 @@ Store64 (uint64_t *ptr, uint64_t val) } void Storeuintptr (uintptr_t *ptr, uintptr_t val) - __asm__ (GOSYM_PREFIX "runtime_internal_atomic.Storeuintptr") + __asm__ (GOSYM_PREFIX "runtime..z2finternal..z2fatomic.Storeuintptr") __attribute__ ((no_split_stack)); void @@ -241,7 +241,7 @@ Storeuintptr (uintptr_t *ptr, uintptr_t } void StorepNoWB (void *ptr, void *val) - __asm__ (GOSYM_PREFIX "runtime_internal_atomic.StorepNoWB") + __asm__ (GOSYM_PREFIX "runtime..z2finternal..z2fatomic.StorepNoWB") __attribute__ ((no_split_stack)); void Index: libgo/go/runtime/mgc.go =================================================================== --- libgo/go/runtime/mgc.go (revision 265460) +++ libgo/go/runtime/mgc.go (working copy) @@ -219,7 +219,7 @@ func gcenable() { memstats.enablegc = true // now that runtime is initialized, GC is okay } -//go:linkname setGCPercent runtime_debug.setGCPercent +//go:linkname setGCPercent runtime..z2fdebug.setGCPercent func setGCPercent(in int32) (out int32) { lock(&mheap_.lock) out = gcpercent Index: libgo/go/runtime/mheap.go =================================================================== --- libgo/go/runtime/mheap.go (revision 265460) +++ libgo/go/runtime/mheap.go (working copy) @@ -1165,7 +1165,7 @@ func (h *mheap) scavenge(k int32, now, l } } -//go:linkname runtime_debug_freeOSMemory runtime_debug.freeOSMemory +//go:linkname runtime_debug_freeOSMemory runtime..z2fdebug.freeOSMemory func runtime_debug_freeOSMemory() { GC() systemstack(func() { mheap_.scavenge(-1, ^uint64(0), 0) }) Index: libgo/go/runtime/mstats.go =================================================================== --- libgo/go/runtime/mstats.go (revision 265460) +++ libgo/go/runtime/mstats.go (working copy) @@ -477,7 +477,7 @@ func readmemstats_m(stats *MemStats) { stats.StackSys += stats.StackInuse } -//go:linkname readGCStats runtime_debug.readGCStats +//go:linkname readGCStats runtime..z2fdebug.readGCStats func readGCStats(pauses *[]uint64) { systemstack(func() { readGCStats_m(pauses) Index: libgo/go/runtime/net_plan9.go =================================================================== --- libgo/go/runtime/net_plan9.go (revision 265460) +++ libgo/go/runtime/net_plan9.go (working copy) @@ -8,12 +8,12 @@ import ( _ "unsafe" ) -//go:linkname runtime_ignoreHangup internal_poll.runtime_ignoreHangup +//go:linkname runtime_ignoreHangup internal..z2fpoll.runtime_ignoreHangup func runtime_ignoreHangup() { getg().m.ignoreHangup = true } -//go:linkname runtime_unignoreHangup internal_poll.runtime_unignoreHangup +//go:linkname runtime_unignoreHangup internal..z2fpoll.runtime_unignoreHangup func runtime_unignoreHangup(sig string) { getg().m.ignoreHangup = false } Index: libgo/go/runtime/netpoll.go =================================================================== --- libgo/go/runtime/netpoll.go (revision 265460) +++ libgo/go/runtime/netpoll.go (working copy) @@ -85,7 +85,7 @@ var ( netpollWaiters uint32 ) -//go:linkname poll_runtime_pollServerInit internal_poll.runtime_pollServerInit +//go:linkname poll_runtime_pollServerInit internal..z2fpoll.runtime_pollServerInit func poll_runtime_pollServerInit() { netpollinit() atomic.Store(&netpollInited, 1) @@ -95,7 +95,7 @@ func netpollinited() bool { return atomic.Load(&netpollInited) != 0 } -//go:linkname poll_runtime_pollServerDescriptor internal_poll.runtime_pollServerDescriptor +//go:linkname poll_runtime_pollServerDescriptor internal..z2fpoll.runtime_pollServerDescriptor // poll_runtime_pollServerDescriptor returns the descriptor being used, // or ^uintptr(0) if the system does not use a poll descriptor. @@ -103,7 +103,7 @@ func poll_runtime_pollServerDescriptor() return netpolldescriptor() } -//go:linkname poll_runtime_pollOpen internal_poll.runtime_pollOpen +//go:linkname poll_runtime_pollOpen internal..z2fpoll.runtime_pollOpen func poll_runtime_pollOpen(fd uintptr) (*pollDesc, int) { pd := pollcache.alloc() lock(&pd.lock) @@ -127,7 +127,7 @@ func poll_runtime_pollOpen(fd uintptr) ( return pd, int(errno) } -//go:linkname poll_runtime_pollClose internal_poll.runtime_pollClose +//go:linkname poll_runtime_pollClose internal..z2fpoll.runtime_pollClose func poll_runtime_pollClose(pd *pollDesc) { if !pd.closing { throw("runtime: close polldesc w/o unblock") @@ -149,7 +149,7 @@ func (c *pollCache) free(pd *pollDesc) { unlock(&c.lock) } -//go:linkname poll_runtime_pollReset internal_poll.runtime_pollReset +//go:linkname poll_runtime_pollReset internal..z2fpoll.runtime_pollReset func poll_runtime_pollReset(pd *pollDesc, mode int) int { err := netpollcheckerr(pd, int32(mode)) if err != 0 { @@ -163,7 +163,7 @@ func poll_runtime_pollReset(pd *pollDesc return 0 } -//go:linkname poll_runtime_pollWait internal_poll.runtime_pollWait +//go:linkname poll_runtime_pollWait internal..z2fpoll.runtime_pollWait func poll_runtime_pollWait(pd *pollDesc, mode int) int { err := netpollcheckerr(pd, int32(mode)) if err != 0 { @@ -185,7 +185,7 @@ func poll_runtime_pollWait(pd *pollDesc, return 0 } -//go:linkname poll_runtime_pollWaitCanceled internal_poll.runtime_pollWaitCanceled +//go:linkname poll_runtime_pollWaitCanceled internal..z2fpoll.runtime_pollWaitCanceled func poll_runtime_pollWaitCanceled(pd *pollDesc, mode int) { // This function is used only on windows after a failed attempt to cancel // a pending async IO operation. Wait for ioready, ignore closing or timeouts. @@ -193,7 +193,7 @@ func poll_runtime_pollWaitCanceled(pd *p } } -//go:linkname poll_runtime_pollSetDeadline internal_poll.runtime_pollSetDeadline +//go:linkname poll_runtime_pollSetDeadline internal..z2fpoll.runtime_pollSetDeadline func poll_runtime_pollSetDeadline(pd *pollDesc, d int64, mode int) { lock(&pd.lock) if pd.closing { @@ -263,7 +263,7 @@ func poll_runtime_pollSetDeadline(pd *po } } -//go:linkname poll_runtime_pollUnblock internal_poll.runtime_pollUnblock +//go:linkname poll_runtime_pollUnblock internal..z2fpoll.runtime_pollUnblock func poll_runtime_pollUnblock(pd *pollDesc) { lock(&pd.lock) if pd.closing { Index: libgo/go/runtime/pprof/mprof_test.go =================================================================== --- libgo/go/runtime/pprof/mprof_test.go (revision 265460) +++ libgo/go/runtime/pprof/mprof_test.go (working copy) @@ -87,19 +87,19 @@ func TestMemoryProfiler(t *testing.T) { fmt.Sprintf(`%v: %v \[%v: %v\] @ 0x[0-9,a-f x]+ # 0x[0-9,a-f]+ pprof\.allocatePersistent1K\+0x[0-9,a-f]+ .*/mprof_test\.go:40 -# 0x[0-9,a-f]+ runtime_pprof\.TestMemoryProfiler\+0x[0-9,a-f]+ .*/mprof_test\.go:74 +# 0x[0-9,a-f]+ runtime/pprof\.TestMemoryProfiler\+0x[0-9,a-f]+ .*/mprof_test\.go:74 `, 32*memoryProfilerRun, 1024*memoryProfilerRun, 32*memoryProfilerRun, 1024*memoryProfilerRun), fmt.Sprintf(`0: 0 \[%v: %v\] @ 0x[0-9,a-f x]+ # 0x[0-9,a-f]+ pprof\.allocateTransient1M\+0x[0-9,a-f]+ .*/mprof_test.go:21 -# 0x[0-9,a-f]+ runtime_pprof\.TestMemoryProfiler\+0x[0-9,a-f]+ .*/mprof_test.go:72 +# 0x[0-9,a-f]+ runtime/pprof\.TestMemoryProfiler\+0x[0-9,a-f]+ .*/mprof_test.go:72 `, (1<<10)*memoryProfilerRun, (1<<20)*memoryProfilerRun), // This should start with "0: 0" but gccgo's imprecise // GC means that sometimes the value is not collected. fmt.Sprintf(`(0|%v): (0|%v) \[%v: %v\] @ 0x[0-9,a-f x]+ # 0x[0-9,a-f]+ pprof\.allocateTransient2M\+0x[0-9,a-f]+ .*/mprof_test.go:27 -# 0x[0-9,a-f]+ runtime_pprof\.TestMemoryProfiler\+0x[0-9,a-f]+ .*/mprof_test.go:73 +# 0x[0-9,a-f]+ runtime/pprof\.TestMemoryProfiler\+0x[0-9,a-f]+ .*/mprof_test.go:73 `, memoryProfilerRun, (2<<20)*memoryProfilerRun, memoryProfilerRun, (2<<20)*memoryProfilerRun), // This should start with "0: 0" but gccgo's imprecise Index: libgo/go/runtime/proc.go =================================================================== --- libgo/go/runtime/proc.go (revision 265460) +++ libgo/go/runtime/proc.go (working copy) @@ -4670,7 +4670,7 @@ func runqsteal(_p_, p2 *p, stealRunNextG return gp } -//go:linkname setMaxThreads runtime_debug.setMaxThreads +//go:linkname setMaxThreads runtime..z2fdebug.setMaxThreads func setMaxThreads(in int) (out int) { lock(&sched.lock) out = int(sched.maxmcount) @@ -4716,13 +4716,13 @@ func sync_runtime_procUnpin() { procUnpin() } -//go:linkname sync_atomic_runtime_procPin sync_atomic.runtime_procPin +//go:linkname sync_atomic_runtime_procPin sync..z2fatomic.runtime_procPin //go:nosplit func sync_atomic_runtime_procPin() int { return procPin() } -//go:linkname sync_atomic_runtime_procUnpin sync_atomic.runtime_procUnpin +//go:linkname sync_atomic_runtime_procUnpin sync..z2fatomic.runtime_procUnpin //go:nosplit func sync_atomic_runtime_procUnpin() { procUnpin() Index: libgo/go/runtime/proflabel.go =================================================================== --- libgo/go/runtime/proflabel.go (revision 265460) +++ libgo/go/runtime/proflabel.go (working copy) @@ -8,7 +8,7 @@ import "unsafe" var labelSync uintptr -//go:linkname runtime_setProfLabel runtime_pprof.runtime_setProfLabel +//go:linkname runtime_setProfLabel runtime..z2fpprof.runtime_setProfLabel func runtime_setProfLabel(labels unsafe.Pointer) { // Introduce race edge for read-back via profile. // This would more properly use &getg().labels as the sync address, @@ -34,7 +34,7 @@ func runtime_setProfLabel(labels unsafe. getg().labels = labels } -//go:linkname runtime_getProfLabel runtime_pprof.runtime_getProfLabel +//go:linkname runtime_getProfLabel runtime..z2fpprof.runtime_getProfLabel func runtime_getProfLabel() unsafe.Pointer { return getg().labels } Index: libgo/go/runtime/rdebug.go =================================================================== --- libgo/go/runtime/rdebug.go (revision 265460) +++ libgo/go/runtime/rdebug.go (working copy) @@ -11,14 +11,14 @@ import _ "unsafe" // for go:linkname // maxstacksize. var maxstacksize uintptr = 1 << 20 // enough until runtime.main sets it for real -//go:linkname setMaxStack runtime_debug.setMaxStack +//go:linkname setMaxStack runtime..z2fdebug.setMaxStack func setMaxStack(in int) (out int) { out = int(maxstacksize) maxstacksize = uintptr(in) return out } -//go:linkname setPanicOnFault runtime_debug.setPanicOnFault +//go:linkname setPanicOnFault runtime..z2fdebug.setPanicOnFault func setPanicOnFault(new bool) (old bool) { _g_ := getg() old = _g_.paniconfault Index: libgo/go/runtime/runtime1.go =================================================================== --- libgo/go/runtime/runtime1.go (revision 265460) +++ libgo/go/runtime/runtime1.go (working copy) @@ -413,7 +413,7 @@ func parsedebugvars() { traceback_env = traceback_cache } -//go:linkname setTraceback runtime_debug.SetTraceback +//go:linkname setTraceback runtime..z2fdebug.SetTraceback func setTraceback(level string) { var t uint32 switch level { Index: libgo/go/runtime/sema.go =================================================================== --- libgo/go/runtime/sema.go (revision 265460) +++ libgo/go/runtime/sema.go (working copy) @@ -56,7 +56,7 @@ func sync_runtime_Semacquire(addr *uint3 semacquire1(addr, false, semaBlockProfile) } -//go:linkname poll_runtime_Semacquire internal_poll.runtime_Semacquire +//go:linkname poll_runtime_Semacquire internal..z2fpoll.runtime_Semacquire func poll_runtime_Semacquire(addr *uint32) { semacquire1(addr, false, semaBlockProfile) } @@ -71,7 +71,7 @@ func sync_runtime_SemacquireMutex(addr * semacquire1(addr, lifo, semaBlockProfile|semaMutexProfile) } -//go:linkname poll_runtime_Semrelease internal_poll.runtime_Semrelease +//go:linkname poll_runtime_Semrelease internal..z2fpoll.runtime_Semrelease func poll_runtime_Semrelease(addr *uint32) { semrelease(addr) } Index: libgo/go/runtime/sigqueue.go =================================================================== --- libgo/go/runtime/sigqueue.go (revision 265460) +++ libgo/go/runtime/sigqueue.go (working copy) @@ -117,7 +117,7 @@ Send: // Called to receive the next queued signal. // Must only be called from a single goroutine at a time. -//go:linkname signal_recv os_signal.signal_recv +//go:linkname signal_recv os..z2fsignal.signal_recv func signal_recv() uint32 { for { // Serve any signals from local copy. @@ -161,7 +161,7 @@ func signal_recv() uint32 { // the signal(s) in question, and here we are just waiting to make sure // that all the signals have been delivered to the user channels // by the os/signal package. -//go:linkname signalWaitUntilIdle os_signal.signalWaitUntilIdle +//go:linkname signalWaitUntilIdle os..z2fsignal.signalWaitUntilIdle func signalWaitUntilIdle() { // Although the signals we care about have been removed from // sig.wanted, it is possible that another thread has received @@ -181,7 +181,7 @@ func signalWaitUntilIdle() { } // Must only be called from a single goroutine at a time. -//go:linkname signal_enable os_signal.signal_enable +//go:linkname signal_enable os..z2fsignal.signal_enable func signal_enable(s uint32) { if !sig.inuse { // The first call to signal_enable is for us @@ -208,7 +208,7 @@ func signal_enable(s uint32) { } // Must only be called from a single goroutine at a time. -//go:linkname signal_disable os_signal.signal_disable +//go:linkname signal_disable os..z2fsignal.signal_disable func signal_disable(s uint32) { if s >= uint32(len(sig.wanted)*32) { return @@ -221,7 +221,7 @@ func signal_disable(s uint32) { } // Must only be called from a single goroutine at a time. -//go:linkname signal_ignore os_signal.signal_ignore +//go:linkname signal_ignore os..z2fsignal.signal_ignore func signal_ignore(s uint32) { if s >= uint32(len(sig.wanted)*32) { return @@ -248,7 +248,7 @@ func sigInitIgnored(s uint32) { } // Checked by signal handlers. -//go:linkname signal_ignored os_signal.signal_ignored +//go:linkname signal_ignored os..z2fsignal.signal_ignored func signal_ignored(s uint32) bool { i := atomic.Load(&sig.ignored[s/32]) return i&(1<<(s&31)) != 0 Index: libgo/go/runtime/symtab.go =================================================================== --- libgo/go/runtime/symtab.go (revision 265460) +++ libgo/go/runtime/symtab.go (working copy) @@ -83,6 +83,11 @@ func (ci *Frames) Next() (frame Frame, m if function == "" && file == "" { return Frame{}, more } + + // Demangle function name if needed. + function = demangleSymbol(function) + + // Create entry. entry := funcentry(pc - 1) f := &Func{name: function, entry: entry} @@ -182,6 +187,75 @@ func (f *Func) FileLine(pc uintptr) (fil return file, line } +func hexval(b byte) uint { + if b >= '0' && b <= '9' { + return uint(b - '0') + } + if b >= 'a' && b <= 'f' { + return uint(b-'a') + 10 + } + return 0 +} + +func hexDigitsToRune(digits []byte, ndig int) rune { + result := uint(0) + for i := 0; i < ndig; i++ { + result <<= uint(4) + result |= hexval(digits[i]) + } + return rune(result) +} + +// Perform an in-place decoding on the input byte slice. This looks +// for "..z", "..u" and "..U" and overwrites +// with the encoded bytes corresponding to the unicode in question. +// Return value is the number of bytes taken by the result. + +func decodeIdentifier(bsl []byte) int { + j := 0 + for i := 0; i < len(bsl); i++ { + b := bsl[i] + + if i+1 < len(bsl) && bsl[i] == '.' && bsl[i+1] == '.' { + if i+4 < len(bsl) && bsl[i+2] == 'z' { + digits := bsl[i+3:] + r := hexDigitsToRune(digits, 2) + nc := encoderune(bsl[j:], r) + j += nc + i += 4 + continue + } else if i+6 < len(bsl) && bsl[i+2] == 'u' { + digits := bsl[i+3:] + r := hexDigitsToRune(digits, 4) + nc := encoderune(bsl[j:], r) + j += nc + i += 6 + continue + } else if i+10 < len(bsl) && bsl[i+2] == 'U' { + digits := bsl[i+3:] + r := hexDigitsToRune(digits, 8) + nc := encoderune(bsl[j:], r) + j += nc + i += 10 + continue + } + } + bsl[j] = b + j += 1 + } + return j +} + +// Demangle a function symbol. Applies the reverse of go_encode_id() +// as used in the compiler. + +func demangleSymbol(s string) string { + bsl := []byte(s) + nchars := decodeIdentifier(bsl) + bsl = bsl[:nchars] + return string(bsl) +} + // implemented in go-caller.c func funcfileline(uintptr, int32) (string, string, int) func funcentry(uintptr) uintptr Index: libgo/go/runtime/time.go =================================================================== --- libgo/go/runtime/time.go (revision 265460) +++ libgo/go/runtime/time.go (working copy) @@ -441,7 +441,7 @@ func badTimer() { // Entry points for net, time to call nanotime. -//go:linkname poll_runtimeNano internal_poll.runtimeNano +//go:linkname poll_runtimeNano internal..z2fpoll.runtimeNano func poll_runtimeNano() int64 { return nanotime() } Index: libgo/go/runtime/trace.go =================================================================== --- libgo/go/runtime/trace.go (revision 265460) +++ libgo/go/runtime/trace.go (working copy) @@ -1143,7 +1143,7 @@ func traceNextGC() { // To access runtime functions from runtime/trace. // See runtime/trace/annotation.go -//go:linkname trace_userTaskCreate runtime_trace.userTaskCreate +//go:linkname trace_userTaskCreate runtime..z2ftrace.userTaskCreate func trace_userTaskCreate(id, parentID uint64, taskType string) { if !trace.enabled { return @@ -1161,12 +1161,12 @@ func trace_userTaskCreate(id, parentID u traceReleaseBuffer(pid) } -//go:linkname trace_userTaskEnd runtime_trace.userTaskEnd +//go:linkname trace_userTaskEnd runtime..z2ftrace.userTaskEnd func trace_userTaskEnd(id uint64) { traceEvent(traceEvUserTaskEnd, 2, id) } -//go:linkname trace_userRegion runtime_trace.userRegion +//go:linkname trace_userRegion runtime..z2ftrace.userRegion func trace_userRegion(id, mode uint64, name string) { if !trace.enabled { return @@ -1183,7 +1183,7 @@ func trace_userRegion(id, mode uint64, n traceReleaseBuffer(pid) } -//go:linkname trace_userLog runtime_trace.userLog +//go:linkname trace_userLog runtime..z2ftrace.userLog func trace_userLog(id uint64, category, message string) { if !trace.enabled { return Index: libgo/go/runtime/traceback_gccgo.go =================================================================== --- libgo/go/runtime/traceback_gccgo.go (revision 265460) +++ libgo/go/runtime/traceback_gccgo.go (working copy) @@ -110,9 +110,14 @@ func showframe(name string, gp *g) bool } // isExportedRuntime reports whether name is an exported runtime function. -// It is only for runtime functions, so ASCII A-Z is fine. +// It is only for runtime functions, so ASCII A-Z is fine. Here also check +// for mangled functions from runtime/<...>, which will be prefixed with +// "runtime..z2f". func isExportedRuntime(name string) bool { const n = len("runtime.") + if hasprefix(name, "runtime..z2f") { + return true + } return len(name) > n && name[:n] == "runtime." && 'A' <= name[n] && name[n] <= 'Z' } Index: libgo/go/sync/atomic/atomic.c =================================================================== --- libgo/go/sync/atomic/atomic.c (revision 265460) +++ libgo/go/sync/atomic/atomic.c (working copy) @@ -9,7 +9,7 @@ #include "runtime.h" int32_t SwapInt32 (int32_t *, int32_t) - __asm__ (GOSYM_PREFIX "sync_atomic.SwapInt32") + __asm__ (GOSYM_PREFIX "sync..z2fatomic.SwapInt32") __attribute__ ((no_split_stack)); int32_t @@ -19,7 +19,7 @@ SwapInt32 (int32_t *addr, int32_t new) } int64_t SwapInt64 (int64_t *, int64_t) - __asm__ (GOSYM_PREFIX "sync_atomic.SwapInt64") + __asm__ (GOSYM_PREFIX "sync..z2fatomic.SwapInt64") __attribute__ ((no_split_stack)); int64_t @@ -31,7 +31,7 @@ SwapInt64 (int64_t *addr, int64_t new) } uint32_t SwapUint32 (uint32_t *, uint32_t) - __asm__ (GOSYM_PREFIX "sync_atomic.SwapUint32") + __asm__ (GOSYM_PREFIX "sync..z2fatomic.SwapUint32") __attribute__ ((no_split_stack)); uint32_t @@ -41,7 +41,7 @@ SwapUint32 (uint32_t *addr, uint32_t new } uint64_t SwapUint64 (uint64_t *, uint64_t) - __asm__ (GOSYM_PREFIX "sync_atomic.SwapUint64") + __asm__ (GOSYM_PREFIX "sync..z2fatomic.SwapUint64") __attribute__ ((no_split_stack)); uint64_t @@ -53,7 +53,7 @@ SwapUint64 (uint64_t *addr, uint64_t new } uintptr_t SwapUintptr (uintptr_t *, uintptr_t) - __asm__ (GOSYM_PREFIX "sync_atomic.SwapUintptr") + __asm__ (GOSYM_PREFIX "sync..z2fatomic.SwapUintptr") __attribute__ ((no_split_stack)); uintptr_t @@ -63,7 +63,7 @@ SwapUintptr (uintptr_t *addr, uintptr_t } _Bool CompareAndSwapInt32 (int32_t *, int32_t, int32_t) - __asm__ (GOSYM_PREFIX "sync_atomic.CompareAndSwapInt32") + __asm__ (GOSYM_PREFIX "sync..z2fatomic.CompareAndSwapInt32") __attribute__ ((no_split_stack)); _Bool @@ -73,7 +73,7 @@ CompareAndSwapInt32 (int32_t *val, int32 } _Bool CompareAndSwapInt64 (int64_t *, int64_t, int64_t) - __asm__ (GOSYM_PREFIX "sync_atomic.CompareAndSwapInt64") + __asm__ (GOSYM_PREFIX "sync..z2fatomic.CompareAndSwapInt64") __attribute__ ((no_split_stack)); _Bool @@ -85,7 +85,7 @@ CompareAndSwapInt64 (int64_t *val, int64 } _Bool CompareAndSwapUint32 (uint32_t *, uint32_t, uint32_t) - __asm__ (GOSYM_PREFIX "sync_atomic.CompareAndSwapUint32") + __asm__ (GOSYM_PREFIX "sync..z2fatomic.CompareAndSwapUint32") __attribute__ ((no_split_stack)); _Bool @@ -95,7 +95,7 @@ CompareAndSwapUint32 (uint32_t *val, uin } _Bool CompareAndSwapUint64 (uint64_t *, uint64_t, uint64_t) - __asm__ (GOSYM_PREFIX "sync_atomic.CompareAndSwapUint64") + __asm__ (GOSYM_PREFIX "sync..z2fatomic.CompareAndSwapUint64") __attribute__ ((no_split_stack)); _Bool @@ -107,7 +107,7 @@ CompareAndSwapUint64 (uint64_t *val, uin } _Bool CompareAndSwapUintptr (uintptr_t *, uintptr_t, uintptr_t) - __asm__ (GOSYM_PREFIX "sync_atomic.CompareAndSwapUintptr") + __asm__ (GOSYM_PREFIX "sync..z2fatomic.CompareAndSwapUintptr") __attribute__ ((no_split_stack)); _Bool @@ -117,7 +117,7 @@ CompareAndSwapUintptr (uintptr_t *val, u } int32_t AddInt32 (int32_t *, int32_t) - __asm__ (GOSYM_PREFIX "sync_atomic.AddInt32") + __asm__ (GOSYM_PREFIX "sync..z2fatomic.AddInt32") __attribute__ ((no_split_stack)); int32_t @@ -127,7 +127,7 @@ AddInt32 (int32_t *val, int32_t delta) } uint32_t AddUint32 (uint32_t *, uint32_t) - __asm__ (GOSYM_PREFIX "sync_atomic.AddUint32") + __asm__ (GOSYM_PREFIX "sync..z2fatomic.AddUint32") __attribute__ ((no_split_stack)); uint32_t @@ -137,7 +137,7 @@ AddUint32 (uint32_t *val, uint32_t delta } int64_t AddInt64 (int64_t *, int64_t) - __asm__ (GOSYM_PREFIX "sync_atomic.AddInt64") + __asm__ (GOSYM_PREFIX "sync..z2fatomic.AddInt64") __attribute__ ((no_split_stack)); int64_t @@ -149,7 +149,7 @@ AddInt64 (int64_t *val, int64_t delta) } uint64_t AddUint64 (uint64_t *, uint64_t) - __asm__ (GOSYM_PREFIX "sync_atomic.AddUint64") + __asm__ (GOSYM_PREFIX "sync..z2fatomic.AddUint64") __attribute__ ((no_split_stack)); uint64_t @@ -161,7 +161,7 @@ AddUint64 (uint64_t *val, uint64_t delta } uintptr_t AddUintptr (uintptr_t *, uintptr_t) - __asm__ (GOSYM_PREFIX "sync_atomic.AddUintptr") + __asm__ (GOSYM_PREFIX "sync..z2fatomic.AddUintptr") __attribute__ ((no_split_stack)); uintptr_t @@ -171,7 +171,7 @@ AddUintptr (uintptr_t *val, uintptr_t de } int32_t LoadInt32 (int32_t *addr) - __asm__ (GOSYM_PREFIX "sync_atomic.LoadInt32") + __asm__ (GOSYM_PREFIX "sync..z2fatomic.LoadInt32") __attribute__ ((no_split_stack)); int32_t @@ -186,7 +186,7 @@ LoadInt32 (int32_t *addr) } int64_t LoadInt64 (int64_t *addr) - __asm__ (GOSYM_PREFIX "sync_atomic.LoadInt64") + __asm__ (GOSYM_PREFIX "sync..z2fatomic.LoadInt64") __attribute__ ((no_split_stack)); int64_t @@ -203,7 +203,7 @@ LoadInt64 (int64_t *addr) } uint32_t LoadUint32 (uint32_t *addr) - __asm__ (GOSYM_PREFIX "sync_atomic.LoadUint32") + __asm__ (GOSYM_PREFIX "sync..z2fatomic.LoadUint32") __attribute__ ((no_split_stack)); uint32_t @@ -218,7 +218,7 @@ LoadUint32 (uint32_t *addr) } uint64_t LoadUint64 (uint64_t *addr) - __asm__ (GOSYM_PREFIX "sync_atomic.LoadUint64") + __asm__ (GOSYM_PREFIX "sync..z2fatomic.LoadUint64") __attribute__ ((no_split_stack)); uint64_t @@ -235,7 +235,7 @@ LoadUint64 (uint64_t *addr) } uintptr_t LoadUintptr (uintptr_t *addr) - __asm__ (GOSYM_PREFIX "sync_atomic.LoadUintptr") + __asm__ (GOSYM_PREFIX "sync..z2fatomic.LoadUintptr") __attribute__ ((no_split_stack)); uintptr_t @@ -250,7 +250,7 @@ LoadUintptr (uintptr_t *addr) } void *LoadPointer (void **addr) - __asm__ (GOSYM_PREFIX "sync_atomic.LoadPointer") + __asm__ (GOSYM_PREFIX "sync..z2fatomic.LoadPointer") __attribute__ ((no_split_stack)); void * @@ -265,7 +265,7 @@ LoadPointer (void **addr) } void StoreInt32 (int32_t *addr, int32_t val) - __asm__ (GOSYM_PREFIX "sync_atomic.StoreInt32") + __asm__ (GOSYM_PREFIX "sync..z2fatomic.StoreInt32") __attribute__ ((no_split_stack)); void @@ -279,7 +279,7 @@ StoreInt32 (int32_t *addr, int32_t val) } void StoreInt64 (int64_t *addr, int64_t val) - __asm__ (GOSYM_PREFIX "sync_atomic.StoreInt64") + __asm__ (GOSYM_PREFIX "sync..z2fatomic.StoreInt64") __attribute__ ((no_split_stack)); void @@ -295,7 +295,7 @@ StoreInt64 (int64_t *addr, int64_t val) } void StoreUint32 (uint32_t *addr, uint32_t val) - __asm__ (GOSYM_PREFIX "sync_atomic.StoreUint32") + __asm__ (GOSYM_PREFIX "sync..z2fatomic.StoreUint32") __attribute__ ((no_split_stack)); void @@ -309,7 +309,7 @@ StoreUint32 (uint32_t *addr, uint32_t va } void StoreUint64 (uint64_t *addr, uint64_t val) - __asm__ (GOSYM_PREFIX "sync_atomic.StoreUint64") + __asm__ (GOSYM_PREFIX "sync..z2fatomic.StoreUint64") __attribute__ ((no_split_stack)); void @@ -325,7 +325,7 @@ StoreUint64 (uint64_t *addr, uint64_t va } void StoreUintptr (uintptr_t *addr, uintptr_t val) - __asm__ (GOSYM_PREFIX "sync_atomic.StoreUintptr") + __asm__ (GOSYM_PREFIX "sync..z2fatomic.StoreUintptr") __attribute__ ((no_split_stack)); void Index: libgo/testsuite/gotest =================================================================== --- libgo/testsuite/gotest (revision 265460) +++ libgo/testsuite/gotest (working copy) @@ -504,6 +504,35 @@ localname() { echo $1 | sed 's/^main\./__main__./' } +# Takes a list of tests derived from 'nm' output (whose symbols are mangled) +# and emits a demangled list of tests, using only the terminal package. +# Example: +# +# Original symbol: foo/bar/leaf.Mumble +# Mangled symbol: foo..z2fbar..z2fleaf.Mumble +# Returned: leaf.Mumble +# +symtogo() { + local s="" + local result="" + local ndots="" + for tp in $* + do + s=$(echo $tp | sed -e 's/\.\.z2f/%/g' | sed -e 's/.*%//') + # screen out methods (X.Y.Z) + ndots=$(echo $s | sed -e 's/\./ /g' | wc -w) + if [ $ndots -ne 2 ]; then + continue + fi + if [ -z "${result}" ]; then + result="${s}" + else + result="${result} ${s}" + fi + done + echo "$result" | sed -e 's/ /\n/g' +} + { text="T" @@ -514,26 +543,27 @@ localname() { text="[TD]" fi - symtogo='sed -e s/_test\([^A-Za-z0-9]\)/XXXtest\1/ -e s/.*_\([^_]*\.\)/\1/ -e s/XXXtest/_test/' - # test functions are named TestFoo # the grep -v eliminates methods and other special names # that have multiple dots. pattern='Test([^a-z].*)?' # The -p option tells GNU nm not to sort. # The -v option tells Solaris nm to sort by value. - tests=$($NM -p -v _gotest_.o $xofile | egrep " $text .*\."$pattern'$' | grep -v '[^ ]\..*\.' | fgrep -v ' __go_' | sed 's/.* //' | $symtogo) + testsyms=$($NM -p -v _gotest_.o $xofile | egrep " $text .*\."$pattern'$' | fgrep -v ' __go_' | egrep -v '\.\.\w+$' | sed 's/.* //') + tests=$(symtogo "$testsyms") if [ "x$tests" = x ]; then echo 'gotest: warning: no tests matching '$pattern in _gotest_.o $xofile 1>&2 exit 2 fi # benchmarks are named BenchmarkFoo. pattern='Benchmark([^a-z].*)?' - benchmarks=$($NM -p -v _gotest_.o $xofile | egrep " $text .*\."$pattern'$' | grep -v '[^ ]\..*\.' | fgrep -v ' __go_' | sed 's/.* //' | $symtogo) + benchmarksyms=$($NM -p -v _gotest_.o $xofile | egrep " $text .*\."$pattern'$' | fgrep -v ' __go_' | egrep -v '\.\.\w+$' | sed 's/.* //') + benchmarks=$(symtogo "$benchmarksyms") # examples are named ExampleFoo pattern='Example([^a-z].*)?' - examples=$($NM -p -v _gotest_.o $xofile | egrep " $text .*\."$pattern'$' | grep -v '[^ ]\..*\.' | fgrep -v ' __go_' | sed 's/.* //' | $symtogo) + examplesyms=$($NM -p -v _gotest_.o $xofile | egrep " $text .*\."$pattern'$' | fgrep -v ' __go_' | egrep -v '\.\.\w+$' | sed 's/.* //') + examples=$(symtogo "$examplesyms") # package spec echo 'package main'