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 /* Put DV-only log constants in .logs.* sections, which \
137 * the linker will dutifully discard. */ \
138 __attribute__(( \
139 section(".logs.fields"))) static const log_fields_t kLogFields = \
140 LOG_MAKE_FIELDS_(severity, format, ##__VA_ARGS__); \
141 base_log_internal_dv((const log_fields_t *)((char *)&kLogFields + \
142 (uintptr_t)&_dv_log_offset), \
143 OT_VA_ARGS_COUNT(format, ##__VA_ARGS__), \
144 ##__VA_ARGS__); \
145 } else { \
146 static const log_fields_t log_fields = \
147 LOG_MAKE_FIELDS_(severity, format, ##__VA_ARGS__); \
148 base_log_internal_core(&log_fields, ##__VA_ARGS__); \
149 } \
150 } while (false)
151
152/**
153 * Implementation detail of `LOG`.
154 */
155#define LOG_MAKE_FIELDS_(_severity, _format, ...) \
156 { \
157 .severity = _severity, \
158 .file_name = "" __FILE__ "", \
159 .line = __LINE__, \
160 .nargs = OT_VA_ARGS_COUNT(_format, ##__VA_ARGS__), \
161 .format = _format, \
162 }
163
164/**
165 * Log an informational message.
166 *
167 * @param severity a severity of type `log_severity_t`.
168 * @param format a format string, as described in print.h. This must be a string
169 * literal.
170 * @param ... format parameters matching the format string.
171 */
172#define LOG_INFO(...) LOG(kLogSeverityInfo, __VA_ARGS__)
173
174/**
175 * Log a warning
176 *
177 * @param severity a severity of type `log_severity_t`.
178 * @param format a format string, as described in print.h. This must be a string
179 * literal.
180 * @param ... format parameters matching the format string.
181 */
182#define LOG_WARNING(...) LOG(kLogSeverityWarn, __VA_ARGS__)
183
184/**
185 * Log a non-fatal error.
186 *
187 * @param severity a severity of type `log_severity_t`.
188 * @param format a format string, as described in print.h. This must be a string
189 * literal.
190 * @param ... format parameters matching the format string.
191 */
192#define LOG_ERROR(...) LOG(kLogSeverityError, __VA_ARGS__)
193
194/**
195 * Log a fatal error.
196 *
197 * @param severity a severity of type `log_severity_t`.
198 * @param format a format string, as described in print.h. This must be a string
199 * literal.
200 * @param ... format parameters matching the format string.
201 *
202 * It is the user's responsibility to follow this up with a call to `abort()` to
203 * immediately stop the execution.
204 */
205#define LOG_FATAL(...) LOG(kLogSeverityFatal, __VA_ARGS__)
206
207#endif // OPENTITAN_SW_DEVICE_LIB_RUNTIME_LOG_H_