Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 182595
b: refs/heads/master
c: 2225a12
h: refs/heads/master
i:
  182593: 5500e82
  182591: 6169847
v: v3
  • Loading branch information
Suresh Siddha authored and H. Peter Anvin committed Feb 11, 2010
1 parent 28ae123 commit 3099918
Show file tree
Hide file tree
Showing 4 changed files with 109 additions and 2 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 5b3efd500854d45d305b53c54c97db5970959980
refs/heads/master: 2225a122ae26d542bdce523d9d87a4a7ba10e07b
6 changes: 5 additions & 1 deletion trunk/include/linux/elf.h
Original file line number Diff line number Diff line change
Expand Up @@ -349,7 +349,11 @@ typedef struct elf64_shdr {
#define ELF_OSABI ELFOSABI_NONE
#endif

/* Notes used in ET_CORE */
/*
* Notes used in ET_CORE. Architectures export some of the arch register sets
* using the corresponding note types via the PTRACE_GETREGSET and
* PTRACE_SETREGSET requests.
*/
#define NT_PRSTATUS 1
#define NT_PRFPREG 2
#define NT_PRPSINFO 3
Expand Down
15 changes: 15 additions & 0 deletions trunk/include/linux/ptrace.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,21 @@
#define PTRACE_GETSIGINFO 0x4202
#define PTRACE_SETSIGINFO 0x4203

/*
* Generic ptrace interface that exports the architecture specific regsets
* using the corresponding NT_* types (which are also used in the core dump).
*
* This interface usage is as follows:
* struct iovec iov = { buf, len};
*
* ret = ptrace(PTRACE_GETREGSET/PTRACE_SETREGSET, pid, NT_XXX_TYPE, &iov);
*
* On the successful completion, iov.len will be updated by the kernel,
* specifying how much the kernel has written/read to/from the user's iov.buf.
*/
#define PTRACE_GETREGSET 0x4204
#define PTRACE_SETREGSET 0x4205

/* options set using PTRACE_SETOPTIONS */
#define PTRACE_O_TRACESYSGOOD 0x00000001
#define PTRACE_O_TRACEFORK 0x00000002
Expand Down
88 changes: 88 additions & 0 deletions trunk/kernel/ptrace.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include <linux/pid_namespace.h>
#include <linux/syscalls.h>
#include <linux/uaccess.h>
#include <linux/regset.h>


/*
Expand Down Expand Up @@ -511,6 +512,47 @@ static int ptrace_resume(struct task_struct *child, long request, long data)
return 0;
}

#ifdef CONFIG_HAVE_ARCH_TRACEHOOK

static const struct user_regset *
find_regset(const struct user_regset_view *view, unsigned int type)
{
const struct user_regset *regset;
int n;

for (n = 0; n < view->n; ++n) {
regset = view->regsets + n;
if (regset->core_note_type == type)
return regset;
}

return NULL;
}

static int ptrace_regset(struct task_struct *task, int req, unsigned int type,
struct iovec *kiov)
{
const struct user_regset_view *view = task_user_regset_view(task);
const struct user_regset *regset = find_regset(view, type);
int regset_no;

if (!regset || (kiov->iov_len % regset->size) != 0)
return -EIO;

regset_no = regset - view->regsets;
kiov->iov_len = min(kiov->iov_len,
(__kernel_size_t) (regset->n * regset->size));

if (req == PTRACE_GETREGSET)
return copy_regset_to_user(task, view, regset_no, 0,
kiov->iov_len, kiov->iov_base);
else
return copy_regset_from_user(task, view, regset_no, 0,
kiov->iov_len, kiov->iov_base);
}

#endif

int ptrace_request(struct task_struct *child, long request,
long addr, long data)
{
Expand Down Expand Up @@ -573,6 +615,26 @@ int ptrace_request(struct task_struct *child, long request,
return 0;
return ptrace_resume(child, request, SIGKILL);

#ifdef CONFIG_HAVE_ARCH_TRACEHOOK
case PTRACE_GETREGSET:
case PTRACE_SETREGSET:
{
struct iovec kiov;
struct iovec __user *uiov = (struct iovec __user *) data;

if (!access_ok(VERIFY_WRITE, uiov, sizeof(*uiov)))
return -EFAULT;

if (__get_user(kiov.iov_base, &uiov->iov_base) ||
__get_user(kiov.iov_len, &uiov->iov_len))
return -EFAULT;

ret = ptrace_regset(child, request, addr, &kiov);
if (!ret)
ret = __put_user(kiov.iov_len, &uiov->iov_len);
break;
}
#endif
default:
break;
}
Expand Down Expand Up @@ -711,6 +773,32 @@ int compat_ptrace_request(struct task_struct *child, compat_long_t request,
else
ret = ptrace_setsiginfo(child, &siginfo);
break;
#ifdef CONFIG_HAVE_ARCH_TRACEHOOK
case PTRACE_GETREGSET:
case PTRACE_SETREGSET:
{
struct iovec kiov;
struct compat_iovec __user *uiov =
(struct compat_iovec __user *) datap;
compat_uptr_t ptr;
compat_size_t len;

if (!access_ok(VERIFY_WRITE, uiov, sizeof(*uiov)))
return -EFAULT;

if (__get_user(ptr, &uiov->iov_base) ||
__get_user(len, &uiov->iov_len))
return -EFAULT;

kiov.iov_base = compat_ptr(ptr);
kiov.iov_len = len;

ret = ptrace_regset(child, request, addr, &kiov);
if (!ret)
ret = __put_user(kiov.iov_len, &uiov->iov_len);
break;
}
#endif

default:
ret = ptrace_request(child, request, addr, data);
Expand Down

0 comments on commit 3099918

Please sign in to comment.