]> granicus.if.org Git - strace/blobdiff - xlat.c
xlat: update IFA_* constants
[strace] / xlat.c
diff --git a/xlat.c b/xlat.c
index ad49720dcfe7924e6d64e222f3b5395670d1946e..4614cef7b968411c25c3b23f939683d40649ca04 100644 (file)
--- a/xlat.c
+++ b/xlat.c
@@ -3,7 +3,7 @@
  * Copyright (c) 1993 Branko Lankester <branko@hacktic.nl>
  * Copyright (c) 1993, 1994, 1995, 1996 Rick Sladkey <jrs@world.std.com>
  * Copyright (c) 1996-1999 Wichert Akkerman <wichert@cistron.nl>
- * Copyright (c) 1999-2017 The strace developers.
+ * Copyright (c) 1999-2018 The strace developers.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  */
 
 #include "defs.h"
+#include "xstring.h"
 #include <stdarg.h>
 
+static inline enum xlat_style
+get_xlat_style(enum xlat_style style)
+{
+       if (xlat_verbose(style) == XLAT_STYLE_DEFAULT)
+               return style | xlat_verbosity;
+
+       return style;
+}
+
+static inline const char *
+sprint_xlat_val(uint64_t val, enum xlat_style style)
+{
+       static char buf[sizeof(val) * 3];
+
+       switch (xlat_format(style)) {
+       case XLAT_STYLE_FMT_D:
+               xsprintf(buf, "%" PRId64, val);
+               break;
+
+       case XLAT_STYLE_FMT_U:
+               xsprintf(buf, "%" PRIu64, val);
+               break;
+
+       case XLAT_STYLE_FMT_X:
+               xsprintf(buf, "%#" PRIx64, val);
+               break;
+       }
+
+       return buf;
+}
+
+static inline void
+print_xlat_val(uint64_t val, enum xlat_style style)
+{
+       tprints(sprint_xlat_val(val, style));
+}
+
 const char *
 xlookup(const struct xlat *xlat, const uint64_t val)
 {
-       for (; xlat->str != NULL; xlat++)
-               if (xlat->val == val)
-                       return xlat->str;
+       static const struct xlat *pos;
+
+       if (xlat)
+               pos = xlat;
+
+       for (; pos->str != NULL; pos++)
+               if (pos->val == val)
+                       return pos->str;
        return NULL;
 }
 
@@ -52,45 +95,109 @@ xlat_bsearch_compare(const void *a, const void *b)
 const char *
 xlat_search(const struct xlat *xlat, const size_t nmemb, const uint64_t val)
 {
+       static const struct xlat *pos;
+       static size_t memb_left;
+
+       if (xlat) {
+               pos = xlat;
+               memb_left = nmemb;
+       }
+
        const struct xlat *e =
                bsearch((const void *) &val,
-                       xlat, nmemb, sizeof(*xlat), xlat_bsearch_compare);
+                       pos, memb_left, sizeof(*pos), xlat_bsearch_compare);
 
-       return e ? e->str : NULL;
+       if (e) {
+               memb_left -= e - pos;
+               return e->str;
+       } else {
+               return NULL;
+       }
 }
 
 /**
  * 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.
+ * @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 style Style in which xlat value should be printed.
+ * @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.
  */
 int
-printxvals(const uint64_t val, const char *dflt, const struct xlat *xlat, ...)
+printxvals_ex(const uint64_t val, const char *dflt, enum xlat_style style,
+             const struct xlat *xlat, ...)
 {
+       static const struct xlat *last;
+
+       style = get_xlat_style(style);
+
+       if (xlat_verbose(style) == XLAT_STYLE_RAW) {
+               print_xlat_val(val, style);
+               return 0;
+       }
+
+       const char *str = NULL;
        va_list args;
 
        va_start(args, xlat);
+
+       if (!xlat)
+               xlat = last;
+
        for (; xlat; xlat = va_arg(args, const struct xlat *)) {
-               const char *str = xlookup(xlat, val);
+               last = xlat;
+
+               str = xlookup(xlat, val);
 
                if (str) {
-                       tprints(str);
-                       va_end(args);
-                       return 1;
+                       if (xlat_verbose(style) == XLAT_STYLE_VERBOSE) {
+                               print_xlat_val(val, style);
+                               tprints_comment(str);
+                       } else {
+                               tprints(str);
+                       }
+
+                       goto printxvals_ex_end;
                }
        }
+
        /* No hits -- print raw # instead. */
-       tprintf("%#" PRIx64, val);
+       print_xlat_val(val, style);
        tprints_comment(dflt);
 
+printxvals_ex_end:
        va_end(args);
 
-       return 0;
+       return !!str;
+}
+
+int
+sprintxval_ex(char *const buf, const size_t size, const struct xlat *const x,
+             const unsigned int val, const char *const dflt,
+             enum xlat_style style)
+{
+       style = get_xlat_style(style);
+
+       if (xlat_verbose(style) == XLAT_STYLE_RAW)
+               return xsnprintf(buf, size, "%s", sprint_xlat_val(val, style));
+
+       const char *const str = xlookup(x, val);
+
+       if (str) {
+               if (xlat_verbose(style) == XLAT_STYLE_VERBOSE)
+                       return xsnprintf(buf, size, "%s /* %s */",
+                                        sprint_xlat_val(val, style), str);
+               else
+                       return xsnprintf(buf, size, "%s", str);
+       }
+       if (dflt)
+               return xsnprintf(buf, size, "%s /* %s */",
+                                sprint_xlat_val(val, style), dflt);
+
+       return xsnprintf(buf, size, "%s", sprint_xlat_val(val, style));
 }
 
 /**
@@ -104,95 +211,227 @@ printxvals(const uint64_t val, const char *dflt, const struct xlat *xlat, ...)
  * @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.
+ * @param style     Style in which xlat value should be printed.
+ * @param fn        Search function.
  * @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)
+static int
+printxval_sized(const struct xlat *xlat, size_t xlat_size, uint64_t val,
+               const char *dflt, enum xlat_style style,
+               const char *(* fn)(const struct xlat *, size_t, uint64_t))
 {
-       const char *s = xlat_search(xlat, xlat_size, val);
+       style = get_xlat_style(style);
+
+       if (xlat_verbose(style) == XLAT_STYLE_RAW) {
+               print_xlat_val(val, style);
+               return 0;
+       }
+
+       const char *s = fn(xlat, xlat_size, val);
 
        if (s) {
-               tprints(s);
+               if (xlat_verbose(style) == XLAT_STYLE_VERBOSE) {
+                       print_xlat_val(val, style);
+                       tprints_comment(s);
+               } else {
+                       tprints(s);
+               }
                return 1;
        }
 
-       tprintf("%#" PRIx64, val);
+       print_xlat_val(val, style);
        tprints_comment(dflt);
 
        return 0;
 }
 
-/*
- * Interpret `xlat' as an array of flags
- * print the entries whose bits are on in `flags'
- */
-void
-addflags(const struct xlat *xlat, uint64_t flags)
+int
+printxval_searchn_ex(const struct xlat *xlat, size_t xlat_size, uint64_t val,
+                    const char *dflt, enum xlat_style style)
 {
-       for (; xlat->str; xlat++) {
-               if (xlat->val && (flags & xlat->val) == xlat->val) {
-                       tprintf("|%s", xlat->str);
-                       flags &= ~xlat->val;
-               }
+       return printxval_sized(xlat, xlat_size, val, dflt, style,
+                                 xlat_search);
+}
+
+const char *
+xlat_idx(const struct xlat *xlat, size_t nmemb, uint64_t val)
+{
+       static const struct xlat *pos;
+       static size_t memb_left;
+
+       if (xlat) {
+               pos = xlat;
+               memb_left = nmemb;
        }
-       if (flags) {
-               tprintf("|%#" PRIx64, flags);
+
+       if (val >= memb_left)
+               return NULL;
+
+       if (val != pos[val].val) {
+               error_func_msg("Unexpected xlat value %" PRIu64
+                              " at index %" PRIu64,
+                              pos[val].val, val);
+               return NULL;
        }
+
+       return pos[val].str;
+}
+
+int
+printxval_indexn_ex(const struct xlat *xlat, size_t xlat_size, uint64_t val,
+                   const char *dflt, enum xlat_style style)
+{
+       return printxval_sized(xlat, xlat_size, val, dflt, style, xlat_idx);
 }
 
 /*
  * Interpret `xlat' as an array of flags.
  * Print to static string the entries whose bits are on in `flags'
- * Return static string.
+ * Return static string.  If 0 is provided as flags, and there is no flag that
+ * has the value of 0 (it should be the first in xlat table), return NULL.
+ *
+ * Expected output:
+ * +------------+------------+---------+------------+
+ * | flags != 0 | xlat found | style   | output     |
+ * +------------+------------+---------+------------+
+ * | false      | (any)      | raw     | <none>     |
+ * | true       | (any)      | raw     | VAL        |
+ * +------------+------------+---------+------------+
+ * | false      | false      | abbrev  | <none>     |
+ * | true       | false      | abbrev  | VAL        |
+ * | (any)      | true       | abbrev  | XLAT       |
+ * +------------+------------+---------+------------+
+ * | false      | false      | verbose | <none>     |
+ * | true       | false      | verbose | VAL        |
+ * | (any)      | true       | verbose | VAL (XLAT) |
+ * +------------+------------+---------+------------+
  */
 const char *
-sprintflags(const char *prefix, const struct xlat *xlat, uint64_t flags)
+sprintflags_ex(const char *prefix, const struct xlat *xlat, uint64_t flags,
+              enum xlat_style style)
 {
        static char outstr[1024];
        char *outptr;
        int found = 0;
 
        outptr = stpcpy(outstr, prefix);
+       style = get_xlat_style(style);
+
+       if (xlat_verbose(style) == XLAT_STYLE_RAW) {
+               if (!flags)
+                       return NULL;
+
+               outptr = xappendstr(outstr, outptr, "%s",
+                                   sprint_xlat_val(flags, style));
+
+               return outstr;
+       }
 
        if (flags == 0 && xlat->val == 0 && xlat->str) {
-               strcpy(outptr, xlat->str);
+               if (xlat_verbose(style) == XLAT_STYLE_VERBOSE) {
+                       outptr = xappendstr(outstr, outptr, "0 /* %s */",
+                                           xlat->str);
+               } else {
+                       strcpy(outptr, xlat->str);
+               }
+
                return outstr;
        }
 
-       for (; xlat->str; xlat++) {
+       if (xlat_verbose(style) == XLAT_STYLE_VERBOSE && flags)
+               outptr = xappendstr(outstr, outptr, "%s",
+                                   sprint_xlat_val(flags, style));
+
+       for (; flags && xlat->str; xlat++) {
                if (xlat->val && (flags & xlat->val) == xlat->val) {
                        if (found)
                                *outptr++ = '|';
+                       else if (xlat_verbose(style) == XLAT_STYLE_VERBOSE)
+                               outptr = stpcpy(outptr, " /* ");
+
                        outptr = stpcpy(outptr, xlat->str);
                        found = 1;
                        flags &= ~xlat->val;
-                       if (!flags)
-                               break;
                }
        }
+
        if (flags) {
                if (found)
                        *outptr++ = '|';
-               outptr += sprintf(outptr, "%#" PRIx64, flags);
+               if (found || xlat_verbose(style) != XLAT_STYLE_VERBOSE)
+                       outptr = xappendstr(outstr, outptr, "%s",
+                                           sprint_xlat_val(flags, style));
+       } else {
+               if (!found)
+                       return NULL;
        }
 
+       if (found && xlat_verbose(style) == XLAT_STYLE_VERBOSE)
+               outptr = stpcpy(outptr, " */");
+
        return outstr;
 }
 
+/**
+ * Print flags from multiple xlat tables.
+ *
+ * Expected output:
+ * +------------+--------------+------------+---------+------------+
+ * | flags != 0 | dflt != NULL | xlat found | style   | output     |
+ * +------------+--------------+------------+---------+------------+
+ * | false      | false        | (any)      | raw     | <none>     |
+ * | false      | true         | (any)      | raw     | VAL        |
+ * | true       | (any)        | (any)      | raw     | VAL        |
+ * +------------+--------------+------------+---------+------------+
+ * | false      | false        | false      | abbrev  | <none>     |
+ * | false      | true         | false      | abbrev  | VAL        |
+ * | true       | false        | false      | abbrev  | VAL        |
+ * | true       | true         | false      | abbrev  | VAL (DFLT) |
+ * | (any)      | (any)        | true       | abbrev  | XLAT       |
+ * +------------+--------------+------------+---------+------------+
+ * | false      | false        | false      | verbose | <none>     |
+ * | false      | true         | false      | verbose | VAL        |
+ * | true       | false        | false      | verbose | VAL        |
+ * | true       | true         | false      | verbose | VAL (DFLT) |
+ * | (any)      | (any)        | true       | verbose | VAL (XLAT) |
+ * +------------+--------------+------------+---------+------------+
+ */
 int
-printflags_ex(uint64_t flags, const char *dflt, const struct xlat *xlat, ...)
+printflags_ex(uint64_t flags, const char *dflt, enum xlat_style style,
+             const struct xlat *xlat, ...)
 {
+       style = get_xlat_style(style);
+
+       if (xlat_verbose(style) == XLAT_STYLE_RAW) {
+               if (flags || dflt) {
+                       print_xlat_val(flags, style);
+                       return 1;
+               }
+
+               return 0;
+       }
+
+       const char *init_sep = "";
        unsigned int n = 0;
        va_list args;
 
+       if (xlat_verbose(style) == XLAT_STYLE_VERBOSE) {
+               init_sep = " /* ";
+               if (flags)
+                       print_xlat_val(flags, style);
+       }
+
        va_start(args, xlat);
        for (; xlat; xlat = va_arg(args, const struct xlat *)) {
                for (; (flags || !n) && xlat->str; ++xlat) {
                        if ((flags == xlat->val) ||
                            (xlat->val && (flags & xlat->val) == xlat->val)) {
-                               tprintf("%s%s", (n++ ? "|" : ""), xlat->str);
+                               if (xlat_verbose(style) == XLAT_STYLE_VERBOSE
+                                   && !flags)
+                                       tprints("0");
+                               tprintf("%s%s",
+                                       (n++ ? "|" : init_sep), xlat->str);
                                flags &= ~xlat->val;
                        }
                        if (!flags)
@@ -203,12 +442,17 @@ printflags_ex(uint64_t flags, const char *dflt, const struct xlat *xlat, ...)
 
        if (n) {
                if (flags) {
-                       tprintf("|%#" PRIx64, flags);
+                       tprints("|");
+                       print_xlat_val(flags, style);
                        n++;
                }
+
+               if (xlat_verbose(style) == XLAT_STYLE_VERBOSE)
+                       tprints(" */");
        } else {
                if (flags) {
-                       tprintf("%#" PRIx64, flags);
+                       if (xlat_verbose(style) != XLAT_STYLE_VERBOSE)
+                               print_xlat_val(flags, style);
                        tprints_comment(dflt);
                } else {
                        if (dflt)
@@ -218,3 +462,50 @@ printflags_ex(uint64_t flags, const char *dflt, const struct xlat *xlat, ...)
 
        return n;
 }
+
+void
+print_xlat_ex(const uint64_t val, const char *str, enum xlat_style style)
+{
+       style = get_xlat_style(style);
+
+       switch (xlat_verbose(style)) {
+       case XLAT_STYLE_ABBREV:
+               if (str) {
+                       tprints(str);
+                       break;
+               }
+               ATTRIBUTE_FALLTHROUGH;
+
+       case XLAT_STYLE_RAW:
+               print_xlat_val(val, style);
+               break;
+
+       default:
+               error_func_msg("Unexpected style value of %#x", style);
+               ATTRIBUTE_FALLTHROUGH;
+
+       case XLAT_STYLE_VERBOSE:
+               print_xlat_val(val, style);
+               tprints_comment(str);
+       }
+}
+
+void
+printxval_dispatch_ex(const struct xlat *xlat, size_t xlat_size, uint64_t val,
+                     const char *dflt, enum xlat_type xt,
+                     enum xlat_style style)
+{
+       switch (xt) {
+       case XT_NORMAL:
+               printxvals_ex(val, dflt, style, xlat, NULL);
+               break;
+
+       case XT_SORTED:
+               printxval_searchn_ex(xlat, xlat_size, val, dflt, style);
+               break;
+
+       case XT_INDEXED:
+               printxval_indexn_ex(xlat, xlat_size, val, dflt, style);
+               break;
+       }
+}