]> granicus.if.org Git - strace/blobdiff - xlat.c
nlattr: add unsigned int decoders that print in hex form
[strace] / xlat.c
diff --git a/xlat.c b/xlat.c
index 8cddb227a585daf16b44c539b2a8c595b4fc54ef..4614cef7b968411c25c3b23f939683d40649ca04 100644 (file)
--- a/xlat.c
+++ b/xlat.c
 static inline enum xlat_style
 get_xlat_style(enum xlat_style style)
 {
-       if ((style & XLAT_STYLE_VERBOSITY_MASK) == XLAT_STYLE_DEFAULT)
+       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;
 }
 
@@ -62,11 +95,24 @@ 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;
+       }
 }
 
 /**
@@ -84,38 +130,48 @@ int
 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 (style == XLAT_STYLE_RAW) {
-               tprintf("%#" PRIx64, val);
+       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) {
-                       if (style == XLAT_STYLE_VERBOSE) {
-                               tprintf("%#" PRIx64, val);
+                       if (xlat_verbose(style) == XLAT_STYLE_VERBOSE) {
+                               print_xlat_val(val, style);
                                tprints_comment(str);
                        } else {
                                tprints(str);
                        }
 
-                       va_end(args);
-                       return 1;
+                       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
@@ -125,21 +181,23 @@ sprintxval_ex(char *const buf, const size_t size, const struct xlat *const x,
 {
        style = get_xlat_style(style);
 
-       if (style == XLAT_STYLE_RAW)
-               return xsnprintf(buf, size, "%#x", val);
+       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 (style == XLAT_STYLE_VERBOSE)
-                       return xsnprintf(buf, size, "%#x /* %s */", val, 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, "%#x /* %s */", val, dflt);
+               return xsnprintf(buf, size, "%s /* %s */",
+                                sprint_xlat_val(val, style), dflt);
 
-       return xsnprintf(buf, size, "%#x", val);
+       return xsnprintf(buf, size, "%s", sprint_xlat_val(val, style));
 }
 
 /**
@@ -154,25 +212,27 @@ sprintxval_ex(char *const buf, const size_t size, const struct xlat *const x,
  * @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_ex(const struct xlat *xlat, size_t xlat_size, uint64_t val,
-                    const char *dflt, enum xlat_style style)
+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))
 {
        style = get_xlat_style(style);
 
-       if (style == XLAT_STYLE_RAW) {
-               tprintf("%#" PRIx64, val);
+       if (xlat_verbose(style) == XLAT_STYLE_RAW) {
+               print_xlat_val(val, style);
                return 0;
        }
 
-       const char *s = xlat_search(xlat, xlat_size, val);
+       const char *s = fn(xlat, xlat_size, val);
 
        if (s) {
-               if (style == XLAT_STYLE_VERBOSE) {
-                       tprintf("%#" PRIx64, val);
+               if (xlat_verbose(style) == XLAT_STYLE_VERBOSE) {
+                       print_xlat_val(val, style);
                        tprints_comment(s);
                } else {
                        tprints(s);
@@ -180,12 +240,51 @@ printxval_searchn_ex(const struct xlat *xlat, size_t xlat_size, uint64_t val,
                return 1;
        }
 
-       tprintf("%#" PRIx64, val);
+       print_xlat_val(val, style);
        tprints_comment(dflt);
 
        return 0;
 }
 
+int
+printxval_searchn_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_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 (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'
@@ -219,17 +318,18 @@ sprintflags_ex(const char *prefix, const struct xlat *xlat, uint64_t flags,
        outptr = stpcpy(outstr, prefix);
        style = get_xlat_style(style);
 
-       if (style == XLAT_STYLE_RAW) {
+       if (xlat_verbose(style) == XLAT_STYLE_RAW) {
                if (!flags)
                        return NULL;
 
-               outptr = xappendstr(outstr, outptr, "%#" PRIx64, flags);
+               outptr = xappendstr(outstr, outptr, "%s",
+                                   sprint_xlat_val(flags, style));
 
                return outstr;
        }
 
        if (flags == 0 && xlat->val == 0 && xlat->str) {
-               if (style == XLAT_STYLE_VERBOSE) {
+               if (xlat_verbose(style) == XLAT_STYLE_VERBOSE) {
                        outptr = xappendstr(outstr, outptr, "0 /* %s */",
                                            xlat->str);
                } else {
@@ -239,14 +339,15 @@ sprintflags_ex(const char *prefix, const struct xlat *xlat, uint64_t flags,
                return outstr;
        }
 
-       if (style == XLAT_STYLE_VERBOSE && flags)
-               outptr = xappendstr(outstr, outptr, "%#" PRIx64, flags);
+       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 (style == XLAT_STYLE_VERBOSE)
+                       else if (xlat_verbose(style) == XLAT_STYLE_VERBOSE)
                                outptr = stpcpy(outptr, " /* ");
 
                        outptr = stpcpy(outptr, xlat->str);
@@ -258,14 +359,15 @@ sprintflags_ex(const char *prefix, const struct xlat *xlat, uint64_t flags,
        if (flags) {
                if (found)
                        *outptr++ = '|';
-               if (found || style != XLAT_STYLE_VERBOSE)
-                       outptr = xappendstr(outstr, 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 && style == XLAT_STYLE_VERBOSE)
+       if (found && xlat_verbose(style) == XLAT_STYLE_VERBOSE)
                outptr = stpcpy(outptr, " */");
 
        return outstr;
@@ -301,9 +403,9 @@ printflags_ex(uint64_t flags, const char *dflt, enum xlat_style style,
 {
        style = get_xlat_style(style);
 
-       if (style == XLAT_STYLE_RAW) {
+       if (xlat_verbose(style) == XLAT_STYLE_RAW) {
                if (flags || dflt) {
-                       tprintf("%#" PRIx64, flags);
+                       print_xlat_val(flags, style);
                        return 1;
                }
 
@@ -314,10 +416,10 @@ printflags_ex(uint64_t flags, const char *dflt, enum xlat_style style,
        unsigned int n = 0;
        va_list args;
 
-       if (style == XLAT_STYLE_VERBOSE) {
+       if (xlat_verbose(style) == XLAT_STYLE_VERBOSE) {
                init_sep = " /* ";
                if (flags)
-                       tprintf("%#" PRIx64, flags);
+                       print_xlat_val(flags, style);
        }
 
        va_start(args, xlat);
@@ -325,7 +427,8 @@ printflags_ex(uint64_t flags, const char *dflt, enum xlat_style style,
                for (; (flags || !n) && xlat->str; ++xlat) {
                        if ((flags == xlat->val) ||
                            (xlat->val && (flags & xlat->val) == xlat->val)) {
-                               if (style == XLAT_STYLE_VERBOSE && !flags)
+                               if (xlat_verbose(style) == XLAT_STYLE_VERBOSE
+                                   && !flags)
                                        tprints("0");
                                tprintf("%s%s",
                                        (n++ ? "|" : init_sep), xlat->str);
@@ -339,16 +442,17 @@ printflags_ex(uint64_t flags, const char *dflt, enum xlat_style style,
 
        if (n) {
                if (flags) {
-                       tprintf("|%#" PRIx64, flags);
+                       tprints("|");
+                       print_xlat_val(flags, style);
                        n++;
                }
 
-               if (style == XLAT_STYLE_VERBOSE)
+               if (xlat_verbose(style) == XLAT_STYLE_VERBOSE)
                        tprints(" */");
        } else {
                if (flags) {
-                       if (style != XLAT_STYLE_VERBOSE)
-                               tprintf("%#" PRIx64, flags);
+                       if (xlat_verbose(style) != XLAT_STYLE_VERBOSE)
+                               print_xlat_val(flags, style);
                        tprints_comment(dflt);
                } else {
                        if (dflt)
@@ -358,3 +462,50 @@ printflags_ex(uint64_t flags, const char *dflt, enum xlat_style style,
 
        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;
+       }
+}