]> granicus.if.org Git - strace/blob - xlat.c
time: use indexed lookups
[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         for (; xlat->str != NULL; xlat++)
77                 if (xlat->val == val)
78                         return xlat->str;
79         return NULL;
80 }
81
82 static int
83 xlat_bsearch_compare(const void *a, const void *b)
84 {
85         const uint64_t val1 = *(const uint64_t *) a;
86         const uint64_t val2 = ((const struct xlat *) b)->val;
87         return (val1 > val2) ? 1 : (val1 < val2) ? -1 : 0;
88 }
89
90 const char *
91 xlat_search(const struct xlat *xlat, const size_t nmemb, const uint64_t val)
92 {
93         const struct xlat *e =
94                 bsearch((const void *) &val,
95                         xlat, nmemb, sizeof(*xlat), xlat_bsearch_compare);
96
97         return e ? e->str : NULL;
98 }
99
100 /**
101  * Print entry in struct xlat table, if there.
102  *
103  * @param val   Value to search a literal representation for.
104  * @param dflt  String (abbreviated in comment syntax) which should be emitted
105  *              if no appropriate xlat value has been found.
106  * @param style Style in which xlat value should be printed.
107  * @param xlat  (And the following arguments) Pointers to arrays of xlat values.
108  *              The last argument should be NULL.
109  * @return      1 if appropriate xlat value has been found, 0 otherwise.
110  */
111 int
112 printxvals_ex(const uint64_t val, const char *dflt, enum xlat_style style,
113               const struct xlat *xlat, ...)
114 {
115         style = get_xlat_style(style);
116
117         if (xlat_verbose(style) == XLAT_STYLE_RAW) {
118                 print_xlat_val(val, style);
119                 return 0;
120         }
121
122         va_list args;
123
124         va_start(args, xlat);
125         for (; xlat; xlat = va_arg(args, const struct xlat *)) {
126                 const char *str = xlookup(xlat, val);
127
128                 if (str) {
129                         if (xlat_verbose(style) == XLAT_STYLE_VERBOSE) {
130                                 print_xlat_val(val, style);
131                                 tprints_comment(str);
132                         } else {
133                                 tprints(str);
134                         }
135
136                         va_end(args);
137                         return 1;
138                 }
139         }
140         /* No hits -- print raw # instead. */
141         print_xlat_val(val, style);
142         tprints_comment(dflt);
143
144         va_end(args);
145
146         return 0;
147 }
148
149 int
150 sprintxval_ex(char *const buf, const size_t size, const struct xlat *const x,
151               const unsigned int val, const char *const dflt,
152               enum xlat_style style)
153 {
154         style = get_xlat_style(style);
155
156         if (xlat_verbose(style) == XLAT_STYLE_RAW)
157                 return xsnprintf(buf, size, "%s", sprint_xlat_val(val, style));
158
159         const char *const str = xlookup(x, val);
160
161         if (str) {
162                 if (xlat_verbose(style) == XLAT_STYLE_VERBOSE)
163                         return xsnprintf(buf, size, "%s /* %s */",
164                                          sprint_xlat_val(val, style), str);
165                 else
166                         return xsnprintf(buf, size, "%s", str);
167         }
168         if (dflt)
169                 return xsnprintf(buf, size, "%s /* %s */",
170                                  sprint_xlat_val(val, style), dflt);
171
172         return xsnprintf(buf, size, "%s", sprint_xlat_val(val, style));
173 }
174
175 /**
176  * Print entry in sorted struct xlat table, if it is there.
177  *
178  * @param xlat      Pointer to an array of xlat values (not terminated with
179  *                  XLAT_END).
180  * @param xlat_size Number of xlat elements present in array (usually ARRAY_SIZE
181  *                  if array is declared in the unit's scope and not
182  *                  terminated with XLAT_END).
183  * @param val       Value to search literal representation for.
184  * @param dflt      String (abbreviated in comment syntax) which should be
185  *                  emitted if no appropriate xlat value has been found.
186  * @param style     Style in which xlat value should be printed.
187  * @param fn        Search function.
188  * @return          1 if appropriate xlat value has been found, 0
189  *                  otherwise.
190  */
191 static int
192 printxval_sized(const struct xlat *xlat, size_t xlat_size, uint64_t val,
193                 const char *dflt, enum xlat_style style,
194                 const char *(* fn)(const struct xlat *, size_t, uint64_t))
195 {
196         style = get_xlat_style(style);
197
198         if (xlat_verbose(style) == XLAT_STYLE_RAW) {
199                 print_xlat_val(val, style);
200                 return 0;
201         }
202
203         const char *s = fn(xlat, xlat_size, val);
204
205         if (s) {
206                 if (xlat_verbose(style) == XLAT_STYLE_VERBOSE) {
207                         print_xlat_val(val, style);
208                         tprints_comment(s);
209                 } else {
210                         tprints(s);
211                 }
212                 return 1;
213         }
214
215         print_xlat_val(val, style);
216         tprints_comment(dflt);
217
218         return 0;
219 }
220
221 int
222 printxval_searchn_ex(const struct xlat *xlat, size_t xlat_size, uint64_t val,
223                      const char *dflt, enum xlat_style style)
224 {
225         return printxval_sized(xlat, xlat_size, val, dflt, style,
226                                   xlat_search);
227 }
228
229 const char *
230 xlat_idx(const struct xlat *xlat, size_t nmemb, uint64_t val)
231 {
232         if (val >= nmemb)
233                 return NULL;
234
235         if (val != xlat[val].val) {
236                 error_func_msg("Unexpected xlat value %" PRIu64
237                                " at index %" PRIu64,
238                                xlat[val].val, val);
239                 return NULL;
240         }
241
242         return xlat[val].str;
243 }
244
245 int
246 printxval_indexn_ex(const struct xlat *xlat, size_t xlat_size, uint64_t val,
247                     const char *dflt, enum xlat_style style)
248 {
249         return printxval_sized(xlat, xlat_size, val, dflt, style, xlat_idx);
250 }
251
252 /*
253  * Interpret `xlat' as an array of flags.
254  * Print to static string the entries whose bits are on in `flags'
255  * Return static string.  If 0 is provided as flags, and there is no flag that
256  * has the value of 0 (it should be the first in xlat table), return NULL.
257  *
258  * Expected output:
259  * +------------+------------+---------+------------+
260  * | flags != 0 | xlat found | style   | output     |
261  * +------------+------------+---------+------------+
262  * | false      | (any)      | raw     | <none>     |
263  * | true       | (any)      | raw     | VAL        |
264  * +------------+------------+---------+------------+
265  * | false      | false      | abbrev  | <none>     |
266  * | true       | false      | abbrev  | VAL        |
267  * | (any)      | true       | abbrev  | XLAT       |
268  * +------------+------------+---------+------------+
269  * | false      | false      | verbose | <none>     |
270  * | true       | false      | verbose | VAL        |
271  * | (any)      | true       | verbose | VAL (XLAT) |
272  * +------------+------------+---------+------------+
273  */
274 const char *
275 sprintflags_ex(const char *prefix, const struct xlat *xlat, uint64_t flags,
276                enum xlat_style style)
277 {
278         static char outstr[1024];
279         char *outptr;
280         int found = 0;
281
282         outptr = stpcpy(outstr, prefix);
283         style = get_xlat_style(style);
284
285         if (xlat_verbose(style) == XLAT_STYLE_RAW) {
286                 if (!flags)
287                         return NULL;
288
289                 outptr = xappendstr(outstr, outptr, "%s",
290                                     sprint_xlat_val(flags, style));
291
292                 return outstr;
293         }
294
295         if (flags == 0 && xlat->val == 0 && xlat->str) {
296                 if (xlat_verbose(style) == XLAT_STYLE_VERBOSE) {
297                         outptr = xappendstr(outstr, outptr, "0 /* %s */",
298                                             xlat->str);
299                 } else {
300                         strcpy(outptr, xlat->str);
301                 }
302
303                 return outstr;
304         }
305
306         if (xlat_verbose(style) == XLAT_STYLE_VERBOSE && flags)
307                 outptr = xappendstr(outstr, outptr, "%s",
308                                     sprint_xlat_val(flags, style));
309
310         for (; flags && xlat->str; xlat++) {
311                 if (xlat->val && (flags & xlat->val) == xlat->val) {
312                         if (found)
313                                 *outptr++ = '|';
314                         else if (xlat_verbose(style) == XLAT_STYLE_VERBOSE)
315                                 outptr = stpcpy(outptr, " /* ");
316
317                         outptr = stpcpy(outptr, xlat->str);
318                         found = 1;
319                         flags &= ~xlat->val;
320                 }
321         }
322
323         if (flags) {
324                 if (found)
325                         *outptr++ = '|';
326                 if (found || xlat_verbose(style) != XLAT_STYLE_VERBOSE)
327                         outptr = xappendstr(outstr, outptr, "%s",
328                                             sprint_xlat_val(flags, style));
329         } else {
330                 if (!found)
331                         return NULL;
332         }
333
334         if (found && xlat_verbose(style) == XLAT_STYLE_VERBOSE)
335                 outptr = stpcpy(outptr, " */");
336
337         return outstr;
338 }
339
340 /**
341  * Print flags from multiple xlat tables.
342  *
343  * Expected output:
344  * +------------+--------------+------------+---------+------------+
345  * | flags != 0 | dflt != NULL | xlat found | style   | output     |
346  * +------------+--------------+------------+---------+------------+
347  * | false      | false        | (any)      | raw     | <none>     |
348  * | false      | true         | (any)      | raw     | VAL        |
349  * | true       | (any)        | (any)      | raw     | VAL        |
350  * +------------+--------------+------------+---------+------------+
351  * | false      | false        | false      | abbrev  | <none>     |
352  * | false      | true         | false      | abbrev  | VAL        |
353  * | true       | false        | false      | abbrev  | VAL        |
354  * | true       | true         | false      | abbrev  | VAL (DFLT) |
355  * | (any)      | (any)        | true       | abbrev  | XLAT       |
356  * +------------+--------------+------------+---------+------------+
357  * | false      | false        | false      | verbose | <none>     |
358  * | false      | true         | false      | verbose | VAL        |
359  * | true       | false        | false      | verbose | VAL        |
360  * | true       | true         | false      | verbose | VAL (DFLT) |
361  * | (any)      | (any)        | true       | verbose | VAL (XLAT) |
362  * +------------+--------------+------------+---------+------------+
363  */
364 int
365 printflags_ex(uint64_t flags, const char *dflt, enum xlat_style style,
366               const struct xlat *xlat, ...)
367 {
368         style = get_xlat_style(style);
369
370         if (xlat_verbose(style) == XLAT_STYLE_RAW) {
371                 if (flags || dflt) {
372                         print_xlat_val(flags, style);
373                         return 1;
374                 }
375
376                 return 0;
377         }
378
379         const char *init_sep = "";
380         unsigned int n = 0;
381         va_list args;
382
383         if (xlat_verbose(style) == XLAT_STYLE_VERBOSE) {
384                 init_sep = " /* ";
385                 if (flags)
386                         print_xlat_val(flags, style);
387         }
388
389         va_start(args, xlat);
390         for (; xlat; xlat = va_arg(args, const struct xlat *)) {
391                 for (; (flags || !n) && xlat->str; ++xlat) {
392                         if ((flags == xlat->val) ||
393                             (xlat->val && (flags & xlat->val) == xlat->val)) {
394                                 if (xlat_verbose(style) == XLAT_STYLE_VERBOSE
395                                     && !flags)
396                                         tprints("0");
397                                 tprintf("%s%s",
398                                         (n++ ? "|" : init_sep), xlat->str);
399                                 flags &= ~xlat->val;
400                         }
401                         if (!flags)
402                                 break;
403                 }
404         }
405         va_end(args);
406
407         if (n) {
408                 if (flags) {
409                         tprints("|");
410                         print_xlat_val(flags, style);
411                         n++;
412                 }
413
414                 if (xlat_verbose(style) == XLAT_STYLE_VERBOSE)
415                         tprints(" */");
416         } else {
417                 if (flags) {
418                         if (xlat_verbose(style) != XLAT_STYLE_VERBOSE)
419                                 print_xlat_val(flags, style);
420                         tprints_comment(dflt);
421                 } else {
422                         if (dflt)
423                                 tprints("0");
424                 }
425         }
426
427         return n;
428 }
429
430 void
431 print_xlat_ex(const uint64_t val, const char *str, enum xlat_style style)
432 {
433         style = get_xlat_style(style);
434
435         switch (xlat_verbose(style)) {
436         case XLAT_STYLE_ABBREV:
437                 if (str) {
438                         tprints(str);
439                         break;
440                 }
441                 ATTRIBUTE_FALLTHROUGH;
442
443         case XLAT_STYLE_RAW:
444                 print_xlat_val(val, style);
445                 break;
446
447         default:
448                 error_func_msg("Unexpected style value of %#x", style);
449                 ATTRIBUTE_FALLTHROUGH;
450
451         case XLAT_STYLE_VERBOSE:
452                 print_xlat_val(val, style);
453                 tprints_comment(str);
454         }
455 }