LCOV - code coverage report
Current view: top level - lib - hexdump.c (source / functions) Hit Total Coverage
Test: landlock.info Lines: 0 113 0.0 %
Date: 2021-04-22 12:43:58 Functions: 0 5 0.0 %

          Line data    Source code
       1             : // SPDX-License-Identifier: GPL-2.0-only
       2             : /*
       3             :  * lib/hexdump.c
       4             :  */
       5             : 
       6             : #include <linux/types.h>
       7             : #include <linux/ctype.h>
       8             : #include <linux/errno.h>
       9             : #include <linux/kernel.h>
      10             : #include <linux/minmax.h>
      11             : #include <linux/export.h>
      12             : #include <asm/unaligned.h>
      13             : 
      14             : const char hex_asc[] = "0123456789abcdef";
      15             : EXPORT_SYMBOL(hex_asc);
      16             : const char hex_asc_upper[] = "0123456789ABCDEF";
      17             : EXPORT_SYMBOL(hex_asc_upper);
      18             : 
      19             : /**
      20             :  * hex_to_bin - convert a hex digit to its real value
      21             :  * @ch: ascii character represents hex digit
      22             :  *
      23             :  * hex_to_bin() converts one hex digit to its actual value or -1 in case of bad
      24             :  * input.
      25             :  */
      26           0 : int hex_to_bin(char ch)
      27             : {
      28           0 :         if ((ch >= '0') && (ch <= '9'))
      29           0 :                 return ch - '0';
      30           0 :         ch = tolower(ch);
      31           0 :         if ((ch >= 'a') && (ch <= 'f'))
      32           0 :                 return ch - 'a' + 10;
      33             :         return -1;
      34             : }
      35             : EXPORT_SYMBOL(hex_to_bin);
      36             : 
      37             : /**
      38             :  * hex2bin - convert an ascii hexadecimal string to its binary representation
      39             :  * @dst: binary result
      40             :  * @src: ascii hexadecimal string
      41             :  * @count: result length
      42             :  *
      43             :  * Return 0 on success, -EINVAL in case of bad input.
      44             :  */
      45           0 : int hex2bin(u8 *dst, const char *src, size_t count)
      46             : {
      47           0 :         while (count--) {
      48           0 :                 int hi = hex_to_bin(*src++);
      49           0 :                 int lo = hex_to_bin(*src++);
      50             : 
      51           0 :                 if ((hi < 0) || (lo < 0))
      52             :                         return -EINVAL;
      53             : 
      54           0 :                 *dst++ = (hi << 4) | lo;
      55             :         }
      56             :         return 0;
      57             : }
      58             : EXPORT_SYMBOL(hex2bin);
      59             : 
      60             : /**
      61             :  * bin2hex - convert binary data to an ascii hexadecimal string
      62             :  * @dst: ascii hexadecimal result
      63             :  * @src: binary data
      64             :  * @count: binary data length
      65             :  */
      66           0 : char *bin2hex(char *dst, const void *src, size_t count)
      67             : {
      68           0 :         const unsigned char *_src = src;
      69             : 
      70           0 :         while (count--)
      71           0 :                 dst = hex_byte_pack(dst, *_src++);
      72           0 :         return dst;
      73             : }
      74             : EXPORT_SYMBOL(bin2hex);
      75             : 
      76             : /**
      77             :  * hex_dump_to_buffer - convert a blob of data to "hex ASCII" in memory
      78             :  * @buf: data blob to dump
      79             :  * @len: number of bytes in the @buf
      80             :  * @rowsize: number of bytes to print per line; must be 16 or 32
      81             :  * @groupsize: number of bytes to print at a time (1, 2, 4, 8; default = 1)
      82             :  * @linebuf: where to put the converted data
      83             :  * @linebuflen: total size of @linebuf, including space for terminating NUL
      84             :  * @ascii: include ASCII after the hex output
      85             :  *
      86             :  * hex_dump_to_buffer() works on one "line" of output at a time, i.e.,
      87             :  * 16 or 32 bytes of input data converted to hex + ASCII output.
      88             :  *
      89             :  * Given a buffer of u8 data, hex_dump_to_buffer() converts the input data
      90             :  * to a hex + ASCII dump at the supplied memory location.
      91             :  * The converted output is always NUL-terminated.
      92             :  *
      93             :  * E.g.:
      94             :  *   hex_dump_to_buffer(frame->data, frame->len, 16, 1,
      95             :  *                      linebuf, sizeof(linebuf), true);
      96             :  *
      97             :  * example output buffer:
      98             :  * 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f  @ABCDEFGHIJKLMNO
      99             :  *
     100             :  * Return:
     101             :  * The amount of bytes placed in the buffer without terminating NUL. If the
     102             :  * output was truncated, then the return value is the number of bytes
     103             :  * (excluding the terminating NUL) which would have been written to the final
     104             :  * string if enough space had been available.
     105             :  */
     106           0 : int hex_dump_to_buffer(const void *buf, size_t len, int rowsize, int groupsize,
     107             :                        char *linebuf, size_t linebuflen, bool ascii)
     108             : {
     109           0 :         const u8 *ptr = buf;
     110           0 :         int ngroups;
     111           0 :         u8 ch;
     112           0 :         int j, lx = 0;
     113           0 :         int ascii_column;
     114           0 :         int ret;
     115             : 
     116           0 :         if (rowsize != 16 && rowsize != 32)
     117           0 :                 rowsize = 16;
     118             : 
     119           0 :         if (len > rowsize)           /* limit to one line at a time */
     120             :                 len = rowsize;
     121           0 :         if (!is_power_of_2(groupsize) || groupsize > 8)
     122           0 :                 groupsize = 1;
     123           0 :         if ((len % groupsize) != 0)     /* no mixed size output */
     124           0 :                 groupsize = 1;
     125             : 
     126           0 :         ngroups = len / groupsize;
     127           0 :         ascii_column = rowsize * 2 + rowsize / groupsize + 1;
     128             : 
     129           0 :         if (!linebuflen)
     130           0 :                 goto overflow1;
     131             : 
     132           0 :         if (!len)
     133           0 :                 goto nil;
     134             : 
     135           0 :         if (groupsize == 8) {
     136           0 :                 const u64 *ptr8 = buf;
     137             : 
     138           0 :                 for (j = 0; j < ngroups; j++) {
     139           0 :                         ret = snprintf(linebuf + lx, linebuflen - lx,
     140             :                                        "%s%16.16llx", j ? " " : "",
     141           0 :                                        get_unaligned(ptr8 + j));
     142           0 :                         if (ret >= linebuflen - lx)
     143           0 :                                 goto overflow1;
     144           0 :                         lx += ret;
     145             :                 }
     146           0 :         } else if (groupsize == 4) {
     147           0 :                 const u32 *ptr4 = buf;
     148             : 
     149           0 :                 for (j = 0; j < ngroups; j++) {
     150           0 :                         ret = snprintf(linebuf + lx, linebuflen - lx,
     151             :                                        "%s%8.8x", j ? " " : "",
     152           0 :                                        get_unaligned(ptr4 + j));
     153           0 :                         if (ret >= linebuflen - lx)
     154           0 :                                 goto overflow1;
     155           0 :                         lx += ret;
     156             :                 }
     157           0 :         } else if (groupsize == 2) {
     158           0 :                 const u16 *ptr2 = buf;
     159             : 
     160           0 :                 for (j = 0; j < ngroups; j++) {
     161           0 :                         ret = snprintf(linebuf + lx, linebuflen - lx,
     162             :                                        "%s%4.4x", j ? " " : "",
     163           0 :                                        get_unaligned(ptr2 + j));
     164           0 :                         if (ret >= linebuflen - lx)
     165           0 :                                 goto overflow1;
     166           0 :                         lx += ret;
     167             :                 }
     168             :         } else {
     169           0 :                 for (j = 0; j < len; j++) {
     170           0 :                         if (linebuflen < lx + 2)
     171           0 :                                 goto overflow2;
     172           0 :                         ch = ptr[j];
     173           0 :                         linebuf[lx++] = hex_asc_hi(ch);
     174           0 :                         if (linebuflen < lx + 2)
     175           0 :                                 goto overflow2;
     176           0 :                         linebuf[lx++] = hex_asc_lo(ch);
     177           0 :                         if (linebuflen < lx + 2)
     178           0 :                                 goto overflow2;
     179           0 :                         linebuf[lx++] = ' ';
     180             :                 }
     181           0 :                 if (j)
     182           0 :                         lx--;
     183             :         }
     184           0 :         if (!ascii)
     185           0 :                 goto nil;
     186             : 
     187           0 :         while (lx < ascii_column) {
     188           0 :                 if (linebuflen < lx + 2)
     189           0 :                         goto overflow2;
     190           0 :                 linebuf[lx++] = ' ';
     191             :         }
     192           0 :         for (j = 0; j < len; j++) {
     193           0 :                 if (linebuflen < lx + 2)
     194           0 :                         goto overflow2;
     195           0 :                 ch = ptr[j];
     196           0 :                 linebuf[lx++] = (isascii(ch) && isprint(ch)) ? ch : '.';
     197             :         }
     198           0 : nil:
     199           0 :         linebuf[lx] = '\0';
     200           0 :         return lx;
     201           0 : overflow2:
     202           0 :         linebuf[lx++] = '\0';
     203           0 : overflow1:
     204           0 :         return ascii ? ascii_column + len : (groupsize * 2 + 1) * ngroups - 1;
     205             : }
     206             : EXPORT_SYMBOL(hex_dump_to_buffer);
     207             : 
     208             : #ifdef CONFIG_PRINTK
     209             : /**
     210             :  * print_hex_dump - print a text hex dump to syslog for a binary blob of data
     211             :  * @level: kernel log level (e.g. KERN_DEBUG)
     212             :  * @prefix_str: string to prefix each line with;
     213             :  *  caller supplies trailing spaces for alignment if desired
     214             :  * @prefix_type: controls whether prefix of an offset, address, or none
     215             :  *  is printed (%DUMP_PREFIX_OFFSET, %DUMP_PREFIX_ADDRESS, %DUMP_PREFIX_NONE)
     216             :  * @rowsize: number of bytes to print per line; must be 16 or 32
     217             :  * @groupsize: number of bytes to print at a time (1, 2, 4, 8; default = 1)
     218             :  * @buf: data blob to dump
     219             :  * @len: number of bytes in the @buf
     220             :  * @ascii: include ASCII after the hex output
     221             :  *
     222             :  * Given a buffer of u8 data, print_hex_dump() prints a hex + ASCII dump
     223             :  * to the kernel log at the specified kernel log level, with an optional
     224             :  * leading prefix.
     225             :  *
     226             :  * print_hex_dump() works on one "line" of output at a time, i.e.,
     227             :  * 16 or 32 bytes of input data converted to hex + ASCII output.
     228             :  * print_hex_dump() iterates over the entire input @buf, breaking it into
     229             :  * "line size" chunks to format and print.
     230             :  *
     231             :  * E.g.:
     232             :  *   print_hex_dump(KERN_DEBUG, "raw data: ", DUMP_PREFIX_ADDRESS,
     233             :  *                  16, 1, frame->data, frame->len, true);
     234             :  *
     235             :  * Example output using %DUMP_PREFIX_OFFSET and 1-byte mode:
     236             :  * 0009ab42: 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f  @ABCDEFGHIJKLMNO
     237             :  * Example output using %DUMP_PREFIX_ADDRESS and 4-byte mode:
     238             :  * ffffffff88089af0: 73727170 77767574 7b7a7978 7f7e7d7c  pqrstuvwxyz{|}~.
     239             :  */
     240           0 : void print_hex_dump(const char *level, const char *prefix_str, int prefix_type,
     241             :                     int rowsize, int groupsize,
     242             :                     const void *buf, size_t len, bool ascii)
     243             : {
     244           0 :         const u8 *ptr = buf;
     245           0 :         int i, linelen, remaining = len;
     246           0 :         unsigned char linebuf[32 * 3 + 2 + 32 + 1];
     247             : 
     248           0 :         if (rowsize != 16 && rowsize != 32)
     249           0 :                 rowsize = 16;
     250             : 
     251           0 :         for (i = 0; i < len; i += rowsize) {
     252           0 :                 linelen = min(remaining, rowsize);
     253           0 :                 remaining -= rowsize;
     254             : 
     255           0 :                 hex_dump_to_buffer(ptr + i, linelen, rowsize, groupsize,
     256             :                                    linebuf, sizeof(linebuf), ascii);
     257             : 
     258           0 :                 switch (prefix_type) {
     259           0 :                 case DUMP_PREFIX_ADDRESS:
     260           0 :                         printk("%s%s%p: %s\n",
     261             :                                level, prefix_str, ptr + i, linebuf);
     262           0 :                         break;
     263           0 :                 case DUMP_PREFIX_OFFSET:
     264           0 :                         printk("%s%s%.8x: %s\n", level, prefix_str, i, linebuf);
     265           0 :                         break;
     266           0 :                 default:
     267           0 :                         printk("%s%s%s\n", level, prefix_str, linebuf);
     268           0 :                         break;
     269             :                 }
     270             :         }
     271           0 : }
     272             : EXPORT_SYMBOL(print_hex_dump);
     273             : 
     274             : #endif /* defined(CONFIG_PRINTK) */

Generated by: LCOV version 1.14