blob: 11fa466f2a7c6795371cf94f4fa10c912e78473b [file] [log] [blame]
/*
* Copyright (c) 2021 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/ztest.h>
#include <zephyr/sys/cbprintf.h>
#include <zephyr/linker/utils.h>
#define CBPRINTF_DEBUG 1
#ifndef CBPRINTF_PACKAGE_ALIGN_OFFSET
#define CBPRINTF_PACKAGE_ALIGN_OFFSET 0
#endif
#define ALIGN_OFFSET (sizeof(void *) * CBPRINTF_PACKAGE_ALIGN_OFFSET)
struct out_buffer {
char *buf;
size_t idx;
size_t size;
};
static int out(int c, void *dest)
{
int rv = EOF;
struct out_buffer *buf = (struct out_buffer *)dest;
if (buf->idx < buf->size) {
buf->buf[buf->idx++] = (char)(unsigned char)c;
rv = (int)(unsigned char)c;
}
return rv;
}
static char static_buf[512];
static char runtime_buf[512];
static char compare_buf[128];
static void dump(const char *desc, uint8_t *package, size_t len)
{
printk("%s package %p:\n", desc, package);
for (size_t i = 0; i < len; i++) {
printk("%02x ", package[i]);
}
printk("\n");
}
static void unpack(const char *desc, struct out_buffer *buf,
uint8_t *package, size_t len)
{
cbpprintf((cbprintf_cb)out, buf, package);
buf->buf[buf->idx] = 0;
zassert_equal(strcmp(buf->buf, compare_buf), 0,
"Strings differ\nexp: |%s|\ngot: |%s|\n",
compare_buf, buf->buf);
}
#define TEST_PACKAGING(flags, fmt, ...) do { \
int must_runtime = CBPRINTF_MUST_RUNTIME_PACKAGE(flags, fmt, __VA_ARGS__); \
zassert_equal(must_runtime, !Z_C_GENERIC, NULL); \
snprintfcb(compare_buf, sizeof(compare_buf), fmt, __VA_ARGS__); \
printk("-----------------------------------------\n"); \
printk("%s\n", compare_buf); \
uint8_t *pkg; \
struct out_buffer rt_buf = { \
.buf = runtime_buf, .idx = 0, .size = sizeof(runtime_buf) \
}; \
int rc = cbprintf_package(NULL, ALIGN_OFFSET, 0, fmt, __VA_ARGS__); \
zassert_true(rc > 0, "cbprintf_package() returned %d", rc); \
int len = rc; \
/* Aligned so the package is similar to the static one. */ \
uint8_t __aligned(CBPRINTF_PACKAGE_ALIGNMENT) \
rt_package[len + ALIGN_OFFSET]; \
memset(rt_package, 0, len + ALIGN_OFFSET); \
pkg = &rt_package[ALIGN_OFFSET]; \
rc = cbprintf_package(pkg, len, 0, fmt, __VA_ARGS__); \
zassert_equal(rc, len, "cbprintf_package() returned %d, expected %d", \
rc, len); \
dump("runtime", pkg, len); \
unpack("runtime", &rt_buf, pkg, len); \
struct out_buffer st_buf = { \
.buf = static_buf, .idx = 0, .size = sizeof(static_buf) \
}; \
CBPRINTF_STATIC_PACKAGE(NULL, 0, len, ALIGN_OFFSET, flags, fmt, __VA_ARGS__); \
zassert_true(len > 0, "CBPRINTF_STATIC_PACKAGE() returned %d", len); \
uint8_t __aligned(CBPRINTF_PACKAGE_ALIGNMENT) \
package[len + ALIGN_OFFSET];\
int outlen; \
pkg = &package[ALIGN_OFFSET]; \
CBPRINTF_STATIC_PACKAGE(pkg, len, outlen, ALIGN_OFFSET, flags, fmt, __VA_ARGS__);\
zassert_equal(len, outlen, NULL); \
dump("static", pkg, len); \
unpack("static", &st_buf, pkg, len); \
} while (0)
ZTEST(cbprintf_package, test_cbprintf_package)
{
volatile signed char sc = -11;
int i = 100;
char c = 'a';
static const short s = -300;
long li = -1111111111;
long long lli = 0x1122334455667788;
unsigned char uc = 100;
unsigned int ui = 0x12345;
unsigned short us = 0x1234;
unsigned long ul = 0xaabbaabb;
unsigned long long ull = 0xaabbaabbaabb;
void *vp = NULL;
static const char *str = "test";
char *pstr = (char *)str;
int rv;
/* tests to exercise different element alignments */
TEST_PACKAGING(0, "test long %x %lx %x", 0xb1b2b3b4, li, 0xe4e3e2e1);
TEST_PACKAGING(0, "test long long %x %llx %x", 0xb1b2b3b4, lli, 0xe4e3e2e1);
/* tests with varied elements */
TEST_PACKAGING(0, "test %d %hd %hhd", i, s, sc);
TEST_PACKAGING(0, "test %ld %llx %hhu %hu %u", li, lli, uc, us, ui);
TEST_PACKAGING(0, "test %lu %llu", ul, ull);
TEST_PACKAGING(0, "test %c %p", c, vp);
/* Runtime packaging is still possible when const strings are used. */
TEST_PACKAGING(CBPRINTF_PACKAGE_CONST_CHAR_RO,
"test %s %s", str, (const char *)pstr);
/* When flag is set but argument is char * runtime packaging must be used. */
rv = CBPRINTF_MUST_RUNTIME_PACKAGE(CBPRINTF_PACKAGE_CONST_CHAR_RO,
"test %s %s", str, pstr);
zassert_true(rv != 0, "Unexpected value %d", rv);
/* When const char * are used but flag is not used then runtime packaging must be used. */
rv = CBPRINTF_MUST_RUNTIME_PACKAGE(0, "test %s %s", str, (const char *)pstr);
zassert_true(rv != 0, "Unexpected value %d", rv);
rv = CBPRINTF_MUST_RUNTIME_PACKAGE(CBPRINTF_PACKAGE_CONST_CHAR_RO,
"test %s", (char *)str);
zassert_true(rv != 0, "Unexpected value %d", rv);
if (IS_ENABLED(CONFIG_CBPRINTF_FP_SUPPORT)) {
float f = -1.234f;
double d = 1.2333;
TEST_PACKAGING(0, "test double %x %f %x", 0xb1b2b3b4, d, 0xe4e3e2e1);
TEST_PACKAGING(0, "test %f %a", (double)f, d);
#if CONFIG_CBPRINTF_PACKAGE_LONGDOUBLE && !(defined(CONFIG_RISCV) && !defined(CONFIG_64BIT))
/* Excluding riscv32 which does not handle long double correctly. */
long double ld = 1.2333;
TEST_PACKAGING(0, "test %Lf", ld);
#endif
}
}
ZTEST(cbprintf_package, test_cbprintf_rw_str_indexes)
{
int len0, len1, len2;
static const char *test_str = "test %d %s";
static const char *test_str1 = "lorem ipsum";
uint8_t str_idx;
char *addr;
len0 = cbprintf_package(NULL, 0, 0, test_str, 100, test_str1);
if (len0 > (int)(4 * sizeof(void *))) {
TC_PRINT("Skipping test, platform does not detect RO strings.\n");
ztest_test_skip();
}
zassert_true(len0 > 0, NULL);
len1 = cbprintf_package(NULL, 0, CBPRINTF_PACKAGE_ADD_STRING_IDXS,
test_str, 100, test_str1);
zassert_true(len1 > 0, NULL);
CBPRINTF_STATIC_PACKAGE(NULL, 0, len2, 0,
CBPRINTF_PACKAGE_ADD_STRING_IDXS,
test_str, 100, test_str1);
zassert_true(len2 > 0, NULL);
/* package with string indexes will contain two more bytes holding indexes
* of string parameter locations.
*/
zassert_equal(len0 + 2, len1, NULL);
zassert_equal(len0 + 2, len2, NULL);
uint8_t __aligned(CBPRINTF_PACKAGE_ALIGNMENT) package0[len0];
uint8_t __aligned(CBPRINTF_PACKAGE_ALIGNMENT) package1[len1];
uint8_t __aligned(CBPRINTF_PACKAGE_ALIGNMENT) package2[len2];
len0 = cbprintf_package(package0, sizeof(package0), 0,
test_str, 100, test_str1);
len1 = cbprintf_package(package1, sizeof(package1) - 1,
CBPRINTF_PACKAGE_ADD_STRING_IDXS,
test_str, 100, test_str1);
zassert_equal(-ENOSPC, len1, NULL);
CBPRINTF_STATIC_PACKAGE(package2, sizeof(package2) - 1, len2, 0,
CBPRINTF_PACKAGE_ADD_STRING_IDXS,
test_str, 100, test_str1);
zassert_equal(-ENOSPC, len2, NULL);
len1 = cbprintf_package(package1, sizeof(package1),
CBPRINTF_PACKAGE_ADD_STRING_IDXS,
test_str, 100, test_str1);
zassert_equal(len0 + 2, len1, NULL);
CBPRINTF_STATIC_PACKAGE(package2, sizeof(package2), len2, 0,
CBPRINTF_PACKAGE_ADD_STRING_IDXS,
test_str, 100, test_str1);
zassert_equal(len0 + 2, len2, NULL);
union cbprintf_package_hdr *desc0 = (union cbprintf_package_hdr *)package0;
union cbprintf_package_hdr *desc1 = (union cbprintf_package_hdr *)package1;
union cbprintf_package_hdr *desc2 = (union cbprintf_package_hdr *)package2;
/* Compare descriptor content. Second package has one ro string index. */
zassert_equal(desc0->desc.ro_str_cnt, 0, NULL);
zassert_equal(desc1->desc.ro_str_cnt, 2, NULL);
zassert_equal(desc2->desc.ro_str_cnt, 2, NULL);
int *p = (int *)package1;
str_idx = package1[len0];
addr = *(char **)&p[str_idx];
zassert_equal(addr, test_str, NULL);
str_idx = package2[len0];
addr = *(char **)&p[str_idx];
zassert_equal(addr, test_str, NULL);
str_idx = package1[len0 + 1];
addr = *(char **)&p[str_idx];
zassert_equal(addr, test_str1, NULL);
str_idx = package2[len0 + 1];
addr = *(char **)&p[str_idx];
zassert_equal(addr, test_str1, NULL);
}
ZTEST(cbprintf_package, test_cbprintf_fsc_package)
{
int len;
static const char *test_str = "test %d %s";
static const char *test_str1 = "lorem ipsum";
char *addr;
int fsc_len;
len = cbprintf_package(NULL, 0, CBPRINTF_PACKAGE_ADD_STRING_IDXS,
test_str, 100, test_str1);
if (len > (int)(4 * sizeof(void *) + 2)) {
TC_PRINT("Skipping test, platform does not detect RO strings.\n");
ztest_test_skip();
}
uint8_t __aligned(CBPRINTF_PACKAGE_ALIGNMENT) package[len];
len = cbprintf_package(package, sizeof(package),
CBPRINTF_PACKAGE_ADD_STRING_IDXS,
test_str, 100, test_str1);
union cbprintf_package_hdr *desc = (union cbprintf_package_hdr *)package;
zassert_equal(desc->desc.ro_str_cnt, 2, NULL);
zassert_equal(desc->desc.str_cnt, 0, NULL);
/* Get length of fsc package. */
fsc_len = cbprintf_fsc_package(package, len, NULL, 0);
int exp_len = len + (int)strlen(test_str) + 1 + (int)strlen(test_str1) + 1;
zassert_equal(exp_len, fsc_len, NULL);
uint8_t __aligned(CBPRINTF_PACKAGE_ALIGNMENT) fsc_package[fsc_len];
fsc_len = cbprintf_fsc_package(package, len, fsc_package, sizeof(fsc_package) - 1);
zassert_equal(fsc_len, -ENOSPC, NULL);
fsc_len = cbprintf_fsc_package(package, len, fsc_package, sizeof(fsc_package));
zassert_equal((int)sizeof(fsc_package), fsc_len, NULL);
/* New package has no RO string locations, only copied one. */
desc = (union cbprintf_package_hdr *)fsc_package;
zassert_equal(desc->desc.ro_str_cnt, 0, NULL);
zassert_equal(desc->desc.str_cnt, 2, NULL);
/* Get pointer to the first string in the package. */
addr = (char *)&fsc_package[desc->desc.len * sizeof(int) + 1];
zassert_equal(strcmp(test_str, addr), 0, NULL);
/* Get address of the second string. */
addr += strlen(addr) + 2;
zassert_equal(strcmp(test_str1, addr), 0, NULL);
}
static void check_package(void *package, size_t len, const char *exp_str)
{
char out_str[128];
strcpy(compare_buf, exp_str);
struct out_buffer out_buf = {
.buf = out_str,
.idx = 0,
.size = sizeof(out_str)
};
unpack(NULL, &out_buf, (uint8_t *)package, len);
}
ZTEST(cbprintf_package, test_cbprintf_ro_loc)
{
static const char *test_str = "test %d";
uint32_t flags = CBPRINTF_PACKAGE_ADD_RO_STR_POS;
#define TEST_FMT test_str, 100
char exp_str[256];
snprintfcb(exp_str, sizeof(exp_str), TEST_FMT);
int len = cbprintf_package(NULL, 0, flags, TEST_FMT);
int slen;
CBPRINTF_STATIC_PACKAGE(NULL, 0, slen, ALIGN_OFFSET, flags, TEST_FMT);
zassert_true(len > 0, NULL);
zassert_equal(len, slen, "Runtime length: %d, static length: %d", len, slen);
uint8_t __aligned(CBPRINTF_PACKAGE_ALIGNMENT) package[len];
uint8_t __aligned(CBPRINTF_PACKAGE_ALIGNMENT) spackage[slen];
/*
* Since memcpy() is being done below, it is better to zero out
* both arrays as there might a paddings in the package headers
* which are not touched by packaging functions, where those bytes
* have whatever is in the stack.
*/
memset(package, 0, len);
memset(spackage, 0, slen);
len = cbprintf_package(package, sizeof(package), flags, TEST_FMT);
CBPRINTF_STATIC_PACKAGE(spackage, sizeof(spackage), slen, ALIGN_OFFSET, flags, TEST_FMT);
zassert_true(len > 0, NULL);
zassert_equal(len, slen, "Runtime length: %d, static length: %d", len, slen);
zassert_equal(memcmp(package, spackage, len), 0, NULL);
uint8_t *hdr = package;
/* Check that only read-only string location array size is non zero */
zassert_equal(hdr[1], 0, NULL);
zassert_equal(hdr[2], 1, NULL);
zassert_equal(hdr[3], 0, NULL);
int clen;
/* Calculate size needed for package with appended read-only strings. */
clen = cbprintf_package_copy(package, sizeof(package), NULL, 0,
CBPRINTF_PACKAGE_COPY_RO_STR, NULL, 0);
/* Length will be increased by string length + null terminator. */
zassert_equal(clen, len + (int)strlen(test_str) + 1, NULL);
uint8_t __aligned(CBPRINTF_PACKAGE_ALIGNMENT) cpackage[clen];
int clen2 = cbprintf_package_copy(package, sizeof(package), cpackage, sizeof(cpackage),
CBPRINTF_PACKAGE_COPY_RO_STR, NULL, 0);
zassert_equal(clen, clen2, NULL);
/* Length will be increased by string length + null terminator. */
zassert_equal(clen, len + (int)strlen(test_str) + 1, NULL);
uint8_t *chdr = cpackage;
/* Check that only package after copying has no locations but has
* appended string.
*/
zassert_equal(chdr[1], 1, NULL);
zassert_equal(chdr[2], 0, NULL);
zassert_equal(chdr[3], 0, NULL);
check_package(package, len, exp_str);
check_package(cpackage, clen, exp_str);
#undef TEST_FMT
}
/* Store read-only string by index when read-write string is appended. This
* is supported only by runtime packaging.
*/
ZTEST(cbprintf_package, test_cbprintf_ro_loc_rw_present)
{
static const char *test_str = "test %d %s";
char test_str1[] = "test str1";
uint32_t flags = CBPRINTF_PACKAGE_ADD_RO_STR_POS;
#define TEST_FMT test_str, 100, test_str1
char exp_str[256];
snprintfcb(exp_str, sizeof(exp_str), TEST_FMT);
int len = cbprintf_package(NULL, 0, flags, TEST_FMT);
zassert_true(len > 0, NULL);
uint8_t __aligned(CBPRINTF_PACKAGE_ALIGNMENT) package[len];
len = cbprintf_package(package, sizeof(package), flags, TEST_FMT);
zassert_true(len > 0, NULL);
uint8_t *hdr = package;
/* Check that only read-only string location array size is non zero */
zassert_equal(hdr[1], 1, NULL);
zassert_equal(hdr[2], 1, NULL);
zassert_equal(hdr[3], 0, NULL);
int clen;
/* Calculate size needed for package with appended read-only strings. */
clen = cbprintf_package_copy(package, sizeof(package), NULL, 0,
CBPRINTF_PACKAGE_COPY_RO_STR, NULL, 0);
/* Length will be increased by string length + null terminator. */
zassert_equal(clen, len + (int)strlen(test_str) + 1, NULL);
uint8_t __aligned(CBPRINTF_PACKAGE_ALIGNMENT) cpackage[clen];
int clen2 = cbprintf_package_copy(package, sizeof(package), cpackage, sizeof(cpackage),
CBPRINTF_PACKAGE_COPY_RO_STR, NULL, 0);
zassert_equal(clen, clen2, NULL);
/* Length will be increased by string length + null terminator. */
zassert_equal(clen, len + (int)strlen(test_str) + 1, NULL);
uint8_t *chdr = cpackage;
/* Check that only package after copying has no locations but has
* appended string.
*/
zassert_equal(chdr[1], 2, NULL);
zassert_equal(chdr[2], 0, NULL);
zassert_equal(chdr[3], 0, NULL);
check_package(package, clen, exp_str);
check_package(cpackage, clen, exp_str);
#undef TEST_FMT
}
ZTEST(cbprintf_package, test_cbprintf_ro_rw_loc)
{
/* Strings does not need to be in read-only memory section, flag indicates
* that n first strings are read only.
*/
char test_str[] = "test %s %s %d %s";
char cstr[] = "const";
char test_str1[] = "test str1";
char test_str2[] = "test str2";
#define TEST_FMT test_str, cstr, test_str1, 100, test_str2
char exp_str[256];
snprintfcb(exp_str, sizeof(exp_str), TEST_FMT);
uint32_t flags = CBPRINTF_PACKAGE_FIRST_RO_STR_CNT(1) |
CBPRINTF_PACKAGE_ADD_RO_STR_POS |
CBPRINTF_PACKAGE_ADD_RW_STR_POS;
int len = cbprintf_package(NULL, 0, flags, TEST_FMT);
int slen;
CBPRINTF_STATIC_PACKAGE(NULL, 0, slen, ALIGN_OFFSET, flags, TEST_FMT);
zassert_true(len > 0, NULL);
zassert_equal(len, slen, NULL);
uint8_t __aligned(CBPRINTF_PACKAGE_ALIGNMENT) package[len];
uint8_t __aligned(CBPRINTF_PACKAGE_ALIGNMENT) spackage[len];
memset(package, 0, len);
memset(spackage, 0, len);
int len2 = cbprintf_package(package, sizeof(package), flags, TEST_FMT);
CBPRINTF_STATIC_PACKAGE(spackage, sizeof(spackage), slen, ALIGN_OFFSET, flags, TEST_FMT);
zassert_equal(len, len2, NULL);
zassert_equal(slen, len2, NULL);
zassert_equal(memcmp(package, spackage, len), 0, NULL);
uint8_t *hdr = package;
/* Check that expected number of ro and rw locations are present and no
* strings appended.
*/
zassert_equal(hdr[1], 0, NULL);
zassert_equal(hdr[2], 2, NULL);
zassert_equal(hdr[3], 2, NULL);
int clen;
uint16_t strl[2] = {0};
/* Calculate size needed for package with appended read-only strings. */
clen = cbprintf_package_copy(package, sizeof(package), NULL, 0,
CBPRINTF_PACKAGE_COPY_RO_STR, strl, ARRAY_SIZE(strl));
/* Length will be increased by 2 string lengths + null terminators. */
zassert_equal(clen, len + (int)strlen(test_str) + (int)strlen(cstr) + 2, NULL);
zassert_equal(strl[0], strlen(test_str) + 1, NULL);
zassert_equal(strl[1], strlen(cstr) + 1, NULL);
uint8_t __aligned(CBPRINTF_PACKAGE_ALIGNMENT) cpackage[clen];
int clen2 = cbprintf_package_copy(package, sizeof(package), cpackage, sizeof(cpackage),
CBPRINTF_PACKAGE_COPY_RO_STR, strl, ARRAY_SIZE(strl));
zassert_equal(clen, clen2, NULL);
uint8_t *chdr = cpackage;
/* Check that read only strings have been appended. */
zassert_equal(chdr[1], 2, NULL);
zassert_equal(chdr[2], 0, NULL);
zassert_equal(chdr[3], 2, NULL);
check_package(package, len, exp_str);
check_package(cpackage, clen, exp_str);
uint32_t cpy_flags = CBPRINTF_PACKAGE_COPY_RW_STR |
CBPRINTF_PACKAGE_COPY_KEEP_RO_STR;
/* Calculate size needed for package with appended read-write strings. */
clen = cbprintf_package_copy(package, sizeof(package), NULL, 0,
cpy_flags, NULL, 0);
/* Length will be increased by 2 string lengths + null terminators. */
zassert_equal(clen, len + (int)strlen(test_str1) + (int)strlen(test_str2) + 2, NULL);
uint8_t __aligned(CBPRINTF_PACKAGE_ALIGNMENT) cpackage2[clen];
clen2 = cbprintf_package_copy(package, sizeof(package), cpackage2, sizeof(cpackage2),
cpy_flags, NULL, 0);
zassert_equal(clen, clen2, NULL);
chdr = cpackage2;
/* Check that read write strings have been appended. */
zassert_equal(chdr[1], 2, NULL);
zassert_equal(chdr[2], 2, NULL);
zassert_equal(chdr[3], 0, NULL);
check_package(package, len, exp_str);
check_package(cpackage2, clen, exp_str);
#undef TEST_FMT
}
ZTEST(cbprintf_package, test_cbprintf_ro_rw_loc_const_char_ptr)
{
/* Strings does not need to be in read-only memory section, flag indicates
* that n first strings are read only.
*/
char test_str[] = "test %s %s %d %s";
static const char cstr[] = "const";
char test_str1[] = "test str1";
static const char test_str2[] = "test str2";
/* Test skipped for cases where static const data is not located in
* read-only section.
*/
if (!linker_is_in_rodata(test_str)) {
ztest_test_skip();
}
#define TEST_FMT test_str, cstr, test_str1, 100, test_str2
char exp_str[256];
snprintfcb(exp_str, sizeof(exp_str), TEST_FMT);
/* Use flag which is causing all const char pointers to be considered as
* read only strings.
*/
uint32_t flags = CBPRINTF_PACKAGE_CONST_CHAR_RO |
CBPRINTF_PACKAGE_ADD_RO_STR_POS |
CBPRINTF_PACKAGE_ADD_RW_STR_POS;
int len = cbprintf_package(NULL, 0, flags, TEST_FMT);
int slen;
CBPRINTF_STATIC_PACKAGE(NULL, 0, slen, ALIGN_OFFSET, flags, TEST_FMT);
zassert_true(len > 0, NULL);
zassert_equal(len, slen, NULL);
uint8_t __aligned(CBPRINTF_PACKAGE_ALIGNMENT) package[len];
uint8_t __aligned(CBPRINTF_PACKAGE_ALIGNMENT) spackage[len];
memset(package, 0, len);
memset(spackage, 0, len);
int len2 = cbprintf_package(package, sizeof(package), flags, TEST_FMT);
CBPRINTF_STATIC_PACKAGE(spackage, sizeof(spackage), slen, ALIGN_OFFSET, flags, TEST_FMT);
zassert_equal(len, len2, NULL);
zassert_equal(slen, len2, NULL);
zassert_equal(memcmp(package, spackage, len), 0, NULL);
uint8_t *hdr = package;
/* Check that expected number of ro and rw locations are present and no
* strings appended.
*/
zassert_equal(hdr[1], 0, NULL);
zassert_equal(hdr[2], 3, NULL);
zassert_equal(hdr[3], 1, NULL);
int clen;
/* Calculate size needed for package with appended read-only strings. */
clen = cbprintf_package_copy(package, sizeof(package), NULL, 0,
CBPRINTF_PACKAGE_COPY_RO_STR, NULL, 0);
/* Length will be increased by 2 string lengths + null terminators. */
size_t str_append_len = (int)strlen(test_str) +
(int)strlen(cstr) +
(int)strlen(test_str2) + 3;
zassert_equal(clen, len + (int)str_append_len, NULL);
uint8_t __aligned(CBPRINTF_PACKAGE_ALIGNMENT) cpackage[clen];
int clen2 = cbprintf_package_copy(package, sizeof(package), cpackage, sizeof(cpackage),
CBPRINTF_PACKAGE_COPY_RO_STR, NULL, 0);
zassert_equal(clen, clen2, NULL);
uint8_t *chdr = cpackage;
/* Check that read only strings have been appended. */
zassert_equal(chdr[1], 3, NULL);
zassert_equal(chdr[2], 0, NULL);
zassert_equal(chdr[3], 1, NULL);
check_package(package, len, exp_str);
check_package(cpackage, clen, exp_str);
/* Calculate size needed for package with appended read-write strings. */
clen = cbprintf_package_copy(package, sizeof(package), NULL, 0,
CBPRINTF_PACKAGE_COPY_RW_STR, NULL, 0);
/* Length will be increased by 1 string length + null terminator. */
zassert_equal(clen, len + (int)strlen(test_str1) + 1, NULL);
uint8_t __aligned(CBPRINTF_PACKAGE_ALIGNMENT) cpackage2[clen];
clen2 = cbprintf_package_copy(package, sizeof(package), cpackage2, sizeof(cpackage2),
CBPRINTF_PACKAGE_COPY_RW_STR, NULL, 0);
zassert_equal(clen, clen2, NULL);
chdr = cpackage2;
/* Check that read write strings have been appended. */
zassert_equal(chdr[1], 1, NULL);
zassert_equal(chdr[2], 3, NULL);
zassert_equal(chdr[3], 0, NULL);
check_package(package, len, exp_str);
check_package(cpackage2, clen, exp_str);
#undef TEST_FMT
}
static void cbprintf_rw_loc_const_char_ptr(bool keep_ro_str)
{
/* Test requires that static packaging is applied. Runtime packaging
* cannot be tricked because it checks pointers against read only
* section.
*/
if (Z_C_GENERIC == 0) {
ztest_test_skip();
}
int slen, slen2;
int clen, clen2;
static const char test_str[] = "test %s %d %s";
char test_str1[] = "test str1";
static const char test_str2[] = "test str2";
/* Store indexes of rw strings. */
uint32_t flags = CBPRINTF_PACKAGE_ADD_RW_STR_POS;
uint8_t *hdr;
/* Test skipped for cases where static const data is not located in
* read-only section.
*/
if (!linker_is_in_rodata(test_str)) {
ztest_test_skip();
}
#define TEST_FMT test_str, test_str1, 100, test_str2
char exp_str[256];
snprintfcb(exp_str, sizeof(exp_str), TEST_FMT);
CBPRINTF_STATIC_PACKAGE(NULL, 0, slen, ALIGN_OFFSET, flags, TEST_FMT);
zassert_true(slen > 0, NULL);
uint8_t __aligned(CBPRINTF_PACKAGE_ALIGNMENT) spackage[slen];
memset(spackage, 0, slen);
CBPRINTF_STATIC_PACKAGE(spackage, sizeof(spackage), slen2, ALIGN_OFFSET, flags, TEST_FMT);
zassert_equal(slen, slen2, NULL);
hdr = spackage;
/* Check that expected number of ro and rw locations are present and no
* strings appended.
*/
zassert_equal(hdr[1], 0, NULL);
zassert_equal(hdr[2], 0, NULL);
zassert_equal(hdr[3], 2, NULL);
uint32_t copy_flags = CBPRINTF_PACKAGE_COPY_RW_STR |
(keep_ro_str ? CBPRINTF_PACKAGE_COPY_KEEP_RO_STR : 0);
/* Calculate size needed for package with appended read-only strings. */
clen = cbprintf_package_copy(spackage, sizeof(spackage), NULL, 0,
copy_flags, NULL, 0);
int exp_len = slen + (int)strlen(test_str1) + 1 - (keep_ro_str ? 0 : 1);
/* Length will be increased by string length + null terminator. */
zassert_equal(clen, exp_len, NULL);
uint8_t __aligned(CBPRINTF_PACKAGE_ALIGNMENT) cpackage[clen];
clen2 = cbprintf_package_copy(spackage, sizeof(spackage), cpackage, sizeof(cpackage),
copy_flags, NULL, 0);
zassert_equal(clen, clen2, NULL);
hdr = cpackage;
/* Check that one string has been appended. Second is detected to be RO */
zassert_equal(hdr[1], 1, NULL);
zassert_equal(hdr[2], keep_ro_str ? 1 : 0, NULL);
zassert_equal(hdr[3], 0, NULL);
check_package(spackage, slen, exp_str);
test_str1[0] = '\0';
check_package(cpackage, clen, exp_str);
#undef TEST_FMT
}
ZTEST(cbprintf_package, test_cbprintf_rw_loc_const_char_ptr)
{
cbprintf_rw_loc_const_char_ptr(true);
cbprintf_rw_loc_const_char_ptr(false);
}
ZTEST(cbprintf_package, test_cbprintf_must_runtime_package)
{
int rv;
if (Z_C_GENERIC == 0) {
ztest_test_skip();
}
rv = CBPRINTF_MUST_RUNTIME_PACKAGE(0, "test");
zassert_equal(rv, 0, NULL);
rv = CBPRINTF_MUST_RUNTIME_PACKAGE(0, "test %x", 100);
zassert_equal(rv, 0, NULL);
rv = CBPRINTF_MUST_RUNTIME_PACKAGE(0, "test %x %s", 100, "");
zassert_equal(rv, 1, NULL);
rv = CBPRINTF_MUST_RUNTIME_PACKAGE(CBPRINTF_PACKAGE_CONST_CHAR_RO, "test %x", 100);
zassert_equal(rv, 0, NULL);
rv = CBPRINTF_MUST_RUNTIME_PACKAGE(CBPRINTF_PACKAGE_CONST_CHAR_RO,
"test %x %s", 100, (const char *)"s");
zassert_equal(rv, 0, NULL);
rv = CBPRINTF_MUST_RUNTIME_PACKAGE(CBPRINTF_PACKAGE_CONST_CHAR_RO,
"test %x %s %s", 100, (char *)"s", (const char *)"foo");
zassert_equal(rv, 1, NULL);
rv = CBPRINTF_MUST_RUNTIME_PACKAGE(CBPRINTF_PACKAGE_FIRST_RO_STR_CNT(1),
"test %s", (char *)"s");
zassert_equal(rv, 0, NULL);
rv = CBPRINTF_MUST_RUNTIME_PACKAGE(CBPRINTF_PACKAGE_FIRST_RO_STR_CNT(2),
"test %s %s %d", (const char *)"s", (char *)"s", 10);
zassert_equal(rv, 0, NULL);
rv = CBPRINTF_MUST_RUNTIME_PACKAGE(CBPRINTF_PACKAGE_FIRST_RO_STR_CNT(2),
"test %s %s %s", (const char *)"s", (char *)"s", "s");
zassert_equal(rv, 1, NULL);
rv = CBPRINTF_MUST_RUNTIME_PACKAGE(CBPRINTF_PACKAGE_FIRST_RO_STR_CNT(1) |
CBPRINTF_PACKAGE_CONST_CHAR_RO,
"test %s %s %d", (char *)"s", (const char *)"s", 10);
zassert_equal(rv, 0, NULL);
/* When RW str positions are stored static packaging can always be used */
rv = CBPRINTF_MUST_RUNTIME_PACKAGE(CBPRINTF_PACKAGE_ADD_RW_STR_POS,
"test %s %s %d", (char *)"s", (const char *)"s", 10);
zassert_equal(rv, 0, NULL);
}
struct test_cbprintf_covert_ctx {
uint8_t buf[256];
size_t offset;
bool null;
};
static int convert_cb(const void *buf, size_t len, void *context)
{
struct test_cbprintf_covert_ctx *ctx = (struct test_cbprintf_covert_ctx *)context;
zassert_false(ctx->null, NULL);
if (buf) {
zassert_false(ctx->null, NULL);
zassert_true(ctx->offset + len <= sizeof(ctx->buf), NULL);
memcpy(&ctx->buf[ctx->offset], buf, len);
ctx->offset += len;
return len;
}
/* At the end of conversion callback should be called with null
* buffer to indicate the end.
*/
ctx->null = true;
return 0;
}
ZTEST(cbprintf_package, test_cbprintf_package_convert)
{
int slen, clen;
static const char test_str[] = "test %s %d %s";
char test_str1[] = "test str1";
static const char test_str2[] = "test str2";
/* Store indexes of rw strings. */
uint32_t flags = CBPRINTF_PACKAGE_ADD_RW_STR_POS;
struct test_cbprintf_covert_ctx ctx;
#define TEST_FMT test_str, test_str1, 100, test_str2
char exp_str[256];
snprintfcb(exp_str, sizeof(exp_str), TEST_FMT);
slen = cbprintf_package(NULL, 0, flags, TEST_FMT);
zassert_true(slen > 0, NULL);
uint8_t __aligned(CBPRINTF_PACKAGE_ALIGNMENT) spackage[slen];
memset(&ctx, 0, sizeof(ctx));
memset(spackage, 0, slen);
slen = cbprintf_package(spackage, slen, flags, TEST_FMT);
zassert_true(slen > 0, NULL);
uint32_t copy_flags = CBPRINTF_PACKAGE_COPY_RW_STR |
CBPRINTF_PACKAGE_COPY_KEEP_RO_STR;
clen = cbprintf_package_convert(spackage, slen, NULL, 0, copy_flags, NULL, 0);
zassert_true(clen > 0, NULL);
clen = cbprintf_package_convert(spackage, slen, convert_cb, &ctx, copy_flags, NULL, 0);
zassert_true(clen > 0, NULL);
zassert_true(ctx.null, NULL);
zassert_equal(ctx.offset, clen, NULL);
check_package(ctx.buf, ctx.offset, exp_str);
#undef TEST_FMT
}
/**
* @brief Log information about variable sizes and alignment.
*
* @return NULL as we are not supplying any fixture object.
*/
static void *print_size_and_alignment_info(void)
{
#ifdef __cplusplus
printk("C++\n");
#else
printk("sizeof: int=%zu long=%zu ptr=%zu long long=%zu double=%zu long double=%zu\n",
sizeof(int), sizeof(long), sizeof(void *), sizeof(long long), sizeof(double),
sizeof(long double));
printk("alignof: int=%zu long=%zu ptr=%zu long long=%zu double=%zu long double=%zu\n",
__alignof__(int), __alignof__(long), __alignof__(void *), __alignof__(long long),
__alignof__(double), __alignof__(long double));
printk("%s C11 _Generic\n", Z_C_GENERIC ? "With" : "Without");
#endif
return NULL;
}
ZTEST_SUITE(cbprintf_package, NULL, print_size_and_alignment_info, NULL, NULL, NULL);