diff options
Diffstat (limited to 'lib/hexdump.c')
| -rw-r--r-- | lib/hexdump.c | 105 |
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 | */ |
| 101 | void hex_dump_to_buffer(const void *buf, size_t len, int rowsize, | 107 | int 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 | } |
| 177 | nil: | 195 | nil: |
| 196 | linebuf[lx] = '\0'; | ||
| 197 | return lx; | ||
| 198 | overflow2: | ||
| 178 | linebuf[lx++] = '\0'; | 199 | linebuf[lx++] = '\0'; |
| 200 | overflow1: | ||
| 201 | return ascii ? ascii_column + len : (groupsize * 2 + 1) * ngroups - 1; | ||
| 179 | } | 202 | } |
| 180 | EXPORT_SYMBOL(hex_dump_to_buffer); | 203 | EXPORT_SYMBOL(hex_dump_to_buffer); |
| 181 | 204 | ||
