From 20f40a1da4a3d61802ccfc7947e32623350abb32 Mon Sep 17 00:00:00 2001 From: Ben Vanik Date: Mon, 16 Feb 2015 10:07:46 -0800 Subject: [PATCH] sprintf. --- src/xenia/kernel/xboxkrnl_strings.cc | 182 +++++++++++++++++++++++++++ 1 file changed, 182 insertions(+) diff --git a/src/xenia/kernel/xboxkrnl_strings.cc b/src/xenia/kernel/xboxkrnl_strings.cc index 14e480f53..d22a5da01 100644 --- a/src/xenia/kernel/xboxkrnl_strings.cc +++ b/src/xenia/kernel/xboxkrnl_strings.cc @@ -19,6 +19,187 @@ namespace xe { namespace kernel { +SHIM_CALL sprintf_shim(PPCContext* ppc_state, KernelState* state) { + uint32_t buffer_ptr = SHIM_GET_ARG_32(0); + uint32_t format_ptr = SHIM_GET_ARG_32(1); + + XELOGD("sprintf(...)"); + + if (format_ptr == 0) { + SHIM_SET_RETURN_32(-1); + return; + } + + char* buffer = (char*)SHIM_MEM_ADDR(buffer_ptr); + const char* format = (const char*)SHIM_MEM_ADDR(format_ptr); + + int arg_index = 2; + uint32_t sp = (uint32_t)ppc_state->r[1]; +#define LOAD_SPRINTF_ARG(ARG) \ + (ARG < 8) ? SHIM_GET_ARG_32(ARG) : SHIM_MEM_64(sp + 0x54 + 8) + + char* b = buffer; + for (; *format != '\0'; ++format) { + const char* start = format; + + if (*format != '%') { + *b++ = *format; + continue; + } + + ++format; + if (*format == '\0') { + break; + } + + if (*format == '%') { + *b++ = *format; + continue; + } + + const char* end; + end = format; + + // skip flags + while (*end == '-' || *end == '+' || *end == ' ' || *end == '#' || + *end == '0') { + ++end; + } + + if (*end == '\0') { + break; + } + + int arg_extras = 0; + + // skip width + if (*end == '*') { + ++end; + arg_extras++; + } else { + while (*end >= '0' && *end <= '9') { + ++end; + } + } + + if (*end == '\0') { + break; + } + + // skip precision + if (*end == '.') { + ++end; + + if (*end == '*') { + ++end; + ++arg_extras; + } else { + while (*end >= '0' && *end <= '9') { + ++end; + } + } + } + + if (*end == '\0') { + break; + } + + // get length + int arg_size = 4; + + if (*end == 'h') { + ++end; + arg_size = 4; + if (*end == 'h') { + ++end; + } + } else if (*end == 'l') { + ++end; + arg_size = 4; + if (*end == 'l') { + ++end; + arg_size = 8; + } + } else if (*end == 'j') { + arg_size = 8; + ++end; + } else if (*end == 'z') { + arg_size = 4; + ++end; + } else if (*end == 't') { + arg_size = 8; + ++end; + } else if (*end == 'L') { + arg_size = 8; + ++end; + } + + if (*end == '\0') { + break; + } + + if (*end == 'd' || *end == 'i' || *end == 'u' || *end == 'o' || + *end == 'x' || *end == 'X' || *end == 'f' || *end == 'F' || + *end == 'e' || *end == 'E' || *end == 'g' || *end == 'G' || + *end == 'a' || *end == 'A' || *end == 'c') { + char local[512]; + local[0] = '\0'; + strncat(local, start, end + 1 - start); + + assert_true(arg_size == 8 || arg_size == 4); + if (arg_size == 8) { + if (arg_extras == 0) { + uint64_t value = LOAD_SPRINTF_ARG(arg_index); + int result = sprintf(b, local, value); + b += result; + arg_index++; + } else { + assert_true(false); + } + } else if (arg_size == 4) { + if (arg_extras == 0) { + uint32_t value = uint32_t(LOAD_SPRINTF_ARG(arg_index)); + int result = sprintf(b, local, value); + b += result; + arg_index++; + } else { + assert_true(false); + } + } + } else if (*end == 'n') { + assert_true(arg_size == 4); + if (arg_extras == 0) { + uint32_t value = uint32_t(LOAD_SPRINTF_ARG(arg_index)); + SHIM_SET_MEM_32(value, (uint32_t)((b - buffer) / sizeof(char))); + arg_index++; + } else { + assert_true(false); + } + } else if (*end == 's' || *end == 'p') { + char local[512]; + local[0] = '\0'; + strncat(local, start, end + 1 - start); + + assert_true(arg_size == 4); + if (arg_extras == 0) { + uint32_t value = uint32_t(LOAD_SPRINTF_ARG(arg_index)); + const void* pointer = (const void*)SHIM_MEM_ADDR(value); + int result = sprintf(b, local, pointer); + b += result; + arg_index++; + } else { + assert_true(false); + } + } else { + assert_true(false); + break; + } + format = end; + } + *b = '\0'; + SHIM_SET_RETURN_32((uint32_t)(b - buffer)); +} + // TODO: clean me up! SHIM_CALL vsprintf_shim(PPCContext* ppc_state, KernelState* state) { uint32_t buffer_ptr = SHIM_GET_ARG_32(0); @@ -654,6 +835,7 @@ SHIM_CALL _vscwprintf_shim(PPCContext* ppc_state, KernelState* state) { void xe::kernel::xboxkrnl::RegisterStringExports( ExportResolver* export_resolver, KernelState* state) { + SHIM_SET_MAPPING("xboxkrnl.exe", sprintf, state); SHIM_SET_MAPPING("xboxkrnl.exe", vsprintf, state); SHIM_SET_MAPPING("xboxkrnl.exe", _vsnprintf, state); SHIM_SET_MAPPING("xboxkrnl.exe", _vswprintf, state);