ARMv7: LDR_REG, LDRD_IMM, LDREX, STREX

sceLibc: printf() improved
sceLibKernel: sceKernelGetThreadId(), sceKernelWaitThreadEnd()
This commit is contained in:
Nekotekina 2015-01-21 01:29:33 +03:00
parent 5dd3437da9
commit 2d7bf06dea
6 changed files with 296 additions and 56 deletions

View File

@ -110,6 +110,9 @@ struct ARMv7Context
} ITSTATE;
u32 R_ADDR;
u64 R_DATA;
void write_gpr(u32 n, u32 value)
{
assert(n < 16);
@ -135,6 +138,21 @@ struct ARMv7Context
return read_pc();
}
// function for processing va_args in printf-like functions
u32 get_next_gpr_arg(u32& g_count, u32& f_count, u32& v_count)
{
assert(!f_count && !v_count); // not supported
if (g_count < 4)
{
return GPR[g_count++];
}
else
{
return get_stack_arg(g_count++);
}
}
};
template<typename T, bool is_enum = std::is_enum<T>::value>

View File

@ -22,7 +22,7 @@ public:
code.code1 = vm::psv::read16(address + 2 & ~1);
u32 arg = address & 0x1 ? code.data : (u32)code.code0 << 16 | code.code1;
LOG_NOTICE(GENERAL, "code0 = 0x%04x, code1 = 0x%04x, data = 0x%08x, arg = 0x%08x", code.code0, code.code1, code.data, arg);
//LOG_NOTICE(GENERAL, "code0 = 0x%04x, code1 = 0x%04x, data = 0x%08x, arg = 0x%08x", code.code0, code.code1, code.data, arg);
// old decoding algorithm
@ -32,7 +32,7 @@ public:
{
code.data = opcode.length == 2 ? code.code0 : arg;
(*opcode.func)(m_thr.context, code, opcode.type);
// LOG_NOTICE(GENERAL, "%s, %d \n\n", opcode.name, opcode.length);
//LOG_NOTICE(ARMv7, "%s, %s", opcode.name, m_thr.RegsToString());
return opcode.length;
}
}

View File

@ -1204,12 +1204,12 @@ void ARMv7_instrs::LDR_IMM(ARMv7Context& context, const ARMv7Code code, const AR
const u32 offset_addr = add ? context.read_gpr(n) + imm32 : context.read_gpr(n) - imm32;
const u32 addr = index ? offset_addr : context.read_gpr(n);
context.write_gpr(t, vm::psv::read32(addr));
if (wback)
{
context.write_gpr(n, offset_addr);
}
context.write_gpr(t, vm::psv::read32(addr));
}
}
@ -1224,11 +1224,56 @@ void ARMv7_instrs::LDR_LIT(ARMv7Context& context, const ARMv7Code code, const AR
void ARMv7_instrs::LDR_REG(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type)
{
u32 cond = context.ITSTATE.advance();
u32 t = 0;
u32 n = 0;
u32 m = 0;
bool index = true;
bool add = true;
bool wback = false;
auto shift_t = SRType_LSL;
u32 shift_n = 0;
switch (type)
{
case T1:
{
t = (code.data & 0x7);
n = (code.data & 0x38) >> 3;
m = (code.data & 0x1c0) >> 6;
break;
}
case T2:
{
t = (code.data & 0xf000) >> 12;
n = (code.data & 0xf0000) >> 16;
m = (code.data & 0xf);
shift_n = (code.data & 0x30) >> 4;
if (n == 15)
{
throw "LDR (literal)";
}
break;
}
case A1: throw __FUNCTION__;
default: throw __FUNCTION__;
}
if (ConditionPassed(context, cond))
{
const u32 offset = Shift(context.read_gpr(m), shift_t, shift_n, context.APSR.C);
const u32 offset_addr = add ? context.read_gpr(n) + offset : context.read_gpr(n) - offset;
const u32 addr = index ? offset_addr : context.read_gpr(n);
const u32 data = vm::psv::read32(addr);
if (wback)
{
context.write_gpr(n, offset_addr);
}
context.write_gpr(t, data);
}
}
@ -1262,11 +1307,55 @@ void ARMv7_instrs::LDRB_REG(ARMv7Context& context, const ARMv7Code code, const A
void ARMv7_instrs::LDRD_IMM(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type)
{
u32 cond = context.ITSTATE.advance();
u32 t = 0;
u32 t2 = 0;
u32 n = 13;
u32 imm32 = 0;
bool index = true;
bool add = true;
bool wback = false;
switch (type)
{
case T1:
{
t = (code.data & 0xf000) >> 12;
t2 = (code.data & 0xf00) >> 8;
n = (code.data & 0xf0000) >> 16;
imm32 = (code.data & 0xff) << 2;
index = (code.data & 0x1000000);
add = (code.data & 0x800000);
wback = (code.data & 0x200000);
if (!index && !wback)
{
throw "LDRD_IMM_T1: Related encodings";
}
if (n == 15)
{
throw "LDRD (literal)";
}
break;
}
case A1: throw __FUNCTION__;
default: throw __FUNCTION__;
}
if (ConditionPassed(context, cond))
{
const u32 offset_addr = add ? context.read_gpr(n) + imm32 : context.read_gpr(n) - imm32;
const u32 addr = index ? offset_addr : context.read_gpr(n);
const u64 value = vm::psv::read64(addr);
context.write_gpr(t, (u32)(value));
context.write_gpr(t2, (u32)(value >> 32));
if (wback)
{
context.write_gpr(n, offset_addr);
}
}
}
void ARMv7_instrs::LDRD_LIT(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type)
@ -1374,11 +1463,33 @@ void ARMv7_instrs::LDRSH_REG(ARMv7Context& context, const ARMv7Code code, const
void ARMv7_instrs::LDREX(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type)
{
u32 cond = context.ITSTATE.advance();
u32 t = 0;
u32 n = 0;
u32 imm32 = 0;
switch (type)
{
case T1:
{
t = (code.data & 0xf000) >> 12;
n = (code.data & 0xf0000) >> 16;
imm32 = (code.data & 0xff) << 2;
break;
}
case A1: throw __FUNCTION__;
default: throw __FUNCTION__;
}
if (ConditionPassed(context, cond))
{
const u32 addr = context.read_gpr(n) + imm32;
const u32 value = vm::psv::read32(addr);
context.R_ADDR = addr;
context.R_DATA = value;
context.write_gpr(t, value);
}
}
void ARMv7_instrs::LDREXB(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type)
@ -1853,14 +1964,17 @@ void ARMv7_instrs::POP(ARMv7Context& context, const ARMv7Code code, const ARMv7_
if (ConditionPassed(context, cond))
{
u32 written = 0;
for (u16 mask = 1, i = 0; mask; mask <<= 1, i++)
{
if (reg_list & mask)
{
context.write_gpr(i, vm::psv::read32(context.SP));
context.SP += 4;
context.write_gpr(i, vm::psv::read32(context.SP + written));
written += 4;
}
}
context.SP += written;
}
}
@ -1907,14 +2021,17 @@ void ARMv7_instrs::PUSH(ARMv7Context& context, const ARMv7Code code, const ARMv7
if (ConditionPassed(context, cond))
{
u32 read = 0;
for (u16 mask = 1 << 15, i = 15; mask; mask >>= 1, i--)
{
if (reg_list & mask)
{
context.SP -= 4;
vm::psv::write32(context.SP, context.read_gpr(i));
read += 4;
vm::psv::write32(context.SP - read, context.read_gpr(i));
}
}
context.SP -= read;
}
}
@ -2692,11 +2809,35 @@ void ARMv7_instrs::STRH_REG(ARMv7Context& context, const ARMv7Code code, const A
void ARMv7_instrs::STREX(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type)
{
u32 cond = context.ITSTATE.advance();
u32 d = 0;
u32 t = 0;
u32 n = 0;
u32 imm32 = 0;
switch (type)
{
case T1:
{
d = (code.data & 0xf00) >> 8;
t = (code.data & 0xf000) >> 12;
n = (code.data & 0xf0000) >> 16;
imm32 = (code.data & 0xff) << 2;
break;
}
case A1: throw __FUNCTION__;
default: throw __FUNCTION__;
}
if (ConditionPassed(context, cond))
{
const u32 addr = context.read_gpr(n) + imm32;
const u32 value = context.read_gpr(t);
auto& sync_obj = vm::get_ref<atomic_le_t<u32>>(addr);
context.write_gpr(d, addr != context.R_ADDR || sync_obj.compare_and_swap((u32)context.R_DATA, value) != context.R_DATA);
context.R_ADDR = 0;
}
}
void ARMv7_instrs::STREXB(ARMv7Context& context, const ARMv7Code code, const ARMv7_encoding type)

View File

@ -500,6 +500,15 @@ static const ARMv7_opcode_t ARMv7_opcode_table[] =
ARMv7_OP2(0xff00, 0xbf00, T1, IT),
ARMv7_OP4(0xfff0, 0x0f00, 0xe850, 0x0f00, T1, LDREX),
ARMv7_OP4(0x0ff0, 0x0fff, 0x0190, 0x0f9f, A1, LDREX),
ARMv7_OP4(0xfff0, 0x0fff, 0xe8d0, 0x0f4f, T1, LDREXB),
ARMv7_OP4(0x0ff0, 0x0fff, 0x01d0, 0x0f9f, A1, LDREXB),
ARMv7_OP4(0xfff0, 0x00ff, 0xe8d0, 0x007f, T1, LDREXD),
ARMv7_OP4(0x0ff0, 0x0fff, 0x01b0, 0x0f9f, A1, LDREXD),
ARMv7_OP4(0xfff0, 0x0fff, 0xe8d0, 0x0f5f, T1, LDREXH),
ARMv7_OP4(0x0ff0, 0x0fff, 0x01f0, 0x0f9f, A1, LDREXH),
ARMv7_OP2(0xf800, 0xc800, T1, LDM),
ARMv7_OP4(0xffd0, 0x2000, 0xe890, 0x0000, T2, LDM),
ARMv7_OP4(0x0fd0, 0x0000, 0x0890, 0x0000, A1, LDM),
@ -554,15 +563,6 @@ static const ARMv7_opcode_t ARMv7_opcode_table[] =
ARMv7_OP4(0xfff0, 0x0fc0, 0xf930, 0x0000, T2, LDRSH_REG),
ARMv7_OP4(0x0e50, 0x0ff0, 0x0010, 0x00f0, A1, LDRSH_REG),
ARMv7_OP4(0xfff0, 0x0f00, 0xe850, 0x0f00, T1, LDREX),
ARMv7_OP4(0x0ff0, 0x0fff, 0x0190, 0x0f9f, A1, LDREX),
ARMv7_OP4(0xfff0, 0x0fff, 0xe8d0, 0x0f4f, T1, LDREXB),
ARMv7_OP4(0x0ff0, 0x0fff, 0x01d0, 0x0f9f, A1, LDREXB),
ARMv7_OP4(0xfff0, 0x00ff, 0xe8d0, 0x007f, T1, LDREXD),
ARMv7_OP4(0x0ff0, 0x0fff, 0x01b0, 0x0f9f, A1, LDREXD),
ARMv7_OP4(0xfff0, 0x0fff, 0xe8d0, 0x0f5f, T1, LDREXH),
ARMv7_OP4(0x0ff0, 0x0fff, 0x01f0, 0x0f9f, A1, LDREXH),
ARMv7_OP2(0xf800, 0x0000, T1, LSL_IMM),
ARMv7_OP4(0xffef, 0x8030, 0xea4f, 0x0000, T2, LSL_IMM),
ARMv7_OP4(0x0fef, 0x0070, 0x01a0, 0x0000, A1, LSL_IMM),
@ -773,6 +773,15 @@ static const ARMv7_opcode_t ARMv7_opcode_table[] =
ARMv7_OP4(0xfff0, 0xf0f0, 0xfac0, 0xf000, T1, SSUB8),
ARMv7_OP4(0x0ff0, 0x0ff0, 0x0610, 0x0ff0, A1, SSUB8),
ARMv7_OP4(0xfff0, 0x0000, 0xe840, 0x0000, T1, STREX),
ARMv7_OP4(0x0ff0, 0x0ff0, 0x0180, 0x0f90, A1, STREX),
ARMv7_OP4(0xfff0, 0x0ff0, 0xe8c0, 0x0f40, T1, STREXB),
ARMv7_OP4(0x0ff0, 0x0ff0, 0x01c0, 0x0f90, A1, STREXB),
ARMv7_OP4(0xfff0, 0x00f0, 0xe8c0, 0x0070, T1, STREXD),
ARMv7_OP4(0x0ff0, 0x0ff0, 0x01a0, 0x0f90, A1, STREXD),
ARMv7_OP4(0xfff0, 0x0ff0, 0xe8c0, 0x0f50, T1, STREXH),
ARMv7_OP4(0x0ff0, 0x0ff0, 0x01e0, 0x0f90, A1, STREXH),
ARMv7_OP2(0xf800, 0xc000, T1, STM),
ARMv7_OP4(0xffd0, 0xa000, 0xe880, 0x0000, T2, STM),
ARMv7_OP4(0x0fd0, 0x0000, 0x0880, 0x0000, A1, STM),
@ -810,15 +819,6 @@ static const ARMv7_opcode_t ARMv7_opcode_table[] =
ARMv7_OP4(0xfff0, 0x0fc0, 0xf820, 0x0000, T2, STRH_REG),
ARMv7_OP4(0x0e50, 0x0ff0, 0x0000, 0x00b0, A1, STRH_REG),
ARMv7_OP4(0xfff0, 0x0000, 0xe840, 0x0000, T1, STREX),
ARMv7_OP4(0x0ff0, 0x0ff0, 0x0180, 0x0f90, A1, STREX),
ARMv7_OP4(0xfff0, 0x0ff0, 0xe8c0, 0x0f40, T1, STREXB),
ARMv7_OP4(0x0ff0, 0x0ff0, 0x01c0, 0x0f90, A1, STREXB),
ARMv7_OP4(0xfff0, 0x00f0, 0xe8c0, 0x0070, T1, STREXD),
ARMv7_OP4(0x0ff0, 0x0ff0, 0x01a0, 0x0f90, A1, STREXD),
ARMv7_OP4(0xfff0, 0x0ff0, 0xe8c0, 0x0f50, T1, STREXH),
ARMv7_OP4(0x0ff0, 0x0ff0, 0x01e0, 0x0f90, A1, STREXH),
ARMv7_OP2(0xff80, 0xb080, T1, SUB_SPI),
ARMv7_OP4(0xfbef, 0x8000, 0xf1ad, 0x0000, T2, SUB_SPI),
ARMv7_OP4(0xfbff, 0x8000, 0xf2ad, 0x0000, T3, SUB_SPI),

View File

@ -87,7 +87,7 @@ struct SceKernelSystemInfo
#pragma pack(pop)
s32 sceKernelCreateThread(
u32 sceKernelCreateThread(
vm::psv::ptr<const char> pName,
vm::psv::ptr<SceKernelThreadEntry> entry,
s32 initPriority,
@ -101,24 +101,21 @@ s32 sceKernelCreateThread(
ARMv7Thread& new_thread = static_cast<ARMv7Thread&>(Emu.GetCPU().AddThread(CPU_THREAD_ARMv7));
u32 id = new_thread.GetId();
const auto id = new_thread.GetId();
new_thread.SetEntry(entry.addr() ^ 1);
new_thread.SetPrio(initPriority);
new_thread.SetStackSize(stackSize);
new_thread.SetName(pName.get_ptr());
sceLibKernel.Error("*** New ARMv7 Thread [%s] (entry=0x%x)^1: id = %d", pName.get_ptr(), entry, id);
sceLibKernel.Error("*** New ARMv7 Thread [%s] (entry=0x%x)^1: id -> 0x%x", pName.get_ptr(), entry, id);
new_thread.Run();
Emu.Pause();
return id;
}
s32 sceKernelStartThread(s32 threadId, u32 argSize, vm::psv::ptr<const void> pArgBlock)
s32 sceKernelStartThread(u32 threadId, u32 argSize, vm::psv::ptr<const void> pArgBlock)
{
sceLibKernel.Error("sceKernelStartThread(threadId=%d, argSize=%d, pArgBlock=0x%x)", threadId, argSize, pArgBlock);
sceLibKernel.Error("sceKernelStartThread(threadId=0x%x, argSize=0x%x, pArgBlock=0x%x)", threadId, argSize, pArgBlock);
std::shared_ptr<CPUThread> t = Emu.GetCPU().GetThread(threadId);
@ -134,8 +131,8 @@ s32 sceKernelStartThread(s32 threadId, u32 argSize, vm::psv::ptr<const void> pAr
memcpy(vm::get_ptr<void>(pos), pArgBlock.get_ptr(), argSize);
// set SceKernelThreadEntry function arguments
thread.context.write_gpr(0, argSize);
thread.context.write_gpr(1, pos);
thread.context.GPR[0] = argSize;
thread.context.GPR[1] = pos;
thread.Exec();
return SCE_OK;
@ -151,9 +148,9 @@ s32 sceKernelExitThread(ARMv7Context& context, s32 exitStatus)
return SCE_OK;
}
s32 sceKernelDeleteThread(s32 threadId)
s32 sceKernelDeleteThread(u32 threadId)
{
sceLibKernel.Todo("sceKernelDeleteThread(threadId=%d)", threadId);
sceLibKernel.Todo("sceKernelDeleteThread(threadId=0x%x)", threadId);
return SCE_OK;
}
@ -165,21 +162,21 @@ s32 sceKernelExitDeleteThread(s32 exitStatus)
return SCE_OK;
}
s32 sceKernelChangeThreadCpuAffinityMask(s32 threadId, s32 cpuAffinityMask)
s32 sceKernelChangeThreadCpuAffinityMask(u32 threadId, s32 cpuAffinityMask)
{
sceLibKernel.Todo("sceKernelChangeThreadCpuAffinityMask(threadId=%d, cpuAffinityMask=0x%x)", threadId, cpuAffinityMask);
sceLibKernel.Todo("sceKernelChangeThreadCpuAffinityMask(threadId=0x%x, cpuAffinityMask=0x%x)", threadId, cpuAffinityMask);
return SCE_OK;
}
s32 sceKernelGetThreadCpuAffinityMask(s32 threadId)
s32 sceKernelGetThreadCpuAffinityMask(u32 threadId)
{
sceLibKernel.Todo("sceKernelGetThreadCpuAffinityMask(threadId=0x%x)", threadId);
return SCE_OK;
}
s32 sceKernelChangeThreadPriority(s32 threadId, s32 priority)
s32 sceKernelChangeThreadPriority(u32 threadId, s32 priority)
{
sceLibKernel.Todo("sceKernelChangeThreadPriority(threadId=0x%x, priority=%d)", threadId, priority);
@ -193,11 +190,11 @@ s32 sceKernelGetThreadCurrentPriority()
return SCE_OK;
}
s32 sceKernelGetThreadId()
u32 sceKernelGetThreadId(ARMv7Context& context)
{
sceLibKernel.Todo("sceKernelGetThreadId()");
sceLibKernel.Log("sceKernelGetThreadId()");
return SCE_OK;
return context.thread.GetId();
}
s32 sceKernelChangeCurrentThreadAttr(u32 clearAttr, u32 setAttr)
@ -207,9 +204,9 @@ s32 sceKernelChangeCurrentThreadAttr(u32 clearAttr, u32 setAttr)
return SCE_OK;
}
s32 sceKernelGetThreadExitStatus(s32 threadId, vm::psv::ptr<s32> pExitStatus)
s32 sceKernelGetThreadExitStatus(u32 threadId, vm::psv::ptr<s32> pExitStatus)
{
sceLibKernel.Todo("sceKernelGetThreadExitStatus(threadId=%d, pExitStatus=0x%x)", threadId, pExitStatus);
sceLibKernel.Todo("sceKernelGetThreadExitStatus(threadId=0x%x, pExitStatus=0x%x)", threadId, pExitStatus);
return SCE_OK;
}
@ -228,9 +225,9 @@ s32 sceKernelCheckWaitableStatus()
return SCE_OK;
}
s32 sceKernelGetThreadInfo(s32 threadId, vm::psv::ptr<SceKernelThreadInfo> pInfo)
s32 sceKernelGetThreadInfo(u32 threadId, vm::psv::ptr<SceKernelThreadInfo> pInfo)
{
sceLibKernel.Todo("sceKernelGetThreadInfo(threadId=%d, pInfo=0x%x)", threadId, pInfo);
sceLibKernel.Todo("sceKernelGetThreadInfo(threadId=0x%x, pInfo=0x%x)", threadId, pInfo);
return SCE_OK;
}
@ -251,7 +248,7 @@ s32 sceKernelGetSystemInfo(vm::psv::ptr<SceKernelSystemInfo> pInfo)
s32 sceKernelGetThreadmgrUIDClass(s32 uid)
{
sceLibKernel.Todo("sceKernelGetThreadmgrUIDClass(uid=%d)", uid);
sceLibKernel.Todo("sceKernelGetThreadmgrUIDClass(uid=0x%x)", uid);
return SCE_OK;
}
@ -284,16 +281,44 @@ s32 sceKernelDelayThreadCB(u32 usec)
return SCE_OK;
}
s32 sceKernelWaitThreadEnd(s32 threadId, vm::psv::ptr<s32> pExitStatus, vm::psv::ptr<u32> pTimeout)
s32 sceKernelWaitThreadEnd(u32 threadId, vm::psv::ptr<s32> pExitStatus, vm::psv::ptr<u32> pTimeout)
{
sceLibKernel.Todo("sceKernelWaitThreadEnd(threadId=%d, pExitStatus=0x%x, pTimeout=0x%x)", threadId, pExitStatus, pTimeout);
sceLibKernel.Error("sceKernelWaitThreadEnd(threadId=0x%x, pExitStatus=0x%x, pTimeout=0x%x)", threadId, pExitStatus, pTimeout);
std::shared_ptr<CPUThread> t = Emu.GetCPU().GetThread(threadId);
if (!t || t->GetType() != CPU_THREAD_ARMv7)
{
RETURN_ERROR(SCE_KERNEL_ERROR_INVALID_UID);
}
ARMv7Thread& thread = static_cast<ARMv7Thread&>(*t);
if (pTimeout)
{
}
while (thread.IsAlive())
{
if (Emu.IsStopped())
{
sceLibKernel.Warning("sceKernelWaitThreadEnd(0x%x) aborted", threadId);
return SCE_OK;
}
std::this_thread::sleep_for(std::chrono::milliseconds(1)); // hack
}
if (pExitStatus)
{
*pExitStatus = thread.context.GPR[0];
}
return SCE_OK;
}
s32 sceKernelWaitThreadEndCB(s32 threadId, vm::psv::ptr<s32> pExitStatus, vm::psv::ptr<u32> pTimeout)
s32 sceKernelWaitThreadEndCB(u32 threadId, vm::psv::ptr<s32> pExitStatus, vm::psv::ptr<u32> pTimeout)
{
sceLibKernel.Todo("sceKernelWaitThreadEndCB(threadId=%d, pExitStatus=0x%x, pTimeout=0x%x)", threadId, pExitStatus, pTimeout);
sceLibKernel.Todo("sceKernelWaitThreadEndCB(threadId=0x%x, pExitStatus=0x%x, pTimeout=0x%x)", threadId, pExitStatus, pTimeout);
return SCE_OK;
}

View File

@ -26,11 +26,67 @@ namespace sce_libc_func
});
}
void printf(vm::psv::ptr<const char> fmt) // va_args...
void printf(ARMv7Context& context, vm::psv::ptr<const char> fmt) // va_args...
{
sceLibc.Error("printf(fmt=0x%x)", fmt);
LOG_NOTICE(TTY, "%s", fmt.get_ptr());
sceLibc.Notice("*** *fmt = '%s'", fmt.get_ptr());
std::string result;
u32 g_count = 1;
u32 f_count = 0;
u32 v_count = 0;
for (char c = *fmt++; c; c = *fmt++)
{
switch (c)
{
case '%':
{
const auto start = fmt - 1;
const bool <EFBFBD> = *fmt == '#' ? fmt++, true : false;
switch (*fmt++)
{
case '%':
{
result += '%';
continue;
}
case 'd':
case 'i':
{
// signed decimal
const s64 value = context.get_next_gpr_arg(g_count, f_count, v_count);
result += fmt::to_sdec(value);
continue;
}
case 'x':
{
// hexadecimal
const u64 value = context.get_next_gpr_arg(g_count, f_count, v_count);
if (<EFBFBD> && value)
{
result += "0x";
}
result += fmt::to_hex(value);
continue;
}
default:
{
throw fmt::Format("printf(): unknown formatting: '%s'", start.get_ptr());
}
}
}
}
result += c;
}
LOG_NOTICE(TTY, result);
}
void __cxa_set_dso_handle_main()