2018-11-07 22:21:35 +00:00
|
|
|
package proc_test
|
|
|
|
|
|
|
|
import (
|
2023-11-12 11:01:21 +00:00
|
|
|
"fmt"
|
2018-11-07 22:21:35 +00:00
|
|
|
"os"
|
|
|
|
"os/exec"
|
|
|
|
"path/filepath"
|
2023-11-12 11:01:21 +00:00
|
|
|
"runtime"
|
|
|
|
"strings"
|
2018-11-07 22:21:35 +00:00
|
|
|
"testing"
|
|
|
|
|
2023-07-05 15:39:01 +00:00
|
|
|
"github.com/go-delve/delve/pkg/proc"
|
2019-01-04 18:39:25 +00:00
|
|
|
"github.com/go-delve/delve/pkg/proc/native"
|
|
|
|
protest "github.com/go-delve/delve/pkg/proc/test"
|
2018-11-07 22:21:35 +00:00
|
|
|
)
|
|
|
|
|
2024-01-09 22:13:00 +00:00
|
|
|
func mustHaveObjcopy(t *testing.T) {
|
|
|
|
t.Helper()
|
|
|
|
if objcopyPath, _ := exec.LookPath("objcopy"); objcopyPath == "" {
|
|
|
|
t.Skip("no objcopy in path")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-07 22:21:35 +00:00
|
|
|
func TestLoadingExternalDebugInfo(t *testing.T) {
|
2024-01-09 22:13:00 +00:00
|
|
|
mustHaveObjcopy(t)
|
2018-11-07 22:21:35 +00:00
|
|
|
fixture := protest.BuildFixture("locationsprog", 0)
|
|
|
|
defer os.Remove(fixture.Path)
|
|
|
|
stripAndCopyDebugInfo(fixture, t)
|
2023-07-05 15:39:01 +00:00
|
|
|
p, err := native.Launch(append([]string{fixture.Path}, ""), "", 0, []string{filepath.Dir(fixture.Path)}, "", "", proc.OutputRedirect{}, proc.OutputRedirect{})
|
2018-11-07 22:21:35 +00:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
p.Detach(true)
|
|
|
|
}
|
|
|
|
|
2023-11-12 11:01:21 +00:00
|
|
|
func TestGnuDebuglink(t *testing.T) {
|
2024-01-09 22:13:00 +00:00
|
|
|
mustHaveObjcopy(t)
|
2023-11-12 11:01:21 +00:00
|
|
|
// build math.go and make a copy of the executable
|
|
|
|
fixture := protest.BuildFixture("math", 0)
|
|
|
|
buf, err := os.ReadFile(fixture.Path)
|
|
|
|
assertNoError(err, t, "ReadFile")
|
|
|
|
debuglinkPath := fixture.Path + "-gnu_debuglink"
|
|
|
|
assertNoError(os.WriteFile(debuglinkPath, buf, 0666), t, "WriteFile")
|
|
|
|
defer os.Remove(debuglinkPath)
|
|
|
|
|
|
|
|
run := func(exe string, args ...string) {
|
|
|
|
cmd := exec.Command(exe, args...)
|
|
|
|
out, err := cmd.CombinedOutput()
|
|
|
|
assertNoError(err, t, fmt.Sprintf("%s %q: %s", cmd, strings.Join(args, " "), out))
|
|
|
|
}
|
|
|
|
|
|
|
|
// convert the executable copy to use .gnu_debuglink
|
|
|
|
debuglinkDwoPath := debuglinkPath + ".dwo"
|
|
|
|
run("objcopy", "--only-keep-debug", debuglinkPath, debuglinkDwoPath)
|
|
|
|
defer os.Remove(debuglinkDwoPath)
|
|
|
|
run("objcopy", "--strip-debug", debuglinkPath)
|
|
|
|
run("objcopy", "--add-gnu-debuglink="+debuglinkDwoPath, debuglinkPath)
|
|
|
|
|
|
|
|
// open original executable
|
|
|
|
normalBinInfo := proc.NewBinaryInfo(runtime.GOOS, runtime.GOARCH)
|
|
|
|
assertNoError(normalBinInfo.LoadBinaryInfo(fixture.Path, 0, []string{"/debugdir"}), t, "LoadBinaryInfo (normal exe)")
|
|
|
|
|
|
|
|
// open .gnu_debuglink executable
|
|
|
|
debuglinkBinInfo := proc.NewBinaryInfo(runtime.GOOS, runtime.GOARCH)
|
|
|
|
assertNoError(debuglinkBinInfo.LoadBinaryInfo(debuglinkPath, 0, []string{"/debugdir"}), t, "LoadBinaryInfo (gnu_debuglink exe)")
|
|
|
|
|
|
|
|
if len(normalBinInfo.Functions) != len(debuglinkBinInfo.Functions) {
|
|
|
|
t.Fatalf("function list mismatch")
|
|
|
|
}
|
|
|
|
|
|
|
|
for i := range normalBinInfo.Functions {
|
|
|
|
normalFn := normalBinInfo.Functions[i]
|
|
|
|
debuglinkFn := debuglinkBinInfo.Functions[i]
|
|
|
|
if normalFn.Entry != debuglinkFn.Entry || normalFn.Name != debuglinkFn.Name {
|
|
|
|
t.Fatalf("function definition mismatch")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-07 22:21:35 +00:00
|
|
|
func stripAndCopyDebugInfo(f protest.Fixture, t *testing.T) {
|
|
|
|
name := filepath.Base(f.Path)
|
|
|
|
// Copy the debug information to an external file.
|
|
|
|
copyCmd := exec.Command("objcopy", "--only-keep-debug", name, name+".debug")
|
|
|
|
copyCmd.Dir = filepath.Dir(f.Path)
|
|
|
|
if err := copyCmd.Run(); err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Strip the original binary of the debug information.
|
|
|
|
stripCmd := exec.Command("strip", "--strip-debug", "--strip-unneeded", name)
|
|
|
|
stripCmd.Dir = filepath.Dir(f.Path)
|
|
|
|
if err := stripCmd.Run(); err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
}
|