blob: ac4445b74d97877f79f4b0b1af91484da07aac99 [file] [log] [blame]
Andrew Scull18834872018-10-12 11:48:09 +01001/*
Andrew Walbran692b3252019-03-07 15:51:31 +00002 * Copyright 2018 The Hafnium Authors.
Andrew Scull18834872018-10-12 11:48:09 +01003 *
Andrew Walbrane959ec12020-06-17 15:01:09 +01004 * Use of this source code is governed by a BSD-style
5 * license that can be found in the LICENSE file or at
6 * https://opensource.org/licenses/BSD-3-Clause.
Andrew Scull18834872018-10-12 11:48:09 +01007 */
8
Andrew Scull18c78fc2018-08-20 12:57:41 +01009#include "hf/dlog.h"
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +010010
11#include <stdbool.h>
12#include <stddef.h>
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +010013
Andrew Scull18c78fc2018-08-20 12:57:41 +010014#include "hf/spinlock.h"
Karl Meakin70894da2024-03-30 21:06:12 +000015#include "hf/static_assert.h"
Andrew Scull8d9e1212019-04-05 13:52:55 +010016#include "hf/std.h"
David Brazdil52230432020-01-27 15:08:34 +000017#include "hf/stdout.h"
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +010018
Karl Meakine980e612024-03-28 17:46:32 +000019enum { DLOG_MAX_STRING_LENGTH = 64 };
20
21/* Keep fields aligned */
Andrew Scull4f170f52018-07-19 12:58:20 +010022/* clang-format off */
Karl Meakine980e612024-03-28 17:46:32 +000023struct format_flags {
24 bool minus : 1;
25 bool plus : 1;
26 bool space : 1;
27 bool alt : 1;
28 bool zero : 1;
29 bool upper : 1;
30 bool neg : 1;
31};
Andrew Scull4f170f52018-07-19 12:58:20 +010032/* clang-format on */
33
Karl Meakine980e612024-03-28 17:46:32 +000034enum format_base {
35 base8 = 8,
36 base10 = 10,
37 base16 = 16,
38};
39
Karl Meakin70894da2024-03-30 21:06:12 +000040enum format_length {
41 length8 = 8,
42 length16 = 16,
43 length32 = 32,
44 length64 = 64,
45};
46
47static_assert(sizeof(char) == sizeof(uint8_t),
48 "dlog expects char to be 8 bits wide");
49static_assert(sizeof(short) == sizeof(uint16_t),
50 "dlog expects short to be 16 bits wide");
51static_assert(sizeof(int) == sizeof(uint32_t),
52 "dlog expects int to be 32 bits wide");
53static_assert(sizeof(long) == sizeof(uint64_t),
54 "dlog expects long to be 64 bits wide");
55static_assert(sizeof(long long) == sizeof(uint64_t),
56 "dlog expects long long to be 64 bits wide");
57static_assert(sizeof(intmax_t) == sizeof(uint64_t),
58 "dlog expects intmax_t to be 64 bits wide");
59static_assert(sizeof(size_t) == sizeof(uint64_t),
60 "dlog expects size_t to be 64 bits wide");
61static_assert(sizeof(ptrdiff_t) == sizeof(uint64_t),
62 "dlog expects ptrdiff_t to be 64 bits wide");
63
Andrew Scullfdd716e2018-12-20 05:37:31 +000064static bool dlog_lock_enabled = false;
Andrew Walbranc1ad4ce2019-05-09 11:41:39 +010065static struct spinlock sl = SPINLOCK_INIT;
66
Andrew Walbranf3ac84d2019-07-26 16:10:02 +010067/*
68 * These global variables for the log buffer are not static because a test needs
69 * to access them directly.
70 */
71size_t dlog_buffer_offset;
72char dlog_buffer[DLOG_BUFFER_SIZE];
73
Andrew Walbranc1ad4ce2019-05-09 11:41:39 +010074/**
75 * Takes the lock, if it is enabled.
76 */
77static void lock(void)
78{
79 if (dlog_lock_enabled) {
80 sl_lock(&sl);
81 }
82}
83
84/**
85 * Releases the lock, if it is enabled.
86 */
87static void unlock(void)
88{
89 if (dlog_lock_enabled) {
90 sl_unlock(&sl);
91 }
92}
Andrew Scullfdd716e2018-12-20 05:37:31 +000093
94/**
95 * Enables the lock protecting the serial device.
96 */
97void dlog_enable_lock(void)
98{
99 dlog_lock_enabled = true;
100}
101
Andrew Walbranf3ac84d2019-07-26 16:10:02 +0100102static void dlog_putchar(char c)
103{
104 dlog_buffer[dlog_buffer_offset] = c;
105 dlog_buffer_offset = (dlog_buffer_offset + 1) % DLOG_BUFFER_SIZE;
David Brazdil52230432020-01-27 15:08:34 +0000106 stdout_putchar(c);
Andrew Walbranf3ac84d2019-07-26 16:10:02 +0100107}
108
Wedson Almeida Filhofdf4afc2018-07-19 15:45:21 +0100109/**
Karl Meakine980e612024-03-28 17:46:32 +0000110 * Prints a literal string (i.e. '%' is not interpreted specially) to the debug
111 * log.
112 *
113 * Returns number of characters written.
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100114 */
115static size_t print_raw_string(const char *str)
116{
117 const char *c = str;
Andrew Scullcbefbdb2019-01-11 16:36:26 +0000118
Karl Meakine980e612024-03-28 17:46:32 +0000119 for (; *c != '\0'; c++) {
120 dlog_putchar(*c);
Andrew Scull7364a8e2018-07-19 15:39:29 +0100121 }
Andrew Scullcbefbdb2019-01-11 16:36:26 +0000122
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100123 return c - str;
124}
125
Wedson Almeida Filhofdf4afc2018-07-19 15:45:21 +0100126/**
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100127 * Prints a formatted string to the debug log. The format includes a minimum
128 * width, the fill character, and flags (whether to align to left or right).
129 *
130 * str is the full string, while suffix is a pointer within str that indicates
131 * where the suffix begins. This is used when printing right-aligned numbers
132 * with a zero fill; for example, -10 with width 4 should be padded to -010,
133 * so suffix would point to index one of the "-10" string .
Karl Meakind2ef6182024-05-22 11:23:12 +0100134 *
135 * Returns number of characters written.
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100136 */
Karl Meakine980e612024-03-28 17:46:32 +0000137static size_t print_string(const char *str, const char *suffix,
138 size_t min_width, struct format_flags flags,
139 char fill)
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100140{
Karl Meakind2ef6182024-05-22 11:23:12 +0100141 size_t chars_written = 0;
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100142 size_t len = suffix - str;
143
144 /* Print the string up to the beginning of the suffix. */
Andrew Scull7364a8e2018-07-19 15:39:29 +0100145 while (str != suffix) {
Karl Meakind2ef6182024-05-22 11:23:12 +0100146 chars_written++;
Andrew Walbranf3ac84d2019-07-26 16:10:02 +0100147 dlog_putchar(*str++);
Andrew Scull7364a8e2018-07-19 15:39:29 +0100148 }
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100149
Karl Meakine980e612024-03-28 17:46:32 +0000150 if (flags.minus) {
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100151 /* Left-aligned. Print suffix, then print padding if needed. */
152 len += print_raw_string(suffix);
Karl Meakine980e612024-03-28 17:46:32 +0000153 while (len < min_width) {
Karl Meakind2ef6182024-05-22 11:23:12 +0100154 chars_written++;
Andrew Walbranf3ac84d2019-07-26 16:10:02 +0100155 dlog_putchar(' ');
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100156 len++;
157 }
Karl Meakind2ef6182024-05-22 11:23:12 +0100158 return chars_written;
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100159 }
160
161 /* Fill until we reach the desired length. */
Andrew Scull4a867bc2019-04-08 10:15:11 +0100162 len += strnlen_s(suffix, DLOG_MAX_STRING_LENGTH);
Karl Meakine980e612024-03-28 17:46:32 +0000163 while (len < min_width) {
Karl Meakind2ef6182024-05-22 11:23:12 +0100164 chars_written++;
Andrew Walbranf3ac84d2019-07-26 16:10:02 +0100165 dlog_putchar(fill);
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100166 len++;
167 }
168
169 /* Now print the rest of the string. */
Karl Meakind2ef6182024-05-22 11:23:12 +0100170 chars_written += print_raw_string(suffix);
171 return chars_written;
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100172}
173
Wedson Almeida Filhofdf4afc2018-07-19 15:45:21 +0100174/**
Karl Meakine980e612024-03-28 17:46:32 +0000175 * Prints an integer to the debug log. The caller specifies the base, its
176 * minimum width and printf-style flags.
Karl Meakind2ef6182024-05-22 11:23:12 +0100177 *
178 * Returns number of characters written.
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100179 */
Karl Meakine980e612024-03-28 17:46:32 +0000180static size_t print_int(size_t value, enum format_base base, size_t min_width,
181 struct format_flags flags)
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100182{
183 static const char *digits_lower = "0123456789abcdefx";
184 static const char *digits_upper = "0123456789ABCDEFX";
Karl Meakine980e612024-03-28 17:46:32 +0000185 const char *digits = flags.upper ? digits_upper : digits_lower;
Andrew Scull4a867bc2019-04-08 10:15:11 +0100186 char buf[DLOG_MAX_STRING_LENGTH];
Andrew Scullf3d45592018-09-20 14:30:22 +0100187 char *ptr = &buf[sizeof(buf) - 1];
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100188 char *num;
189 *ptr = '\0';
190 do {
191 --ptr;
Karl Meakine980e612024-03-28 17:46:32 +0000192 *ptr = digits[value % base];
193 value /= base;
194 } while (value);
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100195
196 /* Num stores where the actual number begins. */
197 num = ptr;
198
199 /* Add prefix if requested. */
Karl Meakine980e612024-03-28 17:46:32 +0000200 if (flags.alt) {
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100201 switch (base) {
Karl Meakine980e612024-03-28 17:46:32 +0000202 case base16:
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100203 ptr -= 2;
204 ptr[0] = '0';
Karl Meakine980e612024-03-28 17:46:32 +0000205 ptr[1] = digits[16];
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100206 break;
207
Karl Meakine980e612024-03-28 17:46:32 +0000208 case base8:
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100209 ptr--;
210 *ptr = '0';
211 break;
Karl Meakine980e612024-03-28 17:46:32 +0000212
213 case base10:
214 /* do nothing */
215 break;
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100216 }
217 }
218
219 /* Add sign if requested. */
Karl Meakine980e612024-03-28 17:46:32 +0000220 if (flags.neg) {
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100221 *--ptr = '-';
Karl Meakine980e612024-03-28 17:46:32 +0000222 } else if (flags.plus) {
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100223 *--ptr = '+';
Karl Meakine980e612024-03-28 17:46:32 +0000224 } else if (flags.space) {
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100225 *--ptr = ' ';
Andrew Scull7364a8e2018-07-19 15:39:29 +0100226 }
Karl Meakine980e612024-03-28 17:46:32 +0000227 return print_string(ptr, num, min_width, flags, flags.zero ? '0' : ' ');
228}
229
230/**
231 * Parses the optional flags field of a printf-style format. Returns a pointer
232 * to the first non-flag character in the string.
233 */
234static const char *parse_flags(const char *fmt, struct format_flags *flags)
235{
236 for (;; fmt++) {
237 switch (*fmt) {
238 case '-':
239 flags->minus = true;
240 break;
241
242 case '+':
243 flags->plus = true;
244 break;
245
246 case ' ':
247 flags->space = true;
248 break;
249
250 case '#':
251 flags->alt = true;
252 break;
253
254 case '0':
255 flags->zero = true;
256 break;
257
258 default:
259 return fmt;
260 }
Andrew Scull7364a8e2018-07-19 15:39:29 +0100261 }
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100262}
263
Wedson Almeida Filhofdf4afc2018-07-19 15:45:21 +0100264/**
Karl Meakin70894da2024-03-30 21:06:12 +0000265 * Parses the optional length modifier field of a printf-style format.
266 *
267 * Returns a pointer to the first non-length modifier character in the string.
268 */
269static const char *parse_length_modifier(const char *fmt,
270 enum format_length *length)
271{
272 switch (*fmt) {
273 case 'h':
274 fmt++;
275 if (*fmt == 'h') {
276 fmt++;
277 *length = length8;
278 } else {
279 *length = length16;
280 }
281 break;
282 case 'l':
283 fmt++;
284 if (*fmt == 'l') {
285 fmt++;
286 *length = length64;
287 } else {
288 *length = length64;
289 }
290 break;
291
292 case 'j':
293 case 'z':
294 case 't':
295 fmt++;
296 *length = length64;
297 break;
298
299 default:
300 *length = length32;
301 break;
302 }
303
304 return fmt;
305}
306
307/**
Karl Meakine980e612024-03-28 17:46:32 +0000308 * Parses the optional minimum width field of a printf-style format.
309 * If the width is negative, `flags.minus` is set.
310 *
311 * Returns a pointer to the first non-digit character in the string.
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100312 */
Karl Meakine980e612024-03-28 17:46:32 +0000313static const char *parse_min_width(const char *fmt, va_list args,
314 struct format_flags *flags, int *min_width)
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100315{
Karl Meakine980e612024-03-28 17:46:32 +0000316 int width = 0;
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100317
Karl Meakine980e612024-03-28 17:46:32 +0000318 /* Read minimum width from arguments. */
319 if (*fmt == '*') {
320 fmt++;
321 width = va_arg(args, int);
322 if (width < 0) {
323 width = -width;
324 flags->minus = true;
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100325 }
Karl Meakine980e612024-03-28 17:46:32 +0000326 } else {
327 for (; *fmt >= '0' && *fmt <= '9'; fmt++) {
328 width = (width * 10) + (*fmt - '0');
329 }
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100330 }
Karl Meakine980e612024-03-28 17:46:32 +0000331
332 *min_width = width;
333
334 return fmt;
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100335}
336
Wedson Almeida Filhofdf4afc2018-07-19 15:45:21 +0100337/**
Karl Meakin70894da2024-03-30 21:06:12 +0000338 * Reinterpret an unsigned 64-bit integer as a potentially shorter unsigned
339 * integer according to the length modifier.
340 * Returns an unsigned integer suitable for passing to `print_int`.
341 */
342uint64_t reinterpret_unsigned_int(enum format_length length, uint64_t value)
343{
344 switch (length) {
345 case length8:
346 return (uint8_t)value;
347 case length16:
348 return (uint16_t)value;
349 case length32:
350 return (uint32_t)value;
351 case length64:
352 return value;
353 }
354}
355
356/**
357 * Reinterpret an unsigned 64-bit integer as a potentially shorter signed
358 * integer according to the length modifier.
359 *
360 * Returns an *unsigned* integer suitable for passing to `print_int`. If the
361 * reinterpreted value is negative, `flags.neg` is set and the absolute value is
362 * returned.
363 */
364uint64_t reinterpret_signed_int(enum format_length length, uint64_t value,
365 struct format_flags *flags)
366{
367 int64_t signed_value = (int64_t)reinterpret_unsigned_int(length, value);
368
369 switch (length) {
370 case length8:
371 if ((int8_t)signed_value < 0) {
372 flags->neg = true;
373 signed_value = (-signed_value) & 0xFF;
374 }
375 break;
376 case length16:
377 if ((int16_t)signed_value < 0) {
378 flags->neg = true;
379 signed_value = (-signed_value) & 0xFFFF;
380 }
381 break;
382 case length32:
383 if ((int32_t)signed_value < 0) {
384 flags->neg = true;
385 signed_value = (-signed_value) & 0xFFFFFFFF;
386 }
387 break;
388 case length64:
389 if ((int64_t)signed_value < 0) {
390 flags->neg = true;
391 signed_value = -signed_value;
392 }
393 break;
394 }
395
396 return signed_value;
397}
398
399/**
Andrew Scullfdd716e2018-12-20 05:37:31 +0000400 * Same as "dlog", except that arguments are passed as a va_list
Karl Meakind2ef6182024-05-22 11:23:12 +0100401 *
402 * Returns number of characters written, or `-1` if format string is invalid.
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100403 */
Karl Meakind2ef6182024-05-22 11:23:12 +0100404size_t vdlog(const char *fmt, va_list args)
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100405{
Karl Meakind2ef6182024-05-22 11:23:12 +0100406 size_t chars_written = 0;
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100407
Andrew Walbranc1ad4ce2019-05-09 11:41:39 +0100408 lock();
Andrew Scullfdd716e2018-12-20 05:37:31 +0000409
Karl Meakine980e612024-03-28 17:46:32 +0000410 while (*fmt != '\0') {
411 switch (*fmt) {
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100412 default:
Karl Meakind2ef6182024-05-22 11:23:12 +0100413 chars_written++;
Karl Meakine980e612024-03-28 17:46:32 +0000414 dlog_putchar(*fmt);
415 fmt++;
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100416 break;
417
Karl Meakine980e612024-03-28 17:46:32 +0000418 case '%': {
419 struct format_flags flags = {0};
420 int min_width = 0;
Karl Meakin70894da2024-03-30 21:06:12 +0000421 enum format_length length = length32;
422 uint64_t value;
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100423
Karl Meakine980e612024-03-28 17:46:32 +0000424 fmt++;
425 fmt = parse_flags(fmt, &flags);
426 fmt = parse_min_width(fmt, args, &flags, &min_width);
Karl Meakin70894da2024-03-30 21:06:12 +0000427 fmt = parse_length_modifier(fmt, &length);
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100428
429 /* Handle the format specifier. */
Karl Meakine980e612024-03-28 17:46:32 +0000430 switch (*fmt) {
431 case '%':
432 fmt++;
433 chars_written++;
434 dlog_putchar('%');
435 break;
436
437 case 'c': {
438 char str[2] = {va_arg(args, int), 0};
439
440 fmt++;
441 chars_written += print_string(
442 str, str, min_width, flags, ' ');
443 break;
444 }
445
Andrew Scull4f170f52018-07-19 12:58:20 +0100446 case 's': {
447 char *str = va_arg(args, char *);
Wedson Almeida Filho81568c42019-01-04 13:33:02 +0000448
Karl Meakine980e612024-03-28 17:46:32 +0000449 fmt++;
450 chars_written += print_string(
451 str, str, min_width, flags, ' ');
452 break;
453 }
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100454
455 case 'd':
Andrew Scull4f170f52018-07-19 12:58:20 +0100456 case 'i': {
Karl Meakine980e612024-03-28 17:46:32 +0000457 fmt++;
Karl Meakin70894da2024-03-30 21:06:12 +0000458 value = va_arg(args, uint64_t);
459 value = reinterpret_signed_int(length, value,
460 &flags);
Wedson Almeida Filho81568c42019-01-04 13:33:02 +0000461
Karl Meakin70894da2024-03-30 21:06:12 +0000462 chars_written += print_int(value, base10,
Karl Meakine980e612024-03-28 17:46:32 +0000463 min_width, flags);
464 break;
465 }
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100466
Karl Meakin70894da2024-03-30 21:06:12 +0000467 case 'o':
Karl Meakine980e612024-03-28 17:46:32 +0000468 fmt++;
Karl Meakin70894da2024-03-30 21:06:12 +0000469 value = va_arg(args, uint64_t);
470 value = reinterpret_unsigned_int(length, value);
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100471
Karl Meakin70894da2024-03-30 21:06:12 +0000472 chars_written += print_int(value, base8,
473 min_width, flags);
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100474 break;
475
476 case 'x':
Karl Meakine980e612024-03-28 17:46:32 +0000477 fmt++;
Karl Meakin70894da2024-03-30 21:06:12 +0000478 value = va_arg(args, uint64_t);
479 value = reinterpret_unsigned_int(length, value);
480
481 chars_written += print_int(value, base16,
482 min_width, flags);
483 break;
484
485 case 'X':
486 fmt++;
487 flags.upper = true;
488 value = va_arg(args, uint64_t);
489 value = reinterpret_unsigned_int(length, value);
490
491 chars_written += print_int(value, base16,
492 min_width, flags);
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100493 break;
494
495 case 'u':
Karl Meakine980e612024-03-28 17:46:32 +0000496 fmt++;
Karl Meakin70894da2024-03-30 21:06:12 +0000497 value = va_arg(args, uint64_t);
498 value = reinterpret_unsigned_int(length, value);
499
500 chars_written += print_int(value, base10,
501 min_width, flags);
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100502 break;
503
Karl Meakin70894da2024-03-30 21:06:12 +0000504 case 'p':
Karl Meakine980e612024-03-28 17:46:32 +0000505 fmt++;
Karl Meakin70894da2024-03-30 21:06:12 +0000506 value = va_arg(args, uint64_t);
507 min_width = sizeof(size_t) * 2 + 2;
508 flags.zero = true;
509 flags.alt = true;
510
511 chars_written += print_int(value, base16,
512 min_width, flags);
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100513 break;
514
515 default:
Karl Meakind2ef6182024-05-22 11:23:12 +0100516 chars_written = -1;
517 goto out;
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100518 }
Karl Meakine980e612024-03-28 17:46:32 +0000519 }
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100520 }
521 }
Karl Meakine980e612024-03-28 17:46:32 +0000522
Karl Meakind2ef6182024-05-22 11:23:12 +0100523out:
Kathleen Capellafd306bb2023-03-17 18:14:01 -0400524 stdout_flush();
Andrew Walbranc1ad4ce2019-05-09 11:41:39 +0100525 unlock();
Karl Meakind2ef6182024-05-22 11:23:12 +0100526 return chars_written;
Wedson Almeida Filhofdf4afc2018-07-19 15:45:21 +0100527}
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100528
Wedson Almeida Filhofdf4afc2018-07-19 15:45:21 +0100529/**
530 * Prints the given format string to the debug log.
Karl Meakind2ef6182024-05-22 11:23:12 +0100531 *
Karl Meakine980e612024-03-28 17:46:32 +0000532 * The format string supported is the same as described in
533 * https://en.cppreference.com/w/c/io/fprintf, with the following exceptions:
534 * - Floating-point formatters (`%f`, `%F`, `%e`, `%E`, `%a`, `%A`, `%g`, `%G`,
535 * `%L`) are not supported because floats are not used in Hafnium and
536 * formatting them is too complicated.
537 * - `%n` is not supported because it is rarely used and potentially dangerous.
538 * - Precision modifiers (`%.*` and `%.` followed by an integer) are not
539 * supported.
540 *
Karl Meakind2ef6182024-05-22 11:23:12 +0100541 * Returns number of characters written, or `-1` if format string is invalid.
Wedson Almeida Filhofdf4afc2018-07-19 15:45:21 +0100542 */
Karl Meakind2ef6182024-05-22 11:23:12 +0100543size_t dlog(const char *fmt, ...)
Wedson Almeida Filhofdf4afc2018-07-19 15:45:21 +0100544{
Karl Meakind2ef6182024-05-22 11:23:12 +0100545 size_t chars_written = 0;
Wedson Almeida Filhofdf4afc2018-07-19 15:45:21 +0100546 va_list args;
547
548 va_start(args, fmt);
Karl Meakind2ef6182024-05-22 11:23:12 +0100549 chars_written = vdlog(fmt, args);
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100550 va_end(args);
Karl Meakind2ef6182024-05-22 11:23:12 +0100551 return chars_written;
Wedson Almeida Filho987c0ff2018-06-20 16:34:38 +0100552}