|
@@ -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")
|
|
|
|
|
+}
|