Branch data Line data Source code
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 : :
31 : 177 : void z_log_msg_finalize(struct log_msg *msg, const void *source,
32 : : const struct log_msg_desc desc, const void *data)
33 : : {
34 [ - + ]: 177 : if (!msg) {
35 : 0 : z_log_dropped(false);
36 : :
37 : 0 : return;
38 : : }
39 : :
40 [ - + ]: 177 : if (data) {
41 : 0 : uint8_t *d = msg->data + desc.package_len;
42 : :
43 : 0 : memcpy(d, data, desc.data_len);
44 : : }
45 : :
46 : 177 : msg->hdr.desc = desc;
47 : 177 : 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 : 177 : z_log_msg_commit(msg);
52 : : }
53 : :
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 : : */
93 : 0 : 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 : 0 : size_t plen32 = len + CBPRINTF_DESC_SIZE32;
97 : : /* Package length in bytes. */
98 : 0 : size_t plen8 = sizeof(uint32_t) * plen32 +
99 : : (IS_ENABLED(CONFIG_LOG_MSG_APPEND_RO_STRING_LOC) ? 1 : 0);
100 : 0 : struct log_msg *msg = z_log_msg_alloc(Z_LOG_MSG_ALIGNED_WLEN(plen8, 0));
101 : 0 : 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 [ # # ]: 0 : if (msg) {
109 : 0 : uint32_t *package = (uint32_t *)msg->data;
110 : :
111 : 0 : *package++ = (uint32_t)(uintptr_t)package_hdr.raw;
112 [ # # ]: 0 : for (size_t i = 0; i < len; i++) {
113 : 0 : *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 : 0 : struct log_msg_desc desc = {
122 : : .level = level,
123 : : .package_len = plen8,
124 : : .data_len = 0,
125 : : };
126 : :
127 : 0 : z_log_msg_finalize(msg, source, desc, NULL);
128 : 0 : }
129 : :
130 : 0 : void z_impl_z_log_msg_simple_create_0(const void *source, uint32_t level, const char *fmt)
131 : : {
132 : :
133 : 0 : 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 : 0 : if (!BACKENDS_IN_USE()) {
171 : : return;
172 : : }
173 : :
174 : 0 : uint32_t data[] = {(uint32_t)(uintptr_t)fmt};
175 : :
176 : 0 : z_log_msg_simple_create(source, level, data, ARRAY_SIZE(data));
177 : : }
178 : :
179 : 0 : void z_impl_z_log_msg_simple_create_1(const void *source, uint32_t level,
180 : : const char *fmt, uint32_t arg)
181 : : {
182 : 0 : 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 : 0 : if (!BACKENDS_IN_USE()) {
221 : : return;
222 : : }
223 : :
224 : 0 : uint32_t data[] = {(uint32_t)(uintptr_t)fmt, arg};
225 : :
226 : 0 : z_log_msg_simple_create(source, level, data, ARRAY_SIZE(data));
227 : : }
228 : :
229 : 0 : 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 : 0 : 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 : 0 : if (!BACKENDS_IN_USE()) {
272 : : return;
273 : : }
274 : :
275 : 0 : uint32_t data[] = {(uint32_t)(uintptr_t)fmt, arg0, arg1};
276 : :
277 : 0 : z_log_msg_simple_create(source, level, data, ARRAY_SIZE(data));
278 : : }
279 : :
280 : 0 : 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 : 0 : if (IS_ENABLED(CONFIG_LOG_FRONTEND) && frontend_runtime_filtering(source, desc.level)) {
285 : : log_frontend_msg(source, desc, package, data);
286 : : }
287 : :
288 : 0 : if (!BACKENDS_IN_USE()) {
289 : 0 : return;
290 : : }
291 : :
292 : 0 : struct log_msg_desc out_desc = desc;
293 : 0 : int inlen = desc.package_len;
294 : 0 : struct log_msg *msg;
295 : :
296 [ # # ]: 0 : if (inlen > 0) {
297 : 0 : 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 : 0 : uint16_t strl[4];
303 : 0 : int len;
304 : :
305 : 0 : len = cbprintf_package_copy(package, inlen,
306 : : NULL, 0, flags,
307 : : strl, ARRAY_SIZE(strl));
308 : :
309 [ # # ]: 0 : if (len > Z_LOG_MSG_MAX_PACKAGE) {
310 : 0 : struct cbprintf_package_hdr_ext *pkg =
311 : : (struct cbprintf_package_hdr_ext *)package;
312 : :
313 : 0 : LOG_WRN("Message (\"%s\") dropped because it exceeds size limitation (%u)",
314 : : pkg->fmt, (uint32_t)Z_LOG_MSG_MAX_PACKAGE);
315 : 0 : return;
316 : : }
317 : : /* Update package length with calculated value (which may be extended
318 : : * when strings are copied into the package.
319 : : */
320 : 0 : out_desc.package_len = len;
321 : 0 : msg = z_log_msg_alloc(log_msg_get_total_wlen(out_desc));
322 [ # # ]: 0 : if (msg) {
323 : 0 : len = cbprintf_package_copy(package, inlen,
324 : 0 : msg->data, out_desc.package_len,
325 : : flags, strl, ARRAY_SIZE(strl));
326 [ # # ]: 0 : __ASSERT_NO_MSG(len >= 0);
327 : : }
328 : : } else {
329 : 0 : msg = z_log_msg_alloc(log_msg_get_total_wlen(out_desc));
330 : : }
331 : :
332 : 0 : z_log_msg_finalize(msg, source, out_desc, data);
333 : : }
334 : :
335 : : #ifdef CONFIG_USERSPACE
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 : : return 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 : :
345 : 177 : 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 : 177 : int plen;
350 : :
351 [ + - ]: 177 : if (fmt) {
352 : 177 : va_list ap2;
353 : :
354 : 177 : va_copy(ap2, ap);
355 : 177 : plen = cbvprintf_package(NULL, Z_LOG_MSG_ALIGN_OFFSET,
356 : : package_flags, fmt, ap2);
357 [ - + ]: 177 : __ASSERT_NO_MSG(plen >= 0);
358 : 177 : va_end(ap2);
359 : : } else {
360 : : plen = 0;
361 : : }
362 : :
363 [ - + ]: 177 : if (plen > Z_LOG_MSG_MAX_PACKAGE) {
364 : 0 : LOG_WRN("Message dropped because it exceeds size limitation (%u)",
365 : : (uint32_t)Z_LOG_MSG_MAX_PACKAGE);
366 : 0 : return;
367 : : }
368 : :
369 : 177 : size_t msg_wlen = Z_LOG_MSG_ALIGNED_WLEN(plen, dlen);
370 : 177 : struct log_msg *msg;
371 : 177 : uint8_t *pkg;
372 : 177 : struct log_msg_desc desc =
373 : : Z_LOG_MSG_DESC_INITIALIZER(domain_id, level, plen, dlen);
374 : :
375 : 177 : 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 : 177 : msg = alloca(msg_wlen * sizeof(int));
384 : 177 : pkg = msg->data;
385 : : }
386 : :
387 [ + - ]: 177 : if (pkg && fmt) {
388 : 177 : plen = cbvprintf_package(pkg, (size_t)plen, package_flags, fmt, ap);
389 [ - + ]: 177 : __ASSERT_NO_MSG(plen >= 0);
390 : : }
391 : :
392 : 177 : if (IS_ENABLED(CONFIG_LOG_FRONTEND) && frontend_runtime_filtering(source, desc.level)) {
393 : : log_frontend_msg(source, desc, pkg, data);
394 : : }
395 : :
396 : 177 : if (BACKENDS_IN_USE()) {
397 : 177 : z_log_msg_finalize(msg, source, desc, data);
398 : : }
399 : : }
400 : : EXPORT_SYMBOL(z_log_msg_runtime_vcreate);
401 : :
402 : 177 : int16_t log_msg_get_source_id(struct log_msg *msg)
403 : : {
404 [ - + ]: 177 : if (!z_log_is_local_domain(log_msg_get_domain(msg))) {
405 : : /* Remote domain is converting source pointer to ID */
406 : 0 : return (int16_t)(uintptr_t)log_msg_get_source(msg);
407 : : }
408 : :
409 : 177 : void *source = (void *)log_msg_get_source(msg);
410 : :
411 [ - + ]: 177 : if (source != NULL) {
412 : 0 : return IS_ENABLED(CONFIG_LOG_RUNTIME_FILTERING)
413 : : ? log_dynamic_source_id(source)
414 : 0 : : log_const_source_id(source);
415 : : }
416 : :
417 : : return -1;
418 : : }
|