]> granicus.if.org Git - strace/commitdiff
Introduce print_array function for consistent decoding of arrays
authorDmitry V. Levin <ldv@altlinux.org>
Fri, 6 May 2016 23:26:43 +0000 (23:26 +0000)
committerDmitry V. Levin <ldv@altlinux.org>
Sat, 7 May 2016 13:08:36 +0000 (13:08 +0000)
* defs.h (print_array): New prototype.
* util.c (print_array): New function.

defs.h
util.c

diff --git a/defs.h b/defs.h
index fe2e46b5909aa11d26bed2951460c4ed50dbe927..97ac9736710d1ab6d0328739f86241a7e8ebb74d 100644 (file)
--- 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 a9bce9986c0fe81ca3a8c51cbf3b975e4d4ff8f6..454c7cf619971a06c34786c13c51d43e98aabc7d 100644 (file)
--- 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;
+}