@@ -39,9 +39,15 @@ typedef unsigned int uint32_t;
typedef long long int64_t;
typedef unsigned long long uint64_t;
typedef unsigned long uintptr_t;
+typedef __builtin_va_list va_list;
#define NULL ((void *)0)
+#define va_start __builtin_va_start
+#define va_arg __builtin_va_arg
+#define va_end __builtin_va_end
+#define va_copy __builtin_va_copy
+
void *memset(void *dest, int val, size_t size);
void *memzero(void *dest, size_t size);
void *memcpy(void *dest, const void *src, size_t size);
@@ -49,6 +55,11 @@ void *memcpy(void *dest, const void *src, size_t size);
char *strcpy(char *dest, const char *src);
char *strcat(char *dest, const char *src);
size_t strlen(const char *str);
+char *strchr(const char *s, int c);
+char *strrchr(const char *s, int c);
+
+int vsprintf(char *dest, const char *fmt, va_list ap);
+int sprintf(char *dest, const char *fmt, ...);
/* Exit the VM by looping on a HLT instruction forever */
void kvm_exit(void) __attribute__((noreturn));
@@ -76,6 +76,74 @@ size_t strlen(const char *str)
return ret;
}
+char *strchr(const char *s, int c)
+{
+ for (; *s; s++) {
+ if (*s == c)
+ return (char *)s;
+ }
+
+ return NULL;
+}
+
+char *strrchr(const char *s, int c)
+{
+ const char *ret = NULL;
+
+ for (; *s; s++) {
+ if (*s == c)
+ ret = s;
+ }
+
+ return (char *)ret;
+}
+
+#if defined(__x86_64__) && !defined(__ILP32__)
+uint64_t u64divu16(uint64_t a, uint16_t b)
+{
+ return a / b;
+}
+
+unsigned int u64modu16(uint64_t a, uint16_t b)
+{
+ return a % b;
+}
+
+#else /* defined(__x86_64__) && !defined(__ILP32__) */
+
+/* u64 short division helpers to avoid need to link libgcc on 32bit archs */
+uint64_t u64divu16(uint64_t a, uint16_t b)
+{
+ uint64_t ret = 0;
+ uint32_t tmp = a >> 32;
+
+ ret = tmp / b;
+ ret <<= 32;
+ tmp %= b;
+ tmp <<= 16;
+ tmp |= (a >> 16) & 0xffff;
+ ret |= (tmp / b) << 16;
+ tmp %= b;
+ tmp <<= 16;
+ tmp |= a & 0xffff;
+ ret |= tmp / b;
+ return ret;
+}
+
+unsigned int u64modu16(uint64_t a, uint16_t b)
+{
+ uint32_t tmp = a >> 32;
+
+ tmp %= b;
+ tmp <<= 16;
+ tmp |= (a >> 16) & 0xffff;
+ tmp %= b;
+ tmp <<= 16;
+ tmp |= a & 0xffff;
+ return tmp % b;
+}
+#endif /* defined(__x86_64__) && !defined(__ILP32__) */
+
char *ptr2hex(char *dest, uintptr_t val)
{
unsigned int i;
@@ -95,6 +163,250 @@ char *ptr2hex(char *dest, uintptr_t val)
return ret;
}
+char *u64tostr(char *dest, uint64_t val, uint16_t base, int caps)
+{
+ unsigned int i;
+ uintptr_t tmp = u64divu16(val, base);
+ char hex = caps ? 'A' : 'a';
+ char *ret = dest;
+
+ for (i = 1; tmp; i++, tmp = u64divu16(tmp, base))
+ ;
+
+ dest[i] = '\0';
+
+ do {
+ tmp = u64modu16(val, base);
+ dest[--i] = tmp + (tmp >= 10 ? hex - 10 : '0');
+ val = u64divu16(val, base);
+ } while (i);
+
+ return ret;
+}
+
+char *i64tostr(char *dest, int64_t val)
+{
+ if (val < 0) {
+ dest[0] = '-';
+ u64tostr(dest + 1, -val, 10, 0);
+ return dest;
+ }
+
+ return u64tostr(dest, val, 10, 0);
+}
+
+int vsprintf(char *dest, const char *fmt, va_list ap)
+{
+ va_list args;
+ int ret = 0;
+ char conv;
+ uint64_t u64val = 0;
+ int64_t i64val = 0;
+ const char * const uint_conv = "ouxX";
+
+ va_copy(args, ap);
+
+ for (; *fmt; fmt++) {
+ if (*fmt != '%') {
+ dest[ret++] = *fmt;
+ continue;
+ }
+
+ conv = 0;
+ fmt++;
+
+ switch (*fmt) {
+ case '%':
+ dest[ret++] = *fmt;
+ break;
+
+ case 'c':
+ dest[ret++] = va_arg(args, int);
+ break;
+
+ case 's':
+ strcpy(dest + ret, va_arg(args, const char *));
+ ret += strlen(dest + ret);
+ break;
+
+ case 'p':
+ strcpy(dest + ret, "0x");
+ ptr2hex(dest + ret + 2,
+ (uintptr_t)va_arg(args, void *));
+ ret += strlen(dest + ret);
+ break;
+
+ case 'l':
+ fmt++;
+
+ switch (*fmt) {
+ case 'l':
+ fmt++;
+
+ if (*fmt == 'd' || *fmt == 'i') {
+ i64val = va_arg(args, long long);
+ conv = *fmt;
+ break;
+ }
+
+ if (strchr(uint_conv, *fmt)) {
+ u64val = va_arg(args,
+ unsigned long long);
+ conv = *fmt;
+ break;
+ }
+
+ va_end(args);
+ return -1;
+
+ case 'd':
+ case 'i':
+ i64val = va_arg(args, long);
+ conv = *fmt;
+ break;
+
+ default:
+ if (strchr(uint_conv, *fmt)) {
+ u64val = va_arg(args,
+ unsigned long);
+ conv = *fmt;
+ break;
+ }
+
+ va_end(args);
+ return -1;
+ }
+ break;
+
+ case 'h':
+ fmt++;
+
+ switch (*fmt) {
+ case 'h':
+ fmt++;
+
+ if (*fmt == 'd' || *fmt == 'i') {
+ i64val = (signed char)va_arg(args, int);
+ conv = *fmt;
+ break;
+ }
+
+ if (strchr(uint_conv, *fmt)) {
+ u64val = (unsigned char)va_arg(args,
+ unsigned int);
+ conv = *fmt;
+ break;
+ }
+
+ va_end(args);
+ return -1;
+
+ case 'd':
+ case 'i':
+ i64val = (short int)va_arg(args, int);
+ conv = *fmt;
+ break;
+
+ default:
+ if (strchr(uint_conv, *fmt)) {
+ u64val = (unsigned short int)va_arg(
+ args, unsigned int);
+ conv = *fmt;
+ break;
+ }
+
+ va_end(args);
+ return -1;
+ }
+ break;
+
+ case 'z':
+ fmt++;
+
+ if (*fmt == 'd' || *fmt == 'i') {
+ i64val = va_arg(args, ssize_t);
+ conv = *fmt;
+ break;
+ }
+
+ if (strchr(uint_conv, *fmt)) {
+ u64val = va_arg(args, size_t);
+ conv = *fmt;
+ break;
+ }
+
+ va_end(args);
+ return -1;
+
+ case 'd':
+ case 'i':
+ i64val = va_arg(args, int);
+ conv = *fmt;
+ break;
+
+ default:
+ if (strchr(uint_conv, *fmt)) {
+ u64val = va_arg(args, unsigned int);
+ conv = *fmt;
+ break;
+ }
+
+ va_end(args);
+ return -1;
+ }
+
+ switch (conv) {
+ case 0:
+ continue;
+
+ case 'd':
+ case 'i':
+ i64tostr(dest + ret, i64val);
+ ret += strlen(dest + ret);
+ break;
+
+ case 'o':
+ u64tostr(dest + ret, u64val, 8, 0);
+ ret += strlen(dest + ret);
+ break;
+
+ case 'u':
+ u64tostr(dest + ret, u64val, 10, 0);
+ ret += strlen(dest + ret);
+ break;
+
+ case 'x':
+ u64tostr(dest + ret, u64val, 16, 0);
+ ret += strlen(dest + ret);
+ break;
+
+ case 'X':
+ u64tostr(dest + ret, u64val, 16, 1);
+ ret += strlen(dest + ret);
+ break;
+
+ default:
+ va_end(args);
+ return -1;
+ }
+ }
+
+ va_end(args);
+ dest[ret++] = '\0';
+ return ret;
+}
+
+int sprintf(char *dest, const char *fmt, ...)
+{
+ va_list args;
+ int ret;
+
+ va_start(args, fmt);
+ ret = vsprintf(dest, fmt, args);
+ va_end(args);
+ return ret;
+}
+
void *tst_heap_alloc_aligned(size_t size, size_t align)
{
uintptr_t addr = (uintptr_t)heap_end;
Add basic implementation of sprintf() that supports string, pointer and integer arguments but without advanced formatting options like field alignment and padding. Signed-off-by: Martin Doucha <mdoucha@suse.cz> --- testcases/kernel/kvm/include/kvm_guest.h | 11 + testcases/kernel/kvm/lib_guest.c | 312 +++++++++++++++++++++++ 2 files changed, 323 insertions(+)