From e8c3f34eddc79c8e90200410c495ac07c6647638 Mon Sep 17 00:00:00 2001 From: Eugene Syromyatnikov Date: Sat, 10 Mar 2018 04:48:33 +0100 Subject: [PATCH] Introduce xlat verbosity styles * defs.h (printxvals_ex): Rename from printxvals, add style argument. (enum xlat_style): New enumeration. (printxvals): New macro, a wrapper for printxvals_ex. (printxval_searchn_ex): Rename from printxval_searchn, add style argument. (printxval_searchn): New macro, a wrapper for printxval_searchn_ex. (printxval_search_ex): New macro, a wrapper for printxval_searchn_ex. (sprintxval_ex): Rename from sprintxval, add style argument. (sprintxval): New macro, a wrapper for sprintxval_ex. (printflags_ex): Add style argument. (sprintflags_ex): Rename from sprintflags, add style argument. (sprintflags): New macro, a wrapper for sprintflags_ex. (printflags64): Pass XLAT_STYLE_ABBREV as a style in printflags_ex call. * netlink.c (decode_nlmsg_flags): Pass XLAT_STYLE_ABBREV as a style in printflags_ex call. * xlat.c (printxvals_ex): Rename from printxvals, add style argument, handle it. (sprintxval_ex): Rename from sprintxval, add style argument, handle it. (printxval_searchn_ex): Rename from printxval_searchn, add style argument, handle it. (sprintflags_ex): Rename from sprintflags, add style argument, handle it. (printflags_ex): Add style argument, handle it. Co-Authored-by: Dmitry V. Levin References: https://github.com/strace/strace/issues/27 --- defs.h | 49 +++++++++++++--- netlink.c | 3 +- xlat.c | 168 ++++++++++++++++++++++++++++++++++++++++++++++-------- 3 files changed, 187 insertions(+), 33 deletions(-) diff --git a/defs.h b/defs.h index 12c76f38..569825ff 100644 --- a/defs.h +++ b/defs.h @@ -583,10 +583,31 @@ extern int printllval(struct tcb *, const char *, int) extern void printaddr64(uint64_t addr); extern void printaddr(kernel_ulong_t addr); -extern int printxvals(const uint64_t, const char *, const struct xlat *, ...) + +enum xlat_style { + /** Print xlat value as is without xlat processing */ + XLAT_STYLE_RAW = 1 << 0, + /** + * Historic strace style, process xlat and print the result (xlat + * constant name/combination of flags), raw number only if nothing is + * found. + */ + XLAT_STYLE_ABBREV = 1 << 1, + /** Always print both raw number and xlat processing result. */ + XLAT_STYLE_VERBOSE = XLAT_STYLE_RAW | XLAT_STYLE_ABBREV, +}; + +extern int printxvals_ex(uint64_t val, const char *dflt, + enum xlat_style style, const struct xlat *, ...) ATTRIBUTE_SENTINEL; -extern int printxval_searchn(const struct xlat *xlat, size_t xlat_size, - uint64_t val, const char *dflt); +#define printxvals(val_, dflt_, ...) \ + printxvals_ex((val_), (dflt_), XLAT_STYLE_ABBREV, __VA_ARGS__) +extern int printxval_searchn_ex(const struct xlat *xlat, size_t xlat_size, + uint64_t val, const char *dflt, + enum xlat_style style); +#define printxval_searchn(xlat_, xlat_size_, val_, dflt_) \ + printxval_searchn_ex((xlat_), (xlat_size_), (val_), (dflt_), \ + XLAT_STYLE_ABBREV) /** * Wrapper around printxval_searchn that passes ARRAY_SIZE - 1 * as the array size, as all arrays are XLAT_END-terminated and @@ -594,15 +615,27 @@ extern int printxval_searchn(const struct xlat *xlat, size_t xlat_size, */ #define printxval_search(xlat__, val__, dflt__) \ printxval_searchn(xlat__, ARRAY_SIZE(xlat__) - 1, val__, dflt__) -extern int sprintxval(char *buf, size_t size, const struct xlat *, - unsigned int val, const char *dflt); +#define printxval_search_ex(xlat__, val__, dflt__) \ + printxval_searchn_ex((xlat__), ARRAY_SIZE(xlat__) - 1, (val__), \ + (dflt__), XLAT_STYLE_ABBREV) +extern int sprintxval_ex(char *buf, size_t size, const struct xlat *xlat, + unsigned int val, const char *dflt, + enum xlat_style style); +#define sprintxval(buf_, size_, xlat_, val_, dflt_) \ + sprintxval_ex((buf_), (size_), (xlat_), (val_), (dflt_), \ + XLAT_STYLE_ABBREV) + extern int printargs(struct tcb *); extern int printargs_u(struct tcb *); extern int printargs_d(struct tcb *); -extern int printflags_ex(uint64_t, const char *, const struct xlat *, ...) +extern int printflags_ex(uint64_t flags, const char *dflt, + enum xlat_style style, const struct xlat *, ...) ATTRIBUTE_SENTINEL; -extern const char *sprintflags(const char *, const struct xlat *, uint64_t); +extern const char *sprintflags_ex(const char *prefix, const struct xlat *xlat, + uint64_t flags, enum xlat_style style); +#define sprintflags(prefix_, xlat_, flags_) \ + sprintflags_ex((prefix_), (xlat_), (flags_), XLAT_STYLE_ABBREV) extern const char *sprinttime(long long sec); extern const char *sprinttime_nsec(long long sec, unsigned long long nsec); extern const char *sprinttime_usec(long long sec, unsigned long long usec); @@ -779,7 +812,7 @@ printstr(struct tcb *tcp, kernel_ulong_t addr) static inline int printflags64(const struct xlat *x, uint64_t flags, const char *dflt) { - return printflags_ex(flags, dflt, x, NULL); + return printflags_ex(flags, dflt, XLAT_STYLE_ABBREV, x, NULL); } static inline int diff --git a/netlink.c b/netlink.c index c9abb4c8..46a394c6 100644 --- a/netlink.c +++ b/netlink.c @@ -430,7 +430,8 @@ decode_nlmsg_flags(const uint16_t flags, const uint16_t type, } else if (family < ARRAY_SIZE(nlmsg_flags) && nlmsg_flags[family]) table = nlmsg_flags[family](type); - printflags_ex(flags, "NLM_F_???", netlink_flags, table, NULL); + printflags_ex(flags, "NLM_F_???", XLAT_STYLE_ABBREV, + netlink_flags, table, NULL); } static void diff --git a/xlat.c b/xlat.c index be58f72e..647786b6 100644 --- a/xlat.c +++ b/xlat.c @@ -63,16 +63,23 @@ xlat_search(const struct xlat *xlat, const size_t nmemb, const uint64_t val) /** * 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, ...) { + if (style == XLAT_STYLE_RAW) { + tprintf("%#" PRIx64, val); + return 0; + } + va_list args; va_start(args, xlat); @@ -80,7 +87,13 @@ printxvals(const uint64_t val, const char *dflt, const struct xlat *xlat, ...) const char *str = xlookup(xlat, val); if (str) { - tprints(str); + if (style == XLAT_STYLE_VERBOSE) { + tprintf("%#" PRIx64, val); + tprints_comment(str); + } else { + tprints(str); + } + va_end(args); return 1; } @@ -95,13 +108,21 @@ printxvals(const uint64_t val, const char *dflt, const struct xlat *xlat, ...) } int -sprintxval(char *const buf, const size_t size, const struct xlat *const x, - const unsigned int val, const char *const dflt) +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) { + if (style == XLAT_STYLE_RAW) + return xsnprintf(buf, size, "%#x", val); + const char *const str = xlookup(x, val); - if (str) - return xsnprintf(buf, size, "%s", str); + if (str) { + if (style == XLAT_STYLE_VERBOSE) + return xsnprintf(buf, size, "%#x /* %s */", val, str); + else + return xsnprintf(buf, size, "%s", str); + } if (dflt) return xsnprintf(buf, size, "%#x /* %s */", val, dflt); @@ -119,17 +140,28 @@ sprintxval(char *const buf, const size_t size, const struct xlat *const x, * @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. * @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) +printxval_searchn_ex(const struct xlat *xlat, size_t xlat_size, uint64_t val, + const char *dflt, enum xlat_style style) { + if (style == XLAT_STYLE_RAW) { + tprintf("%#" PRIx64, val); + return 0; + } + const char *s = xlat_search(xlat, xlat_size, val); if (s) { - tprints(s); + if (style == XLAT_STYLE_VERBOSE) { + tprintf("%#" PRIx64, val); + tprints_comment(s); + } else { + tprints(s); + } return 1; } @@ -144,9 +176,26 @@ printxval_searchn(const struct xlat *xlat, size_t xlat_size, uint64_t val, * Print to static string the entries whose bits are on in `flags' * 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 | | + * | true | (any) | raw | VAL | + * +------------+------------+---------+------------+ + * | false | false | abbrev | | + * | true | false | abbrev | VAL | + * | (any) | true | abbrev | XLAT | + * +------------+------------+---------+------------+ + * | false | false | verbose | | + * | 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; @@ -154,47 +203,114 @@ sprintflags(const char *prefix, const struct xlat *xlat, uint64_t flags) outptr = stpcpy(outstr, prefix); + if (style == XLAT_STYLE_RAW) { + if (!flags) + return NULL; + + outptr = xappendstr(outstr, outptr, "%#" PRIx64, flags); + + return outstr; + } + if (flags == 0 && xlat->val == 0 && xlat->str) { - strcpy(outptr, xlat->str); + if (style == XLAT_STYLE_VERBOSE) { + outptr = xappendstr(outstr, outptr, "0 /* %s */", + xlat->str); + } else { + strcpy(outptr, xlat->str); + } + return outstr; } - for (; xlat->str; xlat++) { + if (style == XLAT_STYLE_VERBOSE && flags) + outptr = xappendstr(outstr, outptr, "%#" PRIx64, flags); + + for (; flags && xlat->str; xlat++) { if (xlat->val && (flags & xlat->val) == xlat->val) { if (found) *outptr++ = '|'; + else if (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 = xappendstr(outstr, outptr, "%#" PRIx64, flags); + if (found || style != XLAT_STYLE_VERBOSE) + outptr = xappendstr(outstr, outptr, "%#" PRIx64, flags); } else { if (!found) return NULL; } + if (found && 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 | | + * | false | true | (any) | raw | VAL | + * | true | (any) | (any) | raw | VAL | + * +------------+--------------+------------+---------+------------+ + * | false | false | false | abbrev | | + * | 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 | | + * | 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, ...) { + if (style == XLAT_STYLE_RAW) { + if (flags || dflt) { + tprintf("%#" PRIx64, flags); + return 1; + } + + return 0; + } + + const char *init_sep = ""; unsigned int n = 0; va_list args; + if (style == XLAT_STYLE_VERBOSE) { + init_sep = " /* "; + if (flags) + tprintf("%#" PRIx64, flags); + } + 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 (style == XLAT_STYLE_VERBOSE && !flags) + tprints("0"); + tprintf("%s%s", + (n++ ? "|" : init_sep), xlat->str); flags &= ~xlat->val; } if (!flags) @@ -208,9 +324,13 @@ printflags_ex(uint64_t flags, const char *dflt, const struct xlat *xlat, ...) tprintf("|%#" PRIx64, flags); n++; } + + if (style == XLAT_STYLE_VERBOSE) + tprints(" */"); } else { if (flags) { - tprintf("%#" PRIx64, flags); + if (style != XLAT_STYLE_VERBOSE) + tprintf("%#" PRIx64, flags); tprints_comment(dflt); } else { if (dflt) -- 2.40.0