160b2e8f4SAndy Shevchenko /*
260b2e8f4SAndy Shevchenko * Test cases for lib/hexdump.c module.
360b2e8f4SAndy Shevchenko */
460b2e8f4SAndy Shevchenko #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
560b2e8f4SAndy Shevchenko
660b2e8f4SAndy Shevchenko #include <linux/init.h>
760b2e8f4SAndy Shevchenko #include <linux/kernel.h>
860b2e8f4SAndy Shevchenko #include <linux/module.h>
960b2e8f4SAndy Shevchenko #include <linux/random.h>
1060b2e8f4SAndy Shevchenko #include <linux/string.h>
1160b2e8f4SAndy Shevchenko
1260b2e8f4SAndy Shevchenko static const unsigned char data_b[] = {
1360b2e8f4SAndy Shevchenko '\xbe', '\x32', '\xdb', '\x7b', '\x0a', '\x18', '\x93', '\xb2', /* 00 - 07 */
1460b2e8f4SAndy Shevchenko '\x70', '\xba', '\xc4', '\x24', '\x7d', '\x83', '\x34', '\x9b', /* 08 - 0f */
1560b2e8f4SAndy Shevchenko '\xa6', '\x9c', '\x31', '\xad', '\x9c', '\x0f', '\xac', '\xe9', /* 10 - 17 */
1660b2e8f4SAndy Shevchenko '\x4c', '\xd1', '\x19', '\x99', '\x43', '\xb1', '\xaf', '\x0c', /* 18 - 1f */
1760b2e8f4SAndy Shevchenko };
1860b2e8f4SAndy Shevchenko
1960b2e8f4SAndy Shevchenko static const unsigned char data_a[] = ".2.{....p..$}.4...1.....L...C...";
2060b2e8f4SAndy Shevchenko
21de9df399SChristophe Leroy static const char * const test_data_1[] __initconst = {
2260b2e8f4SAndy Shevchenko "be", "32", "db", "7b", "0a", "18", "93", "b2",
2360b2e8f4SAndy Shevchenko "70", "ba", "c4", "24", "7d", "83", "34", "9b",
2460b2e8f4SAndy Shevchenko "a6", "9c", "31", "ad", "9c", "0f", "ac", "e9",
2560b2e8f4SAndy Shevchenko "4c", "d1", "19", "99", "43", "b1", "af", "0c",
2660b2e8f4SAndy Shevchenko };
2760b2e8f4SAndy Shevchenko
2860b2e8f4SAndy Shevchenko static const char * const test_data_2_le[] __initconst = {
2960b2e8f4SAndy Shevchenko "32be", "7bdb", "180a", "b293",
3060b2e8f4SAndy Shevchenko "ba70", "24c4", "837d", "9b34",
3160b2e8f4SAndy Shevchenko "9ca6", "ad31", "0f9c", "e9ac",
3260b2e8f4SAndy Shevchenko "d14c", "9919", "b143", "0caf",
3360b2e8f4SAndy Shevchenko };
3460b2e8f4SAndy Shevchenko
35de9df399SChristophe Leroy static const char * const test_data_2_be[] __initconst = {
36de9df399SChristophe Leroy "be32", "db7b", "0a18", "93b2",
37de9df399SChristophe Leroy "70ba", "c424", "7d83", "349b",
38de9df399SChristophe Leroy "a69c", "31ad", "9c0f", "ace9",
39de9df399SChristophe Leroy "4cd1", "1999", "43b1", "af0c",
40de9df399SChristophe Leroy };
41de9df399SChristophe Leroy
4260b2e8f4SAndy Shevchenko static const char * const test_data_4_le[] __initconst = {
4360b2e8f4SAndy Shevchenko "7bdb32be", "b293180a", "24c4ba70", "9b34837d",
4460b2e8f4SAndy Shevchenko "ad319ca6", "e9ac0f9c", "9919d14c", "0cafb143",
4560b2e8f4SAndy Shevchenko };
4660b2e8f4SAndy Shevchenko
47de9df399SChristophe Leroy static const char * const test_data_4_be[] __initconst = {
48de9df399SChristophe Leroy "be32db7b", "0a1893b2", "70bac424", "7d83349b",
49de9df399SChristophe Leroy "a69c31ad", "9c0face9", "4cd11999", "43b1af0c",
50de9df399SChristophe Leroy };
51de9df399SChristophe Leroy
5260b2e8f4SAndy Shevchenko static const char * const test_data_8_le[] __initconst = {
5360b2e8f4SAndy Shevchenko "b293180a7bdb32be", "9b34837d24c4ba70",
5460b2e8f4SAndy Shevchenko "e9ac0f9cad319ca6", "0cafb1439919d14c",
5560b2e8f4SAndy Shevchenko };
5660b2e8f4SAndy Shevchenko
57de9df399SChristophe Leroy static const char * const test_data_8_be[] __initconst = {
58de9df399SChristophe Leroy "be32db7b0a1893b2", "70bac4247d83349b",
59de9df399SChristophe Leroy "a69c31ad9c0face9", "4cd1199943b1af0c",
60de9df399SChristophe Leroy };
61de9df399SChristophe Leroy
623db4a987SAndy Shevchenko #define FILL_CHAR '#'
633db4a987SAndy Shevchenko
647aaf4c3eSAndy Shevchenko static unsigned total_tests __initdata;
657aaf4c3eSAndy Shevchenko static unsigned failed_tests __initdata;
667aaf4c3eSAndy Shevchenko
test_hexdump_prepare_test(size_t len,int rowsize,int groupsize,char * test,size_t testlen,bool ascii)6787977ca6SAndy Shevchenko static void __init test_hexdump_prepare_test(size_t len, int rowsize,
6887977ca6SAndy Shevchenko int groupsize, char *test,
6987977ca6SAndy Shevchenko size_t testlen, bool ascii)
7060b2e8f4SAndy Shevchenko {
7160b2e8f4SAndy Shevchenko char *p;
7260b2e8f4SAndy Shevchenko const char * const *result;
7360b2e8f4SAndy Shevchenko size_t l = len;
7460b2e8f4SAndy Shevchenko int gs = groupsize, rs = rowsize;
7560b2e8f4SAndy Shevchenko unsigned int i;
76de9df399SChristophe Leroy const bool is_be = IS_ENABLED(CONFIG_CPU_BIG_ENDIAN);
7760b2e8f4SAndy Shevchenko
7860b2e8f4SAndy Shevchenko if (rs != 16 && rs != 32)
7960b2e8f4SAndy Shevchenko rs = 16;
8060b2e8f4SAndy Shevchenko
8160b2e8f4SAndy Shevchenko if (l > rs)
8260b2e8f4SAndy Shevchenko l = rs;
8360b2e8f4SAndy Shevchenko
8460b2e8f4SAndy Shevchenko if (!is_power_of_2(gs) || gs > 8 || (len % gs != 0))
8560b2e8f4SAndy Shevchenko gs = 1;
8660b2e8f4SAndy Shevchenko
8760b2e8f4SAndy Shevchenko if (gs == 8)
88de9df399SChristophe Leroy result = is_be ? test_data_8_be : test_data_8_le;
8960b2e8f4SAndy Shevchenko else if (gs == 4)
90de9df399SChristophe Leroy result = is_be ? test_data_4_be : test_data_4_le;
9160b2e8f4SAndy Shevchenko else if (gs == 2)
92de9df399SChristophe Leroy result = is_be ? test_data_2_be : test_data_2_le;
9360b2e8f4SAndy Shevchenko else
94de9df399SChristophe Leroy result = test_data_1;
9560b2e8f4SAndy Shevchenko
9660b2e8f4SAndy Shevchenko /* hex dump */
9760b2e8f4SAndy Shevchenko p = test;
9860b2e8f4SAndy Shevchenko for (i = 0; i < l / gs; i++) {
9960b2e8f4SAndy Shevchenko const char *q = *result++;
10060b2e8f4SAndy Shevchenko size_t amount = strlen(q);
10160b2e8f4SAndy Shevchenko
102b1286ed7SLinus Torvalds memcpy(p, q, amount);
1033db4a987SAndy Shevchenko p += amount;
1043db4a987SAndy Shevchenko
1053db4a987SAndy Shevchenko *p++ = ' ';
10660b2e8f4SAndy Shevchenko }
10760b2e8f4SAndy Shevchenko if (i)
10860b2e8f4SAndy Shevchenko p--;
10960b2e8f4SAndy Shevchenko
11060b2e8f4SAndy Shevchenko /* ASCII part */
11160b2e8f4SAndy Shevchenko if (ascii) {
1123db4a987SAndy Shevchenko do {
1133db4a987SAndy Shevchenko *p++ = ' ';
1143db4a987SAndy Shevchenko } while (p < test + rs * 2 + rs / gs + 1);
1153db4a987SAndy Shevchenko
1163ef3a05bSArnd Bergmann memcpy(p, data_a, l);
11760b2e8f4SAndy Shevchenko p += l;
11860b2e8f4SAndy Shevchenko }
11960b2e8f4SAndy Shevchenko
12060b2e8f4SAndy Shevchenko *p = '\0';
12187977ca6SAndy Shevchenko }
12287977ca6SAndy Shevchenko
12387977ca6SAndy Shevchenko #define TEST_HEXDUMP_BUF_SIZE (32 * 3 + 2 + 32 + 1)
12487977ca6SAndy Shevchenko
test_hexdump(size_t len,int rowsize,int groupsize,bool ascii)12587977ca6SAndy Shevchenko static void __init test_hexdump(size_t len, int rowsize, int groupsize,
12687977ca6SAndy Shevchenko bool ascii)
12787977ca6SAndy Shevchenko {
12887977ca6SAndy Shevchenko char test[TEST_HEXDUMP_BUF_SIZE];
12987977ca6SAndy Shevchenko char real[TEST_HEXDUMP_BUF_SIZE];
13087977ca6SAndy Shevchenko
1317aaf4c3eSAndy Shevchenko total_tests++;
1327aaf4c3eSAndy Shevchenko
1337047d813SAndy Shevchenko memset(real, FILL_CHAR, sizeof(real));
13487977ca6SAndy Shevchenko hex_dump_to_buffer(data_b, len, rowsize, groupsize, real, sizeof(real),
13587977ca6SAndy Shevchenko ascii);
13687977ca6SAndy Shevchenko
1377047d813SAndy Shevchenko memset(test, FILL_CHAR, sizeof(test));
13887977ca6SAndy Shevchenko test_hexdump_prepare_test(len, rowsize, groupsize, test, sizeof(test),
13987977ca6SAndy Shevchenko ascii);
14060b2e8f4SAndy Shevchenko
1417047d813SAndy Shevchenko if (memcmp(test, real, TEST_HEXDUMP_BUF_SIZE)) {
14260b2e8f4SAndy Shevchenko pr_err("Len: %zu row: %d group: %d\n", len, rowsize, groupsize);
14360b2e8f4SAndy Shevchenko pr_err("Result: '%s'\n", real);
14460b2e8f4SAndy Shevchenko pr_err("Expect: '%s'\n", test);
1457aaf4c3eSAndy Shevchenko failed_tests++;
14660b2e8f4SAndy Shevchenko }
14760b2e8f4SAndy Shevchenko }
14860b2e8f4SAndy Shevchenko
test_hexdump_set(int rowsize,bool ascii)14960b2e8f4SAndy Shevchenko static void __init test_hexdump_set(int rowsize, bool ascii)
15060b2e8f4SAndy Shevchenko {
15160b2e8f4SAndy Shevchenko size_t d = min_t(size_t, sizeof(data_b), rowsize);
152e8a533cbSJason A. Donenfeld size_t len = get_random_u32_inclusive(1, d);
15360b2e8f4SAndy Shevchenko
15460b2e8f4SAndy Shevchenko test_hexdump(len, rowsize, 4, ascii);
15560b2e8f4SAndy Shevchenko test_hexdump(len, rowsize, 2, ascii);
15660b2e8f4SAndy Shevchenko test_hexdump(len, rowsize, 8, ascii);
15760b2e8f4SAndy Shevchenko test_hexdump(len, rowsize, 1, ascii);
15860b2e8f4SAndy Shevchenko }
15960b2e8f4SAndy Shevchenko
test_hexdump_overflow(size_t buflen,size_t len,int rowsize,int groupsize,bool ascii)1601dacd9ddSAndy Shevchenko static void __init test_hexdump_overflow(size_t buflen, size_t len,
1611dacd9ddSAndy Shevchenko int rowsize, int groupsize,
1621dacd9ddSAndy Shevchenko bool ascii)
16360b2e8f4SAndy Shevchenko {
164cc77a719SAndy Shevchenko char test[TEST_HEXDUMP_BUF_SIZE];
165a3d601fcSAndy Shevchenko char buf[TEST_HEXDUMP_BUF_SIZE];
166cc77a719SAndy Shevchenko int rs = rowsize, gs = groupsize;
167cc77a719SAndy Shevchenko int ae, he, e, f, r;
16860b2e8f4SAndy Shevchenko bool a;
16960b2e8f4SAndy Shevchenko
1707aaf4c3eSAndy Shevchenko total_tests++;
1717aaf4c3eSAndy Shevchenko
1723db4a987SAndy Shevchenko memset(buf, FILL_CHAR, sizeof(buf));
17360b2e8f4SAndy Shevchenko
174ad27a755SAndy Shevchenko r = hex_dump_to_buffer(data_b, len, rs, gs, buf, buflen, ascii);
175ad27a755SAndy Shevchenko
176ad27a755SAndy Shevchenko /*
177ad27a755SAndy Shevchenko * Caller must provide the data length multiple of groupsize. The
178ad27a755SAndy Shevchenko * calculations below are made with that assumption in mind.
179ad27a755SAndy Shevchenko */
180ad27a755SAndy Shevchenko ae = rs * 2 /* hex */ + rs / gs /* spaces */ + 1 /* space */ + len /* ascii */;
181ad27a755SAndy Shevchenko he = (gs * 2 /* hex */ + 1 /* space */) * len / gs - 1 /* no trailing space */;
18260b2e8f4SAndy Shevchenko
18360b2e8f4SAndy Shevchenko if (ascii)
184ad27a755SAndy Shevchenko e = ae;
18560b2e8f4SAndy Shevchenko else
186ad27a755SAndy Shevchenko e = he;
18760b2e8f4SAndy Shevchenko
188cc77a719SAndy Shevchenko f = min_t(int, e + 1, buflen);
189cc77a719SAndy Shevchenko if (buflen) {
190cc77a719SAndy Shevchenko test_hexdump_prepare_test(len, rs, gs, test, sizeof(test), ascii);
191cc77a719SAndy Shevchenko test[f - 1] = '\0';
19260b2e8f4SAndy Shevchenko }
193cc77a719SAndy Shevchenko memset(test + f, FILL_CHAR, sizeof(test) - f);
194cc77a719SAndy Shevchenko
195cc77a719SAndy Shevchenko a = r == e && !memcmp(test, buf, TEST_HEXDUMP_BUF_SIZE);
196cc77a719SAndy Shevchenko
197cc77a719SAndy Shevchenko buf[sizeof(buf) - 1] = '\0';
19860b2e8f4SAndy Shevchenko
19960b2e8f4SAndy Shevchenko if (!a) {
200cc77a719SAndy Shevchenko pr_err("Len: %zu buflen: %zu strlen: %zu\n",
201cc77a719SAndy Shevchenko len, buflen, strnlen(buf, sizeof(buf)));
202cc77a719SAndy Shevchenko pr_err("Result: %d '%s'\n", r, buf);
203cc77a719SAndy Shevchenko pr_err("Expect: %d '%s'\n", e, test);
2047aaf4c3eSAndy Shevchenko failed_tests++;
20560b2e8f4SAndy Shevchenko }
20660b2e8f4SAndy Shevchenko }
20760b2e8f4SAndy Shevchenko
test_hexdump_overflow_set(size_t buflen,bool ascii)2081dacd9ddSAndy Shevchenko static void __init test_hexdump_overflow_set(size_t buflen, bool ascii)
2091dacd9ddSAndy Shevchenko {
2101dacd9ddSAndy Shevchenko unsigned int i = 0;
211e8a533cbSJason A. Donenfeld int rs = get_random_u32_inclusive(1, 2) * 16;
2121dacd9ddSAndy Shevchenko
2131dacd9ddSAndy Shevchenko do {
2141dacd9ddSAndy Shevchenko int gs = 1 << i;
2158032bf12SJason A. Donenfeld size_t len = get_random_u32_below(rs) + gs;
2161dacd9ddSAndy Shevchenko
2171dacd9ddSAndy Shevchenko test_hexdump_overflow(buflen, rounddown(len, gs), rs, gs, ascii);
2181dacd9ddSAndy Shevchenko } while (i++ < 3);
2191dacd9ddSAndy Shevchenko }
2201dacd9ddSAndy Shevchenko
test_hexdump_init(void)22160b2e8f4SAndy Shevchenko static int __init test_hexdump_init(void)
22260b2e8f4SAndy Shevchenko {
22360b2e8f4SAndy Shevchenko unsigned int i;
22460b2e8f4SAndy Shevchenko int rowsize;
22560b2e8f4SAndy Shevchenko
226e8a533cbSJason A. Donenfeld rowsize = get_random_u32_inclusive(1, 2) * 16;
22760b2e8f4SAndy Shevchenko for (i = 0; i < 16; i++)
22860b2e8f4SAndy Shevchenko test_hexdump_set(rowsize, false);
22960b2e8f4SAndy Shevchenko
230e8a533cbSJason A. Donenfeld rowsize = get_random_u32_inclusive(1, 2) * 16;
23160b2e8f4SAndy Shevchenko for (i = 0; i < 16; i++)
23260b2e8f4SAndy Shevchenko test_hexdump_set(rowsize, true);
23360b2e8f4SAndy Shevchenko
234a3d601fcSAndy Shevchenko for (i = 0; i <= TEST_HEXDUMP_BUF_SIZE; i++)
2351dacd9ddSAndy Shevchenko test_hexdump_overflow_set(i, false);
23660b2e8f4SAndy Shevchenko
237a3d601fcSAndy Shevchenko for (i = 0; i <= TEST_HEXDUMP_BUF_SIZE; i++)
2381dacd9ddSAndy Shevchenko test_hexdump_overflow_set(i, true);
23960b2e8f4SAndy Shevchenko
2407aaf4c3eSAndy Shevchenko if (failed_tests == 0)
2417aaf4c3eSAndy Shevchenko pr_info("all %u tests passed\n", total_tests);
2427aaf4c3eSAndy Shevchenko else
2437aaf4c3eSAndy Shevchenko pr_err("failed %u out of %u tests\n", failed_tests, total_tests);
2447aaf4c3eSAndy Shevchenko
2457aaf4c3eSAndy Shevchenko return failed_tests ? -EINVAL : 0;
24660b2e8f4SAndy Shevchenko }
24760b2e8f4SAndy Shevchenko module_init(test_hexdump_init);
2487aaf4c3eSAndy Shevchenko
test_hexdump_exit(void)2497aaf4c3eSAndy Shevchenko static void __exit test_hexdump_exit(void)
2507aaf4c3eSAndy Shevchenko {
2517aaf4c3eSAndy Shevchenko /* do nothing */
2527aaf4c3eSAndy Shevchenko }
2537aaf4c3eSAndy Shevchenko module_exit(test_hexdump_exit);
2547aaf4c3eSAndy Shevchenko
2557aaf4c3eSAndy Shevchenko MODULE_AUTHOR("Andy Shevchenko <andriy.shevchenko@linux.intel.com>");
256*30347491SJeff Johnson MODULE_DESCRIPTION("Test cases for lib/hexdump.c module");
25760b2e8f4SAndy Shevchenko MODULE_LICENSE("Dual BSD/GPL");
258