blob: 405703fe732285ebf3d06f193035c6a7fd64710d [file] [log] [blame]
Stefan Reinauer6540ae52007-07-12 16:35:42 +00001/*****************************************************************************\
2 * hexdump.c
Stefan Reinauer6540ae52007-07-12 16:35:42 +00003\*****************************************************************************/
4
5#include "hexdump.h"
6
7/* hexdump.c
8 *
9 * Copyright (C) 2002
10 * David S. Peterson. All rights reserved.
11 *
12 * Author: David S. Peterson <dave_peterson@pobox.com>
13 *
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions are
16 * met:
17 * 1. Redistributions of source code must retain the above copyright notice,
18 * this list of conditions, and the entire permission notice, including
19 * the following disclaimer of warranties.
20 * 2. Redistributions in binary form must reproduce the above copyright
21 * notice, this list of conditions, and the entire permission notice,
22 * including the following disclaimer in the documentation and/or other
23 * materials provided with the distribution.
24 * 3. The name(s) of the author(s) may not be used to endorse or promote
25 * products derived from this software without specific prior written
26 * permission.
27 *
28 * ALTERNATIVELY, this product may be distributed under the terms of the GNU
29 * General Public License, in which case the provisions of the GPL are
30 * required INSTEAD OF the above restrictions. (This clause is necessary due
31 * to a potential bad interaction between the GPL and the restrictions
32 * contained in a BSD-style copyright.)
33 *
34 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
35 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
36 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED.
37 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
38 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
39 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
40 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
41 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
42 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
43 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
44 */
45
Stefan Reinauer90b96b62010-01-13 21:00:23 +000046static void addrprint(FILE * outfile, uint64_t address, int width);
47static void hexprint(FILE * outfile, unsigned char byte);
48static void charprint(FILE * outfile, unsigned char byte,
49 unsigned char nonprintable,
50 is_printable_fn_t is_printable_fn);
Stefan Reinauer6540ae52007-07-12 16:35:42 +000051
52/*--------------------------------------------------------------------------
53 * hexdump
54 *
55 * Write a hex dump of 'mem' to 'outfile'.
56 *
57 * parameters:
58 * mem: a pointer to the memory to display
59 * bytes: the number of bytes of data to display
60 * addrprint_start: The address to associate with the first byte of
61 * data. For instance, a value of 0 indicates that the
62 * first byte displayed should be labeled as byte 0.
63 * outfile: The place where the hex dump should be written.
64 * For instance, stdout or stderr may be passed here.
65 * format: A structure specifying how the hex dump should be
66 * formatted.
67 *--------------------------------------------------------------------------*/
Stefan Reinauer90b96b62010-01-13 21:00:23 +000068void hexdump(const void *mem, int bytes, uint64_t addrprint_start,
69 FILE * outfile, const hexdump_format_t * format)
70{
71 int bytes_left, index, i;
72 const unsigned char *p;
73 is_printable_fn_t is_printable_fn;
Stefan Reinauer6540ae52007-07-12 16:35:42 +000074
Stefan Reinauer90b96b62010-01-13 21:00:23 +000075 /* Quietly return if the caller asks us to do something unreasonable. */
76 if ((format->bytes_per_line <= 0) || (bytes < 0))
77 return;
Stefan Reinauer6540ae52007-07-12 16:35:42 +000078
Stefan Reinauer90b96b62010-01-13 21:00:23 +000079 is_printable_fn = format->is_printable_fn;
Stefan Reinauer6540ae52007-07-12 16:35:42 +000080
Stefan Reinauer90b96b62010-01-13 21:00:23 +000081 if (is_printable_fn == NULL)
82 is_printable_fn = default_is_printable_fn;
Stefan Reinauer6540ae52007-07-12 16:35:42 +000083
Stefan Reinauer90b96b62010-01-13 21:00:23 +000084 p = (const unsigned char *)mem;
85 index = 0;
Stefan Reinauer6540ae52007-07-12 16:35:42 +000086
Stefan Reinauer90b96b62010-01-13 21:00:23 +000087 /* Each iteration handles one full line of output. When loop
88 * terminates, the number of remaining bytes to display (if any)
89 * will not be enough to fill an entire line.
90 */
Stefan Reinauer14e22772010-04-27 06:56:47 +000091 for (bytes_left = bytes;
Stefan Reinauer90b96b62010-01-13 21:00:23 +000092 bytes_left >= format->bytes_per_line;
93 bytes_left -= format->bytes_per_line) {
94 /* print start address for current line */
95 fprintf(outfile, format->indent);
96 addrprint(outfile, addrprint_start + index,
97 format->addrprint_width);
98 fprintf(outfile, format->sep1);
Stefan Reinauer6540ae52007-07-12 16:35:42 +000099
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000100 /* display the bytes in hex */
101 for (i = 0;;) {
102 hexprint(outfile, p[index++]);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000103
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000104 if (++i >= format->bytes_per_line)
105 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000106
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000107 fprintf(outfile, format->sep2);
108 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000109
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000110 index -= format->bytes_per_line;
111 fprintf(outfile, format->sep3);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000112
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000113 /* display the bytes as characters */
114 for (i = 0; i < format->bytes_per_line; i++)
115 charprint(outfile, p[index++], format->nonprintable,
116 is_printable_fn);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000117
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000118 fprintf(outfile, "\n");
119 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000120
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000121 if (bytes_left == 0)
122 return;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000123
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000124 /* print start address for last line */
125 fprintf(outfile, format->indent);
126 addrprint(outfile, addrprint_start + index, format->addrprint_width);
127 fprintf(outfile, format->sep1);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000128
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000129 /* display bytes for last line in hex */
130 for (i = 0; i < bytes_left; i++) {
131 hexprint(outfile, p[index++]);
132 fprintf(outfile, format->sep2);
133 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000134
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000135 index -= bytes_left;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000136
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000137 /* pad the rest of the hex byte area with spaces */
138 for (;;) {
139 fprintf(outfile, " ");
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000140
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000141 if (++i >= format->bytes_per_line)
142 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000143
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000144 fprintf(outfile, format->sep2);
145 }
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000146
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000147 fprintf(outfile, format->sep3);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000148
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000149 /* display bytes for last line as characters */
150 for (i = 0; i < bytes_left; i++)
151 charprint(outfile, p[index++], format->nonprintable,
152 is_printable_fn);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000153
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000154 /* pad the rest of the character area with spaces */
155 for (; i < format->bytes_per_line; i++)
156 fprintf(outfile, " ");
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000157
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000158 fprintf(outfile, "\n");
159}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000160
161/*--------------------------------------------------------------------------
162 * default_is_printable_fn
163 *
164 * Determine whether the input character is printable. The proper behavior
165 * for this type of function may be system-dependent. This function takes a
166 * conservative approach. If it is not adequate for your purposes, you can
167 * write your own.
168 *
169 * parameters:
170 * c: the input character
171 *
172 * return value:
173 * Return 1 if the input character is printable. Otherwise return 0.
174 *--------------------------------------------------------------------------*/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000175int default_is_printable_fn(unsigned char c)
176{
177 return (c >= 0x20) && (c <= 0x7e);
178}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000179
180/*--------------------------------------------------------------------------
181 * addrprint
182 *
183 * Display an address as a hexadecimal number.
184 *
185 * parameters:
186 * outfile: the place where the output should be written
187 * address: the address to display
188 * width: The number of bytes wide the address should be displayed as.
189 * Must be a value from 1 to 8.
190 *--------------------------------------------------------------------------*/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000191static void addrprint(FILE * outfile, uint64_t address, int width)
192{
193 char s[17];
194 int i;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000195
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000196 /* force the user's input to be valid */
197 if (width < 1)
198 width = 1;
199 else if (width > 8)
200 width = 8;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000201
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000202 /* convert address to string */
203 sprintf(s, "%016llx", (unsigned long long)address);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000204
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000205 /* write it out, with colons separating consecutive 16-bit
206 * chunks of the address
207 */
208 for (i = 16 - (2 * width);;) {
209 fprintf(outfile, "%c", s[i]);
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000210
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000211 if (++i >= 16)
212 break;
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000213
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000214 if ((i % 4) == 0)
215 fprintf(outfile, ":");
216 }
217}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000218
219/*--------------------------------------------------------------------------
220 * hexprint
221 *
222 * Display a byte as a two digit hex value.
223 *
224 * parameters:
225 * outfile: the place where the output should be written
226 * byte: the byte to display
227 *--------------------------------------------------------------------------*/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000228static void hexprint(FILE * outfile, unsigned char byte)
229{
230 static const char tbl[] = {
231 '0', '1', '2', '3', '4', '5', '6', '7',
232 '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
233 };
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000234
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000235 fprintf(outfile, "%c%c", tbl[byte >> 4], tbl[byte & 0x0f]);
236}
Stefan Reinauer6540ae52007-07-12 16:35:42 +0000237
238/*--------------------------------------------------------------------------
239 * charprint
240 *
241 * Display a byte as its character representation.
242 *
243 * parameters:
244 * outfile: the place where the output should be written
245 * byte: the byte to display
246 * nonprintable: a substitute character to display if the byte
247 * represents a nonprintable character
248 * is_printable_fn: a function that returns a boolean value indicating
249 * whether a given character is printable
250 *--------------------------------------------------------------------------*/
Stefan Reinauer90b96b62010-01-13 21:00:23 +0000251static void charprint(FILE * outfile, unsigned char byte,
252 unsigned char nonprintable,
253 is_printable_fn_t is_printable_fn)
254{
255 fprintf(outfile, "%c", is_printable_fn(byte) ? byte : nonprintable);
256}