0001
0002
0003
0004 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0005
0006 #include <linux/init.h>
0007 #include <linux/kernel.h>
0008 #include <linux/module.h>
0009 #include <linux/random.h>
0010 #include <linux/string.h>
0011
0012 static const unsigned char data_b[] = {
0013 '\xbe', '\x32', '\xdb', '\x7b', '\x0a', '\x18', '\x93', '\xb2',
0014 '\x70', '\xba', '\xc4', '\x24', '\x7d', '\x83', '\x34', '\x9b',
0015 '\xa6', '\x9c', '\x31', '\xad', '\x9c', '\x0f', '\xac', '\xe9',
0016 '\x4c', '\xd1', '\x19', '\x99', '\x43', '\xb1', '\xaf', '\x0c',
0017 };
0018
0019 static const unsigned char data_a[] = ".2.{....p..$}.4...1.....L...C...";
0020
0021 static const char * const test_data_1[] __initconst = {
0022 "be", "32", "db", "7b", "0a", "18", "93", "b2",
0023 "70", "ba", "c4", "24", "7d", "83", "34", "9b",
0024 "a6", "9c", "31", "ad", "9c", "0f", "ac", "e9",
0025 "4c", "d1", "19", "99", "43", "b1", "af", "0c",
0026 };
0027
0028 static const char * const test_data_2_le[] __initconst = {
0029 "32be", "7bdb", "180a", "b293",
0030 "ba70", "24c4", "837d", "9b34",
0031 "9ca6", "ad31", "0f9c", "e9ac",
0032 "d14c", "9919", "b143", "0caf",
0033 };
0034
0035 static const char * const test_data_2_be[] __initconst = {
0036 "be32", "db7b", "0a18", "93b2",
0037 "70ba", "c424", "7d83", "349b",
0038 "a69c", "31ad", "9c0f", "ace9",
0039 "4cd1", "1999", "43b1", "af0c",
0040 };
0041
0042 static const char * const test_data_4_le[] __initconst = {
0043 "7bdb32be", "b293180a", "24c4ba70", "9b34837d",
0044 "ad319ca6", "e9ac0f9c", "9919d14c", "0cafb143",
0045 };
0046
0047 static const char * const test_data_4_be[] __initconst = {
0048 "be32db7b", "0a1893b2", "70bac424", "7d83349b",
0049 "a69c31ad", "9c0face9", "4cd11999", "43b1af0c",
0050 };
0051
0052 static const char * const test_data_8_le[] __initconst = {
0053 "b293180a7bdb32be", "9b34837d24c4ba70",
0054 "e9ac0f9cad319ca6", "0cafb1439919d14c",
0055 };
0056
0057 static const char * const test_data_8_be[] __initconst = {
0058 "be32db7b0a1893b2", "70bac4247d83349b",
0059 "a69c31ad9c0face9", "4cd1199943b1af0c",
0060 };
0061
0062 #define FILL_CHAR '#'
0063
0064 static unsigned total_tests __initdata;
0065 static unsigned failed_tests __initdata;
0066
0067 static void __init test_hexdump_prepare_test(size_t len, int rowsize,
0068 int groupsize, char *test,
0069 size_t testlen, bool ascii)
0070 {
0071 char *p;
0072 const char * const *result;
0073 size_t l = len;
0074 int gs = groupsize, rs = rowsize;
0075 unsigned int i;
0076 const bool is_be = IS_ENABLED(CONFIG_CPU_BIG_ENDIAN);
0077
0078 if (rs != 16 && rs != 32)
0079 rs = 16;
0080
0081 if (l > rs)
0082 l = rs;
0083
0084 if (!is_power_of_2(gs) || gs > 8 || (len % gs != 0))
0085 gs = 1;
0086
0087 if (gs == 8)
0088 result = is_be ? test_data_8_be : test_data_8_le;
0089 else if (gs == 4)
0090 result = is_be ? test_data_4_be : test_data_4_le;
0091 else if (gs == 2)
0092 result = is_be ? test_data_2_be : test_data_2_le;
0093 else
0094 result = test_data_1;
0095
0096
0097 p = test;
0098 for (i = 0; i < l / gs; i++) {
0099 const char *q = *result++;
0100 size_t amount = strlen(q);
0101
0102 memcpy(p, q, amount);
0103 p += amount;
0104
0105 *p++ = ' ';
0106 }
0107 if (i)
0108 p--;
0109
0110
0111 if (ascii) {
0112 do {
0113 *p++ = ' ';
0114 } while (p < test + rs * 2 + rs / gs + 1);
0115
0116 strncpy(p, data_a, l);
0117 p += l;
0118 }
0119
0120 *p = '\0';
0121 }
0122
0123 #define TEST_HEXDUMP_BUF_SIZE (32 * 3 + 2 + 32 + 1)
0124
0125 static void __init test_hexdump(size_t len, int rowsize, int groupsize,
0126 bool ascii)
0127 {
0128 char test[TEST_HEXDUMP_BUF_SIZE];
0129 char real[TEST_HEXDUMP_BUF_SIZE];
0130
0131 total_tests++;
0132
0133 memset(real, FILL_CHAR, sizeof(real));
0134 hex_dump_to_buffer(data_b, len, rowsize, groupsize, real, sizeof(real),
0135 ascii);
0136
0137 memset(test, FILL_CHAR, sizeof(test));
0138 test_hexdump_prepare_test(len, rowsize, groupsize, test, sizeof(test),
0139 ascii);
0140
0141 if (memcmp(test, real, TEST_HEXDUMP_BUF_SIZE)) {
0142 pr_err("Len: %zu row: %d group: %d\n", len, rowsize, groupsize);
0143 pr_err("Result: '%s'\n", real);
0144 pr_err("Expect: '%s'\n", test);
0145 failed_tests++;
0146 }
0147 }
0148
0149 static void __init test_hexdump_set(int rowsize, bool ascii)
0150 {
0151 size_t d = min_t(size_t, sizeof(data_b), rowsize);
0152 size_t len = get_random_int() % d + 1;
0153
0154 test_hexdump(len, rowsize, 4, ascii);
0155 test_hexdump(len, rowsize, 2, ascii);
0156 test_hexdump(len, rowsize, 8, ascii);
0157 test_hexdump(len, rowsize, 1, ascii);
0158 }
0159
0160 static void __init test_hexdump_overflow(size_t buflen, size_t len,
0161 int rowsize, int groupsize,
0162 bool ascii)
0163 {
0164 char test[TEST_HEXDUMP_BUF_SIZE];
0165 char buf[TEST_HEXDUMP_BUF_SIZE];
0166 int rs = rowsize, gs = groupsize;
0167 int ae, he, e, f, r;
0168 bool a;
0169
0170 total_tests++;
0171
0172 memset(buf, FILL_CHAR, sizeof(buf));
0173
0174 r = hex_dump_to_buffer(data_b, len, rs, gs, buf, buflen, ascii);
0175
0176
0177
0178
0179
0180 ae = rs * 2 + rs / gs + 1 + len ;
0181 he = (gs * 2 + 1 ) * len / gs - 1 ;
0182
0183 if (ascii)
0184 e = ae;
0185 else
0186 e = he;
0187
0188 f = min_t(int, e + 1, buflen);
0189 if (buflen) {
0190 test_hexdump_prepare_test(len, rs, gs, test, sizeof(test), ascii);
0191 test[f - 1] = '\0';
0192 }
0193 memset(test + f, FILL_CHAR, sizeof(test) - f);
0194
0195 a = r == e && !memcmp(test, buf, TEST_HEXDUMP_BUF_SIZE);
0196
0197 buf[sizeof(buf) - 1] = '\0';
0198
0199 if (!a) {
0200 pr_err("Len: %zu buflen: %zu strlen: %zu\n",
0201 len, buflen, strnlen(buf, sizeof(buf)));
0202 pr_err("Result: %d '%s'\n", r, buf);
0203 pr_err("Expect: %d '%s'\n", e, test);
0204 failed_tests++;
0205 }
0206 }
0207
0208 static void __init test_hexdump_overflow_set(size_t buflen, bool ascii)
0209 {
0210 unsigned int i = 0;
0211 int rs = (get_random_int() % 2 + 1) * 16;
0212
0213 do {
0214 int gs = 1 << i;
0215 size_t len = get_random_int() % rs + gs;
0216
0217 test_hexdump_overflow(buflen, rounddown(len, gs), rs, gs, ascii);
0218 } while (i++ < 3);
0219 }
0220
0221 static int __init test_hexdump_init(void)
0222 {
0223 unsigned int i;
0224 int rowsize;
0225
0226 rowsize = (get_random_int() % 2 + 1) * 16;
0227 for (i = 0; i < 16; i++)
0228 test_hexdump_set(rowsize, false);
0229
0230 rowsize = (get_random_int() % 2 + 1) * 16;
0231 for (i = 0; i < 16; i++)
0232 test_hexdump_set(rowsize, true);
0233
0234 for (i = 0; i <= TEST_HEXDUMP_BUF_SIZE; i++)
0235 test_hexdump_overflow_set(i, false);
0236
0237 for (i = 0; i <= TEST_HEXDUMP_BUF_SIZE; i++)
0238 test_hexdump_overflow_set(i, true);
0239
0240 if (failed_tests == 0)
0241 pr_info("all %u tests passed\n", total_tests);
0242 else
0243 pr_err("failed %u out of %u tests\n", failed_tests, total_tests);
0244
0245 return failed_tests ? -EINVAL : 0;
0246 }
0247 module_init(test_hexdump_init);
0248
0249 static void __exit test_hexdump_exit(void)
0250 {
0251
0252 }
0253 module_exit(test_hexdump_exit);
0254
0255 MODULE_AUTHOR("Andy Shevchenko <andriy.shevchenko@linux.intel.com>");
0256 MODULE_LICENSE("Dual BSD/GPL");