1 /*
2 * Copyright (c) 2020 Nordic Semiconductor
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6 #include <zephyr/kernel.h>
7 #include <zephyr/internal/syscall_handler.h>
8 #include <zephyr/logging/log_internal.h>
9 #include <zephyr/logging/log_ctrl.h>
10 #include <zephyr/logging/log_frontend.h>
11 #include <zephyr/logging/log_backend.h>
12 #include <zephyr/logging/log.h>
13 #include <zephyr/llext/symbol.h>
14 LOG_MODULE_DECLARE(log);
15
16 BUILD_ASSERT(sizeof(struct log_msg_desc) == sizeof(uint32_t),
17 "Descriptor must fit in 32 bits");
18
19 /* Returns true if any backend is in use. */
20 #define BACKENDS_IN_USE() \
21 !(IS_ENABLED(CONFIG_LOG_FRONTEND) && \
22 (IS_ENABLED(CONFIG_LOG_FRONTEND_ONLY) || log_backend_count_get() == 0))
23
24 #define CBPRINTF_DESC_SIZE32 (sizeof(struct cbprintf_package_desc) / sizeof(uint32_t))
25
26 /* For simplified message handling cprintf package must have only 1 word. */
27 BUILD_ASSERT(!IS_ENABLED(CONFIG_LOG_SIMPLE_MSG_OPTIMIZE) ||
28 (IS_ENABLED(CONFIG_LOG_SIMPLE_MSG_OPTIMIZE) && (CBPRINTF_DESC_SIZE32 == 1)));
29
30
z_log_msg_finalize(struct log_msg * msg,const void * source,const struct log_msg_desc desc,const void * data)31 void z_log_msg_finalize(struct log_msg *msg, const void *source,
32 const struct log_msg_desc desc, const void *data)
33 {
34 if (!msg) {
35 z_log_dropped(false);
36
37 return;
38 }
39
40 if (data) {
41 uint8_t *d = msg->data + desc.package_len;
42
43 memcpy(d, data, desc.data_len);
44 }
45
46 msg->hdr.desc = desc;
47 msg->hdr.source = source;
48 #if CONFIG_LOG_THREAD_ID_PREFIX
49 msg->hdr.tid = k_is_in_isr() ? NULL : k_current_get();
50 #endif
51 z_log_msg_commit(msg);
52 }
53
frontend_runtime_filtering(const void * source,uint32_t level)54 static bool frontend_runtime_filtering(const void *source, uint32_t level)
55 {
56 if (!IS_ENABLED(CONFIG_LOG_RUNTIME_FILTERING)) {
57 return true;
58 }
59
60 /* If only frontend is used and log got here it means that it was accepted
61 * unless userspace is enabled then runtime filtering is done here.
62 */
63 if (!IS_ENABLED(CONFIG_USERSPACE) && IS_ENABLED(CONFIG_LOG_FRONTEND_ONLY)) {
64 return true;
65 }
66
67 if (level == LOG_LEVEL_NONE) {
68 return true;
69 }
70
71 struct log_source_dynamic_data *dynamic = (struct log_source_dynamic_data *)source;
72 uint32_t f_level = LOG_FILTER_SLOT_GET(&dynamic->filters, LOG_FRONTEND_SLOT_ID);
73
74 return level <= f_level;
75 }
76
77 /** @brief Create a log message using simplified method.
78 *
79 * Simple log message has 0-2 32 bit word arguments so creating cbprintf package
80 * is straightforward as there is no padding or alignment to concern about.
81 * This function takes input data which is fmt pointer + 0-2 arguments, creates
82 * package header which is very simple as it only contain non-zero length field.
83 * Then space is allocated and message is committed. Such simple approach can
84 * be applied because it is known that input string does not have any arguments
85 * which complicate things (string pointers, floating numbers). Simple method is
86 * also limited to 32 bit arch.
87 *
88 * @param source Source.
89 * @param level Severity level.
90 * @param data Package content (without header).
91 * @param len Package content length in words.
92 */
z_log_msg_simple_create(const void * source,uint32_t level,uint32_t * data,size_t len)93 static void z_log_msg_simple_create(const void *source, uint32_t level, uint32_t *data, size_t len)
94 {
95 /* Package length (in words) is increased by the header. */
96 size_t plen32 = len + CBPRINTF_DESC_SIZE32;
97 /* Package length in bytes. */
98 size_t plen8 = sizeof(uint32_t) * plen32 +
99 (IS_ENABLED(CONFIG_LOG_MSG_APPEND_RO_STRING_LOC) ? 1 : 0);
100 struct log_msg *msg = z_log_msg_alloc(Z_LOG_MSG_ALIGNED_WLEN(plen8, 0));
101 union cbprintf_package_hdr package_hdr = {
102 .desc = {
103 .len = plen32,
104 .ro_str_cnt = IS_ENABLED(CONFIG_LOG_MSG_APPEND_RO_STRING_LOC) ? 1 : 0
105 }
106 };
107
108 if (msg) {
109 uint32_t *package = (uint32_t *)msg->data;
110
111 *package++ = (uint32_t)(uintptr_t)package_hdr.raw;
112 for (size_t i = 0; i < len; i++) {
113 *package++ = data[i];
114 }
115 if (IS_ENABLED(CONFIG_LOG_MSG_APPEND_RO_STRING_LOC)) {
116 /* fmt string located at index 1 */
117 *(uint8_t *)package = 1;
118 }
119 }
120
121 struct log_msg_desc desc = {
122 .level = level,
123 .package_len = plen8,
124 .data_len = 0,
125 };
126
127 z_log_msg_finalize(msg, source, desc, NULL);
128 }
129
z_impl_z_log_msg_simple_create_0(const void * source,uint32_t level,const char * fmt)130 void z_impl_z_log_msg_simple_create_0(const void *source, uint32_t level, const char *fmt)
131 {
132
133 if (IS_ENABLED(CONFIG_LOG_FRONTEND) && frontend_runtime_filtering(source, level)) {
134 if (IS_ENABLED(CONFIG_LOG_FRONTEND_OPT_API)) {
135 log_frontend_simple_0(source, level, fmt);
136 } else {
137 /* If frontend does not support optimized API prepare data for
138 * the generic call.
139 */
140 uint32_t plen32 = CBPRINTF_DESC_SIZE32 + 1;
141 union cbprintf_package_hdr hdr = {
142 .desc = {
143 .len = plen32,
144 .ro_str_cnt =
145 IS_ENABLED(CONFIG_LOG_MSG_APPEND_RO_STRING_LOC) ? 1 : 0
146 }
147 };
148 uint8_t package[sizeof(uint32_t) * (CBPRINTF_DESC_SIZE32 + 1) +
149 (IS_ENABLED(CONFIG_LOG_MSG_APPEND_RO_STRING_LOC) ? 1 : 0)]
150 __aligned(sizeof(uint32_t));
151 uint32_t *p32 = (uint32_t *)package;
152
153 *p32++ = (uint32_t)(uintptr_t)hdr.raw;
154 *p32++ = (uint32_t)(uintptr_t)fmt;
155 if (IS_ENABLED(CONFIG_LOG_MSG_APPEND_RO_STRING_LOC)) {
156 /* fmt string located at index 1 */
157 *(uint8_t *)p32 = 1;
158 }
159
160 struct log_msg_desc desc = {
161 .level = level,
162 .package_len = sizeof(package),
163 .data_len = 0,
164 };
165
166 log_frontend_msg(source, desc, package, NULL);
167 }
168 }
169
170 if (!BACKENDS_IN_USE()) {
171 return;
172 }
173
174 uint32_t data[] = {(uint32_t)(uintptr_t)fmt};
175
176 z_log_msg_simple_create(source, level, data, ARRAY_SIZE(data));
177 }
178
z_impl_z_log_msg_simple_create_1(const void * source,uint32_t level,const char * fmt,uint32_t arg)179 void z_impl_z_log_msg_simple_create_1(const void *source, uint32_t level,
180 const char *fmt, uint32_t arg)
181 {
182 if (IS_ENABLED(CONFIG_LOG_FRONTEND) && frontend_runtime_filtering(source, level)) {
183 if (IS_ENABLED(CONFIG_LOG_FRONTEND_OPT_API)) {
184 log_frontend_simple_1(source, level, fmt, arg);
185 } else {
186 /* If frontend does not support optimized API prepare data for
187 * the generic call.
188 */
189 uint32_t plen32 = CBPRINTF_DESC_SIZE32 + 2;
190 union cbprintf_package_hdr hdr = {
191 .desc = {
192 .len = plen32,
193 .ro_str_cnt =
194 IS_ENABLED(CONFIG_LOG_MSG_APPEND_RO_STRING_LOC) ? 1 : 0
195 }
196 };
197 uint8_t package[sizeof(uint32_t) * (CBPRINTF_DESC_SIZE32 + 2) +
198 (IS_ENABLED(CONFIG_LOG_MSG_APPEND_RO_STRING_LOC) ? 1 : 0)]
199 __aligned(sizeof(uint32_t));
200 uint32_t *p32 = (uint32_t *)package;
201
202 *p32++ = (uint32_t)(uintptr_t)hdr.raw;
203 *p32++ = (uint32_t)(uintptr_t)fmt;
204 *p32++ = arg;
205 if (IS_ENABLED(CONFIG_LOG_MSG_APPEND_RO_STRING_LOC)) {
206 /* fmt string located at index 1 */
207 *(uint8_t *)p32 = 1;
208 }
209
210 struct log_msg_desc desc = {
211 .level = level,
212 .package_len = sizeof(package),
213 .data_len = 0,
214 };
215
216 log_frontend_msg(source, desc, package, NULL);
217 }
218 }
219
220 if (!BACKENDS_IN_USE()) {
221 return;
222 }
223
224 uint32_t data[] = {(uint32_t)(uintptr_t)fmt, arg};
225
226 z_log_msg_simple_create(source, level, data, ARRAY_SIZE(data));
227 }
228
z_impl_z_log_msg_simple_create_2(const void * source,uint32_t level,const char * fmt,uint32_t arg0,uint32_t arg1)229 void z_impl_z_log_msg_simple_create_2(const void *source, uint32_t level,
230 const char *fmt, uint32_t arg0, uint32_t arg1)
231 {
232 if (IS_ENABLED(CONFIG_LOG_FRONTEND) && frontend_runtime_filtering(source, level)) {
233 if (IS_ENABLED(CONFIG_LOG_FRONTEND_OPT_API)) {
234 log_frontend_simple_2(source, level, fmt, arg0, arg1);
235 } else {
236 /* If frontend does not support optimized API prepare data for
237 * the generic call.
238 */
239 uint32_t plen32 = CBPRINTF_DESC_SIZE32 + 3;
240 union cbprintf_package_hdr hdr = {
241 .desc = {
242 .len = plen32,
243 .ro_str_cnt =
244 IS_ENABLED(CONFIG_LOG_MSG_APPEND_RO_STRING_LOC) ? 1 : 0
245 }
246 };
247 uint8_t package[sizeof(uint32_t) * (CBPRINTF_DESC_SIZE32 + 3) +
248 (IS_ENABLED(CONFIG_LOG_MSG_APPEND_RO_STRING_LOC) ? 1 : 0)]
249 __aligned(sizeof(uint32_t));
250 uint32_t *p32 = (uint32_t *)package;
251
252 *p32++ = (uint32_t)(uintptr_t)hdr.raw;
253 *p32++ = (uint32_t)(uintptr_t)fmt;
254 *p32++ = arg0;
255 *p32++ = arg1;
256 if (IS_ENABLED(CONFIG_LOG_MSG_APPEND_RO_STRING_LOC)) {
257 /* fmt string located at index 1 */
258 *(uint8_t *)p32 = 1;
259 }
260
261 struct log_msg_desc desc = {
262 .level = level,
263 .package_len = sizeof(package),
264 .data_len = 0,
265 };
266
267 log_frontend_msg(source, desc, package, NULL);
268 }
269 }
270
271 if (!BACKENDS_IN_USE()) {
272 return;
273 }
274
275 uint32_t data[] = {(uint32_t)(uintptr_t)fmt, arg0, arg1};
276
277 z_log_msg_simple_create(source, level, data, ARRAY_SIZE(data));
278 }
279
z_impl_z_log_msg_static_create(const void * source,const struct log_msg_desc desc,uint8_t * package,const void * data)280 void z_impl_z_log_msg_static_create(const void *source,
281 const struct log_msg_desc desc,
282 uint8_t *package, const void *data)
283 {
284 if (IS_ENABLED(CONFIG_LOG_FRONTEND) && frontend_runtime_filtering(source, desc.level)) {
285 log_frontend_msg(source, desc, package, data);
286 }
287
288 if (!BACKENDS_IN_USE()) {
289 return;
290 }
291
292 struct log_msg_desc out_desc = desc;
293 int inlen = desc.package_len;
294 struct log_msg *msg;
295
296 if (inlen > 0) {
297 uint32_t flags = CBPRINTF_PACKAGE_CONVERT_RW_STR |
298 (IS_ENABLED(CONFIG_LOG_MSG_APPEND_RO_STRING_LOC) ?
299 CBPRINTF_PACKAGE_CONVERT_KEEP_RO_STR : 0) |
300 (IS_ENABLED(CONFIG_LOG_FMT_SECTION_STRIP) ?
301 0 : CBPRINTF_PACKAGE_CONVERT_PTR_CHECK);
302 uint16_t strl[4];
303 int len;
304
305 len = cbprintf_package_copy(package, inlen,
306 NULL, 0, flags,
307 strl, ARRAY_SIZE(strl));
308
309 if (len > Z_LOG_MSG_MAX_PACKAGE) {
310 struct cbprintf_package_hdr_ext *pkg =
311 (struct cbprintf_package_hdr_ext *)package;
312
313 LOG_WRN("Message (\"%s\") dropped because it exceeds size limitation (%u)",
314 pkg->fmt, (uint32_t)Z_LOG_MSG_MAX_PACKAGE);
315 return;
316 }
317 /* Update package length with calculated value (which may be extended
318 * when strings are copied into the package.
319 */
320 out_desc.package_len = len;
321 msg = z_log_msg_alloc(log_msg_get_total_wlen(out_desc));
322 if (msg) {
323 len = cbprintf_package_copy(package, inlen,
324 msg->data, out_desc.package_len,
325 flags, strl, ARRAY_SIZE(strl));
326 __ASSERT_NO_MSG(len >= 0);
327 }
328 } else {
329 msg = z_log_msg_alloc(log_msg_get_total_wlen(out_desc));
330 }
331
332 z_log_msg_finalize(msg, source, out_desc, data);
333 }
334
335 #ifdef CONFIG_USERSPACE
z_vrfy_z_log_msg_static_create(const void * source,const struct log_msg_desc desc,uint8_t * package,const void * data)336 static inline void z_vrfy_z_log_msg_static_create(const void *source,
337 const struct log_msg_desc desc,
338 uint8_t *package, const void *data)
339 {
340 z_impl_z_log_msg_static_create(source, desc, package, data);
341 }
342 #include <zephyr/syscalls/z_log_msg_static_create_mrsh.c>
343 #endif
344
z_log_msg_runtime_vcreate(uint8_t domain_id,const void * source,uint8_t level,const void * data,size_t dlen,uint32_t package_flags,const char * fmt,va_list ap)345 void z_log_msg_runtime_vcreate(uint8_t domain_id, const void *source,
346 uint8_t level, const void *data, size_t dlen,
347 uint32_t package_flags, const char *fmt, va_list ap)
348 {
349 int plen;
350
351 if (fmt) {
352 va_list ap2;
353
354 va_copy(ap2, ap);
355 plen = cbvprintf_package(NULL, Z_LOG_MSG_ALIGN_OFFSET,
356 package_flags, fmt, ap2);
357 __ASSERT_NO_MSG(plen >= 0);
358 va_end(ap2);
359 } else {
360 plen = 0;
361 }
362
363 if (plen > Z_LOG_MSG_MAX_PACKAGE) {
364 LOG_WRN("Message dropped because it exceeds size limitation (%u)",
365 (uint32_t)Z_LOG_MSG_MAX_PACKAGE);
366 return;
367 }
368
369 size_t msg_wlen = Z_LOG_MSG_ALIGNED_WLEN(plen, dlen);
370 struct log_msg *msg;
371 uint8_t *pkg;
372 struct log_msg_desc desc =
373 Z_LOG_MSG_DESC_INITIALIZER(domain_id, level, plen, dlen);
374
375 if (IS_ENABLED(CONFIG_LOG_MODE_DEFERRED) && BACKENDS_IN_USE()) {
376 msg = z_log_msg_alloc(msg_wlen);
377 if (IS_ENABLED(CONFIG_LOG_FRONTEND) && msg == NULL) {
378 pkg = alloca(plen);
379 } else {
380 pkg = msg ? msg->data : NULL;
381 }
382 } else {
383 msg = alloca(msg_wlen * sizeof(int));
384 pkg = msg->data;
385 }
386
387 if (pkg && fmt) {
388 plen = cbvprintf_package(pkg, (size_t)plen, package_flags, fmt, ap);
389 __ASSERT_NO_MSG(plen >= 0);
390 }
391
392 if (IS_ENABLED(CONFIG_LOG_FRONTEND) && frontend_runtime_filtering(source, desc.level)) {
393 log_frontend_msg(source, desc, pkg, data);
394 }
395
396 if (BACKENDS_IN_USE()) {
397 z_log_msg_finalize(msg, source, desc, data);
398 }
399 }
400 EXPORT_SYMBOL(z_log_msg_runtime_vcreate);
401
log_msg_get_source_id(struct log_msg * msg)402 int16_t log_msg_get_source_id(struct log_msg *msg)
403 {
404 if (!z_log_is_local_domain(log_msg_get_domain(msg))) {
405 /* Remote domain is converting source pointer to ID */
406 return (int16_t)(uintptr_t)log_msg_get_source(msg);
407 }
408
409 void *source = (void *)log_msg_get_source(msg);
410
411 if (source != NULL) {
412 return log_source_id(source);
413 }
414
415 return -1;
416 }
417