core: page-aware TryReadUtf8Z and unify exit/_exit handling (#57)

Read guest C strings in page-bounded chunks without heap allocations.
Return false when the buffer fills without a null terminator. Route exit
and _exit through RequestProcessExit.
This commit is contained in:
Mike Saito
2026-07-11 15:42:43 +03:00
committed by GitHub
parent c4326a1143
commit 9ddc09ea91
2 changed files with 36 additions and 22 deletions

View File

@@ -52,14 +52,7 @@ public static class KernelExports
ExportName = "exit",
Target = Generation.Gen4 | Generation.Gen5,
LibraryName = "libKernel")]
public static int Exit(CpuContext ctx)
{
var status = unchecked((int)ctx[CpuRegister.Rdi]);
Console.Error.WriteLine($"[LOADER][INFO] exit(status={status})");
GuestThreadExecution.RequestCurrentEntryExit("exit", status);
ctx[CpuRegister.Rax] = unchecked((ulong)status);
return (int)OrbisGen2Result.ORBIS_GEN2_OK;
}
public static int Exit(CpuContext ctx) => RequestProcessExit(ctx, "exit");
[SysAbiExport(
Nid = "XKRegsFpEpk",
@@ -172,11 +165,7 @@ public static class KernelExports
ExportName = "_exit",
Target = Generation.Gen4 | Generation.Gen5,
LibraryName = "libKernel")]
public static int UnderscoreExit(CpuContext ctx)
{
_ = ctx;
return (int)OrbisGen2Result.ORBIS_GEN2_OK;
}
public static int UnderscoreExit(CpuContext ctx) => RequestProcessExit(ctx, "_exit");
[SysAbiExport(
Nid = "Ac86z8q7T8A",
@@ -437,4 +426,13 @@ public static class KernelExports
{
return string.Equals(Environment.GetEnvironmentVariable("SHARPEMU_LOG_PTHREADS"), "1", StringComparison.Ordinal);
}
private static int RequestProcessExit(CpuContext ctx, string syscallName)
{
var status = unchecked((int)ctx[CpuRegister.Rdi]);
Console.Error.WriteLine($"[LOADER][INFO] {syscallName}(status={status})");
GuestThreadExecution.RequestCurrentEntryExit(syscallName, status);
ctx[CpuRegister.Rax] = unchecked((ulong)status);
return (int)OrbisGen2Result.ORBIS_GEN2_OK;
}
}

View File

@@ -1469,26 +1469,42 @@ public static class KernelRuntimeCompatExports
return false;
}
var bytes = new List<byte>(Math.Min(maxLength, 64));
Span<byte> one = stackalloc byte[1];
for (var i = 0; i < maxLength; i++)
const int pageSize = 4096;
const int inlineChunkSize = 64;
Span<byte> buffer = stackalloc byte[Math.Min(maxLength, 512)];
var length = 0;
for (var offset = 0; offset < maxLength && length < buffer.Length;)
{
if (!ctx.Memory.TryRead(address + (ulong)i, one))
var current = address + (ulong)offset;
var pageRemaining = pageSize - (int)(current & (pageSize - 1));
var chunkSize = Math.Min(
buffer.Length - length,
Math.Min(maxLength - offset, Math.Min(inlineChunkSize, pageRemaining)));
if (chunkSize <= 0)
{
return false;
}
if (one[0] == 0)
var chunk = buffer.Slice(length, chunkSize);
if (!ctx.Memory.TryRead(current, chunk))
{
value = Encoding.UTF8.GetString(bytes.ToArray());
return false;
}
var nulIndex = chunk.IndexOf((byte)0);
if (nulIndex >= 0)
{
value = Encoding.UTF8.GetString(buffer[..(length + nulIndex)]);
return true;
}
bytes.Add(one[0]);
length += chunkSize;
offset += chunkSize;
}
value = Encoding.UTF8.GetString(bytes.ToArray());
return true;
return false;
}
private static ulong GetTlsScratchAddress(CpuContext ctx, ulong offset)