xref: /openbmc/linux/lib/test_hexdump.c (revision e8a533cb)
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 
11660b2e8f4SAndy Shevchenko 		strncpy(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);
152*e8a533cbSJason 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;
211*e8a533cbSJason 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 
226*e8a533cbSJason 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 
230*e8a533cbSJason 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>");
25660b2e8f4SAndy Shevchenko MODULE_LICENSE("Dual BSD/GPL");
257