LCOV - code coverage report
Current view: top level - lib - hexdump.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 11 110 10.0 %
Date: 2022-04-01 14:35:51 Functions: 2 5 40.0 %
Branches: 6 95 6.3 %

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

Generated by: LCOV version 1.14