[cpu] Add guest thread continuation

This commit is contained in:
ParantezTech
2026-06-21 23:18:29 +03:00
parent 08b315b5fc
commit 2a52ccfe6a
6 changed files with 1458 additions and 187 deletions
+15 -4
View File
@@ -22,6 +22,7 @@ public sealed class CpuDispatcher : ICpuDispatcher, IDisposable
private const ulong StackSize = 0x0020_0000UL; private const ulong StackSize = 0x0020_0000UL;
private const ulong TlsBaseAddress = 0x7FFE_0000_0000UL; private const ulong TlsBaseAddress = 0x7FFE_0000_0000UL;
private const ulong TlsSize = 0x0001_0000UL; private const ulong TlsSize = 0x0001_0000UL;
private const ulong TlsPrefixSize = 0x0000_1000UL;
private const ulong BootstrapStubBaseAddress = 0x7FFD_F000_0000UL; private const ulong BootstrapStubBaseAddress = 0x7FFD_F000_0000UL;
private const ulong BootstrapPayloadBaseAddress = 0x7FFD_E000_0000UL; private const ulong BootstrapPayloadBaseAddress = 0x7FFD_E000_0000UL;
private const ulong DynlibFallbackStubBaseAddress = 0x7FFD_D000_0000UL; private const ulong DynlibFallbackStubBaseAddress = 0x7FFD_D000_0000UL;
@@ -342,11 +343,12 @@ public sealed class CpuDispatcher : ICpuDispatcher, IDisposable
for (var i = 0; i < 32; i++) for (var i = 0; i < 32; i++)
{ {
var candidateBase = TlsBaseAddress - ((ulong)i * tlsStride); var candidateBase = TlsBaseAddress - ((ulong)i * tlsStride);
var mappedBase = candidateBase - TlsPrefixSize;
try try
{ {
_virtualMemory.Map( _virtualMemory.Map(
candidateBase, mappedBase,
TlsSize, TlsSize + TlsPrefixSize,
fileOffset: 0, fileOffset: 0,
fileData: ReadOnlySpan<byte>.Empty, fileData: ReadOnlySpan<byte>.Empty,
ProgramHeaderFlags.Read | ProgramHeaderFlags.Write); ProgramHeaderFlags.Read | ProgramHeaderFlags.Write);
@@ -363,9 +365,11 @@ public sealed class CpuDispatcher : ICpuDispatcher, IDisposable
private static bool InitializeTls(CpuContext context, ulong tlsBase) private static bool InitializeTls(CpuContext context, ulong tlsBase)
{ {
return context.TryWriteUInt64(tlsBase + 0x00, tlsBase) && return context.TryWriteUInt64(tlsBase - 0xF0, 0) &&
context.TryWriteUInt64(tlsBase + 0x00, tlsBase) &&
context.TryWriteUInt64(tlsBase + 0x10, tlsBase) && context.TryWriteUInt64(tlsBase + 0x10, tlsBase) &&
context.TryWriteUInt64(tlsBase + 0x28, 0xC0DEC0DECAFEBABEUL); context.TryWriteUInt64(tlsBase + 0x28, 0xC0DEC0DECAFEBABEUL) &&
context.TryWriteUInt64(tlsBase + 0x60, tlsBase);
} }
private static bool InitializeGuestFrameChainSentinel(CpuContext context) private static bool InitializeGuestFrameChainSentinel(CpuContext context)
@@ -420,6 +424,13 @@ public sealed class CpuDispatcher : ICpuDispatcher, IDisposable
return false; return false;
} }
var entryStackPointer = entryParamsAddress - sizeof(ulong);
if (!context.TryWriteUInt64(entryStackPointer, 0))
{
return false;
}
context[CpuRegister.Rsp] = entryStackPointer;
context[CpuRegister.Rdi] = entryParamsAddress; context[CpuRegister.Rdi] = entryParamsAddress;
context[CpuRegister.Rsi] = programExitHandlerAddress; context[CpuRegister.Rsi] = programExitHandlerAddress;
context[CpuRegister.Rdx] = 0; context[CpuRegister.Rdx] = 0;
@@ -97,12 +97,13 @@ public sealed partial class DirectExecutionBackend
private void ProbeReturnRip(ulong returnRip, long dispatchIndex) private void ProbeReturnRip(ulong returnRip, long dispatchIndex)
{ {
if (_cpuContext == null || returnRip == 0) var cpuContext = ActiveCpuContext;
if (cpuContext == null || returnRip == 0)
{ {
return; return;
} }
Span<byte> destination = stackalloc byte[128]; Span<byte> destination = stackalloc byte[128];
if (!_cpuContext.Memory.TryRead(returnRip, destination)) if (!cpuContext.Memory.TryRead(returnRip, destination))
{ {
Console.Error.WriteLine($"[LOADER][TRACE] Import#{dispatchIndex} return-rip probe: unreadable @0x{returnRip:X16}"); Console.Error.WriteLine($"[LOADER][TRACE] Import#{dispatchIndex} return-rip probe: unreadable @0x{returnRip:X16}");
return; return;
@@ -113,7 +114,7 @@ public sealed partial class DirectExecutionBackend
{ {
int num = BitConverter.ToInt32(destination.Slice(2, 4)); int num = BitConverter.ToInt32(destination.Slice(2, 4));
ulong num2 = returnRip + 6 + (ulong)num; ulong num2 = returnRip + 6 + (ulong)num;
if (_cpuContext.TryReadUInt64(num2, out var value2)) if (cpuContext.TryReadUInt64(num2, out var value2))
{ {
Console.Error.WriteLine($"[LOADER][TRACE] Import#{dispatchIndex} return-rip slot: [0x{num2:X16}] = 0x{value2:X16}"); Console.Error.WriteLine($"[LOADER][TRACE] Import#{dispatchIndex} return-rip slot: [0x{num2:X16}] = 0x{value2:X16}");
} }
@@ -122,7 +123,7 @@ public sealed partial class DirectExecutionBackend
{ {
int num3 = BitConverter.ToInt32(destination.Slice(3, 4)); int num3 = BitConverter.ToInt32(destination.Slice(3, 4));
ulong num4 = returnRip + 7 + (ulong)num3; ulong num4 = returnRip + 7 + (ulong)num3;
if (_cpuContext.TryReadUInt64(num4, out var value3)) if (cpuContext.TryReadUInt64(num4, out var value3))
{ {
Console.Error.WriteLine($"[LOADER][TRACE] Import#{dispatchIndex} return-rip mov-slot: [0x{num4:X16}] = 0x{value3:X16}"); Console.Error.WriteLine($"[LOADER][TRACE] Import#{dispatchIndex} return-rip mov-slot: [0x{num4:X16}] = 0x{value3:X16}");
} }
@@ -134,12 +135,82 @@ public sealed partial class DirectExecutionBackend
int num5 = BitConverter.ToInt32(destination.Slice(i + 2, 4)); int num5 = BitConverter.ToInt32(destination.Slice(i + 2, 4));
ulong num6 = returnRip + (ulong)i; ulong num6 = returnRip + (ulong)i;
ulong num7 = num6 + 6 + (ulong)num5; ulong num7 = num6 + 6 + (ulong)num5;
if (_cpuContext.TryReadUInt64(num7, out var value4)) if (cpuContext.TryReadUInt64(num7, out var value4))
{ {
Console.Error.WriteLine($"[LOADER][TRACE] Import#{dispatchIndex} near-indirect @{num6:X16}: slot=0x{num7:X16} val=0x{value4:X16}"); Console.Error.WriteLine($"[LOADER][TRACE] Import#{dispatchIndex} near-indirect @{num6:X16}: slot=0x{num7:X16} val=0x{value4:X16}");
} }
} }
} }
Span<byte> targetBytes = stackalloc byte[32];
for (int i = 0; i + 5 <= destination.Length; i++)
{
if (destination[i] != 0xE8)
{
continue;
}
int rel32 = BitConverter.ToInt32(destination.Slice(i + 1, 4));
ulong callRip = returnRip + (ulong)i;
ulong target = unchecked((ulong)((long)(callRip + 5) + rel32));
Console.Error.WriteLine($"[LOADER][TRACE] Import#{dispatchIndex} near-call @{callRip:X16}: target=0x{target:X16}");
for (int importIndex = 0; importIndex < _importEntries.Length; importIndex++)
{
if (_importEntries[importIndex].Address != target)
{
continue;
}
string nid = _importEntries[importIndex].Nid;
if (_moduleManager.TryGetExport(nid, out var export))
{
Console.Error.WriteLine(
$"[LOADER][TRACE] Import#{dispatchIndex} near-call import: index={importIndex} {export.LibraryName}:{export.Name} ({nid})");
}
else
{
Console.Error.WriteLine(
$"[LOADER][TRACE] Import#{dispatchIndex} near-call import: index={importIndex} nid={nid}");
}
break;
}
if (cpuContext.Memory.TryRead(target, targetBytes))
{
Console.Error.WriteLine(
$"[LOADER][TRACE] Import#{dispatchIndex} near-call target bytes @0x{target:X16}: " +
BitConverter.ToString(targetBytes.ToArray()).Replace("-", " "));
if (targetBytes[0] == 0xFF && targetBytes[1] == 0x25)
{
int slotRel32 = BitConverter.ToInt32(targetBytes.Slice(2, 4));
ulong slot = unchecked((ulong)((long)(target + 6) + slotRel32));
if (cpuContext.TryReadUInt64(slot, out var slotTarget))
{
Console.Error.WriteLine(
$"[LOADER][TRACE] Import#{dispatchIndex} near-call PLT slot: [0x{slot:X16}] = 0x{slotTarget:X16}");
for (int importIndex = 0; importIndex < _importEntries.Length; importIndex++)
{
if (_importEntries[importIndex].Address != slotTarget)
{
continue;
}
string nid = _importEntries[importIndex].Nid;
if (_moduleManager.TryGetExport(nid, out var export))
{
Console.Error.WriteLine(
$"[LOADER][TRACE] Import#{dispatchIndex} near-call PLT import: index={importIndex} {export.LibraryName}:{export.Name} ({nid})");
}
else
{
Console.Error.WriteLine(
$"[LOADER][TRACE] Import#{dispatchIndex} near-call PLT import: index={importIndex} nid={nid}");
}
break;
}
}
}
}
}
} }
private static bool IsUnresolvedSentinel(ulong value) private static bool IsUnresolvedSentinel(ulong value)
@@ -7,6 +7,7 @@ using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using System.Reflection; using System.Reflection;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Threading;
using SharpEmu.Core.Cpu.Disasm; using SharpEmu.Core.Cpu.Disasm;
using SharpEmu.HLE; using SharpEmu.HLE;
@@ -61,7 +62,7 @@ public sealed partial class DirectExecutionBackend
{ {
if (_vectoredHandlerDepth > 0) if (_vectoredHandlerDepth > 0)
{ {
Console.Error.WriteLine("[LOADER][TRACE] Nested VEH exception; passing through."); LogNestedVectoredException(exceptionInfo);
Console.Error.Flush(); Console.Error.Flush();
return 0; return 0;
} }
@@ -84,10 +85,18 @@ public sealed partial class DirectExecutionBackend
ulong rip = ReadCtxU64(contextRecord, 248); ulong rip = ReadCtxU64(contextRecord, 248);
ulong rsp = ReadCtxU64(contextRecord, 152); ulong rsp = ReadCtxU64(contextRecord, 152);
if (exceptionCode == 3221225477u && TryHandleLazyCommittedPage(exceptionRecord)) if (exceptionCode == 3221225477u && TryHandleLazyCommittedPage(exceptionRecord, rip, rsp))
{ {
return -1; return -1;
} }
if (IsBenignHostDebugException(exceptionCode))
{
return -1;
}
if (exceptionCode == MSVC_CPP_EXCEPTION)
{
return 0;
}
switch (exceptionCode) switch (exceptionCode)
{ {
@@ -278,6 +287,37 @@ public sealed partial class DirectExecutionBackend
} }
} }
private static bool IsBenignHostDebugException(uint exceptionCode)
{
return exceptionCode is DBG_PRINTEXCEPTION_C or DBG_PRINTEXCEPTION_WIDE_C or MS_VC_THREADNAME_EXCEPTION;
}
private unsafe static void LogNestedVectoredException(void* exceptionInfo)
{
int count = Interlocked.Increment(ref _nestedVehTraceCount);
if (count > 16 && count % 128 != 0)
{
return;
}
try
{
EXCEPTION_POINTERS* pointers = (EXCEPTION_POINTERS*)exceptionInfo;
EXCEPTION_RECORD* record = pointers->ExceptionRecord;
void* contextRecord = pointers->ContextRecord;
ulong rip = contextRecord != null ? ReadCtxU64(contextRecord, 248) : 0;
ulong rsp = contextRecord != null ? ReadCtxU64(contextRecord, 152) : 0;
ulong accessType = record->NumberParameters >= 1 ? *record->ExceptionInformation : 0;
ulong target = record->NumberParameters >= 2 ? record->ExceptionInformation[1] : 0;
Console.Error.WriteLine(
$"[LOADER][TRACE] Nested VEH exception#{count}: code=0x{record->ExceptionCode:X8} ex=0x{(ulong)record->ExceptionAddress:X16} rip=0x{rip:X16} rsp=0x{rsp:X16} type={accessType} target=0x{target:X16}; passing through.");
}
catch
{
Console.Error.WriteLine($"[LOADER][TRACE] Nested VEH exception#{count}; passing through.");
}
}
private unsafe void LogAccessViolationTrace(ulong exceptionAddress, EXCEPTION_RECORD* exceptionRecord) private unsafe void LogAccessViolationTrace(ulong exceptionAddress, EXCEPTION_RECORD* exceptionRecord)
{ {
ulong accessType = exceptionRecord->NumberParameters >= 1 ? (*exceptionRecord->ExceptionInformation) : 0; ulong accessType = exceptionRecord->NumberParameters >= 1 ? (*exceptionRecord->ExceptionInformation) : 0;
@@ -828,7 +868,7 @@ public sealed partial class DirectExecutionBackend
return true; return true;
} }
private unsafe static bool TryHandleLazyCommittedPage(EXCEPTION_RECORD* exceptionRecord) private unsafe bool TryHandleLazyCommittedPage(EXCEPTION_RECORD* exceptionRecord, ulong rip, ulong rsp)
{ {
if (exceptionRecord->NumberParameters < 2) if (exceptionRecord->NumberParameters < 2)
{ {
@@ -845,6 +885,10 @@ public sealed partial class DirectExecutionBackend
{ {
return false; return false;
} }
if (!IsGuestOwnedLazyCommitAddress(faultAddress, out var owner))
{
return false;
}
if (VirtualQuery((void*)faultAddress, out var mbi, (nuint)sizeof(MEMORY_BASIC_INFORMATION64)) == 0) if (VirtualQuery((void*)faultAddress, out var mbi, (nuint)sizeof(MEMORY_BASIC_INFORMATION64)) == 0)
{ {
return false; return false;
@@ -852,7 +896,7 @@ public sealed partial class DirectExecutionBackend
ulong pageBase = faultAddress & 0xFFFFFFFFFFFFF000uL; ulong pageBase = faultAddress & 0xFFFFFFFFFFFFF000uL;
uint commitProtect = ResolveLazyCommitProtection(accessType, mbi.AllocationProtect); uint commitProtect = ResolveLazyCommitProtection(accessType, mbi.AllocationProtect);
Console.Error.WriteLine($"[LOADER][TRACE] lazy-query: fault=0x{faultAddress:X16} state=0x{mbi.State:X08} base=0x{mbi.BaseAddress:X16} size=0x{mbi.RegionSize:X16} alloc=0x{mbi.AllocationProtect:X08} prot=0x{mbi.Protect:X08}"); Console.Error.WriteLine($"[LOADER][TRACE] lazy-query: fault=0x{faultAddress:X16} owner={owner} rip=0x{rip:X16} rsp=0x{rsp:X16} state=0x{mbi.State:X08} base=0x{mbi.BaseAddress:X16} size=0x{mbi.RegionSize:X16} alloc=0x{mbi.AllocationProtect:X08} prot=0x{mbi.Protect:X08}");
bool committed = false; bool committed = false;
ulong committedBase = 0; ulong committedBase = 0;
@@ -3,6 +3,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics;
using System.Linq; using System.Linq;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Threading; using System.Threading;
@@ -74,7 +75,8 @@ public sealed partial class DirectExecutionBackend
{ {
long num = Interlocked.Increment(ref _importDispatchCount); long num = Interlocked.Increment(ref _importDispatchCount);
MarkExecutionProgress(); MarkExecutionProgress();
if (_cpuContext == null) var cpuContext = ActiveCpuContext;
if (cpuContext == null)
{ {
LastError = "Import dispatch called without active CPU context"; LastError = "Import dispatch called without active CPU context";
return 18446744071562199298uL; return 18446744071562199298uL;
@@ -91,32 +93,32 @@ public sealed partial class DirectExecutionBackend
Console.Error.WriteLine($"[LOADER][TRACE] Raw sentinel recoveries: {num2} (last import index={importIndex})"); Console.Error.WriteLine($"[LOADER][TRACE] Raw sentinel recoveries: {num2} (last import index={importIndex})");
_lastReportedRawSentinelRecoveries = num2; _lastReportedRawSentinelRecoveries = num2;
} }
_cpuContext.Rip = importStubEntry.Address; cpuContext.Rip = importStubEntry.Address;
_cpuContext[CpuRegister.Rdi] = *(ulong*)argPackPtr; cpuContext[CpuRegister.Rdi] = *(ulong*)argPackPtr;
_cpuContext[CpuRegister.Rsi] = *(ulong*)(argPackPtr + 8); cpuContext[CpuRegister.Rsi] = *(ulong*)(argPackPtr + 8);
_cpuContext[CpuRegister.Rdx] = *(ulong*)(argPackPtr + 16); cpuContext[CpuRegister.Rdx] = *(ulong*)(argPackPtr + 16);
_cpuContext[CpuRegister.Rcx] = *(ulong*)(argPackPtr + 24); cpuContext[CpuRegister.Rcx] = *(ulong*)(argPackPtr + 24);
_cpuContext[CpuRegister.R8] = *(ulong*)(argPackPtr + 32); cpuContext[CpuRegister.R8] = *(ulong*)(argPackPtr + 32);
_cpuContext[CpuRegister.R9] = *(ulong*)(argPackPtr + 40); cpuContext[CpuRegister.R9] = *(ulong*)(argPackPtr + 40);
_cpuContext[CpuRegister.Rbx] = *(ulong*)(argPackPtr + 48); cpuContext[CpuRegister.Rbx] = *(ulong*)(argPackPtr + 48);
_cpuContext[CpuRegister.Rbp] = *(ulong*)(argPackPtr + 56); cpuContext[CpuRegister.Rbp] = *(ulong*)(argPackPtr + 56);
_cpuContext[CpuRegister.R12] = *(ulong*)(argPackPtr + 64); cpuContext[CpuRegister.R12] = *(ulong*)(argPackPtr + 64);
_cpuContext[CpuRegister.R13] = *(ulong*)(argPackPtr + 72); cpuContext[CpuRegister.R13] = *(ulong*)(argPackPtr + 72);
_cpuContext[CpuRegister.R14] = *(ulong*)(argPackPtr + 80); cpuContext[CpuRegister.R14] = *(ulong*)(argPackPtr + 80);
_cpuContext[CpuRegister.R15] = *(ulong*)(argPackPtr + 88); cpuContext[CpuRegister.R15] = *(ulong*)(argPackPtr + 88);
_cpuContext[CpuRegister.Rsp] = (ulong)argPackPtr + 96uL; cpuContext[CpuRegister.Rsp] = (ulong)argPackPtr + 96uL;
ulong value = _cpuContext[CpuRegister.Rdi]; ulong value = cpuContext[CpuRegister.Rdi];
ulong value2 = _cpuContext[CpuRegister.Rsi]; ulong value2 = cpuContext[CpuRegister.Rsi];
ulong num3 = _cpuContext[CpuRegister.Rdx]; ulong num3 = cpuContext[CpuRegister.Rdx];
ulong num4 = _cpuContext[CpuRegister.Rcx]; ulong num4 = cpuContext[CpuRegister.Rcx];
ulong num5 = _cpuContext[CpuRegister.R8]; ulong num5 = cpuContext[CpuRegister.R8];
ulong num6 = _cpuContext[CpuRegister.R9]; ulong num6 = cpuContext[CpuRegister.R9];
ulong value3 = _cpuContext[CpuRegister.Rbx]; ulong value3 = cpuContext[CpuRegister.Rbx];
ulong value4 = _cpuContext[CpuRegister.Rbp]; ulong value4 = cpuContext[CpuRegister.Rbp];
ulong value5 = _cpuContext[CpuRegister.R12]; ulong value5 = cpuContext[CpuRegister.R12];
ulong value6 = _cpuContext[CpuRegister.R13]; ulong value6 = cpuContext[CpuRegister.R13];
ulong value7 = _cpuContext[CpuRegister.R14]; ulong value7 = cpuContext[CpuRegister.R14];
ulong value8 = _cpuContext[CpuRegister.R15]; ulong value8 = cpuContext[CpuRegister.R15];
ulong num7 = *(ulong*)(argPackPtr + 96); ulong num7 = *(ulong*)(argPackPtr + 96);
if (!IsLikelyReturnAddress(num7)) if (!IsLikelyReturnAddress(num7))
{ {
@@ -133,6 +135,13 @@ public sealed partial class DirectExecutionBackend
} }
} }
TrackDistinctImportNid(importStubEntry.Nid); TrackDistinctImportNid(importStubEntry.Nid);
var probeImportReturn = Environment.GetEnvironmentVariable("SHARPEMU_PROBE_IMPORT_RET");
if (!string.IsNullOrWhiteSpace(probeImportReturn) &&
(string.Equals(probeImportReturn, "*", StringComparison.Ordinal) ||
string.Equals(probeImportReturn, importStubEntry.Nid, StringComparison.Ordinal)))
{
ProbeReturnRip(num7, num);
}
TrackStrlenPrelude(importStubEntry.Nid, num, num7); TrackStrlenPrelude(importStubEntry.Nid, num, num7);
bool logBootstrap = string.Equals(Environment.GetEnvironmentVariable("SHARPEMU_LOG_BOOTSTRAP"), "1", StringComparison.Ordinal); bool logBootstrap = string.Equals(Environment.GetEnvironmentVariable("SHARPEMU_LOG_BOOTSTRAP"), "1", StringComparison.Ordinal);
if (logBootstrap && string.Equals(importStubEntry.Nid, RuntimeStubNids.BootstrapBridge, StringComparison.Ordinal)) if (logBootstrap && string.Equals(importStubEntry.Nid, RuntimeStubNids.BootstrapBridge, StringComparison.Ordinal))
@@ -145,9 +154,9 @@ public sealed partial class DirectExecutionBackend
Console.Error.WriteLine( Console.Error.WriteLine(
$"[LOADER][TRACE] bootstrap_call#{num}: op=0x{value:X16} sym_ptr=0x{value2:X16} sym='{symbolText}' out_ptr=0x{num3:X16} ret=0x{num7:X16}"); $"[LOADER][TRACE] bootstrap_call#{num}: op=0x{value:X16} sym_ptr=0x{value2:X16} sym='{symbolText}' out_ptr=0x{num3:X16} ret=0x{num7:X16}");
} }
if (!_forcedGuestExit && ShouldForceGuestExitOnImportLoop(importStubEntry.Nid, num7, num, value, value2) && TryForceGuestExitToHostStub(argPackPtr, num, num7, importStubEntry.Nid)) if (!ActiveForcedGuestExit && ShouldForceGuestExitOnImportLoop(importStubEntry.Nid, num7, num, value, value2) && TryForceGuestExitToHostStub(argPackPtr, num, num7, importStubEntry.Nid))
{ {
_cpuContext[CpuRegister.Rax] = 1uL; cpuContext[CpuRegister.Rax] = 1uL;
return 1uL; return 1uL;
} }
bool flag0 = ShouldSuppressStrlenTrace(importStubEntry.Nid); bool flag0 = ShouldSuppressStrlenTrace(importStubEntry.Nid);
@@ -209,33 +218,41 @@ public sealed partial class DirectExecutionBackend
} }
if (!flag0) if (!flag0)
{ {
RecordRecentImportTrace($"#{num} nid={importStubEntry.Nid} ret=0x{num7:X16} rdi=0x{_cpuContext[CpuRegister.Rdi]:X16} rsi=0x{_cpuContext[CpuRegister.Rsi]:X16} rdx=0x{_cpuContext[CpuRegister.Rdx]:X16}"); RecordRecentImportTrace($"#{num} nid={importStubEntry.Nid} ret=0x{num7:X16} rdi=0x{cpuContext[CpuRegister.Rdi]:X16} rsi=0x{cpuContext[CpuRegister.Rsi]:X16} rdx=0x{cpuContext[CpuRegister.Rdx]:X16}");
} }
if (importStubEntry.Nid == "8zTFvBIAIN8" && num <= 256) if (importStubEntry.Nid == "8zTFvBIAIN8" && num <= 256)
{ {
Console.Error.WriteLine($"[LOADER][TRACE] memset#{num}: dst=0x{_cpuContext[CpuRegister.Rdi]:X16} val=0x{_cpuContext[CpuRegister.Rsi] & 0xFF:X2} len=0x{_cpuContext[CpuRegister.Rdx]:X16} ret=0x{num7:X16}"); Console.Error.WriteLine($"[LOADER][TRACE] memset#{num}: dst=0x{cpuContext[CpuRegister.Rdi]:X16} val=0x{cpuContext[CpuRegister.Rsi] & 0xFF:X2} len=0x{cpuContext[CpuRegister.Rdx]:X16} ret=0x{num7:X16}");
} }
if (importStubEntry.Nid == "tsvEmnenz48" && num <= 64) if (importStubEntry.Nid == "tsvEmnenz48" && num <= 64)
{ {
Console.Error.WriteLine($"[LOADER][TRACE] __cxa_atexit#{num}: func=0x{_cpuContext[CpuRegister.Rdi]:X16} arg=0x{_cpuContext[CpuRegister.Rsi]:X16} dso=0x{_cpuContext[CpuRegister.Rdx]:X16} ret=0x{num7:X16}"); Console.Error.WriteLine($"[LOADER][TRACE] __cxa_atexit#{num}: func=0x{cpuContext[CpuRegister.Rdi]:X16} arg=0x{cpuContext[CpuRegister.Rsi]:X16} dso=0x{cpuContext[CpuRegister.Rdx]:X16} ret=0x{num7:X16}");
} }
if (importStubEntry.Nid == "bzQExy189ZI" || importStubEntry.Nid == "8G2LB+A3rzg") if (importStubEntry.Nid == "bzQExy189ZI" || importStubEntry.Nid == "8G2LB+A3rzg")
{ {
Console.Error.WriteLine($"[LOADER][TRACE] {importStubEntry.Nid}#{num}: rdi=0x{_cpuContext[CpuRegister.Rdi]:X16} rsi=0x{_cpuContext[CpuRegister.Rsi]:X16} rdx=0x{_cpuContext[CpuRegister.Rdx]:X16} ret=0x{num7:X16}"); Console.Error.WriteLine($"[LOADER][TRACE] {importStubEntry.Nid}#{num}: rdi=0x{cpuContext[CpuRegister.Rdi]:X16} rsi=0x{cpuContext[CpuRegister.Rsi]:X16} rdx=0x{cpuContext[CpuRegister.Rdx]:X16} ret=0x{num7:X16}");
} }
if (flag || flag2 || flag3) if (flag6 || flag || flag2 || flag3)
{ {
Console.Error.WriteLine($"[LOADER][TRACE] ImportCtx#{num}: nid={importStubEntry.Nid} ret=0x{num7:X16} rdi=0x{_cpuContext[CpuRegister.Rdi]:X16} rsi=0x{_cpuContext[CpuRegister.Rsi]:X16} rdx=0x{_cpuContext[CpuRegister.Rdx]:X16} rcx=0x{_cpuContext[CpuRegister.Rcx]:X16}"); Console.Error.WriteLine($"[LOADER][TRACE] ImportCtx#{num}: nid={importStubEntry.Nid} ret=0x{num7:X16} rdi=0x{cpuContext[CpuRegister.Rdi]:X16} rsi=0x{cpuContext[CpuRegister.Rsi]:X16} rdx=0x{cpuContext[CpuRegister.Rdx]:X16} rcx=0x{cpuContext[CpuRegister.Rcx]:X16}");
Console.Error.WriteLine($"[LOADER][TRACE] ImportNV#{num}: rbx=0x{value3:X16} rbp=0x{value4:X16} r12=0x{value5:X16} r13=0x{value6:X16} r14=0x{value7:X16} r15=0x{value8:X16}"); Console.Error.WriteLine($"[LOADER][TRACE] ImportNV#{num}: rbx=0x{value3:X16} rbp=0x{value4:X16} r12=0x{value5:X16} r13=0x{value6:X16} r14=0x{value7:X16} r15=0x{value8:X16}");
if (flag3) if (flag3)
{ {
ulong num9 = _cpuContext[CpuRegister.Rsp]; ulong num9 = cpuContext[CpuRegister.Rsp];
if (_cpuContext.TryReadUInt64(num9, out var value9) && _cpuContext.TryReadUInt64(num9 + 8, out var value10) && _cpuContext.TryReadUInt64(num9 + 16, out var value11) && _cpuContext.TryReadUInt64(num9 + 24, out var value12) && _cpuContext.TryReadUInt64(num9 + 32, out var value13) && _cpuContext.TryReadUInt64(num9 + 40, out var value14) && _cpuContext.TryReadUInt64(num9 + 48, out var value15) && _cpuContext.TryReadUInt64(num9 + 56, out var value16) && _cpuContext.TryReadUInt64(num9 + 64, out var value17)) if (cpuContext.TryReadUInt64(num9, out var value9) && cpuContext.TryReadUInt64(num9 + 8, out var value10) && cpuContext.TryReadUInt64(num9 + 16, out var value11) && cpuContext.TryReadUInt64(num9 + 24, out var value12) && cpuContext.TryReadUInt64(num9 + 32, out var value13) && cpuContext.TryReadUInt64(num9 + 40, out var value14) && cpuContext.TryReadUInt64(num9 + 48, out var value15) && cpuContext.TryReadUInt64(num9 + 56, out var value16) && cpuContext.TryReadUInt64(num9 + 64, out var value17))
{ {
Console.Error.WriteLine($"[LOADER][TRACE] ImportStackHead#{num}: rsp=0x{num9:X16} [0]=0x{value9:X16} [20]=0x{value13:X16} [40]=0x{value17:X16}"); Console.Error.WriteLine($"[LOADER][TRACE] ImportStackHead#{num}: rsp=0x{num9:X16} [0]=0x{value9:X16} [20]=0x{value13:X16} [40]=0x{value17:X16}");
Console.Error.WriteLine($"[LOADER][TRACE] ImportStack#{num}: rsp=0x{num9:X16} [0]=0x{value9:X16} [8]=0x{value10:X16} [10]=0x{value11:X16} [18]=0x{value12:X16} [20]=0x{value13:X16} [28]=0x{value14:X16} [30]=0x{value15:X16} [38]=0x{value16:X16} [40]=0x{value17:X16}"); Console.Error.WriteLine($"[LOADER][TRACE] ImportStack#{num}: rsp=0x{num9:X16} [0]=0x{value9:X16} [8]=0x{value10:X16} [10]=0x{value11:X16} [18]=0x{value12:X16} [20]=0x{value13:X16} [28]=0x{value14:X16} [30]=0x{value15:X16} [38]=0x{value16:X16} [40]=0x{value17:X16}");
} }
} }
if (flag6 && string.Equals(Environment.GetEnvironmentVariable("SHARPEMU_LOG_IMPORT_FRAMES"), "1", StringComparison.Ordinal))
{
TraceImportFrameChain(cpuContext, num);
}
if (flag6 && string.Equals(Environment.GetEnvironmentVariable("SHARPEMU_LOG_IMPORT_RECENT"), "1", StringComparison.Ordinal))
{
DumpRecentImportTrace();
}
if (flag3) if (flag3)
{ {
Console.Error.Flush(); Console.Error.Flush();
@@ -243,6 +260,16 @@ public sealed partial class DirectExecutionBackend
} }
if (importStubEntry.Nid == "Ou3iL1abvng") if (importStubEntry.Nid == "Ou3iL1abvng")
{ {
if (string.Equals(Environment.GetEnvironmentVariable("SHARPEMU_LOG_STACK_CHK"), "1", StringComparison.Ordinal))
{
var savedGuardAddress = value4 >= 0x10 ? value4 - 0x10 : 0;
var guardKnown = TryReadUInt64Compat(value3, out var guardValue);
var savedKnown = TryReadUInt64Compat(savedGuardAddress, out var savedGuardValue);
Console.Error.WriteLine(
$"[LOADER][TRACE] stack_chk_diag#{num}: ret=0x{num7:X16} guard_ptr=0x{value3:X16} " +
$"guard={(guardKnown ? $"0x{guardValue:X16}" : "?")} saved@0x{savedGuardAddress:X16}={(savedKnown ? $"0x{savedGuardValue:X16}" : "?")} " +
$"rbp=0x{value4:X16} rsp=0x{((ulong)argPackPtr + 96uL):X16}");
}
try try
{ {
byte[] array = new byte[64]; byte[] array = new byte[64];
@@ -258,17 +285,31 @@ public sealed partial class DirectExecutionBackend
{ {
OrbisGen2Result orbisGen2Result; OrbisGen2Result orbisGen2Result;
bool dispatchResolved = true; bool dispatchResolved = true;
if (string.Equals(importStubEntry.Nid, RuntimeStubNids.BootstrapBridge, StringComparison.Ordinal)) var previousImportCallFrame = GuestThreadExecution.EnterImportCallFrame(num7, (ulong)argPackPtr + 104uL);
try
{ {
orbisGen2Result = DispatchBootstrapBridge(); if (string.Equals(importStubEntry.Nid, RuntimeStubNids.BootstrapBridge, StringComparison.Ordinal))
{
orbisGen2Result = DispatchBootstrapBridge();
}
else if (string.Equals(importStubEntry.Nid, RuntimeStubNids.KernelDynlibDlsym, StringComparison.Ordinal))
{
orbisGen2Result = DispatchKernelDynlibDlsym();
}
else
{
dispatchResolved = _moduleManager.TryDispatch(importStubEntry.Nid, cpuContext, out orbisGen2Result);
}
} }
else if (string.Equals(importStubEntry.Nid, RuntimeStubNids.KernelDynlibDlsym, StringComparison.Ordinal)) finally
{ {
orbisGen2Result = DispatchKernelDynlibDlsym(); GuestThreadExecution.RestoreImportCallFrame(previousImportCallFrame);
} }
else if (dispatchResolved &&
orbisGen2Result == OrbisGen2Result.ORBIS_GEN2_OK &&
string.Equals(importStubEntry.Nid, "BohYr-F7-is", StringComparison.Ordinal))
{ {
dispatchResolved = _moduleManager.TryDispatch(importStubEntry.Nid, _cpuContext, out orbisGen2Result); RegisterPrtLazyCommitRange(value2, num3);
} }
if (!dispatchResolved) if (!dispatchResolved)
{ {
@@ -287,59 +328,86 @@ public sealed partial class DirectExecutionBackend
ExportedFunction export2; ExportedFunction export2;
bool value20 = _moduleManager.TryGetExport(importStubEntry.Nid, out export2); bool value20 = _moduleManager.TryGetExport(importStubEntry.Nid, out export2);
Console.Error.WriteLine($"[LOADER][WARN] map_direct lookup with import nid: function={value19}, export={value20}"); Console.Error.WriteLine($"[LOADER][WARN] map_direct lookup with import nid: function={value19}, export={value20}");
Console.Error.WriteLine(_moduleManager.TryGetExport("L-Q3LEjIbgA", out ExportedFunction export3) ? $"[LOADER][WARN] Canonical map_direct exists as {export3.LibraryName}:{export3.Name}, target={export3.Target}, ctx_target={_cpuContext.TargetGeneration}" : "[LOADER][WARN] Canonical map_direct export lookup also missing"); Console.Error.WriteLine(_moduleManager.TryGetExport("L-Q3LEjIbgA", out ExportedFunction export3) ? $"[LOADER][WARN] Canonical map_direct exists as {export3.LibraryName}:{export3.Name}, target={export3.Target}, ctx_target={cpuContext.TargetGeneration}" : "[LOADER][WARN] Canonical map_direct export lookup also missing");
} }
} }
else if (orbisGen2Result != OrbisGen2Result.ORBIS_GEN2_OK) else if (orbisGen2Result != OrbisGen2Result.ORBIS_GEN2_OK)
{ {
Console.Error.WriteLine($"[LOADER][WARN] Import#{num} result: {orbisGen2Result} ({importStubEntry.Nid})"); Console.Error.WriteLine(
$"[LOADER][WARN] Import#{num} result: {orbisGen2Result} ({importStubEntry.Nid}) " +
$"rdi=0x{value:X16} rsi=0x{value2:X16} rdx=0x{num3:X16} rcx=0x{num4:X16} ret=0x{num7:X16}");
} }
_cpuContext[CpuRegister.Rbx] = value3; cpuContext[CpuRegister.Rbx] = value3;
_cpuContext[CpuRegister.Rbp] = value4; cpuContext[CpuRegister.Rbp] = value4;
_cpuContext[CpuRegister.R12] = value5; cpuContext[CpuRegister.R12] = value5;
_cpuContext[CpuRegister.R13] = value6; cpuContext[CpuRegister.R13] = value6;
_cpuContext[CpuRegister.R14] = value7; cpuContext[CpuRegister.R14] = value7;
_cpuContext[CpuRegister.R15] = value8; cpuContext[CpuRegister.R15] = value8;
_cpuContext[CpuRegister.Rdi] = value; cpuContext[CpuRegister.Rdi] = value;
_cpuContext[CpuRegister.Rsi] = value2; cpuContext[CpuRegister.Rsi] = value2;
if (GuestThreadExecution.TryConsumeCurrentEntryExit(out var exitStatus, out var exitReason)) if (GuestThreadExecution.TryConsumeCurrentEntryExit(out var exitStatus, out var exitReason))
{ {
if (TryCompleteGuestEntryToHostStub(argPackPtr, num, num7, importStubEntry.Nid, exitReason, exitStatus)) if (TryCompleteGuestEntryToHostStub(argPackPtr, num, num7, importStubEntry.Nid, exitReason, exitStatus))
{ {
_cpuContext[CpuRegister.Rax] = unchecked((ulong)exitStatus); cpuContext[CpuRegister.Rax] = unchecked((ulong)exitStatus);
} }
else else
{ {
LastError = $"Failed to complete guest entry after {importStubEntry.Nid}: missing host return sentinel"; LastError = $"Failed to complete guest entry after {importStubEntry.Nid}: missing host return sentinel";
_cpuContext[CpuRegister.Rax] = 18446744071562199298uL; cpuContext[CpuRegister.Rax] = 18446744071562199298uL;
} }
} }
if (GuestThreadExecution.TryConsumeCurrentThreadBlock(out var blockReason) && if (GuestThreadExecution.TryConsumeCurrentThreadBlock(out var blockReason) &&
TryYieldGuestThreadToHostStub(argPackPtr, num, num7, importStubEntry.Nid, blockReason)) TryYieldGuestThreadToHostStub(argPackPtr, num, num7, importStubEntry.Nid, blockReason))
{ {
_cpuContext[CpuRegister.Rax] = 0uL; cpuContext[CpuRegister.Rax] = 0uL;
} }
if (flag || flag2 || flag3) if (flag || flag2 || flag3)
{ {
Console.Error.WriteLine($"[LOADER][TRACE] ImportRet#{num}: nid={importStubEntry.Nid} result={orbisGen2Result} rax=0x{_cpuContext[CpuRegister.Rax]:X16}"); Console.Error.WriteLine($"[LOADER][TRACE] ImportRet#{num}: nid={importStubEntry.Nid} result={orbisGen2Result} rax=0x{cpuContext[CpuRegister.Rax]:X16}");
if (flag3) if (flag3)
{ {
Console.Error.Flush(); Console.Error.Flush();
} }
} }
return _cpuContext[CpuRegister.Rax]; return cpuContext[CpuRegister.Rax];
} }
catch (Exception ex) catch (Exception ex)
{ {
LastError = $"HLE dispatch error for {importStubEntry.Nid}: {ex.GetType().Name}: {ex.Message}"; LastError = $"HLE dispatch error for {importStubEntry.Nid}: {ex.GetType().Name}: {ex.Message}";
_cpuContext[CpuRegister.Rax] = 18446744071562199298uL; cpuContext[CpuRegister.Rax] = 18446744071562199298uL;
return 18446744071562199298uL; return 18446744071562199298uL;
} }
} }
private void TraceImportFrameChain(CpuContext context, long dispatchIndex)
{
var frame = context[CpuRegister.Rbp];
for (int i = 0; i < 16; i++)
{
if (!context.TryReadUInt64(frame, out var next) ||
!context.TryReadUInt64(frame + sizeof(ulong), out var returnRip))
{
break;
}
var symbol = TryFormatNearestRuntimeSymbol(returnRip, out var formatted)
? $" [{formatted}]"
: string.Empty;
Console.Error.WriteLine(
$"[LOADER][TRACE] ImportFrame#{dispatchIndex}.{i}: rbp=0x{frame:X16} ret=0x{returnRip:X16}{symbol} next=0x{next:X16}");
if (next <= frame || next - frame > 0x100000)
{
break;
}
frame = next;
}
}
private unsafe bool TryForceGuestExitToHostStub(nint argPackPtr, long dispatchIndex, ulong returnRip, string nid) private unsafe bool TryForceGuestExitToHostStub(nint argPackPtr, long dispatchIndex, ulong returnRip, string nid)
{ {
ulong num = _entryReturnSentinelRip; ulong num = ActiveEntryReturnSentinelRip;
if (num < 65536) if (num < 65536)
{ {
return false; return false;
@@ -352,7 +420,7 @@ public sealed partial class DirectExecutionBackend
{ {
return false; return false;
} }
_forcedGuestExit = true; ActiveForcedGuestExit = true;
LastError = $"Detected repeating import loop at import#{dispatchIndex} ({nid}) and forced guest exit."; LastError = $"Detected repeating import loop at import#{dispatchIndex} ({nid}) and forced guest exit.";
Console.Error.WriteLine($"[LOADER][ERROR] Import-loop guard fired at import#{dispatchIndex}: nid={nid} ret=0x{returnRip:X16} -> host_exit=0x{num:X16}"); Console.Error.WriteLine($"[LOADER][ERROR] Import-loop guard fired at import#{dispatchIndex}: nid={nid} ret=0x{returnRip:X16} -> host_exit=0x{num:X16}");
DumpRecentImportTrace(); DumpRecentImportTrace();
@@ -361,7 +429,7 @@ public sealed partial class DirectExecutionBackend
private unsafe bool TryCompleteGuestEntryToHostStub(nint argPackPtr, long dispatchIndex, ulong returnRip, string nid, string reason, int status) private unsafe bool TryCompleteGuestEntryToHostStub(nint argPackPtr, long dispatchIndex, ulong returnRip, string nid, string reason, int status)
{ {
ulong hostExit = _entryReturnSentinelRip; ulong hostExit = ActiveEntryReturnSentinelRip;
if (hostExit < 65536) if (hostExit < 65536)
{ {
return false; return false;
@@ -381,7 +449,7 @@ public sealed partial class DirectExecutionBackend
private unsafe bool TryYieldGuestThreadToHostStub(nint argPackPtr, long dispatchIndex, ulong returnRip, string nid, string reason) private unsafe bool TryYieldGuestThreadToHostStub(nint argPackPtr, long dispatchIndex, ulong returnRip, string nid, string reason)
{ {
ulong hostExit = _entryReturnSentinelRip; ulong hostExit = ActiveEntryReturnSentinelRip;
if (hostExit < 65536) if (hostExit < 65536)
{ {
return false; return false;
@@ -395,10 +463,10 @@ public sealed partial class DirectExecutionBackend
return false; return false;
} }
_guestThreadYieldRequested = true; ActiveGuestThreadYieldRequested = true;
_guestThreadYieldReason = string.IsNullOrWhiteSpace(reason) ? nid : reason; ActiveGuestThreadYieldReason = string.IsNullOrWhiteSpace(reason) ? nid : reason;
Console.Error.WriteLine( Console.Error.WriteLine(
$"[LOADER][INFO] Guest thread yield at import#{dispatchIndex}: nid={nid} ret=0x{returnRip:X16} reason={_guestThreadYieldReason}"); $"[LOADER][INFO] Guest thread yield at import#{dispatchIndex}: nid={nid} ret=0x{returnRip:X16} reason={ActiveGuestThreadYieldReason}");
return true; return true;
} }
@@ -424,10 +492,35 @@ public sealed partial class DirectExecutionBackend
{ {
_importLoopPatternHits--; _importLoopPatternHits--;
} }
if (_importLoopPatternHits == 0)
{
_importLoopPatternStartTimestamp = 0;
}
return false; return false;
} }
if (_importLoopPatternStartTimestamp == 0)
{
_importLoopPatternStartTimestamp = Stopwatch.GetTimestamp();
}
_importLoopPatternHits++; _importLoopPatternHits++;
return _importLoopPatternHits >= 6; var guardSeconds = GetImportLoopGuardSeconds();
if (guardSeconds <= 0 || _importLoopPatternHits < 6)
{
return false;
}
var elapsedTicks = Stopwatch.GetTimestamp() - _importLoopPatternStartTimestamp;
return elapsedTicks >= (long)(guardSeconds * Stopwatch.Frequency);
}
private static int GetImportLoopGuardSeconds()
{
if (int.TryParse(Environment.GetEnvironmentVariable("SHARPEMU_IMPORT_LOOP_GUARD_SECONDS"), out var seconds))
{
return Math.Max(0, seconds);
}
return DefaultImportLoopGuardSeconds;
} }
private ulong BuildImportLoopSignature(ulong nidHash, ulong returnRip, ulong arg0, ulong arg1) private ulong BuildImportLoopSignature(ulong nidHash, ulong returnRip, ulong arg0, ulong arg1)
@@ -645,41 +738,43 @@ public sealed partial class DirectExecutionBackend
private OrbisGen2Result DispatchKernelDynlibDlsym() private OrbisGen2Result DispatchKernelDynlibDlsym()
{ {
if (_cpuContext == null) var cpuContext = ActiveCpuContext;
if (cpuContext == null)
{ {
return OrbisGen2Result.ORBIS_GEN2_ERROR_INVALID_ARGUMENT; return OrbisGen2Result.ORBIS_GEN2_ERROR_INVALID_ARGUMENT;
} }
ulong symbolNameAddress = _cpuContext[CpuRegister.Rsi]; ulong symbolNameAddress = cpuContext[CpuRegister.Rsi];
ulong outputAddress = _cpuContext[CpuRegister.Rdx]; ulong outputAddress = cpuContext[CpuRegister.Rdx];
if (!TryReadAsciiZ(symbolNameAddress, 512, out var symbolName)) if (!TryReadAsciiZ(symbolNameAddress, 512, out var symbolName))
{ {
_cpuContext[CpuRegister.Rax] = 18446744073709551615uL; cpuContext[CpuRegister.Rax] = 18446744073709551615uL;
return OrbisGen2Result.ORBIS_GEN2_OK; return OrbisGen2Result.ORBIS_GEN2_OK;
} }
if (!TryResolveRuntimeSymbolAddress(symbolName, out var resolvedAddress)) if (!TryResolveRuntimeSymbolAddress(symbolName, out var resolvedAddress))
{ {
_cpuContext[CpuRegister.Rax] = 18446744073709551615uL; cpuContext[CpuRegister.Rax] = 18446744073709551615uL;
return OrbisGen2Result.ORBIS_GEN2_OK; return OrbisGen2Result.ORBIS_GEN2_OK;
} }
if (outputAddress == 0L || !TryWriteUInt64Compat(outputAddress, resolvedAddress)) if (outputAddress == 0L || !TryWriteUInt64Compat(outputAddress, resolvedAddress))
{ {
_cpuContext[CpuRegister.Rax] = 18446744073709551615uL; cpuContext[CpuRegister.Rax] = 18446744073709551615uL;
return OrbisGen2Result.ORBIS_GEN2_OK; return OrbisGen2Result.ORBIS_GEN2_OK;
} }
_cpuContext[CpuRegister.Rax] = 0uL; cpuContext[CpuRegister.Rax] = 0uL;
return OrbisGen2Result.ORBIS_GEN2_OK; return OrbisGen2Result.ORBIS_GEN2_OK;
} }
private OrbisGen2Result DispatchBootstrapBridge() private OrbisGen2Result DispatchBootstrapBridge()
{ {
if (_cpuContext == null) var cpuContext = ActiveCpuContext;
if (cpuContext == null)
{ {
return OrbisGen2Result.ORBIS_GEN2_ERROR_INVALID_ARGUMENT; return OrbisGen2Result.ORBIS_GEN2_ERROR_INVALID_ARGUMENT;
} }
ulong bridgeHandle = _cpuContext[CpuRegister.Rdi]; ulong bridgeHandle = cpuContext[CpuRegister.Rdi];
ulong symbolNameAddress = _cpuContext[CpuRegister.Rsi]; ulong symbolNameAddress = cpuContext[CpuRegister.Rsi];
ulong outputAddress = _cpuContext[CpuRegister.Rdx]; ulong outputAddress = cpuContext[CpuRegister.Rdx];
_ = TryReadAsciiZ(symbolNameAddress, 512, out var symbolName); _ = TryReadAsciiZ(symbolNameAddress, 512, out var symbolName);
OrbisGen2Result result = DispatchKernelDynlibDlsym(); OrbisGen2Result result = DispatchKernelDynlibDlsym();
@@ -691,10 +786,10 @@ public sealed partial class DirectExecutionBackend
if (logBootstrap) if (logBootstrap)
{ {
Console.Error.WriteLine( Console.Error.WriteLine(
$"[LOADER][TRACE] bootstrap_dispatch: handle=0x{bridgeHandle:X16} symbol='{symbolName}' out=0x{outputAddress:X16} rax=0x{_cpuContext[CpuRegister.Rax]:X16}"); $"[LOADER][TRACE] bootstrap_dispatch: handle=0x{bridgeHandle:X16} symbol='{symbolName}' out=0x{outputAddress:X16} rax=0x{cpuContext[CpuRegister.Rax]:X16}");
} }
if (_cpuContext[CpuRegister.Rax] == 0uL) if (cpuContext[CpuRegister.Rax] == 0uL)
{ {
return OrbisGen2Result.ORBIS_GEN2_OK; return OrbisGen2Result.ORBIS_GEN2_OK;
} }
@@ -737,7 +832,7 @@ public sealed partial class DirectExecutionBackend
private bool TryReadAsciiZ(ulong address, int maxLength, out string value) private bool TryReadAsciiZ(ulong address, int maxLength, out string value)
{ {
value = string.Empty; value = string.Empty;
if (_cpuContext == null || address == 0L || maxLength <= 0) if (ActiveCpuContext == null || address == 0L || maxLength <= 0)
{ {
return false; return false;
} }
@@ -762,11 +857,12 @@ public sealed partial class DirectExecutionBackend
private bool TryReadByteCompat(ulong address, Span<byte> destination) private bool TryReadByteCompat(ulong address, Span<byte> destination)
{ {
if (_cpuContext == null || destination.Length == 0) var cpuContext = ActiveCpuContext;
if (cpuContext == null || destination.Length == 0)
{ {
return false; return false;
} }
if (_cpuContext.Memory.TryRead(address, destination)) if (cpuContext.Memory.TryRead(address, destination))
{ {
return true; return true;
} }
@@ -781,13 +877,38 @@ public sealed partial class DirectExecutionBackend
} }
} }
private bool TryWriteUInt64Compat(ulong address, ulong value) private bool TryReadUInt64Compat(ulong address, out ulong value)
{ {
if (_cpuContext == null || address == 0L) value = 0;
var cpuContext = ActiveCpuContext;
if (cpuContext == null || address == 0L)
{ {
return false; return false;
} }
if (_cpuContext.TryWriteUInt64(address, value)) if (cpuContext.TryReadUInt64(address, out value))
{
return true;
}
try
{
value = unchecked((ulong)Marshal.ReadInt64((nint)address));
return true;
}
catch
{
value = 0;
return false;
}
}
private bool TryWriteUInt64Compat(ulong address, ulong value)
{
var cpuContext = ActiveCpuContext;
if (cpuContext == null || address == 0L)
{
return false;
}
if (cpuContext.TryWriteUInt64(address, value))
{ {
return true; return true;
} }
@@ -804,7 +925,8 @@ public sealed partial class DirectExecutionBackend
private void TryBypassStackChkFailTrap(long dispatchIndex, ulong returnRip) private void TryBypassStackChkFailTrap(long dispatchIndex, ulong returnRip)
{ {
if (_cpuContext == null || returnRip < 32) var cpuContext = ActiveCpuContext;
if (cpuContext == null || returnRip < 32)
{ {
return; return;
} }
@@ -818,8 +940,8 @@ public sealed partial class DirectExecutionBackend
return; return;
} }
ulong value = returnRip - 21; ulong value = returnRip - 21;
ulong address = _cpuContext[CpuRegister.Rsp]; ulong address = cpuContext[CpuRegister.Rsp];
if (_cpuContext.TryWriteUInt64(address, value)) if (cpuContext.TryWriteUInt64(address, value))
{ {
if (_stackChkBypassSites.Add(num) && TryPatchStackChkFailBranch(num)) if (_stackChkBypassSites.Add(num) && TryPatchStackChkFailBranch(num))
{ {
File diff suppressed because it is too large Load Diff
+87
View File
@@ -15,8 +15,49 @@ public interface IGuestThreadScheduler
bool TryStartThread(CpuContext creatorContext, GuestThreadStartRequest request, out string? error); bool TryStartThread(CpuContext creatorContext, GuestThreadStartRequest request, out string? error);
void Pump(CpuContext callerContext, string reason); void Pump(CpuContext callerContext, string reason);
bool TryCallGuestFunction(
CpuContext callerContext,
ulong entryPoint,
ulong arg0,
ulong arg1,
ulong stackAddress,
ulong stackSize,
string reason,
out string? error);
bool TryCallGuestContinuation(
CpuContext callerContext,
GuestCpuContinuation continuation,
string reason,
out string? error);
} }
public readonly record struct GuestImportCallFrame(
bool IsValid,
ulong ReturnRip,
ulong ResumeRsp);
public readonly record struct GuestCpuContinuation(
ulong Rip,
ulong Rsp,
ulong Rflags,
ulong FsBase,
ulong GsBase,
ulong Rax,
ulong Rcx,
ulong Rdx,
ulong Rbx,
ulong Rbp,
ulong Rsi,
ulong Rdi,
ulong R8,
ulong R9,
ulong R12,
ulong R13,
ulong R14,
ulong R15);
public static class GuestThreadExecution public static class GuestThreadExecution
{ {
[ThreadStatic] [ThreadStatic]
@@ -34,6 +75,15 @@ public static class GuestThreadExecution
[ThreadStatic] [ThreadStatic]
private static string? _pendingEntryExitReason; private static string? _pendingEntryExitReason;
[ThreadStatic]
private static bool _hasCurrentImportCallFrame;
[ThreadStatic]
private static ulong _currentImportReturnRip;
[ThreadStatic]
private static ulong _currentImportResumeRsp;
public static IGuestThreadScheduler? Scheduler { get; set; } public static IGuestThreadScheduler? Scheduler { get; set; }
public static bool IsGuestThread => _currentGuestThreadHandle != 0; public static bool IsGuestThread => _currentGuestThreadHandle != 0;
@@ -48,6 +98,9 @@ public static class GuestThreadExecution
_pendingEntryExit = false; _pendingEntryExit = false;
_pendingEntryExitStatus = 0; _pendingEntryExitStatus = 0;
_pendingEntryExitReason = null; _pendingEntryExitReason = null;
_hasCurrentImportCallFrame = false;
_currentImportReturnRip = 0;
_currentImportResumeRsp = 0;
return previous; return previous;
} }
@@ -58,6 +111,9 @@ public static class GuestThreadExecution
_pendingEntryExit = false; _pendingEntryExit = false;
_pendingEntryExitStatus = 0; _pendingEntryExitStatus = 0;
_pendingEntryExitReason = null; _pendingEntryExitReason = null;
_hasCurrentImportCallFrame = false;
_currentImportReturnRip = 0;
_currentImportResumeRsp = 0;
} }
public static bool RequestCurrentThreadBlock(string reason) public static bool RequestCurrentThreadBlock(string reason)
@@ -104,4 +160,35 @@ public static class GuestThreadExecution
_pendingEntryExitReason = null; _pendingEntryExitReason = null;
return true; return true;
} }
public static GuestImportCallFrame EnterImportCallFrame(ulong returnRip, ulong resumeRsp)
{
var previous = new GuestImportCallFrame(
_hasCurrentImportCallFrame,
_currentImportReturnRip,
_currentImportResumeRsp);
_hasCurrentImportCallFrame = true;
_currentImportReturnRip = returnRip;
_currentImportResumeRsp = resumeRsp;
return previous;
}
public static void RestoreImportCallFrame(GuestImportCallFrame previous)
{
_hasCurrentImportCallFrame = previous.IsValid;
_currentImportReturnRip = previous.ReturnRip;
_currentImportResumeRsp = previous.ResumeRsp;
}
public static bool TryGetCurrentImportCallFrame(out GuestImportCallFrame frame)
{
if (!_hasCurrentImportCallFrame)
{
frame = default;
return false;
}
frame = new GuestImportCallFrame(true, _currentImportReturnRip, _currentImportResumeRsp);
return true;
}
} }