diff options
| author | TSR Berry <20988865+TSRBerry@users.noreply.github.com> | 2023-04-08 01:22:00 +0200 |
|---|---|---|
| committer | Mary <thog@protonmail.com> | 2023-04-27 23:51:14 +0200 |
| commit | cee712105850ac3385cd0091a923438167433f9f (patch) | |
| tree | 4a5274b21d8b7f938c0d0ce18736d3f2993b11b1 /src/Ryujinx.HLE/Loaders/Executables | |
| parent | cd124bda587ef09668a971fa1cac1c3f0cfc9f21 (diff) | |
Move solution and projects to src
Diffstat (limited to 'src/Ryujinx.HLE/Loaders/Executables')
| -rw-r--r-- | src/Ryujinx.HLE/Loaders/Executables/IExecutable.cs | 18 | ||||
| -rw-r--r-- | src/Ryujinx.HLE/Loaders/Executables/KipExecutable.cs | 86 | ||||
| -rw-r--r-- | src/Ryujinx.HLE/Loaders/Executables/NroExecutable.cs | 38 | ||||
| -rw-r--r-- | src/Ryujinx.HLE/Loaders/Executables/NsoExecutable.cs | 123 |
4 files changed, 265 insertions, 0 deletions
diff --git a/src/Ryujinx.HLE/Loaders/Executables/IExecutable.cs b/src/Ryujinx.HLE/Loaders/Executables/IExecutable.cs new file mode 100644 index 00000000..27479efe --- /dev/null +++ b/src/Ryujinx.HLE/Loaders/Executables/IExecutable.cs @@ -0,0 +1,18 @@ +using System; + +namespace Ryujinx.HLE.Loaders.Executables +{ + interface IExecutable + { + byte[] Program { get; } + Span<byte> Text { get; } + Span<byte> Ro { get; } + Span<byte> Data { get; } + + uint TextOffset { get; } + uint RoOffset { get; } + uint DataOffset { get; } + uint BssOffset { get; } + uint BssSize { get; } + } +}
\ No newline at end of file diff --git a/src/Ryujinx.HLE/Loaders/Executables/KipExecutable.cs b/src/Ryujinx.HLE/Loaders/Executables/KipExecutable.cs new file mode 100644 index 00000000..ad2b681c --- /dev/null +++ b/src/Ryujinx.HLE/Loaders/Executables/KipExecutable.cs @@ -0,0 +1,86 @@ +using LibHac.Common; +using LibHac.Fs; +using LibHac.Kernel; +using System; + +namespace Ryujinx.HLE.Loaders.Executables +{ + class KipExecutable : IExecutable + { + public byte[] Program { get; } + public Span<byte> Text => Program.AsSpan((int)TextOffset, (int)TextSize); + public Span<byte> Ro => Program.AsSpan((int)RoOffset, (int)RoSize); + public Span<byte> Data => Program.AsSpan((int)DataOffset, (int)DataSize); + + public uint TextOffset { get; } + public uint RoOffset { get; } + public uint DataOffset { get; } + public uint BssOffset { get; } + + public uint TextSize { get; } + public uint RoSize { get; } + public uint DataSize { get; } + public uint BssSize { get; } + + public uint[] Capabilities { get; } + public bool UsesSecureMemory { get; } + public bool Is64BitAddressSpace { get; } + public bool Is64Bit { get; } + public ulong ProgramId { get; } + public byte Priority { get; } + public int StackSize { get; } + public byte IdealCoreId { get; } + public int Version { get; } + public string Name { get; } + + public KipExecutable(in SharedRef<IStorage> inStorage) + { + KipReader reader = new KipReader(); + + reader.Initialize(in inStorage).ThrowIfFailure(); + + TextOffset = (uint)reader.Segments[0].MemoryOffset; + RoOffset = (uint)reader.Segments[1].MemoryOffset; + DataOffset = (uint)reader.Segments[2].MemoryOffset; + BssOffset = (uint)reader.Segments[3].MemoryOffset; + BssSize = (uint)reader.Segments[3].Size; + + StackSize = reader.StackSize; + + UsesSecureMemory = reader.UsesSecureMemory; + Is64BitAddressSpace = reader.Is64BitAddressSpace; + Is64Bit = reader.Is64Bit; + + ProgramId = reader.ProgramId; + Priority = reader.Priority; + IdealCoreId = reader.IdealCoreId; + Version = reader.Version; + Name = reader.Name.ToString(); + + Capabilities = new uint[32]; + + for (int index = 0; index < Capabilities.Length; index++) + { + Capabilities[index] = reader.Capabilities[index]; + } + + reader.GetSegmentSize(KipReader.SegmentType.Data, out int uncompressedSize).ThrowIfFailure(); + Program = new byte[DataOffset + uncompressedSize]; + + TextSize = DecompressSection(reader, KipReader.SegmentType.Text, TextOffset, Program); + RoSize = DecompressSection(reader, KipReader.SegmentType.Ro, RoOffset, Program); + DataSize = DecompressSection(reader, KipReader.SegmentType.Data, DataOffset, Program); + } + + private static uint DecompressSection(KipReader reader, KipReader.SegmentType segmentType, uint offset, byte[] program) + { + reader.GetSegmentSize(segmentType, out int uncompressedSize).ThrowIfFailure(); + + var span = program.AsSpan((int)offset, uncompressedSize); + + reader.ReadSegment(segmentType, span).ThrowIfFailure(); + + return (uint)uncompressedSize; + } + } +}
\ No newline at end of file diff --git a/src/Ryujinx.HLE/Loaders/Executables/NroExecutable.cs b/src/Ryujinx.HLE/Loaders/Executables/NroExecutable.cs new file mode 100644 index 00000000..621ab43b --- /dev/null +++ b/src/Ryujinx.HLE/Loaders/Executables/NroExecutable.cs @@ -0,0 +1,38 @@ +using LibHac.Fs; +using LibHac.Tools.Ro; +using System; + +namespace Ryujinx.HLE.Loaders.Executables +{ + class NroExecutable : Nro, IExecutable + { + public byte[] Program { get; } + public Span<byte> Text => Program.AsSpan((int)TextOffset, (int)Header.NroSegments[0].Size); + public Span<byte> Ro => Program.AsSpan((int)RoOffset, (int)Header.NroSegments[1].Size); + public Span<byte> Data => Program.AsSpan((int)DataOffset, (int)Header.NroSegments[2].Size); + + public uint TextOffset => Header.NroSegments[0].FileOffset; + public uint RoOffset => Header.NroSegments[1].FileOffset; + public uint DataOffset => Header.NroSegments[2].FileOffset; + public uint BssOffset => DataOffset + (uint)Data.Length; + public uint BssSize => Header.BssSize; + + public uint Mod0Offset => (uint)Start.Mod0Offset; + public uint FileSize => Header.Size; + + public ulong SourceAddress { get; private set; } + public ulong BssAddress { get; private set; } + + public NroExecutable(IStorage inStorage, ulong sourceAddress = 0, ulong bssAddress = 0) : base(inStorage) + { + Program = new byte[FileSize]; + + SourceAddress = sourceAddress; + BssAddress = bssAddress; + + OpenNroSegment(NroSegmentType.Text, false).Read(0, Text); + OpenNroSegment(NroSegmentType.Ro , false).Read(0, Ro); + OpenNroSegment(NroSegmentType.Data, false).Read(0, Data); + } + } +}
\ No newline at end of file diff --git a/src/Ryujinx.HLE/Loaders/Executables/NsoExecutable.cs b/src/Ryujinx.HLE/Loaders/Executables/NsoExecutable.cs new file mode 100644 index 00000000..d695449b --- /dev/null +++ b/src/Ryujinx.HLE/Loaders/Executables/NsoExecutable.cs @@ -0,0 +1,123 @@ +using LibHac.Common.FixedArrays; +using LibHac.Fs; +using LibHac.Loader; +using LibHac.Tools.FsSystem; +using Ryujinx.Common.Logging; +using System; +using System.Text; +using System.Text.RegularExpressions; + +namespace Ryujinx.HLE.Loaders.Executables +{ + partial class NsoExecutable : IExecutable + { + public byte[] Program { get; } + public Span<byte> Text => Program.AsSpan((int)TextOffset, (int)TextSize); + public Span<byte> Ro => Program.AsSpan((int)RoOffset, (int)RoSize); + public Span<byte> Data => Program.AsSpan((int)DataOffset, (int)DataSize); + + public uint TextOffset { get; } + public uint RoOffset { get; } + public uint DataOffset { get; } + public uint BssOffset => DataOffset + (uint)Data.Length; + + public uint TextSize { get; } + public uint RoSize { get; } + public uint DataSize { get; } + public uint BssSize { get; } + + public string Name; + public Array32<byte> BuildId; + + [GeneratedRegex(@"[a-z]:[\\/][ -~]{5,}\.nss", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant)] + private static partial Regex ModuleRegex(); + [GeneratedRegex(@"sdk_version: ([0-9.]*)")] + private static partial Regex FsSdkRegex(); + [GeneratedRegex(@"SDK MW[ -~]*")] + private static partial Regex SdkMwRegex(); + + public NsoExecutable(IStorage inStorage, string name = null) + { + NsoReader reader = new NsoReader(); + + reader.Initialize(inStorage.AsFile(OpenMode.Read)).ThrowIfFailure(); + + TextOffset = reader.Header.Segments[0].MemoryOffset; + RoOffset = reader.Header.Segments[1].MemoryOffset; + DataOffset = reader.Header.Segments[2].MemoryOffset; + BssSize = reader.Header.BssSize; + + reader.GetSegmentSize(NsoReader.SegmentType.Data, out uint uncompressedSize).ThrowIfFailure(); + + Program = new byte[DataOffset + uncompressedSize]; + + TextSize = DecompressSection(reader, NsoReader.SegmentType.Text, TextOffset); + RoSize = DecompressSection(reader, NsoReader.SegmentType.Ro, RoOffset); + DataSize = DecompressSection(reader, NsoReader.SegmentType.Data, DataOffset); + + Name = name; + BuildId = reader.Header.ModuleId; + + PrintRoSectionInfo(); + } + + private uint DecompressSection(NsoReader reader, NsoReader.SegmentType segmentType, uint offset) + { + reader.GetSegmentSize(segmentType, out uint uncompressedSize).ThrowIfFailure(); + + var span = Program.AsSpan((int)offset, (int)uncompressedSize); + + reader.ReadSegment(segmentType, span).ThrowIfFailure(); + + return uncompressedSize; + } + + private void PrintRoSectionInfo() + { + string rawTextBuffer = Encoding.ASCII.GetString(Ro); + StringBuilder stringBuilder = new StringBuilder(); + + string modulePath = null; + + if (BitConverter.ToInt32(Ro.Slice(0, 4)) == 0) + { + int length = BitConverter.ToInt32(Ro.Slice(4, 4)); + if (length > 0) + { + modulePath = Encoding.UTF8.GetString(Ro.Slice(8, length)); + } + } + + if (string.IsNullOrEmpty(modulePath)) + { + Match moduleMatch = ModuleRegex().Match(rawTextBuffer); + if (moduleMatch.Success) + { + modulePath = moduleMatch.Value; + } + } + + stringBuilder.AppendLine($" Module: {modulePath}"); + + Match fsSdkMatch = FsSdkRegex().Match(rawTextBuffer); + if (fsSdkMatch.Success) + { + stringBuilder.AppendLine($" FS SDK Version: {fsSdkMatch.Value.Replace("sdk_version: ", "")}"); + } + + MatchCollection sdkMwMatches = SdkMwRegex().Matches(rawTextBuffer); + if (sdkMwMatches.Count != 0) + { + string libHeader = " SDK Libraries: "; + string libContent = string.Join($"\n{new string(' ', libHeader.Length)}", sdkMwMatches); + + stringBuilder.AppendLine($"{libHeader}{libContent}"); + } + + if (stringBuilder.Length > 0) + { + Logger.Info?.Print(LogClass.Loader, $"{Name}:\n{stringBuilder.ToString().TrimEnd('\r', '\n')}"); + } + } + } +}
\ No newline at end of file |
