Mirror of strace – the linux syscall tracer
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

xlat.c 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516
  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. #include "defs.h"
  12. #include "xstring.h"
  13. #include <stdarg.h>
  14. static inline enum xlat_style
  15. get_xlat_style(enum xlat_style style)
  16. {
  17. if (xlat_verbose(style) == XLAT_STYLE_DEFAULT)
  18. return style | xlat_verbosity;
  19. return style;
  20. }
  21. static inline const char *
  22. sprint_xlat_val(uint64_t val, enum xlat_style style)
  23. {
  24. static char buf[sizeof(val) * 3];
  25. switch (xlat_format(style)) {
  26. case XLAT_STYLE_FMT_D:
  27. xsprintf(buf, "%" PRId64, val);
  28. break;
  29. case XLAT_STYLE_FMT_U:
  30. xsprintf(buf, "%" PRIu64, val);
  31. break;
  32. case XLAT_STYLE_FMT_X:
  33. xsprintf(buf, "%#" PRIx64, val);
  34. break;
  35. }
  36. return buf;
  37. }
  38. static inline void
  39. print_xlat_val(uint64_t val, enum xlat_style style)
  40. {
  41. tprints(sprint_xlat_val(val, style));
  42. }
  43. static int
  44. xlat_bsearch_compare(const void *a, const void *b)
  45. {
  46. const uint64_t val1 = *(const uint64_t *) a;
  47. const uint64_t val2 = ((const struct xlat_data *) b)->val;
  48. return (val1 > val2) ? 1 : (val1 < val2) ? -1 : 0;
  49. }
  50. const char *
  51. xlookup(const struct xlat *xlat, const uint64_t val)
  52. {
  53. static const struct xlat *x;
  54. static size_t idx;
  55. const struct xlat_data *e;
  56. if (xlat) {
  57. x = xlat;
  58. idx = 0;
  59. }
  60. if (!x || !x->data)
  61. return NULL;
  62. switch (x->type) {
  63. case XT_NORMAL:
  64. for (; idx < x->size; idx++)
  65. if (x->data[idx].val == val)
  66. return x->data[idx].str;
  67. break;
  68. case XT_SORTED:
  69. e = bsearch((const void *) &val,
  70. x->data + idx,
  71. x->size - idx,
  72. sizeof(x->data[0]),
  73. xlat_bsearch_compare);
  74. if (e) {
  75. idx = e - x->data;
  76. return e->str;
  77. }
  78. break;
  79. case XT_INDEXED:
  80. if (val < x->size) {
  81. if (val == x->data[val].val)
  82. return x->data[val].str;
  83. if (x->data[val].val == 0)
  84. break; /* a hole in the index */
  85. error_func_msg("Unexpected xlat value %" PRIu64
  86. " at index %" PRIu64 " (str %s)",
  87. x->data[val].val, val,
  88. x->data[val].str);
  89. }
  90. break;
  91. default:
  92. error_func_msg("Invalid xlat type: %#x", x->type);
  93. }
  94. return NULL;
  95. }
  96. static const char *
  97. xlat_search_eq_or_less(const struct xlat *xlat, uint64_t *val)
  98. {
  99. const struct xlat_data *base = xlat->data;
  100. const struct xlat_data *cur = xlat->data;
  101. size_t nmemb = xlat->size;
  102. for (; nmemb > 0; nmemb >>= 1) {
  103. cur = base + (nmemb >> 1);
  104. if (*val == cur->val)
  105. return cur->str;
  106. if (*val > cur->val) {
  107. base = cur + 1;
  108. nmemb--;
  109. }
  110. }
  111. if (*val < cur->val) {
  112. if (cur > xlat->data)
  113. cur--;
  114. else
  115. return NULL;
  116. }
  117. *val = cur->val;
  118. return cur->str;
  119. }
  120. const char *
  121. xlookup_le(const struct xlat *xlat, uint64_t *val)
  122. {
  123. if (!xlat || !xlat->data)
  124. return NULL;
  125. switch (xlat->type) {
  126. case XT_SORTED:
  127. return xlat_search_eq_or_less(xlat, val);
  128. #if 0 /* enable when used */
  129. case XT_NORMAL: {
  130. uint64_t best_hit = 0;
  131. const char *str = NULL;
  132. for (size_t idx = 0; idx < xlat->size; idx++) {
  133. if (xlat->data[idx].val == *val)
  134. return xlat->data[idx].str;
  135. if (xlat->data[idx].val < *val
  136. && xlat->data[idx].val > best_hit) {
  137. best_hit = xlat->data[idx].val;
  138. str = xlat->data[idx].str;
  139. }
  140. }
  141. *val = best_hit;
  142. return str;
  143. }
  144. case XT_INDEXED: {
  145. size_t idx = *val;
  146. if (idx >= xlat->size) {
  147. if (!xlat->size)
  148. return NULL;
  149. idx = xlat->size - 1;
  150. }
  151. do {
  152. if (idx == xlat->data[idx].val && xlat->data[idx].str) {
  153. *val = idx;
  154. return xlat->data[idx].str;
  155. }
  156. if (xlat->data[idx].val == 0)
  157. continue; /* a hole in the index */
  158. error_func_msg("Unexpected xlat value %" PRIu64
  159. " at index %zu (str %s)",
  160. xlat->data[idx].val, idx,
  161. xlat->data[idx].str);
  162. } while (idx--);
  163. return NULL;
  164. }
  165. #endif
  166. default:
  167. error_func_msg("Invalid xlat type: %#x", xlat->type);
  168. }
  169. return NULL;
  170. }
  171. /**
  172. * Print entry in struct xlat table, if there.
  173. *
  174. * @param val Value to search a literal representation for.
  175. * @param dflt String (abbreviated in comment syntax) which should be emitted
  176. * if no appropriate xlat value has been found.
  177. * @param style Style in which xlat value should be printed.
  178. * @param xlat (And the following arguments) Pointers to arrays of xlat values.
  179. * The last argument should be NULL.
  180. * @return 1 if appropriate xlat value has been found, 0 otherwise.
  181. */
  182. int
  183. printxvals_ex(const uint64_t val, const char *dflt, enum xlat_style style,
  184. const struct xlat *xlat, ...)
  185. {
  186. static const struct xlat *last;
  187. style = get_xlat_style(style);
  188. if (xlat_verbose(style) == XLAT_STYLE_RAW) {
  189. print_xlat_val(val, style);
  190. return 0;
  191. }
  192. const char *str = NULL;
  193. va_list args;
  194. va_start(args, xlat);
  195. if (!xlat)
  196. xlat = last;
  197. for (; xlat; xlat = va_arg(args, const struct xlat *)) {
  198. last = xlat;
  199. str = xlookup(xlat, val);
  200. if (str) {
  201. if (xlat_verbose(style) == XLAT_STYLE_VERBOSE) {
  202. print_xlat_val(val, style);
  203. tprints_comment(str);
  204. } else {
  205. tprints(str);
  206. }
  207. goto printxvals_ex_end;
  208. }
  209. }
  210. /* No hits -- print raw # instead. */
  211. print_xlat_val(val, style);
  212. tprints_comment(dflt);
  213. printxvals_ex_end:
  214. va_end(args);
  215. return !!str;
  216. }
  217. int
  218. sprintxval_ex(char *const buf, const size_t size, const struct xlat *const x,
  219. const unsigned int val, const char *const dflt,
  220. enum xlat_style style)
  221. {
  222. style = get_xlat_style(style);
  223. if (xlat_verbose(style) == XLAT_STYLE_RAW)
  224. return xsnprintf(buf, size, "%s", sprint_xlat_val(val, style));
  225. const char *const str = xlookup(x, val);
  226. if (str) {
  227. if (xlat_verbose(style) == XLAT_STYLE_VERBOSE)
  228. return xsnprintf(buf, size, "%s /* %s */",
  229. sprint_xlat_val(val, style), str);
  230. else
  231. return xsnprintf(buf, size, "%s", str);
  232. }
  233. if (dflt)
  234. return xsnprintf(buf, size, "%s /* %s */",
  235. sprint_xlat_val(val, style), dflt);
  236. return xsnprintf(buf, size, "%s", sprint_xlat_val(val, style));
  237. }
  238. /*
  239. * Interpret `xlat' as an array of flags.
  240. * Print to static string the entries whose bits are on in `flags'
  241. * Return static string. If 0 is provided as flags, and there is no flag that
  242. * has the value of 0 (it should be the first in xlat table), return NULL.
  243. *
  244. * Expected output:
  245. * +------------+------------+---------+------------+
  246. * | flags != 0 | xlat found | style | output |
  247. * +------------+------------+---------+------------+
  248. * | false | (any) | raw | <none> |
  249. * | true | (any) | raw | VAL |
  250. * +------------+------------+---------+------------+
  251. * | false | false | abbrev | <none> |
  252. * | true | false | abbrev | VAL |
  253. * | (any) | true | abbrev | XLAT |
  254. * +------------+------------+---------+------------+
  255. * | false | false | verbose | <none> |
  256. * | true | false | verbose | VAL |
  257. * | (any) | true | verbose | VAL (XLAT) |
  258. * +------------+------------+---------+------------+
  259. */
  260. const char *
  261. sprintflags_ex(const char *prefix, const struct xlat *xlat, uint64_t flags,
  262. char sep, enum xlat_style style)
  263. {
  264. static char outstr[1024];
  265. char *outptr;
  266. int found = 0;
  267. outptr = stpcpy(outstr, prefix);
  268. style = get_xlat_style(style);
  269. if (xlat_verbose(style) == XLAT_STYLE_RAW) {
  270. if (!flags)
  271. return NULL;
  272. if (sep)
  273. *outptr++ = sep;
  274. outptr = xappendstr(outstr, outptr, "%s",
  275. sprint_xlat_val(flags, style));
  276. return outstr;
  277. }
  278. if (flags == 0 && xlat->data->val == 0 && xlat->data->str) {
  279. if (sep)
  280. *outptr++ = sep;
  281. if (xlat_verbose(style) == XLAT_STYLE_VERBOSE) {
  282. outptr = xappendstr(outstr, outptr, "0 /* %s */",
  283. xlat->data->str);
  284. } else {
  285. strcpy(outptr, xlat->data->str);
  286. }
  287. return outstr;
  288. }
  289. if (xlat_verbose(style) == XLAT_STYLE_VERBOSE && flags) {
  290. if (sep) {
  291. *outptr++ = sep;
  292. sep = '\0';
  293. }
  294. outptr = xappendstr(outstr, outptr, "%s",
  295. sprint_xlat_val(flags, style));
  296. }
  297. for (size_t idx = 0; flags && idx < xlat->size; idx++) {
  298. if (xlat->data[idx].val && xlat->data[idx].str
  299. && (flags & xlat->data[idx].val) == xlat->data[idx].val) {
  300. if (sep) {
  301. *outptr++ = sep;
  302. } else if (xlat_verbose(style) == XLAT_STYLE_VERBOSE) {
  303. outptr = stpcpy(outptr, " /* ");
  304. }
  305. outptr = stpcpy(outptr, xlat->data[idx].str);
  306. found = 1;
  307. sep = '|';
  308. flags &= ~xlat->data[idx].val;
  309. }
  310. }
  311. if (flags) {
  312. if (sep)
  313. *outptr++ = sep;
  314. if (found || xlat_verbose(style) != XLAT_STYLE_VERBOSE)
  315. outptr = xappendstr(outstr, outptr, "%s",
  316. sprint_xlat_val(flags, style));
  317. } else {
  318. if (!found)
  319. return NULL;
  320. }
  321. if (found && xlat_verbose(style) == XLAT_STYLE_VERBOSE)
  322. outptr = stpcpy(outptr, " */");
  323. return outstr;
  324. }
  325. /**
  326. * Print flags from multiple xlat tables.
  327. *
  328. * Expected output:
  329. * +------------+--------------+------------+---------+------------+
  330. * | flags != 0 | dflt != NULL | xlat found | style | output |
  331. * +------------+--------------+------------+---------+------------+
  332. * | false | false | (any) | raw | <none> |
  333. * | false | true | (any) | raw | VAL |
  334. * | true | (any) | (any) | raw | VAL |
  335. * +------------+--------------+------------+---------+------------+
  336. * | false | false | false | abbrev | <none> |
  337. * | false | true | false | abbrev | VAL |
  338. * | true | false | false | abbrev | VAL |
  339. * | true | true | false | abbrev | VAL (DFLT) |
  340. * | (any) | (any) | true | abbrev | XLAT |
  341. * +------------+--------------+------------+---------+------------+
  342. * | false | false | false | verbose | <none> |
  343. * | false | true | false | verbose | VAL |
  344. * | true | false | false | verbose | VAL |
  345. * | true | true | false | verbose | VAL (DFLT) |
  346. * | (any) | (any) | true | verbose | VAL (XLAT) |
  347. * +------------+--------------+------------+---------+------------+
  348. */
  349. int
  350. printflags_ex(uint64_t flags, const char *dflt, enum xlat_style style,
  351. const struct xlat *xlat, ...)
  352. {
  353. style = get_xlat_style(style);
  354. if (xlat_verbose(style) == XLAT_STYLE_RAW) {
  355. if (flags || dflt) {
  356. print_xlat_val(flags, style);
  357. return 1;
  358. }
  359. return 0;
  360. }
  361. const char *init_sep = "";
  362. unsigned int n = 0;
  363. va_list args;
  364. if (xlat_verbose(style) == XLAT_STYLE_VERBOSE) {
  365. init_sep = " /* ";
  366. if (flags)
  367. print_xlat_val(flags, style);
  368. }
  369. va_start(args, xlat);
  370. for (; xlat; xlat = va_arg(args, const struct xlat *)) {
  371. for (size_t idx = 0; (flags || !n) && idx < xlat->size; ++idx) {
  372. uint64_t v = xlat->data[idx].val;
  373. if (xlat->data[idx].str
  374. && ((flags == v) || (v && (flags & v) == v))) {
  375. if (xlat_verbose(style) == XLAT_STYLE_VERBOSE
  376. && !flags)
  377. tprints("0");
  378. tprintf("%s%s",
  379. (n++ ? "|" : init_sep),
  380. xlat->data[idx].str);
  381. flags &= ~v;
  382. }
  383. if (!flags)
  384. break;
  385. }
  386. }
  387. va_end(args);
  388. if (n) {
  389. if (flags) {
  390. tprints("|");
  391. print_xlat_val(flags, style);
  392. n++;
  393. }
  394. if (xlat_verbose(style) == XLAT_STYLE_VERBOSE)
  395. tprints(" */");
  396. } else {
  397. if (flags) {
  398. if (xlat_verbose(style) != XLAT_STYLE_VERBOSE)
  399. print_xlat_val(flags, style);
  400. tprints_comment(dflt);
  401. } else {
  402. if (dflt)
  403. tprints("0");
  404. }
  405. }
  406. return n;
  407. }
  408. void
  409. print_xlat_ex(const uint64_t val, const char *str, enum xlat_style style)
  410. {
  411. bool default_str = style & PXF_DEFAULT_STR;
  412. style = get_xlat_style(style);
  413. switch (xlat_verbose(style)) {
  414. case XLAT_STYLE_ABBREV:
  415. if (str) {
  416. if (default_str) {
  417. print_xlat_val(val, style);
  418. tprints_comment(str);
  419. } else {
  420. tprints(str);
  421. }
  422. break;
  423. }
  424. ATTRIBUTE_FALLTHROUGH;
  425. case XLAT_STYLE_RAW:
  426. print_xlat_val(val, style);
  427. break;
  428. default:
  429. error_func_msg("Unexpected style value of %#x", style);
  430. ATTRIBUTE_FALLTHROUGH;
  431. case XLAT_STYLE_VERBOSE:
  432. print_xlat_val(val, style);
  433. tprints_comment(str);
  434. }
  435. }