mirror of
https://github.com/par274/sharpemu.git
synced 2026-07-19 01:16:12 +08:00
fix(core): lazy dlsym stub materialization, COW snapshots and deferred bootstrap logging (#94)
* fix(core): implement 4-tier lazy dlsym stub materialization and argument normalization Enforce transactional and thread-safe resolution for standalone ELF bootstrapper pipelines. - Implement a 4-tier additive fallback cascade (T0: runtime symbols, T1: import entries scan, T2: Aerolib mapping, T3: runtime slack-pool lazy stub allocation at 0x7000_0000_0000). - Fix UnmanagedCallersOnly CLR runtime crashes on second bootstrap by adding NormalizeKernelDynlibDlsymArguments to detect and swap mirrored (symbol, handle) register inputs via rigorous pointer bounds verification. - Protect failure paths via CompleteKernelDynlibDlsymFailure, cleanly zero-filling target outputAddress buffers and returns Rax = -1 with zero managed logging execution in hot native paths. * fix(core): harden lazy-stub diagnostics with COW snapshots and deferred bootstrap logging Follow-up to lazy stub pool copy-on-write publishing in TryGetOrCreateLazyImportStub. - Snapshot _importEntries in ProbeReturnRip before near-call and PLT import lookup loops to prevent torn iteration during concurrent array replacement. - Defer SHARPEMU_LOG_BOOTSTRAP output: hot path records raw register slots in a ring buffer under lock; TryReadAsciiZ and Console.Error run only after import handler completion via DrainDeferredBootstrapTraces. - Normalize bootstrap dynlib register order at DispatchImport gateway entry before any logging or trace reads, so swapped RDI/RSI on Import#2 cannot fault the native gateway when bootstrap tracing is enabled. - Resolve lazy stub pool bounds from the full SelfLoader-mapped import region via VirtualQuery instead of a hardcoded 4 KiB cap. - Use ConcurrentDictionary for runtime symbol registration during concurrent dlsym. - Emit distinct [LOADER][WARN] reasons when import stub region resolution fails versus lazy stub pool exhaustion.
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
@@ -48,6 +49,13 @@ public sealed unsafe partial class DirectExecutionBackend : INativeCpuBackend, I
|
||||
ulong Arg1,
|
||||
ulong Arg2);
|
||||
|
||||
private readonly record struct DeferredBootstrapTraceEntry(
|
||||
long DispatchIndex,
|
||||
ulong Op,
|
||||
ulong SymbolPointer,
|
||||
ulong OutputPointer,
|
||||
ulong ReturnRip);
|
||||
|
||||
#pragma warning disable CS0649
|
||||
private struct EXCEPTION_POINTERS
|
||||
{
|
||||
@@ -232,7 +240,31 @@ public sealed unsafe partial class DirectExecutionBackend : INativeCpuBackend, I
|
||||
|
||||
private KeyValuePair<string, ulong>[] _runtimeSymbolsByAddress = Array.Empty<KeyValuePair<string, ulong>>();
|
||||
|
||||
private readonly Dictionary<string, ulong> _runtimeSymbolsByName = new Dictionary<string, ulong>(StringComparer.Ordinal);
|
||||
private readonly ConcurrentDictionary<string, ulong> _runtimeSymbolsByName =
|
||||
new(StringComparer.Ordinal);
|
||||
|
||||
// Keep in sync with SelfLoader import-stub mapping constants.
|
||||
private const ulong ImportStubRegionCanonicalBase = 0x0000_7000_0000_0000UL;
|
||||
|
||||
private const ulong ImportStubRegionAddressStride = 0x0000_0000_0100_0000UL;
|
||||
|
||||
private const ulong LazyImportStubSlotSize = 0x10;
|
||||
|
||||
private const ulong ImportStubRegionPageSize = 0x1000UL;
|
||||
|
||||
private const string KernelDynlibDlsymAerolibNid = "LwG8g3niqwA";
|
||||
|
||||
private readonly object _lazyDlsymStubGate = new();
|
||||
|
||||
private readonly Dictionary<string, ulong> _lazyDlsymStubCache = new(StringComparer.Ordinal);
|
||||
|
||||
private ulong _lazyImportStubPoolBase;
|
||||
|
||||
private ulong _lazyImportStubNextSlot;
|
||||
|
||||
private ulong _lazyImportStubPoolLimit;
|
||||
|
||||
private bool _lazyImportStubPoolMapped;
|
||||
|
||||
private readonly RecentImportTraceEntry[] _recentImportTrace = new RecentImportTraceEntry[64];
|
||||
|
||||
@@ -240,6 +272,14 @@ public sealed unsafe partial class DirectExecutionBackend : INativeCpuBackend, I
|
||||
|
||||
private int _recentImportTraceWriteIndex;
|
||||
|
||||
private readonly DeferredBootstrapTraceEntry[] _deferredBootstrapTrace = new DeferredBootstrapTraceEntry[32];
|
||||
|
||||
private int _deferredBootstrapTraceCount;
|
||||
|
||||
private int _deferredBootstrapTraceWriteIndex;
|
||||
|
||||
private readonly object _deferredBootstrapTraceGate = new();
|
||||
|
||||
private readonly string[] _distinctImportNidHistory = new string[128];
|
||||
|
||||
private int _distinctImportNidHistoryCount;
|
||||
@@ -855,8 +895,14 @@ public sealed unsafe partial class DirectExecutionBackend : INativeCpuBackend, I
|
||||
result = OrbisGen2Result.ORBIS_GEN2_OK;
|
||||
LastError = null;
|
||||
InitializeRuntimeSymbolIndex(runtimeSymbols);
|
||||
ResetLazyDlsymStubState();
|
||||
_recentImportTraceCount = 0;
|
||||
_recentImportTraceWriteIndex = 0;
|
||||
lock (_deferredBootstrapTraceGate)
|
||||
{
|
||||
_deferredBootstrapTraceCount = 0;
|
||||
_deferredBootstrapTraceWriteIndex = 0;
|
||||
}
|
||||
_distinctImportNidHistoryCount = 0;
|
||||
_distinctImportNidHistoryWriteIndex = 0;
|
||||
_lastDistinctImportNid = string.Empty;
|
||||
@@ -930,6 +976,7 @@ public sealed unsafe partial class DirectExecutionBackend : INativeCpuBackend, I
|
||||
}
|
||||
finally
|
||||
{
|
||||
DrainDeferredBootstrapTraces();
|
||||
GuestThreadExecution.Scheduler = previousGuestThreadScheduler;
|
||||
Console.Error.WriteLine("[LOADER][INFO] === Execute END (LastError: " + (LastError ?? "null") + ") ===");
|
||||
}
|
||||
@@ -4456,13 +4503,14 @@ public sealed unsafe partial class DirectExecutionBackend : INativeCpuBackend, I
|
||||
ulong rsp = cpuContext[CpuRegister.Rsp];
|
||||
Console.Error.WriteLine($"[LOADER][ERROR] Stall snapshot: rip=0x{cpuContext.Rip:X16} rsp=0x{rsp:X16} rbp=0x{cpuContext[CpuRegister.Rbp]:X16} rax=0x{cpuContext[CpuRegister.Rax]:X16} rbx=0x{cpuContext[CpuRegister.Rbx]:X16} rcx=0x{cpuContext[CpuRegister.Rcx]:X16} rdx=0x{cpuContext[CpuRegister.Rdx]:X16} rsi=0x{cpuContext[CpuRegister.Rsi]:X16} rdi=0x{cpuContext[CpuRegister.Rdi]:X16}");
|
||||
ulong num = cpuContext.Rip & 0xFFFFFFFFFFFFFFF0uL;
|
||||
for (int i = 0; i < _importEntries.Length; i++)
|
||||
var importEntries = _importEntries;
|
||||
for (int i = 0; i < importEntries.Length; i++)
|
||||
{
|
||||
if (_importEntries[i].Address != num)
|
||||
if (importEntries[i].Address != num)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
string text = _importEntries[i].Nid;
|
||||
string text = importEntries[i].Nid;
|
||||
if (_moduleManager.TryGetExport(text, out ExportedFunction export))
|
||||
{
|
||||
Console.Error.WriteLine($"[LOADER][ERROR] Stall import-stub: rip=0x{num:X16} nid={text} -> {export.LibraryName}:{export.Name}");
|
||||
@@ -4653,6 +4701,7 @@ public sealed unsafe partial class DirectExecutionBackend : INativeCpuBackend, I
|
||||
ClearImportHandlerTrampolines();
|
||||
_importEntries = Array.Empty<ImportStubEntry>();
|
||||
_runtimeSymbolsByName.Clear();
|
||||
ResetLazyDlsymStubState();
|
||||
_importNidHashCache.Clear();
|
||||
StopStallWatchdog();
|
||||
if (_exceptionHandler != 0)
|
||||
|
||||
Reference in New Issue
Block a user