Merge pull request #5486 from sepalani/hle-print

HLE: More printf logs added
This commit is contained in:
shuffle2 2017-06-05 17:29:13 -07:00 committed by GitHub
commit 065c3d78b7
8 changed files with 369 additions and 47 deletions

View File

@ -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

View File

@ -100,6 +100,7 @@
<ClCompile Include="HLE\HLE.cpp" />
<ClCompile Include="HLE\HLE_Misc.cpp" />
<ClCompile Include="HLE\HLE_OS.cpp" />
<ClCompile Include="HLE\HLE_VarArgs.cpp" />
<ClCompile Include="HotkeyManager.cpp" />
<ClCompile Include="HW\AudioInterface.cpp" />
<ClCompile Include="HW\CPU.cpp" />
@ -343,6 +344,7 @@
<ClInclude Include="HLE\HLE.h" />
<ClInclude Include="HLE\HLE_Misc.h" />
<ClInclude Include="HLE\HLE_OS.h" />
<ClInclude Include="HLE\HLE_VarArgs.h" />
<ClInclude Include="Host.h" />
<ClInclude Include="HotkeyManager.h" />
<ClInclude Include="HW\AudioInterface.h" />

View File

@ -293,6 +293,9 @@
<ClCompile Include="HLE\HLE_OS.cpp">
<Filter>HLE</Filter>
</ClCompile>
<ClCompile Include="HLE\HLE_VarArgs.cpp" />
<Filter>HLE</Filter>
</ClCompile>
<ClCompile Include="PowerPC\BreakPoints.cpp">
<Filter>PowerPC</Filter>
</ClCompile>
@ -955,6 +958,9 @@
<ClInclude Include="HLE\HLE_OS.h">
<Filter>HLE</Filter>
</ClInclude>
<ClInclude Include="HLE\HLE_VarArgs.h">
<Filter>HLE</Filter>
</ClInclude>
<ClInclude Include="PowerPC\CachedInterpreter\CachedInterpreter.h">
<Filter>PowerPC\Cached Interpreter</Filter>
</ClInclude>

View File

@ -60,8 +60,12 @@ 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},
{"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)

View File

@ -2,6 +2,7 @@
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include <memory>
#include <string>
#include "Common/CommonTypes.h"
@ -9,12 +10,20 @@
#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"
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()
{
@ -27,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;
@ -38,12 +47,12 @@ void HLE_GeneralDebugPrint()
if (PowerPC::HostIsRAMAddress(GPR(4)))
{
// ___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
@ -51,12 +60,12 @@ void HLE_GeneralDebugPrint()
if (PowerPC::HostIsRAMAddress(GPR(3)))
{
// ___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);
}
}
@ -65,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()
{
@ -89,14 +110,79 @@ void HLE_write_console()
NOTICE_LOG(OSREPORT, "%08x->%08x| %s", LR, PC, SHIFTJISToUTF8(report_message).c_str());
}
std::string GetStringVA(u32 strReg)
// 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);
}
// 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<short>(PowerPC::HostRead_U16(GPR(3) + 0xE));
}
if (fd != 1 && fd != 2)
{
// On RVL SDK it seems stored at FILE+0x2.
fd = static_cast<short>(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;
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));
auto ap = parameter_type == ParameterType::VariableArgumentList ?
std::make_unique<HLE::SystemVABI::VAListStruct>(GPR(str_reg + 1)) :
std::make_unique<HLE::SystemVABI::VAList>(GPR(1) + 0x8, str_reg + 1);
for (size_t i = 0; i < string.size(); i++)
{
@ -120,38 +206,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<u32>()).c_str());
break;
case 'd':
case 'i':
{
result += StringFromFormat(ArgumentBuffer.c_str(), Parameter);
break;
}
case 'a':
case 'A':
case 'e':
@ -160,25 +221,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<double>());
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<u32>());
break;
case 'n':
PowerPC::HostWrite_U32(static_cast<u32>(result.size()), static_cast<u32>(Parameter));
// %n doesn't output anything, so the result variable is untouched
PowerPC::HostWrite_U32(static_cast<u32>(result.size()), ap->GetArgT<u32>());
break;
default:
result += StringFromFormat(ArgumentBuffer.c_str(), Parameter);
if (string[i - 1] == 'l' && string[i - 2] == 'l')
result += StringFromFormat(ArgumentBuffer.c_str(), ap->GetArgT<u64>());
else
result += StringFromFormat(ArgumentBuffer.c_str(), ap->GetArgT<u32>());
break;
}
}

View File

@ -7,6 +7,11 @@
namespace HLE_OS
{
void HLE_GeneralDebugPrint();
void HLE_GeneralDebugVPrint();
void HLE_write_console();
void HLE_OSPanic();
void HLE_LogDPrint();
void HLE_LogVDPrint();
void HLE_LogFPrint();
void HLE_LogVFPrint();
}

View File

@ -0,0 +1,67 @@
// Copyright 2017 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.
#include "Core/HLE/HLE_VarArgs.h"
#include "Common/Logging/Log.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);
}
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;
}

View File

@ -0,0 +1,177 @@
// Copyright 2017 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 <type_traits>
namespace HLE
{
namespace SystemVABI
{
// SFINAE
template <typename T>
constexpr bool IS_ARG_POINTER = std::is_union<T>() || std::is_class<T>();
template <typename T>
constexpr bool IS_WORD = std::is_pointer<T>() || (std::is_integral<T>() && sizeof(T) <= 4);
template <typename T>
constexpr bool IS_DOUBLE_WORD = std::is_integral<T>() && sizeof(T) == 8;
template <typename T>
constexpr bool IS_ARG_REAL = std::is_floating_point<T>();
// 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)
{
}
virtual ~VAList();
// 0 - arg_ARGPOINTER
template <typename T, typename std::enable_if_t<IS_ARG_POINTER<T>>* = nullptr>
T GetArg()
{
T obj;
u32 addr = GetArg<u32>();
for (size_t i = 0; i < sizeof(T); i += 1, addr += 1)
{
reinterpret_cast<u8*>(&obj)[i] = PowerPC::HostRead_U8(addr);
}
return obj;
}
// 1 - arg_WORD
template <typename T, typename std::enable_if_t<IS_WORD<T>>* = nullptr>
T GetArg()
{
static_assert(!std::is_pointer<T>(), "VAList doesn't support pointers");
u64 value;
if (m_gpr <= m_gpr_max)
{
value = GetGPR(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<T>(value);
}
// 2 - arg_DOUBLEWORD
template <typename T, typename std::enable_if_t<IS_DOUBLE_WORD<T>>* = nullptr>
T GetArg()
{
u64 value;
if (m_gpr % 2 == 0)
m_gpr += 1;
if (m_gpr < m_gpr_max)
{
value = static_cast<u64>(GetGPR(m_gpr)) << 32 | GetGPR(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<T>(value);
}
// 3 - arg_ARGREAL
template <typename T, typename std::enable_if_t<IS_ARG_REAL<T>>* = nullptr>
T GetArg()
{
double value;
if (m_fpr <= m_fpr_max)
{
value = GetFPR(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<T>(value);
}
// Helper
template <typename T>
T GetArgT()
{
return static_cast<T>(GetArg<T>());
}
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