git: ad0379660d0c - main - linux: make PTRACE_GETREGS return correct struct

From: Edward Tomasz Napierala <trasz_at_FreeBSD.org>
Date: Fri, 29 Oct 2021 16:34:40 UTC
The branch main has been updated by trasz:

URL: https://cgit.FreeBSD.org/src/commit/?id=ad0379660d0c77aaf0ca6ec19472b7bb173c5794

commit ad0379660d0c77aaf0ca6ec19472b7bb173c5794
Author:     Edward Tomasz Napierala <trasz@FreeBSD.org>
AuthorDate: 2021-10-29 15:18:13 +0000
Commit:     Edward Tomasz Napierala <trasz@FreeBSD.org>
CommitDate: 2021-10-29 15:18:28 +0000

    linux: make PTRACE_GETREGS return correct struct
    
    Previously it returned a shorter struct.  I can't find any
    modern software that uses it, but tests/ptrace from strace(1)
    repo complained.
    
    Differential Revision: https://reviews.freebsd.org/D32601
---
 sys/amd64/linux/linux_ptrace.c | 62 ++++++++++++------------------------------
 1 file changed, 18 insertions(+), 44 deletions(-)

diff --git a/sys/amd64/linux/linux_ptrace.c b/sys/amd64/linux/linux_ptrace.c
index 275450d63b2d..0f06f2aa9c5c 100644
--- a/sys/amd64/linux/linux_ptrace.c
+++ b/sys/amd64/linux/linux_ptrace.c
@@ -214,38 +214,6 @@ struct syscall_info {
 	};
 };
 
-/*
- * Translate amd64 ptrace registers between Linux and FreeBSD formats.
- * The translation is pretty straighforward, for all registers but
- * orig_rax on Linux side and r_trapno and r_err in FreeBSD.
- */
-static void
-map_regs_to_linux(struct reg *b_reg, struct linux_pt_reg *l_reg)
-{
-
-	l_reg->r15 = b_reg->r_r15;
-	l_reg->r14 = b_reg->r_r14;
-	l_reg->r13 = b_reg->r_r13;
-	l_reg->r12 = b_reg->r_r12;
-	l_reg->rbp = b_reg->r_rbp;
-	l_reg->rbx = b_reg->r_rbx;
-	l_reg->r11 = b_reg->r_r11;
-	l_reg->r10 = b_reg->r_r10;
-	l_reg->r9 = b_reg->r_r9;
-	l_reg->r8 = b_reg->r_r8;
-	l_reg->rax = b_reg->r_rax;
-	l_reg->rcx = b_reg->r_rcx;
-	l_reg->rdx = b_reg->r_rdx;
-	l_reg->rsi = b_reg->r_rsi;
-	l_reg->rdi = b_reg->r_rdi;
-	l_reg->orig_rax = b_reg->r_rax;
-	l_reg->rip = b_reg->r_rip;
-	l_reg->cs = b_reg->r_cs;
-	l_reg->eflags = b_reg->r_rflags;
-	l_reg->rsp = b_reg->r_rsp;
-	l_reg->ss = b_reg->r_ss;
-}
-
 static void
 map_regs_from_linux(struct reg *b_reg, struct linux_pt_reg *l_reg)
 {
@@ -434,14 +402,21 @@ linux_ptrace_getregs(struct thread *td, pid_t pid, void *data)
 {
 	struct ptrace_lwpinfo lwpinfo;
 	struct reg b_reg;
-	struct linux_pt_reg l_reg;
+	struct linux_pt_regset l_regset;
+	struct pcb *pcb;
 	int error;
 
 	error = kern_ptrace(td, PT_GETREGS, pid, &b_reg, 0);
 	if (error != 0)
 		return (error);
 
-	map_regs_to_linux(&b_reg, &l_reg);
+	pcb = td->td_pcb;
+	if (td == curthread)
+		update_pcb_bases(pcb);
+
+	bsd_to_linux_regset(&b_reg, &l_regset);
+	l_regset.fs_base = pcb->pcb_fsbase;
+	l_regset.gs_base = pcb->pcb_gsbase;
 
 	error = kern_ptrace(td, PT_LWPINFO, pid, &lwpinfo, sizeof(lwpinfo));
 	if (error != 0) {
@@ -450,21 +425,20 @@ linux_ptrace_getregs(struct thread *td, pid_t pid, void *data)
 	}
 	if (lwpinfo.pl_flags & PL_FLAG_SCE) {
 		/*
-		 * The strace(1) utility depends on RAX being set to -ENOSYS
-		 * on syscall entry; otherwise it loops printing those:
-		 *
-		 * [ Process PID=928 runs in 64 bit mode. ]
-		 * [ Process PID=928 runs in x32 mode. ]
+		 * Undo the mangling done in exception.S:fast_syscall_common().
 		 */
-		l_reg.rax = -38; /* -ENOSYS */
-
+		l_regset.r10 = l_regset.rcx;
+	}
+	if (lwpinfo.pl_flags & (PL_FLAG_SCE | PL_FLAG_SCX)) {
 		/*
-		 * Undo the mangling done in exception.S:fast_syscall_common().
+		 * In Linux, the syscall number - passed to the syscall
+		 * as rax - is preserved in orig_rax; rax gets overwritten
+		 * with syscall return value.
 		 */
-		l_reg.r10 = l_reg.rcx;
+		l_regset.orig_rax = lwpinfo.pl_syscall_code;
 	}
 
-	error = copyout(&l_reg, (void *)data, sizeof(l_reg));
+	error = copyout(&l_regset, (void *)data, sizeof(l_regset));
 	return (error);
 }