1 /*
2  * Copyright (c) 2021 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 #ifndef ZEPHYR_INCLUDE_LOGGING_LOG_MSG2_H_
7 #define ZEPHYR_INCLUDE_LOGGING_LOG_MSG2_H_
8 
9 #include <logging/log_instance.h>
10 #include <sys/mpsc_packet.h>
11 #include <sys/cbprintf.h>
12 #include <sys/atomic.h>
13 #include <sys/util.h>
14 #include <string.h>
15 
16 #ifdef __GNUC__
17 #ifndef alloca
18 #define alloca __builtin_alloca
19 #endif
20 #else
21 #include <alloca.h>
22 #endif
23 
24 #ifdef __cplusplus
25 extern "C" {
26 #endif
27 
28 #define LOG_MSG2_DEBUG 0
29 #define LOG_MSG2_DBG(...) IF_ENABLED(LOG_MSG2_DEBUG, (printk(__VA_ARGS__)))
30 
31 #if CONFIG_LOG_TIMESTAMP_64BIT
32 typedef uint64_t log_timestamp_t;
33 #else
34 typedef uint32_t log_timestamp_t;
35 #endif
36 
37 /**
38  * @brief Log message API
39  * @defgroup log_msg2 Log message v2 API
40  * @ingroup logger
41  * @{
42  */
43 
44 #define Z_LOG_MSG2_LOG 0
45 
46 #define LOG_MSG2_GENERIC_HDR \
47 	MPSC_PBUF_HDR;\
48 	uint32_t type:1
49 
50 struct log_msg2_desc {
51 	LOG_MSG2_GENERIC_HDR;
52 	uint32_t domain:3;
53 	uint32_t level:3;
54 	uint32_t package_len:10;
55 	uint32_t data_len:12;
56 	uint32_t reserved:1;
57 };
58 
59 union log_msg2_source {
60 	const struct log_source_const_data *fixed;
61 	struct log_source_dynamic_data *dynamic;
62 	void *raw;
63 };
64 
65 struct log_msg2_hdr {
66 	struct log_msg2_desc desc;
67 /* Attempting to keep best alignment. When address is 64 bit and timestamp 32
68  * swap the order to have 16 byte header instead of 24 byte.
69  */
70 #if (INTPTR_MAX > INT32_MAX) && !CONFIG_LOG_TIMESTAMP_64BIT
71 	log_timestamp_t timestamp;
72 	const void *source;
73 #else
74 	const void *source;
75 	log_timestamp_t timestamp;
76 #endif
77 #if defined(__xtensa__) && !defined(CONFIG_LOG_TIMESTAMP_64BIT)
78 	/* xtensa requires that cbprintf package that follows the header is
79 	 * aligned to 16 bytes. Adding padding when necessary.
80 	 */
81 	uint32_t padding;
82 #endif
83 };
84 
85 struct log_msg2 {
86 	struct log_msg2_hdr hdr;
87 	uint8_t data[];
88 };
89 
90 struct log_msg2_generic_hdr {
91 	LOG_MSG2_GENERIC_HDR;
92 };
93 
94 union log_msg2_generic {
95 	union mpsc_pbuf_generic buf;
96 	struct log_msg2_generic_hdr generic;
97 	struct log_msg2 log;
98 };
99 
100 /** @brief Method used for creating a log message.
101  *
102  * It is used for testing purposes to validate that expected mode was used.
103  */
104 enum z_log_msg2_mode {
105 	/* Runtime mode is least efficient but supports all cases thus it is
106 	 * threated as a fallback method when others cannot be used.
107 	 */
108 	Z_LOG_MSG2_MODE_RUNTIME,
109 	/* Mode creates statically a string package on stack and calls a
110 	 * function for creating a message. It takes code size than
111 	 * Z_LOG_MSG2_MODE_ZERO_COPY but is a bit slower.
112 	 */
113 	Z_LOG_MSG2_MODE_FROM_STACK,
114 
115 	/* Mode calculates size of the message and allocates it and writes
116 	 * directly to the message space. It is the fastest method but requires
117 	 * more code size.
118 	 */
119 	Z_LOG_MSG2_MODE_ZERO_COPY,
120 
121 	/* Mode used when synchronous logging is enabled. */
122 	Z_LOG_MSG2_MODE_SYNC
123 };
124 
125 #define Z_LOG_MSG_DESC_INITIALIZER(_domain_id, _level, _plen, _dlen) \
126 { \
127 	.valid = 0, \
128 	.busy = 0, \
129 	.type = Z_LOG_MSG2_LOG, \
130 	.domain = _domain_id, \
131 	.level = _level, \
132 	.package_len = _plen, \
133 	.data_len = _dlen, \
134 	.reserved = 0, \
135 }
136 
137 /* Messages are aligned to alignment required by cbprintf package. */
138 #define Z_LOG_MSG2_ALIGNMENT CBPRINTF_PACKAGE_ALIGNMENT
139 
140 #if CONFIG_LOG2_USE_VLA
141 #define Z_LOG_MSG2_ON_STACK_ALLOC(ptr, len) \
142 	long long _ll_buf[ceiling_fraction(len, sizeof(long long))]; \
143 	long double _ld_buf[ceiling_fraction(len, sizeof(long double))]; \
144 	ptr = (sizeof(long double) == Z_LOG_MSG2_ALIGNMENT) ? \
145 			(struct log_msg2 *)_ld_buf : (struct log_msg2 *)_ll_buf; \
146 	if (IS_ENABLED(CONFIG_LOG_TEST_CLEAR_MESSAGE_SPACE)) { \
147 		/* During test fill with 0's to simplify message comparison */ \
148 		memset(ptr, 0, len); \
149 	}
150 #else /* Z_LOG_MSG2_USE_VLA */
151 /* When VLA cannot be used we need to trick compiler a bit and create multiple
152  * fixed size arrays and take the smallest one that will fit the message.
153  * Compiler will remove unused arrays and stack usage will be kept similar
154  * to vla case, rounded to the size of the used buffer.
155  */
156 #define Z_LOG_MSG2_ON_STACK_ALLOC(ptr, len) \
157 	long long _ll_buf32[32 / sizeof(long long)]; \
158 	long long _ll_buf48[48 / sizeof(long long)]; \
159 	long long _ll_buf64[64 / sizeof(long long)]; \
160 	long long _ll_buf128[128 / sizeof(long long)]; \
161 	long long _ll_buf256[256 / sizeof(long long)]; \
162 	long double _ld_buf32[32 / sizeof(long double)]; \
163 	long double _ld_buf48[48 / sizeof(long double)]; \
164 	long double _ld_buf64[64 / sizeof(long double)]; \
165 	long double _ld_buf128[128 / sizeof(long double)]; \
166 	long double _ld_buf256[256 / sizeof(long double)]; \
167 	if (sizeof(long double) == Z_LOG_MSG2_ALIGNMENT) { \
168 		ptr = (len > 128) ? (struct log_msg2 *)_ld_buf256 : \
169 			((len > 64) ? (struct log_msg2 *)_ld_buf128 : \
170 			((len > 48) ? (struct log_msg2 *)_ld_buf64 : \
171 			((len > 32) ? (struct log_msg2 *)_ld_buf48 : \
172 				      (struct log_msg2 *)_ld_buf32)));\
173 	} else { \
174 		ptr = (len > 128) ? (struct log_msg2 *)_ll_buf256 : \
175 			((len > 64) ? (struct log_msg2 *)_ll_buf128 : \
176 			((len > 48) ? (struct log_msg2 *)_ll_buf64 : \
177 			((len > 32) ? (struct log_msg2 *)_ll_buf48 : \
178 				      (struct log_msg2 *)_ll_buf32)));\
179 	} \
180 	if (IS_ENABLED(CONFIG_LOG_TEST_CLEAR_MESSAGE_SPACE)) { \
181 		/* During test fill with 0's to simplify message comparison */ \
182 		memset(ptr, 0, len); \
183 	}
184 #endif /* Z_LOG_MSG2_USE_VLA */
185 
186 #define Z_LOG_MSG2_ALIGN_OFFSET \
187 	sizeof(struct log_msg2_hdr)
188 
189 #define Z_LOG_MSG2_LEN(pkg_len, data_len) \
190 	(sizeof(struct log_msg2_hdr) + pkg_len + (data_len))
191 
192 #define Z_LOG_MSG2_ALIGNED_WLEN(pkg_len, data_len) \
193 	ceiling_fraction(ROUND_UP(Z_LOG_MSG2_LEN(pkg_len, data_len), \
194 				  Z_LOG_MSG2_ALIGNMENT), \
195 			 sizeof(uint32_t))
196 
197 #define Z_LOG_MSG2_SYNC(_domain_id, _source, _level, _data, _dlen, ...) do { \
198 	int _plen; \
199 	CBPRINTF_STATIC_PACKAGE(NULL, 0, _plen, Z_LOG_MSG2_ALIGN_OFFSET, \
200 				0, __VA_ARGS__); \
201 	struct log_msg2 *_msg; \
202 	Z_LOG_MSG2_ON_STACK_ALLOC(_msg, Z_LOG_MSG2_LEN(_plen, _dlen)); \
203 	if (_plen) {\
204 		CBPRINTF_STATIC_PACKAGE(_msg->data, _plen, _plen, \
205 					Z_LOG_MSG2_ALIGN_OFFSET, \
206 					0, __VA_ARGS__); \
207 	} \
208 	struct log_msg2_desc _desc = \
209 		     Z_LOG_MSG_DESC_INITIALIZER(_domain_id, _level, \
210 			   (uint32_t)_plen, _dlen); \
211 	z_log_msg2_finalize(_msg, _source, _desc, _data); \
212 } while (0)
213 
214 #define Z_LOG_MSG2_STACK_CREATE(_domain_id, _source, _level, _data, _dlen, ...)\
215 do { \
216 	int _plen; \
217 	if (GET_ARG_N(1, __VA_ARGS__) == NULL) { \
218 		_plen = 0; \
219 	} else { \
220 		CBPRINTF_STATIC_PACKAGE(NULL, 0, _plen, Z_LOG_MSG2_ALIGN_OFFSET, \
221 					0, __VA_ARGS__); \
222 	} \
223 	struct log_msg2 *_msg; \
224 	Z_LOG_MSG2_ON_STACK_ALLOC(_msg, Z_LOG_MSG2_LEN(_plen, 0)); \
225 	if (_plen) { \
226 		CBPRINTF_STATIC_PACKAGE(_msg->data, _plen, \
227 					_plen, Z_LOG_MSG2_ALIGN_OFFSET, \
228 					0, __VA_ARGS__);\
229 	} \
230 	struct log_msg2_desc _desc = \
231 		Z_LOG_MSG_DESC_INITIALIZER(_domain_id, _level, \
232 					   (uint32_t)_plen, _dlen); \
233 	LOG_MSG2_DBG("creating message on stack: package len: %d, data len: %d\n", \
234 			_plen, (int)(_dlen)); \
235 	z_log_msg2_static_create((void *)_source, _desc, _msg->data, _data); \
236 } while (0)
237 
238 #if CONFIG_LOG_SPEED
239 #define Z_LOG_MSG2_SIMPLE_CREATE(_domain_id, _source, _level, ...) do { \
240 	int _plen; \
241 	CBPRINTF_STATIC_PACKAGE(NULL, 0, _plen, Z_LOG_MSG2_ALIGN_OFFSET, \
242 				0, __VA_ARGS__); \
243 	size_t _msg_wlen = Z_LOG_MSG2_ALIGNED_WLEN(_plen, 0); \
244 	struct log_msg2 *_msg = z_log_msg2_alloc(_msg_wlen); \
245 	struct log_msg2_desc _desc = \
246 		Z_LOG_MSG_DESC_INITIALIZER(_domain_id, _level, (uint32_t)_plen, 0); \
247 	LOG_MSG2_DBG("creating message zero copy: package len: %d, msg: %p\n", \
248 			_plen, _msg); \
249 	if (_msg) { \
250 		CBPRINTF_STATIC_PACKAGE(_msg->data, _plen, _plen, \
251 					Z_LOG_MSG2_ALIGN_OFFSET, \
252 					0, __VA_ARGS__); \
253 	} \
254 	z_log_msg2_finalize(_msg, (void *)_source, _desc, NULL); \
255 } while (0)
256 #else
257 /* Alternative empty macro created to speed up compilation when LOG_SPEED is
258  * disabled (default).
259  */
260 #define Z_LOG_MSG2_SIMPLE_CREATE(...)
261 #endif
262 
263 /* Macro handles case when local variable with log message string is created.It
264  * replaces origing string literal with that variable.
265  */
266 #define Z_LOG_FMT_ARGS_2(_name, ...) \
267 	COND_CODE_1(CONFIG_LOG2_FMT_SECTION, \
268 		(COND_CODE_0(NUM_VA_ARGS_LESS_1(__VA_ARGS__), \
269 		   (_name), (_name, GET_ARGS_LESS_N(1, __VA_ARGS__)))), \
270 		(__VA_ARGS__))
271 
272 /** @brief Wrapper for log message string with arguments.
273  *
274  * Wrapper is replacing first argument with a variable from a dedicated memory
275  * section if option is enabled. Macro handles the case when there is no
276  * log message provided.
277  *
278  * @param _name Name of the variable with log message string. It is optionally used.
279  * @param ... Optional log message with arguments (may be empty).
280  */
281 #define Z_LOG_FMT_ARGS(_name, ...) \
282 	COND_CODE_0(NUM_VA_ARGS_LESS_1(_, ##__VA_ARGS__), \
283 		(NULL), \
284 		(Z_LOG_FMT_ARGS_2(_name, ##__VA_ARGS__)))
285 
286 /* Macro handles case when there is no string provided, in that case variable
287  * is not created.
288  */
289 #define Z_LOG_MSG2_STR_VAR_IN_SECTION(_name, ...) \
290 	COND_CODE_0(NUM_VA_ARGS_LESS_1(_, ##__VA_ARGS__), \
291 		    (/* No args provided, no variable */), \
292 		    (static const char _name[] \
293 			__attribute__((__section__(".log_strings"))) = \
294 			GET_ARG_N(1, __VA_ARGS__);))
295 
296 /** @brief Create variable in the dedicated memory section (if enabled).
297  *
298  * Variable is initialized with a format string from the log message.
299  *
300  * @param _name Variable name.
301  * @param ... Optional log message with arguments (may be empty).
302  */
303 #define Z_LOG_MSG2_STR_VAR(_name, ...) \
304 	IF_ENABLED(CONFIG_LOG2_FMT_SECTION, \
305 		   (Z_LOG_MSG2_STR_VAR_IN_SECTION(_name, ##__VA_ARGS__)))
306 
307 /** @brief Create log message and write it into the logger buffer.
308  *
309  * Macro handles creation of log message which includes storing log message
310  * description, timestamp, arguments, copying string arguments into message and
311  * copying user data into the message space. The are 3 modes of message
312  * creation:
313  * - at compile time message size is determined, message is allocated and
314  *   content is written directly to the message. It is the fastest but cannot
315  *   be used in user mode. Message size cannot be determined at compile time if
316  *   it contains data or string arguments which are string pointers.
317  * - at compile time message size is determined, string package is created on
318  *   stack, message is created in function call. String package can only be
319  *   created on stack if it does not contain unexpected pointers to strings.
320  * - string package is created at runtime. This mode has no limitations but
321  *   it is significantly slower.
322  *
323  * @param _try_0cpy If positive then, if possible, message content is written
324  * directly to message. If 0 then, if possible, string package is created on
325  * the stack and message is created in the function call.
326  *
327  * @param _mode Used for testing. It is set according to message creation mode
328  *		used.
329  *
330  * @param _cstr_cnt Number of constant strings present in the string. It is
331  * used to help detect messages which must be runtime processed, compared to
332  * message which can be prebuilt at compile time.
333  *
334  * @param _domain_id Domain ID.
335  *
336  * @param _source Pointer to the constant descriptor of the log message source.
337  *
338  * @param _level Log message level.
339  *
340  * @param _data Pointer to the data. Can be null.
341  *
342  * @param _dlen Number of data bytes. 0 if data is not provided.
343  *
344  * @param ...  Optional string with arguments (fmt, ...). It may be empty.
345  */
346 #if CONFIG_LOG2_ALWAYS_RUNTIME
347 #define Z_LOG_MSG2_CREATE2(_try_0cpy, _mode,  _cstr_cnt, _domain_id, _source,\
348 			  _level, _data, _dlen, ...) \
349 do {\
350 	Z_LOG_MSG2_STR_VAR(_fmt, ##__VA_ARGS__) \
351 	z_log_msg2_runtime_create(_domain_id, (void *)_source, \
352 				  _level, (uint8_t *)_data, _dlen,\
353 				  Z_LOG_FMT_ARGS(_fmt, ##__VA_ARGS__));\
354 	_mode = Z_LOG_MSG2_MODE_RUNTIME; \
355 } while (0)
356 #elif CONFIG_LOG2_MODE_IMMEDIATE /* CONFIG_LOG2_ALWAYS_RUNTIME */
357 #define Z_LOG_MSG2_CREATE2(_try_0cpy, _mode,  _cstr_cnt, _domain_id, _source,\
358 			  _level, _data, _dlen, ...) \
359 do { \
360 	Z_LOG_MSG2_STR_VAR(_fmt, ##__VA_ARGS__); \
361 	if (CBPRINTF_MUST_RUNTIME_PACKAGE(_cstr_cnt, __VA_ARGS__)) { \
362 		LOG_MSG2_DBG("create runtime message\n");\
363 		z_log_msg2_runtime_create(_domain_id, (void *)_source, \
364 					  _level, (uint8_t *)_data, _dlen,\
365 					  Z_LOG_FMT_ARGS(_fmt, ##__VA_ARGS__));\
366 		_mode = Z_LOG_MSG2_MODE_RUNTIME; \
367 	} else {\
368 		Z_LOG_MSG2_SYNC(_domain_id, _source, _level, \
369 				_data, _dlen, Z_LOG_FMT_ARGS(_fmt, ##__VA_ARGS__)); \
370 		_mode = Z_LOG_MSG2_MODE_SYNC; \
371 	} \
372 } while (0)
373 #else /* CONFIG_LOG2_ALWAYS_RUNTIME */
374 #define Z_LOG_MSG2_CREATE2(_try_0cpy, _mode,  _cstr_cnt, _domain_id, _source,\
375 			  _level, _data, _dlen, ...) \
376 do { \
377 	Z_LOG_MSG2_STR_VAR(_fmt, ##__VA_ARGS__); \
378 	if (CBPRINTF_MUST_RUNTIME_PACKAGE(_cstr_cnt, __VA_ARGS__)) { \
379 		LOG_MSG2_DBG("create runtime message\n");\
380 		z_log_msg2_runtime_create(_domain_id, (void *)_source, \
381 					  _level, (uint8_t *)_data, _dlen,\
382 					  Z_LOG_FMT_ARGS(_fmt, ##__VA_ARGS__));\
383 		_mode = Z_LOG_MSG2_MODE_RUNTIME; \
384 	} else if (IS_ENABLED(CONFIG_LOG_SPEED) && _try_0cpy && ((_dlen) == 0)) {\
385 		LOG_MSG2_DBG("create zero-copy message\n");\
386 		Z_LOG_MSG2_SIMPLE_CREATE(_domain_id, _source, \
387 					_level, Z_LOG_FMT_ARGS(_fmt, ##__VA_ARGS__)); \
388 		_mode = Z_LOG_MSG2_MODE_ZERO_COPY; \
389 	} else { \
390 		LOG_MSG2_DBG("create on stack message\n");\
391 		Z_LOG_MSG2_STACK_CREATE(_domain_id, _source, _level, _data, \
392 					_dlen, Z_LOG_FMT_ARGS(_fmt, ##__VA_ARGS__)); \
393 		_mode = Z_LOG_MSG2_MODE_FROM_STACK; \
394 	} \
395 	(void)_mode; \
396 } while (0)
397 #endif /* CONFIG_LOG2_ALWAYS_RUNTIME */
398 
399 #define Z_LOG_MSG2_CREATE(_try_0cpy, _mode,  _domain_id, _source,\
400 			  _level, _data, _dlen, ...) \
401 	Z_LOG_MSG2_CREATE2(_try_0cpy, _mode, UTIL_CAT(Z_LOG_FUNC_PREFIX_, _level), \
402 			   _domain_id, _source, _level, _data, _dlen, \
403 			   Z_LOG_STR(_level, __VA_ARGS__))
404 
405 /** @brief Finalize message.
406  *
407  * Finalization includes setting source, copying data and timestamp in the
408  * message followed by committing the message.
409  *
410  * @param msg Message.
411  *
412  * @param source Address of the source descriptor.
413  *
414  * @param desc Message descriptor.
415  *
416  * @param data Data.
417  */
418 void z_log_msg2_finalize(struct log_msg2 *msg, const void *source,
419 			 const struct log_msg2_desc desc, const void *data);
420 
421 /** @brief Create simple message from message details and string package.
422  *
423  * @param source Source.
424  *
425  * @param desc Message descriptor.
426  *
427  * @param package Package.
428  *
429  * @oaram data Data.
430  */
431 __syscall void z_log_msg2_static_create(const void *source,
432 					const struct log_msg2_desc desc,
433 					uint8_t *package, const void *data);
434 
435 /** @brief Create message at runtime.
436  *
437  * Function allows to build any log message based on input data. Processing
438  * time is significantly higher than statically message creating.
439  *
440  * @param domain_id Domain ID.
441  *
442  * @param source Source.
443  *
444  * @param level Log level.
445  *
446  * @param data Data.
447  *
448  * @param dlen Data length.
449  *
450  * @param fmt String.
451  *
452  * @param ap Variable list of string arguments.
453  */
454 __syscall void z_log_msg2_runtime_vcreate(uint8_t domain_id, const void *source,
455 					  uint8_t level, const void *data,
456 					  size_t dlen, const char *fmt,
457 					  va_list ap);
458 
459 /** @brief Create message at runtime.
460  *
461  * Function allows to build any log message based on input data. Processing
462  * time is significantly higher than statically message creating.
463  *
464  * @param domain_id Domain ID.
465  *
466  * @param source Source.
467  *
468  * @param level Log level.
469  *
470  * @param data Data.
471  *
472  * @param dlen Data length.
473  *
474  * @param fmt String.
475  *
476  * @param ... String arguments.
477  */
z_log_msg2_runtime_create(uint8_t domain_id,const void * source,uint8_t level,const void * data,size_t dlen,const char * fmt,...)478 static inline void z_log_msg2_runtime_create(uint8_t domain_id,
479 					     const void *source,
480 					     uint8_t level, const void *data,
481 					     size_t dlen, const char *fmt, ...)
482 {
483 	va_list ap;
484 
485 	va_start(ap, fmt);
486 	z_log_msg2_runtime_vcreate(domain_id, source, level,
487 				   data, dlen, fmt, ap);
488 	va_end(ap);
489 }
490 
z_log_item_is_msg(union log_msg2_generic * msg)491 static inline bool z_log_item_is_msg(union log_msg2_generic *msg)
492 {
493 	return msg->generic.type == Z_LOG_MSG2_LOG;
494 }
495 
496 /** @brief Get total length (in 32 bit words) of a log message.
497  *
498  * @param desc Log message descriptor.
499  *
500  * @return Length.
501  */
log_msg2_get_total_wlen(const struct log_msg2_desc desc)502 static inline uint32_t log_msg2_get_total_wlen(const struct log_msg2_desc desc)
503 {
504 	return Z_LOG_MSG2_ALIGNED_WLEN(desc.package_len, desc.data_len);
505 }
506 
507 /** @brief Get length of the log item.
508  *
509  * @param item Item.
510  *
511  * @return Length in 32 bit words.
512  */
log_msg2_generic_get_wlen(const union mpsc_pbuf_generic * item)513 static inline uint32_t log_msg2_generic_get_wlen(const union mpsc_pbuf_generic *item)
514 {
515 	union log_msg2_generic *generic_msg = (union log_msg2_generic *)item;
516 
517 	if (z_log_item_is_msg(generic_msg)) {
518 		struct log_msg2 *msg = (struct log_msg2 *)generic_msg;
519 
520 		return log_msg2_get_total_wlen(msg->hdr.desc);
521 	}
522 
523 	return 0;
524 }
525 
526 /** @brief Get log message domain ID.
527  *
528  * @param msg Log message.
529  *
530  * @return Domain ID
531  */
log_msg2_get_domain(struct log_msg2 * msg)532 static inline uint8_t log_msg2_get_domain(struct log_msg2 *msg)
533 {
534 	return msg->hdr.desc.domain;
535 }
536 
537 /** @brief Get log message level.
538  *
539  * @param msg Log message.
540  *
541  * @return Log level.
542  */
log_msg2_get_level(struct log_msg2 * msg)543 static inline uint8_t log_msg2_get_level(struct log_msg2 *msg)
544 {
545 	return msg->hdr.desc.level;
546 }
547 
548 /** @brief Get message source data.
549  *
550  * @param msg Log message.
551  *
552  * @return Pointer to the source data.
553  */
log_msg2_get_source(struct log_msg2 * msg)554 static inline const void *log_msg2_get_source(struct log_msg2 *msg)
555 {
556 	return msg->hdr.source;
557 }
558 
559 /** @brief Get timestamp.
560  *
561  * @param msg Log message.
562  *
563  * @return Timestamp.
564  */
log_msg2_get_timestamp(struct log_msg2 * msg)565 static inline log_timestamp_t log_msg2_get_timestamp(struct log_msg2 *msg)
566 {
567 	return msg->hdr.timestamp;
568 }
569 
570 /** @brief Get data buffer.
571  *
572  * @param msg log message.
573  *
574  * @param len location where data length is written.
575  *
576  * @return pointer to the data buffer.
577  */
log_msg2_get_data(struct log_msg2 * msg,size_t * len)578 static inline uint8_t *log_msg2_get_data(struct log_msg2 *msg, size_t *len)
579 {
580 	*len = msg->hdr.desc.data_len;
581 
582 	return msg->data + msg->hdr.desc.package_len;
583 }
584 
585 /** @brief Get string package.
586  *
587  * @param msg log message.
588  *
589  * @param len location where string package length is written.
590  *
591  * @return pointer to the package.
592  */
log_msg2_get_package(struct log_msg2 * msg,size_t * len)593 static inline uint8_t *log_msg2_get_package(struct log_msg2 *msg, size_t *len)
594 {
595 	*len = msg->hdr.desc.package_len;
596 
597 	return msg->data;
598 }
599 
600 /**
601  * @}
602  */
603 
604 #include <syscalls/log_msg2.h>
605 
606 #ifdef __cplusplus
607 }
608 #endif
609 
610 #endif /* ZEPHYR_INCLUDE_LOGGING_LOG_MSG2_H_ */
611