mirror of
git://gcc.gnu.org/git/gcc.git
synced 2024-12-11 19:00:50 +08:00
compiler: improve name mangling for packpaths
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. Switch to a better mangling scheme to insure 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). Fixes golang/go#27534. Reviewed-on: https://go-review.googlesource.com/c/135455 From-SVN: r265510
This commit is contained in:
parent
fc756f9f46
commit
34489eb2af
@ -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.
|
||||
|
@ -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 int* pc)
|
||||
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)
|
||||
{
|
||||
|
@ -20,6 +20,11 @@ go_id_needs_encoding(const std::string& str);
|
||||
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
|
||||
|
@ -256,26 +256,11 @@ Gogo::Gogo(Backend* backend, Linemap* linemap, int, int pointer_size)
|
||||
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
|
||||
|
@ -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.
|
||||
|
@ -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()); }
|
||||
|
@ -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::string& go_name, const Package* package,
|
||||
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* package, const std::string& mname)
|
||||
|
||||
// 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::string& go_name, const Package* package)
|
||||
{
|
||||
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, std::string* ret) const
|
||||
|
||||
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* gogo, std::string* ret) const
|
||||
|
||||
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_name(Gogo* gogo, std::string* ret) const
|
||||
{
|
||||
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(Gogo* gogo, bool use_alias,
|
||||
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, Named_type* nt)
|
||||
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)
|
||||
{
|
||||
|
@ -229,6 +229,8 @@ var exportHeader = flag.String("exportheader", "", "where to write export header
|
||||
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
|
||||
|
@ -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(fgcch io.Writer) {
|
||||
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() string {
|
||||
}
|
||||
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"
|
||||
}
|
||||
|
@ -38,7 +38,7 @@ static const void *goMemmem(const void *in, size_t inl, const void *s, size_t sl
|
||||
#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, struct __go_open_array b)
|
||||
}
|
||||
|
||||
_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, struct __go_open_array b)
|
||||
}
|
||||
|
||||
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, byte c)
|
||||
|
||||
|
||||
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, struct __go_open_array b)
|
||||
}
|
||||
|
||||
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)
|
||||
|
@ -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
|
||||
|
@ -52,10 +52,10 @@ func casp(ptr *unsafe.Pointer, old, new unsafe.Pointer) bool {
|
||||
// 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 *unsafe.Pointer, new unsafe.Pointer) {
|
||||
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.Pointer, new unsafe.Pointer) unsafe.Poi
|
||||
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 {
|
||||
|
@ -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_cyclesPerSecond() int64 {
|
||||
// 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
|
||||
|
@ -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", "")
|
||||
}
|
||||
|
||||
|
@ -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")
|
||||
|
||||
|
@ -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 delta)
|
||||
}
|
||||
|
||||
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 new)
|
||||
}
|
||||
|
||||
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_t new)
|
||||
}
|
||||
|
||||
_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, uint64_t new)
|
||||
}
|
||||
|
||||
_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 old, uintptr_t new)
|
||||
}
|
||||
|
||||
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 val)
|
||||
}
|
||||
|
||||
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
|
||||
|
@ -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
|
||||
|
@ -1165,7 +1165,7 @@ func (h *mheap) scavenge(k int32, now, limit uint64) {
|
||||
}
|
||||
}
|
||||
|
||||
//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) })
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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() uintptr {
|
||||
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) (*pollDesc, int) {
|
||||
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, mode int) int {
|
||||
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, mode int) int {
|
||||
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 *pollDesc, mode int) {
|
||||
}
|
||||
}
|
||||
|
||||
//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 *pollDesc, d int64, mode int) {
|
||||
}
|
||||
}
|
||||
|
||||
//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 {
|
||||
|
@ -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
|
||||
|
@ -4670,7 +4670,7 @@ func runqsteal(_p_, p2 *p, stealRunNextG bool) *g {
|
||||
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()
|
||||
|
@ -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.Pointer) {
|
||||
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
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -56,7 +56,7 @@ func sync_runtime_Semacquire(addr *uint32) {
|
||||
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 *uint32, lifo bool) {
|
||||
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)
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -83,6 +83,11 @@ func (ci *Frames) Next() (frame Frame, more bool) {
|
||||
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) (file string, line int) {
|
||||
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<hex 2 >", "..u<hex x 4>" and "..U<hex x 8>" 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
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -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 uint64, taskType string) {
|
||||
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, name string) {
|
||||
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
|
||||
|
@ -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'
|
||||
}
|
||||
|
||||
|
@ -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 new)
|
||||
}
|
||||
|
||||
_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_t old, int32_t new)
|
||||
}
|
||||
|
||||
_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_t old, int64_t new)
|
||||
}
|
||||
|
||||
_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, uint32_t old, uint32_t new)
|
||||
}
|
||||
|
||||
_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, uint64_t old, uint64_t new)
|
||||
}
|
||||
|
||||
_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, uintptr_t old, uintptr_t new)
|
||||
}
|
||||
|
||||
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 delta)
|
||||
}
|
||||
|
||||
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 val)
|
||||
}
|
||||
|
||||
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 val)
|
||||
}
|
||||
|
||||
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
|
||||
|
@ -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'
|
||||
|
Loading…
Reference in New Issue
Block a user