18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * seq_buf.c 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2014 Red Hat Inc, Steven Rostedt <srostedt@redhat.com> 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * The seq_buf is a handy tool that allows you to pass a descriptor around 88c2ecf20Sopenharmony_ci * to a buffer that other functions can write to. It is similar to the 98c2ecf20Sopenharmony_ci * seq_file functionality but has some differences. 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * To use it, the seq_buf must be initialized with seq_buf_init(). 128c2ecf20Sopenharmony_ci * This will set up the counters within the descriptor. You can call 138c2ecf20Sopenharmony_ci * seq_buf_init() more than once to reset the seq_buf to start 148c2ecf20Sopenharmony_ci * from scratch. 158c2ecf20Sopenharmony_ci */ 168c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 178c2ecf20Sopenharmony_ci#include <linux/seq_file.h> 188c2ecf20Sopenharmony_ci#include <linux/seq_buf.h> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci/** 218c2ecf20Sopenharmony_ci * seq_buf_can_fit - can the new data fit in the current buffer? 228c2ecf20Sopenharmony_ci * @s: the seq_buf descriptor 238c2ecf20Sopenharmony_ci * @len: The length to see if it can fit in the current buffer 248c2ecf20Sopenharmony_ci * 258c2ecf20Sopenharmony_ci * Returns true if there's enough unused space in the seq_buf buffer 268c2ecf20Sopenharmony_ci * to fit the amount of new data according to @len. 278c2ecf20Sopenharmony_ci */ 288c2ecf20Sopenharmony_cistatic bool seq_buf_can_fit(struct seq_buf *s, size_t len) 298c2ecf20Sopenharmony_ci{ 308c2ecf20Sopenharmony_ci return s->len + len <= s->size; 318c2ecf20Sopenharmony_ci} 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci/** 348c2ecf20Sopenharmony_ci * seq_buf_print_seq - move the contents of seq_buf into a seq_file 358c2ecf20Sopenharmony_ci * @m: the seq_file descriptor that is the destination 368c2ecf20Sopenharmony_ci * @s: the seq_buf descriptor that is the source. 378c2ecf20Sopenharmony_ci * 388c2ecf20Sopenharmony_ci * Returns zero on success, non zero otherwise 398c2ecf20Sopenharmony_ci */ 408c2ecf20Sopenharmony_ciint seq_buf_print_seq(struct seq_file *m, struct seq_buf *s) 418c2ecf20Sopenharmony_ci{ 428c2ecf20Sopenharmony_ci unsigned int len = seq_buf_used(s); 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci return seq_write(m, s->buffer, len); 458c2ecf20Sopenharmony_ci} 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci/** 488c2ecf20Sopenharmony_ci * seq_buf_vprintf - sequence printing of information. 498c2ecf20Sopenharmony_ci * @s: seq_buf descriptor 508c2ecf20Sopenharmony_ci * @fmt: printf format string 518c2ecf20Sopenharmony_ci * @args: va_list of arguments from a printf() type function 528c2ecf20Sopenharmony_ci * 538c2ecf20Sopenharmony_ci * Writes a vnprintf() format into the sequencce buffer. 548c2ecf20Sopenharmony_ci * 558c2ecf20Sopenharmony_ci * Returns zero on success, -1 on overflow. 568c2ecf20Sopenharmony_ci */ 578c2ecf20Sopenharmony_ciint seq_buf_vprintf(struct seq_buf *s, const char *fmt, va_list args) 588c2ecf20Sopenharmony_ci{ 598c2ecf20Sopenharmony_ci int len; 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci WARN_ON(s->size == 0); 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci if (s->len < s->size) { 648c2ecf20Sopenharmony_ci len = vsnprintf(s->buffer + s->len, s->size - s->len, fmt, args); 658c2ecf20Sopenharmony_ci if (s->len + len < s->size) { 668c2ecf20Sopenharmony_ci s->len += len; 678c2ecf20Sopenharmony_ci return 0; 688c2ecf20Sopenharmony_ci } 698c2ecf20Sopenharmony_ci } 708c2ecf20Sopenharmony_ci seq_buf_set_overflow(s); 718c2ecf20Sopenharmony_ci return -1; 728c2ecf20Sopenharmony_ci} 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci/** 758c2ecf20Sopenharmony_ci * seq_buf_printf - sequence printing of information 768c2ecf20Sopenharmony_ci * @s: seq_buf descriptor 778c2ecf20Sopenharmony_ci * @fmt: printf format string 788c2ecf20Sopenharmony_ci * 798c2ecf20Sopenharmony_ci * Writes a printf() format into the sequence buffer. 808c2ecf20Sopenharmony_ci * 818c2ecf20Sopenharmony_ci * Returns zero on success, -1 on overflow. 828c2ecf20Sopenharmony_ci */ 838c2ecf20Sopenharmony_ciint seq_buf_printf(struct seq_buf *s, const char *fmt, ...) 848c2ecf20Sopenharmony_ci{ 858c2ecf20Sopenharmony_ci va_list ap; 868c2ecf20Sopenharmony_ci int ret; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci va_start(ap, fmt); 898c2ecf20Sopenharmony_ci ret = seq_buf_vprintf(s, fmt, ap); 908c2ecf20Sopenharmony_ci va_end(ap); 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci return ret; 938c2ecf20Sopenharmony_ci} 948c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(seq_buf_printf); 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci#ifdef CONFIG_BINARY_PRINTF 978c2ecf20Sopenharmony_ci/** 988c2ecf20Sopenharmony_ci * seq_buf_bprintf - Write the printf string from binary arguments 998c2ecf20Sopenharmony_ci * @s: seq_buf descriptor 1008c2ecf20Sopenharmony_ci * @fmt: The format string for the @binary arguments 1018c2ecf20Sopenharmony_ci * @binary: The binary arguments for @fmt. 1028c2ecf20Sopenharmony_ci * 1038c2ecf20Sopenharmony_ci * When recording in a fast path, a printf may be recorded with just 1048c2ecf20Sopenharmony_ci * saving the format and the arguments as they were passed to the 1058c2ecf20Sopenharmony_ci * function, instead of wasting cycles converting the arguments into 1068c2ecf20Sopenharmony_ci * ASCII characters. Instead, the arguments are saved in a 32 bit 1078c2ecf20Sopenharmony_ci * word array that is defined by the format string constraints. 1088c2ecf20Sopenharmony_ci * 1098c2ecf20Sopenharmony_ci * This function will take the format and the binary array and finish 1108c2ecf20Sopenharmony_ci * the conversion into the ASCII string within the buffer. 1118c2ecf20Sopenharmony_ci * 1128c2ecf20Sopenharmony_ci * Returns zero on success, -1 on overflow. 1138c2ecf20Sopenharmony_ci */ 1148c2ecf20Sopenharmony_ciint seq_buf_bprintf(struct seq_buf *s, const char *fmt, const u32 *binary) 1158c2ecf20Sopenharmony_ci{ 1168c2ecf20Sopenharmony_ci unsigned int len = seq_buf_buffer_left(s); 1178c2ecf20Sopenharmony_ci int ret; 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci WARN_ON(s->size == 0); 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci if (s->len < s->size) { 1228c2ecf20Sopenharmony_ci ret = bstr_printf(s->buffer + s->len, len, fmt, binary); 1238c2ecf20Sopenharmony_ci if (s->len + ret < s->size) { 1248c2ecf20Sopenharmony_ci s->len += ret; 1258c2ecf20Sopenharmony_ci return 0; 1268c2ecf20Sopenharmony_ci } 1278c2ecf20Sopenharmony_ci } 1288c2ecf20Sopenharmony_ci seq_buf_set_overflow(s); 1298c2ecf20Sopenharmony_ci return -1; 1308c2ecf20Sopenharmony_ci} 1318c2ecf20Sopenharmony_ci#endif /* CONFIG_BINARY_PRINTF */ 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci/** 1348c2ecf20Sopenharmony_ci * seq_buf_puts - sequence printing of simple string 1358c2ecf20Sopenharmony_ci * @s: seq_buf descriptor 1368c2ecf20Sopenharmony_ci * @str: simple string to record 1378c2ecf20Sopenharmony_ci * 1388c2ecf20Sopenharmony_ci * Copy a simple string into the sequence buffer. 1398c2ecf20Sopenharmony_ci * 1408c2ecf20Sopenharmony_ci * Returns zero on success, -1 on overflow 1418c2ecf20Sopenharmony_ci */ 1428c2ecf20Sopenharmony_ciint seq_buf_puts(struct seq_buf *s, const char *str) 1438c2ecf20Sopenharmony_ci{ 1448c2ecf20Sopenharmony_ci size_t len = strlen(str); 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci WARN_ON(s->size == 0); 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci /* Add 1 to len for the trailing null byte which must be there */ 1498c2ecf20Sopenharmony_ci len += 1; 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci if (seq_buf_can_fit(s, len)) { 1528c2ecf20Sopenharmony_ci memcpy(s->buffer + s->len, str, len); 1538c2ecf20Sopenharmony_ci /* Don't count the trailing null byte against the capacity */ 1548c2ecf20Sopenharmony_ci s->len += len - 1; 1558c2ecf20Sopenharmony_ci return 0; 1568c2ecf20Sopenharmony_ci } 1578c2ecf20Sopenharmony_ci seq_buf_set_overflow(s); 1588c2ecf20Sopenharmony_ci return -1; 1598c2ecf20Sopenharmony_ci} 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci/** 1628c2ecf20Sopenharmony_ci * seq_buf_putc - sequence printing of simple character 1638c2ecf20Sopenharmony_ci * @s: seq_buf descriptor 1648c2ecf20Sopenharmony_ci * @c: simple character to record 1658c2ecf20Sopenharmony_ci * 1668c2ecf20Sopenharmony_ci * Copy a single character into the sequence buffer. 1678c2ecf20Sopenharmony_ci * 1688c2ecf20Sopenharmony_ci * Returns zero on success, -1 on overflow 1698c2ecf20Sopenharmony_ci */ 1708c2ecf20Sopenharmony_ciint seq_buf_putc(struct seq_buf *s, unsigned char c) 1718c2ecf20Sopenharmony_ci{ 1728c2ecf20Sopenharmony_ci WARN_ON(s->size == 0); 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci if (seq_buf_can_fit(s, 1)) { 1758c2ecf20Sopenharmony_ci s->buffer[s->len++] = c; 1768c2ecf20Sopenharmony_ci return 0; 1778c2ecf20Sopenharmony_ci } 1788c2ecf20Sopenharmony_ci seq_buf_set_overflow(s); 1798c2ecf20Sopenharmony_ci return -1; 1808c2ecf20Sopenharmony_ci} 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci/** 1838c2ecf20Sopenharmony_ci * seq_buf_putmem - write raw data into the sequenc buffer 1848c2ecf20Sopenharmony_ci * @s: seq_buf descriptor 1858c2ecf20Sopenharmony_ci * @mem: The raw memory to copy into the buffer 1868c2ecf20Sopenharmony_ci * @len: The length of the raw memory to copy (in bytes) 1878c2ecf20Sopenharmony_ci * 1888c2ecf20Sopenharmony_ci * There may be cases where raw memory needs to be written into the 1898c2ecf20Sopenharmony_ci * buffer and a strcpy() would not work. Using this function allows 1908c2ecf20Sopenharmony_ci * for such cases. 1918c2ecf20Sopenharmony_ci * 1928c2ecf20Sopenharmony_ci * Returns zero on success, -1 on overflow 1938c2ecf20Sopenharmony_ci */ 1948c2ecf20Sopenharmony_ciint seq_buf_putmem(struct seq_buf *s, const void *mem, unsigned int len) 1958c2ecf20Sopenharmony_ci{ 1968c2ecf20Sopenharmony_ci WARN_ON(s->size == 0); 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci if (seq_buf_can_fit(s, len)) { 1998c2ecf20Sopenharmony_ci memcpy(s->buffer + s->len, mem, len); 2008c2ecf20Sopenharmony_ci s->len += len; 2018c2ecf20Sopenharmony_ci return 0; 2028c2ecf20Sopenharmony_ci } 2038c2ecf20Sopenharmony_ci seq_buf_set_overflow(s); 2048c2ecf20Sopenharmony_ci return -1; 2058c2ecf20Sopenharmony_ci} 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci#define MAX_MEMHEX_BYTES 8U 2088c2ecf20Sopenharmony_ci#define HEX_CHARS (MAX_MEMHEX_BYTES*2 + 1) 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci/** 2118c2ecf20Sopenharmony_ci * seq_buf_putmem_hex - write raw memory into the buffer in ASCII hex 2128c2ecf20Sopenharmony_ci * @s: seq_buf descriptor 2138c2ecf20Sopenharmony_ci * @mem: The raw memory to write its hex ASCII representation of 2148c2ecf20Sopenharmony_ci * @len: The length of the raw memory to copy (in bytes) 2158c2ecf20Sopenharmony_ci * 2168c2ecf20Sopenharmony_ci * This is similar to seq_buf_putmem() except instead of just copying the 2178c2ecf20Sopenharmony_ci * raw memory into the buffer it writes its ASCII representation of it 2188c2ecf20Sopenharmony_ci * in hex characters. 2198c2ecf20Sopenharmony_ci * 2208c2ecf20Sopenharmony_ci * Returns zero on success, -1 on overflow 2218c2ecf20Sopenharmony_ci */ 2228c2ecf20Sopenharmony_ciint seq_buf_putmem_hex(struct seq_buf *s, const void *mem, 2238c2ecf20Sopenharmony_ci unsigned int len) 2248c2ecf20Sopenharmony_ci{ 2258c2ecf20Sopenharmony_ci unsigned char hex[HEX_CHARS]; 2268c2ecf20Sopenharmony_ci const unsigned char *data = mem; 2278c2ecf20Sopenharmony_ci unsigned int start_len; 2288c2ecf20Sopenharmony_ci int i, j; 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci WARN_ON(s->size == 0); 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci BUILD_BUG_ON(MAX_MEMHEX_BYTES * 2 >= HEX_CHARS); 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci while (len) { 2358c2ecf20Sopenharmony_ci start_len = min(len, MAX_MEMHEX_BYTES); 2368c2ecf20Sopenharmony_ci#ifdef __BIG_ENDIAN 2378c2ecf20Sopenharmony_ci for (i = 0, j = 0; i < start_len; i++) { 2388c2ecf20Sopenharmony_ci#else 2398c2ecf20Sopenharmony_ci for (i = start_len-1, j = 0; i >= 0; i--) { 2408c2ecf20Sopenharmony_ci#endif 2418c2ecf20Sopenharmony_ci hex[j++] = hex_asc_hi(data[i]); 2428c2ecf20Sopenharmony_ci hex[j++] = hex_asc_lo(data[i]); 2438c2ecf20Sopenharmony_ci } 2448c2ecf20Sopenharmony_ci if (WARN_ON_ONCE(j == 0 || j/2 > len)) 2458c2ecf20Sopenharmony_ci break; 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci /* j increments twice per loop */ 2488c2ecf20Sopenharmony_ci hex[j++] = ' '; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci seq_buf_putmem(s, hex, j); 2518c2ecf20Sopenharmony_ci if (seq_buf_has_overflowed(s)) 2528c2ecf20Sopenharmony_ci return -1; 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci len -= start_len; 2558c2ecf20Sopenharmony_ci data += start_len; 2568c2ecf20Sopenharmony_ci } 2578c2ecf20Sopenharmony_ci return 0; 2588c2ecf20Sopenharmony_ci} 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci/** 2618c2ecf20Sopenharmony_ci * seq_buf_path - copy a path into the sequence buffer 2628c2ecf20Sopenharmony_ci * @s: seq_buf descriptor 2638c2ecf20Sopenharmony_ci * @path: path to write into the sequence buffer. 2648c2ecf20Sopenharmony_ci * @esc: set of characters to escape in the output 2658c2ecf20Sopenharmony_ci * 2668c2ecf20Sopenharmony_ci * Write a path name into the sequence buffer. 2678c2ecf20Sopenharmony_ci * 2688c2ecf20Sopenharmony_ci * Returns the number of written bytes on success, -1 on overflow 2698c2ecf20Sopenharmony_ci */ 2708c2ecf20Sopenharmony_ciint seq_buf_path(struct seq_buf *s, const struct path *path, const char *esc) 2718c2ecf20Sopenharmony_ci{ 2728c2ecf20Sopenharmony_ci char *buf; 2738c2ecf20Sopenharmony_ci size_t size = seq_buf_get_buf(s, &buf); 2748c2ecf20Sopenharmony_ci int res = -1; 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci WARN_ON(s->size == 0); 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci if (size) { 2798c2ecf20Sopenharmony_ci char *p = d_path(path, buf, size); 2808c2ecf20Sopenharmony_ci if (!IS_ERR(p)) { 2818c2ecf20Sopenharmony_ci char *end = mangle_path(buf, p, esc); 2828c2ecf20Sopenharmony_ci if (end) 2838c2ecf20Sopenharmony_ci res = end - buf; 2848c2ecf20Sopenharmony_ci } 2858c2ecf20Sopenharmony_ci } 2868c2ecf20Sopenharmony_ci seq_buf_commit(s, res); 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci return res; 2898c2ecf20Sopenharmony_ci} 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci/** 2928c2ecf20Sopenharmony_ci * seq_buf_to_user - copy the squence buffer to user space 2938c2ecf20Sopenharmony_ci * @s: seq_buf descriptor 2948c2ecf20Sopenharmony_ci * @ubuf: The userspace memory location to copy to 2958c2ecf20Sopenharmony_ci * @cnt: The amount to copy 2968c2ecf20Sopenharmony_ci * 2978c2ecf20Sopenharmony_ci * Copies the sequence buffer into the userspace memory pointed to 2988c2ecf20Sopenharmony_ci * by @ubuf. It starts from the last read position (@s->readpos) 2998c2ecf20Sopenharmony_ci * and writes up to @cnt characters or till it reaches the end of 3008c2ecf20Sopenharmony_ci * the content in the buffer (@s->len), which ever comes first. 3018c2ecf20Sopenharmony_ci * 3028c2ecf20Sopenharmony_ci * On success, it returns a positive number of the number of bytes 3038c2ecf20Sopenharmony_ci * it copied. 3048c2ecf20Sopenharmony_ci * 3058c2ecf20Sopenharmony_ci * On failure it returns -EBUSY if all of the content in the 3068c2ecf20Sopenharmony_ci * sequence has been already read, which includes nothing in the 3078c2ecf20Sopenharmony_ci * sequence (@s->len == @s->readpos). 3088c2ecf20Sopenharmony_ci * 3098c2ecf20Sopenharmony_ci * Returns -EFAULT if the copy to userspace fails. 3108c2ecf20Sopenharmony_ci */ 3118c2ecf20Sopenharmony_ciint seq_buf_to_user(struct seq_buf *s, char __user *ubuf, int cnt) 3128c2ecf20Sopenharmony_ci{ 3138c2ecf20Sopenharmony_ci int len; 3148c2ecf20Sopenharmony_ci int ret; 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci if (!cnt) 3178c2ecf20Sopenharmony_ci return 0; 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci len = seq_buf_used(s); 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci if (len <= s->readpos) 3228c2ecf20Sopenharmony_ci return -EBUSY; 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci len -= s->readpos; 3258c2ecf20Sopenharmony_ci if (cnt > len) 3268c2ecf20Sopenharmony_ci cnt = len; 3278c2ecf20Sopenharmony_ci ret = copy_to_user(ubuf, s->buffer + s->readpos, cnt); 3288c2ecf20Sopenharmony_ci if (ret == cnt) 3298c2ecf20Sopenharmony_ci return -EFAULT; 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci cnt -= ret; 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci s->readpos += cnt; 3348c2ecf20Sopenharmony_ci return cnt; 3358c2ecf20Sopenharmony_ci} 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci/** 3388c2ecf20Sopenharmony_ci * seq_buf_hex_dump - print formatted hex dump into the sequence buffer 3398c2ecf20Sopenharmony_ci * @s: seq_buf descriptor 3408c2ecf20Sopenharmony_ci * @prefix_str: string to prefix each line with; 3418c2ecf20Sopenharmony_ci * caller supplies trailing spaces for alignment if desired 3428c2ecf20Sopenharmony_ci * @prefix_type: controls whether prefix of an offset, address, or none 3438c2ecf20Sopenharmony_ci * is printed (%DUMP_PREFIX_OFFSET, %DUMP_PREFIX_ADDRESS, %DUMP_PREFIX_NONE) 3448c2ecf20Sopenharmony_ci * @rowsize: number of bytes to print per line; must be 16 or 32 3458c2ecf20Sopenharmony_ci * @groupsize: number of bytes to print at a time (1, 2, 4, 8; default = 1) 3468c2ecf20Sopenharmony_ci * @buf: data blob to dump 3478c2ecf20Sopenharmony_ci * @len: number of bytes in the @buf 3488c2ecf20Sopenharmony_ci * @ascii: include ASCII after the hex output 3498c2ecf20Sopenharmony_ci * 3508c2ecf20Sopenharmony_ci * Function is an analogue of print_hex_dump() and thus has similar interface. 3518c2ecf20Sopenharmony_ci * 3528c2ecf20Sopenharmony_ci * linebuf size is maximal length for one line. 3538c2ecf20Sopenharmony_ci * 32 * 3 - maximum bytes per line, each printed into 2 chars + 1 for 3548c2ecf20Sopenharmony_ci * separating space 3558c2ecf20Sopenharmony_ci * 2 - spaces separating hex dump and ascii representation 3568c2ecf20Sopenharmony_ci * 32 - ascii representation 3578c2ecf20Sopenharmony_ci * 1 - terminating '\0' 3588c2ecf20Sopenharmony_ci * 3598c2ecf20Sopenharmony_ci * Returns zero on success, -1 on overflow 3608c2ecf20Sopenharmony_ci */ 3618c2ecf20Sopenharmony_ciint seq_buf_hex_dump(struct seq_buf *s, const char *prefix_str, int prefix_type, 3628c2ecf20Sopenharmony_ci int rowsize, int groupsize, 3638c2ecf20Sopenharmony_ci const void *buf, size_t len, bool ascii) 3648c2ecf20Sopenharmony_ci{ 3658c2ecf20Sopenharmony_ci const u8 *ptr = buf; 3668c2ecf20Sopenharmony_ci int i, linelen, remaining = len; 3678c2ecf20Sopenharmony_ci unsigned char linebuf[32 * 3 + 2 + 32 + 1]; 3688c2ecf20Sopenharmony_ci int ret; 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci if (rowsize != 16 && rowsize != 32) 3718c2ecf20Sopenharmony_ci rowsize = 16; 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci for (i = 0; i < len; i += rowsize) { 3748c2ecf20Sopenharmony_ci linelen = min(remaining, rowsize); 3758c2ecf20Sopenharmony_ci remaining -= rowsize; 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci hex_dump_to_buffer(ptr + i, linelen, rowsize, groupsize, 3788c2ecf20Sopenharmony_ci linebuf, sizeof(linebuf), ascii); 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci switch (prefix_type) { 3818c2ecf20Sopenharmony_ci case DUMP_PREFIX_ADDRESS: 3828c2ecf20Sopenharmony_ci ret = seq_buf_printf(s, "%s%p: %s\n", 3838c2ecf20Sopenharmony_ci prefix_str, ptr + i, linebuf); 3848c2ecf20Sopenharmony_ci break; 3858c2ecf20Sopenharmony_ci case DUMP_PREFIX_OFFSET: 3868c2ecf20Sopenharmony_ci ret = seq_buf_printf(s, "%s%.8x: %s\n", 3878c2ecf20Sopenharmony_ci prefix_str, i, linebuf); 3888c2ecf20Sopenharmony_ci break; 3898c2ecf20Sopenharmony_ci default: 3908c2ecf20Sopenharmony_ci ret = seq_buf_printf(s, "%s%s\n", prefix_str, linebuf); 3918c2ecf20Sopenharmony_ci break; 3928c2ecf20Sopenharmony_ci } 3938c2ecf20Sopenharmony_ci if (ret) 3948c2ecf20Sopenharmony_ci return ret; 3958c2ecf20Sopenharmony_ci } 3968c2ecf20Sopenharmony_ci return 0; 3978c2ecf20Sopenharmony_ci} 398