1 /*
2  * Copyright (c) 1991, 1992 Paul Kranenburg <pk@cs.few.eur.nl>
3  * Copyright (c) 1993 Branko Lankester <branko@hacktic.nl>
4  * Copyright (c) 1993, 1994, 1995, 1996 Rick Sladkey <jrs@world.std.com>
5  * Copyright (c) 1996-1999 Wichert Akkerman <wichert@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
get_xlat_style(enum xlat_style 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 *
sprint_xlat_val(uint64_t val,enum xlat_style style)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
print_xlat_val(uint64_t val,enum xlat_style style)68 print_xlat_val(uint64_t val, enum xlat_style style)
69 {
70 	tprints(sprint_xlat_val(val, style));
71 }
72 
73 const char *
xlookup(const struct xlat * xlat,const uint64_t val)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
xlat_bsearch_compare(const void * a,const void * b)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 *
xlat_search(const struct xlat * xlat,const size_t nmemb,const uint64_t val)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
printxvals_ex(const uint64_t val,const char * dflt,enum xlat_style style,const struct xlat * xlat,...)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
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)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
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))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
printxval_searchn_ex(const struct xlat * xlat,size_t xlat_size,uint64_t val,const char * dflt,enum xlat_style style)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 *
xlat_idx(const struct xlat * xlat,size_t nmemb,uint64_t val)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
printxval_indexn_ex(const struct xlat * xlat,size_t xlat_size,uint64_t val,const char * dflt,enum xlat_style style)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 *
sprintflags_ex(const char * prefix,const struct xlat * xlat,uint64_t flags,enum xlat_style style)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
printflags_ex(uint64_t flags,const char * dflt,enum xlat_style style,const struct xlat * xlat,...)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
print_xlat_ex(const uint64_t val,const char * str,enum xlat_style style)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
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)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