]> Cypherpunks repositories - gostls13.git/commitdiff
debug/goobj: expand package prefix correctly
authorRuss Cox <rsc@golang.org>
Thu, 19 Dec 2013 00:00:52 +0000 (19:00 -0500)
committerRuss Cox <rsc@golang.org>
Thu, 19 Dec 2013 00:00:52 +0000 (19:00 -0500)
R=r, bradfitz
CC=golang-dev
https://golang.org/cl/43480049

src/cmd/gc/subr.c
src/cmd/ld/lib.c
src/pkg/debug/goobj/read.go
src/pkg/debug/goobj/read_test.go [new file with mode: 0644]

index a79cf06b750fe15d27bbba0f248cacfca7024d4f..cca9705b27e57b674805042f45bc0dc009d8dd2a 100644 (file)
@@ -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)
index f4ac30a571ca854b129b08d0db911c295b184b09..138a91787d60fb16774c0e4dcab85a25a434d2ee 100644 (file)
@@ -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)
index 86c2aef87afb7f86f2857c04b0aa9f5e4e278fed..3338c411dc3f8ea59e600aa0481bcc418cdd2fd0 100644 (file)
@@ -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 (file)
index 0000000..dee1405
--- /dev/null
@@ -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)
+               }
+       }
+}