1 /*
2 * Copyright (c) 2021 Nordic Semiconductor ASA
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/ztest.h>
8 #include <zephyr/sys/cbprintf.h>
9 #include <zephyr/linker/utils.h>
10
11 #define CBPRINTF_DEBUG 1
12
13 #ifndef CBPRINTF_PACKAGE_ALIGN_OFFSET
14 #define CBPRINTF_PACKAGE_ALIGN_OFFSET 0
15 #endif
16
17 #define ALIGN_OFFSET (sizeof(void *) * CBPRINTF_PACKAGE_ALIGN_OFFSET)
18
19 struct out_buffer {
20 char *buf;
21 size_t idx;
22 size_t size;
23 };
24
out(int c,void * dest)25 static int out(int c, void *dest)
26 {
27 int rv = EOF;
28 struct out_buffer *buf = (struct out_buffer *)dest;
29
30 if (buf->idx < buf->size) {
31 buf->buf[buf->idx++] = (char)(unsigned char)c;
32 rv = (int)(unsigned char)c;
33 }
34 return rv;
35 }
36
37 static char static_buf[512];
38 static char runtime_buf[512];
39 static char compare_buf[128];
40
dump(const char * desc,uint8_t * package,size_t len)41 static void dump(const char *desc, uint8_t *package, size_t len)
42 {
43 printk("%s package %p:\n", desc, package);
44 for (size_t i = 0; i < len; i++) {
45 printk("%02x ", package[i]);
46 }
47 printk("\n");
48 }
49
unpack(const char * desc,struct out_buffer * buf,uint8_t * package,size_t len)50 static void unpack(const char *desc, struct out_buffer *buf,
51 uint8_t *package, size_t len)
52 {
53 cbpprintf((cbprintf_cb)out, buf, package);
54 buf->buf[buf->idx] = 0;
55 zassert_equal(strcmp(buf->buf, compare_buf), 0,
56 "Strings differ\nexp: |%s|\ngot: |%s|\n",
57 compare_buf, buf->buf);
58 }
59
60 #define TEST_PACKAGING(flags, fmt, ...) do { \
61 int must_runtime = CBPRINTF_MUST_RUNTIME_PACKAGE(flags, fmt, __VA_ARGS__); \
62 zassert_equal(must_runtime, !Z_C_GENERIC); \
63 snprintfcb(compare_buf, sizeof(compare_buf), fmt, __VA_ARGS__); \
64 printk("-----------------------------------------\n"); \
65 printk("%s\n", compare_buf); \
66 uint8_t *pkg; \
67 struct out_buffer rt_buf = { \
68 .buf = runtime_buf, .idx = 0, .size = sizeof(runtime_buf) \
69 }; \
70 int rc = cbprintf_package(NULL, ALIGN_OFFSET, 0, fmt, __VA_ARGS__); \
71 zassert_true(rc > 0, "cbprintf_package() returned %d", rc); \
72 int len = rc; \
73 /* Aligned so the package is similar to the static one. */ \
74 uint8_t __aligned(CBPRINTF_PACKAGE_ALIGNMENT) \
75 rt_package[len + ALIGN_OFFSET]; \
76 memset(rt_package, 0, len + ALIGN_OFFSET); \
77 pkg = &rt_package[ALIGN_OFFSET]; \
78 rc = cbprintf_package(pkg, len, 0, fmt, __VA_ARGS__); \
79 zassert_equal(rc, len, "cbprintf_package() returned %d, expected %d", \
80 rc, len); \
81 dump("runtime", pkg, len); \
82 unpack("runtime", &rt_buf, pkg, len); \
83 struct out_buffer st_buf = { \
84 .buf = static_buf, .idx = 0, .size = sizeof(static_buf) \
85 }; \
86 CBPRINTF_STATIC_PACKAGE(NULL, 0, len, ALIGN_OFFSET, flags, fmt, __VA_ARGS__); \
87 zassert_true(len > 0, "CBPRINTF_STATIC_PACKAGE() returned %d", len); \
88 uint8_t __aligned(CBPRINTF_PACKAGE_ALIGNMENT) \
89 package[len + ALIGN_OFFSET];\
90 int outlen; \
91 pkg = &package[ALIGN_OFFSET]; \
92 CBPRINTF_STATIC_PACKAGE(pkg, len, outlen, ALIGN_OFFSET, flags, fmt, __VA_ARGS__);\
93 zassert_equal(len, outlen); \
94 dump("static", pkg, len); \
95 unpack("static", &st_buf, pkg, len); \
96 } while (0)
97
ZTEST(cbprintf_package,test_cbprintf_package)98 ZTEST(cbprintf_package, test_cbprintf_package)
99 {
100 volatile signed char sc = -11;
101 int i = 100;
102 char c = 'a';
103 static const short s = -300;
104 long li = -1111111111;
105 long long lli = 0x1122334455667788;
106 unsigned char uc = 100;
107 unsigned int ui = 0x12345;
108 unsigned short us = 0x1234;
109 unsigned long ul = 0xaabbaabb;
110 unsigned long long ull = 0xaabbaabbaabb;
111 void *vp = NULL;
112 static const char *str = "test";
113 char *pstr = (char *)str;
114 int rv;
115
116 /* tests to exercise different element alignments */
117 TEST_PACKAGING(0, "test long %x %lx %x", 0xb1b2b3b4, li, 0xe4e3e2e1);
118 TEST_PACKAGING(0, "test long long %x %llx %x", 0xb1b2b3b4, lli, 0xe4e3e2e1);
119
120 /* tests with varied elements */
121 TEST_PACKAGING(0, "test %d %hd %hhd", i, s, sc);
122 TEST_PACKAGING(0, "test %ld %llx %hhu %hu %u", li, lli, uc, us, ui);
123 TEST_PACKAGING(0, "test %lu %llu", ul, ull);
124 TEST_PACKAGING(0, "test %c %p", c, vp);
125
126 /* Runtime packaging is still possible when const strings are used. */
127 TEST_PACKAGING(CBPRINTF_PACKAGE_CONST_CHAR_RO,
128 "test %s %s", str, (const char *)pstr);
129
130 /* When flag is set but argument is char * runtime packaging must be used. */
131 rv = CBPRINTF_MUST_RUNTIME_PACKAGE(CBPRINTF_PACKAGE_CONST_CHAR_RO,
132 "test %s %s", str, pstr);
133 zassert_true(rv != 0, "Unexpected value %d", rv);
134
135 /* When const char * are used but flag is not used then runtime packaging must be used. */
136 rv = CBPRINTF_MUST_RUNTIME_PACKAGE(0, "test %s %s", str, (const char *)pstr);
137 zassert_true(rv != 0, "Unexpected value %d", rv);
138
139 rv = CBPRINTF_MUST_RUNTIME_PACKAGE(CBPRINTF_PACKAGE_CONST_CHAR_RO,
140 "test %s", (char *)str);
141 zassert_true(rv != 0, "Unexpected value %d", rv);
142
143 if (IS_ENABLED(CONFIG_CBPRINTF_FP_SUPPORT)) {
144 float f = -1.234f;
145 double d = 1.2333;
146
147 TEST_PACKAGING(0, "test double %x %f %x", 0xb1b2b3b4, d, 0xe4e3e2e1);
148 TEST_PACKAGING(0, "test %f %a", (double)f, d);
149 #if CONFIG_CBPRINTF_PACKAGE_LONGDOUBLE && !(defined(CONFIG_RISCV) && !defined(CONFIG_64BIT))
150 /* Excluding riscv32 which does not handle long double correctly. */
151 long double ld = 1.2333L;
152
153 TEST_PACKAGING(0, "test %Lf", ld);
154 #endif
155 }
156 }
157
ZTEST(cbprintf_package,test_cbprintf_rw_str_indexes)158 ZTEST(cbprintf_package, test_cbprintf_rw_str_indexes)
159 {
160 int len0, len1, len2;
161 static const char *test_str = "test %d %s";
162 static const char *test_str1 = "lorem ipsum";
163 uint8_t str_idx;
164 char *addr;
165
166 len0 = cbprintf_package(NULL, 0, 0, test_str, 100, test_str1);
167 if (len0 > (int)(4 * sizeof(void *))) {
168 TC_PRINT("Skipping test, platform does not detect RO strings.\n");
169 ztest_test_skip();
170 }
171
172 zassert_true(len0 > 0);
173 len1 = cbprintf_package(NULL, 0, CBPRINTF_PACKAGE_ADD_STRING_IDXS,
174 test_str, 100, test_str1);
175 zassert_true(len1 > 0);
176
177 CBPRINTF_STATIC_PACKAGE(NULL, 0, len2, 0,
178 CBPRINTF_PACKAGE_ADD_STRING_IDXS,
179 test_str, 100, test_str1);
180 zassert_true(len2 > 0);
181
182 /* package with string indexes will contain two more bytes holding indexes
183 * of string parameter locations.
184 */
185 zassert_equal(len0 + 2, len1);
186 zassert_equal(len0 + 2, len2);
187
188 uint8_t __aligned(CBPRINTF_PACKAGE_ALIGNMENT) package0[len0];
189 uint8_t __aligned(CBPRINTF_PACKAGE_ALIGNMENT) package1[len1];
190 uint8_t __aligned(CBPRINTF_PACKAGE_ALIGNMENT) package2[len2];
191
192 len0 = cbprintf_package(package0, sizeof(package0), 0,
193 test_str, 100, test_str1);
194
195 len1 = cbprintf_package(package1, sizeof(package1) - 1,
196 CBPRINTF_PACKAGE_ADD_STRING_IDXS,
197 test_str, 100, test_str1);
198 zassert_equal(-ENOSPC, len1);
199
200 CBPRINTF_STATIC_PACKAGE(package2, sizeof(package2) - 1, len2, 0,
201 CBPRINTF_PACKAGE_ADD_STRING_IDXS,
202 test_str, 100, test_str1);
203 zassert_equal(-ENOSPC, len2);
204
205 len1 = cbprintf_package(package1, sizeof(package1),
206 CBPRINTF_PACKAGE_ADD_STRING_IDXS,
207 test_str, 100, test_str1);
208 zassert_equal(len0 + 2, len1);
209
210 CBPRINTF_STATIC_PACKAGE(package2, sizeof(package2), len2, 0,
211 CBPRINTF_PACKAGE_ADD_STRING_IDXS,
212 test_str, 100, test_str1);
213 zassert_equal(len0 + 2, len2);
214
215 union cbprintf_package_hdr *desc0 = (union cbprintf_package_hdr *)package0;
216 union cbprintf_package_hdr *desc1 = (union cbprintf_package_hdr *)package1;
217 union cbprintf_package_hdr *desc2 = (union cbprintf_package_hdr *)package2;
218
219 /* Compare descriptor content. Second package has one ro string index. */
220 zassert_equal(desc0->desc.ro_str_cnt, 0);
221 zassert_equal(desc1->desc.ro_str_cnt, 2);
222 zassert_equal(desc2->desc.ro_str_cnt, 2);
223
224 int *p = (int *)package1;
225
226 str_idx = package1[len0];
227 addr = *(char **)&p[str_idx];
228 zassert_equal(addr, test_str);
229
230 str_idx = package2[len0];
231 addr = *(char **)&p[str_idx];
232 zassert_equal(addr, test_str);
233
234 str_idx = package1[len0 + 1];
235 addr = *(char **)&p[str_idx];
236 zassert_equal(addr, test_str1);
237
238 str_idx = package2[len0 + 1];
239 addr = *(char **)&p[str_idx];
240 zassert_equal(addr, test_str1);
241 }
242
ZTEST(cbprintf_package,test_cbprintf_fsc_package)243 ZTEST(cbprintf_package, test_cbprintf_fsc_package)
244 {
245 int len;
246 static const char *test_str = "test %d %s";
247 static const char *test_str1 = "lorem ipsum";
248 char *addr;
249 int fsc_len;
250
251 len = cbprintf_package(NULL, 0, CBPRINTF_PACKAGE_ADD_STRING_IDXS,
252 test_str, 100, test_str1);
253 if (len > (int)(4 * sizeof(void *) + 2)) {
254 TC_PRINT("Skipping test, platform does not detect RO strings.\n");
255 ztest_test_skip();
256 }
257
258 uint8_t __aligned(CBPRINTF_PACKAGE_ALIGNMENT) package[len];
259
260 len = cbprintf_package(package, sizeof(package),
261 CBPRINTF_PACKAGE_ADD_STRING_IDXS,
262 test_str, 100, test_str1);
263
264 union cbprintf_package_hdr *desc = (union cbprintf_package_hdr *)package;
265
266 zassert_equal(desc->desc.ro_str_cnt, 2);
267 zassert_equal(desc->desc.str_cnt, 0);
268
269 /* Get length of fsc package. */
270 fsc_len = cbprintf_fsc_package(package, len, NULL, 0);
271
272 int exp_len = len + (int)strlen(test_str) + 1 + (int)strlen(test_str1) + 1;
273
274 zassert_equal(exp_len, fsc_len);
275
276 uint8_t __aligned(CBPRINTF_PACKAGE_ALIGNMENT) fsc_package[fsc_len];
277
278 fsc_len = cbprintf_fsc_package(package, len, fsc_package, sizeof(fsc_package) - 1);
279 zassert_equal(fsc_len, -ENOSPC);
280
281 fsc_len = cbprintf_fsc_package(package, len, fsc_package, sizeof(fsc_package));
282 zassert_equal((int)sizeof(fsc_package), fsc_len);
283
284 /* New package has no RO string locations, only copied one. */
285 desc = (union cbprintf_package_hdr *)fsc_package;
286 zassert_equal(desc->desc.ro_str_cnt, 0);
287 zassert_equal(desc->desc.str_cnt, 2);
288
289 /* Get pointer to the first string in the package. */
290 addr = (char *)&fsc_package[desc->desc.len * sizeof(int) + 1];
291
292 zassert_str_equal(test_str, addr);
293
294 /* Get address of the second string. */
295 addr += strlen(addr) + 2;
296 zassert_str_equal(test_str1, addr);
297 }
298
check_package(void * package,size_t len,const char * exp_str)299 static void check_package(void *package, size_t len, const char *exp_str)
300 {
301 char out_str[128];
302
303 strcpy(compare_buf, exp_str);
304
305 struct out_buffer out_buf = {
306 .buf = out_str,
307 .idx = 0,
308 .size = sizeof(out_str)
309 };
310
311 unpack(NULL, &out_buf, (uint8_t *)package, len);
312 }
313
ZTEST(cbprintf_package,test_cbprintf_ro_loc)314 ZTEST(cbprintf_package, test_cbprintf_ro_loc)
315 {
316 static const char *test_str = "test %d";
317 uint32_t flags = CBPRINTF_PACKAGE_ADD_RO_STR_POS;
318
319 #define TEST_FMT test_str, 100
320 char exp_str[256];
321
322 snprintfcb(exp_str, sizeof(exp_str), TEST_FMT);
323
324 int len = cbprintf_package(NULL, 0, flags, TEST_FMT);
325
326 int slen;
327
328 CBPRINTF_STATIC_PACKAGE(NULL, 0, slen, ALIGN_OFFSET, flags, TEST_FMT);
329
330 zassert_true(len > 0);
331 zassert_equal(len, slen, "Runtime length: %d, static length: %d", len, slen);
332
333 uint8_t __aligned(CBPRINTF_PACKAGE_ALIGNMENT) package[len];
334 uint8_t __aligned(CBPRINTF_PACKAGE_ALIGNMENT) spackage[slen];
335
336 /*
337 * Since memcpy() is being done below, it is better to zero out
338 * both arrays as there might a paddings in the package headers
339 * which are not touched by packaging functions, where those bytes
340 * have whatever is in the stack.
341 */
342 memset(package, 0, len);
343 memset(spackage, 0, slen);
344
345 len = cbprintf_package(package, sizeof(package), flags, TEST_FMT);
346 CBPRINTF_STATIC_PACKAGE(spackage, sizeof(spackage), slen, ALIGN_OFFSET, flags, TEST_FMT);
347
348 zassert_true(len > 0);
349 zassert_equal(len, slen, "Runtime length: %d, static length: %d", len, slen);
350
351 zassert_equal(memcmp(package, spackage, len), 0);
352
353 uint8_t *hdr = package;
354
355 /* Check that only read-only string location array size is non zero */
356 zassert_equal(hdr[1], 0);
357 zassert_equal(hdr[2], 1);
358 zassert_equal(hdr[3], 0);
359
360 int clen;
361
362 /* Calculate size needed for package with appended read-only strings. */
363 clen = cbprintf_package_copy(package, sizeof(package), NULL, 0,
364 CBPRINTF_PACKAGE_CONVERT_RO_STR, NULL, 0);
365
366 /* Length will be increased by string length + null terminator. */
367 zassert_equal(clen, len + (int)strlen(test_str) + 1);
368
369 uint8_t __aligned(CBPRINTF_PACKAGE_ALIGNMENT) cpackage[clen];
370
371 int clen2 = cbprintf_package_copy(package, sizeof(package), cpackage, sizeof(cpackage),
372 CBPRINTF_PACKAGE_CONVERT_RO_STR, NULL, 0);
373
374 zassert_equal(clen, clen2);
375
376 /* Length will be increased by string length + null terminator. */
377 zassert_equal(clen, len + (int)strlen(test_str) + 1);
378
379 uint8_t *chdr = cpackage;
380
381 /* Check that only package after copying has no locations but has
382 * appended string.
383 */
384 zassert_equal(chdr[1], 1);
385 zassert_equal(chdr[2], 0);
386 zassert_equal(chdr[3], 0);
387
388 check_package(package, len, exp_str);
389 check_package(cpackage, clen, exp_str);
390
391 #undef TEST_FMT
392 }
393
394 /* Store read-only string by index when read-write string is appended. This
395 * is supported only by runtime packaging.
396 */
ZTEST(cbprintf_package,test_cbprintf_ro_loc_rw_present)397 ZTEST(cbprintf_package, test_cbprintf_ro_loc_rw_present)
398 {
399 static const char *test_str = "test %d %s";
400 char test_str1[] = "test str1";
401 uint32_t flags = CBPRINTF_PACKAGE_ADD_RO_STR_POS;
402
403 #define TEST_FMT test_str, 100, test_str1
404 char exp_str[256];
405
406 snprintfcb(exp_str, sizeof(exp_str), TEST_FMT);
407
408 int len = cbprintf_package(NULL, 0, flags, TEST_FMT);
409
410 zassert_true(len > 0);
411
412 uint8_t __aligned(CBPRINTF_PACKAGE_ALIGNMENT) package[len];
413
414 len = cbprintf_package(package, sizeof(package), flags, TEST_FMT);
415 zassert_true(len > 0);
416
417 uint8_t *hdr = package;
418
419 /* Check that only read-only string location array size is non zero */
420 zassert_equal(hdr[1], 1);
421 zassert_equal(hdr[2], 1);
422 zassert_equal(hdr[3], 0);
423
424 int clen;
425
426 /* Calculate size needed for package with appended read-only strings. */
427 clen = cbprintf_package_copy(package, sizeof(package), NULL, 0,
428 CBPRINTF_PACKAGE_CONVERT_RO_STR, NULL, 0);
429
430 /* Length will be increased by string length + null terminator. */
431 zassert_equal(clen, len + (int)strlen(test_str) + 1);
432
433 uint8_t __aligned(CBPRINTF_PACKAGE_ALIGNMENT) cpackage[clen];
434
435 int clen2 = cbprintf_package_copy(package, sizeof(package), cpackage, sizeof(cpackage),
436 CBPRINTF_PACKAGE_CONVERT_RO_STR, NULL, 0);
437
438 zassert_equal(clen, clen2);
439
440 /* Length will be increased by string length + null terminator. */
441 zassert_equal(clen, len + (int)strlen(test_str) + 1);
442
443 uint8_t *chdr = cpackage;
444
445 /* Check that only package after copying has no locations but has
446 * appended string.
447 */
448 zassert_equal(chdr[1], 2);
449 zassert_equal(chdr[2], 0);
450 zassert_equal(chdr[3], 0);
451
452 check_package(package, clen, exp_str);
453 check_package(cpackage, clen, exp_str);
454
455 #undef TEST_FMT
456 }
457
ZTEST(cbprintf_package,test_cbprintf_ro_rw_loc)458 ZTEST(cbprintf_package, test_cbprintf_ro_rw_loc)
459 {
460 /* Strings does not need to be in read-only memory section, flag indicates
461 * that n first strings are read only.
462 */
463 char test_str[] = "test %s %s %d %s";
464 char cstr[] = "const";
465
466 char test_str1[] = "test str1";
467 char test_str2[] = "test str2";
468
469 #define TEST_FMT test_str, cstr, test_str1, 100, test_str2
470 char exp_str[256];
471
472 snprintfcb(exp_str, sizeof(exp_str), TEST_FMT);
473
474 uint32_t flags = CBPRINTF_PACKAGE_FIRST_RO_STR_CNT(1) |
475 CBPRINTF_PACKAGE_ADD_RO_STR_POS |
476 CBPRINTF_PACKAGE_ADD_RW_STR_POS;
477
478 int len = cbprintf_package(NULL, 0, flags, TEST_FMT);
479 int slen;
480
481 CBPRINTF_STATIC_PACKAGE(NULL, 0, slen, ALIGN_OFFSET, flags, TEST_FMT);
482 zassert_true(len > 0);
483 zassert_equal(len, slen);
484
485 uint8_t __aligned(CBPRINTF_PACKAGE_ALIGNMENT) package[len];
486 uint8_t __aligned(CBPRINTF_PACKAGE_ALIGNMENT) spackage[len];
487
488 memset(package, 0, len);
489 memset(spackage, 0, len);
490
491 int len2 = cbprintf_package(package, sizeof(package), flags, TEST_FMT);
492
493 CBPRINTF_STATIC_PACKAGE(spackage, sizeof(spackage), slen, ALIGN_OFFSET, flags, TEST_FMT);
494 zassert_equal(len, len2);
495 zassert_equal(slen, len2);
496 zassert_equal(memcmp(package, spackage, len), 0);
497
498 struct cbprintf_package_desc *hdr = (struct cbprintf_package_desc *)package;
499
500 /* Check that expected number of ro and rw locations are present and no
501 * strings appended.
502 */
503 zassert_equal(hdr->str_cnt, 0);
504 zassert_equal(hdr->ro_str_cnt, 2);
505 zassert_equal(hdr->rw_str_cnt, 2);
506
507 int clen;
508
509 uint16_t strl[2] = {0};
510
511 /* Calculate size needed for package with appended read-only strings. */
512 clen = cbprintf_package_copy(package, sizeof(package), NULL, 0,
513 CBPRINTF_PACKAGE_CONVERT_RO_STR, strl, ARRAY_SIZE(strl));
514
515 /* Length will be increased by 2 string lengths + null terminators. */
516 zassert_equal(clen, len + (int)strlen(test_str) + (int)strlen(cstr) + 2);
517 zassert_equal(strl[0], strlen(test_str) + 1);
518 zassert_equal(strl[1], strlen(cstr) + 1);
519
520 uint8_t __aligned(CBPRINTF_PACKAGE_ALIGNMENT) cpackage[clen];
521
522 int clen2 = cbprintf_package_copy(package, sizeof(package), cpackage, sizeof(cpackage),
523 CBPRINTF_PACKAGE_CONVERT_RO_STR, strl, ARRAY_SIZE(strl));
524
525 zassert_equal(clen, clen2);
526
527 struct cbprintf_package_desc *chdr = (struct cbprintf_package_desc *)cpackage;
528
529 /* Check that read only strings have been appended. */
530 zassert_equal(chdr->str_cnt, 2);
531 zassert_equal(chdr->ro_str_cnt, 0);
532 zassert_equal(chdr->rw_str_cnt, 2);
533
534 check_package(package, len, exp_str);
535 check_package(cpackage, clen, exp_str);
536
537 uint32_t cpy_flags = CBPRINTF_PACKAGE_CONVERT_RW_STR |
538 CBPRINTF_PACKAGE_CONVERT_KEEP_RO_STR;
539
540 /* Calculate size needed for package with appended read-write strings. */
541 clen = cbprintf_package_copy(package, sizeof(package), NULL, 0,
542 cpy_flags, NULL, 0);
543
544 /* Length will be increased by 2 string lengths + null terminators - arg indexes. */
545 zassert_equal(clen, len + (int)strlen(test_str1) + (int)strlen(test_str2) + 2 - 2,
546 "exp: %d, got: %d",
547 clen, len + (int)strlen(test_str1) + (int)strlen(test_str2) + 2 - 2);
548
549 uint8_t __aligned(CBPRINTF_PACKAGE_ALIGNMENT) cpackage2[clen];
550
551 clen2 = cbprintf_package_copy(package, sizeof(package), cpackage2, sizeof(cpackage2),
552 cpy_flags, NULL, 0);
553
554 zassert_equal(clen, clen2);
555
556 chdr = (struct cbprintf_package_desc *)cpackage2;
557
558 /* Check that read write strings have been appended. */
559 zassert_equal(chdr->str_cnt, 2);
560 zassert_equal(chdr->ro_str_cnt, 2);
561 zassert_equal(chdr->rw_str_cnt, 0);
562
563 check_package(package, len, exp_str);
564 check_package(cpackage2, clen, exp_str);
565
566 #undef TEST_FMT
567 }
568
ZTEST(cbprintf_package,test_cbprintf_ro_rw_loc_const_char_ptr)569 ZTEST(cbprintf_package, test_cbprintf_ro_rw_loc_const_char_ptr)
570 {
571 /* Strings does not need to be in read-only memory section, flag indicates
572 * that n first strings are read only.
573 */
574 char test_str[] = "test %s %s %d %s";
575 static const char cstr[] = "const";
576
577 char test_str1[] = "test str1";
578 static const char test_str2[] = "test str2";
579
580 /* Test skipped for cases where static const data is not located in
581 * read-only section.
582 */
583 if (!linker_is_in_rodata(test_str)) {
584 ztest_test_skip();
585 }
586
587 #define TEST_FMT test_str, cstr, test_str1, 100, test_str2
588 char exp_str[256];
589
590 snprintfcb(exp_str, sizeof(exp_str), TEST_FMT);
591
592
593 /* Use flag which is causing all const char pointers to be considered as
594 * read only strings.
595 */
596 uint32_t flags = CBPRINTF_PACKAGE_CONST_CHAR_RO |
597 CBPRINTF_PACKAGE_ADD_RO_STR_POS |
598 CBPRINTF_PACKAGE_ADD_RW_STR_POS;
599
600 int len = cbprintf_package(NULL, 0, flags, TEST_FMT);
601 int slen;
602
603 CBPRINTF_STATIC_PACKAGE(NULL, 0, slen, ALIGN_OFFSET, flags, TEST_FMT);
604 zassert_true(len > 0);
605 zassert_equal(len, slen);
606
607 uint8_t __aligned(CBPRINTF_PACKAGE_ALIGNMENT) package[len];
608 uint8_t __aligned(CBPRINTF_PACKAGE_ALIGNMENT) spackage[len];
609
610 memset(package, 0, len);
611 memset(spackage, 0, len);
612
613 int len2 = cbprintf_package(package, sizeof(package), flags, TEST_FMT);
614
615 CBPRINTF_STATIC_PACKAGE(spackage, sizeof(spackage), slen, ALIGN_OFFSET, flags, TEST_FMT);
616 zassert_equal(len, len2);
617 zassert_equal(slen, len2);
618 zassert_equal(memcmp(package, spackage, len), 0);
619
620 uint8_t *hdr = package;
621
622 /* Check that expected number of ro and rw locations are present and no
623 * strings appended.
624 */
625 zassert_equal(hdr[1], 0);
626 zassert_equal(hdr[2], 3);
627 zassert_equal(hdr[3], 1);
628
629 int clen;
630
631 /* Calculate size needed for package with appended read-only strings. */
632 clen = cbprintf_package_copy(package, sizeof(package), NULL, 0,
633 CBPRINTF_PACKAGE_CONVERT_RO_STR, NULL, 0);
634
635 /* Length will be increased by 2 string lengths + null terminators. */
636 size_t str_append_len = (int)strlen(test_str) +
637 (int)strlen(cstr) +
638 (int)strlen(test_str2) + 3;
639 zassert_equal(clen, len + (int)str_append_len);
640
641 uint8_t __aligned(CBPRINTF_PACKAGE_ALIGNMENT) cpackage[clen];
642
643 int clen2 = cbprintf_package_copy(package, sizeof(package), cpackage, sizeof(cpackage),
644 CBPRINTF_PACKAGE_CONVERT_RO_STR, NULL, 0);
645
646 zassert_equal(clen, clen2);
647
648 uint8_t *chdr = cpackage;
649
650 /* Check that read only strings have been appended. */
651 zassert_equal(chdr[1], 3);
652 zassert_equal(chdr[2], 0);
653 zassert_equal(chdr[3], 1);
654
655 check_package(package, len, exp_str);
656 check_package(cpackage, clen, exp_str);
657
658 /* Calculate size needed for package with appended read-write strings. */
659 clen = cbprintf_package_copy(package, sizeof(package), NULL, 0,
660 CBPRINTF_PACKAGE_CONVERT_RW_STR, NULL, 0);
661
662 /* Length will be increased by 1 string length + null terminator. */
663 zassert_equal(clen, len + (int)strlen(test_str1) + 1);
664
665 uint8_t __aligned(CBPRINTF_PACKAGE_ALIGNMENT) cpackage2[clen];
666
667 clen2 = cbprintf_package_copy(package, sizeof(package), cpackage2, sizeof(cpackage2),
668 CBPRINTF_PACKAGE_CONVERT_RW_STR, NULL, 0);
669
670 zassert_equal(clen, clen2);
671
672 chdr = cpackage2;
673
674 /* Check that read write strings have been appended. */
675 zassert_equal(chdr[1], 1);
676 zassert_equal(chdr[2], 3);
677 zassert_equal(chdr[3], 0);
678
679 check_package(package, len, exp_str);
680 check_package(cpackage2, clen, exp_str);
681 #undef TEST_FMT
682 }
683
cbprintf_rw_loc_const_char_ptr(bool keep_ro_str)684 static void cbprintf_rw_loc_const_char_ptr(bool keep_ro_str)
685 {
686 /* Test requires that static packaging is applied. Runtime packaging
687 * cannot be tricked because it checks pointers against read only
688 * section.
689 */
690 if (Z_C_GENERIC == 0) {
691 ztest_test_skip();
692 }
693
694 int slen, slen2;
695 int clen, clen2;
696 static const char test_str[] = "test %s %d %s";
697 char test_str1[] = "test str1";
698 static const char test_str2[] = "test str2";
699 /* Store indexes of rw strings. */
700 uint32_t flags = CBPRINTF_PACKAGE_ADD_RW_STR_POS;
701 uint8_t *hdr;
702
703 /* Test skipped for cases where static const data is not located in
704 * read-only section.
705 */
706 if (!linker_is_in_rodata(test_str)) {
707 ztest_test_skip();
708 }
709
710 #define TEST_FMT test_str, test_str1, 100, test_str2
711 char exp_str[256];
712
713 snprintfcb(exp_str, sizeof(exp_str), TEST_FMT);
714
715 CBPRINTF_STATIC_PACKAGE(NULL, 0, slen, ALIGN_OFFSET, flags, TEST_FMT);
716 zassert_true(slen > 0);
717
718 uint8_t __aligned(CBPRINTF_PACKAGE_ALIGNMENT) spackage[slen];
719
720 memset(spackage, 0, slen);
721
722 CBPRINTF_STATIC_PACKAGE(spackage, sizeof(spackage), slen2, ALIGN_OFFSET, flags, TEST_FMT);
723 zassert_equal(slen, slen2);
724
725 hdr = spackage;
726
727 /* Check that expected number of ro and rw locations are present and no
728 * strings appended.
729 */
730 zassert_equal(hdr[1], 0);
731 zassert_equal(hdr[2], 0);
732 zassert_equal(hdr[3], 2);
733
734 uint32_t copy_flags = CBPRINTF_PACKAGE_CONVERT_RW_STR |
735 (keep_ro_str ? CBPRINTF_PACKAGE_CONVERT_KEEP_RO_STR : 0);
736
737 /* Calculate size needed for package with appended read-only strings. */
738 clen = cbprintf_package_copy(spackage, sizeof(spackage), NULL, 0,
739 copy_flags, NULL, 0);
740
741 /* Previous len + string length + null terminator - argument index -
742 * decrease size of ro str location. If it is kept then it is decreased
743 * by 1 (argument index is dropped) if it is discarded then it is decreased
744 * by 2 (argument index + position dropped).
745 */
746 int exp_len = slen + (int)strlen(test_str1) + 1 - 1 - (keep_ro_str ? 1 : 2);
747
748 /* Length will be increased by string length + null terminator. */
749 zassert_equal(clen, exp_len, "clen:%d exp_len:%d", clen, exp_len);
750
751 uint8_t __aligned(CBPRINTF_PACKAGE_ALIGNMENT) cpackage[clen];
752
753 clen2 = cbprintf_package_copy(spackage, sizeof(spackage), cpackage, sizeof(cpackage),
754 copy_flags, NULL, 0);
755
756 zassert_equal(clen, clen2);
757
758 hdr = cpackage;
759
760 /* Check that one string has been appended. Second is detected to be RO */
761 zassert_equal(hdr[1], 1);
762 zassert_equal(hdr[2], keep_ro_str ? 1 : 0);
763 zassert_equal(hdr[3], 0);
764
765 check_package(spackage, slen, exp_str);
766 test_str1[0] = '\0';
767 check_package(cpackage, clen, exp_str);
768 #undef TEST_FMT
769 }
770
ZTEST(cbprintf_package,test_cbprintf_rw_loc_const_char_ptr)771 ZTEST(cbprintf_package, test_cbprintf_rw_loc_const_char_ptr)
772 {
773 cbprintf_rw_loc_const_char_ptr(true);
774 cbprintf_rw_loc_const_char_ptr(false);
775 }
776
ZTEST(cbprintf_package,test_cbprintf_must_runtime_package)777 ZTEST(cbprintf_package, test_cbprintf_must_runtime_package)
778 {
779 int rv;
780
781 if (Z_C_GENERIC == 0) {
782 ztest_test_skip();
783 }
784
785 rv = CBPRINTF_MUST_RUNTIME_PACKAGE(0, "test");
786 zassert_equal(rv, 0);
787
788 rv = CBPRINTF_MUST_RUNTIME_PACKAGE(0, "test %x", 100);
789 zassert_equal(rv, 0);
790
791 rv = CBPRINTF_MUST_RUNTIME_PACKAGE(0, "test %x %s", 100, "");
792 zassert_equal(rv, 1);
793
794 rv = CBPRINTF_MUST_RUNTIME_PACKAGE(CBPRINTF_PACKAGE_CONST_CHAR_RO, "test %x", 100);
795 zassert_equal(rv, 0);
796
797 rv = CBPRINTF_MUST_RUNTIME_PACKAGE(CBPRINTF_PACKAGE_CONST_CHAR_RO,
798 "test %x %s", 100, (const char *)"s");
799 zassert_equal(rv, 0);
800
801 rv = CBPRINTF_MUST_RUNTIME_PACKAGE(CBPRINTF_PACKAGE_CONST_CHAR_RO,
802 "test %x %s %s", 100, (char *)"s", (const char *)"foo");
803 zassert_equal(rv, 1);
804
805 rv = CBPRINTF_MUST_RUNTIME_PACKAGE(CBPRINTF_PACKAGE_FIRST_RO_STR_CNT(1),
806 "test %s", (char *)"s");
807 zassert_equal(rv, 0);
808
809 rv = CBPRINTF_MUST_RUNTIME_PACKAGE(CBPRINTF_PACKAGE_FIRST_RO_STR_CNT(2),
810 "test %s %s %d", (const char *)"s", (char *)"s", 10);
811 zassert_equal(rv, 0);
812
813 rv = CBPRINTF_MUST_RUNTIME_PACKAGE(CBPRINTF_PACKAGE_FIRST_RO_STR_CNT(2),
814 "test %s %s %s", (const char *)"s", (char *)"s", "s");
815 zassert_equal(rv, 1);
816
817 rv = CBPRINTF_MUST_RUNTIME_PACKAGE(CBPRINTF_PACKAGE_FIRST_RO_STR_CNT(1) |
818 CBPRINTF_PACKAGE_CONST_CHAR_RO,
819 "test %s %s %d", (char *)"s", (const char *)"s", 10);
820 zassert_equal(rv, 0);
821
822 /* When RW str positions are stored static packaging can always be used */
823 rv = CBPRINTF_MUST_RUNTIME_PACKAGE(CBPRINTF_PACKAGE_ADD_RW_STR_POS,
824 "test %s %s %d", (char *)"s", (const char *)"s", 10);
825 zassert_equal(rv, 0);
826 }
827
828 struct test_cbprintf_covert_ctx {
829 uint8_t buf[256];
830 size_t offset;
831 bool null;
832 };
833
convert_cb(const void * buf,size_t len,void * context)834 static int convert_cb(const void *buf, size_t len, void *context)
835 {
836 struct test_cbprintf_covert_ctx *ctx = (struct test_cbprintf_covert_ctx *)context;
837
838 zassert_false(ctx->null);
839 if (buf) {
840 zassert_false(ctx->null);
841 zassert_true(ctx->offset + len <= sizeof(ctx->buf));
842 memcpy(&ctx->buf[ctx->offset], buf, len);
843 ctx->offset += len;
844 return len;
845 }
846
847 /* At the end of conversion callback should be called with null
848 * buffer to indicate the end.
849 */
850 ctx->null = true;
851 return 0;
852 }
853
ZTEST(cbprintf_package,test_cbprintf_package_convert)854 ZTEST(cbprintf_package, test_cbprintf_package_convert)
855 {
856 int slen, clen;
857 static const char test_str[] = "test %s %d %s";
858 char test_str1[] = "test str1";
859 static const char test_str2[] = "test str2";
860 /* Store indexes of rw strings. */
861 uint32_t flags = CBPRINTF_PACKAGE_ADD_RW_STR_POS;
862 struct test_cbprintf_covert_ctx ctx;
863
864 #define TEST_FMT test_str, test_str1, 100, test_str2
865 char exp_str[256];
866
867 snprintfcb(exp_str, sizeof(exp_str), TEST_FMT);
868
869 slen = cbprintf_package(NULL, 0, flags, TEST_FMT);
870 zassert_true(slen > 0);
871
872 uint8_t __aligned(CBPRINTF_PACKAGE_ALIGNMENT) spackage[slen];
873
874 memset(&ctx, 0, sizeof(ctx));
875 memset(spackage, 0, slen);
876
877 slen = cbprintf_package(spackage, slen, flags, TEST_FMT);
878 zassert_true(slen > 0);
879
880 uint32_t copy_flags = CBPRINTF_PACKAGE_CONVERT_RW_STR |
881 CBPRINTF_PACKAGE_CONVERT_KEEP_RO_STR;
882
883 clen = cbprintf_package_convert(spackage, slen, NULL, 0, copy_flags, NULL, 0);
884 zassert_true(clen > 0);
885
886 clen = cbprintf_package_convert(spackage, slen, convert_cb, &ctx, copy_flags, NULL, 0);
887 zassert_true(clen > 0);
888 zassert_true(ctx.null);
889 zassert_equal((int)ctx.offset, clen);
890
891 check_package(ctx.buf, ctx.offset, exp_str);
892 #undef TEST_FMT
893
894 }
895
ZTEST(cbprintf_package,test_cbprintf_package_convert_static)896 ZTEST(cbprintf_package, test_cbprintf_package_convert_static)
897 {
898 int slen, clen, olen;
899 static const char test_str[] = "test %s";
900 char test_str1[] = "test str1";
901 /* Store indexes of rw strings. */
902 uint32_t flags = CBPRINTF_PACKAGE_ADD_RW_STR_POS |
903 CBPRINTF_PACKAGE_FIRST_RO_STR_CNT(0) |
904 CBPRINTF_PACKAGE_ADD_STRING_IDXS;
905 struct test_cbprintf_covert_ctx ctx;
906
907 #define TEST_FMT test_str, test_str1
908 char exp_str[256];
909
910 snprintfcb(exp_str, sizeof(exp_str), TEST_FMT);
911
912 CBPRINTF_STATIC_PACKAGE(NULL, 0, slen, CBPRINTF_PACKAGE_ALIGNMENT, flags, TEST_FMT);
913 zassert_true(slen > 0);
914
915 uint8_t __aligned(CBPRINTF_PACKAGE_ALIGNMENT) spackage[slen];
916
917 memset(&ctx, 0, sizeof(ctx));
918 memset(spackage, 0, slen);
919
920 CBPRINTF_STATIC_PACKAGE(spackage, slen, olen, CBPRINTF_PACKAGE_ALIGNMENT, flags, TEST_FMT);
921 zassert_equal(olen, slen);
922
923 uint32_t copy_flags = CBPRINTF_PACKAGE_CONVERT_RW_STR;
924
925 clen = cbprintf_package_convert(spackage, slen, NULL, 0, copy_flags, NULL, 0);
926 zassert_true(clen == slen + sizeof(test_str1) + 1/*null*/ - 2 /* arg+ro idx gone*/);
927
928 clen = cbprintf_package_convert(spackage, slen, convert_cb, &ctx, copy_flags, NULL, 0);
929 zassert_true(clen > 0);
930 zassert_true(ctx.null);
931 zassert_equal((int)ctx.offset, clen);
932
933 check_package(ctx.buf, ctx.offset, exp_str);
934 #undef TEST_FMT
935
936 }
937
938 /**
939 * @brief Log information about variable sizes and alignment.
940 *
941 * @return NULL as we are not supplying any fixture object.
942 */
print_size_and_alignment_info(void)943 static void *print_size_and_alignment_info(void)
944 {
945 #ifdef __cplusplus
946 printk("C++\n");
947 #else
948 printk("sizeof: int=%zu long=%zu ptr=%zu long long=%zu double=%zu long double=%zu\n",
949 sizeof(int), sizeof(long), sizeof(void *), sizeof(long long), sizeof(double),
950 sizeof(long double));
951 printk("alignof: int=%zu long=%zu ptr=%zu long long=%zu double=%zu long double=%zu\n",
952 __alignof__(int), __alignof__(long), __alignof__(void *), __alignof__(long long),
953 __alignof__(double), __alignof__(long double));
954 printk("%s C11 _Generic\n", Z_C_GENERIC ? "With" : "Without");
955 #endif
956
957 return NULL;
958 }
959
960 ZTEST_SUITE(cbprintf_package, NULL, print_size_and_alignment_info, NULL, NULL, NULL);
961