Home | History | Annotate | Download | only in strace
      1 /*
      2  * Copyright (c) 1991, 1992 Paul Kranenburg <pk (at) cs.few.eur.nl>
      3  * Copyright (c) 1993 Branko Lankester <branko (at) hacktic.nl>
      4  * Copyright (c) 1993, 1994, 1995, 1996 Rick Sladkey <jrs (at) world.std.com>
      5  * Copyright (c) 1996-1999 Wichert Akkerman <wichert (at) cistron.nl>
      6  * Copyright (c) 1999-2018 The strace developers.
      7  * All rights reserved.
      8  *
      9  * Redistribution and use in source and binary forms, with or without
     10  * modification, are permitted provided that the following conditions
     11  * are met:
     12  * 1. Redistributions of source code must retain the above copyright
     13  *    notice, this list of conditions and the following disclaimer.
     14  * 2. Redistributions in binary form must reproduce the above copyright
     15  *    notice, this list of conditions and the following disclaimer in the
     16  *    documentation and/or other materials provided with the distribution.
     17  * 3. The name of the author may not be used to endorse or promote products
     18  *    derived from this software without specific prior written permission.
     19  *
     20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     21  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     22  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     23  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     24  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     25  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     29  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     30  */
     31 
     32 #include "defs.h"
     33 #include "xstring.h"
     34 #include <stdarg.h>
     35 
     36 static inline enum xlat_style
     37 get_xlat_style(enum xlat_style style)
     38 {
     39 	if (xlat_verbose(style) == XLAT_STYLE_DEFAULT)
     40 		return style | xlat_verbosity;
     41 
     42 	return style;
     43 }
     44 
     45 static inline const char *
     46 sprint_xlat_val(uint64_t val, enum xlat_style style)
     47 {
     48 	static char buf[sizeof(val) * 3];
     49 
     50 	switch (xlat_format(style)) {
     51 	case XLAT_STYLE_FMT_D:
     52 		xsprintf(buf, "%" PRId64, val);
     53 		break;
     54 
     55 	case XLAT_STYLE_FMT_U:
     56 		xsprintf(buf, "%" PRIu64, val);
     57 		break;
     58 
     59 	case XLAT_STYLE_FMT_X:
     60 		xsprintf(buf, "%#" PRIx64, val);
     61 		break;
     62 	}
     63 
     64 	return buf;
     65 }
     66 
     67 static inline void
     68 print_xlat_val(uint64_t val, enum xlat_style style)
     69 {
     70 	tprints(sprint_xlat_val(val, style));
     71 }
     72 
     73 const char *
     74 xlookup(const struct xlat *xlat, const uint64_t val)
     75 {
     76 	static const struct xlat *pos;
     77 
     78 	if (xlat)
     79 		pos = xlat;
     80 
     81 	for (; pos->str != NULL; pos++)
     82 		if (pos->val == val)
     83 			return pos->str;
     84 	return NULL;
     85 }
     86 
     87 static int
     88 xlat_bsearch_compare(const void *a, const void *b)
     89 {
     90 	const uint64_t val1 = *(const uint64_t *) a;
     91 	const uint64_t val2 = ((const struct xlat *) b)->val;
     92 	return (val1 > val2) ? 1 : (val1 < val2) ? -1 : 0;
     93 }
     94 
     95 const char *
     96 xlat_search(const struct xlat *xlat, const size_t nmemb, const uint64_t val)
     97 {
     98 	static const struct xlat *pos;
     99 	static size_t memb_left;
    100 
    101 	if (xlat) {
    102 		pos = xlat;
    103 		memb_left = nmemb;
    104 	}
    105 
    106 	const struct xlat *e =
    107 		bsearch((const void *) &val,
    108 			pos, memb_left, sizeof(*pos), xlat_bsearch_compare);
    109 
    110 	if (e) {
    111 		memb_left -= e - pos;
    112 		return e->str;
    113 	} else {
    114 		return NULL;
    115 	}
    116 }
    117 
    118 /**
    119  * Print entry in struct xlat table, if there.
    120  *
    121  * @param val   Value to search a literal representation for.
    122  * @param dflt  String (abbreviated in comment syntax) which should be emitted
    123  *              if no appropriate xlat value has been found.
    124  * @param style Style in which xlat value should be printed.
    125  * @param xlat  (And the following arguments) Pointers to arrays of xlat values.
    126  *              The last argument should be NULL.
    127  * @return      1 if appropriate xlat value has been found, 0 otherwise.
    128  */
    129 int
    130 printxvals_ex(const uint64_t val, const char *dflt, enum xlat_style style,
    131 	      const struct xlat *xlat, ...)
    132 {
    133 	static const struct xlat *last;
    134 
    135 	style = get_xlat_style(style);
    136 
    137 	if (xlat_verbose(style) == XLAT_STYLE_RAW) {
    138 		print_xlat_val(val, style);
    139 		return 0;
    140 	}
    141 
    142 	const char *str = NULL;
    143 	va_list args;
    144 
    145 	va_start(args, xlat);
    146 
    147 	if (!xlat)
    148 		xlat = last;
    149 
    150 	for (; xlat; xlat = va_arg(args, const struct xlat *)) {
    151 		last = xlat;
    152 
    153 		str = xlookup(xlat, val);
    154 
    155 		if (str) {
    156 			if (xlat_verbose(style) == XLAT_STYLE_VERBOSE) {
    157 				print_xlat_val(val, style);
    158 				tprints_comment(str);
    159 			} else {
    160 				tprints(str);
    161 			}
    162 
    163 			goto printxvals_ex_end;
    164 		}
    165 	}
    166 
    167 	/* No hits -- print raw # instead. */
    168 	print_xlat_val(val, style);
    169 	tprints_comment(dflt);
    170 
    171 printxvals_ex_end:
    172 	va_end(args);
    173 
    174 	return !!str;
    175 }
    176 
    177 int
    178 sprintxval_ex(char *const buf, const size_t size, const struct xlat *const x,
    179 	      const unsigned int val, const char *const dflt,
    180 	      enum xlat_style style)
    181 {
    182 	style = get_xlat_style(style);
    183 
    184 	if (xlat_verbose(style) == XLAT_STYLE_RAW)
    185 		return xsnprintf(buf, size, "%s", sprint_xlat_val(val, style));
    186 
    187 	const char *const str = xlookup(x, val);
    188 
    189 	if (str) {
    190 		if (xlat_verbose(style) == XLAT_STYLE_VERBOSE)
    191 			return xsnprintf(buf, size, "%s /* %s */",
    192 					 sprint_xlat_val(val, style), str);
    193 		else
    194 			return xsnprintf(buf, size, "%s", str);
    195 	}
    196 	if (dflt)
    197 		return xsnprintf(buf, size, "%s /* %s */",
    198 				 sprint_xlat_val(val, style), dflt);
    199 
    200 	return xsnprintf(buf, size, "%s", sprint_xlat_val(val, style));
    201 }
    202 
    203 /**
    204  * Print entry in sorted struct xlat table, if it is there.
    205  *
    206  * @param xlat      Pointer to an array of xlat values (not terminated with
    207  *                  XLAT_END).
    208  * @param xlat_size Number of xlat elements present in array (usually ARRAY_SIZE
    209  *                  if array is declared in the unit's scope and not
    210  *                  terminated with XLAT_END).
    211  * @param val       Value to search literal representation for.
    212  * @param dflt      String (abbreviated in comment syntax) which should be
    213  *                  emitted if no appropriate xlat value has been found.
    214  * @param style     Style in which xlat value should be printed.
    215  * @param fn        Search function.
    216  * @return          1 if appropriate xlat value has been found, 0
    217  *                  otherwise.
    218  */
    219 static int
    220 printxval_sized(const struct xlat *xlat, size_t xlat_size, uint64_t val,
    221 		const char *dflt, enum xlat_style style,
    222 		const char *(* fn)(const struct xlat *, size_t, uint64_t))
    223 {
    224 	style = get_xlat_style(style);
    225 
    226 	if (xlat_verbose(style) == XLAT_STYLE_RAW) {
    227 		print_xlat_val(val, style);
    228 		return 0;
    229 	}
    230 
    231 	const char *s = fn(xlat, xlat_size, val);
    232 
    233 	if (s) {
    234 		if (xlat_verbose(style) == XLAT_STYLE_VERBOSE) {
    235 			print_xlat_val(val, style);
    236 			tprints_comment(s);
    237 		} else {
    238 			tprints(s);
    239 		}
    240 		return 1;
    241 	}
    242 
    243 	print_xlat_val(val, style);
    244 	tprints_comment(dflt);
    245 
    246 	return 0;
    247 }
    248 
    249 int
    250 printxval_searchn_ex(const struct xlat *xlat, size_t xlat_size, uint64_t val,
    251 		     const char *dflt, enum xlat_style style)
    252 {
    253 	return printxval_sized(xlat, xlat_size, val, dflt, style,
    254 				  xlat_search);
    255 }
    256 
    257 const char *
    258 xlat_idx(const struct xlat *xlat, size_t nmemb, uint64_t val)
    259 {
    260 	static const struct xlat *pos;
    261 	static size_t memb_left;
    262 
    263 	if (xlat) {
    264 		pos = xlat;
    265 		memb_left = nmemb;
    266 	}
    267 
    268 	if (val >= memb_left)
    269 		return NULL;
    270 
    271 	if (val != pos[val].val) {
    272 		error_func_msg("Unexpected xlat value %" PRIu64
    273 			       " at index %" PRIu64,
    274 			       pos[val].val, val);
    275 		return NULL;
    276 	}
    277 
    278 	return pos[val].str;
    279 }
    280 
    281 int
    282 printxval_indexn_ex(const struct xlat *xlat, size_t xlat_size, uint64_t val,
    283 		    const char *dflt, enum xlat_style style)
    284 {
    285 	return printxval_sized(xlat, xlat_size, val, dflt, style, xlat_idx);
    286 }
    287 
    288 /*
    289  * Interpret `xlat' as an array of flags.
    290  * Print to static string the entries whose bits are on in `flags'
    291  * Return static string.  If 0 is provided as flags, and there is no flag that
    292  * has the value of 0 (it should be the first in xlat table), return NULL.
    293  *
    294  * Expected output:
    295  * +------------+------------+---------+------------+
    296  * | flags != 0 | xlat found | style   | output     |
    297  * +------------+------------+---------+------------+
    298  * | false      | (any)      | raw     | <none>     |
    299  * | true       | (any)      | raw     | VAL        |
    300  * +------------+------------+---------+------------+
    301  * | false      | false      | abbrev  | <none>     |
    302  * | true       | false      | abbrev  | VAL        |
    303  * | (any)      | true       | abbrev  | XLAT       |
    304  * +------------+------------+---------+------------+
    305  * | false      | false      | verbose | <none>     |
    306  * | true       | false      | verbose | VAL        |
    307  * | (any)      | true       | verbose | VAL (XLAT) |
    308  * +------------+------------+---------+------------+
    309  */
    310 const char *
    311 sprintflags_ex(const char *prefix, const struct xlat *xlat, uint64_t flags,
    312 	       enum xlat_style style)
    313 {
    314 	static char outstr[1024];
    315 	char *outptr;
    316 	int found = 0;
    317 
    318 	outptr = stpcpy(outstr, prefix);
    319 	style = get_xlat_style(style);
    320 
    321 	if (xlat_verbose(style) == XLAT_STYLE_RAW) {
    322 		if (!flags)
    323 			return NULL;
    324 
    325 		outptr = xappendstr(outstr, outptr, "%s",
    326 				    sprint_xlat_val(flags, style));
    327 
    328 		return outstr;
    329 	}
    330 
    331 	if (flags == 0 && xlat->val == 0 && xlat->str) {
    332 		if (xlat_verbose(style) == XLAT_STYLE_VERBOSE) {
    333 			outptr = xappendstr(outstr, outptr, "0 /* %s */",
    334 					    xlat->str);
    335 		} else {
    336 			strcpy(outptr, xlat->str);
    337 		}
    338 
    339 		return outstr;
    340 	}
    341 
    342 	if (xlat_verbose(style) == XLAT_STYLE_VERBOSE && flags)
    343 		outptr = xappendstr(outstr, outptr, "%s",
    344 				    sprint_xlat_val(flags, style));
    345 
    346 	for (; flags && xlat->str; xlat++) {
    347 		if (xlat->val && (flags & xlat->val) == xlat->val) {
    348 			if (found)
    349 				*outptr++ = '|';
    350 			else if (xlat_verbose(style) == XLAT_STYLE_VERBOSE)
    351 				outptr = stpcpy(outptr, " /* ");
    352 
    353 			outptr = stpcpy(outptr, xlat->str);
    354 			found = 1;
    355 			flags &= ~xlat->val;
    356 		}
    357 	}
    358 
    359 	if (flags) {
    360 		if (found)
    361 			*outptr++ = '|';
    362 		if (found || xlat_verbose(style) != XLAT_STYLE_VERBOSE)
    363 			outptr = xappendstr(outstr, outptr, "%s",
    364 					    sprint_xlat_val(flags, style));
    365 	} else {
    366 		if (!found)
    367 			return NULL;
    368 	}
    369 
    370 	if (found && xlat_verbose(style) == XLAT_STYLE_VERBOSE)
    371 		outptr = stpcpy(outptr, " */");
    372 
    373 	return outstr;
    374 }
    375 
    376 /**
    377  * Print flags from multiple xlat tables.
    378  *
    379  * Expected output:
    380  * +------------+--------------+------------+---------+------------+
    381  * | flags != 0 | dflt != NULL | xlat found | style   | output     |
    382  * +------------+--------------+------------+---------+------------+
    383  * | false      | false        | (any)      | raw     | <none>     |
    384  * | false      | true         | (any)      | raw     | VAL        |
    385  * | true       | (any)        | (any)      | raw     | VAL        |
    386  * +------------+--------------+------------+---------+------------+
    387  * | false      | false        | false      | abbrev  | <none>     |
    388  * | false      | true         | false      | abbrev  | VAL        |
    389  * | true       | false        | false      | abbrev  | VAL        |
    390  * | true       | true         | false      | abbrev  | VAL (DFLT) |
    391  * | (any)      | (any)        | true       | abbrev  | XLAT       |
    392  * +------------+--------------+------------+---------+------------+
    393  * | false      | false        | false      | verbose | <none>     |
    394  * | false      | true         | false      | verbose | VAL        |
    395  * | true       | false        | false      | verbose | VAL        |
    396  * | true       | true         | false      | verbose | VAL (DFLT) |
    397  * | (any)      | (any)        | true       | verbose | VAL (XLAT) |
    398  * +------------+--------------+------------+---------+------------+
    399  */
    400 int
    401 printflags_ex(uint64_t flags, const char *dflt, enum xlat_style style,
    402 	      const struct xlat *xlat, ...)
    403 {
    404 	style = get_xlat_style(style);
    405 
    406 	if (xlat_verbose(style) == XLAT_STYLE_RAW) {
    407 		if (flags || dflt) {
    408 			print_xlat_val(flags, style);
    409 			return 1;
    410 		}
    411 
    412 		return 0;
    413 	}
    414 
    415 	const char *init_sep = "";
    416 	unsigned int n = 0;
    417 	va_list args;
    418 
    419 	if (xlat_verbose(style) == XLAT_STYLE_VERBOSE) {
    420 		init_sep = " /* ";
    421 		if (flags)
    422 			print_xlat_val(flags, style);
    423 	}
    424 
    425 	va_start(args, xlat);
    426 	for (; xlat; xlat = va_arg(args, const struct xlat *)) {
    427 		for (; (flags || !n) && xlat->str; ++xlat) {
    428 			if ((flags == xlat->val) ||
    429 			    (xlat->val && (flags & xlat->val) == xlat->val)) {
    430 				if (xlat_verbose(style) == XLAT_STYLE_VERBOSE
    431 				    && !flags)
    432 					tprints("0");
    433 				tprintf("%s%s",
    434 					(n++ ? "|" : init_sep), xlat->str);
    435 				flags &= ~xlat->val;
    436 			}
    437 			if (!flags)
    438 				break;
    439 		}
    440 	}
    441 	va_end(args);
    442 
    443 	if (n) {
    444 		if (flags) {
    445 			tprints("|");
    446 			print_xlat_val(flags, style);
    447 			n++;
    448 		}
    449 
    450 		if (xlat_verbose(style) == XLAT_STYLE_VERBOSE)
    451 			tprints(" */");
    452 	} else {
    453 		if (flags) {
    454 			if (xlat_verbose(style) != XLAT_STYLE_VERBOSE)
    455 				print_xlat_val(flags, style);
    456 			tprints_comment(dflt);
    457 		} else {
    458 			if (dflt)
    459 				tprints("0");
    460 		}
    461 	}
    462 
    463 	return n;
    464 }
    465 
    466 void
    467 print_xlat_ex(const uint64_t val, const char *str, enum xlat_style style)
    468 {
    469 	bool default_str = style & PXF_DEFAULT_STR;
    470 	style = get_xlat_style(style);
    471 
    472 	switch (xlat_verbose(style)) {
    473 	case XLAT_STYLE_ABBREV:
    474 		if (str) {
    475 			if (default_str) {
    476 				print_xlat_val(val, style);
    477 				tprints_comment(str);
    478 			} else {
    479 				tprints(str);
    480 			}
    481 			break;
    482 		}
    483 		ATTRIBUTE_FALLTHROUGH;
    484 
    485 	case XLAT_STYLE_RAW:
    486 		print_xlat_val(val, style);
    487 		break;
    488 
    489 	default:
    490 		error_func_msg("Unexpected style value of %#x", style);
    491 		ATTRIBUTE_FALLTHROUGH;
    492 
    493 	case XLAT_STYLE_VERBOSE:
    494 		print_xlat_val(val, style);
    495 		tprints_comment(str);
    496 	}
    497 }
    498 
    499 void
    500 printxval_dispatch_ex(const struct xlat *xlat, size_t xlat_size, uint64_t val,
    501 		      const char *dflt, enum xlat_type xt,
    502 		      enum xlat_style style)
    503 {
    504 	switch (xt) {
    505 	case XT_NORMAL:
    506 		printxvals_ex(val, dflt, style, xlat, NULL);
    507 		break;
    508 
    509 	case XT_SORTED:
    510 		printxval_searchn_ex(xlat, xlat_size, val, dflt, style);
    511 		break;
    512 
    513 	case XT_INDEXED:
    514 		printxval_indexn_ex(xlat, xlat_size, val, dflt, style);
    515 		break;
    516 	}
    517 }
    518