0001
0002
0003
0004
0005
0006 #include <linux/types.h>
0007 #include <linux/ctype.h>
0008 #include <linux/errno.h>
0009 #include <linux/kernel.h>
0010 #include <linux/minmax.h>
0011 #include <linux/export.h>
0012 #include <asm/unaligned.h>
0013
0014 const char hex_asc[] = "0123456789abcdef";
0015 EXPORT_SYMBOL(hex_asc);
0016 const char hex_asc_upper[] = "0123456789ABCDEF";
0017 EXPORT_SYMBOL(hex_asc_upper);
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046 int hex_to_bin(unsigned char ch)
0047 {
0048 unsigned char cu = ch & 0xdf;
0049 return -1 +
0050 ((ch - '0' + 1) & (unsigned)((ch - '9' - 1) & ('0' - 1 - ch)) >> 8) +
0051 ((cu - 'A' + 11) & (unsigned)((cu - 'F' - 1) & ('A' - 1 - cu)) >> 8);
0052 }
0053 EXPORT_SYMBOL(hex_to_bin);
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063 int hex2bin(u8 *dst, const char *src, size_t count)
0064 {
0065 while (count--) {
0066 int hi, lo;
0067
0068 hi = hex_to_bin(*src++);
0069 if (unlikely(hi < 0))
0070 return -EINVAL;
0071 lo = hex_to_bin(*src++);
0072 if (unlikely(lo < 0))
0073 return -EINVAL;
0074
0075 *dst++ = (hi << 4) | lo;
0076 }
0077 return 0;
0078 }
0079 EXPORT_SYMBOL(hex2bin);
0080
0081
0082
0083
0084
0085
0086
0087 char *bin2hex(char *dst, const void *src, size_t count)
0088 {
0089 const unsigned char *_src = src;
0090
0091 while (count--)
0092 dst = hex_byte_pack(dst, *_src++);
0093 return dst;
0094 }
0095 EXPORT_SYMBOL(bin2hex);
0096
0097
0098
0099
0100
0101
0102
0103
0104
0105
0106
0107
0108
0109
0110
0111
0112
0113
0114
0115
0116
0117
0118
0119
0120
0121
0122
0123
0124
0125
0126
0127 int hex_dump_to_buffer(const void *buf, size_t len, int rowsize, int groupsize,
0128 char *linebuf, size_t linebuflen, bool ascii)
0129 {
0130 const u8 *ptr = buf;
0131 int ngroups;
0132 u8 ch;
0133 int j, lx = 0;
0134 int ascii_column;
0135 int ret;
0136
0137 if (rowsize != 16 && rowsize != 32)
0138 rowsize = 16;
0139
0140 if (len > rowsize)
0141 len = rowsize;
0142 if (!is_power_of_2(groupsize) || groupsize > 8)
0143 groupsize = 1;
0144 if ((len % groupsize) != 0)
0145 groupsize = 1;
0146
0147 ngroups = len / groupsize;
0148 ascii_column = rowsize * 2 + rowsize / groupsize + 1;
0149
0150 if (!linebuflen)
0151 goto overflow1;
0152
0153 if (!len)
0154 goto nil;
0155
0156 if (groupsize == 8) {
0157 const u64 *ptr8 = buf;
0158
0159 for (j = 0; j < ngroups; j++) {
0160 ret = snprintf(linebuf + lx, linebuflen - lx,
0161 "%s%16.16llx", j ? " " : "",
0162 get_unaligned(ptr8 + j));
0163 if (ret >= linebuflen - lx)
0164 goto overflow1;
0165 lx += ret;
0166 }
0167 } else if (groupsize == 4) {
0168 const u32 *ptr4 = buf;
0169
0170 for (j = 0; j < ngroups; j++) {
0171 ret = snprintf(linebuf + lx, linebuflen - lx,
0172 "%s%8.8x", j ? " " : "",
0173 get_unaligned(ptr4 + j));
0174 if (ret >= linebuflen - lx)
0175 goto overflow1;
0176 lx += ret;
0177 }
0178 } else if (groupsize == 2) {
0179 const u16 *ptr2 = buf;
0180
0181 for (j = 0; j < ngroups; j++) {
0182 ret = snprintf(linebuf + lx, linebuflen - lx,
0183 "%s%4.4x", j ? " " : "",
0184 get_unaligned(ptr2 + j));
0185 if (ret >= linebuflen - lx)
0186 goto overflow1;
0187 lx += ret;
0188 }
0189 } else {
0190 for (j = 0; j < len; j++) {
0191 if (linebuflen < lx + 2)
0192 goto overflow2;
0193 ch = ptr[j];
0194 linebuf[lx++] = hex_asc_hi(ch);
0195 if (linebuflen < lx + 2)
0196 goto overflow2;
0197 linebuf[lx++] = hex_asc_lo(ch);
0198 if (linebuflen < lx + 2)
0199 goto overflow2;
0200 linebuf[lx++] = ' ';
0201 }
0202 if (j)
0203 lx--;
0204 }
0205 if (!ascii)
0206 goto nil;
0207
0208 while (lx < ascii_column) {
0209 if (linebuflen < lx + 2)
0210 goto overflow2;
0211 linebuf[lx++] = ' ';
0212 }
0213 for (j = 0; j < len; j++) {
0214 if (linebuflen < lx + 2)
0215 goto overflow2;
0216 ch = ptr[j];
0217 linebuf[lx++] = (isascii(ch) && isprint(ch)) ? ch : '.';
0218 }
0219 nil:
0220 linebuf[lx] = '\0';
0221 return lx;
0222 overflow2:
0223 linebuf[lx++] = '\0';
0224 overflow1:
0225 return ascii ? ascii_column + len : (groupsize * 2 + 1) * ngroups - 1;
0226 }
0227 EXPORT_SYMBOL(hex_dump_to_buffer);
0228
0229 #ifdef CONFIG_PRINTK
0230
0231
0232
0233
0234
0235
0236
0237
0238
0239
0240
0241
0242
0243
0244
0245
0246
0247
0248
0249
0250
0251
0252
0253
0254
0255
0256
0257
0258
0259
0260
0261 void print_hex_dump(const char *level, const char *prefix_str, int prefix_type,
0262 int rowsize, int groupsize,
0263 const void *buf, size_t len, bool ascii)
0264 {
0265 const u8 *ptr = buf;
0266 int i, linelen, remaining = len;
0267 unsigned char linebuf[32 * 3 + 2 + 32 + 1];
0268
0269 if (rowsize != 16 && rowsize != 32)
0270 rowsize = 16;
0271
0272 for (i = 0; i < len; i += rowsize) {
0273 linelen = min(remaining, rowsize);
0274 remaining -= rowsize;
0275
0276 hex_dump_to_buffer(ptr + i, linelen, rowsize, groupsize,
0277 linebuf, sizeof(linebuf), ascii);
0278
0279 switch (prefix_type) {
0280 case DUMP_PREFIX_ADDRESS:
0281 printk("%s%s%p: %s\n",
0282 level, prefix_str, ptr + i, linebuf);
0283 break;
0284 case DUMP_PREFIX_OFFSET:
0285 printk("%s%s%.8x: %s\n", level, prefix_str, i, linebuf);
0286 break;
0287 default:
0288 printk("%s%s%s\n", level, prefix_str, linebuf);
0289 break;
0290 }
0291 }
0292 }
0293 EXPORT_SYMBOL(print_hex_dump);
0294
0295 #endif