mirror of
https://github.com/par274/sharpemu.git
synced 2026-08-07 10:29:46 +08:00
Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| cecf55bf2e | |||
| 0ede7c70a9 | |||
| 8c39a55501 | |||
| 0a4b36ffcb | |||
| 1a1d61b21c | |||
| 3cf96f38de | |||
| d8c44bb64f | |||
| a4b5171586 |
@@ -0,0 +1,59 @@
|
|||||||
|
# Copyright (C) 2026 SharpEmu Emulator Project
|
||||||
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
name: Bug Report
|
||||||
|
description: Report a bug in the emulator
|
||||||
|
labels: ["bug"]
|
||||||
|
|
||||||
|
body:
|
||||||
|
- type: markdown
|
||||||
|
attributes:
|
||||||
|
value: |
|
||||||
|
### Before creating an issue
|
||||||
|
|
||||||
|
- Do not create issues involving **software piracy**. Our rules specifically prohibit this.
|
||||||
|
Issues related to piracy will be closed and the author may be banned from the repository.
|
||||||
|
|
||||||
|
- The issue tracker is **not for asking questions**.
|
||||||
|
Question-type issues will be closed.
|
||||||
|
|
||||||
|
- Only open an issue if you are reporting an actual **bug in the emulator**.
|
||||||
|
|
||||||
|
- type: input
|
||||||
|
id: emulator_version
|
||||||
|
attributes:
|
||||||
|
label: Emulator Version / Commit
|
||||||
|
description: The emulator version or git commit where the bug occurred
|
||||||
|
placeholder: e.g. v0.0.2 / a1b2c3d
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: description
|
||||||
|
attributes:
|
||||||
|
label: Bug Description
|
||||||
|
description: Describe the problem and how to reproduce it
|
||||||
|
placeholder: |
|
||||||
|
Steps to reproduce:
|
||||||
|
1. Launch emulator
|
||||||
|
2. Load game
|
||||||
|
3. Crash occurs
|
||||||
|
|
||||||
|
Expected behavior:
|
||||||
|
...
|
||||||
|
|
||||||
|
Actual behavior:
|
||||||
|
...
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: logs
|
||||||
|
attributes:
|
||||||
|
label: Log File
|
||||||
|
description: |
|
||||||
|
Drag & drop your log file here, or paste the log contents.
|
||||||
|
|
||||||
|
Supported: .log / .txt / .zip
|
||||||
|
Large logs should be uploaded as a file.
|
||||||
|
render: shell
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
# Copyright (C) 2026 SharpEmu Emulator Project
|
||||||
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
blank_issues_enabled: false
|
||||||
@@ -1,3 +1,6 @@
|
|||||||
|
# Copyright (C) 2026 SharpEmu Emulator Project
|
||||||
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
name: Game Compatibility Report
|
name: Game Compatibility Report
|
||||||
description: Report compatibility status of a game
|
description: Report compatibility status of a game
|
||||||
labels: ["game-compatibility"]
|
labels: ["game-compatibility"]
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
# Copyright (C) 2026 SharpEmu Emulator Project
|
||||||
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
name: Build and Release
|
name: Build and Release
|
||||||
|
|
||||||
on:
|
on:
|
||||||
@@ -79,7 +82,7 @@ jobs:
|
|||||||
- name: Setup .NET SDK
|
- name: Setup .NET SDK
|
||||||
uses: actions/setup-dotnet@v5
|
uses: actions/setup-dotnet@v5
|
||||||
with:
|
with:
|
||||||
dotnet-version: 10.0.x
|
dotnet-version: 10.0.103
|
||||||
cache: true
|
cache: true
|
||||||
cache-dependency-path: |
|
cache-dependency-path: |
|
||||||
Directory.Packages.props
|
Directory.Packages.props
|
||||||
@@ -106,7 +109,7 @@ jobs:
|
|||||||
Compress-Archive -Path (Join-Path $env:PUBLISH_DIR '*') -DestinationPath $archivePath -CompressionLevel Optimal
|
Compress-Archive -Path (Join-Path $env:PUBLISH_DIR '*') -DestinationPath $archivePath -CompressionLevel Optimal
|
||||||
|
|
||||||
- name: Upload build artifact
|
- name: Upload build artifact
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v6
|
||||||
with:
|
with:
|
||||||
name: ${{ needs.init.outputs.artifact-name }}
|
name: ${{ needs.init.outputs.artifact-name }}
|
||||||
path: ${{ env.RELEASE_DIR }}\${{ needs.init.outputs.archive-name }}
|
path: ${{ env.RELEASE_DIR }}\${{ needs.init.outputs.archive-name }}
|
||||||
@@ -123,7 +126,7 @@ jobs:
|
|||||||
contents: write
|
contents: write
|
||||||
steps:
|
steps:
|
||||||
- name: Download build artifact
|
- name: Download build artifact
|
||||||
uses: actions/download-artifact@v4
|
uses: actions/download-artifact@v8
|
||||||
with:
|
with:
|
||||||
name: ${{ needs.init.outputs.artifact-name }}
|
name: ${{ needs.init.outputs.artifact-name }}
|
||||||
path: release
|
path: release
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ version = 1
|
|||||||
[[annotations]]
|
[[annotations]]
|
||||||
path = [
|
path = [
|
||||||
"REUSE.toml",
|
"REUSE.toml",
|
||||||
|
"global.json",
|
||||||
"**/packages.lock.json",
|
"**/packages.lock.json",
|
||||||
"scripts/ps5_names.txt",
|
"scripts/ps5_names.txt",
|
||||||
"src/SharpEmu.HLE/Aerolib/aerolib.bin",
|
"src/SharpEmu.HLE/Aerolib/aerolib.bin",
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"sdk": {
|
||||||
|
"version": "10.0.103",
|
||||||
|
"rollForward": "latestFeature"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -231,9 +231,6 @@ public sealed partial class DirectExecutionBackend
|
|||||||
ProbeReturnRip(num7, num);
|
ProbeReturnRip(num7, num);
|
||||||
Console.Error.Flush();
|
Console.Error.Flush();
|
||||||
}
|
}
|
||||||
ProbeReturnRip(0x0000000800EA020Eul, 999001);
|
|
||||||
ProbeReturnRip(0x0000000800EA0213ul, 999002);
|
|
||||||
ProbeReturnRip(0x0000000800EA040Aul, 999003);
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
OrbisGen2Result orbisGen2Result;
|
OrbisGen2Result orbisGen2Result;
|
||||||
@@ -426,7 +423,20 @@ public sealed partial class DirectExecutionBackend
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
int num2 = CountDistinctImportLoopValuesFromTail(_importLoopReturnRips, sampleCount, 3);
|
int num2 = CountDistinctImportLoopValuesFromTail(_importLoopReturnRips, sampleCount, 3);
|
||||||
return num2 <= 2;
|
if (num2 > 2)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
int num3 = Math.Min(_importLoopSignatureCount, Math.Max(sampleCount * 8, ImportLoopWideDiversityWindow));
|
||||||
|
if (num3 <= sampleCount)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (CountDistinctImportLoopValuesFromTail(_importLoopNidHashes, num3, 3) > 2)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return CountDistinctImportLoopValuesFromTail(_importLoopReturnRips, num3, 3) <= 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int CountDistinctImportLoopValuesFromTail(ulong[] source, int sampleCount, int stopAfter)
|
private int CountDistinctImportLoopValuesFromTail(ulong[] source, int sampleCount, int stopAfter)
|
||||||
|
|||||||
@@ -13,6 +13,10 @@ namespace SharpEmu.Core.Cpu.Native;
|
|||||||
|
|
||||||
public sealed unsafe partial class DirectExecutionBackend : INativeCpuBackend, IDisposable
|
public sealed unsafe partial class DirectExecutionBackend : INativeCpuBackend, IDisposable
|
||||||
{
|
{
|
||||||
|
private const int ImportLoopHistoryLength = 2048;
|
||||||
|
|
||||||
|
private const int ImportLoopWideDiversityWindow = 768;
|
||||||
|
|
||||||
private readonly struct ImportStubEntry
|
private readonly struct ImportStubEntry
|
||||||
{
|
{
|
||||||
public ulong Address { get; }
|
public ulong Address { get; }
|
||||||
@@ -89,7 +93,7 @@ public sealed unsafe partial class DirectExecutionBackend : INativeCpuBackend, I
|
|||||||
|
|
||||||
private const uint PAGE_EXECUTE_READ = 32u;
|
private const uint PAGE_EXECUTE_READ = 32u;
|
||||||
|
|
||||||
private const int TlsHandlerRegionSize = 4096;
|
private const int TlsHandlerRegionSize = 16384;
|
||||||
|
|
||||||
private const ulong TlsModuleAllocStart = 140726751354880uL;
|
private const ulong TlsModuleAllocStart = 140726751354880uL;
|
||||||
|
|
||||||
@@ -179,11 +183,11 @@ public sealed unsafe partial class DirectExecutionBackend : INativeCpuBackend, I
|
|||||||
|
|
||||||
private ulong _entryReturnSentinelRip;
|
private ulong _entryReturnSentinelRip;
|
||||||
|
|
||||||
private readonly ulong[] _importLoopSignatures = new ulong[192];
|
private readonly ulong[] _importLoopSignatures = new ulong[ImportLoopHistoryLength];
|
||||||
|
|
||||||
private readonly ulong[] _importLoopNidHashes = new ulong[192];
|
private readonly ulong[] _importLoopNidHashes = new ulong[ImportLoopHistoryLength];
|
||||||
|
|
||||||
private readonly ulong[] _importLoopReturnRips = new ulong[192];
|
private readonly ulong[] _importLoopReturnRips = new ulong[ImportLoopHistoryLength];
|
||||||
|
|
||||||
private int _importLoopSignatureCount;
|
private int _importLoopSignatureCount;
|
||||||
|
|
||||||
@@ -601,14 +605,6 @@ public sealed unsafe partial class DirectExecutionBackend : INativeCpuBackend, I
|
|||||||
{
|
{
|
||||||
return exportName switch
|
return exportName switch
|
||||||
{
|
{
|
||||||
"_init_env" or
|
|
||||||
"atexit" or
|
|
||||||
"strlen" or
|
|
||||||
"strnlen" or
|
|
||||||
"strcmp" or
|
|
||||||
"strncmp" or
|
|
||||||
"strcpy" or
|
|
||||||
"strncpy" or
|
|
||||||
"memcpy" or
|
"memcpy" or
|
||||||
"memmove" or
|
"memmove" or
|
||||||
"memset" or
|
"memset" or
|
||||||
|
|||||||
@@ -40,6 +40,9 @@ public sealed unsafe class PhysicalVirtualMemory : IVirtualMemory, IDisposable
|
|||||||
[return: MarshalAs(UnmanagedType.Bool)]
|
[return: MarshalAs(UnmanagedType.Bool)]
|
||||||
private static extern bool VirtualProtect(void* lpAddress, nuint dwSize, uint flNewProtect, out uint lpflOldProtect);
|
private static extern bool VirtualProtect(void* lpAddress, nuint dwSize, uint flNewProtect, out uint lpflOldProtect);
|
||||||
|
|
||||||
|
[DllImport("kernel32.dll")]
|
||||||
|
private static extern nuint VirtualQuery(void* lpAddress, out MemoryBasicInformation64 lpBuffer, nuint dwLength);
|
||||||
|
|
||||||
[DllImport("kernel32.dll")]
|
[DllImport("kernel32.dll")]
|
||||||
private static extern void FlushInstructionCache(void* hProcess, void* lpBaseAddress, nuint dwSize);
|
private static extern void FlushInstructionCache(void* hProcess, void* lpBaseAddress, nuint dwSize);
|
||||||
|
|
||||||
@@ -351,6 +354,11 @@ public sealed unsafe class PhysicalVirtualMemory : IVirtualMemory, IDisposable
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!EnsureRangeCommitted((ulong)srcPtr, (ulong)destination.Length, region))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (!TryTemporarilyProtectForRead((ulong)srcPtr, (ulong)destination.Length, region, out var touchedPages))
|
if (!TryTemporarilyProtectForRead((ulong)srcPtr, (ulong)destination.Length, region, out var touchedPages))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
@@ -389,6 +397,11 @@ public sealed unsafe class PhysicalVirtualMemory : IVirtualMemory, IDisposable
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!EnsureRangeCommitted((ulong)destPtr, (ulong)source.Length, region))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (!VirtualProtect(destPtr, (nuint)source.Length, PAGE_EXECUTE_READWRITE, out var oldProtect))
|
if (!VirtualProtect(destPtr, (nuint)source.Length, PAGE_EXECUTE_READWRITE, out var oldProtect))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
@@ -494,6 +507,48 @@ public sealed unsafe class PhysicalVirtualMemory : IVirtualMemory, IDisposable
|
|||||||
return protection is PAGE_EXECUTE or PAGE_EXECUTE_READ or PAGE_EXECUTE_READWRITE or PAGE_EXECUTE_WRITECOPY;
|
return protection is PAGE_EXECUTE or PAGE_EXECUTE_READ or PAGE_EXECUTE_READWRITE or PAGE_EXECUTE_WRITECOPY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static uint GetCommitProtection(MemoryRegion region)
|
||||||
|
{
|
||||||
|
return region.IsExecutable ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static unsafe bool EnsureRangeCommitted(ulong address, ulong size, MemoryRegion region)
|
||||||
|
{
|
||||||
|
if (size == 0 || !region.IsReservedOnly)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
var startPage = AlignDown(address, PageSize);
|
||||||
|
var endPage = AlignUp(address + size, PageSize);
|
||||||
|
var commitProtection = GetCommitProtection(region);
|
||||||
|
|
||||||
|
for (var pageAddress = startPage; pageAddress < endPage; pageAddress += PageSize)
|
||||||
|
{
|
||||||
|
if (VirtualQuery((void*)pageAddress, out var info, (nuint)sizeof(MemoryBasicInformation64)) == 0)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (info.State == MEM_COMMIT)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (info.State != MEM_RESERVE)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (VirtualAlloc((void*)pageAddress, (nuint)PageSize, MEM_COMMIT, commitProtection) == null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
private bool TryTemporarilyProtectForRead(
|
private bool TryTemporarilyProtectForRead(
|
||||||
ulong address,
|
ulong address,
|
||||||
ulong size,
|
ulong size,
|
||||||
@@ -558,4 +613,17 @@ public sealed unsafe class PhysicalVirtualMemory : IVirtualMemory, IDisposable
|
|||||||
public bool IsReservedOnly { get; set; }
|
public bool IsReservedOnly { get; set; }
|
||||||
public uint Protection { get; set; }
|
public uint Protection { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private struct MemoryBasicInformation64
|
||||||
|
{
|
||||||
|
public ulong BaseAddress;
|
||||||
|
public ulong AllocationBase;
|
||||||
|
public uint AllocationProtect;
|
||||||
|
public uint Alignment1;
|
||||||
|
public ulong RegionSize;
|
||||||
|
public uint State;
|
||||||
|
public uint Protect;
|
||||||
|
public uint Type;
|
||||||
|
public uint Alignment2;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
using SharpEmu.HLE;
|
using SharpEmu.HLE;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
|
||||||
namespace SharpEmu.Libs.Kernel;
|
namespace SharpEmu.Libs.Kernel;
|
||||||
|
|
||||||
@@ -258,14 +259,14 @@ public static class KernelPthreadCompatExports
|
|||||||
ExportName = "scePthreadCondSignal",
|
ExportName = "scePthreadCondSignal",
|
||||||
Target = Generation.Gen4 | Generation.Gen5,
|
Target = Generation.Gen4 | Generation.Gen5,
|
||||||
LibraryName = "libKernel")]
|
LibraryName = "libKernel")]
|
||||||
public static int PthreadCondSignal(CpuContext ctx) => PthreadCondSignalCore(ctx[CpuRegister.Rdi], broadcast: false);
|
public static int PthreadCondSignal(CpuContext ctx) => PthreadCondSignalCore(ctx, ctx[CpuRegister.Rdi], broadcast: false);
|
||||||
|
|
||||||
[SysAbiExport(
|
[SysAbiExport(
|
||||||
Nid = "JGgj7Uvrl+A",
|
Nid = "JGgj7Uvrl+A",
|
||||||
ExportName = "scePthreadCondBroadcast",
|
ExportName = "scePthreadCondBroadcast",
|
||||||
Target = Generation.Gen4 | Generation.Gen5,
|
Target = Generation.Gen4 | Generation.Gen5,
|
||||||
LibraryName = "libKernel")]
|
LibraryName = "libKernel")]
|
||||||
public static int PthreadCondBroadcast(CpuContext ctx) => PthreadCondSignalCore(ctx[CpuRegister.Rdi], broadcast: true);
|
public static int PthreadCondBroadcast(CpuContext ctx) => PthreadCondSignalCore(ctx, ctx[CpuRegister.Rdi], broadcast: true);
|
||||||
|
|
||||||
[SysAbiExport(
|
[SysAbiExport(
|
||||||
Nid = "Op8TBGY5KHg",
|
Nid = "Op8TBGY5KHg",
|
||||||
@@ -279,7 +280,7 @@ public static class KernelPthreadCompatExports
|
|||||||
ExportName = "pthread_cond_broadcast",
|
ExportName = "pthread_cond_broadcast",
|
||||||
Target = Generation.Gen4 | Generation.Gen5,
|
Target = Generation.Gen4 | Generation.Gen5,
|
||||||
LibraryName = "libKernel")]
|
LibraryName = "libKernel")]
|
||||||
public static int PosixPthreadCondBroadcast(CpuContext ctx) => PthreadCondSignalCore(ctx[CpuRegister.Rdi], broadcast: true);
|
public static int PosixPthreadCondBroadcast(CpuContext ctx) => PthreadCondSignalCore(ctx, ctx[CpuRegister.Rdi], broadcast: true);
|
||||||
|
|
||||||
[SysAbiExport(
|
[SysAbiExport(
|
||||||
Nid = "m5-2bsNfv7s",
|
Nid = "m5-2bsNfv7s",
|
||||||
@@ -606,7 +607,7 @@ public static class KernelPthreadCompatExports
|
|||||||
return mutexAddress;
|
return mutexAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool TryResolveMutexState(CpuContext ctx, ulong mutexAddress, bool createIfZero, out ulong resolvedAddress, out PthreadMutexState? state)
|
private static bool TryResolveMutexState(CpuContext ctx, ulong mutexAddress, bool createIfZero, out ulong resolvedAddress, [NotNullWhen(true)] out PthreadMutexState? state)
|
||||||
{
|
{
|
||||||
resolvedAddress = 0;
|
resolvedAddress = 0;
|
||||||
state = null;
|
state = null;
|
||||||
@@ -739,7 +740,7 @@ public static class KernelPthreadCompatExports
|
|||||||
return condAddress;
|
return condAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool TryResolveCondState(CpuContext? ctx, ulong condAddress, bool createIfZero, out ulong resolvedAddress, out PthreadCondState? state)
|
private static bool TryResolveCondState(CpuContext? ctx, ulong condAddress, bool createIfZero, out ulong resolvedAddress, [NotNullWhen(true)] out PthreadCondState? state)
|
||||||
{
|
{
|
||||||
resolvedAddress = 0;
|
resolvedAddress = 0;
|
||||||
state = null;
|
state = null;
|
||||||
@@ -901,14 +902,14 @@ public static class KernelPthreadCompatExports
|
|||||||
return waitResult;
|
return waitResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int PthreadCondSignalCore(ulong condAddress, bool broadcast)
|
private static int PthreadCondSignalCore(CpuContext ctx, ulong condAddress, bool broadcast)
|
||||||
{
|
{
|
||||||
if (condAddress == 0)
|
if (condAddress == 0)
|
||||||
{
|
{
|
||||||
return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_INVALID_ARGUMENT;
|
return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_INVALID_ARGUMENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!TryResolveCondState(null, condAddress, createIfZero: false, out _, out var state))
|
if (!TryResolveCondState(ctx, condAddress, createIfZero: true, out _, out var state))
|
||||||
{
|
{
|
||||||
return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_NOT_FOUND;
|
return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_NOT_FOUND;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ using SharpEmu.HLE;
|
|||||||
using System.Buffers.Binary;
|
using System.Buffers.Binary;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
|
||||||
namespace SharpEmu.Libs.Kernel;
|
namespace SharpEmu.Libs.Kernel;
|
||||||
|
|
||||||
@@ -928,7 +929,7 @@ public static class KernelPthreadExtendedCompatExports
|
|||||||
return rwlockAddress;
|
return rwlockAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool TryResolveRwlockState(CpuContext ctx, ulong rwlockAddress, bool createIfZero, out ulong resolvedAddress, out ReaderWriterLockSlim? rwlock)
|
private static bool TryResolveRwlockState(CpuContext ctx, ulong rwlockAddress, bool createIfZero, out ulong resolvedAddress, [NotNullWhen(true)] out ReaderWriterLockSlim? rwlock)
|
||||||
{
|
{
|
||||||
resolvedAddress = 0;
|
resolvedAddress = 0;
|
||||||
rwlock = null;
|
rwlock = null;
|
||||||
|
|||||||
Reference in New Issue
Block a user