aboutsummaryrefslogtreecommitdiffstats
path: root/lib/hexdump.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/hexdump.c')
-rw-r--r--lib/hexdump.c105
1 files changed, 64 insertions, 41 deletions
diff --git a/lib/hexdump.c b/lib/hexdump.c
index 270773b91923..7ea09699855d 100644
--- a/lib/hexdump.c
+++ b/lib/hexdump.c
@@ -97,63 +97,79 @@ EXPORT_SYMBOL(bin2hex);
97 * 97 *
98 * example output buffer: 98 * example output buffer:
99 * 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f @ABCDEFGHIJKLMNO 99 * 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f @ABCDEFGHIJKLMNO
100 *
101 * Return:
102 * The amount of bytes placed in the buffer without terminating NUL. If the
103 * output was truncated, then the return value is the number of bytes
104 * (excluding the terminating NUL) which would have been written to the final
105 * string if enough space had been available.
100 */ 106 */
101void hex_dump_to_buffer(const void *buf, size_t len, int rowsize, 107int hex_dump_to_buffer(const void *buf, size_t len, int rowsize, int groupsize,
102 int groupsize, char *linebuf, size_t linebuflen, 108 char *linebuf, size_t linebuflen, bool ascii)
103 bool ascii)
104{ 109{
105 const u8 *ptr = buf; 110 const u8 *ptr = buf;
111 int ngroups;
106 u8 ch; 112 u8 ch;
107 int j, lx = 0; 113 int j, lx = 0;
108 int ascii_column; 114 int ascii_column;
115 int ret;
109 116
110 if (rowsize != 16 && rowsize != 32) 117 if (rowsize != 16 && rowsize != 32)
111 rowsize = 16; 118 rowsize = 16;
112 119
113 if (!len)
114 goto nil;
115 if (len > rowsize) /* limit to one line at a time */ 120 if (len > rowsize) /* limit to one line at a time */
116 len = rowsize; 121 len = rowsize;
122 if (!is_power_of_2(groupsize) || groupsize > 8)
123 groupsize = 1;
117 if ((len % groupsize) != 0) /* no mixed size output */ 124 if ((len % groupsize) != 0) /* no mixed size output */
118 groupsize = 1; 125 groupsize = 1;
119 126
120 switch (groupsize) { 127 ngroups = len / groupsize;
121 case 8: { 128 ascii_column = rowsize * 2 + rowsize / groupsize + 1;
122 const u64 *ptr8 = buf;
123 int ngroups = len / groupsize;
124 129
125 for (j = 0; j < ngroups; j++) 130 if (!linebuflen)
126 lx += scnprintf(linebuf + lx, linebuflen - lx, 131 goto overflow1;
127 "%s%16.16llx", j ? " " : "",
128 (unsigned long long)*(ptr8 + j));
129 ascii_column = 17 * ngroups + 2;
130 break;
131 }
132 132
133 case 4: { 133 if (!len)
134 const u32 *ptr4 = buf; 134 goto nil;
135 int ngroups = len / groupsize;
136 135
137 for (j = 0; j < ngroups; j++) 136 if (groupsize == 8) {
138 lx += scnprintf(linebuf + lx, linebuflen - lx, 137 const u64 *ptr8 = buf;
139 "%s%8.8x", j ? " " : "", *(ptr4 + j));
140 ascii_column = 9 * ngroups + 2;
141 break;
142 }
143 138
144 case 2: { 139 for (j = 0; j < ngroups; j++) {
145 const u16 *ptr2 = buf; 140 ret = snprintf(linebuf + lx, linebuflen - lx,
146 int ngroups = len / groupsize; 141 "%s%16.16llx", j ? " " : "",
142 (unsigned long long)*(ptr8 + j));
143 if (ret >= linebuflen - lx)
144 goto overflow1;
145 lx += ret;
146 }
147 } else if (groupsize == 4) {
148 const u32 *ptr4 = buf;
147 149
148 for (j = 0; j < ngroups; j++) 150 for (j = 0; j < ngroups; j++) {
149 lx += scnprintf(linebuf + lx, linebuflen - lx, 151 ret = snprintf(linebuf + lx, linebuflen - lx,
150 "%s%4.4x", j ? " " : "", *(ptr2 + j)); 152 "%s%8.8x", j ? " " : "",
151 ascii_column = 5 * ngroups + 2; 153 *(ptr4 + j));
152 break; 154 if (ret >= linebuflen - lx)
153 } 155 goto overflow1;
156 lx += ret;
157 }
158 } else if (groupsize == 2) {
159 const u16 *ptr2 = buf;
154 160
155 default: 161 for (j = 0; j < ngroups; j++) {
156 for (j = 0; (j < len) && (lx + 3) <= linebuflen; j++) { 162 ret = snprintf(linebuf + lx, linebuflen - lx,
163 "%s%4.4x", j ? " " : "",
164 *(ptr2 + j));
165 if (ret >= linebuflen - lx)
166 goto overflow1;
167 lx += ret;
168 }
169 } else {
170 for (j = 0; j < len; j++) {
171 if (linebuflen < lx + 3)
172 goto overflow2;
157 ch = ptr[j]; 173 ch = ptr[j];
158 linebuf[lx++] = hex_asc_hi(ch); 174 linebuf[lx++] = hex_asc_hi(ch);
159 linebuf[lx++] = hex_asc_lo(ch); 175 linebuf[lx++] = hex_asc_lo(ch);
@@ -161,21 +177,28 @@ void hex_dump_to_buffer(const void *buf, size_t len, int rowsize,
161 } 177 }
162 if (j) 178 if (j)
163 lx--; 179 lx--;
164
165 ascii_column = 3 * rowsize + 2;
166 break;
167 } 180 }
168 if (!ascii) 181 if (!ascii)
169 goto nil; 182 goto nil;
170 183
171 while (lx < (linebuflen - 1) && lx < (ascii_column - 1)) 184 while (lx < ascii_column) {
185 if (linebuflen < lx + 2)
186 goto overflow2;
172 linebuf[lx++] = ' '; 187 linebuf[lx++] = ' ';
173 for (j = 0; (j < len) && (lx + 2) < linebuflen; j++) { 188 }
189 for (j = 0; j < len; j++) {
190 if (linebuflen < lx + 2)
191 goto overflow2;
174 ch = ptr[j]; 192 ch = ptr[j];
175 linebuf[lx++] = (isascii(ch) && isprint(ch)) ? ch : '.'; 193 linebuf[lx++] = (isascii(ch) && isprint(ch)) ? ch : '.';
176 } 194 }
177nil: 195nil:
196 linebuf[lx] = '\0';
197 return lx;
198overflow2:
178 linebuf[lx++] = '\0'; 199 linebuf[lx++] = '\0';
200overflow1:
201 return ascii ? ascii_column + len : (groupsize * 2 + 1) * ngroups - 1;
179} 202}
180EXPORT_SYMBOL(hex_dump_to_buffer); 203EXPORT_SYMBOL(hex_dump_to_buffer);
181 204