Skip to content

Commit 35dce1d

Browse files
author
Jay Conrod
committed
cmd/go: trim source paths when compiling C with -trimpath
When then go command is run with -trimpath, it will now use -fdebug-prefix-map when invoking the C compiler (if supported) to replace the source root directory with a dummy root directory. This should prevent source directories from appearing either literally or in compressed DWARF in linked binaries. Updates #36072 Change-Id: Iedd08d5e886f81e981f11248a1be4ed4f58bdd29 Reviewed-on: https://go-review.googlesource.com/c/go/+/212101 Run-TryBot: Jay Conrod <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Bryan C. Mills <[email protected]>
1 parent 5a550b6 commit 35dce1d

File tree

3 files changed

+193
-0
lines changed

3 files changed

+193
-0
lines changed

src/cmd/go/internal/work/exec.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2169,6 +2169,39 @@ func (b *Builder) ccompile(a *Action, p *load.Package, outfile string, flags []s
21692169
desc := p.ImportPath
21702170
outfile = mkAbs(p.Dir, outfile)
21712171

2172+
// Elide source directory paths if -trimpath or GOROOT_FINAL is set.
2173+
// This is needed for source files (e.g., a .c file in a package directory).
2174+
// TODO(golang.org/issue/36072): cgo also generates files with #line
2175+
// directives pointing to the source directory. It should not generate those
2176+
// when -trimpath is enabled.
2177+
if b.gccSupportsFlag(compiler, "-fdebug-prefix-map=a=b") {
2178+
if cfg.BuildTrimpath {
2179+
// Keep in sync with Action.trimpath.
2180+
// The trimmed paths are a little different, but we need to trim in the
2181+
// same situations.
2182+
var from, toPath string
2183+
if m := p.Module; m != nil {
2184+
from = m.Dir
2185+
toPath = m.Path + "@" + m.Version
2186+
} else {
2187+
from = p.Dir
2188+
toPath = p.ImportPath
2189+
}
2190+
// -fdebug-prefix-map requires an absolute "to" path (or it joins the path
2191+
// with the working directory). Pick something that makes sense for the
2192+
// target platform.
2193+
var to string
2194+
if cfg.BuildContext.GOOS == "windows" {
2195+
to = filepath.Join(`\\_\_`, toPath)
2196+
} else {
2197+
to = filepath.Join("/_", toPath)
2198+
}
2199+
flags = append(flags[:len(flags):len(flags)], "-fdebug-prefix-map="+from+"="+to)
2200+
} else if p.Goroot && cfg.GOROOT_FINAL != cfg.GOROOT {
2201+
flags = append(flags[:len(flags):len(flags)], "-fdebug-prefix-map="+cfg.GOROOT+"="+cfg.GOROOT_FINAL)
2202+
}
2203+
}
2204+
21722205
output, err := b.runOut(a, filepath.Dir(file), b.cCompilerEnv(), compiler, flags, "-o", outfile, "-c", filepath.Base(file))
21732206
if len(output) > 0 {
21742207
// On FreeBSD 11, when we pass -g to clang 3.8 it

src/cmd/go/internal/work/gc.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,10 @@ CheckFlags:
223223
// trimpath returns the -trimpath argument to use
224224
// when compiling the action.
225225
func (a *Action) trimpath() string {
226+
// Keep in sync with Builder.ccompile
227+
// The trimmed paths are a little different, but we need to trim in the
228+
// same situations.
229+
226230
// Strip the object directory entirely.
227231
objdir := a.Objdir
228232
if len(objdir) > 1 && objdir[len(objdir)-1] == filepath.Separator {
Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
# This test builds a cgo binary and verifies the source directory path
2+
# does not appear in the binary, either literally or in compressed DWARF.
3+
# TODO(golang.org/issue/36072): ideally we should build a binary from identical
4+
# sources in different directories and verify the binary and all intermediate
5+
# files are identical.
6+
7+
[short] skip
8+
[!cgo] skip
9+
10+
# Check that the source path appears when -trimpath is not used.
11+
go build -o hello.exe .
12+
grep -q gopath[/\\]src hello.exe
13+
go run ./list-dwarf hello.exe
14+
stdout gopath[/\\]src
15+
16+
# Check that the source path does not appear when -trimpath is used.
17+
[aix] stop # can't inspect XCOFF binaries
18+
go build -trimpath -o hello.exe .
19+
! grep -q gopath[/\\]src hello.exe
20+
go run ./list-dwarf hello.exe
21+
! stdout gopath/src
22+
23+
-- go.mod --
24+
module m
25+
26+
go 1.14
27+
-- hello.c --
28+
#include <stdio.h>
29+
30+
void say_hello() { puts("Hello, world!\n"); }
31+
32+
-- hello.go --
33+
package main
34+
35+
// void say_hello();
36+
import "C"
37+
38+
func main() {
39+
C.say_hello()
40+
}
41+
42+
-- list-dwarf/list-dwarf.go --
43+
package main
44+
45+
import (
46+
"debug/dwarf"
47+
"fmt"
48+
"io"
49+
"log"
50+
"os"
51+
"sort"
52+
)
53+
54+
func main() {
55+
files, err := run(os.Args[1])
56+
if err != nil {
57+
log.Fatal(err)
58+
}
59+
for _, file := range files {
60+
fmt.Println(file)
61+
}
62+
}
63+
64+
func run(exePath string) ([]string, error) {
65+
dwarfData, err := readDWARF(exePath)
66+
if err != nil {
67+
return nil, err
68+
}
69+
70+
dwarfReader := dwarfData.Reader()
71+
files := make(map[string]bool)
72+
for {
73+
e, err := dwarfReader.Next()
74+
if err != nil {
75+
return nil, err
76+
}
77+
if e == nil {
78+
break
79+
}
80+
lr, err := dwarfData.LineReader(e)
81+
if err != nil {
82+
return nil, err
83+
}
84+
if lr == nil {
85+
continue
86+
}
87+
88+
var le dwarf.LineEntry
89+
for {
90+
if err := lr.Next(&le); err != nil {
91+
if err == io.EOF {
92+
break
93+
}
94+
return nil, err
95+
}
96+
files[le.File.Name] = true
97+
}
98+
}
99+
100+
sortedFiles := make([]string, 0, len(files))
101+
for file := range files {
102+
sortedFiles = append(sortedFiles, file)
103+
}
104+
sort.Strings(sortedFiles)
105+
return sortedFiles, nil
106+
}
107+
-- list-dwarf/read_darwin.go --
108+
package main
109+
110+
import (
111+
"debug/dwarf"
112+
"debug/macho"
113+
)
114+
115+
func readDWARF(exePath string) (*dwarf.Data, error) {
116+
machoFile, err := macho.Open(exePath)
117+
if err != nil {
118+
return nil, err
119+
}
120+
defer machoFile.Close()
121+
return machoFile.DWARF()
122+
}
123+
-- list-dwarf/read_elf.go --
124+
// +build android dragonfly freebsd illumos linux netbsd openbsd solaris
125+
126+
package main
127+
128+
import (
129+
"debug/dwarf"
130+
"debug/elf"
131+
)
132+
133+
func readDWARF(exePath string) (*dwarf.Data, error) {
134+
elfFile, err := elf.Open(exePath)
135+
if err != nil {
136+
return nil, err
137+
}
138+
defer elfFile.Close()
139+
return elfFile.DWARF()
140+
}
141+
-- list-dwarf/read_windows.go --
142+
package main
143+
144+
import (
145+
"debug/dwarf"
146+
"debug/pe"
147+
)
148+
149+
func readDWARF(exePath string) (*dwarf.Data, error) {
150+
peFile, err := pe.Open(exePath)
151+
if err != nil {
152+
return nil, err
153+
}
154+
defer peFile.Close()
155+
return peFile.DWARF()
156+
}

0 commit comments

Comments
 (0)