summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRuss Cox <rsc@golang.org>2013-12-18 19:00:52 -0500
committerRuss Cox <rsc@golang.org>2013-12-18 19:00:52 -0500
commit2980aae9cc87cf29b17a142869d2b2f6df9317f7 (patch)
tree4e2e4988ac97cbf5fb1d8acbad223547fd874889
parentbc595bdad85982f528d79095d429b615a396be12 (diff)
downloadgo-2980aae9cc87cf29b17a142869d2b2f6df9317f7.tar.gz
debug/goobj: expand package prefix correctly
R=r, bradfitz CC=golang-dev https://codereview.appspot.com/43480049
-rw-r--r--src/cmd/gc/subr.c3
-rw-r--r--src/cmd/ld/lib.c3
-rw-r--r--src/pkg/debug/goobj/read.go66
-rw-r--r--src/pkg/debug/goobj/read_test.go28
4 files changed, 90 insertions, 10 deletions
diff --git a/src/cmd/gc/subr.c b/src/cmd/gc/subr.c
index a79cf06b7..cca9705b2 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 f4ac30a57..138a91787 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 86c2aef87..3338c411d 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 000000000..dee140533
--- /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)
+ }
+ }
+}