blob: 11d45f510d6c18440909229fe8c1a6d6bd86cebc [file] [log] [blame]
Andy Shevchenko64d1d772015-02-12 15:02:21 -08001/*
2 * Test cases for lib/hexdump.c module.
3 */
4#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
5
6#include <linux/init.h>
7#include <linux/kernel.h>
8#include <linux/module.h>
9#include <linux/random.h>
10#include <linux/string.h>
11
12static const unsigned char data_b[] = {
13 '\xbe', '\x32', '\xdb', '\x7b', '\x0a', '\x18', '\x93', '\xb2', /* 00 - 07 */
14 '\x70', '\xba', '\xc4', '\x24', '\x7d', '\x83', '\x34', '\x9b', /* 08 - 0f */
15 '\xa6', '\x9c', '\x31', '\xad', '\x9c', '\x0f', '\xac', '\xe9', /* 10 - 17 */
16 '\x4c', '\xd1', '\x19', '\x99', '\x43', '\xb1', '\xaf', '\x0c', /* 18 - 1f */
17};
18
19static const unsigned char data_a[] = ".2.{....p..$}.4...1.....L...C...";
20
Andi Kleenc79574a2015-04-15 16:16:39 -070021static const char * const test_data_1_le[] __initconst = {
Andy Shevchenko64d1d772015-02-12 15:02:21 -080022 "be", "32", "db", "7b", "0a", "18", "93", "b2",
23 "70", "ba", "c4", "24", "7d", "83", "34", "9b",
24 "a6", "9c", "31", "ad", "9c", "0f", "ac", "e9",
25 "4c", "d1", "19", "99", "43", "b1", "af", "0c",
26};
27
Geert Uytterhoeven79e23d52015-06-25 15:02:11 -070028static const char * const test_data_2_le[] __initconst = {
Andy Shevchenko64d1d772015-02-12 15:02:21 -080029 "32be", "7bdb", "180a", "b293",
30 "ba70", "24c4", "837d", "9b34",
31 "9ca6", "ad31", "0f9c", "e9ac",
32 "d14c", "9919", "b143", "0caf",
33};
34
Geert Uytterhoeven79e23d52015-06-25 15:02:11 -070035static const char * const test_data_4_le[] __initconst = {
Andy Shevchenko64d1d772015-02-12 15:02:21 -080036 "7bdb32be", "b293180a", "24c4ba70", "9b34837d",
37 "ad319ca6", "e9ac0f9c", "9919d14c", "0cafb143",
38};
39
Geert Uytterhoeven79e23d52015-06-25 15:02:11 -070040static const char * const test_data_8_le[] __initconst = {
Andy Shevchenko64d1d772015-02-12 15:02:21 -080041 "b293180a7bdb32be", "9b34837d24c4ba70",
42 "e9ac0f9cad319ca6", "0cafb1439919d14c",
43};
44
Andy Shevchenko3db4a982016-01-20 14:58:50 -080045#define FILL_CHAR '#'
46
Andy Shevchenko87977ca6b2016-01-20 14:58:47 -080047static void __init test_hexdump_prepare_test(size_t len, int rowsize,
48 int groupsize, char *test,
49 size_t testlen, bool ascii)
Andy Shevchenko64d1d772015-02-12 15:02:21 -080050{
Andy Shevchenko64d1d772015-02-12 15:02:21 -080051 char *p;
Linus Torvalds17974c052015-04-19 13:48:40 -070052 const char * const *result;
Andy Shevchenko64d1d772015-02-12 15:02:21 -080053 size_t l = len;
54 int gs = groupsize, rs = rowsize;
55 unsigned int i;
56
Andy Shevchenko64d1d772015-02-12 15:02:21 -080057 if (rs != 16 && rs != 32)
58 rs = 16;
59
60 if (l > rs)
61 l = rs;
62
63 if (!is_power_of_2(gs) || gs > 8 || (len % gs != 0))
64 gs = 1;
65
66 if (gs == 8)
67 result = test_data_8_le;
68 else if (gs == 4)
69 result = test_data_4_le;
70 else if (gs == 2)
71 result = test_data_2_le;
72 else
73 result = test_data_1_le;
74
Andy Shevchenko64d1d772015-02-12 15:02:21 -080075 /* hex dump */
76 p = test;
77 for (i = 0; i < l / gs; i++) {
78 const char *q = *result++;
79 size_t amount = strlen(q);
80
81 strncpy(p, q, amount);
Andy Shevchenko3db4a982016-01-20 14:58:50 -080082 p += amount;
83
84 *p++ = ' ';
Andy Shevchenko64d1d772015-02-12 15:02:21 -080085 }
86 if (i)
87 p--;
88
89 /* ASCII part */
90 if (ascii) {
Andy Shevchenko3db4a982016-01-20 14:58:50 -080091 do {
92 *p++ = ' ';
93 } while (p < test + rs * 2 + rs / gs + 1);
94
Andy Shevchenko64d1d772015-02-12 15:02:21 -080095 strncpy(p, data_a, l);
96 p += l;
97 }
98
99 *p = '\0';
Andy Shevchenko87977ca6b2016-01-20 14:58:47 -0800100}
101
102#define TEST_HEXDUMP_BUF_SIZE (32 * 3 + 2 + 32 + 1)
103
104static void __init test_hexdump(size_t len, int rowsize, int groupsize,
105 bool ascii)
106{
107 char test[TEST_HEXDUMP_BUF_SIZE];
108 char real[TEST_HEXDUMP_BUF_SIZE];
109
Andy Shevchenko7047d812016-01-20 14:58:58 -0800110 memset(real, FILL_CHAR, sizeof(real));
Andy Shevchenko87977ca6b2016-01-20 14:58:47 -0800111 hex_dump_to_buffer(data_b, len, rowsize, groupsize, real, sizeof(real),
112 ascii);
113
Andy Shevchenko7047d812016-01-20 14:58:58 -0800114 memset(test, FILL_CHAR, sizeof(test));
Andy Shevchenko87977ca6b2016-01-20 14:58:47 -0800115 test_hexdump_prepare_test(len, rowsize, groupsize, test, sizeof(test),
116 ascii);
Andy Shevchenko64d1d772015-02-12 15:02:21 -0800117
Andy Shevchenko7047d812016-01-20 14:58:58 -0800118 if (memcmp(test, real, TEST_HEXDUMP_BUF_SIZE)) {
Andy Shevchenko64d1d772015-02-12 15:02:21 -0800119 pr_err("Len: %zu row: %d group: %d\n", len, rowsize, groupsize);
120 pr_err("Result: '%s'\n", real);
121 pr_err("Expect: '%s'\n", test);
122 }
123}
124
125static void __init test_hexdump_set(int rowsize, bool ascii)
126{
127 size_t d = min_t(size_t, sizeof(data_b), rowsize);
128 size_t len = get_random_int() % d + 1;
129
130 test_hexdump(len, rowsize, 4, ascii);
131 test_hexdump(len, rowsize, 2, ascii);
132 test_hexdump(len, rowsize, 8, ascii);
133 test_hexdump(len, rowsize, 1, ascii);
134}
135
Andy Shevchenko1dacd9d2016-01-20 14:59:04 -0800136static void __init test_hexdump_overflow(size_t buflen, size_t len,
137 int rowsize, int groupsize,
138 bool ascii)
Andy Shevchenko114fc1a2015-02-12 15:02:29 -0800139{
Andy Shevchenkocc77a712016-01-20 14:59:01 -0800140 char test[TEST_HEXDUMP_BUF_SIZE];
Andy Shevchenkoa3d601f2016-01-20 14:58:53 -0800141 char buf[TEST_HEXDUMP_BUF_SIZE];
Andy Shevchenkocc77a712016-01-20 14:59:01 -0800142 int rs = rowsize, gs = groupsize;
143 int ae, he, e, f, r;
Andy Shevchenko114fc1a2015-02-12 15:02:29 -0800144 bool a;
Andy Shevchenko114fc1a2015-02-12 15:02:29 -0800145
Andy Shevchenko3db4a982016-01-20 14:58:50 -0800146 memset(buf, FILL_CHAR, sizeof(buf));
Andy Shevchenko114fc1a2015-02-12 15:02:29 -0800147
Andy Shevchenkoad27a752016-01-20 14:58:56 -0800148 r = hex_dump_to_buffer(data_b, len, rs, gs, buf, buflen, ascii);
149
150 /*
151 * Caller must provide the data length multiple of groupsize. The
152 * calculations below are made with that assumption in mind.
153 */
154 ae = rs * 2 /* hex */ + rs / gs /* spaces */ + 1 /* space */ + len /* ascii */;
155 he = (gs * 2 /* hex */ + 1 /* space */) * len / gs - 1 /* no trailing space */;
Andy Shevchenko114fc1a2015-02-12 15:02:29 -0800156
157 if (ascii)
Andy Shevchenkoad27a752016-01-20 14:58:56 -0800158 e = ae;
Andy Shevchenko114fc1a2015-02-12 15:02:29 -0800159 else
Andy Shevchenkoad27a752016-01-20 14:58:56 -0800160 e = he;
Andy Shevchenko114fc1a2015-02-12 15:02:29 -0800161
Andy Shevchenkocc77a712016-01-20 14:59:01 -0800162 f = min_t(int, e + 1, buflen);
163 if (buflen) {
164 test_hexdump_prepare_test(len, rs, gs, test, sizeof(test), ascii);
165 test[f - 1] = '\0';
Andy Shevchenko114fc1a2015-02-12 15:02:29 -0800166 }
Andy Shevchenkocc77a712016-01-20 14:59:01 -0800167 memset(test + f, FILL_CHAR, sizeof(test) - f);
168
169 a = r == e && !memcmp(test, buf, TEST_HEXDUMP_BUF_SIZE);
170
171 buf[sizeof(buf) - 1] = '\0';
Andy Shevchenko114fc1a2015-02-12 15:02:29 -0800172
173 if (!a) {
Andy Shevchenkocc77a712016-01-20 14:59:01 -0800174 pr_err("Len: %zu buflen: %zu strlen: %zu\n",
175 len, buflen, strnlen(buf, sizeof(buf)));
176 pr_err("Result: %d '%s'\n", r, buf);
177 pr_err("Expect: %d '%s'\n", e, test);
Andy Shevchenko114fc1a2015-02-12 15:02:29 -0800178 }
179}
180
Andy Shevchenko1dacd9d2016-01-20 14:59:04 -0800181static void __init test_hexdump_overflow_set(size_t buflen, bool ascii)
182{
183 unsigned int i = 0;
184 int rs = (get_random_int() % 2 + 1) * 16;
185
186 do {
187 int gs = 1 << i;
188 size_t len = get_random_int() % rs + gs;
189
190 test_hexdump_overflow(buflen, rounddown(len, gs), rs, gs, ascii);
191 } while (i++ < 3);
192}
193
Andy Shevchenko64d1d772015-02-12 15:02:21 -0800194static int __init test_hexdump_init(void)
195{
196 unsigned int i;
197 int rowsize;
198
199 pr_info("Running tests...\n");
200
201 rowsize = (get_random_int() % 2 + 1) * 16;
202 for (i = 0; i < 16; i++)
203 test_hexdump_set(rowsize, false);
204
205 rowsize = (get_random_int() % 2 + 1) * 16;
206 for (i = 0; i < 16; i++)
207 test_hexdump_set(rowsize, true);
208
Andy Shevchenkoa3d601f2016-01-20 14:58:53 -0800209 for (i = 0; i <= TEST_HEXDUMP_BUF_SIZE; i++)
Andy Shevchenko1dacd9d2016-01-20 14:59:04 -0800210 test_hexdump_overflow_set(i, false);
Andy Shevchenko114fc1a2015-02-12 15:02:29 -0800211
Andy Shevchenkoa3d601f2016-01-20 14:58:53 -0800212 for (i = 0; i <= TEST_HEXDUMP_BUF_SIZE; i++)
Andy Shevchenko1dacd9d2016-01-20 14:59:04 -0800213 test_hexdump_overflow_set(i, true);
Andy Shevchenko114fc1a2015-02-12 15:02:29 -0800214
Andy Shevchenko64d1d772015-02-12 15:02:21 -0800215 return -EINVAL;
216}
217module_init(test_hexdump_init);
218MODULE_LICENSE("Dual BSD/GPL");