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