Skip to content

Commit 3462036

Browse files
committed
runtime, cgo/test: improve debugging output
tests that run commands should log their actions in a shell-pasteable way. Change-Id: Ifeee88397047ef5a76925c5f30c213e83e535038 Reviewed-on: https://go-review.googlesource.com/c/go/+/309770 Trust: David Chase <drchase@google.com> Run-TryBot: David Chase <drchase@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Cherry Zhang <cherryyz@google.com>
1 parent f2d5bd1 commit 3462036

File tree

3 files changed

+79
-3
lines changed

3 files changed

+79
-3
lines changed

misc/cgo/testplugin/plugin_test.go

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,18 @@ func TestMain(m *testing.M) {
3030
os.Exit(testMain(m))
3131
}
3232

33+
// tmpDir is used to cleanup logged commands -- s/tmpDir/$TMPDIR/
34+
var tmpDir string
35+
36+
// prettyPrintf prints lines with tmpDir sanitized.
37+
func prettyPrintf(format string, args ...interface{}) {
38+
s := fmt.Sprintf(format, args...)
39+
if tmpDir != "" {
40+
s = strings.ReplaceAll(s, tmpDir, "$TMPDIR")
41+
}
42+
fmt.Print(s)
43+
}
44+
3345
func testMain(m *testing.M) int {
3446
// Copy testdata into GOPATH/src/testplugin, along with a go.mod file
3547
// declaring the same path.
@@ -39,6 +51,7 @@ func testMain(m *testing.M) int {
3951
log.Panic(err)
4052
}
4153
defer os.RemoveAll(GOPATH)
54+
tmpDir = GOPATH
4255

4356
modRoot := filepath.Join(GOPATH, "src", "testplugin")
4457
altRoot := filepath.Join(GOPATH, "alt", "src", "testplugin")
@@ -49,21 +62,29 @@ func testMain(m *testing.M) int {
4962
if err := overlayDir(dstRoot, srcRoot); err != nil {
5063
log.Panic(err)
5164
}
65+
prettyPrintf("mkdir -p %s\n", dstRoot)
66+
prettyPrintf("rsync -a %s/ %s\n", srcRoot, dstRoot)
67+
5268
if err := os.WriteFile(filepath.Join(dstRoot, "go.mod"), []byte("module testplugin\n"), 0666); err != nil {
5369
log.Panic(err)
5470
}
71+
prettyPrintf("echo 'module testplugin' > %s/go.mod\n", dstRoot)
5572
}
5673

5774
os.Setenv("GOPATH", filepath.Join(GOPATH, "alt"))
5875
if err := os.Chdir(altRoot); err != nil {
5976
log.Panic(err)
77+
} else {
78+
prettyPrintf("cd %s\n", altRoot)
6079
}
6180
os.Setenv("PWD", altRoot)
6281
goCmd(nil, "build", "-buildmode=plugin", "-o", filepath.Join(modRoot, "plugin-mismatch.so"), "./plugin-mismatch")
6382

6483
os.Setenv("GOPATH", GOPATH)
6584
if err := os.Chdir(modRoot); err != nil {
6685
log.Panic(err)
86+
} else {
87+
prettyPrintf("cd %s\n", modRoot)
6788
}
6889
os.Setenv("PWD", modRoot)
6990

@@ -78,6 +99,7 @@ func testMain(m *testing.M) int {
7899
if err := os.WriteFile("plugin2-dup.so", so, 0444); err != nil {
79100
log.Panic(err)
80101
}
102+
prettyPrintf("cp plugin2.so plugin2-dup.so\n")
81103

82104
goCmd(nil, "build", "-buildmode=plugin", "-o=sub/plugin1.so", "./sub/plugin1")
83105
goCmd(nil, "build", "-buildmode=plugin", "-o=unnamed1.so", "./unnamed1/main.go")
@@ -94,8 +116,53 @@ func goCmd(t *testing.T, op string, args ...string) {
94116
run(t, "go", append([]string{op, "-gcflags", gcflags}, args...)...)
95117
}
96118

119+
// escape converts a string to something suitable for a shell command line.
120+
func escape(s string) string {
121+
s = strings.Replace(s, "\\", "\\\\", -1)
122+
s = strings.Replace(s, "'", "\\'", -1)
123+
// Conservative guess at characters that will force quoting
124+
if s == "" || strings.ContainsAny(s, "\\ ;#*&$~?!|[]()<>{}`") {
125+
s = "'" + s + "'"
126+
}
127+
return s
128+
}
129+
130+
// asCommandLine renders cmd as something that could be copy-and-pasted into a command line
131+
func asCommandLine(cwd string, cmd *exec.Cmd) string {
132+
s := "("
133+
if cmd.Dir != "" && cmd.Dir != cwd {
134+
s += "cd" + escape(cmd.Dir) + ";"
135+
}
136+
for _, e := range cmd.Env {
137+
if !strings.HasPrefix(e, "PATH=") &&
138+
!strings.HasPrefix(e, "HOME=") &&
139+
!strings.HasPrefix(e, "USER=") &&
140+
!strings.HasPrefix(e, "SHELL=") {
141+
s += " "
142+
s += escape(e)
143+
}
144+
}
145+
// These EVs are relevant to this test.
146+
for _, e := range os.Environ() {
147+
if strings.HasPrefix(e, "PWD=") ||
148+
strings.HasPrefix(e, "GOPATH=") ||
149+
strings.HasPrefix(e, "LD_LIBRARY_PATH=") {
150+
s += " "
151+
s += escape(e)
152+
}
153+
}
154+
for _, a := range cmd.Args {
155+
s += " "
156+
s += escape(a)
157+
}
158+
s += " )"
159+
return s
160+
}
161+
97162
func run(t *testing.T, bin string, args ...string) string {
98163
cmd := exec.Command(bin, args...)
164+
cmdLine := asCommandLine(".", cmd)
165+
prettyPrintf("%s\n", cmdLine)
99166
cmd.Stderr = new(strings.Builder)
100167
out, err := cmd.Output()
101168
if err != nil {

src/runtime/plugin.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,8 @@ func pluginftabverify(md *moduledata) {
115115
entry2 = f2.entry
116116
}
117117
badtable = true
118-
println("ftab entry outside pc range: ", hex(entry), "/", hex(entry2), ": ", name, "/", name2)
118+
println("ftab entry", hex(entry), "/", hex(entry2), ": ",
119+
name, "/", name2, "outside pc range:[", hex(md.minpc), ",", hex(md.maxpc), "], modulename=", md.modulename, ", pluginpath=", md.pluginpath)
119120
}
120121
if badtable {
121122
throw("runtime: plugin has bad symbol table")

src/runtime/symtab.go

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -561,7 +561,11 @@ func moduledataverify1(datap *moduledata) {
561561
// Check that the pclntab's format is valid.
562562
hdr := datap.pcHeader
563563
if hdr.magic != 0xfffffffa || hdr.pad1 != 0 || hdr.pad2 != 0 || hdr.minLC != sys.PCQuantum || hdr.ptrSize != sys.PtrSize {
564-
println("runtime: function symbol table header:", hex(hdr.magic), hex(hdr.pad1), hex(hdr.pad2), hex(hdr.minLC), hex(hdr.ptrSize))
564+
print("runtime: function symbol table header:", hex(hdr.magic), hex(hdr.pad1), hex(hdr.pad2), hex(hdr.minLC), hex(hdr.ptrSize))
565+
if datap.pluginpath != "" {
566+
print(", plugin:", datap.pluginpath)
567+
}
568+
println()
565569
throw("invalid function symbol table\n")
566570
}
567571

@@ -576,7 +580,11 @@ func moduledataverify1(datap *moduledata) {
576580
if i+1 < nftab {
577581
f2name = funcname(f2)
578582
}
579-
println("function symbol table not sorted by program counter:", hex(datap.ftab[i].entry), funcname(f1), ">", hex(datap.ftab[i+1].entry), f2name)
583+
print("function symbol table not sorted by program counter:", hex(datap.ftab[i].entry), funcname(f1), ">", hex(datap.ftab[i+1].entry), f2name)
584+
if datap.pluginpath != "" {
585+
print(", plugin:", datap.pluginpath)
586+
}
587+
println()
580588
for j := 0; j <= i; j++ {
581589
print("\t", hex(datap.ftab[j].entry), " ", funcname(funcInfo{(*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[j].funcoff])), datap}), "\n")
582590
}

0 commit comments

Comments
 (0)