Software APIs
log.h
Go to the documentation of this file.
1// Copyright lowRISC contributors (OpenTitan project).
2// Licensed under the Apache License, Version 2.0, see LICENSE for details.
3// SPDX-License-Identifier: Apache-2.0
4
5#ifndef OPENTITAN_SW_DEVICE_LIB_RUNTIME_LOG_H_
6#define OPENTITAN_SW_DEVICE_LIB_RUNTIME_LOG_H_
7
8#include <stdbool.h>
9#include <stdint.h>
10
13
14/**
15 * @file
16 * @brief Generic logging APIs
17 *
18 * The logging APIs below take a format string with a variable number of
19 * arguments for the type specifiers. The APIs are designed to provide a way
20 * for attaching the log severity, file name, and line number
21 * information along with the message to provide an easier path to debug.
22 * These parameters form a log prefix, which is prepended to the actual
23 * message being printed. The following is a brief description of these:
24 *
25 * log_type: Severity of the message: info, warning, error or fatal
26 *
27 * file name: Name of the file using __FILE__
28 *
29 * line number: Line where the print originated using __LINE__
30 *
31 * Log macros support OpenTitan formatting specifiers; see print.h for
32 * details the subset of C specifier syntax supported.
33 *
34 * The precise mechanism for logging is dependent on the target device. On core
35 * devices, like Verilator, logs are printed using whatever `stdout` is set to
36 * in print.h. DV testbenches may use an alternative, more efficient mechanism.
37 *
38 * In DV mode, some format specifiers may be unsupported, such as %s.
39 */
40
41/**
42 * Log severities available.
43 *
44 * Additional log severities can be added as necessary.
45 */
46typedef enum log_severity {
47 kLogSeverityInfo,
48 kLogSeverityWarn,
49 kLogSeverityError,
50 kLogSeverityFatal,
52
53/**
54 * Represents log metadata used to format a log line.
55 *
56 * Any modification to this struct must be made with caution due to external
57 * assumptions. A post-processing script parses the ELF file and extracts the
58 * log fields. The said script uses 20-byte size as the delimiter to collect the
59 * log fields. Any changes to this struct must be accompanied with the updates
60 * to the script, located here:
61 * util/device_sw_utils/extract_sw_logs.py.
62 */
63typedef struct log_fields {
64 /**
65 * Indicates the severity of the LOG.
66 */
68 /**
69 * Name of the file at which a LOG line occurs, e.g. `__FILE__`. There
70 * are no requirements for this string, other than that it be some kind of
71 * UNIX-like pathname.
72 */
73 const char *file_name;
74 /**
75 * Indicates the line number at which the LOG line occurs, e.g., `__LINE__`.
76 */
77 uint32_t line;
78 /**
79 * Indicates the number of arguments passed to the format string.
80 *
81 * This value used only in DV mode, and is ignored by non-DV logging.
82 */
83 uint32_t nargs;
84 /**
85 * The actual format string.
86 */
87 const char *format;
89
90// Internal functions exposed only for access by macros. Their
91// real doxygen can be found in log.c.
92/**
93 * Implementation detail.
94 */
95void base_log_internal_core(const log_fields_t *log, ...);
96/**
97 * Implementation detail.
98 */
99void base_log_internal_dv(const log_fields_t *log, uint32_t nargs, ...);
100
101extern char _dv_log_offset[];
102
103/**
104 * A macro that wraps the `OT_FAIL_IF_64_BIT` macro, providing the name
105 * of the LOG macro for better error messages.
106 *
107 * @param arg an arg/expression to check
108 */
109#define OT_FAIL_IF_64_BIT_LOG(arg) OT_FAIL_IF_64_BIT(arg, LOG)
110
111/**
112 * A macro that checks the variable arguments of the `LOG` function are valid
113 * at compile time, by asserting that each of the argument is not a standard
114 * C integer type with a width of 64 bits. Any such invalid argument will
115 * cause a relevant error via a static assertion.
116 *
117 * @param ... the variable args list
118 */
119#define OT_CHECK_VALID_LOG_ARGS(...) \
120 OT_VA_FOR_EACH(OT_FAIL_IF_64_BIT_LOG, ##__VA_ARGS__)
121
122/**
123 * Basic logging macro that all other logging macros delegate to.
124 *
125 * Prefer to use a LOG function with a specified severity, instead.
126 *
127 * @param severity a severity of type `log_severity_t`.
128 * @param format a format string, as described in print.h. This must be a
129 * string literal.
130 * @param ... format parameters matching the format string.
131 */
132#define LOG(severity, format, ...) \
133 do { \
134 OT_CHECK_VALID_LOG_ARGS(__VA_ARGS__); \
135 if (device_log_bypass_uart_address() != 0) { \
136 /* clang-format off */ \
137 /* Put DV-only log constants in .logs.* sections, which
138 * the linker will dutifully discard.
139 * Unfortunately, clang-format really mangles these
140 * declarations, so we format them manually. */ \
141 __attribute__((section(".logs.fields"))) \
142 static const log_fields_t kLogFields = \
143 LOG_MAKE_FIELDS_(severity, format, ##__VA_ARGS__); \
144 base_log_internal_dv((const log_fields_t*)((char*)&kLogFields + (uintptr_t)&_dv_log_offset), \
145 OT_VA_ARGS_COUNT(format, ##__VA_ARGS__), \
146 ##__VA_ARGS__); /* clang-format on */ \
147 } else { \
148 static const log_fields_t log_fields = \
149 LOG_MAKE_FIELDS_(severity, format, ##__VA_ARGS__); \
150 base_log_internal_core(&log_fields, ##__VA_ARGS__); \
151 } \
152 } while (false)
153
154/**
155 * Implementation detail of `LOG`.
156 */
157#define LOG_MAKE_FIELDS_(_severity, _format, ...) \
158 { \
159 .severity = _severity, .file_name = "" __FILE__ "", .line = __LINE__, \
160 .nargs = OT_VA_ARGS_COUNT(_format, ##__VA_ARGS__), .format = _format, \
161 }
162
163/**
164 * Log an informational message.
165 *
166 * @param severity a severity of type `log_severity_t`.
167 * @param format a format string, as described in print.h. This must be a string
168 * literal.
169 * @param ... format parameters matching the format string.
170 */
171#define LOG_INFO(...) LOG(kLogSeverityInfo, __VA_ARGS__)
172
173/**
174 * Log a warning
175 *
176 * @param severity a severity of type `log_severity_t`.
177 * @param format a format string, as described in print.h. This must be a string
178 * literal.
179 * @param ... format parameters matching the format string.
180 */
181#define LOG_WARNING(...) LOG(kLogSeverityWarn, __VA_ARGS__)
182
183/**
184 * Log a non-fatal error.
185 *
186 * @param severity a severity of type `log_severity_t`.
187 * @param format a format string, as described in print.h. This must be a string
188 * literal.
189 * @param ... format parameters matching the format string.
190 */
191#define LOG_ERROR(...) LOG(kLogSeverityError, __VA_ARGS__)
192
193/**
194 * Log a fatal error.
195 *
196 * @param severity a severity of type `log_severity_t`.
197 * @param format a format string, as described in print.h. This must be a string
198 * literal.
199 * @param ... format parameters matching the format string.
200 *
201 * It is the user's responsibility to follow this up with a call to `abort()` to
202 * immediately stop the execution.
203 */
204#define LOG_FATAL(...) LOG(kLogSeverityFatal, __VA_ARGS__)
205
206#endif // OPENTITAN_SW_DEVICE_LIB_RUNTIME_LOG_H_