uboot/lib/hexdump.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * lib/hexdump.c
   4 *
   5 * This program is free software; you can redistribute it and/or modify
   6 * it under the terms of the GNU General Public License version 2 as
   7 * published by the Free Software Foundation. See README and COPYING for
   8 * more details.
   9 */
  10
  11#include <common.h>
  12#include <hexdump.h>
  13#include <mapmem.h>
  14#include <linux/ctype.h>
  15#include <linux/compat.h>
  16#include <linux/log2.h>
  17#include <asm/unaligned.h>
  18
  19#define MAX_LINE_LENGTH_BYTES   64
  20
  21const char hex_asc[] = "0123456789abcdef";
  22const char hex_asc_upper[] = "0123456789ABCDEF";
  23
  24#if CONFIG_IS_ENABLED(HEXDUMP)
  25int hex_dump_to_buffer(const void *buf, size_t len, int rowsize, int groupsize,
  26                       char *linebuf, size_t linebuflen, bool ascii)
  27{
  28        const u8 *ptr = buf;
  29        int ngroups;
  30        u8 ch;
  31        int j, lx = 0;
  32        int ascii_column;
  33        int ret;
  34
  35        if (!rowsize)
  36                rowsize = 16;
  37        else
  38                rowsize = min(rowsize, MAX_LINE_LENGTH_BYTES);
  39
  40        if (len > rowsize)              /* limit to one line at a time */
  41                len = rowsize;
  42        if (!is_power_of_2(groupsize) || groupsize > 8)
  43                groupsize = 1;
  44        if ((len % groupsize) != 0)     /* no mixed size output */
  45                groupsize = 1;
  46
  47        ngroups = len / groupsize;
  48        ascii_column = rowsize * 2 + rowsize / groupsize + 1;
  49
  50        if (!linebuflen)
  51                goto overflow1;
  52
  53        if (!len)
  54                goto nil;
  55
  56        if (groupsize == 8) {
  57                const u64 *ptr8 = buf;
  58
  59                for (j = 0; j < ngroups; j++) {
  60                        ret = snprintf(linebuf + lx, linebuflen - lx,
  61                                       "%s%16.16llx", j ? " " : "",
  62                                       get_unaligned(ptr8 + j));
  63                        if (ret >= linebuflen - lx)
  64                                goto overflow1;
  65                        lx += ret;
  66                }
  67        } else if (groupsize == 4) {
  68                const u32 *ptr4 = buf;
  69
  70                for (j = 0; j < ngroups; j++) {
  71                        ret = snprintf(linebuf + lx, linebuflen - lx,
  72                                       "%s%8.8x", j ? " " : "",
  73                                       get_unaligned(ptr4 + j));
  74                        if (ret >= linebuflen - lx)
  75                                goto overflow1;
  76                        lx += ret;
  77                }
  78        } else if (groupsize == 2) {
  79                const u16 *ptr2 = buf;
  80
  81                for (j = 0; j < ngroups; j++) {
  82                        ret = snprintf(linebuf + lx, linebuflen - lx,
  83                                       "%s%4.4x", j ? " " : "",
  84                                       get_unaligned(ptr2 + j));
  85                        if (ret >= linebuflen - lx)
  86                                goto overflow1;
  87                        lx += ret;
  88                }
  89        } else {
  90                for (j = 0; j < len; j++) {
  91                        if (linebuflen < lx + 2)
  92                                goto overflow2;
  93                        ch = ptr[j];
  94                        linebuf[lx++] = hex_asc_hi(ch);
  95                        if (linebuflen < lx + 2)
  96                                goto overflow2;
  97                        linebuf[lx++] = hex_asc_lo(ch);
  98                        if (linebuflen < lx + 2)
  99                                goto overflow2;
 100                        linebuf[lx++] = ' ';
 101                }
 102                if (j)
 103                        lx--;
 104        }
 105        if (!ascii)
 106                goto nil;
 107
 108        while (lx < ascii_column) {
 109                if (linebuflen < lx + 2)
 110                        goto overflow2;
 111                linebuf[lx++] = ' ';
 112        }
 113        for (j = 0; j < len; j++) {
 114                if (linebuflen < lx + 2)
 115                        goto overflow2;
 116                ch = ptr[j];
 117                linebuf[lx++] = (isascii(ch) && isprint(ch)) ? ch : '.';
 118        }
 119nil:
 120        linebuf[lx] = '\0';
 121        return lx;
 122overflow2:
 123        linebuf[lx++] = '\0';
 124overflow1:
 125        return ascii ? ascii_column + len : (groupsize * 2 + 1) * ngroups - 1;
 126}
 127
 128int print_hex_dump(const char *prefix_str, int prefix_type, int rowsize,
 129                   int groupsize, const void *buf, size_t len, bool ascii)
 130{
 131        const u8 *ptr = buf;
 132        int i, linelen, remaining = len;
 133        char linebuf[MAX_LINE_LENGTH_BYTES * 3 + 2 + MAX_LINE_LENGTH_BYTES + 1];
 134
 135        if (!rowsize)
 136                rowsize = 16;
 137        else
 138                rowsize = min(rowsize, MAX_LINE_LENGTH_BYTES);
 139
 140        for (i = 0; i < len; i += rowsize) {
 141                linelen = min(remaining, rowsize);
 142                remaining -= rowsize;
 143
 144                hex_dump_to_buffer(ptr + i, linelen, rowsize, groupsize,
 145                                   linebuf, sizeof(linebuf), ascii);
 146
 147                switch (prefix_type) {
 148                case DUMP_PREFIX_ADDRESS:
 149                        printf("%s%0*lx: %s\n", prefix_str,
 150                               IS_ENABLED(CONFIG_PHYS_64BIT) ? 16 : 8,
 151                               (ulong)map_to_sysmem(ptr) + i, linebuf);
 152                        break;
 153                case DUMP_PREFIX_OFFSET:
 154                        printf("%s%.8x: %s\n", prefix_str, i, linebuf);
 155                        break;
 156                default:
 157                        printf("%s%s\n", prefix_str, linebuf);
 158                        break;
 159                }
 160                if (!IS_ENABLED(CONFIG_SPL_BUILD) && ctrlc())
 161                        return -EINTR;
 162        }
 163
 164        return 0;
 165}
 166
 167void print_hex_dump_bytes(const char *prefix_str, int prefix_type,
 168                          const void *buf, size_t len)
 169{
 170        print_hex_dump(prefix_str, prefix_type, 16, 1, buf, len, true);
 171}
 172#else
 173/*
 174 * Some code in U-Boot copy-pasted from Linux kernel uses both
 175 * functions below so to keep stuff compilable we keep these stubs here.
 176 */
 177int print_hex_dump(const char *prefix_str, int prefix_type, int rowsize,
 178                   int groupsize, const void *buf, size_t len, bool ascii)
 179{
 180        return -ENOSYS;
 181}
 182
 183void print_hex_dump_bytes(const char *prefix_str, int prefix_type,
 184                          const void *buf, size_t len)
 185{
 186}
 187#endif /* CONFIG_HEXDUMP */
 188