diff options
| author | Mattias Andrée <maandree@kth.se> | 2020-05-30 12:55:40 +0200 | 
|---|---|---|
| committer | Mattias Andrée <maandree@kth.se> | 2020-05-30 12:55:40 +0200 | 
| commit | bca4b327c6abb3a42e511f12d8af727563bbfc7e (patch) | |
| tree | c12134be30bea47223a61f0d6758eee9bf388f00 | |
| parent | Add an optimisation todo (diff) | |
| download | sctrace-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 '')
| -rw-r--r-- | config.mk | 2 | ||||
| -rw-r--r-- | sctrace.c | 134 | 
2 files changed, 56 insertions, 80 deletions
| @@ -1,6 +1,6 @@  PREFIX    = /usr  MANPREFIX = $(PREFIX)/share/man -CPPFLAGS = -D_XOPEN_SOURCE=700 +CPPFLAGS = -D_XOPEN_SOURCE=700 -D_GNU_SOURCE  CFLAGS   = -std=c99 -Wall -O2  LDFLAGS  = -s @@ -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) | 
