aboutsummaryrefslogtreecommitdiffstats
path: root/sctrace.c
diff options
context:
space:
mode:
authorMattias Andrée <maandree@kth.se>2020-05-30 12:55:40 +0200
committerMattias Andrée <maandree@kth.se>2020-05-30 12:55:40 +0200
commitbca4b327c6abb3a42e511f12d8af727563bbfc7e (patch)
treec12134be30bea47223a61f0d6758eee9bf388f00 /sctrace.c
parentAdd an optimisation todo (diff)
downloadsctrace-bca4b327c6abb3a42e511f12d8af727563bbfc7e.tar.gz
sctrace-bca4b327c6abb3a42e511f12d8af727563bbfc7e.tar.bz2
sctrace-bca4b327c6abb3a42e511f12d8af727563bbfc7e.tar.xz
Use process_vm_readv instead of PTRACE_PEEKDATA (no fallback)
Signed-off-by: Mattias Andrée <maandree@kth.se>
Diffstat (limited to 'sctrace.c')
-rw-r--r--sctrace.c134
1 files changed, 55 insertions, 79 deletions
diff --git a/sctrace.c b/sctrace.c
index 17e8e76..8be566f 100644
--- a/sctrace.c
+++ b/sctrace.c
@@ -5,6 +5,7 @@
#include <sys/ptrace.h>
#include <sys/syscall.h>
+#include <sys/uio.h>
#include <sys/user.h>
#include <sys/wait.h>
#include <ctype.h>
@@ -57,93 +58,70 @@ usage(void)
static char *
-get_string_or_memory(pid_t pid, unsigned long int addr, size_t m, int string, const char **errorp)
+get_string(pid_t pid, unsigned long int addr, size_t *lenp, const char **errorp)
{
- /* TODO use process_vm_readv if supported */
-
- size_t orig_addr = (size_t)addr;
- size_t off;
- char *ret = NULL;
- size_t size = 0;
- size_t len = 0;
- size_t i;
- union {
- long int value;
- char bytes[sizeof(long int)];
- } u;
-
+ struct iovec inv, outv;
+ size_t off = 0, size = 0, page_off, read_size;
+ char *out = NULL, *in = (char *)addr, *p;
+ page_off = (size_t)addr - ((size_t)addr & -sizeof(PAGE_SIZE));
+ read_size = PAGE_SIZE - page_off;
*errorp = NULL;
-
- if (!addr)
- return NULL;
-
- addr &= -sizeof(long int);
- off = orig_addr - (size_t)addr;
-
- for (;;) {
- errno = 0;
- u.value = ptrace(PTRACE_PEEKDATA, pid, addr, 0);
- switch (errno) {
- case 0:
- break;
- case EFAULT:
- *errorp = "<invalid address>";
- return NULL;
- default:
- *errorp = "<an error occured during reading of string>";
- return NULL;
+ for (;; read_size = PAGE_SIZE) {
+ out = realloc(out, size + PAGE_SIZE);
+ if (!out) {
+ fprintf(stderr, "%s: realloc: %s\n", argv0, strerror(errno));
+ exit(1);
}
-
- addr += sizeof(long int);
- if (size - len < sizeof(long int)) {
- ret = realloc(ret, size += sizeof(long int) * 32);
- if (!ret) {
- fprintf(stderr, "%s: realloc: %s\n", argv0, strerror(errno));
- exit(1);
- }
+ inv.iov_base = &in[off];
+ inv.iov_len = read_size;
+ outv.iov_base = &out[off];
+ outv.iov_len = read_size;
+ if (process_vm_readv(pid, &outv, 1, &inv, 1, 0) != (ssize_t)read_size) {
+ *errorp = errno == EFAULT ? "<invalid address>" : "<an error occured during reading of string>";
+ *lenp = 0;
+ return 0;
}
- if (string) {
- for (i = off; i < sizeof(u.bytes); i++, len++) {
- ret[len] = u.bytes[i];
- if (!ret[len])
- return ret;
- }
- } else {
- for (i = off; i < sizeof(u.bytes) && len < m; i++, len++)
- ret[len] = u.bytes[i];
- if (len == m)
- return ret;
+ p = memchr(&out[off], 0, read_size);
+ if (p) {
+ *lenp = (size_t)(p - out);
+ return out;
}
- off = 0;
+ off += read_size;
}
}
-static char *
-get_memory(pid_t pid, unsigned long int addr, size_t m, const char **errorp)
+static int
+get_struct(pid_t pid, unsigned long int addr, void *out, size_t size, const char **errorp)
{
- return get_string_or_memory(pid, addr, m, 0, errorp);
+ struct iovec inv, outv;
+ *errorp = NULL;
+ inv.iov_base = (void *)addr;
+ inv.iov_len = size;
+ outv.iov_base = out;
+ outv.iov_len = size;
+ if (process_vm_readv(pid, &outv, 1, &inv, 1, 0) == size)
+ return 0;
+ *errorp = errno == EFAULT ? "<invalid address>" : "<an error occured during reading of string>";
+ return -1;
}
-
static char *
-get_string(pid_t pid, unsigned long int addr, const char **errorp)
+get_memory(pid_t pid, unsigned long int addr, size_t n, const char **errorp)
{
- return get_string_or_memory(pid, addr, 0, 1, errorp);
+ char *out = malloc(n + (size_t)!n);
+ if (!out) {
+ fprintf(stderr, "%s: malloc: %s\n", argv0, strerror(errno));
+ exit(1);
+ }
+ if (get_struct(pid, addr, out, n, errorp)) {
+ free(out);
+ return NULL;
+ }
+ return out;
}
-static int
-get_struct(pid_t pid, unsigned long int addr, void *out, size_t size, const char **errorp)
-{
- char *data = get_string_or_memory(pid, addr, size, 0, errorp);
- if (!data)
- return -1;
- memcpy(out, data, size);
- free(data);
- return 0;
-}
-
static void
add_char(char **strp, size_t *sizep, size_t *lenp, char c)
@@ -272,13 +250,6 @@ escape_memory(char *str, size_t m)
}
-static char *
-escape_string(char *str)
-{
- return escape_memory(str, str ? strlen(str) : 0);
-}
-
-
static void
fprint_clockid(FILE *fp, pid_t pid, unsigned long int args[6], size_t arg_index) /* TODO */
{
@@ -305,7 +276,7 @@ fprint_systemcall(FILE *fp, pid_t pid, const char *scall, const char *fmt, unsig
{
typedef char *(*Function)(FILE *fp, pid_t pid, unsigned long int args[6], size_t arg_index);
Function funcs[6];
- size_t i, nfuncs = 0, func;
+ size_t i, nfuncs = 0, func, len;
int ells = 0;
char *str;
const char *err;
@@ -341,7 +312,8 @@ fprint_systemcall(FILE *fp, pid_t pid, const char *scall, const char *fmt, unsig
funcs[nfuncs++] = va_arg(ap, Function);
funcs[func - 1](fp, pid, args, i);
} else if (*fmt == 's') {
- str = escape_string(get_string(pid, args[i], &err));
+ str = get_string(pid, args[i], &len, &err);
+ str = escape_memory(str, len);
fprintf(fp, "%s", str ? str : err);
free(str);
} else if (*fmt == 'm') {
@@ -426,6 +398,7 @@ print_systemcall(FILE *fp, pid_t pid, unsigned long long int scall, unsigned lon
*ret_type = Unknown;
+ /* TODO replace GENERIC_HANDLER with specific handlers */
switch (scall) {
GENERIC_HANDLER(_sysctl);
SIMPLE(accept, "ipp", Int); /* TODO output */
@@ -808,6 +781,9 @@ main(int argc, char **argv)
FILE *outfp = stderr;
const char *num = NULL;
+ /* TODO add option to trace children */
+ /* TODO add option to trace threads */
+ /* TODO add option to specify argv[0] */
ARGBEGIN {
case 'f':
if (outfile)