summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatrick Mooney <patrick.f.mooney@gmail.com>2015-06-26 21:55:23 +0000
committerPatrick Mooney <patrick.f.mooney@gmail.com>2015-08-31 20:41:36 +0000
commit9fb41d79bcf917137f62ea68254281fcfe2c9a50 (patch)
treef898c01fb38c847182b7e05331d49afe7e78eb22
parent6fb0bf827f03910897e781c837f13735d760bf48 (diff)
downloadillumos-joyent-9fb41d79bcf917137f62ea68254281fcfe2c9a50.tar.gz
OS-4458 lxbrand complete moving ptrace to IKE
OS-4038 lxbrand PTRACE_PEEKUSER debugregs offset incorrect on 64bit Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com> Reviewed by: Joshua M. Clulow <jmc@joyent.com>
-rw-r--r--usr/src/lib/brand/lx/lx_brand/amd64/Makefile11
-rw-r--r--usr/src/lib/brand/lx/lx_brand/amd64/offsets.in43
-rw-r--r--usr/src/lib/brand/lx/lx_brand/common/lx_brand.c6
-rw-r--r--usr/src/lib/brand/lx/lx_brand/common/ptrace.c786
-rw-r--r--usr/src/lib/brand/lx/lx_brand/i386/Makefile11
-rw-r--r--usr/src/lib/brand/lx/lx_brand/i386/offsets.in40
-rw-r--r--usr/src/uts/common/brand/lx/os/lx_brand.c3
-rw-r--r--usr/src/uts/common/brand/lx/os/lx_misc.c55
-rw-r--r--usr/src/uts/common/brand/lx/os/lx_ptrace.c254
-rw-r--r--usr/src/uts/common/brand/lx/os/lx_syscall.c4
-rw-r--r--usr/src/uts/common/brand/lx/sys/lx_brand.h149
-rw-r--r--usr/src/uts/common/brand/lx/sys/lx_misc.h10
-rw-r--r--usr/src/uts/common/brand/lx/sys/lx_syscalls.h1
-rw-r--r--usr/src/uts/intel/brand/lx/lx_archdep.c1445
14 files changed, 1184 insertions, 1634 deletions
diff --git a/usr/src/lib/brand/lx/lx_brand/amd64/Makefile b/usr/src/lib/brand/lx/lx_brand/amd64/Makefile
index 664cb8de56..a1db90cd38 100644
--- a/usr/src/lib/brand/lx/lx_brand/amd64/Makefile
+++ b/usr/src/lib/brand/lx/lx_brand/amd64/Makefile
@@ -12,7 +12,7 @@
#
# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
-# Copyright 2014 Joyent, Inc. All rights reserved.
+# Copyright 2015 Joyent, Inc.
#
#
# lib/brand/lx/amd64/Makefile
@@ -32,15 +32,6 @@ MSGFILES= $(CSRCS)
ASSYMDEP_OBJS = lx_handler.o
-$(ASSYMDEP_OBJS:%=pics/%): assym.h
-
-OFFSETS = ../$(MACH64)/offsets.in
-
-assym.h: $(OFFSETS)
- $(OFFSETS_CREATE) $(CTF_FLAGS) < $(OFFSETS) > $@
-
-CLOBBERFILES += assym.h
-
install: all $(ROOTLIBS64)
$(POFILE): $(MSGFILES)
diff --git a/usr/src/lib/brand/lx/lx_brand/amd64/offsets.in b/usr/src/lib/brand/lx/lx_brand/amd64/offsets.in
deleted file mode 100644
index 207063a886..0000000000
--- a/usr/src/lib/brand/lx/lx_brand/amd64/offsets.in
+++ /dev/null
@@ -1,43 +0,0 @@
-\
-\ This file and its contents are supplied under the terms of the
-\ Common Development and Distribution License ("CDDL"), version 1.0.
-\ You may only use this file in accordance with the terms of version
-\ 1.0 of the CDDL.
-\
-\ A full copy of the text of the CDDL should have accompanied this
-\ source. A copy of the CDDL is also available via the Internet at
-\ http://www.illumos.org/license/CDDL.
-\
-\ Copyright 2014 Joyent, Inc. All rights reserved.
-\
-
-#include <sys/lx_brand.h>
-#include <sys/lx_sigstack.h>
-
-lx_regs_t SIZEOF_LX_REGS_T
- lxr_fs
- lxr_rdi
- lxr_rsi
- lxr_rbp
- lxr_rsp
- lxr_rbx
- lxr_rdx
- lxr_rcx
- lxr_rax
- lxr_r8
- lxr_r9
- lxr_r10
- lxr_r11
- lxr_r12
- lxr_r13
- lxr_r14
- lxr_r15
- lxr_rip
- lxr_orig_rax
-
-lx_sigstack_t SIZEOF_LX_SIGSTACK_T
- retaddr
- si
- uc
- fpstate
- pad
diff --git a/usr/src/lib/brand/lx/lx_brand/common/lx_brand.c b/usr/src/lib/brand/lx/lx_brand/common/lx_brand.c
index 63bc766eea..dafbe9c862 100644
--- a/usr/src/lib/brand/lx/lx_brand/common/lx_brand.c
+++ b/usr/src/lib/brand/lx/lx_brand/common/lx_brand.c
@@ -663,8 +663,6 @@ lx_init(int argc, char *argv[], char *envp[])
if (lx_statfs_init() != 0)
lx_err_fatal("failed to setup the statfs translator");
- lx_ptrace_init();
-
#if defined(_LP64)
vdso_hdr = map_vdso();
edp.ed_vdso = (uintptr_t)vdso_hdr;
@@ -1031,7 +1029,7 @@ static lx_syscall_handler_t lx_handlers[] = {
lx_getrusage, /* 98: getrusage */
NULL, /* 99: sysinfo */
lx_times, /* 100: times */
- lx_ptrace, /* 101: ptrace */
+ NULL, /* 101: ptrace */
lx_getuid, /* 102: getuid */
lx_syslog, /* 103: syslog */
lx_getgid, /* 104: getgid */
@@ -1287,7 +1285,7 @@ static lx_syscall_handler_t lx_handlers[] = {
lx_setuid16, /* 23: setuid16 */
lx_getuid16, /* 24: getuid16 */
lx_stime, /* 25: stime */
- lx_ptrace, /* 26: ptrace */
+ NULL, /* 26: ptrace */
lx_alarm, /* 27: alarm */
NULL, /* 28: fstat */
lx_pause, /* 29: pause */
diff --git a/usr/src/lib/brand/lx/lx_brand/common/ptrace.c b/usr/src/lib/brand/lx/lx_brand/common/ptrace.c
index 8680563c26..bb6e52a112 100644
--- a/usr/src/lib/brand/lx/lx_brand/common/ptrace.c
+++ b/usr/src/lib/brand/lx/lx_brand/common/ptrace.c
@@ -59,682 +59,6 @@
* detail.
*/
-/*
- * This corresponds to the user_i387_struct Linux structure.
- */
-typedef struct lx_user_fpregs {
- long lxuf_cwd;
- long lxuf_swd;
- long lxuf_twd;
- long lxuf_fip;
- long lxuf_fcs;
- long lxuf_foo;
- long lxuf_fos;
- long lxuf_st_space[20];
-} lx_user_fpregs_t;
-
-/*
- * This corresponds to the user_fxsr_struct Linux structure.
- */
-typedef struct lx_user_fpxregs {
- uint16_t lxux_cwd;
- uint16_t lxux_swd;
- uint16_t lxux_twd;
- uint16_t lxux_fop;
- long lxux_fip;
- long lxux_fcs;
- long lxux_foo;
- long lxux_fos;
- long lxux_mxcsr;
- long lxux_reserved;
- long lxux_st_space[32];
- long lxux_xmm_space[32];
- long lxux_padding[56];
-} lx_user_fpxregs_t;
-
-typedef struct lx_user {
- lx_user_regs_t lxu_regs;
- int lxu_fpvalid;
- lx_user_fpregs_t lxu_i387;
- ulong_t lxu_tsize;
- ulong_t lxu_dsize;
- ulong_t lxu_ssize;
- ulong_t lxu_start_code;
- ulong_t lxu_start_stack;
- long lxu_signal;
- int lxu_reserved;
- lx_user_regs_t *lxu_ar0;
- lx_user_fpregs_t *lxu_fpstate;
- ulong_t lxu_magic;
- char lxu_comm[32];
- int lxu_debugreg[8];
-} lx_user_t;
-
-typedef struct ptrace_state_map {
- struct ptrace_state_map *psm_next; /* next pointer */
- pid_t psm_pid; /* Solaris pid */
- uintptr_t psm_debugreg[8]; /* debug registers */
-} ptrace_state_map_t;
-
-static ptrace_state_map_t *ptrace_state_map = NULL;
-static mutex_t ptrace_map_mtx = DEFAULTMUTEX;
-
-extern void *_START_;
-
-static sigset_t blockable_sigs;
-
-static long lx_ptrace_kernel(int, pid_t, uintptr_t, uintptr_t);
-
-void
-lx_ptrace_init(void)
-{
- (void) sigfillset(&blockable_sigs);
- (void) sigdelset(&blockable_sigs, SIGKILL);
- (void) sigdelset(&blockable_sigs, SIGSTOP);
-}
-
-/*
- * Given a pid, open the named file under /native/proc/<pid>/name using the
- * given mode.
- */
-static int
-open_procfile(pid_t pid, int mode, const char *name)
-{
- char path[MAXPATHLEN];
-
- (void) snprintf(path, sizeof (path), "/native/proc/%d/%s", pid, name);
-
- return (open(path, mode));
-}
-
-/*
- * Given a pid and lwpid, open the named file under
- * /native/proc/<pid>/<lwpid>/name using the given mode.
- */
-static int
-open_lwpfile(pid_t pid, lwpid_t lwpid, int mode, const char *name)
-{
- char path[MAXPATHLEN];
-
- (void) snprintf(path, sizeof (path), "/native/proc/%d/lwp/%d/%s",
- pid, lwpid, name);
-
- return (open(path, mode));
-}
-
-static int
-get_lwpstatus(pid_t pid, lwpid_t lwpid, lwpstatus_t *lsp)
-{
- int fd;
-
- if ((fd = open_lwpfile(pid, lwpid, O_RDONLY, "lwpstatus")) < 0)
- return (-ESRCH);
-
- if (read(fd, lsp, sizeof (lwpstatus_t)) != sizeof (lwpstatus_t)) {
- (void) close(fd);
- return (-EIO);
- }
-
- (void) close(fd);
-
- return (0);
-}
-
-static int
-getfpregs(pid_t pid, lwpid_t lwpid, lx_user_fpregs_t *rp)
-{
- lwpstatus_t status;
- struct _fpstate *fp;
-#if defined(_ILP32)
- char *data;
- int i;
-#endif
- int ret;
-
- if ((ret = get_lwpstatus(pid, lwpid, &status)) != 0)
- return (ret);
-
- fp = (struct _fpstate *)&status.pr_fpreg.fp_reg_set.fpchip_state;
-
-#if defined(_ILP32)
- rp->lxuf_cwd = fp->cw;
- rp->lxuf_swd = fp->sw;
- rp->lxuf_twd = fp->tag;
- rp->lxuf_fip = fp->ipoff;
- rp->lxuf_fcs = fp->cssel;
- rp->lxuf_foo = fp->dataoff;
- rp->lxuf_fos = fp->datasel;
-
- /*
- * The Linux structure uses 10 bytes per floating-point register.
- */
- data = (char *)&rp->lxuf_st_space[0];
- for (i = 0; i < 8; i++) {
- bcopy(&fp->_st[i], data, 10);
- data += 10;
- }
-#endif
-
- return (0);
-}
-
-static int
-setfpregs(pid_t pid, lwpid_t lwpid, const lx_user_fpregs_t *rp)
-{
- lwpstatus_t status;
- struct {
- long cmd;
- prfpregset_t regs;
- } ctl;
-#if defined(_ILP32)
- struct _fpstate *fp = (struct _fpstate *)&ctl.regs;
- char *data;
- int i;
-#endif
- int ret, fd;
-
- if ((ret = get_lwpstatus(pid, lwpid, &status)) != 0)
- return (ret);
-
- bcopy(&status.pr_fpreg, &ctl.regs, sizeof (ctl.regs));
-
-#if defined(_ILP32)
- fp->cw = rp->lxuf_cwd;
- fp->sw = rp->lxuf_swd;
- fp->tag = rp->lxuf_twd;
- fp->ipoff = rp->lxuf_fip;
- fp->cssel = rp->lxuf_fcs;
- fp->dataoff = rp->lxuf_foo;
- fp->datasel = rp->lxuf_fos;
-
- /*
- * The Linux structure uses 10 bytes per floating-point register.
- */
- data = (char *)&rp->lxuf_st_space[0];
- for (i = 0; i < 8; i++) {
- bcopy(data, &fp->_st[i], 10);
- data += 10;
- }
-#endif
-
- if ((fd = open_lwpfile(pid, lwpid, O_WRONLY, "lwpctl")) < 0)
- return (-ESRCH);
-
- ctl.cmd = PCSFPREG;
- if (write(fd, &ctl, sizeof (ctl)) != sizeof (ctl)) {
- (void) close(fd);
- return (-EIO);
- }
-
- (void) close(fd);
-
- return (0);
-}
-
-
-static int
-getfpxregs(pid_t pid, lwpid_t lwpid, lx_user_fpxregs_t *rp)
-{
-#if defined(_ILP32)
- lwpstatus_t status;
- struct _fpstate *fp;
- int ret, i;
-
- if ((ret = get_lwpstatus(pid, lwpid, &status)) != 0)
- return (ret);
-
- fp = (struct _fpstate *)&status.pr_fpreg.fp_reg_set.fpchip_state;
-
- rp->lxux_cwd = (uint16_t)fp->cw;
- rp->lxux_swd = (uint16_t)fp->sw;
- rp->lxux_twd = (uint16_t)fp->tag;
- rp->lxux_fop = (uint16_t)(fp->cssel >> 16);
- rp->lxux_fip = fp->ipoff;
- rp->lxux_fcs = (uint16_t)fp->cssel;
- rp->lxux_foo = fp->dataoff;
- rp->lxux_fos = fp->datasel;
- rp->lxux_mxcsr = status.pr_fpreg.fp_reg_set.fpchip_state.mxcsr;
-
- bcopy(fp->xmm, rp->lxux_xmm_space, sizeof (rp->lxux_xmm_space));
- bzero(rp->lxux_st_space, sizeof (rp->lxux_st_space));
- for (i = 0; i < 8; i++) {
- bcopy(&fp->_st[i], &rp->lxux_st_space[i * 4],
- sizeof (fp->_st[i]));
- }
-#endif
-
- return (0);
-}
-
-static int
-setfpxregs(pid_t pid, lwpid_t lwpid, const lx_user_fpxregs_t *rp)
-{
-#if defined(_ILP32)
- lwpstatus_t status;
- struct {
- long cmd;
- prfpregset_t regs;
- } ctl;
- struct _fpstate *fp = (struct _fpstate *)&ctl.regs;
- int ret, i, fd;
-
- if ((ret = get_lwpstatus(pid, lwpid, &status)) != 0)
- return (ret);
-
- bcopy(&status.pr_fpreg, &ctl.regs, sizeof (ctl.regs));
-
- fp->cw = rp->lxux_cwd;
- fp->sw = rp->lxux_swd;
- fp->tag = rp->lxux_twd;
- fp->ipoff = rp->lxux_fip;
- fp->cssel = rp->lxux_fcs | (rp->lxux_fop << 16);
- fp->dataoff = rp->lxux_foo;
- fp->datasel = rp->lxux_fos;
-
- bcopy(rp->lxux_xmm_space, fp->xmm, sizeof (rp->lxux_xmm_space));
- for (i = 0; i < 8; i++) {
- bcopy(&rp->lxux_st_space[i * 4], &fp->_st[i],
- sizeof (fp->_st[i]));
- }
-
- if ((fd = open_lwpfile(pid, lwpid, O_WRONLY, "lwpctl")) < 0)
- return (-ESRCH);
-
- ctl.cmd = PCSFPREG;
- if (write(fd, &ctl, sizeof (ctl)) != sizeof (ctl)) {
- (void) close(fd);
- return (-EIO);
- }
-
- (void) close(fd);
-#endif
-
- return (0);
-}
-
-/*
- * Solaris does not allow a process to manipulate its own or some
- * other process's debug registers. Linux ptrace(2) allows this
- * and gdb manipulates them for its watchpoint implementation.
- *
- * We keep a pseudo set of debug registers for each traced process
- * and map their contents into the appropriate PCWATCH /proc
- * operations when they are activated by gdb.
- *
- * To understand how the debug registers work on x86 machines,
- * see section 13.1 of the AMD x86-64 Architecture Programmer's
- * Manual, Volume 2, System Programming.
- */
-static uintptr_t *
-debug_registers(pid_t pid)
-{
- ptrace_state_map_t *p;
-
- (void) mutex_lock(&ptrace_map_mtx);
- for (p = ptrace_state_map; p != NULL; p = p->psm_next) {
- if (p->psm_pid == pid)
- break;
- }
- if (p == NULL && (p = malloc(sizeof (*p))) != NULL) {
- bzero(p, sizeof (*p));
- p->psm_pid = pid;
- p->psm_next = ptrace_state_map;
- p->psm_debugreg[6] = 0xffff0ff0; /* read as ones */
- ptrace_state_map = p;
- }
- (void) mutex_unlock(&ptrace_map_mtx);
- return (p != NULL? p->psm_debugreg : NULL);
-}
-
-static int
-setup_watchpoints(pid_t pid, uintptr_t *debugreg)
-{
- int dr7 = debugreg[7];
- int lrw;
- int fd;
- size_t size = NULL;
- prwatch_t prwatch[4];
- int nwatch;
- int i;
- int wflags = NULL;
- int error;
- struct {
- long req;
- prwatch_t prwatch;
- } ctl;
-
- /* find all watched areas */
- if ((fd = open_procfile(pid, O_RDONLY, "watch")) < 0)
- return (-ESRCH);
- nwatch = read(fd, prwatch, sizeof (prwatch)) / sizeof (prwatch_t);
- (void) close(fd);
- if ((fd = open_procfile(pid, O_WRONLY, "ctl")) < 0)
- return (-ESRCH);
- /* clear all watched areas */
- for (i = 0; i < nwatch; i++) {
- ctl.req = PCWATCH;
- ctl.prwatch = prwatch[i];
- ctl.prwatch.pr_wflags = 0;
- if (write(fd, &ctl, sizeof (ctl)) != sizeof (ctl)) {
- error = -errno;
- (void) close(fd);
- return (error);
- }
- }
- /* establish all new watched areas */
- for (i = 0; i < 4; i++) {
- if ((dr7 & (1 << (2 * i))) == 0) /* enabled? */
- continue;
- lrw = (dr7 >> (16 + (4 * i))) & 0xf;
- switch (lrw >> 2) { /* length */
- case 0: size = 1; break;
- case 1: size = 2; break;
- case 2: size = 8; break;
- case 3: size = 4; break;
- }
- switch (lrw & 0x3) { /* mode */
- case 0: wflags = WA_EXEC; break;
- case 1: wflags = WA_WRITE; break;
- case 2: continue;
- case 3: wflags = WA_READ | WA_WRITE; break;
- }
- ctl.req = PCWATCH;
- ctl.prwatch.pr_vaddr = debugreg[i];
- ctl.prwatch.pr_size = size;
- ctl.prwatch.pr_wflags = wflags | WA_TRAPAFTER;
- if (write(fd, &ctl, sizeof (ctl)) != sizeof (ctl)) {
- error = -errno;
- (void) close(fd);
- return (error);
- }
- }
- (void) close(fd);
- return (0);
-}
-
-/*
- * Returns B_TRUE if the target LWP, identified by its Linux pid, is traced by
- * this LWP and is waiting in "ptrace-stop". Returns B_FALSE otherwise.
- */
-static boolean_t
-is_ptrace_stopped(pid_t lxpid)
-{
- ulong_t dummy;
-
- /*
- * We attempt a PTRACE_GETEVENTMSG request to determine if the tracee
- * is stopped appropriately. As we are not in the kernel, this is not
- * an atomic check; the process is not guaranteed to remain stopped
- * once we have dropped the locks protecting that state and left the
- * kernel.
- */
- if (lx_ptrace_kernel(LX_PTRACE_GETEVENTMSG, lxpid, NULL,
- (uintptr_t)&dummy) == 0) {
- return (B_TRUE);
- }
-
- /*
- * This call should only fail with ESRCH, which tells us that the
- * a tracee with that pid was not found in the stopped condition.
- */
- assert(errno == ESRCH);
-
- return (B_FALSE);
-}
-
-/*
- * Read a word of data from the given address. Because this is a process-wide
- * action, we don't need the lwpid.
- */
-static long
-ptrace_peek(pid_t pid, uintptr_t addr, long *ret)
-{
- int fd;
- long data;
-
- if ((fd = open_procfile(pid, O_RDONLY, "as")) < 0)
- return (-ESRCH);
-
- if (pread(fd, &data, sizeof (data), addr) != sizeof (data)) {
- (void) close(fd);
- return (-EIO);
- }
-
- (void) close(fd);
-
- if (uucopy(&data, ret, sizeof (data)) != 0)
- return (-errno);
-
- return (0);
-}
-
-#define LX_USER_BOUND(m) \
-(offsetof(lx_user_t, m) + sizeof (((lx_user_t *)NULL)->m))
-
-static int
-ptrace_peek_user(pid_t lxpid, pid_t pid, lwpid_t lwpid, uintptr_t off, int *ret)
-{
- int err;
- long data;
- uintptr_t *debugreg;
- int dreg;
-
- /*
- * The offset specified by the user is an offset into the Linux
- * user structure (seriously). Rather than constructing a full
- * user structure, we figure out which part of the user structure
- * the offset is in, and fill in just that component.
- */
- if (off < LX_USER_BOUND(lxu_regs)) {
- lx_user_regs_t regs;
-
- if ((err = lx_ptrace_kernel(LX_PTRACE_GETREGS, lxpid, NULL,
- (uintptr_t)&regs)) != 0) {
- return (err);
- }
-
- data = *(long *)((uintptr_t)&regs + off -
- offsetof(lx_user_t, lxu_regs));
-
- } else if (off < LX_USER_BOUND(lxu_fpvalid)) {
- lx_err("offset = %lu\n", off);
- assert(0);
- } else if (off < LX_USER_BOUND(lxu_i387)) {
- lx_user_fpregs_t regs;
-
- if ((err = getfpregs(pid, lwpid, &regs)) != 0)
- return (err);
-
- data = *(long *)((uintptr_t)&regs + off -
- offsetof(lx_user_t, lxu_i387));
-
- } else if (off < LX_USER_BOUND(lxu_tsize)) {
- lx_err("offset = %lu\n", off);
- assert(0);
- } else if (off < LX_USER_BOUND(lxu_dsize)) {
- lx_err("offset = %lu\n", off);
- assert(0);
- } else if (off < LX_USER_BOUND(lxu_ssize)) {
- lx_err("offset = %lu\n", off);
- assert(0);
- } else if (off < LX_USER_BOUND(lxu_start_code)) {
- lx_err("offset = %lu\n", off);
- assert(0);
- } else if (off < LX_USER_BOUND(lxu_start_stack)) {
- lx_err("offset = %lu\n", off);
- assert(0);
- } else if (off < LX_USER_BOUND(lxu_signal)) {
- lx_err("offset = %lu\n", off);
- assert(0);
- } else if (off < LX_USER_BOUND(lxu_reserved)) {
- lx_err("offset = %lu\n", off);
- assert(0);
- } else if (off < LX_USER_BOUND(lxu_ar0)) {
- lx_err("offset = %lu\n", off);
- assert(0);
- } else if (off < LX_USER_BOUND(lxu_fpstate)) {
- lx_err("offset = %lu\n", off);
- assert(0);
- } else if (off < LX_USER_BOUND(lxu_magic)) {
- lx_err("offset = %lu\n", off);
- assert(0);
- } else if (off < LX_USER_BOUND(lxu_comm)) {
- lx_err("offset = %lu\n", off);
- assert(0);
- } else if (off < LX_USER_BOUND(lxu_debugreg)) {
- dreg = (off - offsetof(lx_user_t, lxu_debugreg)) / sizeof (int);
- if (dreg == 4) /* aliased */
- dreg = 6;
- else if (dreg == 5) /* aliased */
- dreg = 7;
- if ((debugreg = debug_registers(pid)) != NULL)
- data = debugreg[dreg];
- else
- data = 0;
- } else {
- lx_unsupported("unsupported ptrace peek user offset: 0x%x\n",
- off);
- assert(0);
- return (-ENOTSUP);
- }
-
- if (uucopy(&data, ret, sizeof (data)) != 0)
- return (-errno);
-
- return (0);
-}
-
-/*
- * Write a word of data to the given address. Because this is a process-wide
- * action, we don't need the lwpid. Returns EINVAL if the address is not
- * word-aligned.
- */
-static int
-ptrace_poke(pid_t pid, uintptr_t addr, int data)
-{
- int fd;
-
- if (addr & 0x3)
- return (-EINVAL);
-
- if ((fd = open_procfile(pid, O_WRONLY, "as")) < 0)
- return (-ESRCH);
-
- if (pwrite(fd, &data, sizeof (data), addr) != sizeof (data)) {
- (void) close(fd);
- return (-EIO);
- }
-
- (void) close(fd);
- return (0);
-}
-
-static int
-ptrace_poke_user(pid_t lxpid, pid_t pid, lwpid_t lwpid,
- uintptr_t off, long data)
-{
- lx_user_regs_t regs;
- int err = 0;
- uintptr_t *debugreg;
- int dreg;
-
- if (off & 0x3)
- return (-EINVAL);
-
- if (off < offsetof(lx_user_t, lxu_regs) + sizeof (lx_user_regs_t)) {
- if ((err = lx_ptrace_kernel(LX_PTRACE_GETREGS, lxpid, NULL,
- (uintptr_t)&regs)) != 0) {
- return (err);
- }
-
- *(long *)((uintptr_t)&regs + off -
- offsetof(lx_user_t, lxu_regs)) = data;
-
- return (lx_ptrace_kernel(LX_PTRACE_SETREGS, lxpid, NULL,
- (uintptr_t)&regs));
- }
-
- if (off >= offsetof(lx_user_t, lxu_debugreg) &&
- off < offsetof(lx_user_t, lxu_debugreg) + 8 * sizeof (int)) {
- dreg = (off - offsetof(lx_user_t, lxu_debugreg)) / sizeof (int);
- if (dreg == 4) /* aliased */
- dreg = 6;
- else if (dreg == 5) /* aliased */
- dreg = 7;
- if ((debugreg = debug_registers(pid)) != NULL) {
- debugreg[dreg] = data;
- if (dreg == 7)
- err = setup_watchpoints(pid, debugreg);
- }
- return (err);
- }
-
- lx_unsupported("unsupported ptrace poke user offset: 0x%x\n", off);
- assert(0);
- return (-ENOTSUP);
-}
-
-static int
-ptrace_kill(pid_t pid)
-{
- int ret;
-
- ret = kill(pid, SIGKILL);
-
- return (ret == 0 ? ret : -errno);
-}
-
-static int
-ptrace_getfpregs(pid_t pid, lwpid_t lwpid, uintptr_t addr)
-{
- lx_user_fpregs_t regs;
- int ret;
-
- if ((ret = getfpregs(pid, lwpid, &regs)) != 0)
- return (ret);
-
- if (uucopy(&regs, (void *)addr, sizeof (regs)) != 0)
- return (-errno);
-
- return (0);
-}
-
-static int
-ptrace_setfpregs(pid_t pid, lwpid_t lwpid, uintptr_t addr)
-{
- lx_user_fpregs_t regs;
-
- if (uucopy((void *)addr, &regs, sizeof (regs)) != 0)
- return (-errno);
-
- return (setfpregs(pid, lwpid, &regs));
-}
-
-static int
-ptrace_getfpxregs(pid_t pid, lwpid_t lwpid, uintptr_t addr)
-{
- lx_user_fpxregs_t regs;
- int ret;
-
- if ((ret = getfpxregs(pid, lwpid, &regs)) != 0)
- return (ret);
-
- if (uucopy(&regs, (void *)addr, sizeof (regs)) != 0)
- return (-errno);
-
- return (0);
-}
-
-static int
-ptrace_setfpxregs(pid_t pid, lwpid_t lwpid, uintptr_t addr)
-{
- lx_user_fpxregs_t regs;
-
- if (uucopy((void *)addr, &regs, sizeof (regs)) != 0)
- return (-errno);
-
- return (setfpxregs(pid, lwpid, &regs));
-}
void
lx_ptrace_stop_if_option(int option, boolean_t child, ulong_t msg,
@@ -779,113 +103,3 @@ lx_ptrace_clone_begin(int option, boolean_t inherit_flag)
strerror(errno));
}
}
-
-static long
-lx_ptrace_kernel(int ptrace_op, pid_t lxpid, uintptr_t addr, uintptr_t data)
-{
- int ret;
-
- /*
- * Call into the in-kernel ptrace(2) emulation code.
- */
- lx_debug("revectoring to B_PTRACE_KERNEL(%d, %d, %p, %p)", ptrace_op,
- lxpid, addr, data);
- ret = syscall(SYS_brand, B_PTRACE_KERNEL, ptrace_op, lxpid, addr,
- data);
- if (ret == 0) {
- lx_debug("\t= %d", ret);
- } else {
- lx_debug("\t= %d (%s)", ret, strerror(errno));
- }
-
- return (ret == 0 ? ret : -errno);
-}
-
-long
-lx_ptrace(uintptr_t p1, uintptr_t p2, uintptr_t p3, uintptr_t p4)
-{
- int ptrace_op = (int)p1;
- pid_t pid, lxpid = (pid_t)p2;
- lwpid_t lwpid;
-
- /*
- * Some PTRACE_* requests are emulated entirely in the kernel.
- */
- switch (ptrace_op) {
- /*
- * PTRACE_TRACEME and PTRACE_ATTACH operations induce the tracing of
- * one LWP by another. The target LWP must not be traced already.
- * Both `data' and `addr' are ignored in both cases.
- */
- case LX_PTRACE_TRACEME:
- return (lx_ptrace_kernel(ptrace_op, 0, 0, 0));
-
- case LX_PTRACE_ATTACH:
- return (lx_ptrace_kernel(ptrace_op, lxpid, 0, 0));
-
- /*
- * PTRACE_DETACH, PTRACE_SYSCALL, PTRACE_SINGLESTEP and PTRACE_CONT
- * are all restarting actions. They are only allowed when attached
- * to the target LWP and when that target LWP is in a "ptrace-stop"
- * condition.
- */
- case LX_PTRACE_DETACH:
- case LX_PTRACE_SYSCALL:
- case LX_PTRACE_CONT:
- case LX_PTRACE_SINGLESTEP:
- /*
- * These actions also require the LWP to be traced and stopped, but do
- * not restart the target LWP.
- */
- case LX_PTRACE_SETOPTIONS:
- case LX_PTRACE_GETEVENTMSG:
- case LX_PTRACE_GETSIGINFO:
- case LX_PTRACE_GETREGS:
- case LX_PTRACE_SETREGS:
- return (lx_ptrace_kernel(ptrace_op, lxpid, p3, p4));
- }
-
- /*
- * The rest of the emulated PTRACE_* actions are emulated in userland.
- * They require the target LWP to be traced and in currently
- * "ptrace-stop", but do not subsequently restart the target LWP.
- */
- if (lx_lpid_to_spair(lxpid, &pid, &lwpid) < 0 ||
- !is_ptrace_stopped(lxpid)) {
- return (-ESRCH);
- }
-
- switch (ptrace_op) {
- case LX_PTRACE_PEEKTEXT:
- case LX_PTRACE_PEEKDATA:
- return (ptrace_peek(pid, p3, (long *)p4));
-
- case LX_PTRACE_PEEKUSER:
- return (ptrace_peek_user(lxpid, pid, lwpid, p3, (int *)p4));
-
- case LX_PTRACE_POKETEXT:
- case LX_PTRACE_POKEDATA:
- return (ptrace_poke(pid, p3, (int)p4));
-
- case LX_PTRACE_POKEUSER:
- return (ptrace_poke_user(lxpid, pid, lwpid, p3, (long)p4));
-
- case LX_PTRACE_KILL:
- return (ptrace_kill(pid));
-
- case LX_PTRACE_GETFPREGS:
- return (ptrace_getfpregs(pid, lwpid, p4));
-
- case LX_PTRACE_SETFPREGS:
- return (ptrace_setfpregs(pid, lwpid, p4));
-
- case LX_PTRACE_GETFPXREGS:
- return (ptrace_getfpxregs(pid, lwpid, p4));
-
- case LX_PTRACE_SETFPXREGS:
- return (ptrace_setfpxregs(pid, lwpid, p4));
-
- default:
- return (-EINVAL);
- }
-}
diff --git a/usr/src/lib/brand/lx/lx_brand/i386/Makefile b/usr/src/lib/brand/lx/lx_brand/i386/Makefile
index e9546dee4a..8723f64292 100644
--- a/usr/src/lib/brand/lx/lx_brand/i386/Makefile
+++ b/usr/src/lib/brand/lx/lx_brand/i386/Makefile
@@ -21,7 +21,7 @@
#
# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
-# Copyright 2014 Joyent, Inc. All rights reserved.
+# Copyright 2015 Joyent, Inc.
#
# lib/brand/lx/i386/Makefile
@@ -38,15 +38,6 @@ MSGFILES= $(CSRCS)
ASSYMDEP_OBJS = lx_handler.o
-$(ASSYMDEP_OBJS:%=pics/%): assym.h
-
-OFFSETS = ../$(MACH)/offsets.in
-
-assym.h: $(OFFSETS)
- $(OFFSETS_CREATE) $(CTF_FLAGS) < $(OFFSETS) > $@
-
-CLOBBERFILES += assym.h
-
install: all $(ROOTLIBS)
$(POFILE): $(MSGFILES)
diff --git a/usr/src/lib/brand/lx/lx_brand/i386/offsets.in b/usr/src/lib/brand/lx/lx_brand/i386/offsets.in
deleted file mode 100644
index ac934ee76c..0000000000
--- a/usr/src/lib/brand/lx/lx_brand/i386/offsets.in
+++ /dev/null
@@ -1,40 +0,0 @@
-\
-\ Copyright 2006 Sun Microsystems, Inc. All rights reserved.
-\ Use is subject to license terms.
-\
-\ CDDL HEADER START
-\
-\ The contents of this file are subject to the terms of the
-\ Common Development and Distribution License (the "License").
-\ You may not use this file except in compliance with the License.
-\
-\ You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
-\ or http://www.opensolaris.org/os/licensing.
-\ See the License for the specific language governing permissions
-\ and limitations under the License.
-\
-\ When distributing Covered Code, include this CDDL HEADER in each
-\ file and include the License file at usr/src/OPENSOLARIS.LICENSE.
-\ If applicable, add the following below this CDDL HEADER, with the
-\ fields enclosed by brackets "[]" replaced with your own identifying
-\ information: Portions Copyright [yyyy] [name of copyright owner]
-\
-\ CDDL HEADER END
-\
-
-#pragma ident "%Z%%M% %I% %E% SMI"
-
-#include <sys/lx_brand.h>
-
-lx_regs_t SIZEOF_LX_REGS_T
- lxr_gs
- lxr_edi
- lxr_esi
- lxr_ebp
- lxr_esp
- lxr_ebx
- lxr_edx
- lxr_ecx
- lxr_eax
- lxr_eip
- lxr_orig_eax
diff --git a/usr/src/uts/common/brand/lx/os/lx_brand.c b/usr/src/uts/common/brand/lx/os/lx_brand.c
index 2f3ede8287..05146886c4 100644
--- a/usr/src/uts/common/brand/lx/os/lx_brand.c
+++ b/usr/src/uts/common/brand/lx/os/lx_brand.c
@@ -1138,9 +1138,6 @@ lx_brandsys(int cmd, int64_t *rval, uintptr_t arg1, uintptr_t arg2,
return (lx_ptrace_set_clone_inherit((int)arg1, arg2 == 0 ?
B_FALSE : B_TRUE));
- case B_PTRACE_KERNEL:
- return (lx_ptrace_kernel((int)arg1, (pid_t)arg2, arg3, arg4));
-
case B_HELPER_WAITID: {
idtype_t idtype = (idtype_t)arg1;
id_t id = (id_t)arg2;
diff --git a/usr/src/uts/common/brand/lx/os/lx_misc.c b/usr/src/uts/common/brand/lx/os/lx_misc.c
index 848370bc3c..c81a1f143e 100644
--- a/usr/src/uts/common/brand/lx/os/lx_misc.c
+++ b/usr/src/uts/common/brand/lx/os/lx_misc.c
@@ -48,6 +48,7 @@
#include <lx_signum.h>
#include <lx_syscall.h>
#include <sys/proc.h>
+#include <sys/procfs.h>
#include <net/if.h>
#include <sys/sunddi.h>
#include <sys/dlpi.h>
@@ -1011,3 +1012,57 @@ lx_read_argv_bounds(proc_t *p)
pd->l_envs_start = env_start;
pd->l_envs_end = env_end;
}
+
+/* Given an LX LWP, determine where user register state is stored. */
+lx_regs_location_t
+lx_regs_location(lx_lwp_data_t *lwpd, void **ucp, boolean_t for_write)
+{
+ switch (lwpd->br_stack_mode) {
+ case LX_STACK_MODE_BRAND:
+ /*
+ * The LWP was stopped with the brand stack and register state
+ * loaded, e.g. during a syscall emulated within the kernel.
+ */
+ return (LX_REG_LOC_LWP);
+
+ case LX_STACK_MODE_PREINIT:
+ if (for_write) {
+ /* setting registers not allowed in this state */
+ break;
+ }
+ if (lwpd->br_ptrace_whatstop == LX_PR_SIGNALLED ||
+ lwpd->br_ptrace_whatstop == LX_PR_SYSEXIT) {
+ /* The LWP was stopped by tracing on exec. */
+ return (LX_REG_LOC_LWP);
+ }
+ break;
+
+ case LX_STACK_MODE_NATIVE:
+ if (for_write) {
+ /* setting registers not allowed in this state */
+ break;
+ }
+ if (lwpd->br_ptrace_whystop == PR_BRAND &&
+ lwpd->br_ptrace_whatstop == LX_PR_EVENT) {
+ /* Called while ptrace-event-stopped by lx_exec. */
+ return (LX_REG_LOC_LWP);
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (lwpd->br_ptrace_stopucp != NULL) {
+ /*
+ * The LWP was stopped in the usermode emulation library
+ * but a ucontext_t for the preserved brand stack and
+ * register state was provided. Return the register state
+ * from that ucontext_t.
+ */
+ VERIFY(ucp != NULL);
+ *ucp = (void *)lwpd->br_ptrace_stopucp;
+ return (LX_REG_LOC_UCP);
+ }
+
+ return (LX_REG_LOC_UNAVAIL);
+}
diff --git a/usr/src/uts/common/brand/lx/os/lx_ptrace.c b/usr/src/uts/common/brand/lx/os/lx_ptrace.c
index 9a4bc71a0b..6a4bf44aab 100644
--- a/usr/src/uts/common/brand/lx/os/lx_ptrace.c
+++ b/usr/src/uts/common/brand/lx/os/lx_ptrace.c
@@ -217,6 +217,16 @@ typedef enum lx_ptrace_cont_flags_t {
LX_PTC_SINGLESTEP = 0x02
} lx_ptrace_cont_flags_t;
+
+extern int lx_user_regs_copyin(lx_lwp_data_t *, void *);
+extern int lx_user_regs_copyout(lx_lwp_data_t *, void *);
+extern int lx_ptrace_peekuser(lx_lwp_data_t *, uintptr_t, void *);
+extern int lx_ptrace_pokeuser(lx_lwp_data_t *, uintptr_t, void *);
+extern int lx_user_fpregs_copyin(lx_lwp_data_t *, void *);
+extern int lx_user_fpregs_copyout(lx_lwp_data_t *, void *);
+extern int lx_user_fpxregs_copyin(lx_lwp_data_t *, void *);
+extern int lx_user_fpxregs_copyout(lx_lwp_data_t *, void *);
+
/*
* Macros for checking the state of an LWP via "br_ptrace_flags":
*/
@@ -803,74 +813,6 @@ lx_ptrace_geteventmsg(lx_lwp_data_t *remote, void *umsgp)
}
static int
-lx_ptrace_getregs(lx_lwp_data_t *remote, void *uregsp)
-{
- if (remote->br_stack_mode == LX_STACK_MODE_BRAND) {
- /*
- * The LWP was stopped with the brand stack and register
- * state loaded, e.g. during a system call emulated within
- * the kernel. Return the LWP register state.
- */
- return (lx_regs_to_userregs(remote, uregsp));
- } else if (remote->br_stack_mode == LX_STACK_MODE_PREINIT &&
- (remote->br_ptrace_whatstop == LX_PR_SIGNALLED ||
- remote->br_ptrace_whatstop == LX_PR_SYSEXIT)) {
- /*
- * The LWP was stopped by tracing on exec.
- */
- return (lx_regs_to_userregs(remote, uregsp));
- } else if (remote->br_stack_mode == LX_STACK_MODE_NATIVE &&
- remote->br_ptrace_whystop == PR_BRAND &&
- remote->br_ptrace_whatstop == LX_PR_EVENT) {
- /*
- * Called while we're ptrace event stopped by lx_exec.
- */
- return (lx_regs_to_userregs(remote, uregsp));
- } else if (remote->br_ptrace_stopucp != NULL) {
- /*
- * The LWP was stopped in the usermode emulation library
- * but a ucontext_t for the preserved brand stack and
- * register state was provided. Return the register state
- * from that ucontext_t.
- */
- return (lx_uc_to_userregs(remote,
- (void *)remote->br_ptrace_stopucp, uregsp));
- } else {
- /*
- * The register state is not currently available.
- */
- return (EIO);
- }
-}
-
-static int
-lx_ptrace_setregs(lx_lwp_data_t *remote, void *uregsp)
-{
- if (remote->br_stack_mode == LX_STACK_MODE_BRAND) {
- /*
- * The LWP was stopped with the brand stack and register
- * state loaded, e.g. during a system call emulated within
- * the kernel. Write to the LWP register state.
- */
- return (lx_userregs_to_regs(remote, uregsp));
- } else if (remote->br_ptrace_stopucp != NULL) {
- /*
- * The LWP was stopped in the usermode emulation library
- * but a ucontext_t for the preserved brand stack and
- * register state was provided. Write to the register state
- * in that ucontext_t.
- */
- return (lx_userregs_to_uc(remote,
- (void *)remote->br_ptrace_stopucp, uregsp));
- } else {
- /*
- * The register state is not currently available.
- */
- return (EIO);
- }
-}
-
-static int
lx_ptrace_getsiginfo(lx_lwp_data_t *remote, void *usiginfo)
{
klwp_t *lwp = remote->br_lwp;
@@ -965,6 +907,7 @@ lx_ptrace_detach(lx_ptrace_accord_t *accord, lx_lwp_data_t *remote, int signo,
* Detach the LWP from the accord and set it running.
*/
VERIFY(!TRACEE_BUSY(remote));
+ VERIFY(MUTEX_HELD(&accord->lxpa_tracees_lock));
remote->br_ptrace_flags &= ~(LX_PTF_SYSCALL | LX_PTF_INHERIT);
VERIFY(list_link_active(&remote->br_ptrace_linkage));
list_remove(&accord->lxpa_tracees, remote);
@@ -2285,11 +2228,72 @@ lx_waitid_helper(idtype_t idtype, id_t id, k_siginfo_t *ip, int options,
return (0);
}
-/*
- * Some PTRACE_* requests are handled in-kernel by this function. It is called
- * through brandsys() via the B_PTRACE_KERNEL subcommand.
- */
-int
+static int
+lx_ptrace_peek(lx_lwp_data_t *lwpd, uintptr_t addr, void *data)
+{
+ proc_t *p = lwptoproc(lwpd->br_lwp);
+ long buf;
+ int error = 0, size = sizeof (buf);
+
+#if defined(_LP64)
+ if (get_udatamodel() != DATAMODEL_NATIVE) {
+ size = sizeof (uint32_t);
+ }
+#endif
+ if ((addr & (size - 1)) != 0) {
+ /* unaligned access */
+ return (EINVAL);
+ }
+
+ mutex_exit(&p->p_lock);
+ error = uread(p, &buf, size, addr);
+ mutex_enter(&p->p_lock);
+
+ if (error != 0) {
+ return (EIO);
+ }
+ if (copyout(&buf, data, size) != 0) {
+ return (EFAULT);
+ }
+
+ return (0);
+}
+
+static int
+lx_ptrace_poke(lx_lwp_data_t *lwpd, uintptr_t addr, uintptr_t data)
+{
+ proc_t *p = lwptoproc(lwpd->br_lwp);
+ int error = 0, size = sizeof (data);
+
+#if defined(_LP64)
+ if (get_udatamodel() != DATAMODEL_NATIVE) {
+ size = sizeof (uint32_t);
+ }
+#endif
+ if ((addr & (size - 1)) != 0) {
+ /* unaligned access */
+ return (EINVAL);
+ }
+
+ mutex_exit(&p->p_lock);
+ error = uwrite(p, &data, size, addr);
+ mutex_enter(&p->p_lock);
+
+ if (error != 0) {
+ return (EIO);
+ }
+ return (0);
+}
+
+static int
+lx_ptrace_kill(lx_lwp_data_t *lwpd)
+{
+ sigtoproc(lwptoproc(lwpd->br_lwp), NULL, SIGKILL);
+
+ return (0);
+}
+
+static int
lx_ptrace_kernel(int ptrace_op, pid_t lxpid, uintptr_t addr, uintptr_t data)
{
lx_lwp_data_t *local = ttolxlwp(curthread);
@@ -2299,12 +2303,10 @@ lx_ptrace_kernel(int ptrace_op, pid_t lxpid, uintptr_t addr, uintptr_t data)
proc_t *rproc;
int error;
boolean_t found = B_FALSE;
- boolean_t release_hold = B_FALSE;
-
- _NOTE(ARGUNUSED(addr));
/*
- * These actions do not require the target LWP to be traced or stopped.
+ * PTRACE_TRACEME and PTRACE_ATTACH operations induce the tracing of
+ * one LWP by another. The target LWP must not be traced already.
*/
switch (ptrace_op) {
case LX_PTRACE_TRACEME:
@@ -2365,15 +2367,39 @@ lx_ptrace_kernel(int ptrace_op, pid_t lxpid, uintptr_t addr, uintptr_t data)
rlwp = remote->br_lwp;
rproc = lwptoproc(rlwp);
+
+ if (ptrace_op == LX_PTRACE_DETACH) {
+ boolean_t release_hold = B_FALSE;
+ error = lx_ptrace_detach(accord, remote, (int)data,
+ &release_hold);
+ /*
+ * Drop the lock on both the tracee process and the tracee list.
+ */
+ mutex_exit(&rproc->p_lock);
+ mutex_exit(&accord->lxpa_tracees_lock);
+
+ if (release_hold) {
+ /*
+ * Release a hold from the accord.
+ */
+ lx_ptrace_accord_enter(accord);
+ lx_ptrace_accord_rele(accord);
+ lx_ptrace_accord_exit(accord);
+ }
+
+ return (error);
+ }
+
+ /*
+ * The tracees lock is not needed for any of the other operations.
+ * Drop it so further actions can avoid deadlock.
+ */
+ mutex_exit(&accord->lxpa_tracees_lock);
+
/*
* Process the ptrace(2) request:
*/
switch (ptrace_op) {
- case LX_PTRACE_DETACH:
- error = lx_ptrace_detach(accord, remote, (int)data,
- &release_hold);
- break;
-
case LX_PTRACE_CONT:
error = lx_ptrace_cont(remote, LX_PTC_NONE, (int)data);
break;
@@ -2395,17 +2421,55 @@ lx_ptrace_kernel(int ptrace_op, pid_t lxpid, uintptr_t addr, uintptr_t data)
break;
case LX_PTRACE_GETREGS:
- error = lx_ptrace_getregs(remote, (void *)data);
+ error = lx_user_regs_copyout(remote, (void *)data);
break;
case LX_PTRACE_SETREGS:
- error = lx_ptrace_setregs(remote, (void *)data);
+ error = lx_user_regs_copyin(remote, (void *)data);
break;
case LX_PTRACE_GETSIGINFO:
error = lx_ptrace_getsiginfo(remote, (void *)data);
break;
+ case LX_PTRACE_PEEKTEXT:
+ case LX_PTRACE_PEEKDATA:
+ error = lx_ptrace_peek(remote, addr, (void *)data);
+ break;
+
+ case LX_PTRACE_POKETEXT:
+ case LX_PTRACE_POKEDATA:
+ error = lx_ptrace_poke(remote, addr, data);
+ break;
+
+ case LX_PTRACE_PEEKUSER:
+ error = lx_ptrace_peekuser(remote, addr, (void *)data);
+ break;
+
+ case LX_PTRACE_POKEUSER:
+ error = lx_ptrace_pokeuser(remote, addr, (void *)data);
+ break;
+
+ case LX_PTRACE_GETFPREGS:
+ error = lx_user_fpregs_copyout(remote, (void *)data);
+ break;
+
+ case LX_PTRACE_SETFPREGS:
+ error = lx_user_fpregs_copyin(remote, (void *)data);
+ break;
+
+ case LX_PTRACE_GETFPXREGS:
+ error = lx_user_fpxregs_copyout(remote, (void *)data);
+ break;
+
+ case LX_PTRACE_SETFPXREGS:
+ error = lx_user_fpxregs_copyin(remote, (void *)data);
+ break;
+
+ case LX_PTRACE_KILL:
+ error = lx_ptrace_kill(remote);
+ break;
+
default:
error = EINVAL;
}
@@ -2414,20 +2478,22 @@ lx_ptrace_kernel(int ptrace_op, pid_t lxpid, uintptr_t addr, uintptr_t data)
* Drop the lock on both the tracee process and the tracee list.
*/
mutex_exit(&rproc->p_lock);
- mutex_exit(&accord->lxpa_tracees_lock);
-
- if (release_hold) {
- /*
- * Release a hold from the accord.
- */
- lx_ptrace_accord_enter(accord);
- lx_ptrace_accord_rele(accord);
- lx_ptrace_accord_exit(accord);
- }
return (error);
}
+int
+lx_ptrace(int ptrace_op, pid_t lxpid, uintptr_t addr, uintptr_t data)
+{
+ int error;
+
+ error = lx_ptrace_kernel(ptrace_op, lxpid, addr, data);
+ if (error != 0) {
+ return (set_errno(error));
+ }
+ return (0);
+}
+
void
lx_ptrace_init(void)
{
diff --git a/usr/src/uts/common/brand/lx/os/lx_syscall.c b/usr/src/uts/common/brand/lx/os/lx_syscall.c
index b3ee62ef75..c141a1ea28 100644
--- a/usr/src/uts/common/brand/lx/os/lx_syscall.c
+++ b/usr/src/uts/common/brand/lx/os/lx_syscall.c
@@ -549,7 +549,7 @@ lx_sysent_t lx_sysent32[] = {
{"setuid16", NULL, 0, 1}, /* 23 */
{"getuid16", NULL, 0, 0}, /* 24 */
{"stime", NULL, 0, 1}, /* 25 */
- {"ptrace", NULL, 0, 4}, /* 26 */
+ {"ptrace", lx_ptrace, 0, 4}, /* 26 */
{"alarm", NULL, 0, 1}, /* 27 */
{"fstat", NULL, NOSYS_OBSOLETE, 0}, /* 28 */
{"pause", NULL, 0, 0}, /* 29 */
@@ -995,7 +995,7 @@ lx_sysent_t lx_sysent64[] = {
{"getrusage", NULL, 0, 2}, /* 98 */
{"sysinfo", lx_sysinfo64, 0, 1}, /* 99 */
{"times", NULL, 0, 1}, /* 100 */
- {"ptrace", NULL, 0, 4}, /* 101 */
+ {"ptrace", lx_ptrace, 0, 4}, /* 101 */
{"getuid", NULL, 0, 0}, /* 102 */
{"syslog", NULL, 0, 3}, /* 103 */
{"getgid", NULL, 0, 0}, /* 104 */
diff --git a/usr/src/uts/common/brand/lx/sys/lx_brand.h b/usr/src/uts/common/brand/lx/sys/lx_brand.h
index aa682d9538..1b00691ba5 100644
--- a/usr/src/uts/common/brand/lx/sys/lx_brand.h
+++ b/usr/src/uts/common/brand/lx/sys/lx_brand.h
@@ -82,7 +82,7 @@ extern "C" {
#define B_LPID_TO_SPAIR 128
#define B_GET_CURRENT_CONTEXT 129
#define B_EMULATION_DONE 130
-#define B_PTRACE_KERNEL 131
+/* formerly B_PTRACE_KERNEL 131 */
#define B_SET_AFFINITY_MASK 132
#define B_GET_AFFINITY_MASK 133
#define B_PTRACE_CLONE_BEGIN 134
@@ -197,149 +197,6 @@ typedef struct lx_brand_registration32 {
uint32_t lxbr_flags; /* LX_PROC_* registration flags */
} lx_brand_registration32_t;
-#ifdef __amd64
-
-typedef struct lx_regs {
- long lxr_fs;
- long lxr_rdi;
- long lxr_rsi;
- long lxr_rbp;
- long lxr_rsp;
- long lxr_rbx;
- long lxr_rdx;
- long lxr_rcx;
- long lxr_rax;
- long lxr_r8;
- long lxr_r9;
- long lxr_r10;
- long lxr_r11;
- long lxr_r12;
- long lxr_r13;
- long lxr_r14;
- long lxr_r15;
- long lxr_rip;
-
- long lxr_orig_rax;
-} lx_regs_t;
-
-typedef struct lx_regs32 {
- uint32_t lxr_gs;
- uint32_t lxr_edi;
- uint32_t lxr_esi;
- uint32_t lxr_ebp;
- uint32_t lxr_esp;
- uint32_t lxr_ebx;
- uint32_t lxr_edx;
- uint32_t lxr_ecx;
- uint32_t lxr_eax;
- uint32_t lxr_eip;
-
- uint32_t lxr_orig_eax;
-} lx_regs32_t;
-
-#else /* ! __amd64 */
-
-typedef struct lx_regs {
- long lxr_gs;
- long lxr_edi;
- long lxr_esi;
- long lxr_ebp;
- long lxr_esp;
- long lxr_ebx;
- long lxr_edx;
- long lxr_ecx;
- long lxr_eax;
- long lxr_eip;
-
- long lxr_orig_eax;
-} lx_regs_t;
-
-#endif /* __amd64 */
-
-#ifdef __amd64
-/*
- * The 64-bit native "user_regs_struct" Linux structure.
- */
-typedef struct lx_user_regs {
- long lxur_r15;
- long lxur_r14;
- long lxur_r13;
- long lxur_r12;
- long lxur_rbp;
- long lxur_rbx;
- long lxur_r11;
- long lxur_r10;
- long lxur_r9;
- long lxur_r8;
- long lxur_rax;
- long lxur_rcx;
- long lxur_rdx;
- long lxur_rsi;
- long lxur_rdi;
- long lxur_orig_rax;
- long lxur_rip;
- long lxur_xcs;
- long lxur_rflags;
- long lxur_rsp;
- long lxur_xss;
- long lxur_xfs_base;
- long lxur_xgs_base;
- long lxur_xds;
- long lxur_xes;
- long lxur_xfs;
- long lxur_xgs;
-} lx_user_regs_t;
-
-#if defined(_KERNEL) && defined(_SYSCALL32_IMPL)
-/*
- * 64-bit kernel view of the 32-bit "user_regs_struct" Linux structure.
- */
-typedef struct lx_user_regs32 {
- int32_t lxur_ebx;
- int32_t lxur_ecx;
- int32_t lxur_edx;
- int32_t lxur_esi;
- int32_t lxur_edi;
- int32_t lxur_ebp;
- int32_t lxur_eax;
- int32_t lxur_xds;
- int32_t lxur_xes;
- int32_t lxur_xfs;
- int32_t lxur_xgs;
- int32_t lxur_orig_eax;
- int32_t lxur_eip;
- int32_t lxur_xcs;
- int32_t lxur_eflags;
- int32_t lxur_esp;
- int32_t lxur_xss;
-} lx_user_regs32_t;
-#endif /* defined(_KERNEL) && defined(_SYSCALL32_IMPL) */
-
-#else /* !__amd64 */
-/*
- * The 32-bit native "user_regs_struct" Linux structure.
- */
-typedef struct lx_user_regs {
- long lxur_ebx;
- long lxur_ecx;
- long lxur_edx;
- long lxur_esi;
- long lxur_edi;
- long lxur_ebp;
- long lxur_eax;
- long lxur_xds;
- long lxur_xes;
- long lxur_xfs;
- long lxur_xgs;
- long lxur_orig_eax;
- long lxur_eip;
- long lxur_xcs;
- long lxur_eflags;
- long lxur_esp;
- long lxur_xss;
-} lx_user_regs_t;
-#endif /* __amd64 */
-
#endif /* _ASM */
/*
@@ -713,10 +570,6 @@ extern void lx_lwp_set_native_stack_current(lx_lwp_data_t *, uintptr_t);
extern void lx_divert(klwp_t *, uintptr_t);
extern int lx_runexe(klwp_t *, void *);
extern void lx_switch_to_native(klwp_t *);
-extern int lx_regs_to_userregs(lx_lwp_data_t *, void *);
-extern int lx_uc_to_userregs(lx_lwp_data_t *, void *, void *);
-extern int lx_userregs_to_regs(lx_lwp_data_t *lwpd, void *);
-extern int lx_userregs_to_uc(lx_lwp_data_t *lwpd, void *, void *);
extern int lx_syscall_enter(void);
extern int lx_syscall_return(klwp_t *, int, long);
diff --git a/usr/src/uts/common/brand/lx/sys/lx_misc.h b/usr/src/uts/common/brand/lx/sys/lx_misc.h
index 73f7ae1f5c..5e123db2ee 100644
--- a/usr/src/uts/common/brand/lx/sys/lx_misc.h
+++ b/usr/src/uts/common/brand/lx/sys/lx_misc.h
@@ -50,6 +50,15 @@ extern int stol_ksiginfo32_copyout(k_siginfo_t *, void *);
#endif
extern void lx_read_argv_bounds(proc_t *p);
+typedef enum lx_regs_location {
+ LX_REG_LOC_UNAVAIL,
+ LX_REG_LOC_LWP,
+ LX_REG_LOC_UCP
+} lx_regs_location_t;
+
+extern lx_regs_location_t lx_regs_location(lx_lwp_data_t *, void **, boolean_t);
+
+
typedef enum lx_if_action {
LX_IF_FROMNATIVE,
LX_IF_TONATIVE
@@ -69,7 +78,6 @@ extern boolean_t lx_ptrace_stop(ushort_t);
extern void lx_stop_notify(proc_t *, klwp_t *, ushort_t, ushort_t);
extern void lx_ptrace_init(void);
extern void lx_ptrace_fini(void);
-extern int lx_ptrace_kernel(int, pid_t, uintptr_t, uintptr_t);
extern int lx_waitid_helper(idtype_t, id_t, k_siginfo_t *, int, boolean_t *,
int *);
extern void lx_ptrace_exit(proc_t *, klwp_t *);
diff --git a/usr/src/uts/common/brand/lx/sys/lx_syscalls.h b/usr/src/uts/common/brand/lx/sys/lx_syscalls.h
index f0cbcedb8c..6ceb748914 100644
--- a/usr/src/uts/common/brand/lx/sys/lx_syscalls.h
+++ b/usr/src/uts/common/brand/lx/sys/lx_syscalls.h
@@ -82,6 +82,7 @@ extern long lx_pipe();
extern long lx_pipe2();
extern long lx_prctl();
extern long lx_prlimit64();
+extern long lx_ptrace();
extern long lx_read();
extern long lx_recv();
extern long lx_recvmsg();
diff --git a/usr/src/uts/intel/brand/lx/lx_archdep.c b/usr/src/uts/intel/brand/lx/lx_archdep.c
index 70e54d4fb9..254985f23b 100644
--- a/usr/src/uts/intel/brand/lx/lx_archdep.c
+++ b/usr/src/uts/intel/brand/lx/lx_archdep.c
@@ -22,6 +22,7 @@
#include <sys/ddi.h>
#include <sys/brand.h>
#include <sys/lx_brand.h>
+#include <sys/lx_misc.h>
#include <sys/privregs.h>
#include <sys/pcb.h>
#include <sys/archsystm.h>
@@ -32,12 +33,171 @@
#define LX_REG(ucp, r) ((ucp)->uc_mcontext.gregs[(r)])
+#ifdef __amd64
+/* 64-bit native user_regs_struct */
+typedef struct lx_user_regs64 {
+ int64_t lxur_r15;
+ int64_t lxur_r14;
+ int64_t lxur_r13;
+ int64_t lxur_r12;
+ int64_t lxur_rbp;
+ int64_t lxur_rbx;
+ int64_t lxur_r11;
+ int64_t lxur_r10;
+ int64_t lxur_r9;
+ int64_t lxur_r8;
+ int64_t lxur_rax;
+ int64_t lxur_rcx;
+ int64_t lxur_rdx;
+ int64_t lxur_rsi;
+ int64_t lxur_rdi;
+ int64_t lxur_orig_rax;
+ int64_t lxur_rip;
+ int64_t lxur_xcs;
+ int64_t lxur_rflags;
+ int64_t lxur_rsp;
+ int64_t lxur_xss;
+ int64_t lxur_xfs_base;
+ int64_t lxur_xgs_base;
+ int64_t lxur_xds;
+ int64_t lxur_xes;
+ int64_t lxur_xfs;
+ int64_t lxur_xgs;
+} lx_user_regs64_t;
+
+/* 64-bit native user_fpregs_struct */
+typedef struct lx_user_fpregs64 {
+ uint16_t lxufp_cwd;
+ uint16_t lxufp_swd;
+ uint16_t lxufp_ftw;
+ uint16_t lxufp_fop;
+ uint64_t lxufp_rip;
+ uint64_t lxufp_rdp;
+ uint32_t lxufp_mxcsr;
+ uint32_t lxufp_mxcr_mask;
+ /* 8*16 bytes for each FP-reg = 128 bytes */
+ uint32_t lxufp_st_space[32];
+ /* 16*16 bytes for each XMM-reg = 256 bytes */
+ uint32_t lxufp_xmm_space[64];
+ uint32_t lxufp_padding[24];
+} lx_user_fpregs64_t;
+
+/* 64-bit native user_struct */
+typedef struct lx_user64 {
+ lx_user_regs64_t lxu_regs;
+ int32_t lxu_fpvalid;
+ int32_t lxu_pad0;
+ lx_user_fpregs64_t lxu_i387;
+ uint64_t lxu_tsize;
+ uint64_t lxu_dsize;
+ uint64_t lxu_ssize;
+ uint64_t lxu_start_code;
+ uint64_t lxu_start_stack;
+ int64_t lxu_signal;
+ int32_t lxu_reserved;
+ int32_t lxu_pad1;
+ /* help gdb to locate user_regs structure */
+ caddr_t lxu_ar0;
+ /* help gdb to locate user_fpregs structure */
+ caddr_t lxu_fpstate;
+ uint64_t lxu_magic;
+ char lxu_comm[32];
+ uint64_t lxu_debugreg[8];
+ uint64_t lxu_error_code;
+ uint64_t lxu_fault_address;
+} lx_user64_t;
+
+#endif /* __amd64 */
+
+/* 32-bit native user_regs_struct */
+typedef struct lx_user_regs32 {
+ int32_t lxur_ebx;
+ int32_t lxur_ecx;
+ int32_t lxur_edx;
+ int32_t lxur_esi;
+ int32_t lxur_edi;
+ int32_t lxur_ebp;
+ int32_t lxur_eax;
+ int32_t lxur_xds;
+ int32_t lxur_xes;
+ int32_t lxur_xfs;
+ int32_t lxur_xgs;
+ int32_t lxur_orig_eax;
+ int32_t lxur_eip;
+ int32_t lxur_xcs;
+ int32_t lxur_eflags;
+ int32_t lxur_esp;
+ int32_t lxur_xss;
+} lx_user_regs32_t;
+
+/* 32-bit native user_fpregs_struct */
+typedef struct lx_user_fpregs32 {
+ int32_t lxufp_cwd;
+ int32_t lxufp_swd;
+ int32_t lxufp_twd;
+ int32_t lxufp_fip;
+ int32_t lxufp_fcs;
+ int32_t lxufp_foo;
+ int32_t lxufp_fos;
+ int32_t lxufp_st_space[20];
+} lx_user_fpregs32_t;
+
+/* 32-bit native user_fpxregs_struct */
+typedef struct lx_user_fpxregs32 {
+ uint16_t lxufpx_cwd;
+ uint16_t lxufpx_swd;
+ uint16_t lxufpx_twd;
+ uint16_t lxufpx_fop;
+ int32_t lxufpx_fip;
+ int32_t lxufpx_fcs;
+ int32_t lxufpx_foo;
+ int32_t lxufpx_fos;
+ int32_t lxufpx_mxcsr;
+ int32_t lxufpx_reserved;
+ /* 8*16 bytes for each FP-reg = 128 bytes */
+ int32_t lxufpx_st_space[32];
+ /* 8*16 bytes for each XMM-reg = 128 bytes */
+ int32_t lxufpx_xmm_space[32];
+ int32_t lxufpx_padding[56];
+} lx_user_fpxregs32_t;
+
+/* 32-bit native user_struct */
+typedef struct lx_user32 {
+ lx_user_regs32_t lxu_regs;
+ int32_t lxu_fpvalid;
+ lx_user_fpregs32_t lxu_i387;
+ uint32_t lxu_tsize;
+ uint32_t lxu_dsize;
+ uint32_t lxu_ssize;
+ uint32_t lxu_start_code;
+ uint32_t lxu_start_stack;
+ int32_t lxu_signal;
+ int32_t lxu_reserved;
+ caddr32_t lxu_ar0;
+ caddr32_t lxu_fpstate;
+ uint32_t lxu_magic;
+ char lxu_comm[32];
+ int32_t lxu_debugreg[8];
+} lx_user32_t;
+
+/*
+ * Certain version of strace (on centos6 for example) use the %cs value to
+ * determine what kind of process is being traced. Here is a sample comment:
+ * Check CS register value. On x86-64 linux it is:
+ * 0x33 for long mode (64 bit and x32))
+ * 0x23 for compatibility mode (32 bit)
+ * %ds = 0x2b for x32 mode (x86-64 in 32 bit)
+ * We can't change the %cs value in the ucp (see setgregs and _sys_rtt) so we
+ * emulate the expected value for ptrace use.
+ */
+#define LX_CS_64BIT 0x33
+#define LX_CS_32BIT 0x23
+
extern int getsetcontext(int, void *);
#if defined(_SYSCALL32_IMPL)
extern int getsetcontext32(int, void *);
#endif
-#if defined(__amd64)
static int
lx_rw_uc(proc_t *p, void *ucp, void *kucp, size_t ucsz, boolean_t writing)
{
@@ -100,616 +260,915 @@ lx_write_uc(proc_t *p, void *ucp, void *kucp, size_t ucsz)
{
return (lx_rw_uc(p, ucp, kucp, ucsz, B_TRUE));
}
+
+static void
+lx_getfpregs32(lx_lwp_data_t *lwpd, lx_user_fpregs32_t *lfp)
+{
+#ifdef __amd64
+ fpregset32_t fp;
+ getfpregs32(lwpd->br_lwp, &fp);
+#else /* __i386 */
+ fpregset_t fp;
+ getfpregs(lwpd->br_lwp, &fp);
#endif /* __amd64 */
-/*
- * Load register state from a usermode "lx_user_regs_t" in the tracer
- * and store it in the tracee ucontext_t.
- */
-int
-lx_userregs_to_uc(lx_lwp_data_t *lwpd, void *ucp, void *uregsp)
+ /*
+ * The fpchip_state.state field should correspond to all 27 fields in
+ * the 32-bit structure.
+ */
+ bcopy(&fp.fp_reg_set.fpchip_state.state, lfp, sizeof (*lfp));
+}
+
+static void
+lx_setfpregs32(lx_lwp_data_t *lwpd, lx_user_fpregs32_t *lfp)
+{
+#ifdef __amd64
+ fpregset32_t fp;
+#else /* __i386 */
+ fpregset_t fp;
+#endif /* __amd64 */
+
+ /*
+ * The fpchip_state field should correspond to all 27 fields in the
+ * native 32-bit structure.
+ */
+ bcopy(lfp, &fp.fp_reg_set.fpchip_state.state, sizeof (*lfp));
+
+#ifdef __amd64
+ setfpregs32(lwpd->br_lwp, &fp);
+#else /* __i386 */
+ setfpregs(lwpd->br_lwp, &fp);
+#endif /* __amd64 */
+}
+
+static int
+lx_get_user_regs32_uc(klwp_t *lwp, void *ucp, lx_user_regs32_t *lxrp)
{
-#if defined(__amd64)
- klwp_t *lwp = lwpd->br_lwp;
proc_t *p = lwptoproc(lwp);
+ ucontext32_t uc;
- switch (get_udatamodel()) {
- case DATAMODEL_LP64: {
- lx_user_regs_t lxur;
+ if (lx_read_uc(p, ucp, &uc, sizeof (uc)) != 0) {
+ return (-1);
+ }
- if (copyin(uregsp, &lxur, sizeof (lxur)) != 0) {
- return (EFAULT);
- }
+ lxrp->lxur_ebx = LX_REG(&uc, EBX);
+ lxrp->lxur_ecx = LX_REG(&uc, ECX);
+ lxrp->lxur_edx = LX_REG(&uc, EDX);
+ lxrp->lxur_esi = LX_REG(&uc, ESI);
+ lxrp->lxur_edi = LX_REG(&uc, EDI);
+ lxrp->lxur_ebp = LX_REG(&uc, EBP);
+ lxrp->lxur_eax = LX_REG(&uc, EAX);
+ lxrp->lxur_orig_eax = 0;
+
+ lxrp->lxur_eip = LX_REG(&uc, EIP);
+ lxrp->lxur_eflags = LX_REG(&uc, EFL);
+ lxrp->lxur_esp = LX_REG(&uc, UESP);
+ lxrp->lxur_xss = LX_REG(&uc, SS);
+
+ /* emulated %cs, see defines */
+ lxrp->lxur_xcs = LX_CS_32BIT;
+ lxrp->lxur_xds = LX_REG(&uc, DS);
+ lxrp->lxur_xes = LX_REG(&uc, ES);
+ lxrp->lxur_xfs = LX_REG(&uc, FS);
+ lxrp->lxur_xgs = LX_REG(&uc, GS);
+ return (0);
+}
- switch (lwp_getdatamodel(lwp)) {
- case DATAMODEL_LP64: {
- ucontext_t uc;
+static int
+lx_get_user_regs32(lx_lwp_data_t *lwpd, lx_user_regs32_t *lxrp)
+{
+ klwp_t *lwp = lwpd->br_lwp;
+ struct regs *rp = lwptoregs(lwp);
+ void *ucp;
+#ifdef __amd64
+ struct pcb *pcb = &lwp->lwp_pcb;
+#endif
- if (lx_read_uc(p, ucp, &uc, sizeof (uc)) != 0) {
- return (EIO);
- }
+ VERIFY(lwp_getdatamodel(lwp) == DATAMODEL_ILP32);
- /*
- * Note: we currently ignore "lxur_orig_rax" here (as
- * this path should not be used for system call stops)
- * as well as "lxur_xcs" (lest we get caught up in our
- * own lies about %cs from lx_uc_to_userregs()).
- */
- LX_REG(&uc, REG_R15) = lxur.lxur_r15;
- LX_REG(&uc, REG_R14) = lxur.lxur_r14;
- LX_REG(&uc, REG_R13) = lxur.lxur_r13;
- LX_REG(&uc, REG_R12) = lxur.lxur_r12;
- LX_REG(&uc, REG_RBP) = lxur.lxur_rbp;
- LX_REG(&uc, REG_RBX) = lxur.lxur_rbx;
- LX_REG(&uc, REG_R11) = lxur.lxur_r11;
- LX_REG(&uc, REG_R10) = lxur.lxur_r10;
- LX_REG(&uc, REG_R9) = lxur.lxur_r9;
- LX_REG(&uc, REG_R8) = lxur.lxur_r8;
- LX_REG(&uc, REG_RAX) = lxur.lxur_rax;
- LX_REG(&uc, REG_RCX) = lxur.lxur_rcx;
- LX_REG(&uc, REG_RDX) = lxur.lxur_rdx;
- LX_REG(&uc, REG_RSI) = lxur.lxur_rsi;
- LX_REG(&uc, REG_RDI) = lxur.lxur_rdi;
- LX_REG(&uc, REG_RIP) = lxur.lxur_rip;
- LX_REG(&uc, REG_RFL) = lxur.lxur_rflags;
- LX_REG(&uc, REG_RSP) = lxur.lxur_rsp;
- LX_REG(&uc, REG_SS) = lxur.lxur_xss;
- LX_REG(&uc, REG_FSBASE) = lxur.lxur_xfs_base;
- LX_REG(&uc, REG_GSBASE) = lxur.lxur_xgs_base;
-
- LX_REG(&uc, REG_DS) = lxur.lxur_xds;
- LX_REG(&uc, REG_ES) = lxur.lxur_xes;
- LX_REG(&uc, REG_FS) = lxur.lxur_xfs;
- LX_REG(&uc, REG_GS) = lxur.lxur_xgs;
-
- if (lx_write_uc(p, ucp, &uc, sizeof (uc)) != 0) {
- return (EIO);
- }
+ switch (lx_regs_location(lwpd, &ucp, B_FALSE)) {
+ case LX_REG_LOC_UNAVAIL:
+ return (-1);
- return (0);
- }
+ case LX_REG_LOC_UCP:
+ return (lx_get_user_regs32_uc(lwp, ucp, lxrp));
- case DATAMODEL_ILP32: {
- ucontext32_t uc;
+ case LX_REG_LOC_LWP:
+ /* transformation below */
+ break;
- if (lx_read_uc(p, ucp, &uc, sizeof (uc)) != 0) {
- return (EIO);
- }
+ default:
+ VERIFY(0);
+ break;
+ }
- /*
- * Note: we currently ignore "lxur_orig_eax" here (as
- * this path should not be used for system call stops)
- * as well as "lxur_xcs" (lest we get caught up in our
- * own lies about %cs from lx_uc_to_userregs()).
- */
- LX_REG(&uc, EBP) = (int32_t)lxur.lxur_rbp;
- LX_REG(&uc, EBX) = (int32_t)lxur.lxur_rbx;
- LX_REG(&uc, EAX) = (int32_t)lxur.lxur_rax;
- LX_REG(&uc, ECX) = (int32_t)lxur.lxur_rcx;
- LX_REG(&uc, EDX) = (int32_t)lxur.lxur_rdx;
- LX_REG(&uc, ESI) = (int32_t)lxur.lxur_rsi;
- LX_REG(&uc, EDI) = (int32_t)lxur.lxur_rdi;
- LX_REG(&uc, EIP) = (int32_t)lxur.lxur_rip;
- LX_REG(&uc, EFL) = (int32_t)lxur.lxur_rflags;
- LX_REG(&uc, UESP) = (int32_t)lxur.lxur_rsp;
- LX_REG(&uc, SS) = (int32_t)lxur.lxur_xss;
-
- LX_REG(&uc, DS) = (int32_t)lxur.lxur_xds;
- LX_REG(&uc, ES) = (int32_t)lxur.lxur_xes;
- LX_REG(&uc, FS) = (int32_t)lxur.lxur_xfs;
- LX_REG(&uc, GS) = (int32_t)lxur.lxur_xgs;
-
- if (lx_write_uc(p, ucp, &uc, sizeof (uc)) != 0) {
- return (EIO);
- }
+#ifdef __amd64
+ lxrp->lxur_ebx = (int32_t)rp->r_rbx;
+ lxrp->lxur_ecx = (int32_t)rp->r_rcx;
+ lxrp->lxur_edx = (int32_t)rp->r_rdx;
+ lxrp->lxur_esi = (int32_t)rp->r_rsi;
+ lxrp->lxur_edi = (int32_t)rp->r_rdi;
+ lxrp->lxur_ebp = (int32_t)rp->r_rbp;
+ lxrp->lxur_eax = (int32_t)rp->r_rax;
+ lxrp->lxur_orig_eax = 0;
+ lxrp->lxur_eip = (int32_t)rp->r_rip;
+ lxrp->lxur_eflags = (int32_t)rp->r_rfl;
+ lxrp->lxur_esp = (int32_t)rp->r_rsp;
+ lxrp->lxur_xss = (int32_t)rp->r_ss;
+
+ kpreempt_disable();
+ if (pcb->pcb_rupdate == 1) {
+ lxrp->lxur_xds = pcb->pcb_ds;
+ lxrp->lxur_xes = pcb->pcb_es;
+ lxrp->lxur_xfs = pcb->pcb_fs;
+ lxrp->lxur_xgs = pcb->pcb_gs;
+ } else {
+ lxrp->lxur_xds = rp->r_ds;
+ lxrp->lxur_xes = rp->r_es;
+ lxrp->lxur_xfs = rp->r_fs;
+ lxrp->lxur_xgs = rp->r_gs;
+ }
+ kpreempt_enable();
+#else /* __i386 */
+ lxrp->lxur_ebx = rp->r_ebx;
+ lxrp->lxur_ecx = rp->r_ecx;
+ lxrp->lxur_edx = rp->r_edx;
+ lxrp->lxur_esi = rp->r_esi;
+ lxrp->lxur_edi = rp->r_edi;
+ lxrp->lxur_ebp = rp->r_ebp;
+ lxrp->lxur_eax = rp->r_eax;
+ lxrp->lxur_orig_eax = 0;
+ lxrp->lxur_eip = rp->r_eip;
+ lxrp->lxur_eflags = rp->r_efl;
+ lxrp->lxur_esp = rp->r_esp;
+ lxrp->lxur_xss = rp->r_ss;
+
+ lxrp->lxur_xds = rp->r_ds;
+ lxrp->lxur_xes = rp->r_es;
+ lxrp->lxur_xfs = rp->r_fs;
+ lxrp->lxur_xgs = rp->r_gs;
+#endif /* __amd64 */
- return (0);
- }
+ /* emulated %cs, see defines */
+ lxrp->lxur_xcs = LX_CS_32BIT;
- default:
- return (EIO);
- }
+ if (lwpd->br_ptrace_whatstop == LX_PR_SYSENTRY) {
+ lxrp->lxur_eax = (int32_t)-lx_errno(ENOTSUP, EINVAL);
+ lxrp->lxur_orig_eax = (int32_t)lwpd->br_syscall_num;
+ } else if (lwpd->br_ptrace_whatstop == LX_PR_SYSEXIT) {
+ lxrp->lxur_orig_eax = (int32_t)lwpd->br_syscall_num;
+ }
+
+ return (0);
+}
+
+static int
+lx_set_user_regs32_uc(klwp_t *lwp, void *ucp, lx_user_regs32_t *lxrp)
+{
+ proc_t *p = lwptoproc(lwp);
+ ucontext32_t uc;
- return (EIO);
+ if (lx_read_uc(p, ucp, &uc, sizeof (uc)) != 0) {
+ return (-1);
}
- case DATAMODEL_ILP32: {
- lx_user_regs32_t lxur;
- ucontext32_t uc;
+ /*
+ * Note: we currently ignore "lxur_orig_rax" here since this
+ * path should not be used for system call stops.
+ */
+ LX_REG(&uc, EBP) = lxrp->lxur_ebp;
+ LX_REG(&uc, EBX) = lxrp->lxur_ebx;
+ LX_REG(&uc, EAX) = lxrp->lxur_eax;
+ LX_REG(&uc, ECX) = lxrp->lxur_ecx;
+ LX_REG(&uc, EDX) = lxrp->lxur_edx;
+ LX_REG(&uc, ESI) = lxrp->lxur_esi;
+ LX_REG(&uc, EDI) = lxrp->lxur_edi;
+ LX_REG(&uc, EIP) = lxrp->lxur_eip;
+ LX_REG(&uc, EFL) = lxrp->lxur_eflags;
+ LX_REG(&uc, UESP) = lxrp->lxur_esp;
+ LX_REG(&uc, SS) = lxrp->lxur_xss;
+
+ /* %cs is ignored because of our lies */
+ LX_REG(&uc, DS) = lxrp->lxur_xds;
+ LX_REG(&uc, ES) = lxrp->lxur_xes;
+ LX_REG(&uc, FS) = lxrp->lxur_xfs;
+ LX_REG(&uc, GS) = lxrp->lxur_xgs;
+
+ if (lx_write_uc(p, ucp, &uc, sizeof (uc)) != 0) {
+ return (-1);
+ }
+ return (0);
+}
- if (lwp_getdatamodel(lwp) != DATAMODEL_ILP32) {
- /*
- * The target is not a 32-bit LWP. We refuse to
- * present truncated 64-bit registers to a 32-bit
- * tracer.
- */
- return (EIO);
- }
+static int
+lx_set_user_regs32(lx_lwp_data_t *lwpd, lx_user_regs32_t *lxrp)
+{
+ klwp_t *lwp = lwpd->br_lwp;
+ struct regs *rp = lwptoregs(lwp);
+ void *ucp;
+#ifdef __amd64
+ struct pcb *pcb = &lwp->lwp_pcb;
+#endif
- if (copyin(uregsp, &lxur, sizeof (lxur)) != 0) {
- return (EFAULT);
- }
+ VERIFY(lwp_getdatamodel(lwp) == DATAMODEL_ILP32);
+
+ switch (lx_regs_location(lwpd, &ucp, B_TRUE)) {
+ case LX_REG_LOC_UNAVAIL:
+ return (-1);
+
+ case LX_REG_LOC_UCP:
+ return (lx_set_user_regs32_uc(lwp, ucp, lxrp));
+
+ case LX_REG_LOC_LWP:
+ /* transformation below */
+ break;
+
+ default:
+ VERIFY(0);
+ break;
+ }
+
+#ifdef __amd64
+ rp->r_rbx = (int32_t)lxrp->lxur_ebx;
+ rp->r_rcx = (int32_t)lxrp->lxur_ecx;
+ rp->r_rdx = (int32_t)lxrp->lxur_edx;
+ rp->r_rsi = (int32_t)lxrp->lxur_esi;
+ rp->r_rdi = (int32_t)lxrp->lxur_edi;
+ rp->r_rbp = (int32_t)lxrp->lxur_ebp;
+ rp->r_rax = (int32_t)lxrp->lxur_eax;
+ lwpd->br_syscall_num = (int)lxrp->lxur_orig_eax;
+ rp->r_rip = (int32_t)lxrp->lxur_eip;
+ rp->r_rfl = (int32_t)lxrp->lxur_eflags;
+ rp->r_rsp = (int32_t)lxrp->lxur_esp;
+ rp->r_ss = (int32_t)lxrp->lxur_xss;
+
+ kpreempt_disable();
+ pcb->pcb_rupdate = 1;
+ pcb->pcb_ds = lxrp->lxur_xds;
+ pcb->pcb_es = lxrp->lxur_xes;
+ pcb->pcb_fs = lxrp->lxur_xfs;
+ pcb->pcb_gs = lxrp->lxur_xgs;
+ kpreempt_enable();
+#else /* __i386 */
+ rp->r_ebx = lxrp->lxur_ebx;
+ rp->r_ecx = lxrp->lxur_ecx;
+ rp->r_edx = lxrp->lxur_edx;
+ rp->r_esi = lxrp->lxur_esi;
+ rp->r_edi = lxrp->lxur_edi;
+ rp->r_ebp = lxrp->lxur_ebp;
+ rp->r_eax = lxrp->lxur_eax;
+ lwpd->br_syscall_num = (int)lxrp->lxur_orig_eax;
+ rp->r_eip = lxrp->lxur_eip;
+ rp->r_efl = lxrp->lxur_eflags;
+ rp->r_esp = lxrp->lxur_esp;
+ rp->r_ss = lxrp->lxur_xss;
+
+ rp->r_ds = lxrp->lxur_xds;
+ rp->r_es = lxrp->lxur_xes;
+ rp->r_fs = lxrp->lxur_xfs;
+ rp->r_gs = lxrp->lxur_xgs;
+#endif /* __amd64 */
+
+ return (0);
+}
+
+#ifdef __amd64
+
+static void
+lx_getfpregs64(lx_lwp_data_t *lwpd, lx_user_fpregs64_t *lfp)
+{
+ fpregset_t fp;
+
+ getfpregs(lwpd->br_lwp, &fp);
+ /* Drop the extra illumos status/xstatus fields when copying state */
+ bcopy(&fp.fp_reg_set.fpchip_state, lfp, sizeof (*lfp));
+}
+
+static void
+lx_setfpregs64(lx_lwp_data_t *lwpd, lx_user_fpregs64_t *lfp)
+{
+ fpregset_t fp;
+
+ /*
+ * Since the Linux fpregs structure does not contain the same
+ * additional status register which illumos contains, we simply
+ * preserve the existing values when setting fp state.
+ */
+ getfpregs(lwpd->br_lwp, &fp);
+
+ /* Copy the identically formatted state */
+ bcopy(lfp, &fp.fp_reg_set.fpchip_state, sizeof (*lfp));
+
+ setfpregs(lwpd->br_lwp, &fp);
+}
+
+static int
+lx_get_user_regs64_uc(klwp_t *lwp, void *ucp, lx_user_regs64_t *lxrp)
+{
+ proc_t *p = lwptoproc(lwp);
+
+ switch (lwp_getdatamodel(lwp)) {
+ case DATAMODEL_LP64: {
+ ucontext_t uc;
if (lx_read_uc(p, ucp, &uc, sizeof (uc)) != 0) {
- return (EIO);
+ return (-1);
}
- /*
- * Note: we currently ignore "lxur_orig_eax" here, as
- * this path should not be used for system call stops.
- */
- LX_REG(&uc, EBX) = lxur.lxur_ebx;
- LX_REG(&uc, ECX) = lxur.lxur_ecx;
- LX_REG(&uc, EDX) = lxur.lxur_edx;
- LX_REG(&uc, ESI) = lxur.lxur_esi;
- LX_REG(&uc, EDI) = lxur.lxur_edi;
- LX_REG(&uc, EBP) = lxur.lxur_ebp;
- LX_REG(&uc, EAX) = lxur.lxur_eax;
- LX_REG(&uc, EIP) = lxur.lxur_eip;
- LX_REG(&uc, EFL) = lxur.lxur_eflags;
- LX_REG(&uc, UESP) = lxur.lxur_esp;
- LX_REG(&uc, SS) = lxur.lxur_xss;
-
- LX_REG(&uc, DS) = lxur.lxur_xds;
- LX_REG(&uc, ES) = lxur.lxur_xes;
- LX_REG(&uc, FS) = lxur.lxur_xfs;
- LX_REG(&uc, GS) = lxur.lxur_xgs;
+ lxrp->lxur_r15 = LX_REG(&uc, REG_R15);
+ lxrp->lxur_r14 = LX_REG(&uc, REG_R14);
+ lxrp->lxur_r13 = LX_REG(&uc, REG_R13);
+ lxrp->lxur_r12 = LX_REG(&uc, REG_R12);
+ lxrp->lxur_rbp = LX_REG(&uc, REG_RBP);
+ lxrp->lxur_rbx = LX_REG(&uc, REG_RBX);
+ lxrp->lxur_r11 = LX_REG(&uc, REG_R11);
+ lxrp->lxur_r10 = LX_REG(&uc, REG_R10);
+ lxrp->lxur_r9 = LX_REG(&uc, REG_R9);
+ lxrp->lxur_r8 = LX_REG(&uc, REG_R8);
+ lxrp->lxur_rax = LX_REG(&uc, REG_RAX);
+ lxrp->lxur_rcx = LX_REG(&uc, REG_RCX);
+ lxrp->lxur_rdx = LX_REG(&uc, REG_RDX);
+ lxrp->lxur_rsi = LX_REG(&uc, REG_RSI);
+ lxrp->lxur_rdi = LX_REG(&uc, REG_RDI);
+ lxrp->lxur_orig_rax = 0;
+ lxrp->lxur_rip = LX_REG(&uc, REG_RIP);
+ lxrp->lxur_rflags = LX_REG(&uc, REG_RFL);
+ lxrp->lxur_rsp = LX_REG(&uc, REG_RSP);
+ lxrp->lxur_xss = LX_REG(&uc, REG_SS);
+ lxrp->lxur_xfs_base = LX_REG(&uc, REG_FSBASE);
+ lxrp->lxur_xgs_base = LX_REG(&uc, REG_GSBASE);
+
+ lxrp->lxur_xds = LX_REG(&uc, REG_DS);
+ lxrp->lxur_xes = LX_REG(&uc, REG_ES);
+ lxrp->lxur_xfs = LX_REG(&uc, REG_FS);
+ lxrp->lxur_xgs = LX_REG(&uc, REG_GS);
+
+ /* emulated %cs, see defines */
+ lxrp->lxur_xcs = LX_CS_64BIT;
+ return (0);
+ }
- if (lx_write_uc(p, ucp, &uc, sizeof (uc)) != 0) {
- return (EIO);
+ case DATAMODEL_ILP32: {
+ ucontext32_t uc;
+
+ if (lx_read_uc(p, ucp, &uc, sizeof (uc)) != 0) {
+ return (-1);
}
- return (EIO);
+ lxrp->lxur_r15 = 0;
+ lxrp->lxur_r14 = 0;
+ lxrp->lxur_r13 = 0;
+ lxrp->lxur_r12 = 0;
+ lxrp->lxur_r11 = 0;
+ lxrp->lxur_r10 = 0;
+ lxrp->lxur_r9 = 0;
+ lxrp->lxur_r8 = 0;
+ lxrp->lxur_rbp = LX_REG(&uc, EBP);
+ lxrp->lxur_rbx = LX_REG(&uc, EBX);
+ lxrp->lxur_rax = LX_REG(&uc, EAX);
+ lxrp->lxur_orig_rax = 0;
+ lxrp->lxur_rcx = LX_REG(&uc, ECX);
+ lxrp->lxur_rdx = LX_REG(&uc, EDX);
+ lxrp->lxur_rsi = LX_REG(&uc, ESI);
+ lxrp->lxur_rdi = LX_REG(&uc, EDI);
+ lxrp->lxur_rip = LX_REG(&uc, EIP);
+
+ lxrp->lxur_rflags = LX_REG(&uc, EFL);
+ lxrp->lxur_rsp = LX_REG(&uc, UESP);
+ lxrp->lxur_xss = LX_REG(&uc, SS);
+ lxrp->lxur_xfs_base = 0;
+ lxrp->lxur_xgs_base = 0;
+
+ lxrp->lxur_xds = LX_REG(&uc, DS);
+ lxrp->lxur_xes = LX_REG(&uc, ES);
+ lxrp->lxur_xfs = LX_REG(&uc, FS);
+ lxrp->lxur_xgs = LX_REG(&uc, GS);
+
+ /* See comment above re: %cs register */
+ lxrp->lxur_xcs = LX_CS_32BIT;
+ return (0);
}
default:
- return (EIO);
+ break;
}
-#else
- cmn_err(CE_WARN, "%s: no 32-bit kernel support", __FUNCTION__);
- exit(CLD_KILLED, SIGSYS);
- return (EIO);
-#endif /* __amd64 */
+
+ return (-1);
}
-/*
- * Copy register state from a ucontext_t in the tracee to a usermode
- * "lx_user_regs_t" in the tracer.
- */
-int
-lx_uc_to_userregs(lx_lwp_data_t *lwpd, void *ucp, void *uregsp)
+static int
+lx_get_user_regs64(lx_lwp_data_t *lwpd, lx_user_regs64_t *lxrp)
{
-#if defined(__amd64)
klwp_t *lwp = lwpd->br_lwp;
- proc_t *p = lwptoproc(lwp);
+ struct regs *rp = lwptoregs(lwp);
+ struct pcb *pcb = &lwp->lwp_pcb;
+ void *ucp;
- switch (get_udatamodel()) {
- case DATAMODEL_LP64: {
- lx_user_regs_t lxur;
+ switch (lx_regs_location(lwpd, &ucp, B_FALSE)) {
+ case LX_REG_LOC_UNAVAIL:
+ return (-1);
- switch (lwp_getdatamodel(lwp)) {
- case DATAMODEL_LP64: {
- ucontext_t uc;
+ case LX_REG_LOC_UCP:
+ return (lx_get_user_regs64_uc(lwp, ucp, lxrp));
- if (lx_read_uc(p, ucp, &uc, sizeof (uc)) != 0) {
- return (EIO);
- }
+ case LX_REG_LOC_LWP:
+ /* transformation below */
+ break;
- lxur.lxur_r15 = LX_REG(&uc, REG_R15);
- lxur.lxur_r14 = LX_REG(&uc, REG_R14);
- lxur.lxur_r13 = LX_REG(&uc, REG_R13);
- lxur.lxur_r12 = LX_REG(&uc, REG_R12);
- lxur.lxur_rbp = LX_REG(&uc, REG_RBP);
- lxur.lxur_rbx = LX_REG(&uc, REG_RBX);
- lxur.lxur_r11 = LX_REG(&uc, REG_R11);
- lxur.lxur_r10 = LX_REG(&uc, REG_R10);
- lxur.lxur_r9 = LX_REG(&uc, REG_R9);
- lxur.lxur_r8 = LX_REG(&uc, REG_R8);
- lxur.lxur_rax = LX_REG(&uc, REG_RAX);
- lxur.lxur_rcx = LX_REG(&uc, REG_RCX);
- lxur.lxur_rdx = LX_REG(&uc, REG_RDX);
- lxur.lxur_rsi = LX_REG(&uc, REG_RSI);
- lxur.lxur_rdi = LX_REG(&uc, REG_RDI);
- lxur.lxur_orig_rax = 0;
- lxur.lxur_rip = LX_REG(&uc, REG_RIP);
- /*
- * strace on some releases (e.g. centos) uses the %cs
- * value to determine what kind of process is being
- * traced. Here is a sample comment:
- * Check CS register value. On x86-64 linux it is:
- * 0x33 for long mode (64 bit and x32))
- * 0x23 for compatibility mode (32 bit)
- * %ds = 0x2b for x32 mode (x86-64 in 32 bit)
- * We can't change the %cs value in the ucp (see
- * setgregs and _sys_rtt) so we emulate the expected
- * value for ptrace use.
- */
- lxur.lxur_xcs = 0x33;
- lxur.lxur_rflags = LX_REG(&uc, REG_RFL);
- lxur.lxur_rsp = LX_REG(&uc, REG_RSP);
- lxur.lxur_xss = LX_REG(&uc, REG_SS);
- lxur.lxur_xfs_base = LX_REG(&uc, REG_FSBASE);
- lxur.lxur_xgs_base = LX_REG(&uc, REG_GSBASE);
-
- lxur.lxur_xds = LX_REG(&uc, REG_DS);
- lxur.lxur_xes = LX_REG(&uc, REG_ES);
- lxur.lxur_xfs = LX_REG(&uc, REG_FS);
- lxur.lxur_xgs = LX_REG(&uc, REG_GS);
-
- if (copyout(&lxur, uregsp, sizeof (lxur)) != 0) {
- return (EFAULT);
- }
+ default:
+ VERIFY(0);
+ break;
+ }
- return (0);
- }
+ lxrp->lxur_r15 = rp->r_r15;
+ lxrp->lxur_r14 = rp->r_r14;
+ lxrp->lxur_r13 = rp->r_r13;
+ lxrp->lxur_r12 = rp->r_r12;
+ lxrp->lxur_rbp = rp->r_rbp;
+ lxrp->lxur_rbx = rp->r_rbx;
+ lxrp->lxur_r11 = rp->r_r11;
+ lxrp->lxur_r10 = rp->r_r10;
+ lxrp->lxur_r9 = rp->r_r9;
+ lxrp->lxur_r8 = rp->r_r8;
+ lxrp->lxur_rax = rp->r_rax;
+ lxrp->lxur_rcx = rp->r_rcx;
+ lxrp->lxur_rdx = rp->r_rdx;
+ lxrp->lxur_rsi = rp->r_rsi;
+ lxrp->lxur_rdi = rp->r_rdi;
+ lxrp->lxur_orig_rax = 0;
+ lxrp->lxur_rip = rp->r_rip;
+
+ lxrp->lxur_rflags = rp->r_rfl;
+ lxrp->lxur_rsp = rp->r_rsp;
+ lxrp->lxur_xss = rp->r_ss;
+ lxrp->lxur_xfs_base = pcb->pcb_fsbase;
+ lxrp->lxur_xgs_base = pcb->pcb_gsbase;
+
+ /* emulated %cs, see defines */
+ switch (lwp_getdatamodel(lwp)) {
+ case DATAMODEL_LP64:
+ lxrp->lxur_xcs = LX_CS_64BIT;
+ break;
+ case DATAMODEL_ILP32:
+ lxrp->lxur_xcs = LX_CS_32BIT;
+ break;
+ default:
+ VERIFY(0);
+ break;
+ }
- case DATAMODEL_ILP32: {
- ucontext32_t uc;
+ kpreempt_disable();
+ if (pcb->pcb_rupdate == 1) {
+ lxrp->lxur_xds = pcb->pcb_ds;
+ lxrp->lxur_xes = pcb->pcb_es;
+ lxrp->lxur_xfs = pcb->pcb_fs;
+ lxrp->lxur_xgs = pcb->pcb_gs;
+ } else {
+ lxrp->lxur_xds = rp->r_ds;
+ lxrp->lxur_xes = rp->r_es;
+ lxrp->lxur_xfs = rp->r_fs;
+ lxrp->lxur_xgs = rp->r_gs;
+ }
+ kpreempt_enable();
- if (lx_read_uc(p, ucp, &uc, sizeof (uc)) != 0) {
- return (EIO);
- }
+ if (lwpd->br_ptrace_whatstop == LX_PR_SYSENTRY) {
+ lxrp->lxur_rax = -lx_errno(ENOTSUP, EINVAL);
+ lxrp->lxur_orig_rax = lwpd->br_syscall_num;
+ } else if (lwpd->br_ptrace_whatstop == LX_PR_SYSEXIT) {
+ lxrp->lxur_orig_rax = lwpd->br_syscall_num;
+ }
- lxur.lxur_r15 = 0;
- lxur.lxur_r14 = 0;
- lxur.lxur_r13 = 0;
- lxur.lxur_r12 = 0;
- lxur.lxur_rbp = LX_REG(&uc, EBP);
- lxur.lxur_rbx = LX_REG(&uc, EBX);
- lxur.lxur_r11 = 0;
- lxur.lxur_r10 = 0;
- lxur.lxur_r9 = 0;
- lxur.lxur_r8 = 0;
- lxur.lxur_rax = LX_REG(&uc, EAX);
- lxur.lxur_rcx = LX_REG(&uc, ECX);
- lxur.lxur_rdx = LX_REG(&uc, EDX);
- lxur.lxur_rsi = LX_REG(&uc, ESI);
- lxur.lxur_rdi = LX_REG(&uc, EDI);
- lxur.lxur_orig_rax = 0;
- lxur.lxur_rip = LX_REG(&uc, EIP);
- /* See comment above re: %cs register */
- lxur.lxur_xcs = 0x23;
- lxur.lxur_rflags = LX_REG(&uc, EFL);
- lxur.lxur_rsp = LX_REG(&uc, UESP);
- lxur.lxur_xss = LX_REG(&uc, SS);
- lxur.lxur_xfs_base = 0;
- lxur.lxur_xgs_base = 0;
-
- lxur.lxur_xds = LX_REG(&uc, DS);
- lxur.lxur_xes = LX_REG(&uc, ES);
- lxur.lxur_xfs = LX_REG(&uc, FS);
- lxur.lxur_xgs = LX_REG(&uc, GS);
-
- if (copyout(&lxur, uregsp, sizeof (lxur)) != 0) {
- return (EFAULT);
- }
+ return (0);
+}
- return (0);
+static int
+lx_set_user_regs64_uc(klwp_t *lwp, void *ucp, lx_user_regs64_t *lxrp)
+{
+ proc_t *p = lwptoproc(lwp);
+
+ switch (lwp_getdatamodel(lwp)) {
+ case DATAMODEL_LP64: {
+ ucontext_t uc;
+
+ if (lx_read_uc(p, ucp, &uc, sizeof (uc)) != 0) {
+ return (-1);
}
- default:
- return (EIO);
+ /*
+ * Note: we currently ignore "lxur_orig_rax" here since this
+ * path should not be used for system call stops.
+ */
+ LX_REG(&uc, REG_R15) = lxrp->lxur_r15;
+ LX_REG(&uc, REG_R14) = lxrp->lxur_r14;
+ LX_REG(&uc, REG_R13) = lxrp->lxur_r13;
+ LX_REG(&uc, REG_R12) = lxrp->lxur_r12;
+ LX_REG(&uc, REG_RBP) = lxrp->lxur_rbp;
+ LX_REG(&uc, REG_RBX) = lxrp->lxur_rbx;
+ LX_REG(&uc, REG_R11) = lxrp->lxur_r11;
+ LX_REG(&uc, REG_R10) = lxrp->lxur_r10;
+ LX_REG(&uc, REG_R9) = lxrp->lxur_r9;
+ LX_REG(&uc, REG_R8) = lxrp->lxur_r8;
+ LX_REG(&uc, REG_RAX) = lxrp->lxur_rax;
+ LX_REG(&uc, REG_RCX) = lxrp->lxur_rcx;
+ LX_REG(&uc, REG_RDX) = lxrp->lxur_rdx;
+ LX_REG(&uc, REG_RSI) = lxrp->lxur_rsi;
+ LX_REG(&uc, REG_RDI) = lxrp->lxur_rdi;
+ LX_REG(&uc, REG_RIP) = lxrp->lxur_rip;
+ LX_REG(&uc, REG_RFL) = lxrp->lxur_rflags;
+ LX_REG(&uc, REG_RSP) = lxrp->lxur_rsp;
+ LX_REG(&uc, REG_SS) = lxrp->lxur_xss;
+ LX_REG(&uc, REG_FSBASE) = lxrp->lxur_xfs_base;
+ LX_REG(&uc, REG_GSBASE) = lxrp->lxur_xgs_base;
+
+ /* %cs is ignored because of our lies */
+ LX_REG(&uc, REG_DS) = lxrp->lxur_xds;
+ LX_REG(&uc, REG_ES) = lxrp->lxur_xes;
+ LX_REG(&uc, REG_FS) = lxrp->lxur_xfs;
+ LX_REG(&uc, REG_GS) = lxrp->lxur_xgs;
+
+ if (lx_write_uc(p, ucp, &uc, sizeof (uc)) != 0) {
+ return (-1);
}
+
+ return (0);
}
case DATAMODEL_ILP32: {
- lx_user_regs32_t lxur;
ucontext32_t uc;
- if (lwp_getdatamodel(lwp) != DATAMODEL_ILP32) {
- /*
- * The target is not a 32-bit LWP. We refuse to
- * present truncated 64-bit registers to a 32-bit
- * tracer.
- */
- return (EIO);
- }
-
if (lx_read_uc(p, ucp, &uc, sizeof (uc)) != 0) {
- return (EIO);
+ return (-1);
}
- lxur.lxur_ebx = LX_REG(&uc, EBX);
- lxur.lxur_ecx = LX_REG(&uc, ECX);
- lxur.lxur_edx = LX_REG(&uc, EDX);
- lxur.lxur_esi = LX_REG(&uc, ESI);
- lxur.lxur_edi = LX_REG(&uc, EDI);
- lxur.lxur_ebp = LX_REG(&uc, EBP);
- lxur.lxur_eax = LX_REG(&uc, EAX);
- lxur.lxur_orig_eax = 0;
- lxur.lxur_eip = LX_REG(&uc, EIP);
- /* See comment above re: %cs register */
- lxur.lxur_xcs = 0x23;
- lxur.lxur_eflags = LX_REG(&uc, EFL);
- lxur.lxur_esp = LX_REG(&uc, UESP);
- lxur.lxur_xss = LX_REG(&uc, SS);
-
- lxur.lxur_xds = LX_REG(&uc, DS);
- lxur.lxur_xes = LX_REG(&uc, ES);
- lxur.lxur_xfs = LX_REG(&uc, FS);
- lxur.lxur_xgs = LX_REG(&uc, GS);
-
- if (copyout(&lxur, uregsp, sizeof (lxur)) != 0) {
- return (EFAULT);
- }
+ /*
+ * Note: we currently ignore "lxur_orig_rax" here since this
+ * path should not be used for system call stops.
+ */
+ LX_REG(&uc, EBP) = (int32_t)lxrp->lxur_rbp;
+ LX_REG(&uc, EBX) = (int32_t)lxrp->lxur_rbx;
+ LX_REG(&uc, EAX) = (int32_t)lxrp->lxur_rax;
+ LX_REG(&uc, ECX) = (int32_t)lxrp->lxur_rcx;
+ LX_REG(&uc, EDX) = (int32_t)lxrp->lxur_rdx;
+ LX_REG(&uc, ESI) = (int32_t)lxrp->lxur_rsi;
+ LX_REG(&uc, EDI) = (int32_t)lxrp->lxur_rdi;
+ LX_REG(&uc, EIP) = (int32_t)lxrp->lxur_rip;
+ LX_REG(&uc, EFL) = (int32_t)lxrp->lxur_rflags;
+ LX_REG(&uc, UESP) = (int32_t)lxrp->lxur_rsp;
+ LX_REG(&uc, SS) = (int32_t)lxrp->lxur_xss;
+
+ /* %cs is ignored because of our lies */
+ LX_REG(&uc, DS) = (int32_t)lxrp->lxur_xds;
+ LX_REG(&uc, ES) = (int32_t)lxrp->lxur_xes;
+ LX_REG(&uc, FS) = (int32_t)lxrp->lxur_xfs;
+ LX_REG(&uc, GS) = (int32_t)lxrp->lxur_xgs;
+ if (lx_write_uc(p, ucp, &uc, sizeof (uc)) != 0) {
+ return (-1);
+ }
return (0);
}
default:
- return (EIO);
+ break;
}
-#else
- cmn_err(CE_WARN, "%s: no 32-bit kernel support", __FUNCTION__);
- exit(CLD_KILLED, SIGSYS);
- return (EIO);
-#endif
+
+ return (-1);
}
-/*
- * Load a usermode "lx_user_regs_t" into the register state of the target LWP.
- */
-int
-lx_userregs_to_regs(lx_lwp_data_t *lwpd, void *uregsp)
+static int
+lx_set_user_regs64(lx_lwp_data_t *lwpd, lx_user_regs64_t *lxrp)
{
klwp_t *lwp = lwpd->br_lwp;
- proc_t *p = lwptoproc(lwp);
-
- VERIFY(MUTEX_HELD(&p->p_lock));
-
-#if defined(__amd64)
struct regs *rp = lwptoregs(lwp);
struct pcb *pcb = &lwp->lwp_pcb;
+ void *ucp;
- switch (get_udatamodel()) {
- case DATAMODEL_LP64: {
- lx_user_regs_t lxur;
+ switch (lx_regs_location(lwpd, &ucp, B_TRUE)) {
+ case LX_REG_LOC_UNAVAIL:
+ return (-1);
- if (copyin(uregsp, &lxur, sizeof (lxur)) != 0) {
- return (EFAULT);
- }
+ case LX_REG_LOC_UCP:
+ return (lx_set_user_regs64_uc(lwp, ucp, lxrp));
+
+ case LX_REG_LOC_LWP:
+ /* transformation below */
+ break;
- rp->r_r15 = lxur.lxur_r15;
- rp->r_r14 = lxur.lxur_r14;
- rp->r_r13 = lxur.lxur_r13;
- rp->r_r12 = lxur.lxur_r12;
- rp->r_rbp = lxur.lxur_rbp;
- rp->r_rbx = lxur.lxur_rbx;
- rp->r_r11 = lxur.lxur_r11;
- rp->r_r10 = lxur.lxur_r10;
- rp->r_r9 = lxur.lxur_r9;
- rp->r_r8 = lxur.lxur_r8;
- rp->r_rax = lxur.lxur_rax;
- rp->r_rcx = lxur.lxur_rcx;
- rp->r_rdx = lxur.lxur_rdx;
- rp->r_rsi = lxur.lxur_rsi;
- rp->r_rdi = lxur.lxur_rdi;
- lwpd->br_syscall_num = (int)lxur.lxur_orig_rax;
- rp->r_rip = lxur.lxur_rip;
- rp->r_rfl = lxur.lxur_rflags;
- rp->r_rsp = lxur.lxur_rsp;
- rp->r_ss = lxur.lxur_xss;
- pcb->pcb_fsbase = lxur.lxur_xfs_base;
- pcb->pcb_gsbase = lxur.lxur_xgs_base;
+ default:
+ VERIFY(0);
+ break;
+ }
- kpreempt_disable();
- pcb->pcb_rupdate = 1;
- pcb->pcb_ds = lxur.lxur_xds;
- pcb->pcb_es = lxur.lxur_xes;
- pcb->pcb_fs = lxur.lxur_xfs;
- pcb->pcb_gs = lxur.lxur_xgs;
- kpreempt_enable();
+ rp->r_r15 = lxrp->lxur_r15;
+ rp->r_r14 = lxrp->lxur_r14;
+ rp->r_r13 = lxrp->lxur_r13;
+ rp->r_r12 = lxrp->lxur_r12;
+ rp->r_rbp = lxrp->lxur_rbp;
+ rp->r_rbx = lxrp->lxur_rbx;
+ rp->r_r11 = lxrp->lxur_r11;
+ rp->r_r10 = lxrp->lxur_r10;
+ rp->r_r9 = lxrp->lxur_r9;
+ rp->r_r8 = lxrp->lxur_r8;
+ rp->r_rax = lxrp->lxur_rax;
+ rp->r_rcx = lxrp->lxur_rcx;
+ rp->r_rdx = lxrp->lxur_rdx;
+ rp->r_rsi = lxrp->lxur_rsi;
+ rp->r_rdi = lxrp->lxur_rdi;
+ lwpd->br_syscall_num = (int)lxrp->lxur_orig_rax;
+ rp->r_rip = lxrp->lxur_rip;
+ rp->r_rfl = lxrp->lxur_rflags;
+ rp->r_rsp = lxrp->lxur_rsp;
+ rp->r_ss = lxrp->lxur_xss;
+ pcb->pcb_fsbase = lxrp->lxur_xfs_base;
+ pcb->pcb_gsbase = lxrp->lxur_xgs_base;
+
+ kpreempt_disable();
+ pcb->pcb_rupdate = 1;
+ pcb->pcb_ds = lxrp->lxur_xds;
+ pcb->pcb_es = lxrp->lxur_xes;
+ pcb->pcb_fs = lxrp->lxur_xfs;
+ pcb->pcb_gs = lxrp->lxur_xgs;
+ kpreempt_enable();
+
+ return (0);
+}
+
+#endif /* __amd64 */
+static int
+lx_peekuser32(lx_lwp_data_t *lwpd, uintptr_t offset, uint32_t *res)
+{
+ lx_user32_t lxu;
+ boolean_t valid = B_FALSE;
+
+ bzero(&lxu, sizeof (lxu));
+ if (offset < sizeof (lx_user_regs32_t)) {
+ if (lx_get_user_regs32(lwpd, &lxu.lxu_regs) == 0) {
+ valid = B_TRUE;
+ }
+ }
+ if (valid) {
+ uint32_t *data = (uint32_t *)&lxu;
+ *res = data[offset / sizeof (uint32_t)];
return (0);
}
+ return (-1);
+}
- case DATAMODEL_ILP32: {
- lx_user_regs32_t lxur;
-
- if (lwp_getdatamodel(lwp) != DATAMODEL_ILP32) {
- /*
- * The target is not a 32-bit LWP. We refuse to
- * present truncated 64-bit registers to a 32-bit
- * tracer.
- */
- return (EIO);
+#ifdef __amd64
+static int
+lx_peekuser64(lx_lwp_data_t *lwpd, uintptr_t offset, uintptr_t *res)
+{
+ lx_user64_t lxu;
+ boolean_t valid = B_FALSE;
+
+ bzero(&lxu, sizeof (lxu));
+ if (offset < sizeof (lx_user_regs64_t)) {
+ lx_user_regs64_t regs;
+ if (lx_get_user_regs64(lwpd, &regs) == 0) {
+ valid = B_TRUE;
}
+ }
+ if (valid) {
+ uintptr_t *data = (uintptr_t *)&lxu;
+ *res = data[offset / sizeof (uintptr_t)];
+ return (0);
+ }
+ return (-1);
+}
+#endif /* __amd64 */
+
+int
+lx_user_regs_copyin(lx_lwp_data_t *lwpd, void *uregsp)
+{
+ model_t target_model = lwp_getdatamodel(lwpd->br_lwp);
+
+ switch (get_udatamodel()) {
+ case DATAMODEL_ILP32:
+ if (target_model == DATAMODEL_ILP32) {
+ lx_user_regs32_t regs;
- if (copyin(uregsp, &lxur, sizeof (lxur)) != 0) {
- return (EFAULT);
+ if (copyin(uregsp, &regs, sizeof (regs)) != 0) {
+ return (EFAULT);
+ }
+ if (lx_set_user_regs32(lwpd, &regs) != 0) {
+ return (EIO);
+ }
+ return (0);
}
- rp->r_rbx = lxur.lxur_ebx;
- rp->r_rcx = lxur.lxur_ecx;
- rp->r_rdx = lxur.lxur_edx;
- rp->r_rsi = lxur.lxur_esi;
- rp->r_rdi = lxur.lxur_edi;
- rp->r_rbp = lxur.lxur_ebp;
- rp->r_rax = lxur.lxur_eax;
- lwpd->br_syscall_num = (int)lxur.lxur_orig_eax;
- rp->r_rip = lxur.lxur_eip;
- rp->r_rfl = lxur.lxur_eflags;
- rp->r_rsp = lxur.lxur_esp;
- rp->r_ss = lxur.lxur_xss;
+#ifdef __amd64
+ case DATAMODEL_LP64:
+ if (target_model == DATAMODEL_ILP32 ||
+ target_model == DATAMODEL_LP64) {
+ lx_user_regs64_t regs;
- kpreempt_disable();
- pcb->pcb_rupdate = 1;
- pcb->pcb_ds = lxur.lxur_xds;
- pcb->pcb_es = lxur.lxur_xes;
- pcb->pcb_fs = lxur.lxur_xfs;
- pcb->pcb_gs = lxur.lxur_xgs;
- kpreempt_enable();
+ if (copyin(uregsp, &regs, sizeof (regs)) != 0) {
+ return (EFAULT);
+ }
+ if (lx_set_user_regs64(lwpd, &regs) != 0) {
+ return (EIO);
+ }
+ return (0);
+ }
+ break;
+#endif /* __amd64 */
- return (0);
+ default:
+ break;
}
+ return (EIO);
+}
+
+int
+lx_user_regs_copyout(lx_lwp_data_t *lwpd, void *uregsp)
+{
+ model_t target_model = lwp_getdatamodel(lwpd->br_lwp);
+
+ switch (get_udatamodel()) {
+ case DATAMODEL_ILP32:
+ if (target_model == DATAMODEL_ILP32) {
+ lx_user_regs32_t regs;
+
+ if (lx_get_user_regs32(lwpd, &regs) != 0) {
+ return (EIO);
+ }
+ if (copyout(&regs, uregsp, sizeof (regs)) != 0) {
+ return (EFAULT);
+ }
+ return (0);
+ }
+
+#ifdef __amd64
+ case DATAMODEL_LP64:
+ if (target_model == DATAMODEL_ILP32 ||
+ target_model == DATAMODEL_LP64) {
+ lx_user_regs64_t regs;
+
+ if (lx_get_user_regs64(lwpd, &regs) != 0) {
+ return (EIO);
+ }
+ if (copyout(&regs, uregsp, sizeof (regs)) != 0) {
+ return (EFAULT);
+ }
+ return (0);
+ }
+ break;
+#endif /* __amd64 */
default:
- return (EIO);
+ break;
}
-#else
- cmn_err(CE_WARN, "%s: no 32-bit kernel support", __FUNCTION__);
- exit(CLD_KILLED, SIGSYS);
return (EIO);
-#endif /* __amd64 */
}
-/*
- * Copy the current LWP register state of the target LWP to a usermode
- * "lx_user_regs_t".
- */
int
-lx_regs_to_userregs(lx_lwp_data_t *lwpd, void *uregsp)
+lx_user_fpregs_copyin(lx_lwp_data_t *lwpd, void *uregsp)
{
-#if defined(__amd64)
- klwp_t *lwp = lwpd->br_lwp;
- struct regs *rp = lwptoregs(lwp);
- proc_t *p = lwptoproc(lwp);
+ model_t target_model = lwp_getdatamodel(lwpd->br_lwp);
- VERIFY(MUTEX_HELD(&p->p_lock));
+ switch (get_udatamodel()) {
+ case DATAMODEL_ILP32:
+ if (target_model == DATAMODEL_ILP32) {
+ lx_user_fpregs32_t regs;
- struct pcb *pcb = &lwp->lwp_pcb;
- long r0, orig_r0;
+ if (copyin(uregsp, &regs, sizeof (regs)) != 0) {
+ return (EFAULT);
+ }
+ lx_setfpregs32(lwpd, &regs);
+ return (0);
+ }
- /*
- * We must precisely emulate the "syscall-entry-stop" and
- * "syscall-exit-stop" register appearance from the Linux kernel.
- */
- switch (lwpd->br_ptrace_whatstop) {
- case LX_PR_SYSENTRY:
- orig_r0 = lwpd->br_syscall_num;
- r0 = -lx_errno(ENOTSUP, EINVAL);
- break;
- case LX_PR_SYSEXIT:
- orig_r0 = lwpd->br_syscall_num;
- r0 = rp->r_rax;
+#ifdef __amd64
+ case DATAMODEL_LP64:
+ if (target_model == DATAMODEL_ILP32 ||
+ target_model == DATAMODEL_LP64) {
+ lx_user_fpregs64_t regs;
+
+ if (copyin(uregsp, &regs, sizeof (regs)) != 0) {
+ return (EFAULT);
+ }
+ lx_setfpregs64(lwpd, &regs);
+ return (0);
+ }
break;
+#endif /* __amd64 */
+
default:
- orig_r0 = 0;
- r0 = rp->r_rax;
+ break;
}
+ return (EIO);
+}
+
+int
+lx_user_fpregs_copyout(lx_lwp_data_t *lwpd, void *uregsp)
+{
+ model_t target_model = lwp_getdatamodel(lwpd->br_lwp);
switch (get_udatamodel()) {
- case DATAMODEL_LP64: {
- lx_user_regs_t lxur;
-
- lxur.lxur_r15 = rp->r_r15;
- lxur.lxur_r14 = rp->r_r14;
- lxur.lxur_r13 = rp->r_r13;
- lxur.lxur_r12 = rp->r_r12;
- lxur.lxur_rbp = rp->r_rbp;
- lxur.lxur_rbx = rp->r_rbx;
- lxur.lxur_r11 = rp->r_r11;
- lxur.lxur_r10 = rp->r_r10;
- lxur.lxur_r9 = rp->r_r9;
- lxur.lxur_r8 = rp->r_r8;
- lxur.lxur_rax = r0;
- lxur.lxur_rcx = rp->r_rcx;
- lxur.lxur_rdx = rp->r_rdx;
- lxur.lxur_rsi = rp->r_rsi;
- lxur.lxur_rdi = rp->r_rdi;
- lxur.lxur_orig_rax = orig_r0;
- lxur.lxur_rip = rp->r_rip;
- /*
- * strace on some releases (e.g. centos) uses the %cs value to
- * determine what kind of process is being traced. Here is a
- * sample comment:
- * Check CS register value. On x86-64 linux it is:
- * 0x33 for long mode (64 bit and x32))
- * 0x23 for compatibility mode (32 bit)
- * %ds = 0x2b for x32 mode (x86-64 in 32 bit)
- * We can't change the %cs value in the ucp (see setgregs and
- * _sys_rtt) so we emulate the expected value for ptrace use.
- */
- if (lwp_getdatamodel(lwp) == DATAMODEL_ILP32) {
- lxur.lxur_xcs = 0x23;
- } else {
- lxur.lxur_xcs = 0x33;
- }
- lxur.lxur_rflags = rp->r_rfl;
- lxur.lxur_rsp = rp->r_rsp;
- lxur.lxur_xss = rp->r_ss;
- lxur.lxur_xfs_base = pcb->pcb_fsbase;
- lxur.lxur_xgs_base = pcb->pcb_gsbase;
+ case DATAMODEL_ILP32:
+ if (target_model == DATAMODEL_ILP32) {
+ lx_user_fpregs32_t regs;
- kpreempt_disable();
- if (pcb->pcb_rupdate == 1) {
- lxur.lxur_xds = pcb->pcb_ds;
- lxur.lxur_xes = pcb->pcb_es;
- lxur.lxur_xfs = pcb->pcb_fs;
- lxur.lxur_xgs = pcb->pcb_gs;
- } else {
- lxur.lxur_xds = rp->r_ds;
- lxur.lxur_xes = rp->r_es;
- lxur.lxur_xfs = rp->r_fs;
- lxur.lxur_xgs = rp->r_gs;
+ lx_getfpregs32(lwpd, &regs);
+ if (copyout(&regs, uregsp, sizeof (regs)) != 0) {
+ return (EFAULT);
+ }
+ return (0);
}
- kpreempt_enable();
- if (copyout(&lxur, uregsp, sizeof (lxur)) != 0) {
- return (EFAULT);
+#ifdef __amd64
+ case DATAMODEL_LP64:
+ if (target_model == DATAMODEL_ILP32 ||
+ target_model == DATAMODEL_LP64) {
+ lx_user_fpregs64_t regs;
+
+ lx_getfpregs64(lwpd, &regs);
+ if (copyout(&regs, uregsp, sizeof (regs)) != 0) {
+ return (EFAULT);
+ }
+ return (0);
}
+ break;
+#endif /* __amd64 */
- return (0);
+ default:
+ break;
}
+ return (EIO);
+}
- case DATAMODEL_ILP32: {
- lx_user_regs32_t lxur;
+int
+lx_user_fpxregs_copyin(lx_lwp_data_t *lwpd, void *uregsp)
+{
+ /* Punt on fpxregs for now */
+ return (EIO);
+}
- if (lwp_getdatamodel(lwp) != DATAMODEL_ILP32) {
- /*
- * The target is not a 32-bit LWP. We refuse to
- * present truncated 64-bit registers to a 32-bit
- * tracer.
- */
- return (EIO);
- }
+int
+lx_user_fpxregs_copyout(lx_lwp_data_t *lwpd, void *uregsp)
+{
+ /* Punt on fpxregs for now */
+ return (EIO);
+}
- lxur.lxur_ebx = (int32_t)rp->r_rbx;
- lxur.lxur_ecx = (int32_t)rp->r_rcx;
- lxur.lxur_edx = (int32_t)rp->r_rdx;
- lxur.lxur_esi = (int32_t)rp->r_rsi;
- lxur.lxur_edi = (int32_t)rp->r_rdi;
- lxur.lxur_ebp = (int32_t)rp->r_rbp;
- lxur.lxur_eax = (int32_t)r0;
- lxur.lxur_orig_eax = (int32_t)orig_r0;
- lxur.lxur_eip = (int32_t)rp->r_rip;
- /* See comment above for 64-bit datamodel */
- lxur.lxur_xcs = 0x23;
- lxur.lxur_eflags = (int32_t)rp->r_rfl;
- lxur.lxur_esp = (int32_t)rp->r_rsp;
- lxur.lxur_xss = (int32_t)rp->r_ss;
+int
+lx_ptrace_peekuser(lx_lwp_data_t *lwpd, uintptr_t offset, void *uptr)
+{
+ model_t target_model = lwp_getdatamodel(lwpd->br_lwp);
- kpreempt_disable();
- if (pcb->pcb_rupdate == 1) {
- lxur.lxur_xds = pcb->pcb_ds;
- lxur.lxur_xes = pcb->pcb_es;
- lxur.lxur_xfs = pcb->pcb_fs;
- lxur.lxur_xgs = pcb->pcb_gs;
- } else {
- lxur.lxur_xds = rp->r_ds;
- lxur.lxur_xes = rp->r_es;
- lxur.lxur_xfs = rp->r_fs;
- lxur.lxur_xgs = rp->r_gs;
+ switch (get_udatamodel()) {
+ case DATAMODEL_ILP32:
+ if ((offset & (sizeof (uint32_t) - 1)) != 0) {
+ /* Must be aligned to 32bit boundary */
+ break;
}
- kpreempt_enable();
+ if (target_model == DATAMODEL_ILP32) {
+ uint32_t res;
- if (copyout(&lxur, uregsp, sizeof (lxur)) != 0) {
- return (EFAULT);
+ if (lx_peekuser32(lwpd, offset, &res) != 0) {
+ return (EIO);
+ }
+ if (copyout(&res, uptr, sizeof (res)) != 0) {
+ return (EFAULT);
+ }
+ return (0);
}
- return (0);
- }
+#ifdef __amd64
+ case DATAMODEL_LP64:
+ if ((offset & (sizeof (uintptr_t) - 1)) != 0) {
+ /* Must be aligned to 64bit boundary */
+ break;
+ }
+ if (target_model == DATAMODEL_ILP32 ||
+ target_model == DATAMODEL_LP64) {
+ uintptr_t res;
+
+ if (lx_peekuser64(lwpd, offset, &res) != 0) {
+ return (EIO);
+ }
+ if (copyout(&res, uptr, sizeof (res)) != 0) {
+ return (EFAULT);
+ }
+ return (0);
+ }
+ break;
+#endif /* __amd64 */
default:
- return (EIO);
+ break;
}
-#else
- cmn_err(CE_WARN, "%s: no 32-bit kernel support", __FUNCTION__);
- exit(CLD_KILLED, SIGSYS);
return (EIO);
-#endif /* __amd64 */
}
+int
+lx_ptrace_pokeuser(lx_lwp_data_t *lwpd, uintptr_t offset, void *uptr)
+{
+ return (EIO);
+}
+
+
/*
* Load registers and repoint the stack and program counter. This function is
* used by the B_JUMP_TO_LINUX brand system call to revector to a Linux