lib: os: cbprintf: Add support for conversion to fsc package

Added support for conversion from a standard package which contains
pointers to read only strings to fully self-contained (fsc) package.
Fsc package contains all strings associated with the package thus
access to read only strings is not needed to format a string.

In order to allow conversion to fsc package, standard package must
contain locations of all string pointers within the package. Appending
that information is optional and is controlled by flags parameter
which was added to packaging API. If option flag is set then
package contains header, arguments, locations of read only strings and
transient strings (each prefixed with string argument location).
Package header has been extended with field which contains number of
read only string locations.

A function for conversion to fsc package has been added
(cbprintf_fsc_package()).

Signed-off-by: Krzysztof Chruscinski <krzysztof.chruscinski@nordicsemi.no>
This commit is contained in:
Krzysztof Chruscinski 2021-07-22 13:19:59 +02:00 committed by Carles Cufí
commit 5d80cbae59
8 changed files with 282 additions and 49 deletions

View file

@ -219,12 +219,13 @@ enum z_log_msg2_mode {
#define Z_LOG_MSG2_SYNC(_domain_id, _source, _level, _data, _dlen, ...) do { \
int _plen; \
CBPRINTF_STATIC_PACKAGE(NULL, 0, _plen, Z_LOG_MSG2_ALIGN_OFFSET, \
__VA_ARGS__); \
0, __VA_ARGS__); \
struct log_msg2 *_msg; \
Z_LOG_MSG2_ON_STACK_ALLOC(_msg, Z_LOG_MSG2_LEN(_plen, _dlen)); \
if (_plen) {\
CBPRINTF_STATIC_PACKAGE(_msg->data, _plen, _plen, \
Z_LOG_MSG2_ALIGN_OFFSET, __VA_ARGS__); \
Z_LOG_MSG2_ALIGN_OFFSET, \
0, __VA_ARGS__); \
} \
struct log_msg2_desc _desc = \
Z_LOG_MSG_DESC_INITIALIZER(_domain_id, _level, \
@ -238,15 +239,15 @@ do { \
if (GET_ARG_N(1, __VA_ARGS__) == NULL) { \
_plen = 0; \
} else { \
CBPRINTF_STATIC_PACKAGE(NULL, 0, _plen, \
Z_LOG_MSG2_ALIGN_OFFSET, __VA_ARGS__); \
CBPRINTF_STATIC_PACKAGE(NULL, 0, _plen, Z_LOG_MSG2_ALIGN_OFFSET, \
0, __VA_ARGS__); \
} \
struct log_msg2 *_msg; \
Z_LOG_MSG2_ON_STACK_ALLOC(_msg, Z_LOG_MSG2_LEN(_plen, 0)); \
if (_plen) { \
CBPRINTF_STATIC_PACKAGE(_msg->data, _plen, \
_plen, Z_LOG_MSG2_ALIGN_OFFSET, \
__VA_ARGS__);\
0, __VA_ARGS__);\
} \
struct log_msg2_desc _desc = \
Z_LOG_MSG_DESC_INITIALIZER(_domain_id, _level, \
@ -260,7 +261,7 @@ do { \
#define Z_LOG_MSG2_SIMPLE_CREATE(_domain_id, _source, _level, ...) do { \
int _plen; \
CBPRINTF_STATIC_PACKAGE(NULL, 0, _plen, Z_LOG_MSG2_ALIGN_OFFSET, \
__VA_ARGS__); \
0, __VA_ARGS__); \
size_t _msg_wlen = Z_LOG_MSG2_ALIGNED_WLEN(_plen, 0); \
struct log_msg2 *_msg = z_log_msg2_alloc(_msg_wlen); \
struct log_msg2_desc _desc = \
@ -269,7 +270,8 @@ do { \
_plen, _msg); \
if (_msg) { \
CBPRINTF_STATIC_PACKAGE(_msg->data, _plen, _plen, \
Z_LOG_MSG2_ALIGN_OFFSET, __VA_ARGS__); \
Z_LOG_MSG2_ALIGN_OFFSET, \
0, __VA_ARGS__); \
} \
z_log_msg2_finalize(_msg, (void *)_source, _desc, NULL); \
} while (0)

View file

@ -63,6 +63,20 @@ extern "C" {
sizeof(long double) : MAX(sizeof(double), sizeof(long long)))
#endif
/**@defgroup CBPRINTF_PACKAGE_FLAGS Package flags.
* @{
*/
/** @brief Append indexes of read-only string arguments in the package.
*
* When used, package contains locations of read-only string arguments. Package
* with that information can be converted to fully self-contain package using
* @ref cbprintf_fsc_package.
*/
#define CBPRINTF_PACKAGE_ADD_STRING_IDXS BIT(0)
/**@} */
/** @brief Signature for a cbprintf callback function.
*
* This function expects two parameters:
@ -98,7 +112,7 @@ typedef int (*cbprintf_cb)(/* int c, void *ctx */);
* @retval 1 if string must be packaged in run time.
* @retval 0 string can be statically packaged.
*/
#define CBPRINTF_MUST_RUNTIME_PACKAGE(skip, .../* fmt, ... */) \
#define CBPRINTF_MUST_RUNTIME_PACKAGE(skip, ... /* fmt, ... */) \
Z_CBPRINTF_MUST_RUNTIME_PACKAGE(skip, __VA_ARGS__)
/** @brief Statically package string.
@ -126,12 +140,14 @@ typedef int (*cbprintf_cb)(/* int c, void *ctx */);
* that @p packaged is aligned to CBPRINTF_PACKAGE_ALIGNMENT so it must be
* multiply of CBPRINTF_PACKAGE_ALIGNMENT or 0.
*
* @param flags option flags. See @ref CBPRINTF_PACKAGE_FLAGS.
*
* @param ... formatted string with arguments. Format string must be constant.
*/
#define CBPRINTF_STATIC_PACKAGE(packaged, inlen, outlen, align_offset, \
#define CBPRINTF_STATIC_PACKAGE(packaged, inlen, outlen, align_offset, flags, \
... /* fmt, ... */) \
Z_CBPRINTF_STATIC_PACKAGE(packaged, inlen, outlen, \
align_offset, __VA_ARGS__)
align_offset, flags, __VA_ARGS__)
/** @brief Capture state required to output formatted data later.
*
@ -158,6 +174,8 @@ typedef int (*cbprintf_cb)(/* int c, void *ctx */);
* so it must be multiply of CBPRINTF_PACKAGE_ALIGNMENT or 0 when @p packaged is
* null.
*
* @param flags option flags. See @ref CBPRINTF_PACKAGE_FLAGS.
*
* @param format a standard ISO C format string with characters and conversion
* specifications.
*
@ -171,9 +189,10 @@ typedef int (*cbprintf_cb)(/* int c, void *ctx */);
* @retval -ENOSPC if @p packaged was not null and the space required to store
* exceed @p len.
*/
__printf_like(3, 4)
__printf_like(4, 5)
int cbprintf_package(void *packaged,
size_t len,
uint32_t flags,
const char *format,
...);
@ -197,6 +216,8 @@ int cbprintf_package(void *packaged,
* @param len this must be set to the number of bytes available at @p packaged.
* Ignored if @p packaged is NULL.
*
* @param flags option flags. See @ref CBPRINTF_PACKAGE_FLAGS.
*
* @param format a standard ISO C format string with characters and conversion
* specifications.
*
@ -211,9 +232,41 @@ int cbprintf_package(void *packaged,
*/
int cbvprintf_package(void *packaged,
size_t len,
uint32_t flags,
const char *format,
va_list ap);
/** @brief Convert package to fully self-contained (fsc) package.
*
* By default, package does not contain read only strings. However, if needed
* it may be converted to a fully self-contained package which contains all
* strings. In order to allow such conversion, original package must be created
* with @ref CBPRINTF_PACKAGE_ADD_STRING_IDXS flag. Such package will contain
* necessary data to find read only strings in the package and copy them into
* package body.
*
* @param in_packaged pointer to original package created with
* @ref CBPRINTF_PACKAGE_ADD_STRING_IDXS.
*
* @param in_len @p in_packaged length.
*
* @param packaged pointer to location where fully self-contained version of the
* input package will be written. Pass a null pointer to calculate space required.
*
* @param len must be set to the number of bytes available at @p packaged. Not
* used if @p packaged is null.
*
* @retval nonegative the number of bytes successfully stored at @p packaged.
* This will not exceed @p len. If @p packaged is null, calculated length.
* @retval -ENOSPC if @p packaged was not null and the space required to store
* exceed @p len.
* @retval -EINVAL if @p in_packaged is null.
*/
int cbprintf_fsc_package(void *in_packaged,
size_t in_len,
void *packaged,
size_t len);
/** @brief Generate the output for a previously captured format
* operation.
*

View file

@ -259,7 +259,9 @@ extern "C" {
*
* @param _arg argument.
*/
#define Z_CBPRINTF_PACK_ARG2(_buf, _idx, _align_offset, _max, _arg) do { \
#define Z_CBPRINTF_PACK_ARG2(_buf, _idx, _align_offset, _max, \
_cfg_flags, _s_idx, _s_buf, _arg) \
do { \
BUILD_ASSERT(!((sizeof(double) < VA_STACK_ALIGN(long double)) && \
Z_CBPRINTF_IS_LONGDOUBLE(_arg) && \
!IS_ENABLED(CONFIG_CBPRINTF_PACKAGE_LONGDOUBLE)),\
@ -269,6 +271,9 @@ extern "C" {
_align_offset += sizeof(int); \
} \
uint32_t _arg_size = Z_CBPRINTF_ARG_SIZE(_arg); \
if (Z_CBPRINTF_IS_PCHAR(_arg)) { \
_s_buf[_s_idx++] = _idx / sizeof(int); \
} \
if (_buf && _idx < (int)_max) { \
Z_CBPRINTF_STORE_ARG(&_buf[_idx], _arg); \
} \
@ -283,7 +288,8 @@ extern "C" {
* @param arg argument.
*/
#define Z_CBPRINTF_PACK_ARG(arg) \
Z_CBPRINTF_PACK_ARG2(_pbuf, _pkg_len, _pkg_offset, _pmax, arg)
Z_CBPRINTF_PACK_ARG2(_pbuf, _pkg_len, _pkg_offset, _pmax, _flags, \
_s_cnt, _s_buffer, arg)
/** @brief Package descriptor.
*
@ -294,6 +300,7 @@ extern "C" {
struct z_cbprintf_desc {
uint8_t len;
uint8_t str_cnt;
uint8_t ro_str_cnt;
};
/** @brief Package header. */
@ -325,10 +332,12 @@ union z_cbprintf_hdr {
* @param _align_offset Input buffer alignment offset in words. Where offset 0
* means that buffer is aligned to CBPRINTF_PACKAGE_ALIGNMENT.
*
* @param _flags Option flags. See @ref CBPRINTF_PACKAGE_FLAGS.
*
* @param ... String with variable list of arguments.
*/
#define Z_CBPRINTF_STATIC_PACKAGE_GENERIC(buf, _inlen, _outlen, _align_offset, \
... /* fmt, ... */) \
_flags, ... /* fmt, ... */) \
do { \
_Pragma("GCC diagnostic push") \
_Pragma("GCC diagnostic ignored \"-Wpointer-arith\"") \
@ -342,9 +351,13 @@ do { \
IF_ENABLED(CONFIG_CBPRINTF_STATIC_PACKAGE_CHECK_ALIGNMENT, \
(__ASSERT(!((uintptr_t)buf & (CBPRINTF_PACKAGE_ALIGNMENT - 1)), \
"Buffer must be aligned.");)) \
bool str_idxs = _flags & CBPRINTF_PACKAGE_ADD_STRING_IDXS; \
uint8_t *_pbuf = buf; \
uint8_t _s_cnt = 0; \
uint16_t _s_buffer[16]; \
size_t _pmax = (buf != NULL) ? _inlen : INT32_MAX; \
int _pkg_len = 0; \
int _total_len = 0; \
int _pkg_offset = _align_offset; \
union z_cbprintf_hdr *_len_loc; \
/* package starts with string address and field with length */ \
@ -357,14 +370,24 @@ do { \
_pkg_offset += sizeof(union z_cbprintf_hdr); \
/* Pack remaining arguments */\
FOR_EACH(Z_CBPRINTF_PACK_ARG, (;), __VA_ARGS__);\
_total_len = _pkg_len; \
if (str_idxs) {\
_total_len += _s_cnt; \
if (_pbuf) { \
for (int i = 0; i < _s_cnt; i++) { \
_pbuf[_pkg_len + i] = _s_buffer[i]; \
} \
} \
} \
/* Store length */ \
_outlen = (_pkg_len > (int)_pmax) ? -ENOSPC : _pkg_len; \
_outlen = (_total_len > (int)_pmax) ? -ENOSPC : _total_len; \
/* Store length in the header, set number of dumped strings to 0 */ \
if (_pbuf) { \
union z_cbprintf_hdr hdr = { \
.desc = { \
.len = (uint8_t)(_pkg_len / sizeof(int)), \
.str_cnt = 0, \
.ro_str_cnt = str_idxs ? _s_cnt : (uint8_t)0, \
} \
}; \
*_len_loc = hdr; \
@ -373,19 +396,19 @@ do { \
} while (0)
#if Z_C_GENERIC
#define Z_CBPRINTF_STATIC_PACKAGE(packaged, inlen, outlen, align_offset, \
#define Z_CBPRINTF_STATIC_PACKAGE(packaged, inlen, outlen, align_offset, flags, \
... /* fmt, ... */) \
Z_CBPRINTF_STATIC_PACKAGE_GENERIC(packaged, inlen, outlen, \
align_offset, __VA_ARGS__)
align_offset, flags, __VA_ARGS__)
#else
#define Z_CBPRINTF_STATIC_PACKAGE(packaged, inlen, outlen, align_offset, \
#define Z_CBPRINTF_STATIC_PACKAGE(packaged, inlen, outlen, align_offset, flags, \
... /* fmt, ... */) \
do { \
/* Small trick needed to avoid warning on always true */ \
if (((uintptr_t)packaged + 1) != 1) { \
outlen = cbprintf_package(packaged, inlen, __VA_ARGS__); \
outlen = cbprintf_package(packaged, inlen, flags, __VA_ARGS__); \
} else { \
outlen = cbprintf_package(NULL, align_offset, __VA_ARGS__); \
outlen = cbprintf_package(NULL, align_offset, flags, __VA_ARGS__); \
} \
} while (0)
#endif /* Z_C_GENERIC */