From e9dd0072de608d9ec7dc0b27a4c6a7c2522602ae Mon Sep 17 00:00:00 2001 From: Sepalani Date: Thu, 1 Dec 2016 12:27:13 +0000 Subject: [PATCH 1/6] HLE: Variable Argument Lists support --- Source/Core/Core/Core.vcxproj | 1 + Source/Core/Core/Core.vcxproj.filters | 3 + Source/Core/Core/HLE/HLE_OS.cpp | 51 +++------- Source/Core/Core/HLE/HLE_VarArgs.h | 138 ++++++++++++++++++++++++++ 4 files changed, 154 insertions(+), 39 deletions(-) create mode 100644 Source/Core/Core/HLE/HLE_VarArgs.h diff --git a/Source/Core/Core/Core.vcxproj b/Source/Core/Core/Core.vcxproj index a13c4ea09c..55e2d9c328 100644 --- a/Source/Core/Core/Core.vcxproj +++ b/Source/Core/Core/Core.vcxproj @@ -343,6 +343,7 @@ + diff --git a/Source/Core/Core/Core.vcxproj.filters b/Source/Core/Core/Core.vcxproj.filters index 8dee1673d1..1411269cb1 100644 --- a/Source/Core/Core/Core.vcxproj.filters +++ b/Source/Core/Core/Core.vcxproj.filters @@ -955,6 +955,9 @@ HLE + + HLE + PowerPC\Cached Interpreter diff --git a/Source/Core/Core/HLE/HLE_OS.cpp b/Source/Core/Core/HLE/HLE_OS.cpp index 74adaa148c..547fc7e608 100644 --- a/Source/Core/Core/HLE/HLE_OS.cpp +++ b/Source/Core/Core/HLE/HLE_OS.cpp @@ -9,6 +9,7 @@ #include "Common/MsgHandler.h" #include "Common/StringUtil.h" #include "Core/HLE/HLE_OS.h" +#include "Core/HLE/HLE_VarArgs.h" #include "Core/HW/Memmap.h" #include "Core/PowerPC/PowerPC.h" @@ -89,14 +90,12 @@ void HLE_write_console() NOTICE_LOG(OSREPORT, "%08x->%08x| %s", LR, PC, SHIFTJISToUTF8(report_message).c_str()); } -std::string GetStringVA(u32 strReg) +std::string GetStringVA(u32 str_reg) { std::string ArgumentBuffer; - u32 ParameterCounter = strReg + 1; - u32 FloatingParameterCounter = 1; - std::string result; - std::string string = PowerPC::HostGetString(GPR(strReg)); + std::string string = PowerPC::HostGetString(GPR(str_reg)); + HLE::VAList ap(GPR(1) + 0x8, str_reg + 1); for (size_t i = 0; i < string.size(); i++) { @@ -120,38 +119,13 @@ std::string GetStringVA(u32 strReg) ArgumentBuffer += string[i]; - u64 Parameter; - if (ParameterCounter > 10) - { - Parameter = PowerPC::HostRead_U32(GPR(1) + 0x8 + ((ParameterCounter - 11) * 4)); - } - else - { - if (string[i - 1] == 'l' && - string[i - 2] == 'l') // hax, just seen this on sysmenu osreport - { - Parameter = GPR(++ParameterCounter); - Parameter = (Parameter << 32) | GPR(++ParameterCounter); - } - else // normal, 32bit - Parameter = GPR(ParameterCounter); - } - ParameterCounter++; - switch (string[i]) { case 's': result += StringFromFormat(ArgumentBuffer.c_str(), - PowerPC::HostGetString((u32)Parameter).c_str()); + PowerPC::HostGetString(ap.GetArgT()).c_str()); break; - case 'd': - case 'i': - { - result += StringFromFormat(ArgumentBuffer.c_str(), Parameter); - break; - } - case 'a': case 'A': case 'e': @@ -160,25 +134,24 @@ std::string GetStringVA(u32 strReg) case 'F': case 'g': case 'G': - { - result += StringFromFormat(ArgumentBuffer.c_str(), rPS0(FloatingParameterCounter)); - FloatingParameterCounter++; - ParameterCounter--; + result += StringFromFormat(ArgumentBuffer.c_str(), ap.GetArgT()); break; - } case 'p': // Override, so 64bit Dolphin prints 32bit pointers, since the ppc is 32bit :) - result += StringFromFormat("%x", (u32)Parameter); + result += StringFromFormat("%x", ap.GetArgT()); break; case 'n': - PowerPC::HostWrite_U32(static_cast(result.size()), static_cast(Parameter)); + PowerPC::HostWrite_U32(static_cast(result.size()), ap.GetArgT()); // %n doesn't output anything, so the result variable is untouched break; default: - result += StringFromFormat(ArgumentBuffer.c_str(), Parameter); + if (string[i - 1] == 'l' && string[i - 2] == 'l') + result += StringFromFormat(ArgumentBuffer.c_str(), ap.GetArgT()); + else + result += StringFromFormat(ArgumentBuffer.c_str(), ap.GetArgT()); break; } } diff --git a/Source/Core/Core/HLE/HLE_VarArgs.h b/Source/Core/Core/HLE/HLE_VarArgs.h new file mode 100644 index 0000000000..8c31549d70 --- /dev/null +++ b/Source/Core/Core/HLE/HLE_VarArgs.h @@ -0,0 +1,138 @@ +// Copyright 2016 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#pragma once + +#include "Common/Align.h" +#include "Common/CommonTypes.h" + +#include "Core/HW/Memmap.h" +#include "Core/PowerPC/PowerPC.h" + +#include + +namespace HLE +{ +// See System V ABI (SVR4) for more details +// -> 3-18 Parameter Passing +// -> 3-21 Variable Argument Lists +// +// Source: +// http://refspecs.linux-foundation.org/elf/elfspec_ppc.pdf +class VAList +{ +public: + explicit VAList(u32 stack, u32 gpr = 3, u32 fpr = 1, u32 gpr_max = 10, u32 fpr_max = 8) + : m_gpr(gpr), m_fpr(fpr), m_gpr_max(gpr_max), m_fpr_max(fpr_max), m_stack(stack) + { + } + ~VAList() = default; + + // SFINAE + template + constexpr bool IS_ARG_POINTER = std::is_union() || std::is_class(); + template + constexpr bool IS_WORD = std::is_pointer() || (std::is_integral() && sizeof(T) <= 4); + template + constexpr bool IS_DOUBLE_WORD = std::is_integral() && sizeof(T) == 8; + template + constexpr bool IS_ARG_REAL = std::is_floating_point(); + + // 0 - arg_ARGPOINTER + template >* = nullptr> + T GetArg() + { + T obj; + u32 addr = GetArg(); + + for (size_t i = 0; i < sizeof(T); i += 1, addr += 1) + { + reinterpret_cast(&obj)[i] = PowerPC::HostRead_U8(addr); + } + + return obj; + } + + // 1 - arg_WORD + template >* = nullptr> + T GetArg() + { + static_assert(!std::is_pointer(), "VAList doesn't support pointers"); + u64 value; + + if (m_gpr <= m_gpr_max) + { + value = GPR(m_gpr); + m_gpr += 1; + } + else + { + m_stack = Common::AlignUp(m_stack, 4); + value = PowerPC::HostRead_U32(m_stack); + m_stack += 4; + } + + return static_cast(value); + } + + // 2 - arg_DOUBLEWORD + template >* = nullptr> + T GetArg() + { + u64 value; + + if (m_gpr % 2 == 0) + m_gpr += 1; + if (m_gpr < m_gpr_max) + { + value = static_cast(GPR(m_gpr)) << 32 | GPR(m_gpr + 1); + m_gpr += 2; + } + else + { + m_stack = Common::AlignUp(m_stack, 8); + value = PowerPC::HostRead_U64(m_stack); + m_stack += 8; + } + + return static_cast(value); + } + + // 3 - arg_ARGREAL + template >* = nullptr> + T GetArg() + { + double value; + + if (m_fpr <= m_fpr_max) + { + value = rPS0(m_fpr); + m_fpr += 1; + } + else + { + m_stack = Common::AlignUp(m_stack, 8); + const u64 integral = PowerPC::HostRead_U64(m_stack); + std::memcpy(&value, &integral, sizeof(double)); + m_stack += 8; + } + + return static_cast(value); + } + + // Helper + template + T GetArgT() + { + return static_cast(GetArg()); + } + +private: + u32 m_gpr = 3; + u32 m_fpr = 1; + const u32 m_gpr_max = 10; + const u32 m_fpr_max = 8; + u32 m_stack; +}; +} From 5a4f085c10567224334ca96969e5189553cf6961 Mon Sep 17 00:00:00 2001 From: Sepalani Date: Sat, 28 Jan 2017 02:02:43 +0000 Subject: [PATCH 2/6] HLE: VAList cleanup and SystemVABI namespace --- Source/Core/Core/CMakeLists.txt | 1 + Source/Core/Core/Core.vcxproj | 1 + Source/Core/Core/Core.vcxproj.filters | 3 +++ Source/Core/Core/HLE/HLE_OS.cpp | 4 +-- Source/Core/Core/HLE/HLE_VarArgs.cpp | 17 ++++++++++++ Source/Core/Core/HLE/HLE_VarArgs.h | 38 ++++++++++++++++----------- 6 files changed, 46 insertions(+), 18 deletions(-) create mode 100644 Source/Core/Core/HLE/HLE_VarArgs.cpp diff --git a/Source/Core/Core/CMakeLists.txt b/Source/Core/Core/CMakeLists.txt index 2712a9f951..1f7103009b 100644 --- a/Source/Core/Core/CMakeLists.txt +++ b/Source/Core/Core/CMakeLists.txt @@ -72,6 +72,7 @@ set(SRCS HLE/HLE.cpp HLE/HLE_Misc.cpp HLE/HLE_OS.cpp + HLE/HLE_VarArgs.cpp HW/AudioInterface.cpp HW/CPU.cpp HW/DSP.cpp diff --git a/Source/Core/Core/Core.vcxproj b/Source/Core/Core/Core.vcxproj index 55e2d9c328..a6334c1bb9 100644 --- a/Source/Core/Core/Core.vcxproj +++ b/Source/Core/Core/Core.vcxproj @@ -100,6 +100,7 @@ + diff --git a/Source/Core/Core/Core.vcxproj.filters b/Source/Core/Core/Core.vcxproj.filters index 1411269cb1..029ce1d207 100644 --- a/Source/Core/Core/Core.vcxproj.filters +++ b/Source/Core/Core/Core.vcxproj.filters @@ -293,6 +293,9 @@ HLE + + HLE + PowerPC diff --git a/Source/Core/Core/HLE/HLE_OS.cpp b/Source/Core/Core/HLE/HLE_OS.cpp index 547fc7e608..788e21d53b 100644 --- a/Source/Core/Core/HLE/HLE_OS.cpp +++ b/Source/Core/Core/HLE/HLE_OS.cpp @@ -95,7 +95,7 @@ std::string GetStringVA(u32 str_reg) std::string ArgumentBuffer; std::string result; std::string string = PowerPC::HostGetString(GPR(str_reg)); - HLE::VAList ap(GPR(1) + 0x8, str_reg + 1); + HLE::SystemVABI::VAList ap(GPR(1) + 0x8, str_reg + 1); for (size_t i = 0; i < string.size(); i++) { @@ -143,8 +143,8 @@ std::string GetStringVA(u32 str_reg) break; case 'n': - PowerPC::HostWrite_U32(static_cast(result.size()), ap.GetArgT()); // %n doesn't output anything, so the result variable is untouched + PowerPC::HostWrite_U32(static_cast(result.size()), ap.GetArgT()); break; default: diff --git a/Source/Core/Core/HLE/HLE_VarArgs.cpp b/Source/Core/Core/HLE/HLE_VarArgs.cpp new file mode 100644 index 0000000000..27ac6f7bf2 --- /dev/null +++ b/Source/Core/Core/HLE/HLE_VarArgs.cpp @@ -0,0 +1,17 @@ +// Copyright 2017 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#include "Core/HLE/HLE_VarArgs.h" + +HLE::SystemVABI::VAList::~VAList() = default; + +u32 HLE::SystemVABI::VAList::GetGPR(u32 gpr) const +{ + return GPR(gpr); +} + +double HLE::SystemVABI::VAList::GetFPR(u32 fpr) const +{ + return rPS0(fpr); +} diff --git a/Source/Core/Core/HLE/HLE_VarArgs.h b/Source/Core/Core/HLE/HLE_VarArgs.h index 8c31549d70..a76ae76fe3 100644 --- a/Source/Core/Core/HLE/HLE_VarArgs.h +++ b/Source/Core/Core/HLE/HLE_VarArgs.h @@ -1,4 +1,4 @@ -// Copyright 2016 Dolphin Emulator Project +// Copyright 2017 Dolphin Emulator Project // Licensed under GPLv2+ // Refer to the license.txt file included. @@ -14,6 +14,18 @@ namespace HLE { +namespace SystemVABI +{ +// SFINAE +template +constexpr bool IS_ARG_POINTER = std::is_union() || std::is_class(); +template +constexpr bool IS_WORD = std::is_pointer() || (std::is_integral() && sizeof(T) <= 4); +template +constexpr bool IS_DOUBLE_WORD = std::is_integral() && sizeof(T) == 8; +template +constexpr bool IS_ARG_REAL = std::is_floating_point(); + // See System V ABI (SVR4) for more details // -> 3-18 Parameter Passing // -> 3-21 Variable Argument Lists @@ -27,17 +39,7 @@ public: : m_gpr(gpr), m_fpr(fpr), m_gpr_max(gpr_max), m_fpr_max(fpr_max), m_stack(stack) { } - ~VAList() = default; - - // SFINAE - template - constexpr bool IS_ARG_POINTER = std::is_union() || std::is_class(); - template - constexpr bool IS_WORD = std::is_pointer() || (std::is_integral() && sizeof(T) <= 4); - template - constexpr bool IS_DOUBLE_WORD = std::is_integral() && sizeof(T) == 8; - template - constexpr bool IS_ARG_REAL = std::is_floating_point(); + virtual ~VAList(); // 0 - arg_ARGPOINTER template >* = nullptr> @@ -63,7 +65,7 @@ public: if (m_gpr <= m_gpr_max) { - value = GPR(m_gpr); + value = GetGPR(m_gpr); m_gpr += 1; } else @@ -86,7 +88,7 @@ public: m_gpr += 1; if (m_gpr < m_gpr_max) { - value = static_cast(GPR(m_gpr)) << 32 | GPR(m_gpr + 1); + value = static_cast(GetGPR(m_gpr)) << 32 | GetGPR(m_gpr + 1); m_gpr += 2; } else @@ -107,7 +109,7 @@ public: if (m_fpr <= m_fpr_max) { - value = rPS0(m_fpr); + value = GetFPR(m_fpr); m_fpr += 1; } else @@ -134,5 +136,9 @@ private: const u32 m_gpr_max = 10; const u32 m_fpr_max = 8; u32 m_stack; + + virtual u32 GetGPR(u32 gpr) const; + virtual double GetFPR(u32 fpr) const; }; -} +} // namespace SystemVABI +} // namespace HLE From 061dadbc618b3e50e3c2aa41c2a08846ab367a4b Mon Sep 17 00:00:00 2001 From: Sepalani Date: Sat, 28 Jan 2017 03:28:28 +0000 Subject: [PATCH 3/6] HLE: SVR4 VAList struct added --- Source/Core/Core/HLE/HLE_VarArgs.cpp | 50 ++++++++++++++++++++++++++++ Source/Core/Core/HLE/HLE_VarArgs.h | 35 ++++++++++++++++++- 2 files changed, 84 insertions(+), 1 deletion(-) diff --git a/Source/Core/Core/HLE/HLE_VarArgs.cpp b/Source/Core/Core/HLE/HLE_VarArgs.cpp index 27ac6f7bf2..1b9b14e760 100644 --- a/Source/Core/Core/HLE/HLE_VarArgs.cpp +++ b/Source/Core/Core/HLE/HLE_VarArgs.cpp @@ -4,6 +4,8 @@ #include "Core/HLE/HLE_VarArgs.h" +#include "Common/Logging/Log.h" + HLE::SystemVABI::VAList::~VAList() = default; u32 HLE::SystemVABI::VAList::GetGPR(u32 gpr) const @@ -15,3 +17,51 @@ double HLE::SystemVABI::VAList::GetFPR(u32 fpr) const { return rPS0(fpr); } + +HLE::SystemVABI::VAListStruct::VAListStruct(u32 address) + : VAList(0), m_va_list{PowerPC::HostRead_U8(address), PowerPC::HostRead_U8(address + 1), + PowerPC::HostRead_U32(address + 4), PowerPC::HostRead_U32(address + 8)}, + m_address(address), m_has_fpr_area(GetCRBit(6) == 1) +{ + m_stack = m_va_list.overflow_arg_area; + m_gpr += m_va_list.gpr; + m_fpr += m_va_list.fpr; +} + +u32 HLE::SystemVABI::VAListStruct::GetGPRArea() const +{ + return m_va_list.reg_save_area; +} + +u32 HLE::SystemVABI::VAListStruct::GetFPRArea() const +{ + return GetGPRArea() + 4 * 8; +} + +u32 HLE::SystemVABI::VAListStruct::GetGPR(u32 gpr) const +{ + if (gpr < 3 || gpr > 10) + { + ERROR_LOG(OSHLE, "VAListStruct at %08x doesn't have GPR%d!", m_address, gpr); + return 0; + } + const u32 gpr_address = Common::AlignUp(GetGPRArea() + 4 * (gpr - 3), 4); + return PowerPC::HostRead_U32(gpr_address); +} + +double HLE::SystemVABI::VAListStruct::GetFPR(u32 fpr) const +{ + double value = 0.0; + + if (!m_has_fpr_area || fpr < 1 || fpr > 8) + { + ERROR_LOG(OSHLE, "VAListStruct at %08x doesn't have FPR%d!", m_address, fpr); + } + else + { + const u32 fpr_address = Common::AlignUp(GetFPRArea() + 8 * (fpr - 1), 8); + const u64 integral = PowerPC::HostRead_U64(fpr_address); + std::memcpy(&value, &integral, sizeof(double)); + } + return value; +} diff --git a/Source/Core/Core/HLE/HLE_VarArgs.h b/Source/Core/Core/HLE/HLE_VarArgs.h index a76ae76fe3..3c72c1f05e 100644 --- a/Source/Core/Core/HLE/HLE_VarArgs.h +++ b/Source/Core/Core/HLE/HLE_VarArgs.h @@ -130,15 +130,48 @@ public: return static_cast(GetArg()); } -private: +protected: u32 m_gpr = 3; u32 m_fpr = 1; const u32 m_gpr_max = 10; const u32 m_fpr_max = 8; u32 m_stack; +private: virtual u32 GetGPR(u32 gpr) const; virtual double GetFPR(u32 fpr) const; }; + +// See System V ABI (SVR4) for more details +// -> 6-6 Required Routines +// -> 3-21 Variable Argument Lists +// +// Source: +// http://refspecs.linux-foundation.org/elf/elfspec_ppc.pdf +class VAListStruct : public VAList +{ +public: + explicit VAListStruct(u32 address); + ~VAListStruct() = default; + +private: + struct svr4_va_list + { + u8 gpr; + u8 fpr; + u32 overflow_arg_area; + u32 reg_save_area; + }; + const svr4_va_list m_va_list; + const u32 m_address; + const bool m_has_fpr_area; + + u32 GetGPRArea() const; + u32 GetFPRArea() const; + + u32 GetGPR(u32 gpr) const override; + double GetFPR(u32 fpr) const override; +}; + } // namespace SystemVABI } // namespace HLE From 9f6d6e6921488e0e0c4747afc9f267512096bdaf Mon Sep 17 00:00:00 2001 From: Sepalani Date: Sat, 28 Jan 2017 04:07:00 +0000 Subject: [PATCH 4/6] HLE: HLE_GeneralDebugVPrint added --- Source/Core/Core/HLE/HLE.cpp | 2 +- Source/Core/Core/HLE/HLE_OS.cpp | 52 +++++++++++++++++++++++---------- Source/Core/Core/HLE/HLE_OS.h | 1 + 3 files changed, 39 insertions(+), 16 deletions(-) diff --git a/Source/Core/Core/HLE/HLE.cpp b/Source/Core/Core/HLE/HLE.cpp index 4671ce1fd8..610c747b15 100644 --- a/Source/Core/Core/HLE/HLE.cpp +++ b/Source/Core/Core/HLE/HLE.cpp @@ -60,7 +60,7 @@ static const SPatch OSPatches[] = { {"OSReport", HLE_OS::HLE_GeneralDebugPrint, HLE_HOOK_START, HLE_TYPE_DEBUG}, {"DEBUGPrint", HLE_OS::HLE_GeneralDebugPrint, HLE_HOOK_START, HLE_TYPE_DEBUG}, {"WUD_DEBUGPrint", HLE_OS::HLE_GeneralDebugPrint, HLE_HOOK_START, HLE_TYPE_DEBUG}, - {"vprintf", HLE_OS::HLE_GeneralDebugPrint, HLE_HOOK_START, HLE_TYPE_DEBUG}, + {"vprintf", HLE_OS::HLE_GeneralDebugVPrint, HLE_HOOK_START, HLE_TYPE_DEBUG}, {"printf", HLE_OS::HLE_GeneralDebugPrint, HLE_HOOK_START, HLE_TYPE_DEBUG}, {"nlPrintf", HLE_OS::HLE_GeneralDebugPrint, HLE_HOOK_START, HLE_TYPE_DEBUG}, {"puts", HLE_OS::HLE_GeneralDebugPrint, HLE_HOOK_START, HLE_TYPE_DEBUG}, // gcc-optimized printf? diff --git a/Source/Core/Core/HLE/HLE_OS.cpp b/Source/Core/Core/HLE/HLE_OS.cpp index 788e21d53b..c4c48ef07b 100644 --- a/Source/Core/Core/HLE/HLE_OS.cpp +++ b/Source/Core/Core/HLE/HLE_OS.cpp @@ -2,6 +2,7 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +#include #include #include "Common/CommonTypes.h" @@ -15,7 +16,14 @@ namespace HLE_OS { -std::string GetStringVA(u32 strReg = 3); +enum class ParameterType : bool +{ + ParameterList = false, + VariableArgumentList = true +}; + +std::string GetStringVA(u32 str_reg = 3, + ParameterType parameter_type = ParameterType::ParameterList); void HLE_OSPanic() { @@ -28,8 +36,8 @@ void HLE_OSPanic() NPC = LR; } -// Generalized func for just printing string pointed to by r3. -void HLE_GeneralDebugPrint() +// Generalized function for printing formatted string. +void HLE_GeneralDebugPrint(ParameterType parameter_type) { std::string report_message; @@ -39,12 +47,12 @@ void HLE_GeneralDebugPrint() if (GPR(4) > 0x80000000) { // ___blank(void* this, const char* fmt, ...); - report_message = GetStringVA(4); + report_message = GetStringVA(4, parameter_type); } else { // ___blank(void* this, int log_type, const char* fmt, ...); - report_message = GetStringVA(5); + report_message = GetStringVA(5, parameter_type); } } else @@ -52,12 +60,12 @@ void HLE_GeneralDebugPrint() if (GPR(3) > 0x80000000) { // ___blank(const char* fmt, ...); - report_message = GetStringVA(); + report_message = GetStringVA(3, parameter_type); } else { // ___blank(int log_type, const char* fmt, ...); - report_message = GetStringVA(4); + report_message = GetStringVA(4, parameter_type); } } @@ -66,6 +74,18 @@ void HLE_GeneralDebugPrint() NOTICE_LOG(OSREPORT, "%08x->%08x| %s", LR, PC, SHIFTJISToUTF8(report_message).c_str()); } +// Generalized function for printing formatted string using parameter list. +void HLE_GeneralDebugPrint() +{ + HLE_GeneralDebugPrint(ParameterType::ParameterList); +} + +// Generalized function for printing formatted string using va_list. +void HLE_GeneralDebugVPrint() +{ + HLE_GeneralDebugPrint(ParameterType::VariableArgumentList); +} + // __write_console(int fd, const void* buffer, const u32* size) void HLE_write_console() { @@ -90,12 +110,14 @@ void HLE_write_console() NOTICE_LOG(OSREPORT, "%08x->%08x| %s", LR, PC, SHIFTJISToUTF8(report_message).c_str()); } -std::string GetStringVA(u32 str_reg) +std::string GetStringVA(u32 str_reg, ParameterType parameter_type) { std::string ArgumentBuffer; std::string result; std::string string = PowerPC::HostGetString(GPR(str_reg)); - HLE::SystemVABI::VAList ap(GPR(1) + 0x8, str_reg + 1); + auto ap = parameter_type == ParameterType::VariableArgumentList ? + std::make_unique(GPR(str_reg + 1)) : + std::make_unique(GPR(1) + 0x8, str_reg + 1); for (size_t i = 0; i < string.size(); i++) { @@ -123,7 +145,7 @@ std::string GetStringVA(u32 str_reg) { case 's': result += StringFromFormat(ArgumentBuffer.c_str(), - PowerPC::HostGetString(ap.GetArgT()).c_str()); + PowerPC::HostGetString(ap->GetArgT()).c_str()); break; case 'a': @@ -134,24 +156,24 @@ std::string GetStringVA(u32 str_reg) case 'F': case 'g': case 'G': - result += StringFromFormat(ArgumentBuffer.c_str(), ap.GetArgT()); + result += StringFromFormat(ArgumentBuffer.c_str(), ap->GetArgT()); break; case 'p': // Override, so 64bit Dolphin prints 32bit pointers, since the ppc is 32bit :) - result += StringFromFormat("%x", ap.GetArgT()); + result += StringFromFormat("%x", ap->GetArgT()); break; case 'n': // %n doesn't output anything, so the result variable is untouched - PowerPC::HostWrite_U32(static_cast(result.size()), ap.GetArgT()); + PowerPC::HostWrite_U32(static_cast(result.size()), ap->GetArgT()); break; default: if (string[i - 1] == 'l' && string[i - 2] == 'l') - result += StringFromFormat(ArgumentBuffer.c_str(), ap.GetArgT()); + result += StringFromFormat(ArgumentBuffer.c_str(), ap->GetArgT()); else - result += StringFromFormat(ArgumentBuffer.c_str(), ap.GetArgT()); + result += StringFromFormat(ArgumentBuffer.c_str(), ap->GetArgT()); break; } } diff --git a/Source/Core/Core/HLE/HLE_OS.h b/Source/Core/Core/HLE/HLE_OS.h index d729a8842f..1d8610909e 100644 --- a/Source/Core/Core/HLE/HLE_OS.h +++ b/Source/Core/Core/HLE/HLE_OS.h @@ -7,6 +7,7 @@ namespace HLE_OS { void HLE_GeneralDebugPrint(); +void HLE_GeneralDebugVPrint(); void HLE_write_console(); void HLE_OSPanic(); } From 2989c0cb615e91c8f8d4eda127611496487d973e Mon Sep 17 00:00:00 2001 From: Sepalani Date: Fri, 26 May 2017 18:43:48 +0100 Subject: [PATCH 5/6] HLE: Log (v)dprintf messages --- Source/Core/Core/HLE/HLE.cpp | 2 ++ Source/Core/Core/HLE/HLE_OS.cpp | 26 ++++++++++++++++++++++++++ Source/Core/Core/HLE/HLE_OS.h | 2 ++ 3 files changed, 30 insertions(+) diff --git a/Source/Core/Core/HLE/HLE.cpp b/Source/Core/Core/HLE/HLE.cpp index 610c747b15..c03fa54398 100644 --- a/Source/Core/Core/HLE/HLE.cpp +++ b/Source/Core/Core/HLE/HLE.cpp @@ -62,6 +62,8 @@ static const SPatch OSPatches[] = { {"WUD_DEBUGPrint", HLE_OS::HLE_GeneralDebugPrint, HLE_HOOK_START, HLE_TYPE_DEBUG}, {"vprintf", HLE_OS::HLE_GeneralDebugVPrint, HLE_HOOK_START, HLE_TYPE_DEBUG}, {"printf", HLE_OS::HLE_GeneralDebugPrint, HLE_HOOK_START, HLE_TYPE_DEBUG}, + {"vdprintf", HLE_OS::HLE_LogVDPrint, HLE_HOOK_START, HLE_TYPE_DEBUG}, + {"dprintf", HLE_OS::HLE_LogDPrint, HLE_HOOK_START, HLE_TYPE_DEBUG}, {"nlPrintf", HLE_OS::HLE_GeneralDebugPrint, HLE_HOOK_START, HLE_TYPE_DEBUG}, {"puts", HLE_OS::HLE_GeneralDebugPrint, HLE_HOOK_START, HLE_TYPE_DEBUG}, // gcc-optimized printf? {"___blank", HLE_OS::HLE_GeneralDebugPrint, HLE_HOOK_START, HLE_TYPE_DEBUG}, // used for early init things (normally) diff --git a/Source/Core/Core/HLE/HLE_OS.cpp b/Source/Core/Core/HLE/HLE_OS.cpp index c4c48ef07b..74d2a8ec4f 100644 --- a/Source/Core/Core/HLE/HLE_OS.cpp +++ b/Source/Core/Core/HLE/HLE_OS.cpp @@ -110,6 +110,32 @@ void HLE_write_console() NOTICE_LOG(OSREPORT, "%08x->%08x| %s", LR, PC, SHIFTJISToUTF8(report_message).c_str()); } +// Log (v)dprintf message if fd is 1 (stdout) or 2 (stderr) +void HLE_LogDPrint(ParameterType parameter_type) +{ + NPC = LR; + + if (GPR(3) != 1 && GPR(3) != 2) + return; + + std::string report_message = GetStringVA(4, parameter_type); + NOTICE_LOG(OSREPORT, "%08x->%08x| %s", LR, PC, SHIFTJISToUTF8(report_message).c_str()); +} + +// Log dprintf message +// -> int dprintf(int fd, const char* format, ...); +void HLE_LogDPrint() +{ + HLE_LogDPrint(ParameterType::ParameterList); +} + +// Log vdprintf message +// -> int vdprintf(int fd, const char* format, va_list ap); +void HLE_LogVDPrint() +{ + HLE_LogDPrint(ParameterType::VariableArgumentList); +} + std::string GetStringVA(u32 str_reg, ParameterType parameter_type) { std::string ArgumentBuffer; diff --git a/Source/Core/Core/HLE/HLE_OS.h b/Source/Core/Core/HLE/HLE_OS.h index 1d8610909e..55f3687eb2 100644 --- a/Source/Core/Core/HLE/HLE_OS.h +++ b/Source/Core/Core/HLE/HLE_OS.h @@ -10,4 +10,6 @@ void HLE_GeneralDebugPrint(); void HLE_GeneralDebugVPrint(); void HLE_write_console(); void HLE_OSPanic(); +void HLE_LogDPrint(); +void HLE_LogVDPrint(); } From ac51c80ad0f6de3a75e04e2b4b037ca102f14b63 Mon Sep 17 00:00:00 2001 From: Sepalani Date: Fri, 26 May 2017 19:03:25 +0100 Subject: [PATCH 6/6] HLE: Log (v)fprintf messages --- Source/Core/Core/HLE/HLE.cpp | 2 ++ Source/Core/Core/HLE/HLE_OS.cpp | 39 +++++++++++++++++++++++++++++++++ Source/Core/Core/HLE/HLE_OS.h | 2 ++ 3 files changed, 43 insertions(+) diff --git a/Source/Core/Core/HLE/HLE.cpp b/Source/Core/Core/HLE/HLE.cpp index c03fa54398..cc166768da 100644 --- a/Source/Core/Core/HLE/HLE.cpp +++ b/Source/Core/Core/HLE/HLE.cpp @@ -64,6 +64,8 @@ static const SPatch OSPatches[] = { {"printf", HLE_OS::HLE_GeneralDebugPrint, HLE_HOOK_START, HLE_TYPE_DEBUG}, {"vdprintf", HLE_OS::HLE_LogVDPrint, HLE_HOOK_START, HLE_TYPE_DEBUG}, {"dprintf", HLE_OS::HLE_LogDPrint, HLE_HOOK_START, HLE_TYPE_DEBUG}, + {"vfprintf", HLE_OS::HLE_LogVFPrint, HLE_HOOK_START, HLE_TYPE_DEBUG}, + {"fprintf", HLE_OS::HLE_LogFPrint, HLE_HOOK_START, HLE_TYPE_DEBUG}, {"nlPrintf", HLE_OS::HLE_GeneralDebugPrint, HLE_HOOK_START, HLE_TYPE_DEBUG}, {"puts", HLE_OS::HLE_GeneralDebugPrint, HLE_HOOK_START, HLE_TYPE_DEBUG}, // gcc-optimized printf? {"___blank", HLE_OS::HLE_GeneralDebugPrint, HLE_HOOK_START, HLE_TYPE_DEBUG}, // used for early init things (normally) diff --git a/Source/Core/Core/HLE/HLE_OS.cpp b/Source/Core/Core/HLE/HLE_OS.cpp index 74d2a8ec4f..bcdc9d67d5 100644 --- a/Source/Core/Core/HLE/HLE_OS.cpp +++ b/Source/Core/Core/HLE/HLE_OS.cpp @@ -136,6 +136,45 @@ void HLE_LogVDPrint() HLE_LogDPrint(ParameterType::VariableArgumentList); } +// Log (v)fprintf message if FILE is stdout or stderr +void HLE_LogFPrint(ParameterType parameter_type) +{ + NPC = LR; + + // The structure FILE is implementation defined. + // Both libogc and Dolphin SDK seem to store the fd at the same address. + int fd = -1; + if (PowerPC::HostIsRAMAddress(GPR(3)) && PowerPC::HostIsRAMAddress(GPR(3) + 0xF)) + { + // The fd is stored as a short at FILE+0xE. + fd = static_cast(PowerPC::HostRead_U16(GPR(3) + 0xE)); + } + if (fd != 1 && fd != 2) + { + // On RVL SDK it seems stored at FILE+0x2. + fd = static_cast(PowerPC::HostRead_U16(GPR(3) + 0x2)); + } + if (fd != 1 && fd != 2) + return; + + std::string report_message = GetStringVA(4, parameter_type); + NOTICE_LOG(OSREPORT, "%08x->%08x| %s", LR, PC, SHIFTJISToUTF8(report_message).c_str()); +} + +// Log fprintf message +// -> int fprintf(FILE* stream, const char* format, ...); +void HLE_LogFPrint() +{ + HLE_LogFPrint(ParameterType::ParameterList); +} + +// Log vfprintf message +// -> int vfprintf(FILE* stream, const char* format, va_list ap); +void HLE_LogVFPrint() +{ + HLE_LogFPrint(ParameterType::VariableArgumentList); +} + std::string GetStringVA(u32 str_reg, ParameterType parameter_type) { std::string ArgumentBuffer; diff --git a/Source/Core/Core/HLE/HLE_OS.h b/Source/Core/Core/HLE/HLE_OS.h index 55f3687eb2..af3abb3139 100644 --- a/Source/Core/Core/HLE/HLE_OS.h +++ b/Source/Core/Core/HLE/HLE_OS.h @@ -12,4 +12,6 @@ void HLE_write_console(); void HLE_OSPanic(); void HLE_LogDPrint(); void HLE_LogVDPrint(); +void HLE_LogFPrint(); +void HLE_LogVFPrint(); }