initial commit

This commit is contained in:
ParantezTech
2026-03-11 15:48:28 +03:00
commit 4d73f469bc
92 changed files with 166746 additions and 0 deletions
+205
View File
@@ -0,0 +1,205 @@
// Copyright (C) 2026 SharpEmu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
using System;
using System.Collections.Concurrent;
using System.Threading;
using SharpEmu.HLE;
namespace SharpEmu.Libs.CxxAbi;
public static class CxaGuardExports
{
private sealed class GuardState
{
public int OwnerThreadId { get; set; }
}
private static readonly ConcurrentDictionary<ulong, GuardState> _inProgress = new();
[SysAbiExport(
Nid = "3GPpjQdAMTw",
ExportName = "__cxa_guard_acquire",
Target = Generation.Gen4 | Generation.Gen5,
LibraryName = "libc")]
public static int CxaGuardAcquire(CpuContext ctx)
{
var guardPtr = ctx[CpuRegister.Rdi];
if (guardPtr == 0)
{
ctx[CpuRegister.Rax] = 0;
return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_INVALID_ARGUMENT;
}
var currentThreadId = Environment.CurrentManagedThreadId;
var spinner = new SpinWait();
while (true)
{
if (!TryReadGuardInitialized(ctx, guardPtr, out var initialized))
{
ctx[CpuRegister.Rax] = 0;
return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
}
LogGuardState(ctx, "guard_acquire", guardPtr, initialized);
if (initialized)
{
ctx[CpuRegister.Rax] = 0;
LogGuardResult("guard_acquire", guardPtr, result: 0, initialized, inProgress: false, ownerThreadId: 0);
return (int)OrbisGen2Result.ORBIS_GEN2_OK;
}
var newState = new GuardState
{
OwnerThreadId = currentThreadId,
};
if (_inProgress.TryAdd(guardPtr, newState))
{
ctx[CpuRegister.Rax] = 1;
LogGuardResult("guard_acquire", guardPtr, result: 1, initialized, inProgress: true, ownerThreadId: currentThreadId);
return (int)OrbisGen2Result.ORBIS_GEN2_OK;
}
if (_inProgress.TryGetValue(guardPtr, out var state))
{
if (state.OwnerThreadId == currentThreadId)
{
ctx[CpuRegister.Rax] = 0;
LogGuardResult("guard_acquire", guardPtr, result: 0, initialized, inProgress: true, ownerThreadId: state.OwnerThreadId);
return (int)OrbisGen2Result.ORBIS_GEN2_OK;
}
}
spinner.SpinOnce();
if (spinner.Count % 32 == 0)
{
Thread.Yield();
}
}
}
[SysAbiExport(
Nid = "",
ExportName = "__cxa_guard_release",
Target = Generation.Gen4 | Generation.Gen5,
LibraryName = "libc")]
public static int CxaGuardRelease(CpuContext ctx)
{
var guardPtr = ctx[CpuRegister.Rdi];
if (guardPtr == 0)
{
ctx[CpuRegister.Rax] = 0;
return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_INVALID_ARGUMENT;
}
if (_inProgress.TryGetValue(guardPtr, out var state) &&
state.OwnerThreadId != Environment.CurrentManagedThreadId)
{
ctx[CpuRegister.Rax] = 0;
LogGuardResult("guard_release", guardPtr, result: 0, initialized: false, inProgress: true, ownerThreadId: state.OwnerThreadId);
return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_INVALID_ARGUMENT;
}
if (!TryWriteGuardInitialized(ctx, guardPtr, initialized: true))
{
ctx[CpuRegister.Rax] = 0;
return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
}
_inProgress.TryRemove(guardPtr, out _);
LogGuardState(ctx, "guard_release", guardPtr, initialized: true);
ctx[CpuRegister.Rax] = 0;
return (int)OrbisGen2Result.ORBIS_GEN2_OK;
}
[SysAbiExport(
Nid = "",
ExportName = "__cxa_guard_abort",
Target = Generation.Gen4 | Generation.Gen5,
LibraryName = "libc")]
public static int CxaGuardAbort(CpuContext ctx)
{
var guardPtr = ctx[CpuRegister.Rdi];
if (guardPtr == 0)
{
ctx[CpuRegister.Rax] = 0;
return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_INVALID_ARGUMENT;
}
if (_inProgress.TryGetValue(guardPtr, out var state) &&
state.OwnerThreadId != Environment.CurrentManagedThreadId)
{
ctx[CpuRegister.Rax] = 0;
LogGuardResult("guard_abort", guardPtr, result: 0, initialized: false, inProgress: true, ownerThreadId: state.OwnerThreadId);
return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_INVALID_ARGUMENT;
}
_ = TryWriteGuardInitialized(ctx, guardPtr, initialized: false);
_inProgress.TryRemove(guardPtr, out _);
LogGuardState(ctx, "guard_abort", guardPtr, initialized: false);
ctx[CpuRegister.Rax] = 0;
return (int)OrbisGen2Result.ORBIS_GEN2_OK;
}
private static bool TryReadGuardInitialized(CpuContext ctx, ulong guardPtr, out bool initialized)
{
initialized = false;
var aligned = guardPtr & ~7UL;
var shift = (int)((guardPtr & 7UL) * 8);
if (!ctx.TryReadUInt64(aligned, out var word))
{
return false;
}
var b0 = (byte)((word >> shift) & 0xFF);
initialized = (b0 & 0x01) != 0;
return true;
}
private static bool TryWriteGuardInitialized(CpuContext ctx, ulong guardPtr, bool initialized)
{
var aligned = guardPtr & ~7UL;
var shift = (int)((guardPtr & 7UL) * 8);
var mask = 0xFFUL << shift;
if (!ctx.TryReadUInt64(aligned, out var word))
{
return false;
}
var b0 = (byte)((word >> shift) & 0xFF);
b0 = initialized ? (byte)(b0 | 0x01) : (byte)(b0 & ~0x01);
var newWord = (word & ~mask) | ((ulong)b0 << shift);
return ctx.TryWriteUInt64(aligned, newWord);
}
private static void LogGuardState(CpuContext ctx, string op, ulong guardPtr, bool initialized)
{
if (!string.Equals(Environment.GetEnvironmentVariable("SHARPEMU_LOG_GUARDS"), "1", StringComparison.Ordinal))
{
return;
}
var aligned = guardPtr & ~7UL;
var readable = ctx.TryReadUInt64(aligned, out var word);
Console.Error.WriteLine(
$"[LOADER][TRACE] {op}: guard=0x{guardPtr:X16} aligned=0x{aligned:X16} init={initialized} word={(readable ? $"0x{word:X16}" : "<unreadable>")}");
}
private static void LogGuardResult(string op, ulong guardPtr, int result, bool initialized, bool inProgress, int ownerThreadId)
{
if (!string.Equals(Environment.GetEnvironmentVariable("SHARPEMU_LOG_GUARDS"), "1", StringComparison.Ordinal))
{
return;
}
Console.Error.WriteLine(
$"[LOADER][TRACE] {op}: guard=0x{guardPtr:X16} result={result} init={initialized} in_progress={inProgress} owner_thread={ownerThreadId}");
}
}