Line data Source code
1 0 : /*
2 : * Copyright (c) 2021 Nordic Semiconductor ASA
3 : *
4 : * SPDX-License-Identifier: Apache-2.0
5 : */
6 : #ifndef ZEPHYR_INCLUDE_LOGGING_LOG_MSG_H_
7 : #define ZEPHYR_INCLUDE_LOGGING_LOG_MSG_H_
8 :
9 : #include <zephyr/logging/log_instance.h>
10 : #include <zephyr/sys/mpsc_packet.h>
11 : #include <zephyr/sys/cbprintf.h>
12 : #include <zephyr/sys/atomic.h>
13 : #include <zephyr/sys/iterable_sections.h>
14 : #include <zephyr/sys/util.h>
15 : #include <string.h>
16 : #include <zephyr/toolchain.h>
17 :
18 : #ifdef __GNUC__
19 : #ifndef alloca
20 : #define alloca __builtin_alloca
21 : #endif
22 : #else
23 : #include <alloca.h>
24 : #endif
25 :
26 : #ifdef __cplusplus
27 : extern "C" {
28 : #endif
29 :
30 0 : #define LOG_MSG_DEBUG 0
31 0 : #define LOG_MSG_DBG(...) IF_ENABLED(LOG_MSG_DEBUG, (printk(__VA_ARGS__)))
32 :
33 : #ifdef CONFIG_LOG_TIMESTAMP_64BIT
34 : typedef uint64_t log_timestamp_t;
35 : #else
36 0 : typedef uint32_t log_timestamp_t;
37 : #endif
38 :
39 : /**
40 : * @brief Log message API
41 : * @defgroup log_msg Log message API
42 : * @ingroup logger
43 : * @{
44 : */
45 :
46 : #define Z_LOG_MSG_LOG 0
47 :
48 : #define Z_LOG_MSG_PACKAGE_BITS 11
49 :
50 : #define Z_LOG_MSG_MAX_PACKAGE BIT_MASK(Z_LOG_MSG_PACKAGE_BITS)
51 :
52 0 : #define LOG_MSG_GENERIC_HDR \
53 : MPSC_PBUF_HDR;\
54 : uint32_t type:1
55 :
56 0 : struct log_msg_desc {
57 0 : LOG_MSG_GENERIC_HDR;
58 0 : uint32_t domain:3;
59 0 : uint32_t level:3;
60 0 : uint32_t package_len:Z_LOG_MSG_PACKAGE_BITS;
61 0 : uint32_t data_len:12;
62 : };
63 :
64 0 : union log_msg_source {
65 0 : const struct log_source_const_data *fixed;
66 0 : struct log_source_dynamic_data *dynamic;
67 0 : void *raw;
68 : };
69 :
70 0 : struct log_msg_hdr {
71 0 : struct log_msg_desc desc;
72 : /* Attempting to keep best alignment. When address is 64 bit and timestamp 32
73 : * swap the order to have 16 byte header instead of 24 byte.
74 : */
75 : #if (INTPTR_MAX > INT32_MAX) && !defined(CONFIG_LOG_TIMESTAMP_64BIT)
76 : log_timestamp_t timestamp;
77 : const void *source;
78 : #else
79 0 : const void *source;
80 0 : log_timestamp_t timestamp;
81 : #endif
82 : #if defined(CONFIG_LOG_THREAD_ID_PREFIX)
83 : void *tid;
84 : #endif
85 : };
86 : /* Messages are aligned to alignment required by cbprintf package. */
87 : #define Z_LOG_MSG_ALIGNMENT CBPRINTF_PACKAGE_ALIGNMENT
88 :
89 : #define Z_LOG_MSG_PADDING \
90 : ((sizeof(struct log_msg_hdr) % Z_LOG_MSG_ALIGNMENT) > 0 ? \
91 : (Z_LOG_MSG_ALIGNMENT - (sizeof(struct log_msg_hdr) % Z_LOG_MSG_ALIGNMENT)) : \
92 : 0)
93 :
94 0 : struct log_msg {
95 0 : struct log_msg_hdr hdr;
96 : /* Adding padding to ensure that cbprintf package that follows is
97 : * properly aligned.
98 : */
99 0 : uint8_t padding[Z_LOG_MSG_PADDING];
100 0 : uint8_t data[];
101 : };
102 :
103 : /**
104 : * @cond INTERNAL_HIDDEN
105 : */
106 : BUILD_ASSERT(sizeof(struct log_msg) % Z_LOG_MSG_ALIGNMENT == 0,
107 : "Log msg size must aligned");
108 : /**
109 : * @endcond
110 : */
111 :
112 :
113 0 : struct log_msg_generic_hdr {
114 0 : LOG_MSG_GENERIC_HDR;
115 : };
116 :
117 0 : union log_msg_generic {
118 0 : union mpsc_pbuf_generic buf;
119 0 : struct log_msg_generic_hdr generic;
120 0 : struct log_msg log;
121 : };
122 :
123 : /** @brief Method used for creating a log message.
124 : *
125 : * It is used for testing purposes to validate that expected mode was used.
126 : */
127 : enum z_log_msg_mode {
128 : /* Runtime mode is least efficient but supports all cases thus it is
129 : * treated as a fallback method when others cannot be used.
130 : */
131 : Z_LOG_MSG_MODE_RUNTIME,
132 : /* Mode creates statically a string package on stack and calls a
133 : * function for creating a message. It takes code size than
134 : * Z_LOG_MSG_MODE_ZERO_COPY but is a bit slower.
135 : */
136 : Z_LOG_MSG_MODE_FROM_STACK,
137 :
138 : /* Mode calculates size of the message and allocates it and writes
139 : * directly to the message space. It is the fastest method but requires
140 : * more code size.
141 : */
142 : Z_LOG_MSG_MODE_ZERO_COPY,
143 :
144 : /* Mode optimized for simple messages with 0 to 2 32 bit word arguments.*/
145 : Z_LOG_MSG_MODE_SIMPLE,
146 : };
147 :
148 : #define Z_LOG_MSG_DESC_INITIALIZER(_domain_id, _level, _plen, _dlen) \
149 : { \
150 : .valid = 0, \
151 : .busy = 0, \
152 : .type = Z_LOG_MSG_LOG, \
153 : .domain = (_domain_id), \
154 : .level = (_level), \
155 : .package_len = (_plen), \
156 : .data_len = (_dlen), \
157 : }
158 :
159 : #define Z_LOG_MSG_CBPRINTF_FLAGS(_cstr_cnt) \
160 : (CBPRINTF_PACKAGE_FIRST_RO_STR_CNT(_cstr_cnt) | \
161 : (IS_ENABLED(CONFIG_LOG_MSG_APPEND_RO_STRING_LOC) ? \
162 : CBPRINTF_PACKAGE_ADD_STRING_IDXS : 0))
163 :
164 : #ifdef CONFIG_LOG_USE_VLA
165 : #define Z_LOG_MSG_ON_STACK_ALLOC(ptr, len) \
166 : long long _ll_buf[DIV_ROUND_UP(len, sizeof(long long))]; \
167 : long double _ld_buf[DIV_ROUND_UP(len, sizeof(long double))]; \
168 : (ptr) = (sizeof(long double) == Z_LOG_MSG_ALIGNMENT) ? \
169 : (struct log_msg *)_ld_buf : (struct log_msg *)_ll_buf; \
170 : if (IS_ENABLED(CONFIG_LOG_TEST_CLEAR_MESSAGE_SPACE)) { \
171 : /* During test fill with 0's to simplify message comparison */ \
172 : memset((ptr), 0, (len)); \
173 : }
174 : #else /* Z_LOG_MSG_USE_VLA */
175 : /* When VLA cannot be used we need to trick compiler a bit and create multiple
176 : * fixed size arrays and take the smallest one that will fit the message.
177 : * Compiler will remove unused arrays and stack usage will be kept similar
178 : * to vla case, rounded to the size of the used buffer.
179 : */
180 : #define Z_LOG_MSG_ON_STACK_ALLOC(ptr, len) \
181 : long long _ll_buf32[32 / sizeof(long long)]; \
182 : long long _ll_buf48[48 / sizeof(long long)]; \
183 : long long _ll_buf64[64 / sizeof(long long)]; \
184 : long long _ll_buf128[128 / sizeof(long long)]; \
185 : long long _ll_buf256[256 / sizeof(long long)]; \
186 : long double _ld_buf32[32 / sizeof(long double)]; \
187 : long double _ld_buf48[48 / sizeof(long double)]; \
188 : long double _ld_buf64[64 / sizeof(long double)]; \
189 : long double _ld_buf128[128 / sizeof(long double)]; \
190 : long double _ld_buf256[256 / sizeof(long double)]; \
191 : if (sizeof(long double) == Z_LOG_MSG_ALIGNMENT) { \
192 : ptr = (len > 128) ? (struct log_msg *)_ld_buf256 : \
193 : ((len > 64) ? (struct log_msg *)_ld_buf128 : \
194 : ((len > 48) ? (struct log_msg *)_ld_buf64 : \
195 : ((len > 32) ? (struct log_msg *)_ld_buf48 : \
196 : (struct log_msg *)_ld_buf32)));\
197 : } else { \
198 : ptr = (len > 128) ? (struct log_msg *)_ll_buf256 : \
199 : ((len > 64) ? (struct log_msg *)_ll_buf128 : \
200 : ((len > 48) ? (struct log_msg *)_ll_buf64 : \
201 : ((len > 32) ? (struct log_msg *)_ll_buf48 : \
202 : (struct log_msg *)_ll_buf32)));\
203 : } \
204 : if (IS_ENABLED(CONFIG_LOG_TEST_CLEAR_MESSAGE_SPACE)) { \
205 : /* During test fill with 0's to simplify message comparison */ \
206 : memset((ptr), 0, (len)); \
207 : }
208 : #endif /* Z_LOG_MSG_USE_VLA */
209 :
210 : #define Z_LOG_MSG_ALIGN_OFFSET \
211 : offsetof(struct log_msg, data)
212 :
213 : #define Z_LOG_MSG_LEN(pkg_len, data_len) \
214 : (offsetof(struct log_msg, data) + (pkg_len) + (data_len))
215 :
216 : #define Z_LOG_MSG_ALIGNED_WLEN(pkg_len, data_len) \
217 : DIV_ROUND_UP(ROUND_UP(Z_LOG_MSG_LEN(pkg_len, data_len), \
218 : Z_LOG_MSG_ALIGNMENT), \
219 : sizeof(uint32_t))
220 :
221 : /*
222 : * With Zephyr SDK 0.14.2, aarch64-zephyr-elf-gcc (10.3.0) fails to ensure $sp
223 : * is below the active memory during message construction. As a result,
224 : * interrupts happening in the middle of that process can end up smashing active
225 : * data and causing a logging fault. Work around this by inserting a compiler
226 : * barrier after the allocation and before any use to make sure GCC moves the
227 : * stack pointer soon enough
228 : */
229 :
230 : #define Z_LOG_ARM64_VLA_PROTECT() compiler_barrier()
231 :
232 : #define _LOG_MSG_SIMPLE_XXXX0 1
233 : #define _LOG_MSG_SIMPLE_XXXX1 1
234 : #define _LOG_MSG_SIMPLE_XXXX2 1
235 :
236 : /* Determine if amount of arguments (less than 3) qualifies to simple message. */
237 0 : #define LOG_MSG_SIMPLE_ARG_CNT_CHECK(...) \
238 : COND_CODE_1(UTIL_CAT(_LOG_MSG_SIMPLE_XXXX, NUM_VA_ARGS_LESS_1(__VA_ARGS__)), (1), (0))
239 :
240 : /* Set of marcos used to determine if arguments type allows simplified message creation mode. */
241 0 : #define LOG_MSG_SIMPLE_ARG_TYPE_CHECK_0(fmt) 1
242 0 : #define LOG_MSG_SIMPLE_ARG_TYPE_CHECK_1(fmt, arg) Z_CBPRINTF_IS_WORD_NUM(arg)
243 0 : #define LOG_MSG_SIMPLE_ARG_TYPE_CHECK_2(fmt, arg0, arg1) \
244 : Z_CBPRINTF_IS_WORD_NUM(arg0) && Z_CBPRINTF_IS_WORD_NUM(arg1)
245 :
246 : /** brief Determine if string arguments types allow to use simplified message creation mode.
247 : *
248 : * @param ... String with arguments.
249 : */
250 1 : #define LOG_MSG_SIMPLE_ARG_TYPE_CHECK(...) \
251 : UTIL_CAT(LOG_MSG_SIMPLE_ARG_TYPE_CHECK_, NUM_VA_ARGS_LESS_1(__VA_ARGS__))(__VA_ARGS__)
252 :
253 : /** @brief Check if message can be handled using simplified method.
254 : *
255 : * Following conditions must be met:
256 : * - 32 bit platform
257 : * - Number of arguments from 0 to 2
258 : * - Type of an argument must be a numeric value that fits in 32 bit word.
259 : *
260 : * @param ... String with arguments.
261 : *
262 : * @retval 1 if message qualifies.
263 : * @retval 0 if message does not qualify.
264 : */
265 1 : #define LOG_MSG_SIMPLE_CHECK(...) \
266 : COND_CODE_1(CONFIG_64BIT, (0), (\
267 : COND_CODE_1(LOG_MSG_SIMPLE_ARG_CNT_CHECK(__VA_ARGS__), ( \
268 : LOG_MSG_SIMPLE_ARG_TYPE_CHECK(__VA_ARGS__)), (0))))
269 :
270 : /* Helper macro for handing log with one argument. Macro casts the first argument to uint32_t. */
271 : #define Z_LOG_MSG_SIMPLE_CREATE_1(_source, _level, ...) \
272 : z_log_msg_simple_create_1(_source, _level, GET_ARG_N(1, __VA_ARGS__), \
273 : (uint32_t)(uintptr_t)GET_ARG_N(2, __VA_ARGS__))
274 :
275 : /* Helper macro for handing log with two arguments. Macro casts arguments to uint32_t.
276 : */
277 : #define Z_LOG_MSG_SIMPLE_CREATE_2(_source, _level, ...) \
278 : z_log_msg_simple_create_2(_source, _level, GET_ARG_N(1, __VA_ARGS__), \
279 : (uint32_t)(uintptr_t)GET_ARG_N(2, __VA_ARGS__), \
280 : (uint32_t)(uintptr_t)GET_ARG_N(3, __VA_ARGS__))
281 :
282 : /* Call specific function based on the number of arguments.
283 : * Since up 2 to arguments are supported COND_CODE_0 and COND_CODE_1 can be used to
284 : * handle all cases (0, 1 and 2 arguments). When tracing is enable then for each
285 : * function a macro is create. The difference between function and macro is that
286 : * macro is applied to any input arguments so we need to make sure that it is
287 : * always called with proper number of arguments. For that it is wrapped around
288 : * into another macro and dummy arguments to cover for cases when there is less
289 : * arguments in a log call.
290 : */
291 : #define Z_LOG_MSG_SIMPLE_FUNC2(arg_cnt, _source, _level, ...) \
292 : COND_CODE_0(arg_cnt, \
293 : (z_log_msg_simple_create_0(_source, _level, GET_ARG_N(1, __VA_ARGS__))), \
294 : (COND_CODE_1(arg_cnt, ( \
295 : Z_LOG_MSG_SIMPLE_CREATE_1(_source, _level, __VA_ARGS__, dummy) \
296 : ), ( \
297 : Z_LOG_MSG_SIMPLE_CREATE_2(_source, _level, __VA_ARGS__, dummy, dummy) \
298 : ) \
299 : )))
300 :
301 : /** @brief Call specific function to create a log message.
302 : *
303 : * Macro picks matching function (based on number of arguments) and calls it.
304 : * String arguments are casted to uint32_t.
305 : *
306 : * @param _source Source.
307 : * @param _level Severity level.
308 : * @param ... String with arguments.
309 : */
310 1 : #define LOG_MSG_SIMPLE_FUNC(_source, _level, ...) \
311 : Z_LOG_MSG_SIMPLE_FUNC2(NUM_VA_ARGS_LESS_1(__VA_ARGS__), _source, _level, __VA_ARGS__)
312 :
313 : /** @brief Create log message using simplified method.
314 : *
315 : * Macro is gated by the argument count check to run @ref LOG_MSG_SIMPLE_FUNC only
316 : * on entries with 2 or less arguments.
317 : *
318 : * @param _domain_id Domain ID.
319 : * @param _source Pointer to the source structure.
320 : * @param _level Severity level.
321 : * @param ... String with arguments.
322 : */
323 : #define Z_LOG_MSG_SIMPLE_ARGS_CREATE(_domain_id, _source, _level, ...) \
324 : IF_ENABLED(LOG_MSG_SIMPLE_ARG_CNT_CHECK(__VA_ARGS__), (\
325 : LOG_MSG_SIMPLE_FUNC(_source, _level, __VA_ARGS__); \
326 : ))
327 :
328 : #define Z_LOG_MSG_STACK_CREATE(_cstr_cnt, _domain_id, _source, _level, _data, _dlen, ...) \
329 : do { \
330 : int _plen; \
331 : uint32_t _options = Z_LOG_MSG_CBPRINTF_FLAGS(_cstr_cnt) | \
332 : CBPRINTF_PACKAGE_ADD_RW_STR_POS; \
333 : if (GET_ARG_N(1, __VA_ARGS__) == NULL) { \
334 : _plen = 0; \
335 : } else { \
336 : CBPRINTF_STATIC_PACKAGE(NULL, 0, _plen, Z_LOG_MSG_ALIGN_OFFSET, _options, \
337 : __VA_ARGS__); \
338 : } \
339 : TOOLCHAIN_IGNORE_WSHADOW_BEGIN \
340 : struct log_msg *_msg; \
341 : TOOLCHAIN_IGNORE_WSHADOW_END \
342 : Z_LOG_MSG_ON_STACK_ALLOC(_msg, Z_LOG_MSG_LEN(_plen, 0)); \
343 : Z_LOG_ARM64_VLA_PROTECT(); \
344 : if (_plen != 0) { \
345 : CBPRINTF_STATIC_PACKAGE(_msg->data, _plen, \
346 : _plen, Z_LOG_MSG_ALIGN_OFFSET, _options, \
347 : __VA_ARGS__);\
348 : } \
349 : struct log_msg_desc _desc = \
350 : Z_LOG_MSG_DESC_INITIALIZER(_domain_id, _level, \
351 : (uint32_t)_plen, _dlen); \
352 : LOG_MSG_DBG("creating message on stack: package len: %d, data len: %d\n", \
353 : _plen, (int)(_dlen)); \
354 : z_log_msg_static_create((void *)(_source), _desc, _msg->data, (_data)); \
355 : } while (false)
356 :
357 : #ifdef CONFIG_LOG_SPEED
358 : #define Z_LOG_MSG_SIMPLE_CREATE(_cstr_cnt, _domain_id, _source, _level, ...) do { \
359 : int _plen; \
360 : CBPRINTF_STATIC_PACKAGE(NULL, 0, _plen, Z_LOG_MSG_ALIGN_OFFSET, \
361 : Z_LOG_MSG_CBPRINTF_FLAGS(_cstr_cnt), \
362 : __VA_ARGS__); \
363 : size_t _msg_wlen = Z_LOG_MSG_ALIGNED_WLEN(_plen, 0); \
364 : struct log_msg *_msg = z_log_msg_alloc(_msg_wlen); \
365 : struct log_msg_desc _desc = \
366 : Z_LOG_MSG_DESC_INITIALIZER(_domain_id, _level, (uint32_t)_plen, 0); \
367 : LOG_MSG_DBG("creating message zero copy: package len: %d, msg: %p\n", \
368 : _plen, _msg); \
369 : if (_msg) { \
370 : CBPRINTF_STATIC_PACKAGE(_msg->data, _plen, _plen, \
371 : Z_LOG_MSG_ALIGN_OFFSET, \
372 : Z_LOG_MSG_CBPRINTF_FLAGS(_cstr_cnt), \
373 : __VA_ARGS__); \
374 : } \
375 : z_log_msg_finalize(_msg, (void *)_source, _desc, NULL); \
376 : } while (false)
377 : #else
378 : /* Alternative empty macro created to speed up compilation when LOG_SPEED is
379 : * disabled (default).
380 : */
381 : #define Z_LOG_MSG_SIMPLE_CREATE(...)
382 : #endif
383 :
384 : /* Macro handles case when local variable with log message string is created. It
385 : * replaces original string literal with that variable.
386 : */
387 : #define Z_LOG_FMT_ARGS_2(_name, ...) \
388 : COND_CODE_1(CONFIG_LOG_FMT_SECTION, \
389 : (COND_CODE_0(NUM_VA_ARGS_LESS_1(__VA_ARGS__), \
390 : (_name), (_name, GET_ARGS_LESS_N(1, __VA_ARGS__)))), \
391 : (__VA_ARGS__))
392 :
393 : /** @brief Wrapper for log message string with arguments.
394 : *
395 : * Wrapper is replacing first argument with a variable from a dedicated memory
396 : * section if option is enabled. Macro handles the case when there is no
397 : * log message provided.
398 : *
399 : * @param _name Name of the variable with log message string. It is optionally used.
400 : * @param ... Optional log message with arguments (may be empty).
401 : */
402 : #define Z_LOG_FMT_ARGS(_name, ...) \
403 : COND_CODE_0(NUM_VA_ARGS_LESS_1(_, ##__VA_ARGS__), \
404 : (NULL), \
405 : (Z_LOG_FMT_ARGS_2(_name, ##__VA_ARGS__)))
406 :
407 : #if defined(CONFIG_LOG_USE_TAGGED_ARGUMENTS)
408 :
409 : #define Z_LOG_FMT_TAGGED_ARGS_2(_name, ...) \
410 : COND_CODE_1(CONFIG_LOG_FMT_SECTION, \
411 : (_name, Z_CBPRINTF_TAGGED_ARGS(NUM_VA_ARGS_LESS_1(__VA_ARGS__), \
412 : GET_ARGS_LESS_N(1, __VA_ARGS__))), \
413 : (GET_ARG_N(1, __VA_ARGS__), \
414 : Z_CBPRINTF_TAGGED_ARGS(NUM_VA_ARGS_LESS_1(__VA_ARGS__), \
415 : GET_ARGS_LESS_N(1, __VA_ARGS__))))
416 :
417 : /** @brief Wrapper for log message string with tagged arguments.
418 : *
419 : * Wrapper is replacing first argument with a variable from a dedicated memory
420 : * section if option is enabled. Macro handles the case when there is no
421 : * log message provided. Each subsequent arguments are tagged by preceding
422 : * each argument with its type value.
423 : *
424 : * @param _name Name of the variable with log message string. It is optionally used.
425 : * @param ... Optional log message with arguments (may be empty).
426 : */
427 : #define Z_LOG_FMT_TAGGED_ARGS(_name, ...) \
428 : COND_CODE_0(NUM_VA_ARGS_LESS_1(_, ##__VA_ARGS__), \
429 : (Z_CBPRINTF_TAGGED_ARGS(0)), \
430 : (Z_LOG_FMT_TAGGED_ARGS_2(_name, ##__VA_ARGS__)))
431 :
432 : #define Z_LOG_FMT_RUNTIME_ARGS(...) \
433 : Z_LOG_FMT_TAGGED_ARGS(__VA_ARGS__)
434 :
435 : #else
436 :
437 : #define Z_LOG_FMT_RUNTIME_ARGS(...) \
438 : Z_LOG_FMT_ARGS(__VA_ARGS__)
439 :
440 : #endif /* CONFIG_LOG_USE_TAGGED_ARGUMENTS */
441 :
442 : /* Macro handles case when there is no string provided, in that case variable
443 : * is not created.
444 : */
445 : #define Z_LOG_MSG_STR_VAR_IN_SECTION(_name, ...) \
446 : COND_CODE_0(NUM_VA_ARGS_LESS_1(_, ##__VA_ARGS__), \
447 : (/* No args provided, no variable */), \
448 : (static const char _name[] \
449 : __in_section(_log_strings, static, _CONCAT(_name, _)) __used __noasan = \
450 : GET_ARG_N(1, __VA_ARGS__);))
451 :
452 : /** @brief Create variable in the dedicated memory section (if enabled).
453 : *
454 : * Variable is initialized with a format string from the log message.
455 : *
456 : * @param _name Variable name.
457 : * @param ... Optional log message with arguments (may be empty).
458 : */
459 : #define Z_LOG_MSG_STR_VAR(_name, ...) \
460 : IF_ENABLED(CONFIG_LOG_FMT_SECTION, \
461 : (Z_LOG_MSG_STR_VAR_IN_SECTION(_name, ##__VA_ARGS__)))
462 :
463 : /** @brief Create log message and write it into the logger buffer.
464 : *
465 : * Macro handles creation of log message which includes storing log message
466 : * description, timestamp, arguments, copying string arguments into message and
467 : * copying user data into the message space. There are 3 modes of message
468 : * creation:
469 : * - at compile time message size is determined, message is allocated and
470 : * content is written directly to the message. It is the fastest but cannot
471 : * be used in user mode. Message size cannot be determined at compile time if
472 : * it contains data or string arguments which are string pointers.
473 : * - at compile time message size is determined, string package is created on
474 : * stack, message is created in function call. String package can only be
475 : * created on stack if it does not contain unexpected pointers to strings.
476 : * - string package is created at runtime. This mode has no limitations but
477 : * it is significantly slower.
478 : *
479 : * @param _try_0cpy If positive then, if possible, message content is written
480 : * directly to message. If 0 then, if possible, string package is created on
481 : * the stack and message is created in the function call.
482 : *
483 : * @param _mode Used for testing. It is set according to message creation mode
484 : * used.
485 : *
486 : * @param _cstr_cnt Number of constant strings present in the string. It is
487 : * used to help detect messages which must be runtime processed, compared to
488 : * message which can be prebuilt at compile time.
489 : *
490 : * @param _domain_id Domain ID.
491 : *
492 : * @param _source Pointer to the constant descriptor of the log message source.
493 : *
494 : * @param _level Log message level.
495 : *
496 : * @param _data Pointer to the data. Can be null.
497 : *
498 : * @param _dlen Number of data bytes. 0 if data is not provided.
499 : *
500 : * @param ... Optional string with arguments (fmt, ...). It may be empty.
501 : */
502 : #if defined(CONFIG_LOG_ALWAYS_RUNTIME) || !defined(CONFIG_LOG)
503 : #define Z_LOG_MSG_CREATE2(_try_0cpy, _mode, _cstr_cnt, _domain_id, _source,\
504 : _level, _data, _dlen, ...) \
505 : do {\
506 : Z_LOG_MSG_STR_VAR(_fmt, ##__VA_ARGS__) \
507 : z_log_msg_runtime_create((_domain_id), (void *)(_source), \
508 : (_level), (uint8_t *)(_data), (_dlen),\
509 : Z_LOG_MSG_CBPRINTF_FLAGS(_cstr_cnt) | \
510 : (IS_ENABLED(CONFIG_LOG_USE_TAGGED_ARGUMENTS) ? \
511 : CBPRINTF_PACKAGE_ARGS_ARE_TAGGED : 0), \
512 : Z_LOG_FMT_RUNTIME_ARGS(_fmt, ##__VA_ARGS__));\
513 : (_mode) = Z_LOG_MSG_MODE_RUNTIME; \
514 : } while (false)
515 : #else /* CONFIG_LOG_ALWAYS_RUNTIME || !CONFIG_LOG */
516 : #define Z_LOG_MSG_CREATE3(_try_0cpy, _mode, _cstr_cnt, _domain_id, _source,\
517 : _level, _data, _dlen, ...) \
518 : do { \
519 : Z_LOG_MSG_STR_VAR(_fmt, ##__VA_ARGS__); \
520 : bool has_rw_str = CBPRINTF_MUST_RUNTIME_PACKAGE( \
521 : Z_LOG_MSG_CBPRINTF_FLAGS(_cstr_cnt), \
522 : __VA_ARGS__); \
523 : if (IS_ENABLED(CONFIG_LOG_SPEED) && (_try_0cpy) && ((_dlen) == 0) && !has_rw_str) {\
524 : LOG_MSG_DBG("create zero-copy message\n");\
525 : Z_LOG_MSG_SIMPLE_CREATE(_cstr_cnt, _domain_id, _source, \
526 : _level, Z_LOG_FMT_ARGS(_fmt, ##__VA_ARGS__)); \
527 : (_mode) = Z_LOG_MSG_MODE_ZERO_COPY; \
528 : } else { \
529 : IF_ENABLED(UTIL_AND(IS_ENABLED(CONFIG_LOG_SIMPLE_MSG_OPTIMIZE), \
530 : UTIL_AND(UTIL_NOT(_domain_id), UTIL_NOT(_cstr_cnt))), \
531 : ( \
532 : bool can_simple = LOG_MSG_SIMPLE_CHECK(__VA_ARGS__); \
533 : if (can_simple && ((_dlen) == 0) && !k_is_user_context()) { \
534 : LOG_MSG_DBG("create fast message\n");\
535 : Z_LOG_MSG_SIMPLE_ARGS_CREATE(_domain_id, _source, _level, \
536 : Z_LOG_FMT_ARGS(_fmt, ##__VA_ARGS__)); \
537 : _mode = Z_LOG_MSG_MODE_SIMPLE; \
538 : break; \
539 : } \
540 : ) \
541 : ) \
542 : LOG_MSG_DBG("create on stack message\n");\
543 : Z_LOG_MSG_STACK_CREATE(_cstr_cnt, _domain_id, _source, _level, _data, \
544 : _dlen, Z_LOG_FMT_ARGS(_fmt, ##__VA_ARGS__)); \
545 : (_mode) = Z_LOG_MSG_MODE_FROM_STACK; \
546 : } \
547 : (void)(_mode); \
548 : } while (false)
549 :
550 : #if defined(__cplusplus)
551 : #define Z_AUTO_TYPE auto
552 : #else
553 : #define Z_AUTO_TYPE __auto_type
554 : #endif
555 :
556 : /* Macro for getting name of a local variable with the exception of the first argument
557 : * which is a formatted string in log message.
558 : */
559 : #define Z_LOG_LOCAL_ARG_NAME(idx, arg) COND_CODE_0(idx, (arg), (_v##idx))
560 :
561 : /* Create local variable from input variable (expect for the first (fmt) argument). */
562 : #define Z_LOG_LOCAL_ARG_CREATE(idx, arg) \
563 : COND_CODE_0(idx, (), (Z_AUTO_TYPE Z_LOG_LOCAL_ARG_NAME(idx, arg) = (arg) + 0))
564 :
565 : /* First level of processing creates stack variables to be passed for further processing.
566 : * This is done to prevent multiple evaluations of input arguments (in case argument
567 : * evaluation has side effects, e.g. it is a non-pure function call).
568 : */
569 : #define Z_LOG_MSG_CREATE2(_try_0cpy, _mode, _cstr_cnt, _domain_id, _source, \
570 : _level, _data, _dlen, ...) \
571 : do { \
572 : _Pragma("GCC diagnostic push") \
573 : _Pragma("GCC diagnostic ignored \"-Wpointer-arith\"") \
574 : FOR_EACH_IDX(Z_LOG_LOCAL_ARG_CREATE, (;), __VA_ARGS__); \
575 : _Pragma("GCC diagnostic pop") \
576 : Z_LOG_MSG_CREATE3(_try_0cpy, _mode, _cstr_cnt, _domain_id, _source,\
577 : _level, _data, _dlen, \
578 : FOR_EACH_IDX(Z_LOG_LOCAL_ARG_NAME, (,), __VA_ARGS__)); \
579 : } while (false)
580 : #endif /* CONFIG_LOG_ALWAYS_RUNTIME || !CONFIG_LOG */
581 :
582 :
583 : #define Z_LOG_MSG_CREATE(_try_0cpy, _mode, _domain_id, _source,\
584 : _level, _data, _dlen, ...) \
585 : Z_LOG_MSG_CREATE2(_try_0cpy, _mode, UTIL_CAT(Z_LOG_FUNC_PREFIX_, _level), \
586 : _domain_id, _source, _level, _data, _dlen, \
587 : Z_LOG_STR(_level, __VA_ARGS__))
588 :
589 : /** @brief Allocate log message.
590 : *
591 : * @param wlen Length in 32 bit words.
592 : *
593 : * @return allocated space or null if cannot be allocated.
594 : */
595 : struct log_msg *z_log_msg_alloc(uint32_t wlen);
596 :
597 : /** @brief Finalize message.
598 : *
599 : * Finalization includes setting source, copying data and timestamp in the
600 : * message followed by committing the message.
601 : *
602 : * @param msg Message.
603 : *
604 : * @param source Address of the source descriptor.
605 : *
606 : * @param desc Message descriptor.
607 : *
608 : * @param data Data.
609 : */
610 : void z_log_msg_finalize(struct log_msg *msg, const void *source,
611 : const struct log_msg_desc desc, const void *data);
612 :
613 : /** @brief Create log message using simplified method for string with no arguments.
614 : *
615 : * @param source Pointer to the source structure.
616 : * @param level Severity level.
617 : * @param fmt String pointer.
618 : */
619 : __syscall void z_log_msg_simple_create_0(const void *source, uint32_t level,
620 : const char *fmt);
621 :
622 : /** @brief Create log message using simplified method for string with a one argument.
623 : *
624 : * @param source Pointer to the source structure.
625 : * @param level Severity level.
626 : * @param fmt String pointer.
627 : * @param arg String argument.
628 : */
629 : __syscall void z_log_msg_simple_create_1(const void *source, uint32_t level,
630 : const char *fmt, uint32_t arg);
631 :
632 : /** @brief Create log message using simplified method for string with two arguments.
633 : *
634 : * @param source Pointer to the source structure.
635 : * @param level Severity level.
636 : * @param fmt String pointer.
637 : * @param arg0 String argument.
638 : * @param arg1 String argument.
639 : */
640 : __syscall void z_log_msg_simple_create_2(const void *source, uint32_t level,
641 : const char *fmt, uint32_t arg0, uint32_t arg1);
642 :
643 : /** @brief Create a logging message from message details and string package.
644 : *
645 : * @param source Source.
646 : *
647 : * @param desc Message descriptor.
648 : *
649 : * @param package Package.
650 : *
651 : * @param data Data.
652 : */
653 : __syscall void z_log_msg_static_create(const void *source,
654 : const struct log_msg_desc desc,
655 : uint8_t *package, const void *data);
656 :
657 : /** @brief Create message at runtime.
658 : *
659 : * Function allows to build any log message based on input data. Processing
660 : * time is significantly higher than statically message creating.
661 : *
662 : * @param domain_id Domain ID.
663 : *
664 : * @param source Source.
665 : *
666 : * @param level Log level.
667 : *
668 : * @param data Data.
669 : *
670 : * @param dlen Data length.
671 : *
672 : * @param package_flags Package flags.
673 : *
674 : * @param fmt String.
675 : *
676 : * @param ap Variable list of string arguments.
677 : */
678 : void z_log_msg_runtime_vcreate(uint8_t domain_id, const void *source,
679 : uint8_t level, const void *data,
680 : size_t dlen, uint32_t package_flags,
681 : const char *fmt,
682 : va_list ap);
683 :
684 : /** @brief Create message at runtime.
685 : *
686 : * Function allows to build any log message based on input data. Processing
687 : * time is significantly higher than statically message creating.
688 : *
689 : * @param domain_id Domain ID.
690 : *
691 : * @param source Source.
692 : *
693 : * @param level Log level.
694 : *
695 : * @param data Data.
696 : *
697 : * @param dlen Data length.
698 : *
699 : * @param package_flags Package flags.
700 : *
701 : * @param fmt String.
702 : *
703 : * @param ... String arguments.
704 : */
705 : static inline void z_log_msg_runtime_create(uint8_t domain_id,
706 : const void *source,
707 : uint8_t level, const void *data,
708 : size_t dlen, uint32_t package_flags,
709 : const char *fmt, ...)
710 : {
711 : va_list ap;
712 :
713 : va_start(ap, fmt);
714 : z_log_msg_runtime_vcreate(domain_id, source, level,
715 : data, dlen, package_flags, fmt, ap);
716 : va_end(ap);
717 : }
718 :
719 : static inline bool z_log_item_is_msg(const union log_msg_generic *msg)
720 : {
721 : return msg->generic.type == Z_LOG_MSG_LOG;
722 : }
723 :
724 : /** @brief Get total length (in 32 bit words) of a log message.
725 : *
726 : * @param desc Log message descriptor.
727 : *
728 : * @return Length.
729 : */
730 1 : static inline uint32_t log_msg_get_total_wlen(const struct log_msg_desc desc)
731 : {
732 : return Z_LOG_MSG_ALIGNED_WLEN(desc.package_len, desc.data_len);
733 : }
734 :
735 : /** @brief Get length of the log item.
736 : *
737 : * @param item Item.
738 : *
739 : * @return Length in 32 bit words.
740 : */
741 1 : static inline uint32_t log_msg_generic_get_wlen(const union mpsc_pbuf_generic *item)
742 : {
743 : const union log_msg_generic *generic_msg = (const union log_msg_generic *)item;
744 :
745 : if (z_log_item_is_msg(generic_msg)) {
746 : const struct log_msg *msg = (const struct log_msg *)generic_msg;
747 :
748 : return log_msg_get_total_wlen(msg->hdr.desc);
749 : }
750 :
751 : return 0;
752 : }
753 :
754 : /** @brief Get log message domain ID.
755 : *
756 : * @param msg Log message.
757 : *
758 : * @return Domain ID
759 : */
760 1 : static inline uint8_t log_msg_get_domain(struct log_msg *msg)
761 : {
762 : return msg->hdr.desc.domain;
763 : }
764 :
765 : /** @brief Get log message level.
766 : *
767 : * @param msg Log message.
768 : *
769 : * @return Log level.
770 : */
771 1 : static inline uint8_t log_msg_get_level(struct log_msg *msg)
772 : {
773 : return msg->hdr.desc.level;
774 : }
775 :
776 : /** @brief Get message source data.
777 : *
778 : * @param msg Log message.
779 : *
780 : * @return Pointer to the source data.
781 : */
782 1 : static inline const void *log_msg_get_source(struct log_msg *msg)
783 : {
784 : return msg->hdr.source;
785 : }
786 :
787 : /** @brief Get log message source ID.
788 : *
789 : * @param msg Log message.
790 : *
791 : * @return Source ID, or -1 if not available.
792 : */
793 1 : int16_t log_msg_get_source_id(struct log_msg *msg);
794 :
795 : /** @brief Get timestamp.
796 : *
797 : * @param msg Log message.
798 : *
799 : * @return Timestamp.
800 : */
801 1 : static inline log_timestamp_t log_msg_get_timestamp(struct log_msg *msg)
802 : {
803 : return msg->hdr.timestamp;
804 : }
805 :
806 : /** @brief Get Thread ID.
807 : *
808 : * @param msg Log message.
809 : *
810 : * @return Thread ID.
811 : */
812 1 : static inline void *log_msg_get_tid(struct log_msg *msg)
813 : {
814 : #if defined(CONFIG_LOG_THREAD_ID_PREFIX)
815 : return msg->hdr.tid;
816 : #else
817 : ARG_UNUSED(msg);
818 : return NULL;
819 : #endif
820 : }
821 :
822 : /** @brief Get data buffer.
823 : *
824 : * @param msg log message.
825 : *
826 : * @param len location where data length is written.
827 : *
828 : * @return pointer to the data buffer.
829 : */
830 1 : static inline uint8_t *log_msg_get_data(struct log_msg *msg, size_t *len)
831 : {
832 : *len = msg->hdr.desc.data_len;
833 :
834 : return msg->data + msg->hdr.desc.package_len;
835 : }
836 :
837 : /** @brief Get string package.
838 : *
839 : * @param msg log message.
840 : *
841 : * @param len location where string package length is written.
842 : *
843 : * @return pointer to the package.
844 : */
845 1 : static inline uint8_t *log_msg_get_package(struct log_msg *msg, size_t *len)
846 : {
847 : *len = msg->hdr.desc.package_len;
848 :
849 : return msg->data;
850 : }
851 :
852 : /**
853 : * @}
854 : */
855 :
856 : #include <zephyr/syscalls/log_msg.h>
857 :
858 : #ifdef __cplusplus
859 : }
860 : #endif
861 :
862 : #endif /* ZEPHYR_INCLUDE_LOGGING_LOG_MSG_H_ */
|