1 /* 2 * Copyright (c) 1991, 1992 Paul Kranenburg <pk (at) cs.few.eur.nl> 3 * Copyright (c) 1993 Branko Lankester <branko (at) hacktic.nl> 4 * Copyright (c) 1993, 1994, 1995, 1996 Rick Sladkey <jrs (at) world.std.com> 5 * Copyright (c) 1996-1999 Wichert Akkerman <wichert (at) 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 bool default_str = style & PXF_DEFAULT_STR; 470 style = get_xlat_style(style); 471 472 switch (xlat_verbose(style)) { 473 case XLAT_STYLE_ABBREV: 474 if (str) { 475 if (default_str) { 476 print_xlat_val(val, style); 477 tprints_comment(str); 478 } else { 479 tprints(str); 480 } 481 break; 482 } 483 ATTRIBUTE_FALLTHROUGH; 484 485 case XLAT_STYLE_RAW: 486 print_xlat_val(val, style); 487 break; 488 489 default: 490 error_func_msg("Unexpected style value of %#x", style); 491 ATTRIBUTE_FALLTHROUGH; 492 493 case XLAT_STYLE_VERBOSE: 494 print_xlat_val(val, style); 495 tprints_comment(str); 496 } 497 } 498 499 void 500 printxval_dispatch_ex(const struct xlat *xlat, size_t xlat_size, uint64_t val, 501 const char *dflt, enum xlat_type xt, 502 enum xlat_style style) 503 { 504 switch (xt) { 505 case XT_NORMAL: 506 printxvals_ex(val, dflt, style, xlat, NULL); 507 break; 508 509 case XT_SORTED: 510 printxval_searchn_ex(xlat, xlat_size, val, dflt, style); 511 break; 512 513 case XT_INDEXED: 514 printxval_indexn_ex(xlat, xlat_size, val, dflt, style); 515 break; 516 } 517 } 518