// Copyright (C) 2026 SharpEmu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
using SharpEmu.HLE;
namespace SharpEmu.Libs.Kernel;
///
/// Shared formatting for opt-in kernel synchronization diagnostics.
/// Callers must gate this behind their trace flag so normal synchronization
/// paths do not allocate strings or walk guest frame chains.
///
internal static class KernelSyncTraceFormatter
{
internal static string FormatContext(CpuContext ctx)
{
_ = KernelPthreadState.TryGetCurrentThreadIdentity(out var pthread, out var identity);
var threadName = identity.Name ?? "";
var returnRip = GuestThreadExecution.TryGetCurrentImportCallFrame(out var importFrame)
? importFrame.ReturnRip
: TryReadReturnRip(ctx);
return $"thread='{threadName}' pthread=0x{pthread:X16} " +
$"gth=0x{GuestThreadExecution.CurrentGuestThreadHandle:X16} " +
$"managed={Environment.CurrentManagedThreadId} ret=0x{returnRip:X16} " +
$"frames={FormatFrameChain(ctx)}";
}
internal static string FormatCurrentThread()
{
_ = KernelPthreadState.TryGetCurrentThreadIdentity(out var pthread, out var identity);
var threadName = identity.Name ?? Thread.CurrentThread.Name ?? "";
return $"thread='{threadName}' pthread=0x{pthread:X16} " +
$"gth=0x{GuestThreadExecution.CurrentGuestThreadHandle:X16} " +
$"managed={Environment.CurrentManagedThreadId}";
}
internal static string FormatFrameChain(CpuContext ctx)
{
Span returns = stackalloc ulong[4];
var count = 0;
var frame = ctx[CpuRegister.Rbp];
while (count < returns.Length && frame != 0)
{
if (!ctx.TryReadUInt64(frame, out var nextFrame) ||
!ctx.TryReadUInt64(frame + sizeof(ulong), out var returnAddress))
{
break;
}
returns[count++] = returnAddress;
if (nextFrame <= frame || nextFrame - frame > 0x100000)
{
break;
}
frame = nextFrame;
}
return count switch
{
0 => "none",
1 => $"0x{returns[0]:X16}",
2 => $"0x{returns[0]:X16},0x{returns[1]:X16}",
3 => $"0x{returns[0]:X16},0x{returns[1]:X16},0x{returns[2]:X16}",
_ => $"0x{returns[0]:X16},0x{returns[1]:X16}," +
$"0x{returns[2]:X16},0x{returns[3]:X16}",
};
}
private static ulong TryReadReturnRip(CpuContext ctx)
{
_ = ctx.TryReadUInt64(ctx[CpuRegister.Rsp], out var returnRip);
return returnRip;
}
}