hexdump.c
1 /* SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0-only */ 2 3 #include "hexdump.h" 4 #include <ctype.h> 5 6 static void addrprint(FILE * outfile, uint64_t address, int width); 7 8 /*-------------------------------------------------------------------------- 9 * hexdump 10 * 11 * Write a hex dump of 'mem' to 'outfile'. 12 * 13 * parameters: 14 * mem: a pointer to the memory to display 15 * bytes: the number of bytes of data to display 16 * addrprint_start: The address to associate with the first byte of 17 * data. For instance, a value of 0 indicates that the 18 * first byte displayed should be labeled as byte 0. 19 * outfile: The place where the hex dump should be written. 20 * For instance, stdout or stderr may be passed here. 21 * format: A structure specifying how the hex dump should be 22 * formatted. 23 *--------------------------------------------------------------------------*/ 24 void hexdump(const void *mem, int bytes, uint64_t addrprint_start, 25 FILE * outfile, const hexdump_format_t * format) 26 { 27 int bytes_left, index, i; 28 const unsigned char *p; 29 30 /* Quietly return if the caller asks us to do something unreasonable. */ 31 if ((format->bytes_per_line <= 0) || (bytes < 0)) 32 return; 33 34 p = (const unsigned char *)mem; 35 index = 0; 36 37 /* Each iteration handles one full line of output. When loop 38 * terminates, the number of remaining bytes to display (if any) 39 * will not be enough to fill an entire line. 40 */ 41 for (bytes_left = bytes; 42 bytes_left >= format->bytes_per_line; 43 bytes_left -= format->bytes_per_line) { 44 /* print start address for current line */ 45 fprintf(outfile, "%s", format->indent); 46 addrprint(outfile, addrprint_start + index, 47 format->addrprint_width); 48 fprintf(outfile, "%s", format->sep1); 49 50 /* display the bytes in hex */ 51 for (i = 0;;) { 52 fprintf(outfile, "%02x", p[index++]); 53 54 if (++i >= format->bytes_per_line) 55 break; 56 57 fprintf(outfile, "%s", format->sep2); 58 } 59 60 index -= format->bytes_per_line; 61 fprintf(outfile, "%s", format->sep3); 62 63 /* display the bytes as characters */ 64 for (i = 0; i < format->bytes_per_line; i++, index++) 65 fputc(isprint(p[index])?p[index]:format->nonprintable, outfile); 66 67 fprintf(outfile, "\n"); 68 } 69 70 if (bytes_left == 0) 71 return; 72 73 /* print start address for last line */ 74 fprintf(outfile, "%s", format->indent); 75 addrprint(outfile, addrprint_start + index, format->addrprint_width); 76 fprintf(outfile, "%s", format->sep1); 77 78 /* display bytes for last line in hex */ 79 for (i = 0; i < bytes_left; i++) { 80 fprintf(outfile, "%02x", p[index++]); 81 fprintf(outfile, "%s", format->sep2); 82 } 83 84 index -= bytes_left; 85 86 /* pad the rest of the hex byte area with spaces */ 87 for (;;) { 88 fprintf(outfile, " "); 89 90 if (++i >= format->bytes_per_line) 91 break; 92 93 fprintf(outfile, "%s", format->sep2); 94 } 95 96 fprintf(outfile, "%s", format->sep3); 97 98 /* display bytes for last line as characters */ 99 for (i = 0; i < bytes_left; i++) 100 fputc(isprint(p[index])?p[index++]:format->nonprintable, outfile); 101 102 /* pad the rest of the character area with spaces */ 103 for (; i < format->bytes_per_line; i++) 104 fprintf(outfile, " "); 105 106 fprintf(outfile, "\n"); 107 } 108 109 /*-------------------------------------------------------------------------- 110 * addrprint 111 * 112 * Display an address as a hexadecimal number. 113 * 114 * parameters: 115 * outfile: the place where the output should be written 116 * address: the address to display 117 * width: The number of bytes wide the address should be displayed as. 118 * Must be a value from 1 to 8. 119 *--------------------------------------------------------------------------*/ 120 static void addrprint(FILE * outfile, uint64_t address, int width) 121 { 122 char s[17]; 123 int i; 124 125 /* force the user's input to be valid */ 126 if (width < 1) 127 width = 1; 128 else if (width > 8) 129 width = 8; 130 131 /* convert address to string */ 132 sprintf(s, "%016llx", (unsigned long long)address); 133 134 /* write it out, with colons separating consecutive 16-bit 135 * chunks of the address 136 */ 137 for (i = 16 - (2 * width);;) { 138 fprintf(outfile, "%c", s[i]); 139 140 if (++i >= 16) 141 break; 142 143 if ((i % 4) == 0) 144 fprintf(outfile, ":"); 145 } 146 }