svn commit: r364503 - stable/12/sys/amd64/linux

Edward Tomasz Napierala trasz at FreeBSD.org
Sun Aug 23 19:19:01 UTC 2020


Author: trasz
Date: Sun Aug 23 19:19:00 2020
New Revision: 364503
URL: https://svnweb.freebsd.org/changeset/base/364503

Log:
  MFC r347231:
  
  Support PTRACE_GETREGSET w/ NT_PRSTATUS in Linux ptrace(2).
  
  While Linux strace(1) doesn't strictly require it - it has a fallback
  to PTRACE_GETREGS - it's a newer interface, so we better support it
  before the old one is deprecated.
  
  Sponsored by:	The FreeBSD Foundation

Modified:
  stable/12/sys/amd64/linux/linux_ptrace.c
Directory Properties:
  stable/12/   (props changed)

Modified: stable/12/sys/amd64/linux/linux_ptrace.c
==============================================================================
--- stable/12/sys/amd64/linux/linux_ptrace.c	Sun Aug 23 17:46:10 2020	(r364502)
+++ stable/12/sys/amd64/linux/linux_ptrace.c	Sun Aug 23 19:19:00 2020	(r364503)
@@ -131,6 +131,36 @@ struct linux_pt_reg {
 	l_ulong	ss;
 };
 
+struct linux_pt_regset {
+	l_ulong	r15;
+	l_ulong	r14;
+	l_ulong	r13;
+	l_ulong	r12;
+	l_ulong	rbp;
+	l_ulong	rbx;
+	l_ulong	r11;
+	l_ulong	r10;
+	l_ulong	r9;
+	l_ulong	r8;
+	l_ulong	rax;
+	l_ulong	rcx;
+	l_ulong	rdx;
+	l_ulong	rsi;
+	l_ulong	rdi;
+	l_ulong	orig_rax;
+	l_ulong	rip;
+	l_ulong	cs;
+	l_ulong	eflags;
+	l_ulong	rsp;
+	l_ulong	ss;
+	l_ulong fs_base;
+	l_ulong gs_base;
+	l_ulong ds;
+	l_ulong es;
+	l_ulong fs;
+	l_ulong gs;
+};
+
 /*
  * Translate amd64 ptrace registers between Linux and FreeBSD formats.
  * The translation is pretty straighforward, for all registers but
@@ -164,6 +194,40 @@ map_regs_to_linux(struct reg *b_reg, struct linux_pt_r
 }
 
 static void
+map_regs_to_linux_regset(struct reg *b_reg, unsigned long fs_base,
+    unsigned long gs_base, struct linux_pt_regset *l_regset)
+{
+
+	l_regset->r15 = b_reg->r_r15;
+	l_regset->r14 = b_reg->r_r14;
+	l_regset->r13 = b_reg->r_r13;
+	l_regset->r12 = b_reg->r_r12;
+	l_regset->rbp = b_reg->r_rbp;
+	l_regset->rbx = b_reg->r_rbx;
+	l_regset->r11 = b_reg->r_r11;
+	l_regset->r10 = b_reg->r_r10;
+	l_regset->r9 = b_reg->r_r9;
+	l_regset->r8 = b_reg->r_r8;
+	l_regset->rax = b_reg->r_rax;
+	l_regset->rcx = b_reg->r_rcx;
+	l_regset->rdx = b_reg->r_rdx;
+	l_regset->rsi = b_reg->r_rsi;
+	l_regset->rdi = b_reg->r_rdi;
+	l_regset->orig_rax = b_reg->r_rax;
+	l_regset->rip = b_reg->r_rip;
+	l_regset->cs = b_reg->r_cs;
+	l_regset->eflags = b_reg->r_rflags;
+	l_regset->rsp = b_reg->r_rsp;
+	l_regset->ss = b_reg->r_ss;
+	l_regset->fs_base = fs_base;
+	l_regset->gs_base = gs_base;
+	l_regset->ds = b_reg->r_ds;
+	l_regset->es = b_reg->r_es;
+	l_regset->fs = b_reg->r_fs;
+	l_regset->gs = b_reg->r_gs;
+}
+
+static void
 map_regs_from_linux(struct reg *b_reg, struct linux_pt_reg *l_reg)
 {
 	b_reg->r_r15 = l_reg->r15;
@@ -306,14 +370,75 @@ linux_ptrace_setregs(struct thread *td, pid_t pid, voi
 }
 
 static int
+linux_ptrace_getregset_prstatus(struct thread *td, pid_t pid, l_ulong data)
+{
+	struct ptrace_lwpinfo lwpinfo;
+	struct reg b_reg;
+	struct linux_pt_regset l_regset;
+	struct iovec iov;
+	struct pcb *pcb;
+	unsigned long fsbase, gsbase;
+	size_t len;
+	int error;
+
+	error = copyin((const void *)data, &iov, sizeof(iov));
+	if (error != 0) {
+		printf("%s: copyin error %d\n", __func__, error);
+		return (error);
+	}
+
+	error = kern_ptrace(td, PT_GETREGS, pid, &b_reg, 0);
+	if (error != 0)
+		return (error);
+
+	pcb = td->td_pcb;
+	if (td == curthread)
+		update_pcb_bases(pcb);
+	fsbase = pcb->pcb_fsbase;
+	gsbase = pcb->pcb_gsbase;
+
+	map_regs_to_linux_regset(&b_reg, fsbase, gsbase, &l_regset);
+
+	/*
+	 * 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. ]
+	 */
+	error = kern_ptrace(td, PT_LWPINFO, pid, &lwpinfo, sizeof(lwpinfo));
+	if (error != 0) {
+		printf("%s: PT_LWPINFO failed with error %d\n",
+		    __func__, error);
+		return (error);
+	}
+	if (lwpinfo.pl_flags & PL_FLAG_SCE)
+		l_regset.rax = -38; // XXX: Don't hardcode?
+
+	len = MIN(iov.iov_len, sizeof(l_regset));
+	error = copyout(&l_regset, (void *)iov.iov_base, len);
+	if (error != 0) {
+		printf("%s: copyout error %d\n", __func__, error);
+		return (error);
+	}
+
+	iov.iov_len -= len;
+	error = copyout(&iov, (void *)data, sizeof(iov));
+	if (error != 0) {
+		printf("%s: iov copyout error %d\n", __func__, error);
+		return (error);
+	}
+
+	return (error);
+}
+
+static int
 linux_ptrace_getregset(struct thread *td, pid_t pid, l_ulong addr, l_ulong data)
 {
 
 	switch (addr) {
 	case LINUX_NT_PRSTATUS:
-		printf("%s: NT_PRSTATUS not implemented; returning EINVAL\n",
-		    __func__);
-		return (EINVAL);
+		return (linux_ptrace_getregset_prstatus(td, pid, data));
 	default:
 		printf("%s: PTRACE_GETREGSET request %ld not implemented; "
 		    "returning EINVAL\n", __func__, addr);


More information about the svn-src-stable-12 mailing list