cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

seq_buf.c (10217B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * seq_buf.c
      4 *
      5 * Copyright (C) 2014 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
      6 *
      7 * The seq_buf is a handy tool that allows you to pass a descriptor around
      8 * to a buffer that other functions can write to. It is similar to the
      9 * seq_file functionality but has some differences.
     10 *
     11 * To use it, the seq_buf must be initialized with seq_buf_init().
     12 * This will set up the counters within the descriptor. You can call
     13 * seq_buf_init() more than once to reset the seq_buf to start
     14 * from scratch.
     15 */
     16#include <linux/uaccess.h>
     17#include <linux/seq_file.h>
     18#include <linux/seq_buf.h>
     19
     20/**
     21 * seq_buf_can_fit - can the new data fit in the current buffer?
     22 * @s: the seq_buf descriptor
     23 * @len: The length to see if it can fit in the current buffer
     24 *
     25 * Returns true if there's enough unused space in the seq_buf buffer
     26 * to fit the amount of new data according to @len.
     27 */
     28static bool seq_buf_can_fit(struct seq_buf *s, size_t len)
     29{
     30	return s->len + len <= s->size;
     31}
     32
     33/**
     34 * seq_buf_print_seq - move the contents of seq_buf into a seq_file
     35 * @m: the seq_file descriptor that is the destination
     36 * @s: the seq_buf descriptor that is the source.
     37 *
     38 * Returns zero on success, non zero otherwise
     39 */
     40int seq_buf_print_seq(struct seq_file *m, struct seq_buf *s)
     41{
     42	unsigned int len = seq_buf_used(s);
     43
     44	return seq_write(m, s->buffer, len);
     45}
     46
     47/**
     48 * seq_buf_vprintf - sequence printing of information.
     49 * @s: seq_buf descriptor
     50 * @fmt: printf format string
     51 * @args: va_list of arguments from a printf() type function
     52 *
     53 * Writes a vnprintf() format into the sequencce buffer.
     54 *
     55 * Returns zero on success, -1 on overflow.
     56 */
     57int seq_buf_vprintf(struct seq_buf *s, const char *fmt, va_list args)
     58{
     59	int len;
     60
     61	WARN_ON(s->size == 0);
     62
     63	if (s->len < s->size) {
     64		len = vsnprintf(s->buffer + s->len, s->size - s->len, fmt, args);
     65		if (s->len + len < s->size) {
     66			s->len += len;
     67			return 0;
     68		}
     69	}
     70	seq_buf_set_overflow(s);
     71	return -1;
     72}
     73
     74/**
     75 * seq_buf_printf - sequence printing of information
     76 * @s: seq_buf descriptor
     77 * @fmt: printf format string
     78 *
     79 * Writes a printf() format into the sequence buffer.
     80 *
     81 * Returns zero on success, -1 on overflow.
     82 */
     83int seq_buf_printf(struct seq_buf *s, const char *fmt, ...)
     84{
     85	va_list ap;
     86	int ret;
     87
     88	va_start(ap, fmt);
     89	ret = seq_buf_vprintf(s, fmt, ap);
     90	va_end(ap);
     91
     92	return ret;
     93}
     94EXPORT_SYMBOL_GPL(seq_buf_printf);
     95
     96#ifdef CONFIG_BINARY_PRINTF
     97/**
     98 * seq_buf_bprintf - Write the printf string from binary arguments
     99 * @s: seq_buf descriptor
    100 * @fmt: The format string for the @binary arguments
    101 * @binary: The binary arguments for @fmt.
    102 *
    103 * When recording in a fast path, a printf may be recorded with just
    104 * saving the format and the arguments as they were passed to the
    105 * function, instead of wasting cycles converting the arguments into
    106 * ASCII characters. Instead, the arguments are saved in a 32 bit
    107 * word array that is defined by the format string constraints.
    108 *
    109 * This function will take the format and the binary array and finish
    110 * the conversion into the ASCII string within the buffer.
    111 *
    112 * Returns zero on success, -1 on overflow.
    113 */
    114int seq_buf_bprintf(struct seq_buf *s, const char *fmt, const u32 *binary)
    115{
    116	unsigned int len = seq_buf_buffer_left(s);
    117	int ret;
    118
    119	WARN_ON(s->size == 0);
    120
    121	if (s->len < s->size) {
    122		ret = bstr_printf(s->buffer + s->len, len, fmt, binary);
    123		if (s->len + ret < s->size) {
    124			s->len += ret;
    125			return 0;
    126		}
    127	}
    128	seq_buf_set_overflow(s);
    129	return -1;
    130}
    131#endif /* CONFIG_BINARY_PRINTF */
    132
    133/**
    134 * seq_buf_puts - sequence printing of simple string
    135 * @s: seq_buf descriptor
    136 * @str: simple string to record
    137 *
    138 * Copy a simple string into the sequence buffer.
    139 *
    140 * Returns zero on success, -1 on overflow
    141 */
    142int seq_buf_puts(struct seq_buf *s, const char *str)
    143{
    144	size_t len = strlen(str);
    145
    146	WARN_ON(s->size == 0);
    147
    148	/* Add 1 to len for the trailing null byte which must be there */
    149	len += 1;
    150
    151	if (seq_buf_can_fit(s, len)) {
    152		memcpy(s->buffer + s->len, str, len);
    153		/* Don't count the trailing null byte against the capacity */
    154		s->len += len - 1;
    155		return 0;
    156	}
    157	seq_buf_set_overflow(s);
    158	return -1;
    159}
    160
    161/**
    162 * seq_buf_putc - sequence printing of simple character
    163 * @s: seq_buf descriptor
    164 * @c: simple character to record
    165 *
    166 * Copy a single character into the sequence buffer.
    167 *
    168 * Returns zero on success, -1 on overflow
    169 */
    170int seq_buf_putc(struct seq_buf *s, unsigned char c)
    171{
    172	WARN_ON(s->size == 0);
    173
    174	if (seq_buf_can_fit(s, 1)) {
    175		s->buffer[s->len++] = c;
    176		return 0;
    177	}
    178	seq_buf_set_overflow(s);
    179	return -1;
    180}
    181
    182/**
    183 * seq_buf_putmem - write raw data into the sequenc buffer
    184 * @s: seq_buf descriptor
    185 * @mem: The raw memory to copy into the buffer
    186 * @len: The length of the raw memory to copy (in bytes)
    187 *
    188 * There may be cases where raw memory needs to be written into the
    189 * buffer and a strcpy() would not work. Using this function allows
    190 * for such cases.
    191 *
    192 * Returns zero on success, -1 on overflow
    193 */
    194int seq_buf_putmem(struct seq_buf *s, const void *mem, unsigned int len)
    195{
    196	WARN_ON(s->size == 0);
    197
    198	if (seq_buf_can_fit(s, len)) {
    199		memcpy(s->buffer + s->len, mem, len);
    200		s->len += len;
    201		return 0;
    202	}
    203	seq_buf_set_overflow(s);
    204	return -1;
    205}
    206
    207#define MAX_MEMHEX_BYTES	8U
    208#define HEX_CHARS		(MAX_MEMHEX_BYTES*2 + 1)
    209
    210/**
    211 * seq_buf_putmem_hex - write raw memory into the buffer in ASCII hex
    212 * @s: seq_buf descriptor
    213 * @mem: The raw memory to write its hex ASCII representation of
    214 * @len: The length of the raw memory to copy (in bytes)
    215 *
    216 * This is similar to seq_buf_putmem() except instead of just copying the
    217 * raw memory into the buffer it writes its ASCII representation of it
    218 * in hex characters.
    219 *
    220 * Returns zero on success, -1 on overflow
    221 */
    222int seq_buf_putmem_hex(struct seq_buf *s, const void *mem,
    223		       unsigned int len)
    224{
    225	unsigned char hex[HEX_CHARS];
    226	const unsigned char *data = mem;
    227	unsigned int start_len;
    228	int i, j;
    229
    230	WARN_ON(s->size == 0);
    231
    232	BUILD_BUG_ON(MAX_MEMHEX_BYTES * 2 >= HEX_CHARS);
    233
    234	while (len) {
    235		start_len = min(len, MAX_MEMHEX_BYTES);
    236#ifdef __BIG_ENDIAN
    237		for (i = 0, j = 0; i < start_len; i++) {
    238#else
    239		for (i = start_len-1, j = 0; i >= 0; i--) {
    240#endif
    241			hex[j++] = hex_asc_hi(data[i]);
    242			hex[j++] = hex_asc_lo(data[i]);
    243		}
    244		if (WARN_ON_ONCE(j == 0 || j/2 > len))
    245			break;
    246
    247		/* j increments twice per loop */
    248		hex[j++] = ' ';
    249
    250		seq_buf_putmem(s, hex, j);
    251		if (seq_buf_has_overflowed(s))
    252			return -1;
    253
    254		len -= start_len;
    255		data += start_len;
    256	}
    257	return 0;
    258}
    259
    260/**
    261 * seq_buf_path - copy a path into the sequence buffer
    262 * @s: seq_buf descriptor
    263 * @path: path to write into the sequence buffer.
    264 * @esc: set of characters to escape in the output
    265 *
    266 * Write a path name into the sequence buffer.
    267 *
    268 * Returns the number of written bytes on success, -1 on overflow
    269 */
    270int seq_buf_path(struct seq_buf *s, const struct path *path, const char *esc)
    271{
    272	char *buf;
    273	size_t size = seq_buf_get_buf(s, &buf);
    274	int res = -1;
    275
    276	WARN_ON(s->size == 0);
    277
    278	if (size) {
    279		char *p = d_path(path, buf, size);
    280		if (!IS_ERR(p)) {
    281			char *end = mangle_path(buf, p, esc);
    282			if (end)
    283				res = end - buf;
    284		}
    285	}
    286	seq_buf_commit(s, res);
    287
    288	return res;
    289}
    290
    291/**
    292 * seq_buf_to_user - copy the sequence buffer to user space
    293 * @s: seq_buf descriptor
    294 * @ubuf: The userspace memory location to copy to
    295 * @cnt: The amount to copy
    296 *
    297 * Copies the sequence buffer into the userspace memory pointed to
    298 * by @ubuf. It starts from the last read position (@s->readpos)
    299 * and writes up to @cnt characters or till it reaches the end of
    300 * the content in the buffer (@s->len), which ever comes first.
    301 *
    302 * On success, it returns a positive number of the number of bytes
    303 * it copied.
    304 *
    305 * On failure it returns -EBUSY if all of the content in the
    306 * sequence has been already read, which includes nothing in the
    307 * sequence (@s->len == @s->readpos).
    308 *
    309 * Returns -EFAULT if the copy to userspace fails.
    310 */
    311int seq_buf_to_user(struct seq_buf *s, char __user *ubuf, int cnt)
    312{
    313	int len;
    314	int ret;
    315
    316	if (!cnt)
    317		return 0;
    318
    319	len = seq_buf_used(s);
    320
    321	if (len <= s->readpos)
    322		return -EBUSY;
    323
    324	len -= s->readpos;
    325	if (cnt > len)
    326		cnt = len;
    327	ret = copy_to_user(ubuf, s->buffer + s->readpos, cnt);
    328	if (ret == cnt)
    329		return -EFAULT;
    330
    331	cnt -= ret;
    332
    333	s->readpos += cnt;
    334	return cnt;
    335}
    336
    337/**
    338 * seq_buf_hex_dump - print formatted hex dump into the sequence buffer
    339 * @s: seq_buf descriptor
    340 * @prefix_str: string to prefix each line with;
    341 *  caller supplies trailing spaces for alignment if desired
    342 * @prefix_type: controls whether prefix of an offset, address, or none
    343 *  is printed (%DUMP_PREFIX_OFFSET, %DUMP_PREFIX_ADDRESS, %DUMP_PREFIX_NONE)
    344 * @rowsize: number of bytes to print per line; must be 16 or 32
    345 * @groupsize: number of bytes to print at a time (1, 2, 4, 8; default = 1)
    346 * @buf: data blob to dump
    347 * @len: number of bytes in the @buf
    348 * @ascii: include ASCII after the hex output
    349 *
    350 * Function is an analogue of print_hex_dump() and thus has similar interface.
    351 *
    352 * linebuf size is maximal length for one line.
    353 * 32 * 3 - maximum bytes per line, each printed into 2 chars + 1 for
    354 *	separating space
    355 * 2 - spaces separating hex dump and ascii representation
    356 * 32 - ascii representation
    357 * 1 - terminating '\0'
    358 *
    359 * Returns zero on success, -1 on overflow
    360 */
    361int seq_buf_hex_dump(struct seq_buf *s, const char *prefix_str, int prefix_type,
    362		     int rowsize, int groupsize,
    363		     const void *buf, size_t len, bool ascii)
    364{
    365	const u8 *ptr = buf;
    366	int i, linelen, remaining = len;
    367	unsigned char linebuf[32 * 3 + 2 + 32 + 1];
    368	int ret;
    369
    370	if (rowsize != 16 && rowsize != 32)
    371		rowsize = 16;
    372
    373	for (i = 0; i < len; i += rowsize) {
    374		linelen = min(remaining, rowsize);
    375		remaining -= rowsize;
    376
    377		hex_dump_to_buffer(ptr + i, linelen, rowsize, groupsize,
    378				   linebuf, sizeof(linebuf), ascii);
    379
    380		switch (prefix_type) {
    381		case DUMP_PREFIX_ADDRESS:
    382			ret = seq_buf_printf(s, "%s%p: %s\n",
    383			       prefix_str, ptr + i, linebuf);
    384			break;
    385		case DUMP_PREFIX_OFFSET:
    386			ret = seq_buf_printf(s, "%s%.8x: %s\n",
    387					     prefix_str, i, linebuf);
    388			break;
    389		default:
    390			ret = seq_buf_printf(s, "%s%s\n", prefix_str, linebuf);
    391			break;
    392		}
    393		if (ret)
    394			return ret;
    395	}
    396	return 0;
    397}