1 /*****************************************************************************\
3 \*****************************************************************************/
10 * David S. Peterson. All rights reserved.
12 * Author: David S. Peterson <dave_peterson@pobox.com>
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions are
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
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.)
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.
46 static void addrprint(FILE * outfile, uint64_t address, int width);
47 static void hexprint(FILE * outfile, unsigned char byte);
48 static void charprint(FILE * outfile, unsigned char byte,
49 unsigned char nonprintable,
50 is_printable_fn_t is_printable_fn);
52 /*--------------------------------------------------------------------------
55 * Write a hex dump of 'mem' to 'outfile'.
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
67 *--------------------------------------------------------------------------*/
68 void hexdump(const void *mem, int bytes, uint64_t addrprint_start,
69 FILE * outfile, const hexdump_format_t * format)
71 int bytes_left, index, i;
72 const unsigned char *p;
73 is_printable_fn_t is_printable_fn;
75 /* Quietly return if the caller asks us to do something unreasonable. */
76 if ((format->bytes_per_line <= 0) || (bytes < 0))
79 is_printable_fn = format->is_printable_fn;
81 if (is_printable_fn == NULL)
82 is_printable_fn = default_is_printable_fn;
84 p = (const unsigned char *)mem;
87 /* 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.
91 for (bytes_left = bytes;
92 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);
100 /* display the bytes in hex */
102 hexprint(outfile, p[index++]);
104 if (++i >= format->bytes_per_line)
107 fprintf(outfile, format->sep2);
110 index -= format->bytes_per_line;
111 fprintf(outfile, format->sep3);
113 /* display the bytes as characters */
114 for (i = 0; i < format->bytes_per_line; i++)
115 charprint(outfile, p[index++], format->nonprintable,
118 fprintf(outfile, "\n");
124 /* 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);
129 /* 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);
137 /* pad the rest of the hex byte area with spaces */
139 fprintf(outfile, " ");
141 if (++i >= format->bytes_per_line)
144 fprintf(outfile, format->sep2);
147 fprintf(outfile, format->sep3);
149 /* display bytes for last line as characters */
150 for (i = 0; i < bytes_left; i++)
151 charprint(outfile, p[index++], format->nonprintable,
154 /* pad the rest of the character area with spaces */
155 for (; i < format->bytes_per_line; i++)
156 fprintf(outfile, " ");
158 fprintf(outfile, "\n");
161 /*--------------------------------------------------------------------------
162 * default_is_printable_fn
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
170 * c: the input character
173 * Return 1 if the input character is printable. Otherwise return 0.
174 *--------------------------------------------------------------------------*/
175 int default_is_printable_fn(unsigned char c)
177 return (c >= 0x20) && (c <= 0x7e);
180 /*--------------------------------------------------------------------------
183 * Display an address as a hexadecimal number.
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 *--------------------------------------------------------------------------*/
191 static void addrprint(FILE * outfile, uint64_t address, int width)
196 /* force the user's input to be valid */
202 /* convert address to string */
203 sprintf(s, "%016llx", (unsigned long long)address);
205 /* write it out, with colons separating consecutive 16-bit
206 * chunks of the address
208 for (i = 16 - (2 * width);;) {
209 fprintf(outfile, "%c", s[i]);
215 fprintf(outfile, ":");
219 /*--------------------------------------------------------------------------
222 * Display a byte as a two digit hex value.
225 * outfile: the place where the output should be written
226 * byte: the byte to display
227 *--------------------------------------------------------------------------*/
228 static void hexprint(FILE * outfile, unsigned char byte)
230 static const char tbl[] = {
231 '0', '1', '2', '3', '4', '5', '6', '7',
232 '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
235 fprintf(outfile, "%c%c", tbl[byte >> 4], tbl[byte & 0x0f]);
238 /*--------------------------------------------------------------------------
241 * Display a byte as its character representation.
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 *--------------------------------------------------------------------------*/
251 static void charprint(FILE * outfile, unsigned char byte,
252 unsigned char nonprintable,
253 is_printable_fn_t is_printable_fn)
255 fprintf(outfile, "%c", is_printable_fn(byte) ? byte : nonprintable);