kprintf: fix vararg bug

Turns out you can't pass a va_list to subroutines
as per the C standard, even though it worked
perfectly fine on ARM.  Well then, the entire
kprintf thing needs to be refactored anyway at
some point in the future, so that more formatting
options are supported.
main
anna 3 years ago
parent 25e00354ec
commit 8fb2f7987c
Signed by: fef
GPG Key ID: EC22E476DC2D3D84

@ -3,7 +3,7 @@
#pragma once
/**
* @file Header for the `printf()` family of functions.
* @brief Header for the `kprintf()` family of functions.
*/
#include <stdarg.h>
@ -11,15 +11,61 @@
#include <gay/types.h>
#include <gay/toolchain.h>
/**
* @brief Print to the kernel log.
*
* @param fmt A printf style format string
* @returns The amount of bytes written,
* or a negative number from `errno.h` on failure
*/
__attribute__(( format(printf, 1, 2) ))
int kprintf(const char *__restrict fmt, ...);
/**
* @brief Print to the kernel log.
*
* @param fmt A printf style format string
* @param args The variable arguments pointer
* @returns The amount of bytes written,
* or a negative number from `errno.h` on failure
*/
int kvprintf(const char *__restrict fmt, va_list args);
/**
* @brief Renderer functions that `kprintf()` and friends call for writing.
* Depending on the current kernel log output target (which in turn depends
* primarily on the current boot stage), this will be implemented by different
* subsystems. To change the renderer, call `kprintf_set_renderer()`.
*/
struct kprintf_renderer {
ssize_t (*write)(struct kprintf_renderer *renderer, const void *buf, size_t size);
/**
* @brief Write to the kernel log.
*
* @param renderer A reference to the original structure
* @param buf Data to write
* @param len Amount of data in bytes
* @returns The amount of bytes actually written,
* or a negative code from `errno.h` on failure
*/
ssize_t (*write)(struct kprintf_renderer *renderer, const void *buf, size_t len);
/**
* @brief Flush the kernel log buffer.
* On implementations that don't have a buffer, this can be a no-op.
* If that is the case, this call should always return 0.
*
* @param renderer A reference to the original structure
* @returns The amount of bytes flushed out (0 if none),
* or a negative code from `errno.h` on failure
*/
ssize_t (*flush)(struct kprintf_renderer *renderer);
};
/**
* @brief Set the current renderer for the `fprintf()` family of functions.
*
* @param renderer Implementation of the write and flush functions
* @returns 0 on success, or a negative code from `errno.h` on failure
*/
int kprintf_set_renderer(struct kprintf_renderer *renderer);
/*

@ -20,11 +20,11 @@ typedef __UINT64_TYPE__ u64;
typedef __SIZE_TYPE__ size_t;
typedef __PTRDIFF_TYPE__ ptrdiff_t;
typedef __PTRDIFF_TYPE__ intptr_t;
typedef __INTPTR_TYPE__ intptr_t;
#define unsigned signed /* l00k @ d33z m4d h4xx0r sk1llz!!1 */
typedef __SIZE_TYPE__ ssize_t;
typedef __PTRDIFF_TYPE__ uintptr_t;
typedef __UINTPTR_TYPE__ uintptr_t;
#undef unsigned
/*

@ -38,10 +38,8 @@ int kprintf_set_renderer(struct kprintf_renderer *new)
static int fmt_handle_ptr(uintptr_t ptr)
{
static const char table[] = {
'0', '1', '2', '3',
'4', '5', '6', '7',
'8', '9', 'a', 'b',
'c', 'd', 'e', 'f',
'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'a', 'b', 'c', 'd', 'e', 'f',
};
int ret;
@ -53,9 +51,9 @@ static int fmt_handle_ptr(uintptr_t ptr)
str[1] = 'x';
do {
*pos-- = table[ptr % ARRAY_SIZE(table)];
*pos-- = table[ptr & 0xf];
ptr >>= 4;
} while (pos != &str[2]);
} while (pos != &str[1]);
ret = renderer->write(renderer, str, 2 * sizeof(uintptr_t) + 2);
return ret;
@ -97,19 +95,10 @@ static inline int fmt_handle_int(int i)
return ret;
}
/**
* @brief Parse a formatting escape sequence, fetch the parameter from the `va_arg`
* stack, and print the resulting string to the standard serial console.
*
* @param pos A reference to the pointer to the fmt sequence beginner (`%`).
* This is updated to point to the first character *after* the entire
* escape sequence.
* @param args A pointer to the varargs list. Will be manipulated.
* @returns The amount of bytes written, or a negative POSIX error code.
*/
static inline int fmt_handle(const char **pos, va_list args)
int kvprintf(const char *fmt, va_list args)
{
int ret = 0;
ssize_t ret = 0;
const char *tmp = fmt;
union {
char c;
int d;
@ -118,48 +107,6 @@ static inline int fmt_handle(const char **pos, va_list args)
unsigned int u;
} val;
switch (**pos) {
case '%': /* literal percent sign */
ret = renderer->write(renderer, *pos, sizeof(**pos));
break;
case 'c': /* char */
val.c = va_arg(args, int); /* POSIX says chars are cast to an int */
ret = renderer->write(renderer, &val.c, sizeof(val.c));
break;
case 'd': /* int */
val.d = va_arg(args, typeof(val.d));
ret = fmt_handle_int(val.d);
break;
case 'p': /* ptr */
val.p = va_arg(args, typeof(val.p));
ret = fmt_handle_ptr(val.p);
break;
case 's': /* string */
val.s = va_arg(args, typeof(val.s));
ret = (int)strlen(val.s);
ret = renderer->write(renderer, val.s, (size_t)ret);
break;
case 'u': /* unsigned int */
val.u = va_arg(args, typeof(val.u));
ret = fmt_handle_uint(val.u);
break;
}
(*pos)++;
return ret;
}
int kvprintf(const char *fmt, va_list args)
{
ssize_t ret = 0;
const char *tmp = fmt;
while (*tmp != '\0') {
if (*tmp++ == '%') {
/* flush out everything we have so far (minus one char for %) */
@ -174,7 +121,37 @@ int kvprintf(const char *fmt, va_list args)
}
ret += write_ret;
ssize_t fmt_ret = fmt_handle(&tmp, args);
ssize_t fmt_ret = 0;
switch (*tmp) {
case '%': /* literal percent sign */
fmt_ret = renderer->write(renderer, tmp, sizeof(*tmp));
break;
case 'c': /* char */
val.c = va_arg(args, int); /* POSIX wants an int */
fmt_ret = renderer->write(renderer, &val.c, sizeof(val.c));
break;
case 'd': /* int */
case 'i':
fmt_ret = fmt_handle_int(va_arg(args, int));
break;
case 'p': /* ptr */
fmt_ret = fmt_handle_ptr(va_arg(args, uintptr_t));
break;
case 's': /* string */
val.s = va_arg(args, char *);
fmt_ret = renderer->write(renderer, val.s, strlen(val.s));
break;
case 'u': /* unsigned int */
fmt_ret = fmt_handle_uint(va_arg(args, unsigned int));
break;
}
tmp++;
/*
* act as if the current position were the beginning in
* order to make the first step of this if block easier

Loading…
Cancel
Save