From 2404b7f16866b302efb19083dae155e0f4764144 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Wed, 18 Dec 2013 19:00:52 -0500 Subject: [PATCH] debug/goobj: expand package prefix correctly R=r, bradfitz CC=golang-dev https://golang.org/cl/43480049 --- src/cmd/gc/subr.c | 3 +- src/cmd/ld/lib.c | 3 +- src/pkg/debug/goobj/read.go | 66 ++++++++++++++++++++++++++++---- src/pkg/debug/goobj/read_test.go | 28 ++++++++++++++ 4 files changed, 90 insertions(+), 10 deletions(-) create mode 100644 src/pkg/debug/goobj/read_test.go diff --git a/src/cmd/gc/subr.c b/src/cmd/gc/subr.c index a79cf06b75..cca9705b27 100644 --- a/src/cmd/gc/subr.c +++ b/src/cmd/gc/subr.c @@ -3614,7 +3614,8 @@ ngotype(Node *n) * only in the last segment of the path, and it makes for happier * users if we escape that as little as possible. * - * If you edit this, edit ../ld/lib.c:/^pathtoprefix copy too. + * If you edit this, edit ../ld/lib.c:/^pathtoprefix too. + * If you edit this, edit ../../pkg/debug/goobj/read.go:/importPathToPrefix too. */ static char* pathtoprefix(char *s) diff --git a/src/cmd/ld/lib.c b/src/cmd/ld/lib.c index f4ac30a571..138a91787d 100644 --- a/src/cmd/ld/lib.c +++ b/src/cmd/ld/lib.c @@ -851,7 +851,8 @@ unmal(void *v, uint32 n) * Invalid bytes turn into %xx. Right now the only bytes that need * escaping are %, ., and ", but we escape all control characters too. * - * Must be same as ../gc/subr.c:/^pathtoprefix. + * If you edit this, edit ../gc/subr.c:/^pathtoprefix too. + * If you edit this, edit ../../pkg/debug/goobj/read.go:/importPathToPrefix too. */ static char* pathtoprefix(char *s) diff --git a/src/pkg/debug/goobj/read.go b/src/pkg/debug/goobj/read.go index 86c2aef87a..3338c411dc 100644 --- a/src/pkg/debug/goobj/read.go +++ b/src/pkg/debug/goobj/read.go @@ -16,6 +16,7 @@ import ( "fmt" "io" "strconv" + "strings" ) // A SymKind describes the kind of memory represented by a symbol. @@ -180,14 +181,54 @@ var ( // An objReader is an object file reader. type objReader struct { - p *Package - b *bufio.Reader - f io.ReadSeeker - err error - offset int64 - limit int64 - tmp [256]byte - pkg string + p *Package + b *bufio.Reader + f io.ReadSeeker + err error + offset int64 + limit int64 + tmp [256]byte + pkg string + pkgprefix string +} + +// importPathToPrefix returns the prefix that will be used in the +// final symbol table for the given import path. +// We escape '%', '"', all control characters and non-ASCII bytes, +// and any '.' after the final slash. +// +// See ../../../cmd/ld/lib.c:/^pathtoprefix and +// ../../../cmd/gc/subr.c:/^pathtoprefix. +func importPathToPrefix(s string) string { + // find index of last slash, if any, or else -1. + // used for determining whether an index is after the last slash. + slash := strings.LastIndex(s, "/") + + // check for chars that need escaping + n := 0 + for r := 0; r < len(s); r++ { + if c := s[r]; c <= ' ' || (c == '.' && r > slash) || c == '%' || c == '"' || c >= 0x7F { + n++ + } + } + + // quick exit + if n == 0 { + return s + } + + // escape + const hex = "0123456789abcdef" + p := make([]byte, 0, len(s)+2*n) + for r := 0; r < len(s); r++ { + if c := s[r]; c <= ' ' || (c == '.' && r > slash) || c == '%' || c == '"' || c >= 0x7F { + p = append(p, '%', hex[c>>4], hex[c&0xF]) + } else { + p = append(p, c) + } + } + + return string(p) } // init initializes r to read package p from f. @@ -198,6 +239,7 @@ func (r *objReader) init(f io.ReadSeeker, p *Package) { r.limit, _ = f.Seek(0, 2) f.Seek(r.offset, 0) r.b = bufio.NewReader(f) + r.pkgprefix = importPathToPrefix(p.ImportPath) + "." } // error records that an error occurred. @@ -296,6 +338,11 @@ func (r *objReader) readString() string { func (r *objReader) readSymID() SymID { name, vers := r.readString(), r.readInt() + // In a symbol name in an object file, "". denotes the + // prefix for the package in which the object file has been found. + // Expand it. + name = strings.Replace(name, `"".`, r.pkgprefix, -1) + // An individual object file only records version 0 (extern) or 1 (static). // To make static symbols unique across all files being read, we // replace version 1 with the version corresponding to the current @@ -346,6 +393,9 @@ func (r *objReader) skip(n int64) { // Parse parses an object file or archive from r, // assuming that its import path is pkgpath. func Parse(r io.ReadSeeker, pkgpath string) (*Package, error) { + if pkgpath == "" { + pkgpath = `""` + } p := new(Package) p.ImportPath = pkgpath diff --git a/src/pkg/debug/goobj/read_test.go b/src/pkg/debug/goobj/read_test.go new file mode 100644 index 0000000000..dee140533c --- /dev/null +++ b/src/pkg/debug/goobj/read_test.go @@ -0,0 +1,28 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package goobj + +import "testing" + +var importPathToPrefixTests = []struct { + in string + out string +}{ + {"runtime", "runtime"}, + {"sync/atomic", "sync/atomic"}, + {"code.google.com/p/go.tools/godoc", "code.google.com/p/go.tools/godoc"}, + {"foo.bar/baz.quux", "foo.bar/baz%2equux"}, + {"", ""}, + {"%foo%bar", "%25foo%25bar"}, + {"\x01\x00\x7F☺", "%01%00%7f%e2%98%ba"}, +} + +func TestImportPathToPrefix(t *testing.T) { + for _, tt := range importPathToPrefixTests { + if out := importPathToPrefix(tt.in); out != tt.out { + t.Errorf("importPathToPrefix(%q) = %q, want %q", tt.in, out, tt.out) + } + } +} -- 2.48.1