📄 plwpregs.c
字号:
/* * Copyright 2005 Sun Microsystems, Inc. All rights reserved. * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only. * See the file usr/src/LICENSING.NOTICE in this distribution or * http://www.opensolaris.org/license/ for details. */#pragma ident "@(#)Plwpregs.c 1.5 03/07/09 SMI"#include <sys/types.h>#include <sys/uio.h>#include <string.h>#include <errno.h>#include "Pcontrol.h"#include "P32ton.h"/* * This file implements the routines to read and write per-lwp register * information from either a live process or core file opened with libproc. * We build up a few common routines for reading and writing register * information, and then the public functions are all trivial calls to these. *//* * Utility function to return a pointer to the structure of cached information * about an lwp in the core file, given its lwpid. */static lwp_info_t *getlwpcore(struct ps_prochandle *P, lwpid_t lwpid){ lwp_info_t *lwp = list_next(&P->core->core_lwp_head); uint_t i; for (i = 0; i < P->core->core_nlwp; i++, lwp = list_next(lwp)) { if (lwp->lwp_id == lwpid) return (lwp); } errno = EINVAL; return (NULL);}/* * Utility function to open and read the contents of a per-lwp /proc file. * This function is used to slurp in lwpstatus, xregs, and asrs. */static intgetlwpfile(struct ps_prochandle *P, lwpid_t lwpid, const char *fbase, void *rp, size_t n){ char fname[64]; int fd; if (P->state != PS_STOP) { errno = EBUSY; return (-1); } (void) snprintf(fname, sizeof (fname), "/proc/%d/lwp/%d/%s", (int)P->status.pr_pid, (int)lwpid, fbase); if ((fd = open(fname, O_RDONLY)) >= 0) { if (read(fd, rp, n) > 0) { (void) close(fd); return (0); } (void) close(fd); } return (-1);}/* * Get the lwpstatus_t for an lwp from either the live process or our * cached information from the core file. This is used to get the * general-purpose registers or floating point registers. */intgetlwpstatus(struct ps_prochandle *P, lwpid_t lwpid, lwpstatus_t *lps){ lwp_info_t *lwp; /* * For both live processes and cores, our job is easy if the lwpid * matches that of the representative lwp: */ if (P->status.pr_lwp.pr_lwpid == lwpid) { (void) memcpy(lps, &P->status.pr_lwp, sizeof (lwpstatus_t)); return (0); } /* * If this is a live process, then just read the information out * of the per-lwp status file: */ if (P->state != PS_DEAD) { return (getlwpfile(P, lwpid, "lwpstatus", lps, sizeof (lwpstatus_t))); } /* * If this is a core file, we need to iterate through our list of * cached lwp information and then copy out the status. */ if (P->core != NULL && (lwp = getlwpcore(P, lwpid)) != NULL) { (void) memcpy(lps, &lwp->lwp_status, sizeof (lwpstatus_t)); return (0); } return (-1);}/* * Utility function to modify lwp registers. This is done using either the * process control file or per-lwp control file as necessary. */static intsetlwpregs(struct ps_prochandle *P, lwpid_t lwpid, long cmd, const void *rp, size_t n){ iovec_t iov[2]; char fname[64]; int fd; if (P->state != PS_STOP) { errno = EBUSY; return (-1); } iov[0].iov_base = (caddr_t)&cmd; iov[0].iov_len = sizeof (long); iov[1].iov_base = (caddr_t)rp; iov[1].iov_len = n; /* * Writing the process control file writes the representative lwp. * Psync before we write to make sure we are consistent with the * primary interfaces. Similarly, make sure to update P->status * afterward if we are modifying one of its register sets. */ if (P->status.pr_lwp.pr_lwpid == lwpid) { Psync(P); if (writev(P->ctlfd, iov, 2) == -1) return (-1); if (cmd == PCSREG) (void) memcpy(P->status.pr_lwp.pr_reg, rp, n); else if (cmd == PCSFPREG) (void) memcpy(&P->status.pr_lwp.pr_fpreg, rp, n); return (0); } /* * If the lwp we want is not the representative lwp, we need to * open the ctl file for that specific lwp. */ (void) snprintf(fname, sizeof (fname), "/proc/%d/lwp/%d/lwpctl", (int)P->status.pr_pid, (int)lwpid); if ((fd = open(fname, O_WRONLY)) >= 0) { if (writev(fd, iov, 2) > 0) { (void) close(fd); return (0); } (void) close(fd); } return (-1);}intPlwp_getregs(struct ps_prochandle *P, lwpid_t lwpid, prgregset_t gregs){ lwpstatus_t lps; if (getlwpstatus(P, lwpid, &lps) == -1) return (-1); (void) memcpy(gregs, lps.pr_reg, sizeof (prgregset_t)); return (0);}intPlwp_setregs(struct ps_prochandle *P, lwpid_t lwpid, const prgregset_t gregs){ return (setlwpregs(P, lwpid, PCSREG, gregs, sizeof (prgregset_t)));}intPlwp_getfpregs(struct ps_prochandle *P, lwpid_t lwpid, prfpregset_t *fpregs){ lwpstatus_t lps; if (getlwpstatus(P, lwpid, &lps) == -1) return (-1); (void) memcpy(fpregs, &lps.pr_fpreg, sizeof (prfpregset_t)); return (0);}int Plwp_setfpregs(struct ps_prochandle *P, lwpid_t lwpid, const prfpregset_t *fpregs){ return (setlwpregs(P, lwpid, PCSFPREG, fpregs, sizeof (prfpregset_t)));}#if defined(sparc) || defined(__sparc)intPlwp_getxregs(struct ps_prochandle *P, lwpid_t lwpid, prxregset_t *xregs){ lwp_info_t *lwp; if (P->state == PS_IDLE) { errno = ENODATA; return (-1); } if (P->state != PS_DEAD) { return (getlwpfile(P, lwpid, "xregs", xregs, sizeof (prxregset_t))); } if ((lwp = getlwpcore(P, lwpid)) != NULL && lwp->lwp_xregs != NULL) { (void) memcpy(xregs, lwp->lwp_xregs, sizeof (prxregset_t)); return (0); } if (lwp != NULL) errno = ENODATA; return (-1);}intPlwp_setxregs(struct ps_prochandle *P, lwpid_t lwpid, const prxregset_t *xregs){ return (setlwpregs(P, lwpid, PCSXREG, xregs, sizeof (prxregset_t)));}intPlwp_getgwindows(struct ps_prochandle *P, lwpid_t lwpid, gwindows_t *gwins){ lwp_info_t *lwp; if (P->state == PS_IDLE) { errno = ENODATA; return (-1); } if (P->state != PS_DEAD) return (getlwpfile(P, lwpid, "gwindows", gwins, sizeof (gwindows_t))); if ((lwp = getlwpcore(P, lwpid)) != NULL && lwp->lwp_gwins != NULL) { *gwins = *lwp->lwp_gwins; return (0); } if (lwp != NULL) errno = ENODATA; return (-1);}#if defined(__sparcv9)intPlwp_getasrs(struct ps_prochandle *P, lwpid_t lwpid, asrset_t asrs){ lwp_info_t *lwp; if (P->state == PS_IDLE) { errno = ENODATA; return (-1); } if (P->state != PS_DEAD) return (getlwpfile(P, lwpid, "asrs", asrs, sizeof (asrset_t))); if ((lwp = getlwpcore(P, lwpid)) != NULL && lwp->lwp_asrs != NULL) { (void) memcpy(asrs, lwp->lwp_asrs, sizeof (asrset_t)); return (0); } if (lwp != NULL) errno = ENODATA; return (-1);}intPlwp_setasrs(struct ps_prochandle *P, lwpid_t lwpid, const asrset_t asrs){ return (setlwpregs(P, lwpid, PCSASRS, asrs, sizeof (asrset_t)));}#endif /* __sparcv9 */#endif /* __sparc */intPlwp_getpsinfo(struct ps_prochandle *P, lwpid_t lwpid, lwpsinfo_t *lps){ lwp_info_t *lwp; if (P->state == PS_IDLE) { errno = ENODATA; return (-1); } if (P->state != PS_DEAD) { return (getlwpfile(P, lwpid, "lwpsinfo", lps, sizeof (lwpsinfo_t))); } if ((lwp = getlwpcore(P, lwpid)) != NULL) { (void) memcpy(lps, &lwp->lwp_psinfo, sizeof (lwpsinfo_t)); return (0); } return (-1);}intPlwp_stack(struct ps_prochandle *P, lwpid_t lwpid, stack_t *stkp){ uintptr_t addr; if (P->state == PS_IDLE) { errno = ENODATA; return (-1); } if (P->state != PS_DEAD) { lwpstatus_t ls; if (getlwpfile(P, lwpid, "lwpstatus", &ls, sizeof (ls)) != 0) return (-1); addr = ls.pr_ustack; } else { lwp_info_t *lwp; if ((lwp = getlwpcore(P, lwpid)) == NULL) return (-1); addr = lwp->lwp_status.pr_ustack; } if (P->status.pr_dmodel == PR_MODEL_NATIVE) { if (Pread(P, stkp, sizeof (*stkp), addr) != sizeof (*stkp)) return (-1);#ifdef _LP64 } else { stack32_t stk32; if (Pread(P, &stk32, sizeof (stk32), addr) != sizeof (stk32)) return (-1); stack_32_to_n(&stk32, stkp);#endif } return (0);}intPlwp_main_stack(struct ps_prochandle *P, lwpid_t lwpid, stack_t *stkp){ uintptr_t addr; lwpstatus_t ls; if (P->state == PS_IDLE) { errno = ENODATA; return (-1); } if (P->state != PS_DEAD) { if (getlwpfile(P, lwpid, "lwpstatus", &ls, sizeof (ls)) != 0) return (-1); } else { lwp_info_t *lwp; if ((lwp = getlwpcore(P, lwpid)) == NULL) return (-1); ls = lwp->lwp_status; } addr = ls.pr_ustack; /* * Read out the current stack; if the SS_ONSTACK flag is set then * this LWP is operating on the alternate signal stack. We can * recover the original stack from pr_oldcontext. */ if (P->status.pr_dmodel == PR_MODEL_NATIVE) { if (Pread(P, stkp, sizeof (*stkp), addr) != sizeof (*stkp)) return (-1); if (stkp->ss_flags & SS_ONSTACK) goto on_altstack;#ifdef _LP64 } else { stack32_t stk32; if (Pread(P, &stk32, sizeof (stk32), addr) != sizeof (stk32)) return (-1); if (stk32.ss_flags & SS_ONSTACK) goto on_altstack; stack_32_to_n(&stk32, stkp);#endif } return (0);on_altstack: if (P->status.pr_dmodel == PR_MODEL_NATIVE) { ucontext_t *ctxp = (void *)ls.pr_oldcontext; if (Pread(P, stkp, sizeof (*stkp), (uintptr_t)&ctxp->uc_stack) != sizeof (*stkp)) return (-1);#ifdef _LP64 } else { ucontext32_t *ctxp = (void *)ls.pr_oldcontext; stack32_t stk32; if (Pread(P, &stk32, sizeof (stk32), (uintptr_t)&ctxp->uc_stack) != sizeof (stk32)) return (-1); stack_32_to_n(&stk32, stkp);#endif } return (0);}intPlwp_alt_stack(struct ps_prochandle *P, lwpid_t lwpid, stack_t *stkp){ if (P->state == PS_IDLE) { errno = ENODATA; return (-1); } if (P->state != PS_DEAD) { lwpstatus_t ls; if (getlwpfile(P, lwpid, "lwpstatus", &ls, sizeof (ls)) != 0) return (-1); if (ls.pr_altstack.ss_flags & SS_DISABLE) { errno = ENODATA; return (-1); } *stkp = ls.pr_altstack; } else { lwp_info_t *lwp; if ((lwp = getlwpcore(P, lwpid)) == NULL) return (-1); if (lwp->lwp_status.pr_altstack.ss_flags & SS_DISABLE) { errno = ENODATA; return (-1); } *stkp = lwp->lwp_status.pr_altstack; } return (0);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -