]> granicus.if.org Git - strace/blob - xlat.c
Introduce print_xlat and print_xlat_ex
[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 ((style & XLAT_STYLE_VERBOSITY_MASK) == XLAT_STYLE_DEFAULT)
40                 return style | xlat_verbosity;
41
42         return style;
43 }
44
45 const char *
46 xlookup(const struct xlat *xlat, const uint64_t val)
47 {
48         for (; xlat->str != NULL; xlat++)
49                 if (xlat->val == val)
50                         return xlat->str;
51         return NULL;
52 }
53
54 static int
55 xlat_bsearch_compare(const void *a, const void *b)
56 {
57         const uint64_t val1 = *(const uint64_t *) a;
58         const uint64_t val2 = ((const struct xlat *) b)->val;
59         return (val1 > val2) ? 1 : (val1 < val2) ? -1 : 0;
60 }
61
62 const char *
63 xlat_search(const struct xlat *xlat, const size_t nmemb, const uint64_t val)
64 {
65         const struct xlat *e =
66                 bsearch((const void *) &val,
67                         xlat, nmemb, sizeof(*xlat), xlat_bsearch_compare);
68
69         return e ? e->str : NULL;
70 }
71
72 /**
73  * Print entry in struct xlat table, if there.
74  *
75  * @param val   Value to search a literal representation for.
76  * @param dflt  String (abbreviated in comment syntax) which should be emitted
77  *              if no appropriate xlat value has been found.
78  * @param style Style in which xlat value should be printed.
79  * @param xlat  (And the following arguments) Pointers to arrays of xlat values.
80  *              The last argument should be NULL.
81  * @return      1 if appropriate xlat value has been found, 0 otherwise.
82  */
83 int
84 printxvals_ex(const uint64_t val, const char *dflt, enum xlat_style style,
85               const struct xlat *xlat, ...)
86 {
87         style = get_xlat_style(style);
88
89         if (style == XLAT_STYLE_RAW) {
90                 tprintf("%#" PRIx64, val);
91                 return 0;
92         }
93
94         va_list args;
95
96         va_start(args, xlat);
97         for (; xlat; xlat = va_arg(args, const struct xlat *)) {
98                 const char *str = xlookup(xlat, val);
99
100                 if (str) {
101                         if (style == XLAT_STYLE_VERBOSE) {
102                                 tprintf("%#" PRIx64, val);
103                                 tprints_comment(str);
104                         } else {
105                                 tprints(str);
106                         }
107
108                         va_end(args);
109                         return 1;
110                 }
111         }
112         /* No hits -- print raw # instead. */
113         tprintf("%#" PRIx64, val);
114         tprints_comment(dflt);
115
116         va_end(args);
117
118         return 0;
119 }
120
121 int
122 sprintxval_ex(char *const buf, const size_t size, const struct xlat *const x,
123               const unsigned int val, const char *const dflt,
124               enum xlat_style style)
125 {
126         style = get_xlat_style(style);
127
128         if (style == XLAT_STYLE_RAW)
129                 return xsnprintf(buf, size, "%#x", val);
130
131         const char *const str = xlookup(x, val);
132
133         if (str) {
134                 if (style == XLAT_STYLE_VERBOSE)
135                         return xsnprintf(buf, size, "%#x /* %s */", val, str);
136                 else
137                         return xsnprintf(buf, size, "%s", str);
138         }
139         if (dflt)
140                 return xsnprintf(buf, size, "%#x /* %s */", val, dflt);
141
142         return xsnprintf(buf, size, "%#x", val);
143 }
144
145 /**
146  * Print entry in sorted struct xlat table, if it is there.
147  *
148  * @param xlat      Pointer to an array of xlat values (not terminated with
149  *                  XLAT_END).
150  * @param xlat_size Number of xlat elements present in array (usually ARRAY_SIZE
151  *                  if array is declared in the unit's scope and not
152  *                  terminated with XLAT_END).
153  * @param val       Value to search literal representation for.
154  * @param dflt      String (abbreviated in comment syntax) which should be
155  *                  emitted if no appropriate xlat value has been found.
156  * @param style     Style in which xlat value should be printed.
157  * @return          1 if appropriate xlat value has been found, 0
158  *                  otherwise.
159  */
160 int
161 printxval_searchn_ex(const struct xlat *xlat, size_t xlat_size, uint64_t val,
162                      const char *dflt, enum xlat_style style)
163 {
164         style = get_xlat_style(style);
165
166         if (style == XLAT_STYLE_RAW) {
167                 tprintf("%#" PRIx64, val);
168                 return 0;
169         }
170
171         const char *s = xlat_search(xlat, xlat_size, val);
172
173         if (s) {
174                 if (style == XLAT_STYLE_VERBOSE) {
175                         tprintf("%#" PRIx64, val);
176                         tprints_comment(s);
177                 } else {
178                         tprints(s);
179                 }
180                 return 1;
181         }
182
183         tprintf("%#" PRIx64, val);
184         tprints_comment(dflt);
185
186         return 0;
187 }
188
189 /*
190  * Interpret `xlat' as an array of flags.
191  * Print to static string the entries whose bits are on in `flags'
192  * Return static string.  If 0 is provided as flags, and there is no flag that
193  * has the value of 0 (it should be the first in xlat table), return NULL.
194  *
195  * Expected output:
196  * +------------+------------+---------+------------+
197  * | flags != 0 | xlat found | style   | output     |
198  * +------------+------------+---------+------------+
199  * | false      | (any)      | raw     | <none>     |
200  * | true       | (any)      | raw     | VAL        |
201  * +------------+------------+---------+------------+
202  * | false      | false      | abbrev  | <none>     |
203  * | true       | false      | abbrev  | VAL        |
204  * | (any)      | true       | abbrev  | XLAT       |
205  * +------------+------------+---------+------------+
206  * | false      | false      | verbose | <none>     |
207  * | true       | false      | verbose | VAL        |
208  * | (any)      | true       | verbose | VAL (XLAT) |
209  * +------------+------------+---------+------------+
210  */
211 const char *
212 sprintflags_ex(const char *prefix, const struct xlat *xlat, uint64_t flags,
213                enum xlat_style style)
214 {
215         static char outstr[1024];
216         char *outptr;
217         int found = 0;
218
219         outptr = stpcpy(outstr, prefix);
220         style = get_xlat_style(style);
221
222         if (style == XLAT_STYLE_RAW) {
223                 if (!flags)
224                         return NULL;
225
226                 outptr = xappendstr(outstr, outptr, "%#" PRIx64, flags);
227
228                 return outstr;
229         }
230
231         if (flags == 0 && xlat->val == 0 && xlat->str) {
232                 if (style == XLAT_STYLE_VERBOSE) {
233                         outptr = xappendstr(outstr, outptr, "0 /* %s */",
234                                             xlat->str);
235                 } else {
236                         strcpy(outptr, xlat->str);
237                 }
238
239                 return outstr;
240         }
241
242         if (style == XLAT_STYLE_VERBOSE && flags)
243                 outptr = xappendstr(outstr, outptr, "%#" PRIx64, flags);
244
245         for (; flags && xlat->str; xlat++) {
246                 if (xlat->val && (flags & xlat->val) == xlat->val) {
247                         if (found)
248                                 *outptr++ = '|';
249                         else if (style == XLAT_STYLE_VERBOSE)
250                                 outptr = stpcpy(outptr, " /* ");
251
252                         outptr = stpcpy(outptr, xlat->str);
253                         found = 1;
254                         flags &= ~xlat->val;
255                 }
256         }
257
258         if (flags) {
259                 if (found)
260                         *outptr++ = '|';
261                 if (found || style != XLAT_STYLE_VERBOSE)
262                         outptr = xappendstr(outstr, outptr, "%#" PRIx64, flags);
263         } else {
264                 if (!found)
265                         return NULL;
266         }
267
268         if (found && style == XLAT_STYLE_VERBOSE)
269                 outptr = stpcpy(outptr, " */");
270
271         return outstr;
272 }
273
274 /**
275  * Print flags from multiple xlat tables.
276  *
277  * Expected output:
278  * +------------+--------------+------------+---------+------------+
279  * | flags != 0 | dflt != NULL | xlat found | style   | output     |
280  * +------------+--------------+------------+---------+------------+
281  * | false      | false        | (any)      | raw     | <none>     |
282  * | false      | true         | (any)      | raw     | VAL        |
283  * | true       | (any)        | (any)      | raw     | VAL        |
284  * +------------+--------------+------------+---------+------------+
285  * | false      | false        | false      | abbrev  | <none>     |
286  * | false      | true         | false      | abbrev  | VAL        |
287  * | true       | false        | false      | abbrev  | VAL        |
288  * | true       | true         | false      | abbrev  | VAL (DFLT) |
289  * | (any)      | (any)        | true       | abbrev  | XLAT       |
290  * +------------+--------------+------------+---------+------------+
291  * | false      | false        | false      | verbose | <none>     |
292  * | false      | true         | false      | verbose | VAL        |
293  * | true       | false        | false      | verbose | VAL        |
294  * | true       | true         | false      | verbose | VAL (DFLT) |
295  * | (any)      | (any)        | true       | verbose | VAL (XLAT) |
296  * +------------+--------------+------------+---------+------------+
297  */
298 int
299 printflags_ex(uint64_t flags, const char *dflt, enum xlat_style style,
300               const struct xlat *xlat, ...)
301 {
302         style = get_xlat_style(style);
303
304         if (style == XLAT_STYLE_RAW) {
305                 if (flags || dflt) {
306                         tprintf("%#" PRIx64, flags);
307                         return 1;
308                 }
309
310                 return 0;
311         }
312
313         const char *init_sep = "";
314         unsigned int n = 0;
315         va_list args;
316
317         if (style == XLAT_STYLE_VERBOSE) {
318                 init_sep = " /* ";
319                 if (flags)
320                         tprintf("%#" PRIx64, flags);
321         }
322
323         va_start(args, xlat);
324         for (; xlat; xlat = va_arg(args, const struct xlat *)) {
325                 for (; (flags || !n) && xlat->str; ++xlat) {
326                         if ((flags == xlat->val) ||
327                             (xlat->val && (flags & xlat->val) == xlat->val)) {
328                                 if (style == XLAT_STYLE_VERBOSE && !flags)
329                                         tprints("0");
330                                 tprintf("%s%s",
331                                         (n++ ? "|" : init_sep), xlat->str);
332                                 flags &= ~xlat->val;
333                         }
334                         if (!flags)
335                                 break;
336                 }
337         }
338         va_end(args);
339
340         if (n) {
341                 if (flags) {
342                         tprintf("|%#" PRIx64, flags);
343                         n++;
344                 }
345
346                 if (style == XLAT_STYLE_VERBOSE)
347                         tprints(" */");
348         } else {
349                 if (flags) {
350                         if (style != XLAT_STYLE_VERBOSE)
351                                 tprintf("%#" PRIx64, flags);
352                         tprints_comment(dflt);
353                 } else {
354                         if (dflt)
355                                 tprints("0");
356                 }
357         }
358
359         return n;
360 }
361
362 void
363 print_xlat_ex(const uint64_t val, const char *str, enum xlat_style style)
364 {
365         style = get_xlat_style(style);
366
367         switch (style) {
368         case XLAT_STYLE_RAW:
369                 tprintf("%#" PRIx64, val);
370                 break;
371
372         case XLAT_STYLE_ABBREV:
373                 tprints(str);
374                 break;
375
376         default:
377                 error_func_msg("Unexpected style value of %#x", style);
378                 ATTRIBUTE_FALLTHROUGH;
379
380         case XLAT_STYLE_VERBOSE:
381                 tprintf("%#" PRIx64, val);
382                 tprints_comment(str);
383         }
384 }