summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitry V. Levin <ldv@altlinux.org>2013-02-26 21:16:22 +0000
committerDmitry V. Levin <ldv@altlinux.org>2013-02-26 22:11:32 +0000
commit9700592e49bd7407c58693f1d397055fa485fc18 (patch)
tree9b733ddef8760c17859c9b5f85f57a25683989e0
parent1a880cf3bd8c12af6d831c2dfa5b259be074d77a (diff)
downloadstrace-9700592e49bd7407c58693f1d397055fa485fc18.tar.gz
strace-9700592e49bd7407c58693f1d397055fa485fc18.tar.bz2
strace-9700592e49bd7407c58693f1d397055fa485fc18.tar.xz
Cleanup umoven and umovestr
Cleanup sloppy error handling. First, EFAULT kind of errors from process_vm_readv by itself is not something unusual, so a warning message will not be issued unless a short read is detected. Second, clients of umoven and umovestr are not prepared to detect and handle short reads that can happen in these functions. The most safe way to handle them is to return an error code. * util.c (umoven, umovestr): Cleanup handling of errors coming from process_vm_readv and PTRACE_PEEKDATA.
-rw-r--r--util.c188
1 files changed, 116 insertions, 72 deletions
diff --git a/util.c b/util.c
index 354efef..e14d242 100644
--- a/util.c
+++ b/util.c
@@ -776,8 +776,7 @@ int
umoven(struct tcb *tcp, long addr, int len, char *laddr)
{
int pid = tcp->pid;
- int n, m;
- //int started;
+ int n, m, nread;
union {
long val;
char x[sizeof(long)];
@@ -795,63 +794,82 @@ umoven(struct tcb *tcp, long addr, int len, char *laddr)
local[0].iov_base = laddr;
remote[0].iov_base = (void*)addr;
local[0].iov_len = remote[0].iov_len = len;
- r = process_vm_readv(pid,
- local, 1,
- remote, 1,
- /*flags:*/ 0
- );
+ r = process_vm_readv(pid, local, 1, remote, 1, 0);
if (r == len)
return 0;
- if (r < 0) {
- if (errno == ENOSYS)
+ if (r >= 0) {
+ error_msg("umoven: short read (%d < %d) @0x%lx",
+ r, len, addr);
+ return -1;
+ }
+ switch (errno) {
+ case ENOSYS:
process_vm_readv_not_supported = 1;
- else if (errno != EINVAL && errno != ESRCH)
- /* EINVAL or ESRCH could be seen if process is gone,
- * all the rest is strange and should be reported. */
+ break;
+ case ESRCH:
+ /* the process is gone */
+ return -1;
+ case EFAULT: case EIO: case EPERM:
+ /* address space is inaccessible */
+ return -1;
+ default:
+ /* all the rest is strange and should be reported */
perror_msg("process_vm_readv");
- } else {
- error_msg("process_vm_readv: short read (%d < %d)", r, len);
+ return -1;
}
}
- //started = 0;
+ nread = 0;
if (addr & (sizeof(long) - 1)) {
/* addr not a multiple of sizeof(long) */
n = addr - (addr & -sizeof(long)); /* residue */
addr &= -sizeof(long); /* residue */
errno = 0;
u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
- if (errno) {
- /* But if not started, we had a bogus address. */
- if (addr != 0 && errno != EIO && errno != ESRCH)
- perror_msg("umoven: PTRACE_PEEKDATA pid:%d @0x%lx", pid, addr);
- return -1;
+ switch (errno) {
+ case 0:
+ break;
+ case ESRCH: case EINVAL:
+ /* these could be seen if the process is gone */
+ return -1;
+ case EFAULT: case EIO: case EPERM:
+ /* address space is inaccessible */
+ return -1;
+ default:
+ /* all the rest is strange and should be reported */
+ perror_msg("umoven: PTRACE_PEEKDATA pid:%d @0x%lx",
+ pid, addr);
+ return -1;
}
- //started = 1;
m = MIN(sizeof(long) - n, len);
memcpy(laddr, &u.x[n], m);
- addr += sizeof(long), laddr += m, len -= m;
+ addr += sizeof(long), laddr += m, len -= m, nread += m;
}
while (len) {
errno = 0;
u.val = ptrace(PTRACE_PEEKDATA, pid, (char *) addr, 0);
- if (errno) {
-#if 0
-//FIXME: wrong. printpath doesn't use this routine. Callers expect full copies.
-//Ok to remove?
- if (started && (errno==EPERM || errno==EIO)) {
- /* Ran into 'end of memory' - stupid "printpath" */
- return 0;
- }
-#endif
- if (addr != 0 && errno != EIO && errno != ESRCH)
- perror_msg("umoven: PTRACE_PEEKDATA pid:%d @0x%lx", pid, addr);
- return -1;
+ switch (errno) {
+ case 0:
+ break;
+ case ESRCH: case EINVAL:
+ /* these could be seen if the process is gone */
+ return -1;
+ case EFAULT: case EIO: case EPERM:
+ /* address space is inaccessible */
+ if (nread) {
+ perror_msg("umoven: short read (%d < %d) @0x%lx",
+ nread, nread + len, addr - nread);
+ }
+ return -1;
+ default:
+ /* all the rest is strange and should be reported */
+ perror_msg("umoven: PTRACE_PEEKDATA pid:%d @0x%lx",
+ pid, addr);
+ return -1;
}
- //started = 1;
m = MIN(sizeof(long), len);
memcpy(laddr, u.x, m);
- addr += sizeof(long), laddr += m, len -= m;
+ addr += sizeof(long), laddr += m, len -= m, nread += m;
}
return 0;
@@ -872,9 +890,8 @@ umoven(struct tcb *tcp, long addr, int len, char *laddr)
int
umovestr(struct tcb *tcp, long addr, int len, char *laddr)
{
- int started;
int pid = tcp->pid;
- int i, n, m;
+ int i, n, m, nread;
union {
long val;
char x[sizeof(long)];
@@ -885,6 +902,7 @@ umovestr(struct tcb *tcp, long addr, int len, char *laddr)
addr &= (1ul << 8 * current_wordsize) - 1;
#endif
+ nread = 0;
if (!process_vm_readv_not_supported) {
struct iovec local[1], remote[1];
@@ -911,70 +929,96 @@ umovestr(struct tcb *tcp, long addr, int len, char *laddr)
chunk_len = r; /* chunk_len -= end_in_page */
local[0].iov_len = remote[0].iov_len = chunk_len;
- r = process_vm_readv(pid,
- local, 1,
- remote, 1,
- /*flags:*/ 0
- );
- if (r < 0) {
- if (errno == ENOSYS)
+ r = process_vm_readv(pid, local, 1, remote, 1, 0);
+ if (r > 0) {
+ if (memchr(local[0].iov_base, '\0', r))
+ return 1;
+ local[0].iov_base += r;
+ remote[0].iov_base += r;
+ len -= r;
+ nread += r;
+ continue;
+ }
+ switch (errno) {
+ case ENOSYS:
process_vm_readv_not_supported = 1;
- else if (errno != EINVAL && errno != ESRCH)
- /* EINVAL or ESRCH could be seen
- * if process is gone, all the rest
- * is strange and should be reported. */
+ goto vm_readv_didnt_work;
+ case ESRCH:
+ /* the process is gone */
+ return -1;
+ case EFAULT: case EIO: case EPERM:
+ /* address space is inaccessible */
+ if (nread) {
+ perror_msg("umovestr: short read (%d < %d) @0x%lx",
+ nread, nread + len, addr);
+ }
+ return -1;
+ default:
+ /* all the rest is strange and should be reported */
perror_msg("process_vm_readv");
- goto vm_readv_didnt_work;
+ return -1;
}
- if (memchr(local[0].iov_base, '\0', r))
- return 1;
- local[0].iov_base += r;
- remote[0].iov_base += r;
- len -= r;
}
return 0;
}
vm_readv_didnt_work:
- started = 0;
if (addr & (sizeof(long) - 1)) {
/* addr not a multiple of sizeof(long) */
n = addr - (addr & -sizeof(long)); /* residue */
addr &= -sizeof(long); /* residue */
errno = 0;
u.val = ptrace(PTRACE_PEEKDATA, pid, (char *)addr, 0);
- if (errno) {
- if (addr != 0 && errno != EIO && errno != ESRCH)
- perror_msg("umovestr: PTRACE_PEEKDATA pid:%d @0x%lx", pid, addr);
- return -1;
+ switch (errno) {
+ case 0:
+ break;
+ case ESRCH: case EINVAL:
+ /* these could be seen if the process is gone */
+ return -1;
+ case EFAULT: case EIO: case EPERM:
+ /* address space is inaccessible */
+ return -1;
+ default:
+ /* all the rest is strange and should be reported */
+ perror_msg("umovestr: PTRACE_PEEKDATA pid:%d @0x%lx",
+ pid, addr);
+ return -1;
}
- started = 1;
m = MIN(sizeof(long) - n, len);
memcpy(laddr, &u.x[n], m);
while (n & (sizeof(long) - 1))
if (u.x[n++] == '\0')
return 1;
- addr += sizeof(long), laddr += m, len -= m;
+ addr += sizeof(long), laddr += m, len -= m, nread += m;
}
while (len) {
errno = 0;
u.val = ptrace(PTRACE_PEEKDATA, pid, (char *)addr, 0);
- if (errno) {
- if (started && (errno==EPERM || errno==EIO)) {
- /* Ran into 'end of memory' - stupid "printpath" */
- return 0;
- }
- if (addr != 0 && errno != EIO && errno != ESRCH)
- perror_msg("umovestr: PTRACE_PEEKDATA pid:%d @0x%lx", pid, addr);
- return -1;
+ switch (errno) {
+ case 0:
+ break;
+ case ESRCH: case EINVAL:
+ /* these could be seen if the process is gone */
+ return -1;
+ case EFAULT: case EIO: case EPERM:
+ /* address space is inaccessible */
+ if (nread) {
+ perror_msg("umovestr: short read (%d < %d) @0x%lx",
+ nread, nread + len, addr - nread);
+ }
+ return -1;
+ default:
+ /* all the rest is strange and should be reported */
+ perror_msg("umovestr: PTRACE_PEEKDATA pid:%d @0x%lx",
+ pid, addr);
+ return -1;
}
- started = 1;
m = MIN(sizeof(long), len);
memcpy(laddr, u.x, m);
for (i = 0; i < sizeof(long); i++)
if (u.x[i] == '\0')
return 1;
- addr += sizeof(long), laddr += m, len -= m;
+ addr += sizeof(long), laddr += m, len -= m, nread += m;
}
return 0;
}