unix: add functions PtraceGetRegSetArm64 and PtraceSetRegSetArm64

Since arm64 GNU/Linux version 2.6.34, PTRACE_GETREGS was replaced by PTRACE_GETREGSET,
in order to get or set the general purpose and floating-point register values,
PTRACE_GETREGSET/PTRACE_SETREGSET request type and a proper "NT_XXX" constant values
should be used. For the sake of not breaking the existing API, we added two functions
PtraceGetRegSetArm64 and PtraceSetRegSetArm64, they take an additional argument "addr",
and use PTRACE_GETREGSET and PTRACE_SETREGSET request types respectively.

Change-Id: I14c55733e15cea4b7d775187b1018fcb2880d6a9
Reviewed-on: https://go-review.googlesource.com/c/sys/+/204418
Run-TryBot: eric fang <eric.fang@arm.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
diff --git a/unix/linux/mkall.go b/unix/linux/mkall.go
index 88d9c82..d874a35 100644
--- a/unix/linux/mkall.go
+++ b/unix/linux/mkall.go
@@ -144,12 +144,16 @@
 }
 
 // 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"},
+// run each other's binaries. 'archName' is the combined name of 'a1'
+// and 'a2', which is used in the file name. Generally we use an 'x'
+// suffix in the file name to indicate that the file works for both
+// big-endian and little-endian, here we use 'nn' to indicate that this
+// file is suitable for 32-bit and 64-bit.
+var ptracePairs = []struct{ a1, a2, archName string }{
+	{"386", "amd64", "x86"},
+	{"arm", "arm64", "armnn"},
+	{"mips", "mips64", "mipsnn"},
+	{"mipsle", "mips64le", "mipsnnle"},
 }
 
 func main() {
@@ -186,7 +190,7 @@
 	fmt.Printf("----- GENERATING ptrace pairs -----\n")
 	ok := true
 	for _, p := range ptracePairs {
-		if err := generatePtracePair(p.a1, p.a2); err != nil {
+		if err := generatePtracePair(p.a1, p.a2, p.archName); err != nil {
 			fmt.Printf("%v\n***** FAILURE: %s/%s *****\n\n", err, p.a1, p.a2)
 			ok = false
 		}
@@ -545,8 +549,9 @@
 // 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 {
+// binary on a native system. 'archName' is the combined name of 'arch1'
+// and 'arch2', which is used in the file name.
+func generatePtracePair(arch1, arch2, archName string) error {
 	def1, err := ptraceDef(arch1)
 	if err != nil {
 		return err
@@ -555,12 +560,12 @@
 	if err != nil {
 		return err
 	}
-	f, err := os.Create(fmt.Sprintf("zptrace%s_linux.go", arch1))
+	f, err := os.Create(fmt.Sprintf("zptrace_%s_linux.go", archName))
 	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, "// Code generated by linux/mkall.go generatePtracePair(%q, %q). 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)
@@ -572,6 +577,10 @@
 	writeOnePtrace(buf, arch1, def1)
 	fmt.Fprintf(buf, "\n")
 	writeOnePtrace(buf, arch2, def2)
+	if arch2 == "arm64" {
+		fmt.Fprintf(buf, "\n")
+		writeOnePtraceRegSet(buf, arch2)
+	}
 	if err := buf.Flush(); err != nil {
 		return err
 	}
@@ -617,6 +626,23 @@
 	fmt.Fprintf(w, "}\n")
 }
 
+// writeOnePtraceRegSet writes out the ptrace definitions of PTRACE_GETREGSET and
+// PTRACE_SETREGSET request type.
+func writeOnePtraceRegSet(w io.Writer, arch string) {
+	uarch := string(unicode.ToUpper(rune(arch[0]))) + arch[1:]
+	fmt.Fprintf(w, "// PtraceGetRegSet%s fetches the registers used by %s binaries.\n", uarch, arch)
+	fmt.Fprintf(w, "func PtraceGetRegSet%s(pid, addr int, regsout *PtraceRegs%s) error {\n", uarch, uarch)
+	fmt.Fprintf(w, "\tiovec := Iovec{(*byte)(unsafe.Pointer(regsout)), uint64(unsafe.Sizeof(*regsout))}\n")
+	fmt.Fprintf(w, "\treturn ptrace(PTRACE_GETREGSET, pid, uintptr(addr), uintptr(unsafe.Pointer(&iovec)))\n")
+	fmt.Fprintf(w, "}\n")
+	fmt.Fprintf(w, "\n")
+	fmt.Fprintf(w, "// PtraceSetRegSet%s sets the registers used by %s binaries.\n", uarch, arch)
+	fmt.Fprintf(w, "func PtraceSetRegSet%s(pid, addr int, regs *PtraceRegs%s) error {\n", uarch, uarch)
+	fmt.Fprintf(w, "\tiovec := Iovec{(*byte)(unsafe.Pointer(regs)), uint64(unsafe.Sizeof(*regs))}\n")
+	fmt.Fprintf(w, "\treturn ptrace(PTRACE_SETREGSET, pid, uintptr(addr), uintptr(unsafe.Pointer(&iovec)))\n")
+	fmt.Fprintf(w, "}\n")
+}
+
 // cCode is compiled for the target architecture, and the resulting data section is carved for
 // the statically initialized bit masks.
 const cCode = `
diff --git a/unix/zptracearm_linux.go b/unix/zptrace_armnn_linux.go
similarity index 61%
rename from unix/zptracearm_linux.go
rename to unix/zptrace_armnn_linux.go
index faf23bb..8bcde84 100644
--- a/unix/zptracearm_linux.go
+++ b/unix/zptrace_armnn_linux.go
@@ -1,4 +1,4 @@
-// Code generated by linux/mkall.go generatePtracePair(arm, arm64). DO NOT EDIT.
+// Code generated by linux/mkall.go generatePtracePair("arm", "arm64"). DO NOT EDIT.
 
 // +build linux
 // +build arm arm64
@@ -39,3 +39,15 @@
 func PtraceSetRegsArm64(pid int, regs *PtraceRegsArm64) error {
 	return ptrace(PTRACE_SETREGS, pid, 0, uintptr(unsafe.Pointer(regs)))
 }
+
+// PtraceGetRegSetArm64 fetches the registers used by arm64 binaries.
+func PtraceGetRegSetArm64(pid, addr int, regsout *PtraceRegsArm64) error {
+	iovec := Iovec{(*byte)(unsafe.Pointer(regsout)), uint64(unsafe.Sizeof(*regsout))}
+	return ptrace(PTRACE_GETREGSET, pid, uintptr(addr), uintptr(unsafe.Pointer(&iovec)))
+}
+
+// PtraceSetRegSetArm64 sets the registers used by arm64 binaries.
+func PtraceSetRegSetArm64(pid, addr int, regs *PtraceRegsArm64) error {
+	iovec := Iovec{(*byte)(unsafe.Pointer(regs)), uint64(unsafe.Sizeof(*regs))}
+	return ptrace(PTRACE_SETREGSET, pid, uintptr(addr), uintptr(unsafe.Pointer(&iovec)))
+}
diff --git a/unix/zptracemips_linux.go b/unix/zptrace_mipsnn_linux.go
similarity index 93%
rename from unix/zptracemips_linux.go
rename to unix/zptrace_mipsnn_linux.go
index c431131..24b841e 100644
--- a/unix/zptracemips_linux.go
+++ b/unix/zptrace_mipsnn_linux.go
@@ -1,4 +1,4 @@
-// Code generated by linux/mkall.go generatePtracePair(mips, mips64). DO NOT EDIT.
+// Code generated by linux/mkall.go generatePtracePair("mips", "mips64"). DO NOT EDIT.
 
 // +build linux
 // +build mips mips64
diff --git a/unix/zptracemipsle_linux.go b/unix/zptrace_mipsnnle_linux.go
similarity index 93%
rename from unix/zptracemipsle_linux.go
rename to unix/zptrace_mipsnnle_linux.go
index dc3d6d3..47b0489 100644
--- a/unix/zptracemipsle_linux.go
+++ b/unix/zptrace_mipsnnle_linux.go
@@ -1,4 +1,4 @@
-// Code generated by linux/mkall.go generatePtracePair(mipsle, mips64le). DO NOT EDIT.
+// Code generated by linux/mkall.go generatePtracePair("mipsle", "mips64le"). DO NOT EDIT.
 
 // +build linux
 // +build mipsle mips64le
diff --git a/unix/zptrace386_linux.go b/unix/zptrace_x86_linux.go
similarity index 95%
rename from unix/zptrace386_linux.go
rename to unix/zptrace_x86_linux.go
index 2d21c49..ea5d9cb 100644
--- a/unix/zptrace386_linux.go
+++ b/unix/zptrace_x86_linux.go
@@ -1,4 +1,4 @@
-// Code generated by linux/mkall.go generatePtracePair(386, amd64). DO NOT EDIT.
+// Code generated by linux/mkall.go generatePtracePair("386", "amd64"). DO NOT EDIT.
 
 // +build linux
 // +build 386 amd64