16ff66f50SPeter Crosthwaite /*
26ff66f50SPeter Crosthwaite * Helper to hexdump a buffer
36ff66f50SPeter Crosthwaite *
46ff66f50SPeter Crosthwaite * Copyright (c) 2013 Red Hat, Inc.
56ff66f50SPeter Crosthwaite * Copyright (c) 2013 Gerd Hoffmann <kraxel@redhat.com>
66ff66f50SPeter Crosthwaite * Copyright (c) 2013 Peter Crosthwaite <peter.crosthwaite@xilinx.com>
76ff66f50SPeter Crosthwaite * Copyright (c) 2013 Xilinx, Inc
86ff66f50SPeter Crosthwaite *
96ff66f50SPeter Crosthwaite * This work is licensed under the terms of the GNU GPL, version 2. See
106ff66f50SPeter Crosthwaite * the COPYING file in the top-level directory.
116ff66f50SPeter Crosthwaite *
126ff66f50SPeter Crosthwaite * Contributions after 2012-01-13 are licensed under the terms of the
136ff66f50SPeter Crosthwaite * GNU GPL, version 2 or (at your option) any later version.
146ff66f50SPeter Crosthwaite */
156ff66f50SPeter Crosthwaite
16aafd7584SPeter Maydell #include "qemu/osdep.h"
17415b7327SMarc-André Lureau #include "qemu/cutils.h"
186ff66f50SPeter Crosthwaite
hexdump_nibble(unsigned x)19*10e4927bSRichard Henderson static inline char hexdump_nibble(unsigned x)
20*10e4927bSRichard Henderson {
21*10e4927bSRichard Henderson return (x < 10 ? '0' : 'a' - 10) + x;
22*10e4927bSRichard Henderson }
23*10e4927bSRichard Henderson
qemu_hexdump_line(GString * str,const void * vbuf,size_t len,size_t unit_len,size_t block_len)24c49d1c37SRichard Henderson GString *qemu_hexdump_line(GString *str, const void *vbuf, size_t len,
25c49d1c37SRichard Henderson size_t unit_len, size_t block_len)
266ff66f50SPeter Crosthwaite {
2753ee5f55SRichard Henderson const uint8_t *buf = vbuf;
28c49d1c37SRichard Henderson size_t u, b;
296ff66f50SPeter Crosthwaite
3053ee5f55SRichard Henderson if (str == NULL) {
3153ee5f55SRichard Henderson /* Estimate the length of the output to avoid reallocs. */
32c49d1c37SRichard Henderson size_t est = len * 2;
33c49d1c37SRichard Henderson if (unit_len) {
34c49d1c37SRichard Henderson est += len / unit_len;
35c49d1c37SRichard Henderson }
36c49d1c37SRichard Henderson if (block_len) {
37c49d1c37SRichard Henderson est += len / block_len;
38c49d1c37SRichard Henderson }
39c49d1c37SRichard Henderson str = g_string_sized_new(est + 1);
406ff66f50SPeter Crosthwaite }
41bbb16908SLaurent Vivier
42c49d1c37SRichard Henderson for (u = 0, b = 0; len; u++, b++, len--, buf++) {
43*10e4927bSRichard Henderson uint8_t c;
44*10e4927bSRichard Henderson
45c49d1c37SRichard Henderson if (unit_len && u == unit_len) {
4653ee5f55SRichard Henderson g_string_append_c(str, ' ');
47c49d1c37SRichard Henderson u = 0;
486ff66f50SPeter Crosthwaite }
49c49d1c37SRichard Henderson if (block_len && b == block_len) {
50c49d1c37SRichard Henderson g_string_append_c(str, ' ');
51c49d1c37SRichard Henderson b = 0;
52c49d1c37SRichard Henderson }
53*10e4927bSRichard Henderson
54*10e4927bSRichard Henderson c = *buf;
55*10e4927bSRichard Henderson g_string_append_c(str, hexdump_nibble(c / 16));
56*10e4927bSRichard Henderson g_string_append_c(str, hexdump_nibble(c % 16));
576ff66f50SPeter Crosthwaite }
5853ee5f55SRichard Henderson
5953ee5f55SRichard Henderson return str;
606ff66f50SPeter Crosthwaite }
6113dfa933SRichard Henderson
asciidump_line(char * line,const void * bufptr,size_t len)6213dfa933SRichard Henderson static void asciidump_line(char *line, const void *bufptr, size_t len)
6313dfa933SRichard Henderson {
6413dfa933SRichard Henderson const char *buf = bufptr;
6513dfa933SRichard Henderson
6613dfa933SRichard Henderson for (size_t i = 0; i < len; i++) {
6713dfa933SRichard Henderson char c = buf[i];
6813dfa933SRichard Henderson
69a1555559SIsaac Lozano if (c < ' ' || c > '~') {
70a1555559SIsaac Lozano c = '.';
71a1555559SIsaac Lozano }
72bbb16908SLaurent Vivier *line++ = c;
73a1555559SIsaac Lozano }
74bbb16908SLaurent Vivier *line = '\0';
75bbb16908SLaurent Vivier }
76bbb16908SLaurent Vivier
7753ee5f55SRichard Henderson #define QEMU_HEXDUMP_LINE_BYTES 16
7813dfa933SRichard Henderson #define QEMU_HEXDUMP_LINE_WIDTH \
7913dfa933SRichard Henderson (QEMU_HEXDUMP_LINE_BYTES * 2 + QEMU_HEXDUMP_LINE_BYTES / 4)
8013dfa933SRichard Henderson
qemu_hexdump(FILE * fp,const char * prefix,const void * bufptr,size_t size)81bbb16908SLaurent Vivier void qemu_hexdump(FILE *fp, const char *prefix,
82bbb16908SLaurent Vivier const void *bufptr, size_t size)
83bbb16908SLaurent Vivier {
8453ee5f55SRichard Henderson g_autoptr(GString) str = g_string_sized_new(QEMU_HEXDUMP_LINE_WIDTH + 1);
8513dfa933SRichard Henderson char ascii[QEMU_HEXDUMP_LINE_BYTES + 1];
8613dfa933SRichard Henderson size_t b, len;
87bbb16908SLaurent Vivier
8813dfa933SRichard Henderson for (b = 0; b < size; b += len) {
8913dfa933SRichard Henderson len = MIN(size - b, QEMU_HEXDUMP_LINE_BYTES);
9013dfa933SRichard Henderson
9153ee5f55SRichard Henderson g_string_truncate(str, 0);
92c49d1c37SRichard Henderson qemu_hexdump_line(str, bufptr + b, len, 1, 4);
9313dfa933SRichard Henderson asciidump_line(ascii, bufptr + b, len);
9413dfa933SRichard Henderson
9513dfa933SRichard Henderson fprintf(fp, "%s: %04zx: %-*s %s\n",
9653ee5f55SRichard Henderson prefix, b, QEMU_HEXDUMP_LINE_WIDTH, str->str, ascii);
97bbb16908SLaurent Vivier }
98bbb16908SLaurent Vivier
996ff66f50SPeter Crosthwaite }
100