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