mirror of
https://github.com/zephyrproject-rtos/zephyr
synced 2025-09-11 13:33:04 +00:00
Update reserved function names starting with one underscore, replacing them as follows: '_k_' with 'z_' '_K_' with 'Z_' '_handler_' with 'z_handl_' '_Cstart' with 'z_cstart' '_Swap' with 'z_swap' This renaming is done on both global and those static function names in kernel/include and include/. Other static function names in kernel/ are renamed by removing the leading underscore. Other function names not starting with any prefix listed above are renamed starting with a 'z_' or 'Z_' prefix. Function names starting with two or three leading underscores are not automatcally renamed since these names will collide with the variants with two or three leading underscores. Various generator scripts have also been updated as well as perf, linker and usb files. These are drivers/serial/uart_handlers.c include/linker/kobject-text.ld kernel/include/syscall_handler.h scripts/gen_kobject_list.py scripts/gen_syscall_header.py Signed-off-by: Patrik Flykt <patrik.flykt@intel.com>
638 lines
15 KiB
C
638 lines
15 KiB
C
/*
|
|
* Copyright (c) 2018 Nordic Semiconductor ASA
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#include <logging/log_output.h>
|
|
#include <logging/log_ctrl.h>
|
|
#include <logging/log.h>
|
|
#include <assert.h>
|
|
#include <ctype.h>
|
|
#include <time.h>
|
|
#include <stdio.h>
|
|
#include <stdbool.h>
|
|
|
|
#define LOG_COLOR_CODE_DEFAULT "\x1B[0m"
|
|
#define LOG_COLOR_CODE_RED "\x1B[1;31m"
|
|
#define LOG_COLOR_CODE_YELLOW "\x1B[1;33m"
|
|
|
|
#define HEXDUMP_BYTES_IN_LINE 8
|
|
|
|
#define DROPPED_COLOR_PREFIX \
|
|
Z_LOG_EVAL(CONFIG_LOG_BACKEND_SHOW_COLOR, (LOG_COLOR_CODE_RED), ())
|
|
|
|
#define DROPPED_COLOR_POSTFIX \
|
|
Z_LOG_EVAL(CONFIG_LOG_BACKEND_SHOW_COLOR, (LOG_COLOR_CODE_DEFAULT), ())
|
|
|
|
static const char *const severity[] = {
|
|
NULL,
|
|
"err",
|
|
"wrn",
|
|
"inf",
|
|
"dbg"
|
|
};
|
|
|
|
static const char *const colors[] = {
|
|
NULL,
|
|
LOG_COLOR_CODE_RED, /* err */
|
|
LOG_COLOR_CODE_YELLOW, /* warn */
|
|
NULL, /* info */
|
|
NULL /* dbg */
|
|
};
|
|
|
|
static u32_t freq;
|
|
static u32_t timestamp_div;
|
|
|
|
typedef int (*out_func_t)(int c, void *ctx);
|
|
|
|
extern int _prf(int (*func)(), void *dest, char *format, va_list vargs);
|
|
extern void _vprintk(out_func_t out, void *log_output,
|
|
const char *fmt, va_list ap);
|
|
|
|
/* The RFC 5424 allows very flexible mapping and suggest the value 0 being the
|
|
* highest severity and 7 to be the lowest (debugging level) severity.
|
|
*
|
|
* 0 Emergency System is unusable
|
|
* 1 Alert Action must be taken immediately
|
|
* 2 Critical Critical conditions
|
|
* 3 Error Error conditions
|
|
* 4 Warning Warning conditions
|
|
* 5 Notice Normal but significant condition
|
|
* 6 Informational Informational messages
|
|
* 7 Debug Debug-level messages
|
|
*/
|
|
static int level_to_rfc5424_severity(u32_t level)
|
|
{
|
|
u8_t ret;
|
|
|
|
switch (level) {
|
|
case LOG_LEVEL_NONE:
|
|
ret = 7;
|
|
break;
|
|
case LOG_LEVEL_ERR:
|
|
ret = 3;
|
|
break;
|
|
case LOG_LEVEL_WRN:
|
|
ret = 4;
|
|
break;
|
|
case LOG_LEVEL_INF:
|
|
ret = 6;
|
|
break;
|
|
case LOG_LEVEL_DBG:
|
|
ret = 7;
|
|
break;
|
|
default:
|
|
ret = 7;
|
|
break;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int out_func(int c, void *ctx)
|
|
{
|
|
const struct log_output *out_ctx =
|
|
(const struct log_output *)ctx;
|
|
|
|
out_ctx->buf[out_ctx->control_block->offset] = (u8_t)c;
|
|
out_ctx->control_block->offset++;
|
|
|
|
assert(out_ctx->control_block->offset <= out_ctx->size);
|
|
|
|
if (out_ctx->control_block->offset == out_ctx->size) {
|
|
log_output_flush(out_ctx);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int print_formatted(const struct log_output *log_output,
|
|
const char *fmt, ...)
|
|
{
|
|
va_list args;
|
|
int length = 0;
|
|
|
|
va_start(args, fmt);
|
|
#if !defined(CONFIG_NEWLIB_LIBC) && !defined(CONFIG_ARCH_POSIX) && \
|
|
defined(CONFIG_LOG_ENABLE_FANCY_OUTPUT_FORMATTING)
|
|
length = _prf(out_func, (void *)log_output, (char *)fmt, args);
|
|
#else
|
|
_vprintk(out_func, (void *)log_output, fmt, args);
|
|
#endif
|
|
va_end(args);
|
|
|
|
return length;
|
|
}
|
|
|
|
static void buffer_write(log_output_func_t outf, u8_t *buf, size_t len,
|
|
void *ctx)
|
|
{
|
|
int processed;
|
|
|
|
do {
|
|
processed = outf(buf, len, ctx);
|
|
len -= processed;
|
|
buf += processed;
|
|
} while (len != 0);
|
|
}
|
|
|
|
void log_output_flush(const struct log_output *log_output)
|
|
{
|
|
buffer_write(log_output->func, log_output->buf,
|
|
log_output->control_block->offset,
|
|
log_output->control_block->ctx);
|
|
|
|
log_output->control_block->offset = 0;
|
|
}
|
|
|
|
static int timestamp_print(const struct log_output *log_output,
|
|
u32_t flags, u32_t timestamp)
|
|
{
|
|
int length;
|
|
bool format =
|
|
(flags & LOG_OUTPUT_FLAG_FORMAT_TIMESTAMP) |
|
|
(flags & LOG_OUTPUT_FLAG_FORMAT_SYSLOG);
|
|
|
|
|
|
if (!format) {
|
|
length = print_formatted(log_output, "[%08lu] ", timestamp);
|
|
} else if (freq != 0) {
|
|
u32_t remainder;
|
|
u32_t seconds;
|
|
u32_t hours;
|
|
u32_t mins;
|
|
u32_t ms;
|
|
u32_t us;
|
|
|
|
timestamp /= timestamp_div;
|
|
seconds = timestamp / freq;
|
|
hours = seconds / 3600;
|
|
seconds -= hours * 3600;
|
|
mins = seconds / 60;
|
|
seconds -= mins * 60;
|
|
|
|
remainder = timestamp % freq;
|
|
ms = (remainder * 1000) / freq;
|
|
us = (1000 * (1000 * remainder - (ms * freq))) / freq;
|
|
|
|
if (IS_ENABLED(CONFIG_LOG_BACKEND_NET) &&
|
|
flags & LOG_OUTPUT_FLAG_FORMAT_SYSLOG) {
|
|
#if defined(CONFIG_NEWLIB_LIBC)
|
|
char time_str[sizeof("1970-01-01T00:00:00")];
|
|
struct tm *tm;
|
|
time_t time;
|
|
|
|
time = seconds;
|
|
tm = gmtime(&time);
|
|
|
|
strftime(time_str, sizeof(time_str), "%FT%T", tm);
|
|
|
|
length = print_formatted(log_output, "%s.%06dZ ",
|
|
time_str, ms * 1000 + us);
|
|
#else
|
|
length = print_formatted(log_output,
|
|
"1970-01-01T%02d:%02d:%02d.%06dZ ",
|
|
hours, mins, seconds, ms * 1000 + us);
|
|
#endif
|
|
} else {
|
|
length = print_formatted(log_output,
|
|
"[%02d:%02d:%02d.%03d,%03d] ",
|
|
hours, mins, seconds, ms, us);
|
|
}
|
|
} else {
|
|
length = 0;
|
|
}
|
|
|
|
return length;
|
|
}
|
|
|
|
static void color_print(const struct log_output *log_output,
|
|
bool color, bool start, u32_t level)
|
|
{
|
|
if (color) {
|
|
const char *color = start && (colors[level] != NULL) ?
|
|
colors[level] : LOG_COLOR_CODE_DEFAULT;
|
|
print_formatted(log_output, "%s", color);
|
|
}
|
|
}
|
|
|
|
static void color_prefix(const struct log_output *log_output,
|
|
bool color, u32_t level)
|
|
{
|
|
color_print(log_output, color, true, level);
|
|
}
|
|
|
|
static void color_postfix(const struct log_output *log_output,
|
|
bool color, u32_t level)
|
|
{
|
|
color_print(log_output, color, false, level);
|
|
}
|
|
|
|
|
|
static int ids_print(const struct log_output *log_output, bool level_on,
|
|
bool func_on, u32_t domain_id, u32_t source_id, u32_t level)
|
|
{
|
|
int total = 0;
|
|
|
|
if (level_on) {
|
|
total += print_formatted(log_output, "<%s> ", severity[level]);
|
|
}
|
|
|
|
total += print_formatted(log_output,
|
|
(func_on &&
|
|
((1 << level) & LOG_FUNCTION_PREFIX_MASK)) ?
|
|
"%s." : "%s: ",
|
|
log_source_name_get(domain_id, source_id));
|
|
|
|
return total;
|
|
}
|
|
|
|
static void newline_print(const struct log_output *ctx, u32_t flags)
|
|
{
|
|
if (IS_ENABLED(CONFIG_LOG_BACKEND_NET) &&
|
|
flags & LOG_OUTPUT_FLAG_FORMAT_SYSLOG) {
|
|
return;
|
|
}
|
|
|
|
if ((flags & LOG_OUTPUT_FLAG_CRLF_NONE) != 0) {
|
|
return;
|
|
}
|
|
|
|
if ((flags & LOG_OUTPUT_FLAG_CRLF_LFONLY) != 0) {
|
|
print_formatted(ctx, "\n");
|
|
} else {
|
|
print_formatted(ctx, "\r\n");
|
|
}
|
|
}
|
|
|
|
static void std_print(struct log_msg *msg,
|
|
const struct log_output *log_output)
|
|
{
|
|
const char *str = log_msg_str_get(msg);
|
|
u32_t nargs = log_msg_nargs_get(msg);
|
|
u32_t *args = alloca(sizeof(u32_t)*nargs);
|
|
int i;
|
|
|
|
for (i = 0; i < nargs; i++) {
|
|
args[i] = log_msg_arg_get(msg, i);
|
|
}
|
|
|
|
switch (log_msg_nargs_get(msg)) {
|
|
case 0:
|
|
print_formatted(log_output, str);
|
|
break;
|
|
case 1:
|
|
print_formatted(log_output, str, args[0]);
|
|
break;
|
|
case 2:
|
|
print_formatted(log_output, str, args[0], args[1]);
|
|
break;
|
|
case 3:
|
|
print_formatted(log_output, str, args[0], args[1], args[2]);
|
|
break;
|
|
case 4:
|
|
print_formatted(log_output, str, args[0], args[1], args[2],
|
|
args[3]);
|
|
break;
|
|
case 5:
|
|
print_formatted(log_output, str, args[0], args[1], args[2],
|
|
args[3], args[4]);
|
|
break;
|
|
case 6:
|
|
print_formatted(log_output, str, args[0], args[1], args[2],
|
|
args[3], args[4], args[5]);
|
|
break;
|
|
case 7:
|
|
print_formatted(log_output, str, args[0], args[1], args[2],
|
|
args[3], args[4], args[5], args[6]);
|
|
break;
|
|
case 8:
|
|
print_formatted(log_output, str, args[0], args[1], args[2],
|
|
args[3], args[4], args[5], args[6], args[7]);
|
|
break;
|
|
case 9:
|
|
print_formatted(log_output, str, args[0], args[1], args[2],
|
|
args[3], args[4], args[5], args[6], args[7],
|
|
args[8]);
|
|
break;
|
|
case 10:
|
|
print_formatted(log_output, str, args[0], args[1], args[2],
|
|
args[3], args[4], args[5], args[6], args[7],
|
|
args[8], args[9]);
|
|
break;
|
|
case 11:
|
|
print_formatted(log_output, str, args[0], args[1], args[2],
|
|
args[3], args[4], args[5], args[6], args[7],
|
|
args[8], args[9], args[10]);
|
|
break;
|
|
case 12:
|
|
print_formatted(log_output, str, args[0], args[1], args[2],
|
|
args[3], args[4], args[5], args[6], args[7],
|
|
args[8], args[9], args[10], args[11]);
|
|
break;
|
|
case 13:
|
|
print_formatted(log_output, str, args[0], args[1], args[2],
|
|
args[3], args[4], args[5], args[6], args[7],
|
|
args[8], args[9], args[10], args[11], args[12]);
|
|
break;
|
|
case 14:
|
|
print_formatted(log_output, str, args[0], args[1], args[2],
|
|
args[3], args[4], args[5], args[6], args[7],
|
|
args[8], args[9], args[10], args[11], args[12],
|
|
args[13]);
|
|
break;
|
|
case 15:
|
|
print_formatted(log_output, str, args[0], args[1], args[2],
|
|
args[3], args[4], args[5], args[6], args[7],
|
|
args[8], args[9], args[10], args[11], args[12],
|
|
args[13], args[14]);
|
|
break;
|
|
default:
|
|
/* Unsupported number of arguments. */
|
|
assert(true);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void hexdump_line_print(const struct log_output *log_output,
|
|
const u8_t *data, u32_t length,
|
|
int prefix_offset, u32_t flags)
|
|
{
|
|
newline_print(log_output, flags);
|
|
|
|
for (int i = 0; i < prefix_offset; i++) {
|
|
print_formatted(log_output, " ");
|
|
}
|
|
|
|
for (int i = 0; i < HEXDUMP_BYTES_IN_LINE; i++) {
|
|
if (i < length) {
|
|
print_formatted(log_output, "%02x ", data[i]);
|
|
} else {
|
|
print_formatted(log_output, " ");
|
|
}
|
|
}
|
|
|
|
print_formatted(log_output, "|");
|
|
|
|
for (int i = 0; i < HEXDUMP_BYTES_IN_LINE; i++) {
|
|
if (i < length) {
|
|
char c = (char)data[i];
|
|
|
|
print_formatted(log_output, "%c",
|
|
isprint((int)c) ? c : '.');
|
|
} else {
|
|
print_formatted(log_output, " ");
|
|
}
|
|
}
|
|
}
|
|
|
|
static void hexdump_print(struct log_msg *msg,
|
|
const struct log_output *log_output,
|
|
int prefix_offset, u32_t flags)
|
|
{
|
|
u32_t offset = 0U;
|
|
u8_t buf[HEXDUMP_BYTES_IN_LINE];
|
|
size_t length;
|
|
|
|
print_formatted(log_output, "%s", log_msg_str_get(msg));
|
|
|
|
do {
|
|
length = sizeof(buf);
|
|
log_msg_hexdump_data_get(msg, buf, &length, offset);
|
|
|
|
if (length) {
|
|
hexdump_line_print(log_output, buf, length,
|
|
prefix_offset, flags);
|
|
offset += length;
|
|
} else {
|
|
break;
|
|
}
|
|
} while (true);
|
|
}
|
|
|
|
static void raw_string_print(struct log_msg *msg,
|
|
const struct log_output *log_output)
|
|
{
|
|
assert(log_output->size);
|
|
|
|
size_t offset = 0;
|
|
size_t length;
|
|
bool eol = false;
|
|
|
|
do {
|
|
length = log_output->size;
|
|
/* Sting is stored in a hexdump message. */
|
|
log_msg_hexdump_data_get(msg, log_output->buf, &length, offset);
|
|
log_output->control_block->offset = length;
|
|
|
|
if (length != 0) {
|
|
eol = (log_output->buf[length - 1] == '\n');
|
|
}
|
|
|
|
log_output_flush(log_output);
|
|
offset += length;
|
|
} while (length > 0);
|
|
|
|
if (eol) {
|
|
print_formatted(log_output, "\r");
|
|
}
|
|
}
|
|
|
|
static u32_t prefix_print(const struct log_output *log_output,
|
|
u32_t flags, bool func_on, u32_t timestamp, u8_t level,
|
|
u8_t domain_id, u16_t source_id)
|
|
{
|
|
u32_t length = 0;
|
|
|
|
bool stamp = flags & LOG_OUTPUT_FLAG_TIMESTAMP;
|
|
bool colors_on = flags & LOG_OUTPUT_FLAG_COLORS;
|
|
bool level_on = flags & LOG_OUTPUT_FLAG_LEVEL;
|
|
|
|
if (IS_ENABLED(CONFIG_LOG_BACKEND_NET) &&
|
|
flags & LOG_OUTPUT_FLAG_FORMAT_SYSLOG) {
|
|
/* TODO: As there is no way to figure out the
|
|
* facility at this point, use a pre-defined value.
|
|
* Change this to use the real facility of the
|
|
* logging call when that info is available.
|
|
*/
|
|
static const int facility = 16; /* local0 */
|
|
|
|
length += print_formatted(
|
|
log_output,
|
|
"<%d>1 ",
|
|
facility * 8 +
|
|
level_to_rfc5424_severity(level));
|
|
}
|
|
|
|
if (stamp) {
|
|
length += timestamp_print(log_output, flags, timestamp);
|
|
}
|
|
|
|
if (IS_ENABLED(CONFIG_LOG_BACKEND_NET) &&
|
|
flags & LOG_OUTPUT_FLAG_FORMAT_SYSLOG) {
|
|
length += print_formatted(
|
|
log_output, "%s - - - - ",
|
|
log_output->control_block->hostname ?
|
|
log_output->control_block->hostname :
|
|
"zephyr");
|
|
|
|
} else {
|
|
color_prefix(log_output, colors_on, level);
|
|
length += ids_print(log_output, level_on, func_on,
|
|
domain_id, source_id, level);
|
|
}
|
|
|
|
return length;
|
|
}
|
|
|
|
static void postfix_print(const struct log_output *log_output,
|
|
u32_t flags, u8_t level)
|
|
{
|
|
color_postfix(log_output, (flags & LOG_OUTPUT_FLAG_COLORS),
|
|
level);
|
|
newline_print(log_output, flags);
|
|
}
|
|
|
|
void log_output_msg_process(const struct log_output *log_output,
|
|
struct log_msg *msg,
|
|
u32_t flags)
|
|
{
|
|
bool std_msg = log_msg_is_std(msg);
|
|
u32_t timestamp = log_msg_timestamp_get(msg);
|
|
u8_t level = (u8_t)log_msg_level_get(msg);
|
|
u8_t domain_id = (u8_t)log_msg_domain_id_get(msg);
|
|
u16_t source_id = (u16_t)log_msg_source_id_get(msg);
|
|
bool raw_string = (level == LOG_LEVEL_INTERNAL_RAW_STRING);
|
|
int prefix_offset;
|
|
|
|
prefix_offset = raw_string ?
|
|
0 : prefix_print(log_output, flags, std_msg, timestamp,
|
|
level, domain_id, source_id);
|
|
|
|
if (log_msg_is_std(msg)) {
|
|
std_print(msg, log_output);
|
|
} else if (raw_string) {
|
|
raw_string_print(msg, log_output);
|
|
} else {
|
|
hexdump_print(msg, log_output, prefix_offset, flags);
|
|
}
|
|
|
|
if (!raw_string) {
|
|
postfix_print(log_output, flags, level);
|
|
}
|
|
|
|
log_output_flush(log_output);
|
|
}
|
|
|
|
static bool ends_with_newline(const char *fmt)
|
|
{
|
|
char c = '\0';
|
|
|
|
while (*fmt != '\0') {
|
|
c = *fmt;
|
|
fmt++;
|
|
}
|
|
|
|
return (c == '\n');
|
|
}
|
|
|
|
void log_output_string(const struct log_output *log_output,
|
|
struct log_msg_ids src_level, u32_t timestamp,
|
|
const char *fmt, va_list ap, u32_t flags)
|
|
{
|
|
int length;
|
|
u8_t level = (u8_t)src_level.level;
|
|
u8_t domain_id = (u8_t)src_level.domain_id;
|
|
u16_t source_id = (u16_t)src_level.source_id;
|
|
bool raw_string = (level == LOG_LEVEL_INTERNAL_RAW_STRING);
|
|
|
|
if (!raw_string) {
|
|
prefix_print(log_output, flags, true, timestamp,
|
|
level, domain_id, source_id);
|
|
}
|
|
|
|
#if !defined(CONFIG_NEWLIB_LIBC) && !defined(CONFIG_ARCH_POSIX) && \
|
|
defined(CONFIG_LOG_ENABLE_FANCY_OUTPUT_FORMATTING)
|
|
length = _prf(out_func, (void *)log_output, (char *)fmt, ap);
|
|
#else
|
|
_vprintk(out_func, (void *)log_output, fmt, ap);
|
|
#endif
|
|
|
|
(void)length;
|
|
|
|
if (raw_string) {
|
|
/* add \r if string ends with newline. */
|
|
if (ends_with_newline(fmt)) {
|
|
print_formatted(log_output, "\r");
|
|
}
|
|
} else {
|
|
postfix_print(log_output, flags, level);
|
|
}
|
|
|
|
log_output_flush(log_output);
|
|
}
|
|
|
|
void log_output_hexdump(const struct log_output *log_output,
|
|
struct log_msg_ids src_level, u32_t timestamp,
|
|
const char *metadata, const u8_t *data,
|
|
u32_t length, u32_t flags)
|
|
{
|
|
u32_t prefix_offset;
|
|
u8_t level = (u8_t)src_level.level;
|
|
u8_t domain_id = (u8_t)src_level.domain_id;
|
|
u16_t source_id = (u16_t)src_level.source_id;
|
|
|
|
prefix_offset = prefix_print(log_output, flags, true, timestamp,
|
|
level, domain_id, source_id);
|
|
|
|
/* Print metadata */
|
|
print_formatted(log_output, "%s", metadata);
|
|
|
|
while (length) {
|
|
u32_t part_len = length > HEXDUMP_BYTES_IN_LINE ?
|
|
HEXDUMP_BYTES_IN_LINE : length;
|
|
|
|
hexdump_line_print(log_output, data, part_len,
|
|
prefix_offset, flags);
|
|
|
|
data += part_len;
|
|
length -= part_len;
|
|
};
|
|
|
|
postfix_print(log_output, flags, level);
|
|
log_output_flush(log_output);
|
|
}
|
|
|
|
void log_output_dropped_process(const struct log_output *log_output, u32_t cnt)
|
|
{
|
|
char buf[5];
|
|
int len;
|
|
static const char prefix[] = DROPPED_COLOR_PREFIX "--- ";
|
|
static const char postfix[] =
|
|
" messages dropped ---\r\n" DROPPED_COLOR_POSTFIX;
|
|
log_output_func_t outf = log_output->func;
|
|
struct device *dev = (struct device *)log_output->control_block->ctx;
|
|
|
|
cnt = MIN(cnt, 9999);
|
|
len = snprintf(buf, sizeof(buf), "%d", cnt);
|
|
|
|
buffer_write(outf, (u8_t *)prefix, sizeof(prefix) - 1, dev);
|
|
buffer_write(outf, buf, len, dev);
|
|
buffer_write(outf, (u8_t *)postfix, sizeof(postfix) - 1, dev);
|
|
}
|
|
|
|
void log_output_timestamp_freq_set(u32_t frequency)
|
|
{
|
|
timestamp_div = 1U;
|
|
/* There is no point to have frequency higher than 1MHz (ns are not
|
|
* printed) and too high frequency leads to overflows in calculations.
|
|
*/
|
|
while (frequency > 1000000) {
|
|
frequency /= 2;
|
|
timestamp_div *= 2;
|
|
}
|
|
|
|
freq = frequency;
|
|
}
|