1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Test cases for printf facility. |
4 | */ |
5 | |
6 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
7 | |
8 | #include <linux/init.h> |
9 | #include <linux/kernel.h> |
10 | #include <linux/module.h> |
11 | #include <linux/printk.h> |
12 | #include <linux/random.h> |
13 | #include <linux/rtc.h> |
14 | #include <linux/slab.h> |
15 | #include <linux/sprintf.h> |
16 | #include <linux/string.h> |
17 | |
18 | #include <linux/bitmap.h> |
19 | #include <linux/dcache.h> |
20 | #include <linux/socket.h> |
21 | #include <linux/in.h> |
22 | |
23 | #include <linux/gfp.h> |
24 | #include <linux/mm.h> |
25 | |
26 | #include <linux/property.h> |
27 | |
28 | #include "../tools/testing/selftests/kselftest_module.h" |
29 | |
30 | #define BUF_SIZE 256 |
31 | #define PAD_SIZE 16 |
32 | #define FILL_CHAR '$' |
33 | |
34 | #define NOWARN(option, comment, block) \ |
35 | __diag_push(); \ |
36 | __diag_ignore_all(#option, comment); \ |
37 | block \ |
38 | __diag_pop(); |
39 | |
40 | KSTM_MODULE_GLOBALS(); |
41 | |
42 | static char *test_buffer __initdata; |
43 | static char *alloced_buffer __initdata; |
44 | |
45 | static int __printf(4, 0) __init |
46 | do_test(int bufsize, const char *expect, int elen, |
47 | const char *fmt, va_list ap) |
48 | { |
49 | va_list aq; |
50 | int ret, written; |
51 | |
52 | total_tests++; |
53 | |
54 | memset(alloced_buffer, FILL_CHAR, BUF_SIZE + 2*PAD_SIZE); |
55 | va_copy(aq, ap); |
56 | ret = vsnprintf(buf: test_buffer, size: bufsize, fmt, args: aq); |
57 | va_end(aq); |
58 | |
59 | if (ret != elen) { |
60 | pr_warn("vsnprintf(buf, %d, \"%s\", ...) returned %d, expected %d\n" , |
61 | bufsize, fmt, ret, elen); |
62 | return 1; |
63 | } |
64 | |
65 | if (memchr_inv(p: alloced_buffer, FILL_CHAR, PAD_SIZE)) { |
66 | pr_warn("vsnprintf(buf, %d, \"%s\", ...) wrote before buffer\n" , bufsize, fmt); |
67 | return 1; |
68 | } |
69 | |
70 | if (!bufsize) { |
71 | if (memchr_inv(p: test_buffer, FILL_CHAR, BUF_SIZE + PAD_SIZE)) { |
72 | pr_warn("vsnprintf(buf, 0, \"%s\", ...) wrote to buffer\n" , |
73 | fmt); |
74 | return 1; |
75 | } |
76 | return 0; |
77 | } |
78 | |
79 | written = min(bufsize-1, elen); |
80 | if (test_buffer[written]) { |
81 | pr_warn("vsnprintf(buf, %d, \"%s\", ...) did not nul-terminate buffer\n" , |
82 | bufsize, fmt); |
83 | return 1; |
84 | } |
85 | |
86 | if (memchr_inv(p: test_buffer + written + 1, FILL_CHAR, size: bufsize - (written + 1))) { |
87 | pr_warn("vsnprintf(buf, %d, \"%s\", ...) wrote beyond the nul-terminator\n" , |
88 | bufsize, fmt); |
89 | return 1; |
90 | } |
91 | |
92 | if (memchr_inv(p: test_buffer + bufsize, FILL_CHAR, BUF_SIZE + PAD_SIZE - bufsize)) { |
93 | pr_warn("vsnprintf(buf, %d, \"%s\", ...) wrote beyond buffer\n" , bufsize, fmt); |
94 | return 1; |
95 | } |
96 | |
97 | if (memcmp(p: test_buffer, q: expect, size: written)) { |
98 | pr_warn("vsnprintf(buf, %d, \"%s\", ...) wrote '%s', expected '%.*s'\n" , |
99 | bufsize, fmt, test_buffer, written, expect); |
100 | return 1; |
101 | } |
102 | return 0; |
103 | } |
104 | |
105 | static void __printf(3, 4) __init |
106 | __test(const char *expect, int elen, const char *fmt, ...) |
107 | { |
108 | va_list ap; |
109 | int rand; |
110 | char *p; |
111 | |
112 | if (elen >= BUF_SIZE) { |
113 | pr_err("error in test suite: expected output length %d too long. Format was '%s'.\n" , |
114 | elen, fmt); |
115 | failed_tests++; |
116 | return; |
117 | } |
118 | |
119 | va_start(ap, fmt); |
120 | |
121 | /* |
122 | * Every fmt+args is subjected to four tests: Three where we |
123 | * tell vsnprintf varying buffer sizes (plenty, not quite |
124 | * enough and 0), and then we also test that kvasprintf would |
125 | * be able to print it as expected. |
126 | */ |
127 | failed_tests += do_test(BUF_SIZE, expect, elen, fmt, ap); |
128 | rand = get_random_u32_inclusive(floor: 1, ceil: elen + 1); |
129 | /* Since elen < BUF_SIZE, we have 1 <= rand <= BUF_SIZE. */ |
130 | failed_tests += do_test(bufsize: rand, expect, elen, fmt, ap); |
131 | failed_tests += do_test(bufsize: 0, expect, elen, fmt, ap); |
132 | |
133 | p = kvasprintf(GFP_KERNEL, fmt, args: ap); |
134 | if (p) { |
135 | total_tests++; |
136 | if (memcmp(p, q: expect, size: elen+1)) { |
137 | pr_warn("kvasprintf(..., \"%s\", ...) returned '%s', expected '%s'\n" , |
138 | fmt, p, expect); |
139 | failed_tests++; |
140 | } |
141 | kfree(objp: p); |
142 | } |
143 | va_end(ap); |
144 | } |
145 | |
146 | #define test(expect, fmt, ...) \ |
147 | __test(expect, strlen(expect), fmt, ##__VA_ARGS__) |
148 | |
149 | static void __init |
150 | test_basic(void) |
151 | { |
152 | /* Work around annoying "warning: zero-length gnu_printf format string". */ |
153 | char nul = '\0'; |
154 | |
155 | test("" , &nul); |
156 | test("100%" , "100%%" ); |
157 | test("xxx%yyy" , "xxx%cyyy" , '%'); |
158 | __test(expect: "xxx\0yyy" , elen: 7, fmt: "xxx%cyyy" , '\0'); |
159 | } |
160 | |
161 | static void __init |
162 | test_number(void) |
163 | { |
164 | test("0x1234abcd " , "%#-12x" , 0x1234abcd); |
165 | test(" 0x1234abcd" , "%#12x" , 0x1234abcd); |
166 | test("0|001| 12|+123| 1234|-123|-1234" , "%d|%03d|%3d|%+d|% d|%+d|% d" , 0, 1, 12, 123, 1234, -123, -1234); |
167 | NOWARN(-Wformat, "Intentionally test narrowing conversion specifiers." , { |
168 | test("0|1|1|128|255" , "%hhu|%hhu|%hhu|%hhu|%hhu" , 0, 1, 257, 128, -1); |
169 | test("0|1|1|-128|-1" , "%hhd|%hhd|%hhd|%hhd|%hhd" , 0, 1, 257, 128, -1); |
170 | test("2015122420151225" , "%ho%ho%#ho" , 1037, 5282, -11627); |
171 | }) |
172 | /* |
173 | * POSIX/C99: »The result of converting zero with an explicit |
174 | * precision of zero shall be no characters.« Hence the output |
175 | * from the below test should really be "00|0||| ". However, |
176 | * the kernel's printf also produces a single 0 in that |
177 | * case. This test case simply documents the current |
178 | * behaviour. |
179 | */ |
180 | test("00|0|0|0|0" , "%.2d|%.1d|%.0d|%.*d|%1.0d" , 0, 0, 0, 0, 0, 0); |
181 | } |
182 | |
183 | static void __init |
184 | test_string(void) |
185 | { |
186 | test("" , "%s%.0s" , "" , "123" ); |
187 | test("ABCD|abc|123" , "%s|%.3s|%.*s" , "ABCD" , "abcdef" , 3, "123456" ); |
188 | test("1 | 2|3 | 4|5 " , "%-3s|%3s|%-*s|%*s|%*s" , "1" , "2" , 3, "3" , 3, "4" , -3, "5" ); |
189 | test("1234 " , "%-10.4s" , "123456" ); |
190 | test(" 1234" , "%10.4s" , "123456" ); |
191 | /* |
192 | * POSIX and C99 say that a negative precision (which is only |
193 | * possible to pass via a * argument) should be treated as if |
194 | * the precision wasn't present, and that if the precision is |
195 | * omitted (as in %.s), the precision should be taken to be |
196 | * 0. However, the kernel's printf behave exactly opposite, |
197 | * treating a negative precision as 0 and treating an omitted |
198 | * precision specifier as if no precision was given. |
199 | * |
200 | * These test cases document the current behaviour; should |
201 | * anyone ever feel the need to follow the standards more |
202 | * closely, this can be revisited. |
203 | */ |
204 | test(" " , "%4.*s" , -5, "123456" ); |
205 | test("123456" , "%.s" , "123456" ); |
206 | test("a||" , "%.s|%.0s|%.*s" , "a" , "b" , 0, "c" ); |
207 | test("a | | " , "%-3.s|%-3.0s|%-3.*s" , "a" , "b" , 0, "c" ); |
208 | } |
209 | |
210 | #define PLAIN_BUF_SIZE 64 /* leave some space so we don't oops */ |
211 | |
212 | #if BITS_PER_LONG == 64 |
213 | |
214 | #define PTR_WIDTH 16 |
215 | #define PTR ((void *)0xffff0123456789abUL) |
216 | #define PTR_STR "ffff0123456789ab" |
217 | #define PTR_VAL_NO_CRNG "(____ptrval____)" |
218 | #define ZEROS "00000000" /* hex 32 zero bits */ |
219 | #define ONES "ffffffff" /* hex 32 one bits */ |
220 | |
221 | static int __init |
222 | plain_format(void) |
223 | { |
224 | char buf[PLAIN_BUF_SIZE]; |
225 | int nchars; |
226 | |
227 | nchars = snprintf(buf, PLAIN_BUF_SIZE, fmt: "%p" , PTR); |
228 | |
229 | if (nchars != PTR_WIDTH) |
230 | return -1; |
231 | |
232 | if (strncmp(buf, PTR_VAL_NO_CRNG, PTR_WIDTH) == 0) { |
233 | pr_warn("crng possibly not yet initialized. plain 'p' buffer contains \"%s\"" , |
234 | PTR_VAL_NO_CRNG); |
235 | return 0; |
236 | } |
237 | |
238 | if (strncmp(buf, ZEROS, strlen(ZEROS)) != 0) |
239 | return -1; |
240 | |
241 | return 0; |
242 | } |
243 | |
244 | #else |
245 | |
246 | #define PTR_WIDTH 8 |
247 | #define PTR ((void *)0x456789ab) |
248 | #define PTR_STR "456789ab" |
249 | #define PTR_VAL_NO_CRNG "(ptrval)" |
250 | #define ZEROS "" |
251 | #define ONES "" |
252 | |
253 | static int __init |
254 | plain_format(void) |
255 | { |
256 | /* Format is implicitly tested for 32 bit machines by plain_hash() */ |
257 | return 0; |
258 | } |
259 | |
260 | #endif /* BITS_PER_LONG == 64 */ |
261 | |
262 | static int __init |
263 | plain_hash_to_buffer(const void *p, char *buf, size_t len) |
264 | { |
265 | int nchars; |
266 | |
267 | nchars = snprintf(buf, size: len, fmt: "%p" , p); |
268 | |
269 | if (nchars != PTR_WIDTH) |
270 | return -1; |
271 | |
272 | if (strncmp(buf, PTR_VAL_NO_CRNG, PTR_WIDTH) == 0) { |
273 | pr_warn("crng possibly not yet initialized. plain 'p' buffer contains \"%s\"" , |
274 | PTR_VAL_NO_CRNG); |
275 | return 0; |
276 | } |
277 | |
278 | return 0; |
279 | } |
280 | |
281 | static int __init |
282 | plain_hash(void) |
283 | { |
284 | char buf[PLAIN_BUF_SIZE]; |
285 | int ret; |
286 | |
287 | ret = plain_hash_to_buffer(PTR, buf, PLAIN_BUF_SIZE); |
288 | if (ret) |
289 | return ret; |
290 | |
291 | if (strncmp(buf, PTR_STR, PTR_WIDTH) == 0) |
292 | return -1; |
293 | |
294 | return 0; |
295 | } |
296 | |
297 | /* |
298 | * We can't use test() to test %p because we don't know what output to expect |
299 | * after an address is hashed. |
300 | */ |
301 | static void __init |
302 | plain(void) |
303 | { |
304 | int err; |
305 | |
306 | if (no_hash_pointers) { |
307 | pr_warn("skipping plain 'p' tests" ); |
308 | skipped_tests += 2; |
309 | return; |
310 | } |
311 | |
312 | err = plain_hash(); |
313 | if (err) { |
314 | pr_warn("plain 'p' does not appear to be hashed\n" ); |
315 | failed_tests++; |
316 | return; |
317 | } |
318 | |
319 | err = plain_format(); |
320 | if (err) { |
321 | pr_warn("hashing plain 'p' has unexpected format\n" ); |
322 | failed_tests++; |
323 | } |
324 | } |
325 | |
326 | static void __init |
327 | test_hashed(const char *fmt, const void *p) |
328 | { |
329 | char buf[PLAIN_BUF_SIZE]; |
330 | int ret; |
331 | |
332 | /* |
333 | * No need to increase failed test counter since this is assumed |
334 | * to be called after plain(). |
335 | */ |
336 | ret = plain_hash_to_buffer(p, buf, PLAIN_BUF_SIZE); |
337 | if (ret) |
338 | return; |
339 | |
340 | test(buf, fmt, p); |
341 | } |
342 | |
343 | /* |
344 | * NULL pointers aren't hashed. |
345 | */ |
346 | static void __init |
347 | null_pointer(void) |
348 | { |
349 | test(ZEROS "00000000" , "%p" , NULL); |
350 | test(ZEROS "00000000" , "%px" , NULL); |
351 | test("(null)" , "%pE" , NULL); |
352 | } |
353 | |
354 | /* |
355 | * Error pointers aren't hashed. |
356 | */ |
357 | static void __init |
358 | error_pointer(void) |
359 | { |
360 | test(ONES "fffffff5" , "%p" , ERR_PTR(-11)); |
361 | test(ONES "fffffff5" , "%px" , ERR_PTR(-11)); |
362 | test("(efault)" , "%pE" , ERR_PTR(-11)); |
363 | } |
364 | |
365 | #define PTR_INVALID ((void *)0x000000ab) |
366 | |
367 | static void __init |
368 | invalid_pointer(void) |
369 | { |
370 | test_hashed(fmt: "%p" , PTR_INVALID); |
371 | test(ZEROS "000000ab" , "%px" , PTR_INVALID); |
372 | test("(efault)" , "%pE" , PTR_INVALID); |
373 | } |
374 | |
375 | static void __init |
376 | symbol_ptr(void) |
377 | { |
378 | } |
379 | |
380 | static void __init |
381 | kernel_ptr(void) |
382 | { |
383 | /* We can't test this without access to kptr_restrict. */ |
384 | } |
385 | |
386 | static void __init |
387 | struct_resource(void) |
388 | { |
389 | } |
390 | |
391 | static void __init |
392 | addr(void) |
393 | { |
394 | } |
395 | |
396 | static void __init |
397 | escaped_str(void) |
398 | { |
399 | } |
400 | |
401 | static void __init |
402 | hex_string(void) |
403 | { |
404 | const char buf[3] = {0xc0, 0xff, 0xee}; |
405 | |
406 | test("c0 ff ee|c0:ff:ee|c0-ff-ee|c0ffee" , |
407 | "%3ph|%3phC|%3phD|%3phN" , buf, buf, buf, buf); |
408 | test("c0 ff ee|c0:ff:ee|c0-ff-ee|c0ffee" , |
409 | "%*ph|%*phC|%*phD|%*phN" , 3, buf, 3, buf, 3, buf, 3, buf); |
410 | } |
411 | |
412 | static void __init |
413 | mac(void) |
414 | { |
415 | const u8 addr[6] = {0x2d, 0x48, 0xd6, 0xfc, 0x7a, 0x05}; |
416 | |
417 | test("2d:48:d6:fc:7a:05" , "%pM" , addr); |
418 | test("05:7a:fc:d6:48:2d" , "%pMR" , addr); |
419 | test("2d-48-d6-fc-7a-05" , "%pMF" , addr); |
420 | test("2d48d6fc7a05" , "%pm" , addr); |
421 | test("057afcd6482d" , "%pmR" , addr); |
422 | } |
423 | |
424 | static void __init |
425 | ip4(void) |
426 | { |
427 | struct sockaddr_in sa; |
428 | |
429 | sa.sin_family = AF_INET; |
430 | sa.sin_port = cpu_to_be16(12345); |
431 | sa.sin_addr.s_addr = cpu_to_be32(0x7f000001); |
432 | |
433 | test("127.000.000.001|127.0.0.1" , "%pi4|%pI4" , &sa.sin_addr, &sa.sin_addr); |
434 | test("127.000.000.001|127.0.0.1" , "%piS|%pIS" , &sa, &sa); |
435 | sa.sin_addr.s_addr = cpu_to_be32(0x01020304); |
436 | test("001.002.003.004:12345|1.2.3.4:12345" , "%piSp|%pISp" , &sa, &sa); |
437 | } |
438 | |
439 | static void __init |
440 | ip6(void) |
441 | { |
442 | } |
443 | |
444 | static void __init |
445 | ip(void) |
446 | { |
447 | ip4(); |
448 | ip6(); |
449 | } |
450 | |
451 | static void __init |
452 | uuid(void) |
453 | { |
454 | const char uuid[16] = {0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, |
455 | 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf}; |
456 | |
457 | test("00010203-0405-0607-0809-0a0b0c0d0e0f" , "%pUb" , uuid); |
458 | test("00010203-0405-0607-0809-0A0B0C0D0E0F" , "%pUB" , uuid); |
459 | test("03020100-0504-0706-0809-0a0b0c0d0e0f" , "%pUl" , uuid); |
460 | test("03020100-0504-0706-0809-0A0B0C0D0E0F" , "%pUL" , uuid); |
461 | } |
462 | |
463 | static struct dentry test_dentry[4] __initdata = { |
464 | { .d_parent = &test_dentry[0], |
465 | .d_name = QSTR_INIT(test_dentry[0].d_iname, 3), |
466 | .d_iname = "foo" }, |
467 | { .d_parent = &test_dentry[0], |
468 | .d_name = QSTR_INIT(test_dentry[1].d_iname, 5), |
469 | .d_iname = "bravo" }, |
470 | { .d_parent = &test_dentry[1], |
471 | .d_name = QSTR_INIT(test_dentry[2].d_iname, 4), |
472 | .d_iname = "alfa" }, |
473 | { .d_parent = &test_dentry[2], |
474 | .d_name = QSTR_INIT(test_dentry[3].d_iname, 5), |
475 | .d_iname = "romeo" }, |
476 | }; |
477 | |
478 | static void __init |
479 | dentry(void) |
480 | { |
481 | test("foo" , "%pd" , &test_dentry[0]); |
482 | test("foo" , "%pd2" , &test_dentry[0]); |
483 | |
484 | test("(null)" , "%pd" , NULL); |
485 | test("(efault)" , "%pd" , PTR_INVALID); |
486 | test("(null)" , "%pD" , NULL); |
487 | test("(efault)" , "%pD" , PTR_INVALID); |
488 | |
489 | test("romeo" , "%pd" , &test_dentry[3]); |
490 | test("alfa/romeo" , "%pd2" , &test_dentry[3]); |
491 | test("bravo/alfa/romeo" , "%pd3" , &test_dentry[3]); |
492 | test("/bravo/alfa/romeo" , "%pd4" , &test_dentry[3]); |
493 | test("/bravo/alfa" , "%pd4" , &test_dentry[2]); |
494 | |
495 | test("bravo/alfa |bravo/alfa " , "%-12pd2|%*pd2" , &test_dentry[2], -12, &test_dentry[2]); |
496 | test(" bravo/alfa| bravo/alfa" , "%12pd2|%*pd2" , &test_dentry[2], 12, &test_dentry[2]); |
497 | } |
498 | |
499 | static void __init |
500 | struct_va_format(void) |
501 | { |
502 | } |
503 | |
504 | static void __init |
505 | time_and_date(void) |
506 | { |
507 | /* 1543210543 */ |
508 | const struct rtc_time tm = { |
509 | .tm_sec = 43, |
510 | .tm_min = 35, |
511 | .tm_hour = 5, |
512 | .tm_mday = 26, |
513 | .tm_mon = 10, |
514 | .tm_year = 118, |
515 | }; |
516 | /* 2019-01-04T15:32:23 */ |
517 | time64_t t = 1546615943; |
518 | |
519 | test("(%pt?)" , "%pt" , &tm); |
520 | test("2018-11-26T05:35:43" , "%ptR" , &tm); |
521 | test("0118-10-26T05:35:43" , "%ptRr" , &tm); |
522 | test("05:35:43|2018-11-26" , "%ptRt|%ptRd" , &tm, &tm); |
523 | test("05:35:43|0118-10-26" , "%ptRtr|%ptRdr" , &tm, &tm); |
524 | test("05:35:43|2018-11-26" , "%ptRttr|%ptRdtr" , &tm, &tm); |
525 | test("05:35:43 tr|2018-11-26 tr" , "%ptRt tr|%ptRd tr" , &tm, &tm); |
526 | |
527 | test("2019-01-04T15:32:23" , "%ptT" , &t); |
528 | test("0119-00-04T15:32:23" , "%ptTr" , &t); |
529 | test("15:32:23|2019-01-04" , "%ptTt|%ptTd" , &t, &t); |
530 | test("15:32:23|0119-00-04" , "%ptTtr|%ptTdr" , &t, &t); |
531 | |
532 | test("2019-01-04 15:32:23" , "%ptTs" , &t); |
533 | test("0119-00-04 15:32:23" , "%ptTsr" , &t); |
534 | test("15:32:23|2019-01-04" , "%ptTts|%ptTds" , &t, &t); |
535 | test("15:32:23|0119-00-04" , "%ptTtrs|%ptTdrs" , &t, &t); |
536 | } |
537 | |
538 | static void __init |
539 | struct_clk(void) |
540 | { |
541 | } |
542 | |
543 | static void __init |
544 | large_bitmap(void) |
545 | { |
546 | const int nbits = 1 << 16; |
547 | unsigned long *bits = bitmap_zalloc(nbits, GFP_KERNEL); |
548 | if (!bits) |
549 | return; |
550 | |
551 | bitmap_set(map: bits, start: 1, nbits: 20); |
552 | bitmap_set(map: bits, start: 60000, nbits: 15); |
553 | test("1-20,60000-60014" , "%*pbl" , nbits, bits); |
554 | bitmap_free(bitmap: bits); |
555 | } |
556 | |
557 | static void __init |
558 | bitmap(void) |
559 | { |
560 | DECLARE_BITMAP(bits, 20); |
561 | const int primes[] = {2,3,5,7,11,13,17,19}; |
562 | int i; |
563 | |
564 | bitmap_zero(dst: bits, nbits: 20); |
565 | test("00000|00000" , "%20pb|%*pb" , bits, 20, bits); |
566 | test("|" , "%20pbl|%*pbl" , bits, 20, bits); |
567 | |
568 | for (i = 0; i < ARRAY_SIZE(primes); ++i) |
569 | set_bit(nr: primes[i], addr: bits); |
570 | test("a28ac|a28ac" , "%20pb|%*pb" , bits, 20, bits); |
571 | test("2-3,5,7,11,13,17,19|2-3,5,7,11,13,17,19" , "%20pbl|%*pbl" , bits, 20, bits); |
572 | |
573 | bitmap_fill(dst: bits, nbits: 20); |
574 | test("fffff|fffff" , "%20pb|%*pb" , bits, 20, bits); |
575 | test("0-19|0-19" , "%20pbl|%*pbl" , bits, 20, bits); |
576 | |
577 | large_bitmap(); |
578 | } |
579 | |
580 | static void __init |
581 | netdev_features(void) |
582 | { |
583 | } |
584 | |
585 | struct page_flags_test { |
586 | int width; |
587 | int shift; |
588 | int mask; |
589 | const char *fmt; |
590 | const char *name; |
591 | }; |
592 | |
593 | static const struct page_flags_test pft[] = { |
594 | {SECTIONS_WIDTH, SECTIONS_PGSHIFT, SECTIONS_MASK, |
595 | "%d" , "section" }, |
596 | {NODES_WIDTH, NODES_PGSHIFT, NODES_MASK, |
597 | "%d" , "node" }, |
598 | {ZONES_WIDTH, ZONES_PGSHIFT, ZONES_MASK, |
599 | "%d" , "zone" }, |
600 | {LAST_CPUPID_WIDTH, LAST_CPUPID_PGSHIFT, LAST_CPUPID_MASK, |
601 | "%#x" , "lastcpupid" }, |
602 | {KASAN_TAG_WIDTH, KASAN_TAG_PGSHIFT, KASAN_TAG_MASK, |
603 | "%#x" , "kasantag" }, |
604 | }; |
605 | |
606 | static void __init |
607 | page_flags_test(int section, int node, int zone, int last_cpupid, |
608 | int kasan_tag, unsigned long flags, const char *name, |
609 | char *cmp_buf) |
610 | { |
611 | unsigned long values[] = {section, node, zone, last_cpupid, kasan_tag}; |
612 | unsigned long size; |
613 | bool append = false; |
614 | int i; |
615 | |
616 | for (i = 0; i < ARRAY_SIZE(values); i++) |
617 | flags |= (values[i] & pft[i].mask) << pft[i].shift; |
618 | |
619 | size = scnprintf(buf: cmp_buf, BUF_SIZE, fmt: "%#lx(" , flags); |
620 | if (flags & PAGEFLAGS_MASK) { |
621 | size += scnprintf(buf: cmp_buf + size, BUF_SIZE - size, fmt: "%s" , name); |
622 | append = true; |
623 | } |
624 | |
625 | for (i = 0; i < ARRAY_SIZE(pft); i++) { |
626 | if (!pft[i].width) |
627 | continue; |
628 | |
629 | if (append) |
630 | size += scnprintf(cmp_buf + size, BUF_SIZE - size, "|" ); |
631 | |
632 | size += scnprintf(cmp_buf + size, BUF_SIZE - size, "%s=" , |
633 | pft[i].name); |
634 | size += scnprintf(cmp_buf + size, BUF_SIZE - size, pft[i].fmt, |
635 | values[i] & pft[i].mask); |
636 | append = true; |
637 | } |
638 | |
639 | snprintf(buf: cmp_buf + size, BUF_SIZE - size, fmt: ")" ); |
640 | |
641 | test(cmp_buf, "%pGp" , &flags); |
642 | } |
643 | |
644 | static void __init page_type_test(unsigned int page_type, const char *name, |
645 | char *cmp_buf) |
646 | { |
647 | unsigned long size; |
648 | |
649 | size = scnprintf(buf: cmp_buf, BUF_SIZE, fmt: "%#x(" , page_type); |
650 | if (page_type_has_type(page_type)) |
651 | size += scnprintf(buf: cmp_buf + size, BUF_SIZE - size, fmt: "%s" , name); |
652 | |
653 | snprintf(buf: cmp_buf + size, BUF_SIZE - size, fmt: ")" ); |
654 | test(cmp_buf, "%pGt" , &page_type); |
655 | } |
656 | |
657 | static void __init |
658 | flags(void) |
659 | { |
660 | unsigned long flags; |
661 | char *cmp_buffer; |
662 | gfp_t gfp; |
663 | unsigned int page_type; |
664 | |
665 | cmp_buffer = kmalloc(BUF_SIZE, GFP_KERNEL); |
666 | if (!cmp_buffer) |
667 | return; |
668 | |
669 | flags = 0; |
670 | page_flags_test(section: 0, node: 0, zone: 0, last_cpupid: 0, kasan_tag: 0, flags, name: "" , cmp_buf: cmp_buffer); |
671 | |
672 | flags = 1UL << NR_PAGEFLAGS; |
673 | page_flags_test(section: 0, node: 0, zone: 0, last_cpupid: 0, kasan_tag: 0, flags, name: "" , cmp_buf: cmp_buffer); |
674 | |
675 | flags |= 1UL << PG_uptodate | 1UL << PG_dirty | 1UL << PG_lru |
676 | | 1UL << PG_active | 1UL << PG_swapbacked; |
677 | page_flags_test(section: 1, node: 1, zone: 1, last_cpupid: 0x1fffff, kasan_tag: 1, flags, |
678 | name: "uptodate|dirty|lru|active|swapbacked" , |
679 | cmp_buf: cmp_buffer); |
680 | |
681 | flags = VM_READ | VM_EXEC | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC; |
682 | test("read|exec|mayread|maywrite|mayexec" , "%pGv" , &flags); |
683 | |
684 | gfp = GFP_TRANSHUGE; |
685 | test("GFP_TRANSHUGE" , "%pGg" , &gfp); |
686 | |
687 | gfp = GFP_ATOMIC|__GFP_DMA; |
688 | test("GFP_ATOMIC|GFP_DMA" , "%pGg" , &gfp); |
689 | |
690 | gfp = __GFP_HIGH; |
691 | test("__GFP_HIGH" , "%pGg" , &gfp); |
692 | |
693 | /* Any flags not translated by the table should remain numeric */ |
694 | gfp = ~__GFP_BITS_MASK; |
695 | snprintf(buf: cmp_buffer, BUF_SIZE, fmt: "%#lx" , (unsigned long) gfp); |
696 | test(cmp_buffer, "%pGg" , &gfp); |
697 | |
698 | snprintf(buf: cmp_buffer, BUF_SIZE, fmt: "__GFP_HIGH|%#lx" , |
699 | (unsigned long) gfp); |
700 | gfp |= __GFP_HIGH; |
701 | test(cmp_buffer, "%pGg" , &gfp); |
702 | |
703 | page_type = ~0; |
704 | page_type_test(page_type, name: "" , cmp_buf: cmp_buffer); |
705 | |
706 | page_type = 10; |
707 | page_type_test(page_type, name: "" , cmp_buf: cmp_buffer); |
708 | |
709 | page_type = ~PG_buddy; |
710 | page_type_test(page_type, name: "buddy" , cmp_buf: cmp_buffer); |
711 | |
712 | page_type = ~(PG_table | PG_buddy); |
713 | page_type_test(page_type, name: "table|buddy" , cmp_buf: cmp_buffer); |
714 | |
715 | kfree(objp: cmp_buffer); |
716 | } |
717 | |
718 | static void __init fwnode_pointer(void) |
719 | { |
720 | const struct software_node first = { .name = "first" }; |
721 | const struct software_node second = { .name = "second" , .parent = &first }; |
722 | const struct software_node third = { .name = "third" , .parent = &second }; |
723 | const struct software_node *group[] = { &first, &second, &third, NULL }; |
724 | const char * const full_name_second = "first/second" ; |
725 | const char * const full_name_third = "first/second/third" ; |
726 | const char * const second_name = "second" ; |
727 | const char * const third_name = "third" ; |
728 | int rval; |
729 | |
730 | rval = software_node_register_node_group(node_group: group); |
731 | if (rval) { |
732 | pr_warn("cannot register softnodes; rval %d\n" , rval); |
733 | return; |
734 | } |
735 | |
736 | test(full_name_second, "%pfw" , software_node_fwnode(&second)); |
737 | test(full_name_third, "%pfw" , software_node_fwnode(&third)); |
738 | test(full_name_third, "%pfwf" , software_node_fwnode(&third)); |
739 | test(second_name, "%pfwP" , software_node_fwnode(&second)); |
740 | test(third_name, "%pfwP" , software_node_fwnode(&third)); |
741 | |
742 | software_node_unregister_node_group(node_group: group); |
743 | } |
744 | |
745 | static void __init fourcc_pointer(void) |
746 | { |
747 | struct { |
748 | u32 code; |
749 | char *str; |
750 | } const try[] = { |
751 | { 0x3231564e, "NV12 little-endian (0x3231564e)" , }, |
752 | { 0xb231564e, "NV12 big-endian (0xb231564e)" , }, |
753 | { 0x10111213, ".... little-endian (0x10111213)" , }, |
754 | { 0x20303159, "Y10 little-endian (0x20303159)" , }, |
755 | }; |
756 | unsigned int i; |
757 | |
758 | for (i = 0; i < ARRAY_SIZE(try); i++) |
759 | test(try[i].str, "%p4cc" , &try[i].code); |
760 | } |
761 | |
762 | static void __init |
763 | errptr(void) |
764 | { |
765 | test("-1234" , "%pe" , ERR_PTR(-1234)); |
766 | |
767 | /* Check that %pe with a non-ERR_PTR gets treated as ordinary %p. */ |
768 | BUILD_BUG_ON(IS_ERR(PTR)); |
769 | test_hashed(fmt: "%pe" , PTR); |
770 | |
771 | #ifdef CONFIG_SYMBOLIC_ERRNAME |
772 | test("(-ENOTSOCK)" , "(%pe)" , ERR_PTR(-ENOTSOCK)); |
773 | test("(-EAGAIN)" , "(%pe)" , ERR_PTR(-EAGAIN)); |
774 | BUILD_BUG_ON(EAGAIN != EWOULDBLOCK); |
775 | test("(-EAGAIN)" , "(%pe)" , ERR_PTR(-EWOULDBLOCK)); |
776 | test("[-EIO ]" , "[%-8pe]" , ERR_PTR(-EIO)); |
777 | test("[ -EIO]" , "[%8pe]" , ERR_PTR(-EIO)); |
778 | test("-EPROBE_DEFER" , "%pe" , ERR_PTR(-EPROBE_DEFER)); |
779 | #endif |
780 | } |
781 | |
782 | static void __init |
783 | test_pointer(void) |
784 | { |
785 | plain(); |
786 | null_pointer(); |
787 | error_pointer(); |
788 | invalid_pointer(); |
789 | symbol_ptr(); |
790 | kernel_ptr(); |
791 | struct_resource(); |
792 | addr(); |
793 | escaped_str(); |
794 | hex_string(); |
795 | mac(); |
796 | ip(); |
797 | uuid(); |
798 | dentry(); |
799 | struct_va_format(); |
800 | time_and_date(); |
801 | struct_clk(); |
802 | bitmap(); |
803 | netdev_features(); |
804 | flags(); |
805 | errptr(); |
806 | fwnode_pointer(); |
807 | fourcc_pointer(); |
808 | } |
809 | |
810 | static void __init selftest(void) |
811 | { |
812 | alloced_buffer = kmalloc(BUF_SIZE + 2*PAD_SIZE, GFP_KERNEL); |
813 | if (!alloced_buffer) |
814 | return; |
815 | test_buffer = alloced_buffer + PAD_SIZE; |
816 | |
817 | test_basic(); |
818 | test_number(); |
819 | test_string(); |
820 | test_pointer(); |
821 | |
822 | kfree(objp: alloced_buffer); |
823 | } |
824 | |
825 | KSTM_MODULE_LOADERS(test_printf); |
826 | MODULE_AUTHOR("Rasmus Villemoes <linux@rasmusvillemoes.dk>" ); |
827 | MODULE_LICENSE("GPL" ); |
828 | |