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-2022 The strace developers.
7 * All rights reserved.
8 *
9 * SPDX-License-Identifier: LGPL-2.1-or-later
10 */
11
12 #include "defs.h"
13 #include "xstring.h"
14 #include <stdarg.h>
15
16 static enum xlat_style
17 get_xlat_style(enum xlat_style style)
18 {
19 if (xlat_verbose(style) == XLAT_STYLE_DEFAULT)
20 return style | xlat_verbosity;
21
22 return style;
23 }
24
25 static const char *
26 sprint_xlat_val(uint64_t val, enum xlat_style style)
27 {
28 static char buf[sizeof(val) * 3];
29
30 switch (xlat_format(style)) {
31 case XLAT_STYLE_FMT_D:
32 xsprintf(buf, "%" PRId64, val);
33 break;
34
35 case XLAT_STYLE_FMT_U:
36 xsprintf(buf, "%" PRIu64, val);
37 break;
38
39 case XLAT_STYLE_FMT_X:
40 xsprintf(buf, "%#" PRIx64, val);
41 break;
42 }
43
44 return buf;
45 }
46
47 static void
48 print_xlat_val(uint64_t val, enum xlat_style style)
49 {
50 tprints_string(sprint_xlat_val(val, style));
51 }
52
53 static int
54 xlat_bsearch_compare(const void *a, const void *b)
55 {
56 const uint64_t val1 = *(const uint64_t *) a;
57 const uint64_t val2 = ((const struct xlat_data *) b)->val;
58 return (val1 > val2) ? 1 : (val1 < val2) ? -1 : 0;
59 }
60
61 const char *
62 xlookup(const struct xlat *x, const uint64_t val)
63 {
64 const struct xlat_data *e;
65
66 if (!x || !x->data)
67 return NULL;
68
69 switch (x->type) {
70 case XT_NORMAL:
71 for (size_t idx = 0; idx < x->size; idx++)
72 if (x->data[idx].val == val)
73 return x->data[idx].str;
74 break;
75
76 case XT_SORTED:
77 e = bsearch((const void *) &val,
78 x->data, x->size,
79 sizeof(x->data[0]),
80 xlat_bsearch_compare);
81 if (e)
82 return e->str;
83 break;
84
85 case XT_INDEXED:
86 if (val < x->size) {
87 if (val == x->data[val].val)
88 return x->data[val].str;
89 if (x->data[val].val == 0)
90 break; /* a hole in the index */
91 error_func_msg("Unexpected xlat value %" PRIu64
92 " at index %" PRIu64 " (str %s)",
93 x->data[val].val, val,
94 x->data[val].str);
95 }
96 break;
97
98 default:
99 error_func_msg("Invalid xlat type: %#x", x->type);
100 }
101
102 return NULL;
103 }
104
105 static const char *
106 xlat_search_eq_or_less(const struct xlat *xlat, uint64_t *val)
107 {
108 const struct xlat_data *base = xlat->data;
109 const struct xlat_data *cur = xlat->data;
110 size_t nmemb = xlat->size;
111
112 for (; nmemb > 0; nmemb >>= 1) {
113 cur = base + (nmemb >> 1);
114
115 if (*val == cur->val)
116 return cur->str;
117
118 if (*val > cur->val) {
119 base = cur + 1;
120 nmemb--;
121 }
122 }
123
124 if (*val < cur->val) {
125 if (cur > xlat->data)
126 cur--;
127 else
128 return NULL;
129 }
130
131 *val = cur->val;
132 return cur->str;
133 }
134
135 const char *
136 xlookup_le(const struct xlat *xlat, uint64_t *val)
137 {
138 if (!xlat || !xlat->data)
139 return NULL;
140
141 switch (xlat->type) {
142 case XT_SORTED:
143 return xlat_search_eq_or_less(xlat, val);
144
145 #if 0 /* enable when used */
146 case XT_NORMAL: {
147 uint64_t best_hit = 0;
148 const char *str = NULL;
149
150 for (size_t idx = 0; idx < xlat->size; idx++) {
151 if (xlat->data[idx].val == *val)
152 return xlat->data[idx].str;
153
154 if (xlat->data[idx].val < *val
155 && xlat->data[idx].val > best_hit) {
156 best_hit = xlat->data[idx].val;
157 str = xlat->data[idx].str;
158 }
159 }
160
161 *val = best_hit;
162 return str;
163 }
164
165 case XT_INDEXED: {
166 size_t idx = *val;
167
168 if (idx >= xlat->size) {
169 if (!xlat->size)
170 return NULL;
171
172 idx = xlat->size - 1;
173 }
174
175 do {
176 if (idx == xlat->data[idx].val && xlat->data[idx].str) {
177 *val = idx;
178 return xlat->data[idx].str;
179 }
180 if (xlat->data[idx].val == 0)
181 continue; /* a hole in the index */
182 error_func_msg("Unexpected xlat value %" PRIu64
183 " at index %zu (str %s)",
184 xlat->data[idx].val, idx,
185 xlat->data[idx].str);
186 } while (idx--);
187 return NULL;
188 }
189 #endif
190
191 default:
192 error_func_msg("Invalid xlat type: %#x", xlat->type);
193 }
194
195 return NULL;
196 }
197
198 /**
199 * Print an entry in struct xlat table, if it is there.
200 *
201 * @param val A value to search a literal representation for.
202 * @param dflt A string (encased in comment syntax) which is to be emitted
203 * if no appropriate xlat value has been found.
204 * @param style A style which is to be used for xlat value printing.
205 * @param xlat (and the following arguments) Pointers xlat description
206 * structures.
207 * The last argument should be NULL.
208 * @return 1 if an appropriate xlat value has been found, 0 otherwise.
209 */
210 int
211 printxvals_ex(const uint64_t val, const char *dflt, enum xlat_style style,
212 const struct xlat *xlat, ...)
213 {
214 style = get_xlat_style(style);
215
216 if (xlat_verbose(style) == XLAT_STYLE_RAW) {
217 print_xlat_val(val, style);
218 return 0;
219 }
220
221 const char *str = NULL;
222 va_list args;
223
224 va_start(args, xlat);
225
226 for (; xlat; xlat = va_arg(args, const struct xlat *)) {
227 str = xlookup(xlat, val);
228
229 if (str) {
230 if (xlat_verbose(style) == XLAT_STYLE_VERBOSE) {
231 print_xlat_val(val, style);
232 tprints_comment(str);
233 } else {
234 tprints_string(str);
235 }
236
237 goto printxvals_ex_end;
238 }
239 }
240
241 /* No hits -- print raw # instead. */
242 print_xlat_val(val, style);
243 tprints_comment(dflt);
244
245 printxvals_ex_end:
246 va_end(args);
247
248 return !!str;
249 }
250
251 int
252 sprintxval_ex(char *const buf, const size_t size, const struct xlat *const x,
253 const unsigned int val, const char *const dflt,
254 enum xlat_style style)
255 {
256 style = get_xlat_style(style);
257
258 if (xlat_verbose(style) == XLAT_STYLE_RAW)
259 return xsnprintf(buf, size, "%s", sprint_xlat_val(val, style));
260
261 const char *const str = xlookup(x, val);
262
263 if (str) {
264 if (xlat_verbose(style) == XLAT_STYLE_VERBOSE)
265 return xsnprintf(buf, size, "%s /* %s */",
266 sprint_xlat_val(val, style), str);
267 else
268 return xsnprintf(buf, size, "%s", str);
269 }
270 if (dflt)
271 return xsnprintf(buf, size, "%s /* %s */",
272 sprint_xlat_val(val, style), dflt);
273
274 return xsnprintf(buf, size, "%s", sprint_xlat_val(val, style));
275 }
276
277 /*
278 * Interpret `xlat' as an array of flags.
279 * Print to static string the entries whose bits are on in `flags'
280 * Return static string. If 0 is provided as flags, and there is no flag that
281 * has the value of 0 (it should be the first in xlat table), return NULL.
282 *
283 * Expected output:
284 * +------------+------------+---------+------------+
285 * | flags != 0 | xlat found | style | output |
286 * +------------+------------+---------+------------+
287 * | false | (any) | raw | <none> |
288 * | true | (any) | raw | VAL |
289 * +------------+------------+---------+------------+
290 * | false | false | abbrev | <none> |
291 * | true | false | abbrev | VAL |
292 * | (any) | true | abbrev | XLAT |
293 * +------------+------------+---------+------------+
294 * | false | false | verbose | <none> |
295 * | true | false | verbose | VAL |
296 * | (any) | true | verbose | VAL (XLAT) |
297 * +------------+------------+---------+------------+
298 */
299 const char *
300 sprintflags_ex(const char *prefix, const struct xlat *xlat, uint64_t flags,
301 char sep, enum xlat_style style)
302 {
303 static char outstr[1024];
304 char *outptr;
305 int found = 0;
306
307 outptr = stpcpy(outstr, prefix);
308 style = get_xlat_style(style);
309
310 if (xlat_verbose(style) == XLAT_STYLE_RAW) {
311 if (!flags || ((style & SPFF_AUXSTR_MODE) && !sep))
312 return NULL;
313
314 if (sep)
315 *outptr++ = sep;
316 outptr = xappendstr(outstr, outptr, "%s",
317 sprint_xlat_val(flags, style));
318
319 return outstr;
320 }
321
322 if (flags == 0 && xlat->data->val == 0 && xlat->data->str) {
323 if (sep)
324 *outptr++ = sep;
325 if (xlat_verbose(style) == XLAT_STYLE_VERBOSE &&
326 !(style & SPFF_AUXSTR_MODE)) {
327 outptr = xappendstr(outstr, outptr, "0 /* %s */",
328 xlat->data->str);
329 } else {
330 strcpy(outptr, xlat->data->str);
331 }
332
333 return outstr;
334 }
335
336 if (xlat_verbose(style) == XLAT_STYLE_VERBOSE && flags &&
337 !(style & SPFF_AUXSTR_MODE)) {
338 if (sep) {
339 *outptr++ = sep;
340 sep = '\0';
341 }
342 outptr = xappendstr(outstr, outptr, "%s",
343 sprint_xlat_val(flags, style));
344 }
345
346 for (size_t idx = 0; flags && idx < xlat->size; idx++) {
347 if (xlat->data[idx].val && xlat->data[idx].str
348 && (flags & xlat->data[idx].val) == xlat->data[idx].val) {
349 if (sep) {
350 *outptr++ = sep;
351 } else if (xlat_verbose(style) == XLAT_STYLE_VERBOSE &&
352 !(style & SPFF_AUXSTR_MODE)) {
353 outptr = stpcpy(outptr, " /* ");
354 }
355
356 outptr = stpcpy(outptr, xlat->data[idx].str);
357 found = 1;
358 sep = '|';
359 flags &= ~xlat->data[idx].val;
360 }
361 }
362
363 if (flags) {
364 if (sep)
365 *outptr++ = sep;
366 if (found || (xlat_verbose(style) != XLAT_STYLE_VERBOSE &&
367 (!(style & SPFF_AUXSTR_MODE) || sep)))
368 outptr = xappendstr(outstr, outptr, "%s",
369 sprint_xlat_val(flags, style));
370 } else {
371 if (!found)
372 return NULL;
373 }
374
375 if (found && xlat_verbose(style) == XLAT_STYLE_VERBOSE &&
376 !(style & SPFF_AUXSTR_MODE))
377 outptr = stpcpy(outptr, " */");
378
379 return outptr != outstr ? outstr : NULL;
380 }
381
382 /**
383 * Print flags from multiple xlat tables.
384 *
385 * Expected output:
386 * +------------+--------------+------------+---------+------------+
387 * | flags != 0 | dflt != NULL | xlat found | style | output |
388 * +------------+--------------+------------+---------+------------+
389 * | false | false | (any) | raw | <none> |
390 * | false | true | (any) | raw | VAL |
391 * | true | (any) | (any) | raw | VAL |
392 * +------------+--------------+------------+---------+------------+
393 * | false | false | false | abbrev | <none> |
394 * | false | true | false | abbrev | VAL |
395 * | true | false | false | abbrev | VAL |
396 * | true | true | false | abbrev | VAL (DFLT) |
397 * | (any) | (any) | true | abbrev | XLAT |
398 * +------------+--------------+------------+---------+------------+
399 * | false | false | false | verbose | <none> |
400 * | false | true | false | verbose | VAL |
401 * | true | false | false | verbose | VAL |
402 * | true | true | false | verbose | VAL (DFLT) |
403 * | (any) | (any) | true | verbose | VAL (XLAT) |
404 * +------------+--------------+------------+---------+------------+
405 */
406 int
407 printflags_ex(uint64_t flags, const char *dflt, enum xlat_style style,
408 const struct xlat *xlat, ...)
409 {
410 style = get_xlat_style(style);
411
412 if (xlat_verbose(style) == XLAT_STYLE_RAW) {
413 if (flags || dflt) {
414 print_xlat_val(flags, style);
415 return 1;
416 }
417
418 return 0;
419 }
420
421 bool need_comment = false;
422 unsigned int n = 0;
423 va_list args;
424
425 if (xlat_verbose(style) == XLAT_STYLE_VERBOSE) {
426 need_comment = true;
427 if (flags)
428 print_xlat_val(flags, style);
429 }
430
431 va_start(args, xlat);
432 for (; xlat; xlat = va_arg(args, const struct xlat *)) {
433 for (size_t idx = 0; (flags || !n) && idx < xlat->size; ++idx) {
434 uint64_t v = xlat->data[idx].val;
435 if (xlat->data[idx].str
436 && ((flags == v) || (v && (flags & v) == v))) {
437 if (xlat_verbose(style) == XLAT_STYLE_VERBOSE
438 && !flags)
439 PRINT_VAL_U(0);
440 if (n++)
441 tprint_flags_or();
442 else if (need_comment)
443 tprint_comment_begin();
444 tprints_string(xlat->data[idx].str);
445 flags &= ~v;
446 }
447 if (!flags)
448 break;
449 }
450 }
451 va_end(args);
452
453 if (n) {
454 if (flags) {
455 tprint_flags_or();
456 print_xlat_val(flags, style);
457 n++;
458 }
459
460 if (xlat_verbose(style) == XLAT_STYLE_VERBOSE)
461 tprint_comment_end();
462 } else {
463 if (flags) {
464 if (xlat_verbose(style) != XLAT_STYLE_VERBOSE)
465 print_xlat_val(flags, style);
466 tprints_comment(dflt);
467 } else {
468 if (dflt)
469 PRINT_VAL_U(0);
470 }
471 }
472
473 return n;
474 }
475
476 void
477 print_xlat_ex(const uint64_t val, const char *str, uint32_t style)
478 {
479 bool default_str = style & PXF_DEFAULT_STR;
480 style = get_xlat_style(style);
481
482 switch (xlat_verbose(style)) {
483 case XLAT_STYLE_ABBREV:
484 if (str) {
485 if (default_str) {
486 print_xlat_val(val, style);
487 tprints_comment(str);
488 } else {
489 tprints_string(str);
490 }
491 break;
492 }
493 ATTRIBUTE_FALLTHROUGH;
494
495 case XLAT_STYLE_RAW:
496 print_xlat_val(val, style);
497 break;
498
499 default:
500 error_func_msg("Unexpected style value of %#x", style);
501 ATTRIBUTE_FALLTHROUGH;
502
503 case XLAT_STYLE_VERBOSE:
504 print_xlat_val(val, style);
505 tprints_comment(str);
506 }
507 }