xref: /openbmc/qemu/util/hexdump.c (revision 76bccf3c)
1 /*
2 * Helper to hexdump a buffer
3  *
4  * Copyright (c) 2013 Red Hat, Inc.
5  * Copyright (c) 2013 Gerd Hoffmann <kraxel@redhat.com>
6  * Copyright (c) 2013 Peter Crosthwaite <peter.crosthwaite@xilinx.com>
7  * Copyright (c) 2013 Xilinx, Inc
8  *
9  * This work is licensed under the terms of the GNU GPL, version 2.  See
10  * the COPYING file in the top-level directory.
11  *
12  * Contributions after 2012-01-13 are licensed under the terms of the
13  * GNU GPL, version 2 or (at your option) any later version.
14  */
15 
16 #include "qemu/osdep.h"
17 #include "qemu/cutils.h"
18 
19 static inline char hexdump_nibble(unsigned x)
20 {
21     return (x < 10 ? '0' : 'a' - 10) + x;
22 }
23 
24 GString *qemu_hexdump_line(GString *str, const void *vbuf, size_t len,
25                            size_t unit_len, size_t block_len)
26 {
27     const uint8_t *buf = vbuf;
28     size_t u, b;
29 
30     if (str == NULL) {
31         /* Estimate the length of the output to avoid reallocs. */
32         size_t est = len * 2;
33         if (unit_len) {
34             est += len / unit_len;
35         }
36         if (block_len) {
37             est += len / block_len;
38         }
39         str = g_string_sized_new(est + 1);
40     }
41 
42     for (u = 0, b = 0; len; u++, b++, len--, buf++) {
43         uint8_t c;
44 
45         if (unit_len && u == unit_len) {
46             g_string_append_c(str, ' ');
47             u = 0;
48         }
49         if (block_len && b == block_len) {
50             g_string_append_c(str, ' ');
51             b = 0;
52         }
53 
54         c = *buf;
55         g_string_append_c(str, hexdump_nibble(c / 16));
56         g_string_append_c(str, hexdump_nibble(c % 16));
57     }
58 
59     return str;
60 }
61 
62 static void asciidump_line(char *line, const void *bufptr, size_t len)
63 {
64     const char *buf = bufptr;
65 
66     for (size_t i = 0; i < len; i++) {
67         char c = buf[i];
68 
69         if (c < ' ' || c > '~') {
70             c = '.';
71         }
72         *line++ = c;
73     }
74     *line = '\0';
75 }
76 
77 #define QEMU_HEXDUMP_LINE_BYTES 16
78 #define QEMU_HEXDUMP_LINE_WIDTH \
79     (QEMU_HEXDUMP_LINE_BYTES * 2 + QEMU_HEXDUMP_LINE_BYTES / 4)
80 
81 void qemu_hexdump(FILE *fp, const char *prefix,
82                   const void *bufptr, size_t size)
83 {
84     g_autoptr(GString) str = g_string_sized_new(QEMU_HEXDUMP_LINE_WIDTH + 1);
85     char ascii[QEMU_HEXDUMP_LINE_BYTES + 1];
86     size_t b, len;
87 
88     for (b = 0; b < size; b += len) {
89         len = MIN(size - b, QEMU_HEXDUMP_LINE_BYTES);
90 
91         g_string_truncate(str, 0);
92         qemu_hexdump_line(str, bufptr + b, len, 1, 4);
93         asciidump_line(ascii, bufptr + b, len);
94 
95         fprintf(fp, "%s: %04zx: %-*s %s\n",
96                 prefix, b, QEMU_HEXDUMP_LINE_WIDTH, str->str, ascii);
97     }
98 
99 }
100