]> granicus.if.org Git - strace/blobdiff - util.c
tests: fix expected output in strace-tt.test
[strace] / util.c
diff --git a/util.c b/util.c
index 3979cab9747c2a181ecff7475fe9ab23719e78d5..9976c76e628afc3e3b1c7ed8cf77de4b926f76bb 100644 (file)
--- a/util.c
+++ b/util.c
 #include "ptrace.h"
 
 int
-string_to_uint(const char *str)
+string_to_uint_ex(const char *const str, char **const endptr,
+                 const unsigned int max_val, const char *const accepted_ending)
 {
-       char *error;
-       long value;
+       char *end;
+       long val;
 
        if (!*str)
                return -1;
+
        errno = 0;
-       value = strtol(str, &error, 10);
-       if (errno || *error || value < 0 || (long)(int)value != value)
+       val = strtol(str, &end, 10);
+
+       if (str == end || val < 0 || (unsigned long) val > max_val
+           || (val == LONG_MAX && errno == ERANGE))
                return -1;
-       return (int)value;
+
+       if (*end && (!accepted_ending || !strchr(accepted_ending, *end)))
+               return -1;
+
+       if (endptr)
+               *endptr = end;
+
+       return (int) val;
+}
+
+int
+string_to_uint(const char *const str)
+{
+       return string_to_uint_upto(str, INT_MAX);
 }
 
 int
@@ -171,7 +188,7 @@ int
 next_set_bit(const void *bit_array, unsigned cur_bit, unsigned size_bits)
 {
        const unsigned endian = 1;
-       int little_endian = *(char*)&endian;
+       int little_endian = * (char *) (void *) &endian;
 
        const uint8_t *array = bit_array;
        unsigned pos = cur_bit / 8;
@@ -204,10 +221,18 @@ next_set_bit(const void *bit_array, unsigned cur_bit, unsigned size_bits)
                pos++;
        }
 }
-/*
+
+/**
  * Print entry in struct xlat table, if there.
+ *
+ * @param val  Value to search a literal representation for.
+ * @param dflt String (abbreviated in comment syntax) which should be emitted
+ *             if no appropriate xlat value has been found.
+ * @param xlat (And the following arguments) Pointers to arrays of xlat values.
+ *             The last argument should be NULL.
+ * @return     1 if appropriate xlat value has been found, 0 otherwise.
  */
-void
+int
 printxvals(const uint64_t val, const char *dflt, const struct xlat *xlat, ...)
 {
        va_list args;
@@ -219,13 +244,49 @@ printxvals(const uint64_t val, const char *dflt, const struct xlat *xlat, ...)
                if (str) {
                        tprints(str);
                        va_end(args);
-                       return;
+                       return 1;
                }
        }
        /* No hits -- print raw # instead. */
-       tprintf("%#" PRIx64 " /* %s */", val, dflt);
+       tprintf("%#" PRIx64, val);
+       if (dflt)
+               tprintf(" /* %s */", dflt);
 
        va_end(args);
+
+       return 0;
+}
+
+/**
+ * Print entry in sorted struct xlat table, if it is there.
+ *
+ * @param xlat      Pointer to an array of xlat values (not terminated with
+ *                  XLAT_END).
+ * @param xlat_size Number of xlat elements present in array (usually ARRAY_SIZE
+ *                  if array is declared in the unit's scope and not
+ *                  terminated with XLAT_END).
+ * @param val       Value to search literal representation for.
+ * @param dflt      String (abbreviated in comment syntax) which should be
+ *                  emitted if no appropriate xlat value has been found.
+ * @return          1 if appropriate xlat value has been found, 0
+ *                  otherwise.
+ */
+int
+printxval_searchn(const struct xlat *xlat, size_t xlat_size, uint64_t val,
+       const char *dflt)
+{
+       const char *s = xlat_search(xlat, xlat_size, val);
+
+       if (s) {
+               tprints(s);
+               return 1;
+       }
+
+       tprintf("%#" PRIx64, val);
+       if (dflt)
+               tprintf(" /* %s */", dflt);
+
+       return 0;
 }
 
 /*
@@ -275,7 +336,17 @@ getllval(struct tcb *tcp, unsigned long long *val, int arg_no)
      defined XTENSA
        /* Align arg_no to the next even number. */
        arg_no = (arg_no + 1) & 0xe;
-# endif
+# elif defined SH
+       /*
+        * The SH4 ABI does allow long longs in odd-numbered registers, but
+        * does not allow them to be split between registers and memory - and
+        * there are only four argument registers for normal functions.  As a
+        * result, pread, for example, takes an extra padding argument before
+        * the offset.  This was changed late in the 2.4 series (around 2.4.20).
+        */
+       if (arg_no == 3)
+               arg_no++;
+# endif /* __ARM_EABI__ || LINUX_MIPSO32 || POWERPC || XTENSA || SH */
        *val = LONG_LONG(tcp->u_arg[arg_no], tcp->u_arg[arg_no + 1]);
        arg_no += 2;
 #endif
@@ -396,12 +467,12 @@ printflags64(const struct xlat *xlat, uint64_t flags, const char *dflt)
 }
 
 void
-printaddr(const long addr)
+printaddr_ull(const unsigned long long addr)
 {
        if (!addr)
                tprints("NULL");
        else
-               tprintf("%#lx", addr);
+               tprintf("%#llx", addr);
 }
 
 #define DEF_PRINTNUM(name, type) \
@@ -455,7 +526,7 @@ const char *
 sprinttime(time_t t)
 {
        struct tm *tmp;
-       static char buf[sizeof(int) * 3 * 6];
+       static char buf[sizeof(int) * 3 * 6 + sizeof("+0000")];
 
        if (t == 0) {
                strcpy(buf, "0");
@@ -463,11 +534,9 @@ sprinttime(time_t t)
        }
        tmp = localtime(&t);
        if (tmp)
-               snprintf(buf, sizeof buf, "%02d/%02d/%02d-%02d:%02d:%02d",
-                       tmp->tm_year + 1900, tmp->tm_mon + 1, tmp->tm_mday,
-                       tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+               strftime(buf, sizeof(buf), "%FT%T%z", tmp);
        else
-               snprintf(buf, sizeof buf, "%lu", (unsigned long) t);
+               snprintf(buf, sizeof(buf), "%lu", (unsigned long) t);
 
        return buf;
 }
@@ -609,6 +678,9 @@ string_quote(const char *instr, char *outstr, const unsigned int size,
                        /* Check for NUL-terminated string. */
                        if (c == eol)
                                goto asciz_ended;
+                       if ((i == (size - 1)) &&
+                           (style & QUOTE_OMIT_TRAILING_0) && (c == '\0'))
+                               goto asciz_ended;
                        switch (c) {
                                case '\"': case '\\':
                                        *s++ = '\\';
@@ -781,16 +853,21 @@ printpath(struct tcb *tcp, long addr)
 
 /*
  * Print string specified by address `addr' and length `len'.
- * If `len' < 0, treat the string as a NUL-terminated string.
- * If string length exceeds `max_strlen', append `...' to the output.
+ * If `len' == -1, set QUOTE_0_TERMINATED bit in `user_style'.
+ * If `user_style' has QUOTE_0_TERMINATED bit set, treat the string
+ * as a NUL-terminated string.
+ * Pass `user_style' on to `string_quote'.
+ * Append `...' to the output if either the string length exceeds `max_strlen',
+ * or `len' != -1 and the string length exceeds `len'.
  */
 void
-printstr(struct tcb *tcp, long addr, long len)
+printstr_ex(struct tcb *tcp, long addr, long len, unsigned int user_style)
 {
        static char *str = NULL;
        static char *outstr;
        unsigned int size;
-       unsigned int style;
+       unsigned int style = user_style;
+       int rc;
        int ellipsis;
 
        if (!addr) {
@@ -807,33 +884,39 @@ printstr(struct tcb *tcp, long addr, long len)
                outstr = xmalloc(outstr_size);
        }
 
-       size = max_strlen;
+       size = max_strlen + 1;
        if (len == -1) {
                /*
                 * Treat as a NUL-terminated string: fetch one byte more
                 * because string_quote may look one byte ahead.
                 */
-               if (umovestr(tcp, addr, size + 1, str) < 0) {
-                       printaddr(addr);
-                       return;
-               }
-               style = QUOTE_0_TERMINATED;
+               style |= QUOTE_0_TERMINATED;
+               rc = umovestr(tcp, addr, size, str);
+       } else {
+               if (size > (unsigned long) len)
+                       size = (unsigned long) len;
+               if (style & QUOTE_0_TERMINATED)
+                       rc = umovestr(tcp, addr, size, str);
+               else
+                       rc = umoven(tcp, addr, size, str);
        }
-       else {
-               if (size > (unsigned long)len)
-                       size = (unsigned long)len;
-               if (umoven(tcp, addr, size, str) < 0) {
-                       printaddr(addr);
-                       return;
-               }
-               style = 0;
+       if (rc < 0) {
+               printaddr(addr);
+               return;
        }
 
+       if (size > max_strlen)
+               size = max_strlen;
+       else
+               str[size] = '\xff';
+
        /* If string_quote didn't see NUL and (it was supposed to be ASCIZ str
         * or we were requested to print more than -s NUM chars)...
         */
-       ellipsis = (string_quote(str, outstr, size, style) &&
-                       (len < 0 || (unsigned long) len > max_strlen));
+       ellipsis = string_quote(str, outstr, size, style)
+                  && len
+                  && ((style & QUOTE_0_TERMINATED)
+                      || (unsigned long) len > max_strlen);
 
        tprints(outstr);
        if (ellipsis)
@@ -1141,6 +1224,17 @@ umoven_or_printaddr(struct tcb *tcp, const long addr, const unsigned int len,
        return 0;
 }
 
+int
+umoven_or_printaddr_ignore_syserror(struct tcb *tcp, const long addr,
+                                   const unsigned int len, void *our_addr)
+{
+       if (!addr || !verbose(tcp) || umoven(tcp, addr, len, our_addr) < 0) {
+               printaddr(addr);
+               return -1;
+       }
+       return 0;
+}
+
 /*
  * Like `umove' but make the additional effort of looking
  * for a terminating zero byte.
@@ -1403,26 +1497,44 @@ print_array(struct tcb *tcp,
        return cur >= end_addr;
 }
 
-int
-printargs(struct tcb *tcp)
+long long
+getarg_ll(struct tcb *tcp, int argn)
 {
-       if (entering(tcp)) {
-               int i;
-               int n = tcp->s_ent->nargs;
-               for (i = 0; i < n; i++) {
 #if HAVE_STRUCT_TCB_EXT_ARG
 # if SUPPORTED_PERSONALITIES > 1
-                       if (current_personality == 1)
-                               tprintf("%s%#lx", i ? ", " : "", tcp->u_arg[i]);
-                       else
+       if (current_personality == 1)
+               return (long) tcp->u_arg[argn];
+       else
 # endif
-                       tprintf("%s%#llx", i ? ", " : "", tcp->ext_arg[i]);
+       return (long long) tcp->ext_arg[argn];
 #else
-                       tprintf("%s%#lx", i ? ", " : "", tcp->u_arg[i]);
+       return (long) tcp->u_arg[argn];
 #endif
-               }
-       }
-       return 0;
+}
+
+unsigned long long
+getarg_ull(struct tcb *tcp, int argn)
+{
+#if HAVE_STRUCT_TCB_EXT_ARG
+# if SUPPORTED_PERSONALITIES > 1
+       if (current_personality == 1)
+               return (unsigned long) tcp->u_arg[argn];
+       else
+# endif
+       return (unsigned long long) tcp->ext_arg[argn];
+#else
+       return (unsigned long) tcp->u_arg[argn];
+#endif
+}
+
+int
+printargs(struct tcb *tcp)
+{
+       const int n = tcp->s_ent->nargs;
+       int i;
+       for (i = 0; i < n; ++i)
+               tprintf("%s%#llx", i ? ", " : "", getarg_ull(tcp, i));
+       return RVAL_DECODED;
 }
 
 int