diff --git a/src/xenia/kernel/modules/xboxkrnl/module.cc b/src/xenia/kernel/modules/xboxkrnl/module.cc index 6d3745aee..25e199d16 100644 --- a/src/xenia/kernel/modules/xboxkrnl/module.cc +++ b/src/xenia/kernel/modules/xboxkrnl/module.cc @@ -51,6 +51,7 @@ XboxkrnlModule::XboxkrnlModule(Runtime* runtime) : shared_kernel_state_ = kernel_state_.get(); // Register all exported functions. + RegisterDebugExports(resolver, kernel_state_.get()); RegisterHalExports(resolver, kernel_state_.get()); RegisterMemoryExports(resolver, kernel_state_.get()); RegisterModuleExports(resolver, kernel_state_.get()); diff --git a/src/xenia/kernel/modules/xboxkrnl/module.h b/src/xenia/kernel/modules/xboxkrnl/module.h index 643b9f68e..7ac8ddc5f 100644 --- a/src/xenia/kernel/modules/xboxkrnl/module.h +++ b/src/xenia/kernel/modules/xboxkrnl/module.h @@ -18,6 +18,7 @@ #include // All of the exported functions: +#include #include #include #include diff --git a/src/xenia/kernel/modules/xboxkrnl/sources.gypi b/src/xenia/kernel/modules/xboxkrnl/sources.gypi index aa43d3f06..41702affc 100644 --- a/src/xenia/kernel/modules/xboxkrnl/sources.gypi +++ b/src/xenia/kernel/modules/xboxkrnl/sources.gypi @@ -5,6 +5,8 @@ 'kernel_state.h', 'module.cc', 'module.h', + 'xboxkrnl_debug.cc', + 'xboxkrnl_debug.h', 'xboxkrnl_hal.cc', 'xboxkrnl_hal.h', 'xboxkrnl_memory.cc', diff --git a/src/xenia/kernel/modules/xboxkrnl/xboxkrnl_debug.cc b/src/xenia/kernel/modules/xboxkrnl/xboxkrnl_debug.cc new file mode 100644 index 000000000..7208f4f78 --- /dev/null +++ b/src/xenia/kernel/modules/xboxkrnl/xboxkrnl_debug.cc @@ -0,0 +1,246 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2013 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#include + +#include +#include +#include +#include + + +using namespace xe; +using namespace xe::kernel; +using namespace xe::kernel::xboxkrnl; + + +namespace xe { +namespace kernel { +namespace xboxkrnl { + + +typedef enum { + FAT_INVALID = 0, + FAT_VALUE, + FAT_POINTER, + FAT_EXTRA, +} FORMAT_ARGUMENT_TYPE; + +// TODO: clean me up! +SHIM_CALL DbgPrint_shim( + xe_ppc_state_t* ppc_state, KernelState* state) { + + uint32_t format_ptr = SHIM_GET_ARG_32(0); + if (format_ptr == 0) { + SHIM_SET_RETURN(-1); + return; + } + + const char *format = (const char *)SHIM_MEM_ADDR(format_ptr); + + int arg_index = 0; + + char buffer[512]; // TODO: ensure it never writes past the end of the buffer... + 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; + FORMAT_ARGUMENT_TYPE arg_type; + + // 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; + + if (*format == '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]; + strncpy(local, start, end + 1 - start); + + XEASSERT(arg_size == 8 || arg_size == 4); + if (arg_size == 8) { + if (arg_extras == 0) { + uint64_t value = arg_index < 7 + ? SHIM_GET_ARG_64(1 + arg_index) + : SHIM_MEM_64(SHIM_GPR_32(1) + ((arg_index - 7) * 8)); + int result = sprintf(b, local, value); + b += result; + arg_index++; + } + else { + XEASSERT(false); + } + } + else if (arg_size == 4) { + if (arg_extras == 0) { + uint64_t value = arg_index < 7 + ? SHIM_GET_ARG_64(1 + arg_index) + : SHIM_MEM_64(SHIM_GPR_32(1) + ((arg_index - 7) * 8)); + int result = sprintf(b, local, (uint32_t)value); + b += result; + arg_index++; + } + else { + XEASSERT(false); + } + } + } + else if (*format == 's' || + *format == 'p' || + *format == 'n') { + char local[512]; + strncpy(local, start, end + 1 - start); + + XEASSERT(arg_size == 0); + if (arg_extras == 0) { + uint32_t value = arg_index < 7 + ? SHIM_GET_ARG_32(1 + arg_index) + : SHIM_MEM_32(SHIM_GPR_32(1) + ((arg_index - 7) * 8)); + const char *pointer = (const char *)SHIM_MEM_ADDR(value); + int result = sprintf(b, local, pointer); + b += result; + arg_index++; + } + else { + XEASSERT(false); + } + } + else { + XEASSERT(false); + break; + } + } + *b++ = '\0'; + + XELOGD("(DbgPrint) %s", buffer); +} + + +} // namespace xboxkrnl +} // namespace kernel +} // namespace xe + + +void xe::kernel::xboxkrnl::RegisterDebugExports( + ExportResolver* export_resolver, KernelState* state) { + SHIM_SET_MAPPING("xboxkrnl.exe", DbgPrint, state); +} diff --git a/src/xenia/kernel/modules/xboxkrnl/xboxkrnl_debug.h b/src/xenia/kernel/modules/xboxkrnl/xboxkrnl_debug.h new file mode 100644 index 000000000..851e19240 --- /dev/null +++ b/src/xenia/kernel/modules/xboxkrnl/xboxkrnl_debug.h @@ -0,0 +1,29 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2013 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#ifndef XENIA_KERNEL_MODULES_XBOXKRNL_DEBUG_H_ +#define XENIA_KERNEL_MODULES_XBOXKRNL_DEBUG_H_ + +#include +#include + +#include + + +namespace xe { +namespace kernel { +namespace xboxkrnl { + + +} // namespace xboxkrnl +} // namespace kernel +} // namespace xe + + +#endif // XENIA_KERNEL_MODULES_XBOXKRNL_DEBUG_H_ diff --git a/src/xenia/kernel/modules/xboxkrnl/xboxkrnl_private.h b/src/xenia/kernel/modules/xboxkrnl/xboxkrnl_private.h index fd3fd9506..492c9ef61 100644 --- a/src/xenia/kernel/modules/xboxkrnl/xboxkrnl_private.h +++ b/src/xenia/kernel/modules/xboxkrnl/xboxkrnl_private.h @@ -30,6 +30,7 @@ extern KernelState* shared_kernel_state_; // Registration functions, one per file. +void RegisterDebugExports(ExportResolver* export_resolver, KernelState* state); void RegisterHalExports(ExportResolver* export_resolver, KernelState* state); void RegisterMemoryExports(ExportResolver* export_resolver, KernelState* state); void RegisterModuleExports(ExportResolver* export_resolver, KernelState* state); diff --git a/src/xenia/kernel/modules/xboxkrnl/xboxkrnl_rtl.cc b/src/xenia/kernel/modules/xboxkrnl/xboxkrnl_rtl.cc index 4799a442d..0dad84a1f 100644 --- a/src/xenia/kernel/modules/xboxkrnl/xboxkrnl_rtl.cc +++ b/src/xenia/kernel/modules/xboxkrnl/xboxkrnl_rtl.cc @@ -333,6 +333,213 @@ SHIM_CALL RtlUnicodeStringToAnsiString_shim( } +typedef enum { + FAT_INVALID = 0, + FAT_VALUE, + FAT_POINTER, + FAT_EXTRA, +} FORMAT_ARGUMENT_TYPE; + +// TODO: clean me up! +SHIM_CALL _vsnprintf_shim( + xe_ppc_state_t* ppc_state, KernelState* state) { + + uint32_t buffer_ptr = SHIM_GET_ARG_32(0); + uint32_t count = SHIM_GET_ARG_32(1); + uint32_t format_ptr = SHIM_GET_ARG_32(2); + uint32_t arg_ptr = SHIM_GET_ARG_32(3); + + if (format_ptr == 0) { + SHIM_SET_RETURN(-1); + return; + } + + char *buffer = (char *)SHIM_MEM_ADDR(buffer_ptr); // TODO: ensure it never writes past the end of the buffer (count)... + const char *format = (const char *)SHIM_MEM_ADDR(format_ptr); + + int arg_index = 0; + + 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; + FORMAT_ARGUMENT_TYPE arg_type; + + // 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; + + if (*format == '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]; + strncpy(local, start, end + 1 - start); + + XEASSERT(arg_size == 8 || arg_size == 4); + if (arg_size == 8) { + if (arg_extras == 0) { + uint64_t value = SHIM_MEM_64(arg_ptr + (arg_index * 8)); // TODO: check if this is correct... + int result = sprintf(b, local, value); + b += result; + arg_index++; + } + else { + XEASSERT(false); + } + } + else if (arg_size == 4) { + if (arg_extras == 0) { + uint64_t value = SHIM_MEM_64(arg_ptr + (arg_index * 8)); // TODO: check if this is correct... + int result = sprintf(b, local, (uint32_t)value); + b += result; + arg_index++; + } + else { + XEASSERT(false); + } + } + } + else if (*format == 's' || + *format == 'p' || + *format == 'n') { + char local[512]; + strncpy(local, start, end + 1 - start); + + XEASSERT(arg_size == 0); + if (arg_extras == 0) { + uint64_t value = SHIM_MEM_64(arg_ptr + (arg_index * 8)); // TODO: check if this is correct... + const char *pointer = (const char *)SHIM_MEM_ADDR(value); + int result = sprintf(b, local, pointer); + b += result; + arg_index++; + } + else { + XEASSERT(false); + } + } + else { + XEASSERT(false); + break; + } + } + *b++ = '\0'; + SHIM_SET_RETURN((uint32_t)(b - buffer)); +} + + uint32_t xeRtlImageXexHeaderField(uint32_t xex_header_base_ptr, uint32_t image_field) { KernelState* state = shared_kernel_state_; @@ -631,6 +838,8 @@ void xe::kernel::xboxkrnl::RegisterRtlExports( SHIM_SET_MAPPING("xboxkrnl.exe", RtlFreeUnicodeString, state); SHIM_SET_MAPPING("xboxkrnl.exe", RtlUnicodeStringToAnsiString, state); + SHIM_SET_MAPPING("xboxkrnl.exe", _vsnprintf, state); + SHIM_SET_MAPPING("xboxkrnl.exe", RtlImageXexHeaderField, state); SHIM_SET_MAPPING("xboxkrnl.exe", RtlInitializeCriticalSection, state);