Explorar el Código

unix: add ptrace definitions for compatible GOARCH pairs

For pairs of GOARCH values that can execute each other's binaries on
the same system, such as 386 and amd64, add the definitions and
functions required to fetch and set registers when debugging either
variant.

Fixes golang/go#9739

Change-Id: I7896ddef7d341ffaee56614ebd080dc38c708ed4
Reviewed-on: https://go-review.googlesource.com/73555
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Tobias Klauser <tobias.klauser@gmail.com>
Ian Lance Taylor hace 8 años
padre
commit
3e3646d2c7
Se han modificado 5 ficheros con 323 adiciones y 0 borrados
  1. 102 0
      unix/linux/mkall.go
  2. 80 0
      unix/zptrace386_linux.go
  3. 41 0
      unix/zptracearm_linux.go
  4. 50 0
      unix/zptracemips_linux.go
  5. 50 0
      unix/zptracemipsle_linux.go

+ 102 - 0
unix/linux/mkall.go

@@ -15,12 +15,17 @@
 package main
 package main
 
 
 import (
 import (
+	"bufio"
+	"bytes"
 	"fmt"
 	"fmt"
+	"io"
+	"io/ioutil"
 	"os"
 	"os"
 	"os/exec"
 	"os/exec"
 	"path/filepath"
 	"path/filepath"
 	"runtime"
 	"runtime"
 	"strings"
 	"strings"
+	"unicode"
 )
 )
 
 
 // These will be paths to the appropriate source directories.
 // These will be paths to the appropriate source directories.
@@ -128,6 +133,15 @@ var targets = []target{
 	// },
 	// },
 }
 }
 
 
+// ptracePairs is a list of pairs of targets that can, in some cases,
+// run each other's binaries.
+var ptracePairs = []struct{ a1, a2 string }{
+	{"386", "amd64"},
+	{"arm", "arm64"},
+	{"mips", "mips64"},
+	{"mipsle", "mips64le"},
+}
+
 func main() {
 func main() {
 	if runtime.GOOS != GOOS || runtime.GOARCH != BuildArch {
 	if runtime.GOOS != GOOS || runtime.GOARCH != BuildArch {
 		fmt.Printf("Build system has GOOS_GOARCH = %s_%s, need %s_%s\n",
 		fmt.Printf("Build system has GOOS_GOARCH = %s_%s, need %s_%s\n",
@@ -158,6 +172,17 @@ func main() {
 			fmt.Printf("----- SUCCESS:    %s -----\n\n", t.GoArch)
 			fmt.Printf("----- SUCCESS:    %s -----\n\n", t.GoArch)
 		}
 		}
 	}
 	}
+
+	fmt.Printf("----- GENERATING ptrace pairs -----\n")
+	ok := true
+	for _, p := range ptracePairs {
+		if err := generatePtracePair(p.a1, p.a2); err != nil {
+			fmt.Printf("%v\n***** FAILURE: %s/%s *****\n\n", err, p.a1, p.a2)
+		}
+	}
+	if ok {
+		fmt.Printf("----- SUCCESS ptrace pairs    -----\n\n")
+	}
 }
 }
 
 
 // Makes an exec.Cmd with Stderr attached to os.Stderr
 // Makes an exec.Cmd with Stderr attached to os.Stderr
@@ -377,3 +402,80 @@ func (t *target) mksyscallFlags() (flags []string) {
 	}
 	}
 	return
 	return
 }
 }
+
+// generatePtracePair takes a pair of GOARCH values that can run each
+// other's binaries, such as 386 and amd64. It extracts the PtraceRegs
+// type for each one. It writes a new file defining the types
+// PtraceRegsArch1 and PtraceRegsArch2 and the corresponding functions
+// Ptrace{Get,Set}Regs{arch1,arch2}. This permits debugging the other
+// binary on a native system.
+func generatePtracePair(arch1, arch2 string) error {
+	def1, err := ptraceDef(arch1)
+	if err != nil {
+		return err
+	}
+	def2, err := ptraceDef(arch2)
+	if err != nil {
+		return err
+	}
+	f, err := os.Create(fmt.Sprintf("zptrace%s_linux.go", arch1))
+	if err != nil {
+		return err
+	}
+	buf := bufio.NewWriter(f)
+	fmt.Fprintf(buf, "// Code generated by linux/mkall.go generatePtracePair(%s, %s).  DO NOT EDIT.\n", arch1, arch2)
+	fmt.Fprintf(buf, "\n")
+	fmt.Fprintf(buf, "// +build linux\n")
+	fmt.Fprintf(buf, "// +build %s %s\n", arch1, arch2)
+	fmt.Fprintf(buf, "\n")
+	fmt.Fprintf(buf, "package unix\n")
+	fmt.Fprintf(buf, "\n")
+	fmt.Fprintf(buf, "%s\n", `import "unsafe"`)
+	fmt.Fprintf(buf, "\n")
+	writeOnePtrace(buf, arch1, def1)
+	fmt.Fprintf(buf, "\n")
+	writeOnePtrace(buf, arch2, def2)
+	if err := buf.Flush(); err != nil {
+		return err
+	}
+	if err := f.Close(); err != nil {
+		return err
+	}
+	return nil
+}
+
+// ptraceDef returns the definition of PtraceRegs for arch.
+func ptraceDef(arch string) (string, error) {
+	filename := fmt.Sprintf("ztypes_linux_%s.go", arch)
+	data, err := ioutil.ReadFile(filename)
+	if err != nil {
+		return "", fmt.Errorf("reading %s: %v", filename, err)
+	}
+	start := bytes.Index(data, []byte("type PtraceRegs struct"))
+	if start < 0 {
+		return "", fmt.Errorf("%s: no definition of PtraceRegs", filename)
+	}
+	data = data[start:]
+	end := bytes.Index(data, []byte("\n}\n"))
+	if end < 0 {
+		return "", fmt.Errorf("%s: can't find end of PtraceRegs definition", filename)
+	}
+	return string(data[:end+2]), nil
+}
+
+// writeOnePtrace writes out the ptrace definitions for arch.
+func writeOnePtrace(w io.Writer, arch, def string) {
+	uarch := string(unicode.ToUpper(rune(arch[0]))) + arch[1:]
+	fmt.Fprintf(w, "// PtraceRegs%s is the registers used by %s binaries.\n", uarch, arch)
+	fmt.Fprintf(w, "%s\n", strings.Replace(def, "PtraceRegs", "PtraceRegs"+uarch, 1))
+	fmt.Fprintf(w, "\n")
+	fmt.Fprintf(w, "// PtraceGetRegs%s fetches the registers used by %s binaries.\n", uarch, arch)
+	fmt.Fprintf(w, "func PtraceGetRegs%s(pid int, regsout *PtraceRegs%s) error {\n", uarch, uarch)
+	fmt.Fprintf(w, "\treturn ptrace(PTRACE_GETREGS, pid, 0, uintptr(unsafe.Pointer(regsout)))\n")
+	fmt.Fprintf(w, "}\n")
+	fmt.Fprintf(w, "\n")
+	fmt.Fprintf(w, "// PtraceSetRegs%s sets the registers used by %s binaries.\n", uarch, arch)
+	fmt.Fprintf(w, "func PtraceSetRegs%s(pid int, regs *PtraceRegs%s) error {\n", uarch, uarch)
+	fmt.Fprintf(w, "\treturn ptrace(PTRACE_SETREGS, pid, 0, uintptr(unsafe.Pointer(regs)))\n")
+	fmt.Fprintf(w, "}\n")
+}

+ 80 - 0
unix/zptrace386_linux.go

@@ -0,0 +1,80 @@
+// Code generated by linux/mkall.go generatePtracePair(386, amd64).  DO NOT EDIT.
+
+// +build linux
+// +build 386 amd64
+
+package unix
+
+import "unsafe"
+
+// PtraceRegs386 is the registers used by 386 binaries.
+type PtraceRegs386 struct {
+	Ebx      int32
+	Ecx      int32
+	Edx      int32
+	Esi      int32
+	Edi      int32
+	Ebp      int32
+	Eax      int32
+	Xds      int32
+	Xes      int32
+	Xfs      int32
+	Xgs      int32
+	Orig_eax int32
+	Eip      int32
+	Xcs      int32
+	Eflags   int32
+	Esp      int32
+	Xss      int32
+}
+
+// PtraceGetRegs386 fetches the registers used by 386 binaries.
+func PtraceGetRegs386(pid int, regsout *PtraceRegs386) error {
+	return ptrace(PTRACE_GETREGS, pid, 0, uintptr(unsafe.Pointer(regsout)))
+}
+
+// PtraceSetRegs386 sets the registers used by 386 binaries.
+func PtraceSetRegs386(pid int, regs *PtraceRegs386) error {
+	return ptrace(PTRACE_SETREGS, pid, 0, uintptr(unsafe.Pointer(regs)))
+}
+
+// PtraceRegsAmd64 is the registers used by amd64 binaries.
+type PtraceRegsAmd64 struct {
+	R15      uint64
+	R14      uint64
+	R13      uint64
+	R12      uint64
+	Rbp      uint64
+	Rbx      uint64
+	R11      uint64
+	R10      uint64
+	R9       uint64
+	R8       uint64
+	Rax      uint64
+	Rcx      uint64
+	Rdx      uint64
+	Rsi      uint64
+	Rdi      uint64
+	Orig_rax uint64
+	Rip      uint64
+	Cs       uint64
+	Eflags   uint64
+	Rsp      uint64
+	Ss       uint64
+	Fs_base  uint64
+	Gs_base  uint64
+	Ds       uint64
+	Es       uint64
+	Fs       uint64
+	Gs       uint64
+}
+
+// PtraceGetRegsAmd64 fetches the registers used by amd64 binaries.
+func PtraceGetRegsAmd64(pid int, regsout *PtraceRegsAmd64) error {
+	return ptrace(PTRACE_GETREGS, pid, 0, uintptr(unsafe.Pointer(regsout)))
+}
+
+// PtraceSetRegsAmd64 sets the registers used by amd64 binaries.
+func PtraceSetRegsAmd64(pid int, regs *PtraceRegsAmd64) error {
+	return ptrace(PTRACE_SETREGS, pid, 0, uintptr(unsafe.Pointer(regs)))
+}

+ 41 - 0
unix/zptracearm_linux.go

@@ -0,0 +1,41 @@
+// Code generated by linux/mkall.go generatePtracePair(arm, arm64).  DO NOT EDIT.
+
+// +build linux
+// +build arm arm64
+
+package unix
+
+import "unsafe"
+
+// PtraceRegsArm is the registers used by arm binaries.
+type PtraceRegsArm struct {
+	Uregs [18]uint32
+}
+
+// PtraceGetRegsArm fetches the registers used by arm binaries.
+func PtraceGetRegsArm(pid int, regsout *PtraceRegsArm) error {
+	return ptrace(PTRACE_GETREGS, pid, 0, uintptr(unsafe.Pointer(regsout)))
+}
+
+// PtraceSetRegsArm sets the registers used by arm binaries.
+func PtraceSetRegsArm(pid int, regs *PtraceRegsArm) error {
+	return ptrace(PTRACE_SETREGS, pid, 0, uintptr(unsafe.Pointer(regs)))
+}
+
+// PtraceRegsArm64 is the registers used by arm64 binaries.
+type PtraceRegsArm64 struct {
+	Regs   [31]uint64
+	Sp     uint64
+	Pc     uint64
+	Pstate uint64
+}
+
+// PtraceGetRegsArm64 fetches the registers used by arm64 binaries.
+func PtraceGetRegsArm64(pid int, regsout *PtraceRegsArm64) error {
+	return ptrace(PTRACE_GETREGS, pid, 0, uintptr(unsafe.Pointer(regsout)))
+}
+
+// PtraceSetRegsArm64 sets the registers used by arm64 binaries.
+func PtraceSetRegsArm64(pid int, regs *PtraceRegsArm64) error {
+	return ptrace(PTRACE_SETREGS, pid, 0, uintptr(unsafe.Pointer(regs)))
+}

+ 50 - 0
unix/zptracemips_linux.go

@@ -0,0 +1,50 @@
+// Code generated by linux/mkall.go generatePtracePair(mips, mips64).  DO NOT EDIT.
+
+// +build linux
+// +build mips mips64
+
+package unix
+
+import "unsafe"
+
+// PtraceRegsMips is the registers used by mips binaries.
+type PtraceRegsMips struct {
+	Regs     [32]uint64
+	Lo       uint64
+	Hi       uint64
+	Epc      uint64
+	Badvaddr uint64
+	Status   uint64
+	Cause    uint64
+}
+
+// PtraceGetRegsMips fetches the registers used by mips binaries.
+func PtraceGetRegsMips(pid int, regsout *PtraceRegsMips) error {
+	return ptrace(PTRACE_GETREGS, pid, 0, uintptr(unsafe.Pointer(regsout)))
+}
+
+// PtraceSetRegsMips sets the registers used by mips binaries.
+func PtraceSetRegsMips(pid int, regs *PtraceRegsMips) error {
+	return ptrace(PTRACE_SETREGS, pid, 0, uintptr(unsafe.Pointer(regs)))
+}
+
+// PtraceRegsMips64 is the registers used by mips64 binaries.
+type PtraceRegsMips64 struct {
+	Regs     [32]uint64
+	Lo       uint64
+	Hi       uint64
+	Epc      uint64
+	Badvaddr uint64
+	Status   uint64
+	Cause    uint64
+}
+
+// PtraceGetRegsMips64 fetches the registers used by mips64 binaries.
+func PtraceGetRegsMips64(pid int, regsout *PtraceRegsMips64) error {
+	return ptrace(PTRACE_GETREGS, pid, 0, uintptr(unsafe.Pointer(regsout)))
+}
+
+// PtraceSetRegsMips64 sets the registers used by mips64 binaries.
+func PtraceSetRegsMips64(pid int, regs *PtraceRegsMips64) error {
+	return ptrace(PTRACE_SETREGS, pid, 0, uintptr(unsafe.Pointer(regs)))
+}

+ 50 - 0
unix/zptracemipsle_linux.go

@@ -0,0 +1,50 @@
+// Code generated by linux/mkall.go generatePtracePair(mipsle, mips64le).  DO NOT EDIT.
+
+// +build linux
+// +build mipsle mips64le
+
+package unix
+
+import "unsafe"
+
+// PtraceRegsMipsle is the registers used by mipsle binaries.
+type PtraceRegsMipsle struct {
+	Regs     [32]uint64
+	Lo       uint64
+	Hi       uint64
+	Epc      uint64
+	Badvaddr uint64
+	Status   uint64
+	Cause    uint64
+}
+
+// PtraceGetRegsMipsle fetches the registers used by mipsle binaries.
+func PtraceGetRegsMipsle(pid int, regsout *PtraceRegsMipsle) error {
+	return ptrace(PTRACE_GETREGS, pid, 0, uintptr(unsafe.Pointer(regsout)))
+}
+
+// PtraceSetRegsMipsle sets the registers used by mipsle binaries.
+func PtraceSetRegsMipsle(pid int, regs *PtraceRegsMipsle) error {
+	return ptrace(PTRACE_SETREGS, pid, 0, uintptr(unsafe.Pointer(regs)))
+}
+
+// PtraceRegsMips64le is the registers used by mips64le binaries.
+type PtraceRegsMips64le struct {
+	Regs     [32]uint64
+	Lo       uint64
+	Hi       uint64
+	Epc      uint64
+	Badvaddr uint64
+	Status   uint64
+	Cause    uint64
+}
+
+// PtraceGetRegsMips64le fetches the registers used by mips64le binaries.
+func PtraceGetRegsMips64le(pid int, regsout *PtraceRegsMips64le) error {
+	return ptrace(PTRACE_GETREGS, pid, 0, uintptr(unsafe.Pointer(regsout)))
+}
+
+// PtraceSetRegsMips64le sets the registers used by mips64le binaries.
+func PtraceSetRegsMips64le(pid int, regs *PtraceRegsMips64le) error {
+	return ptrace(PTRACE_SETREGS, pid, 0, uintptr(unsafe.Pointer(regs)))
+}