From: Dmitry V. Levin Date: Fri, 6 May 2016 23:26:43 +0000 (+0000) Subject: Introduce print_array function for consistent decoding of arrays X-Git-Tag: v4.12~224 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=72e4f7af56a207cb2b2627a16509045a1ba400ca;p=strace Introduce print_array function for consistent decoding of arrays * defs.h (print_array): New prototype. * util.c (print_array): New function. --- diff --git a/defs.h b/defs.h index fe2e46b5..97ac9736 100644 --- a/defs.h +++ b/defs.h @@ -515,6 +515,22 @@ extern int umove_ulong_array_or_printaddr(struct tcb *, long, unsigned long *, s extern int umovestr(struct tcb *, long, unsigned int, char *); extern int upeek(int pid, long, long *); +extern bool +print_array(struct tcb *tcp, + const unsigned long start_addr, + const size_t nmemb, + void *const elem_buf, + const size_t elem_size, + int (*const umoven_func)(struct tcb *, + long, + unsigned int, + void *), + bool (*const print_func)(struct tcb *, + void *elem_buf, + size_t elem_size, + void *opaque_data), + void *const opaque_data); + #if defined ALPHA || defined IA64 || defined MIPS \ || defined SH || defined SPARC || defined SPARC64 # define HAVE_GETRVAL2 diff --git a/util.c b/util.c index a9bce998..454c7cf6 100644 --- a/util.c +++ b/util.c @@ -1335,3 +1335,103 @@ umovestr(struct tcb *tcp, long addr, unsigned int len, char *laddr) } return 0; } + +/* + * Iteratively fetch and print up to nmemb elements of elem_size size + * from the array that starts at tracee's address start_addr. + * + * Array elements are being fetched to the address specified by elem_buf. + * + * The fetcher callback function specified by umoven_func should follow + * the same semantics as umoven_or_printaddr function. + * + * The printer callback function specified by print_func is expected + * to print something; if it returns false, no more iterations will be made. + * + * The pointer specified by opaque_data is passed to each invocation + * of print_func callback function. + * + * This function prints: + * - "NULL", if start_addr is NULL; + * - "[]", if nmemb is 0; + * - start_addr, if nmemb * elem_size overflows or wraps around; + * - nothing, if the first element cannot be fetched + * (if umoven_func returns non-zero), but it is assumed that + * umoven_func has printed the address it failed to fetch data from; + * - elements of the array, delimited by ", ", with the array itself + * enclosed with [] brackets. + * + * If abbrev(tcp) is true, then + * - the maximum number of elements printed equals to max_strlen; + * - "..." is printed instead of max_strlen+1 element + * and no more iterations will be made. + * + * This function returns true only if + * - umoven_func has been called at least once AND + * - umoven_func has not returned false. + */ +bool +print_array(struct tcb *tcp, + const unsigned long start_addr, + const size_t nmemb, + void *const elem_buf, + const size_t elem_size, + int (*const umoven_func)(struct tcb *, + long, + unsigned int, + void *), + bool (*const print_func)(struct tcb *, + void *elem_buf, + size_t elem_size, + void *opaque_data), + void *const opaque_data) +{ + if (!start_addr) { + tprints("NULL"); + return false; + } + + if (!nmemb) { + tprints("[]"); + return false; + } + + const size_t size = nmemb * elem_size; + const unsigned long end_addr = start_addr + size; + + if (end_addr <= start_addr || size / elem_size != nmemb) { + printaddr(start_addr); + return false; + } + + const unsigned long abbrev_end = + (abbrev(tcp) && max_strlen < nmemb) ? + start_addr + elem_size * max_strlen : end_addr; + unsigned long cur; + + for (cur = start_addr; cur < end_addr; cur += elem_size) { + if (cur != start_addr) + tprints(", "); + + if (umoven_func(tcp, cur, elem_size, elem_buf)) + break; + + if (cur == start_addr) + tprints("["); + + if (cur >= abbrev_end) { + tprints("..."); + cur = end_addr; + break; + } + + if (!print_func(tcp, elem_buf, elem_size, opaque_data)) { + cur = end_addr; + break; + } + } + if (cur != start_addr) + tprints("]"); + + return cur >= end_addr; +}