]> granicus.if.org Git - strace/blob - xlat.c
xlat.c: handle NULL xlat in lookup routines as incremental search
[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  * 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         style = get_xlat_style(style);
470
471         switch (xlat_verbose(style)) {
472         case XLAT_STYLE_ABBREV:
473                 if (str) {
474                         tprints(str);
475                         break;
476                 }
477                 ATTRIBUTE_FALLTHROUGH;
478
479         case XLAT_STYLE_RAW:
480                 print_xlat_val(val, style);
481                 break;
482
483         default:
484                 error_func_msg("Unexpected style value of %#x", style);
485                 ATTRIBUTE_FALLTHROUGH;
486
487         case XLAT_STYLE_VERBOSE:
488                 print_xlat_val(val, style);
489                 tprints_comment(str);
490         }
491 }
492
493 void
494 printxval_dispatch_ex(const struct xlat *xlat, size_t xlat_size, uint64_t val,
495                       const char *dflt, enum xlat_type xt,
496                       enum xlat_style style)
497 {
498         switch (xt) {
499         case XT_NORMAL:
500                 printxvals_ex(val, dflt, style, xlat, NULL);
501                 break;
502
503         case XT_SORTED:
504                 printxval_searchn_ex(xlat, xlat_size, val, dflt, style);
505                 break;
506
507         case XT_INDEXED:
508                 printxval_indexn_ex(xlat, xlat_size, val, dflt, style);
509                 break;
510         }
511 }