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