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