printk: make it 64-bit compatible
On 64-bit systems the most notable difference is due to longs and pointers being 64-bit wide. Therefore there must be a distinction between ints and longs. Similar to the prf.c case, this patch properly implements the h, hh, l, ll and z length modifiers as well as some small cleanups. Signed-off-by: Nicolas Pitre <npitre@baylibre.com>
This commit is contained in:
parent
f4f2b13126
commit
2b32059a61
3 changed files with 91 additions and 58 deletions
|
@ -33,9 +33,9 @@ extern "C" {
|
||||||
* - character: \%c
|
* - character: \%c
|
||||||
* - percent: \%\%
|
* - percent: \%\%
|
||||||
*
|
*
|
||||||
* Field width (with or without leading zeroes) are supported.
|
* Field width (with or without leading zeroes) is supported.
|
||||||
* Length attributes such as 'h' and 'l' are supported. However,
|
* Length attributes h, hh, l, ll and z are supported. However, integral
|
||||||
* integral values with %lld and %lli are only printed if they fit in 32 bits,
|
* values with %lld and %lli are only printed if they fit in a long
|
||||||
* otherwise 'ERR' is printed. Full 64-bit values may be printed with %llx.
|
* otherwise 'ERR' is printed. Full 64-bit values may be printed with %llx.
|
||||||
* Flags and precision attributes are not supported.
|
* Flags and precision attributes are not supported.
|
||||||
*
|
*
|
||||||
|
|
127
lib/os/printk.c
127
lib/os/printk.c
|
@ -19,6 +19,7 @@
|
||||||
#include <linker/sections.h>
|
#include <linker/sections.h>
|
||||||
#include <syscall_handler.h>
|
#include <syscall_handler.h>
|
||||||
#include <logging/log.h>
|
#include <logging/log.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
typedef int (*out_func_t)(int c, void *ctx);
|
typedef int (*out_func_t)(int c, void *ctx);
|
||||||
|
|
||||||
|
@ -103,7 +104,7 @@ void z_vprintk(out_func_t out, void *ctx, const char *fmt, va_list ap)
|
||||||
int might_format = 0; /* 1 if encountered a '%' */
|
int might_format = 0; /* 1 if encountered a '%' */
|
||||||
enum pad_type padding = PAD_NONE;
|
enum pad_type padding = PAD_NONE;
|
||||||
int min_width = -1;
|
int min_width = -1;
|
||||||
int long_ctr = 0;
|
char length_mod = 0;
|
||||||
|
|
||||||
/* fmt has already been adjusted if needed */
|
/* fmt has already been adjusted if needed */
|
||||||
|
|
||||||
|
@ -115,7 +116,7 @@ void z_vprintk(out_func_t out, void *ctx, const char *fmt, va_list ap)
|
||||||
might_format = 1;
|
might_format = 1;
|
||||||
min_width = -1;
|
min_width = -1;
|
||||||
padding = PAD_NONE;
|
padding = PAD_NONE;
|
||||||
long_ctr = 0;
|
length_mod = 0;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
switch (*fmt) {
|
switch (*fmt) {
|
||||||
|
@ -148,34 +149,39 @@ void z_vprintk(out_func_t out, void *ctx, const char *fmt, va_list ap)
|
||||||
padding = PAD_SPACE_BEFORE;
|
padding = PAD_SPACE_BEFORE;
|
||||||
}
|
}
|
||||||
goto still_might_format;
|
goto still_might_format;
|
||||||
case 'l':
|
|
||||||
long_ctr++;
|
|
||||||
/* Fall through */
|
|
||||||
case 'z':
|
|
||||||
case 'h':
|
case 'h':
|
||||||
/* FIXME: do nothing for these modifiers */
|
case 'l':
|
||||||
|
case 'z':
|
||||||
|
if (*fmt == 'h' && length_mod == 'h') {
|
||||||
|
length_mod = 'H';
|
||||||
|
} else if (*fmt == 'l' && length_mod == 'l') {
|
||||||
|
length_mod = 'L';
|
||||||
|
} else if (length_mod == 0) {
|
||||||
|
length_mod = *fmt;
|
||||||
|
} else {
|
||||||
|
out((int)'%', ctx);
|
||||||
|
out((int)*fmt, ctx);
|
||||||
|
break;
|
||||||
|
}
|
||||||
goto still_might_format;
|
goto still_might_format;
|
||||||
case 'd':
|
case 'd':
|
||||||
case 'i': {
|
case 'i': {
|
||||||
s32_t d;
|
long d;
|
||||||
|
|
||||||
if (long_ctr == 0) {
|
if (length_mod == 'z') {
|
||||||
d = va_arg(ap, int);
|
d = va_arg(ap, ssize_t);
|
||||||
} else if (long_ctr == 1) {
|
} else if (length_mod == 'l') {
|
||||||
long ld = va_arg(ap, long);
|
d = va_arg(ap, long);
|
||||||
if (ld > INT32_MAX || ld < INT32_MIN) {
|
} else if (length_mod == 'L') {
|
||||||
print_err(out, ctx);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
d = (s32_t)ld;
|
|
||||||
} else {
|
|
||||||
long long lld = va_arg(ap, long long);
|
long long lld = va_arg(ap, long long);
|
||||||
if (lld > INT32_MAX ||
|
if (lld > __LONG_MAX__ ||
|
||||||
lld < INT32_MIN) {
|
lld < ~__LONG_MAX__) {
|
||||||
print_err(out, ctx);
|
print_err(out, ctx);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
d = (s32_t)lld;
|
d = lld;
|
||||||
|
} else {
|
||||||
|
d = va_arg(ap, int);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (d < 0) {
|
if (d < 0) {
|
||||||
|
@ -188,25 +194,22 @@ void z_vprintk(out_func_t out, void *ctx, const char *fmt, va_list ap)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 'u': {
|
case 'u': {
|
||||||
u32_t u;
|
unsigned long u;
|
||||||
|
|
||||||
if (long_ctr == 0) {
|
if (length_mod == 'z') {
|
||||||
u = va_arg(ap, unsigned int);
|
u = va_arg(ap, size_t);
|
||||||
} else if (long_ctr == 1) {
|
} else if (length_mod == 'l') {
|
||||||
long lu = va_arg(ap, unsigned long);
|
u = va_arg(ap, unsigned long);
|
||||||
if (lu > INT32_MAX) {
|
} else if (length_mod == 'L') {
|
||||||
print_err(out, ctx);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
u = (u32_t)lu;
|
|
||||||
} else {
|
|
||||||
unsigned long long llu =
|
unsigned long long llu =
|
||||||
va_arg(ap, unsigned long long);
|
va_arg(ap, unsigned long long);
|
||||||
if (llu > INT32_MAX) {
|
if (llu > ~0UL) {
|
||||||
print_err(out, ctx);
|
print_err(out, ctx);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
u = (u32_t)llu;
|
u = llu;
|
||||||
|
} else {
|
||||||
|
u = va_arg(ap, unsigned int);
|
||||||
}
|
}
|
||||||
|
|
||||||
_printk_dec_ulong(out, ctx, u, padding,
|
_printk_dec_ulong(out, ctx, u, padding,
|
||||||
|
@ -224,10 +227,14 @@ void z_vprintk(out_func_t out, void *ctx, const char *fmt, va_list ap)
|
||||||
case 'X': {
|
case 'X': {
|
||||||
unsigned long long x;
|
unsigned long long x;
|
||||||
|
|
||||||
if (long_ctr < 2) {
|
if (*fmt == 'p') {
|
||||||
|
x = (uintptr_t)va_arg(ap, void *);
|
||||||
|
} else if (length_mod == 'l') {
|
||||||
x = va_arg(ap, unsigned long);
|
x = va_arg(ap, unsigned long);
|
||||||
} else {
|
} else if (length_mod == 'L') {
|
||||||
x = va_arg(ap, unsigned long long);
|
x = va_arg(ap, unsigned long long);
|
||||||
|
} else {
|
||||||
|
x = va_arg(ap, unsigned int);
|
||||||
}
|
}
|
||||||
|
|
||||||
_printk_hex_ulong(out, ctx, x, padding,
|
_printk_hex_ulong(out, ctx, x, padding,
|
||||||
|
@ -363,12 +370,16 @@ Z_SYSCALL_HANDLER(k_str_out, c, n)
|
||||||
* printf-like formatting is available.
|
* printf-like formatting is available.
|
||||||
*
|
*
|
||||||
* Available formatting:
|
* Available formatting:
|
||||||
* - %x/%X: outputs a 32-bit number in ABCDWXYZ format. All eight digits
|
* - %x/%X: outputs a number in hexadecimal format
|
||||||
* are printed: if less than 8 characters are needed, leading zeroes
|
* - %s: outputs a null-terminated string
|
||||||
* are displayed.
|
* - %p: pointer, same as %x with a 0x prefix
|
||||||
* - %s: output a null-terminated string
|
* - %u: outputs a number in unsigned decimal format
|
||||||
* - %p: pointer, same as %x
|
* - %d/%i: outputs a number in signed decimal format
|
||||||
* - %d/%i/%u: outputs a 32-bit number in unsigned decimal format.
|
*
|
||||||
|
* Field width (with or without leading zeroes) is supported.
|
||||||
|
* Length attributes h, hh, l, ll and z are supported. However, integral
|
||||||
|
* values with %lld and %lli are only printed if they fit in a long
|
||||||
|
* otherwise 'ERR' is printed. Full 64-bit values may be printed with %llx.
|
||||||
*
|
*
|
||||||
* @param fmt formatted string to output
|
* @param fmt formatted string to output
|
||||||
*
|
*
|
||||||
|
@ -402,15 +413,17 @@ static void _printk_hex_ulong(out_func_t out, void *ctx,
|
||||||
enum pad_type padding,
|
enum pad_type padding,
|
||||||
int min_width)
|
int min_width)
|
||||||
{
|
{
|
||||||
int size = sizeof(num) * 2;
|
int shift = sizeof(num) * 8;
|
||||||
int found_largest_digit = 0;
|
int found_largest_digit = 0;
|
||||||
int remaining = 16; /* 16 digits max */
|
int remaining = 16; /* 16 digits max */
|
||||||
int digits = 0;
|
int digits = 0;
|
||||||
|
char nibble;
|
||||||
|
|
||||||
for (; size != 0; size--) {
|
while (shift >= 4) {
|
||||||
char nibble = (num >> ((size - 1) << 2) & 0xf);
|
shift -= 4;
|
||||||
|
nibble = (num >> shift) & 0xf;
|
||||||
|
|
||||||
if (nibble != 0 || found_largest_digit != 0 || size == 1) {
|
if (nibble != 0 || found_largest_digit != 0 || shift == 0) {
|
||||||
found_largest_digit = 1;
|
found_largest_digit = 1;
|
||||||
nibble += nibble > 9 ? 87 : 48;
|
nibble += nibble > 9 ? 87 : 48;
|
||||||
out((int)nibble, ctx);
|
out((int)nibble, ctx);
|
||||||
|
@ -436,10 +449,10 @@ static void _printk_hex_ulong(out_func_t out, void *ctx,
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Output an unsigned long (32-bit) in decimal format
|
* @brief Output an unsigned long in decimal format
|
||||||
|
*
|
||||||
|
* Output an unsigned long on output installed by platform at init time.
|
||||||
*
|
*
|
||||||
* Output an unsigned long on output installed by platform at init time. Only
|
|
||||||
* works with 32-bit values.
|
|
||||||
* @param num Number to output
|
* @param num Number to output
|
||||||
*
|
*
|
||||||
* @return N/A
|
* @return N/A
|
||||||
|
@ -448,21 +461,25 @@ static void _printk_dec_ulong(out_func_t out, void *ctx,
|
||||||
const unsigned long num, enum pad_type padding,
|
const unsigned long num, enum pad_type padding,
|
||||||
int min_width)
|
int min_width)
|
||||||
{
|
{
|
||||||
unsigned long pos = 999999999;
|
unsigned long pos = 1000000000;
|
||||||
unsigned long remainder = num;
|
unsigned long remainder = num;
|
||||||
int found_largest_digit = 0;
|
int found_largest_digit = 0;
|
||||||
int remaining = 10; /* 10 digits max */
|
int remaining = sizeof(long) * 5 / 2;
|
||||||
int digits = 1;
|
int digits = 1;
|
||||||
|
|
||||||
|
if (sizeof(long) == 8) {
|
||||||
|
pos *= 10000000000;
|
||||||
|
}
|
||||||
|
|
||||||
/* make sure we don't skip if value is zero */
|
/* make sure we don't skip if value is zero */
|
||||||
if (min_width <= 0) {
|
if (min_width <= 0) {
|
||||||
min_width = 1;
|
min_width = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (pos >= 9) {
|
while (pos >= 10) {
|
||||||
if (found_largest_digit != 0 || remainder > pos) {
|
if (found_largest_digit != 0 || remainder >= pos) {
|
||||||
found_largest_digit = 1;
|
found_largest_digit = 1;
|
||||||
out((int)((remainder / (pos + 1)) + 48), ctx);
|
out((int)(remainder / pos + 48), ctx);
|
||||||
digits++;
|
digits++;
|
||||||
} else if (remaining <= min_width
|
} else if (remaining <= min_width
|
||||||
&& padding < PAD_SPACE_AFTER) {
|
&& padding < PAD_SPACE_AFTER) {
|
||||||
|
@ -470,7 +487,7 @@ static void _printk_dec_ulong(out_func_t out, void *ctx,
|
||||||
digits++;
|
digits++;
|
||||||
}
|
}
|
||||||
remaining--;
|
remaining--;
|
||||||
remainder %= (pos + 1);
|
remainder %= pos;
|
||||||
pos /= 10;
|
pos /= 10;
|
||||||
}
|
}
|
||||||
out((int)(remainder + 48), ctx);
|
out((int)(remainder + 48), ctx);
|
||||||
|
|
|
@ -15,6 +15,8 @@ void __printk_hook_install(int (*fn)(int));
|
||||||
void *__printk_get_hook(void);
|
void *__printk_get_hook(void);
|
||||||
int (*_old_char_out)(int);
|
int (*_old_char_out)(int);
|
||||||
|
|
||||||
|
#ifndef CONFIG_64BIT
|
||||||
|
|
||||||
char *expected = "22 113 10000 32768 40000 22\n"
|
char *expected = "22 113 10000 32768 40000 22\n"
|
||||||
"p 112 -10000 -32768 -40000 -22\n"
|
"p 112 -10000 -32768 -40000 -22\n"
|
||||||
"0xcafebabe 0x0000beef\n"
|
"0xcafebabe 0x0000beef\n"
|
||||||
|
@ -27,7 +29,21 @@ char *expected = "22 113 10000 32768 40000 22\n"
|
||||||
"255 42 abcdef 0x0000002a 42\n"
|
"255 42 abcdef 0x0000002a 42\n"
|
||||||
"ERR -1 ERR ffffffffffffffff\n"
|
"ERR -1 ERR ffffffffffffffff\n"
|
||||||
;
|
;
|
||||||
|
#else
|
||||||
|
|
||||||
|
char *expected = "22 113 10000 32768 40000 22\n"
|
||||||
|
"p 112 -10000 -32768 -40000 -22\n"
|
||||||
|
"0xcafebabe 0x0000beef\n"
|
||||||
|
"0x1 0x01 0x0001 0x00000001 0x0000000000000001\n"
|
||||||
|
"0x1 0x 1 0x 1 0x 1\n"
|
||||||
|
"42 42 0042 00000042\n"
|
||||||
|
"-42 -42 -042 -0000042\n"
|
||||||
|
"42 42 42 42\n"
|
||||||
|
"42 42 0042 00000042\n"
|
||||||
|
"255 42 abcdef 0x0000002a 42\n"
|
||||||
|
"68719476735 -1 18446744073709551615 ffffffffffffffff\n"
|
||||||
|
;
|
||||||
|
#endif
|
||||||
|
|
||||||
size_t stv = 22;
|
size_t stv = 22;
|
||||||
unsigned char uc = 'q';
|
unsigned char uc = 'q';
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue