Files
PURErat-crack-scode/decompiled/Libraries/microsoft.codeanalysis/Microsoft.CodeAnalysis.Debugging/CustomDebugInfoReader.cs
T

608 lines
16 KiB
C#
Raw Normal View History

2026-08-27 10:56:38 -06:00
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Globalization;
using System.Text;
using Microsoft.CodeAnalysis.PooledObjects;
namespace Microsoft.CodeAnalysis.Debugging;
internal static class CustomDebugInfoReader
{
private static void ReadGlobalHeader(byte[] bytes, ref int offset, out byte version, out byte count)
{
version = bytes[offset];
count = bytes[offset + 1];
offset += 4;
}
private static void ReadRecordHeader(byte[] bytes, ref int offset, out byte version, out CustomDebugInfoKind kind, out int size, out int alignmentSize)
{
version = bytes[offset];
kind = (CustomDebugInfoKind)bytes[offset + 1];
alignmentSize = bytes[offset + 3];
size = BitConverter.ToInt32(bytes, offset + 4);
offset += 8;
}
public static ImmutableArray<byte> TryGetCustomDebugInfoRecord(byte[] customDebugInfo, CustomDebugInfoKind recordKind)
{
foreach (CustomDebugInfoRecord customDebugInfoRecord in GetCustomDebugInfoRecords(customDebugInfo))
{
if (customDebugInfoRecord.Kind == recordKind)
{
return customDebugInfoRecord.Data;
}
}
return default(ImmutableArray<byte>);
}
public static IEnumerable<CustomDebugInfoRecord> GetCustomDebugInfoRecords(byte[] customDebugInfo)
{
if (customDebugInfo.Length < 4)
{
throw new InvalidOperationException("Invalid header.");
}
int offset = 0;
ReadGlobalHeader(customDebugInfo, ref offset, out var version, out var _);
if (version != 4)
{
yield break;
}
int bodySize;
for (; offset <= customDebugInfo.Length - 8; offset += bodySize)
{
ReadRecordHeader(customDebugInfo, ref offset, out var version2, out var kind, out var size, out var alignmentSize);
if (size < 8)
{
throw new InvalidOperationException("Invalid header.");
}
if (kind - 6 > CustomDebugInfoKind.ForwardModuleInfo)
{
alignmentSize = 0;
}
bodySize = size - 8;
if (offset > customDebugInfo.Length - bodySize || alignmentSize > 3 || alignmentSize > bodySize)
{
throw new InvalidOperationException("Invalid header.");
}
yield return new CustomDebugInfoRecord(kind, version2, ImmutableArray.Create(customDebugInfo, offset, bodySize - alignmentSize));
}
}
public static ImmutableArray<short> DecodeUsingRecord(ImmutableArray<byte> bytes)
{
int offset = 0;
short num = ReadInt16(bytes, ref offset);
ArrayBuilder<short> instance = ArrayBuilder<short>.GetInstance(num);
for (int i = 0; i < num; i++)
{
instance.Add(ReadInt16(bytes, ref offset));
}
return instance.ToImmutableAndFree();
}
public static int DecodeForwardRecord(ImmutableArray<byte> bytes)
{
int offset = 0;
return ReadInt32(bytes, ref offset);
}
public static int DecodeForwardToModuleRecord(ImmutableArray<byte> bytes)
{
int offset = 0;
return ReadInt32(bytes, ref offset);
}
public static ImmutableArray<StateMachineHoistedLocalScope> DecodeStateMachineHoistedLocalScopesRecord(ImmutableArray<byte> bytes)
{
int offset = 0;
int num = ReadInt32(bytes, ref offset);
ArrayBuilder<StateMachineHoistedLocalScope> instance = ArrayBuilder<StateMachineHoistedLocalScope>.GetInstance(num);
for (int i = 0; i < num; i++)
{
int num2 = ReadInt32(bytes, ref offset);
int num3 = ReadInt32(bytes, ref offset);
if (num2 != 0 || num3 != 0)
{
num3++;
}
instance.Add(new StateMachineHoistedLocalScope(num2, num3));
}
return instance.ToImmutableAndFree();
}
public static string DecodeForwardIteratorRecord(ImmutableArray<byte> bytes)
{
int offset = 0;
PooledStringBuilder instance = PooledStringBuilder.GetInstance();
StringBuilder builder = instance.Builder;
while (offset < bytes.Length)
{
char c = (char)ReadInt16(bytes, ref offset);
if (c == '\0')
{
break;
}
builder.Append(c);
}
return instance.ToStringAndFree();
}
public static ImmutableArray<DynamicLocalInfo> DecodeDynamicLocalsRecord(ImmutableArray<byte> bytes)
{
ArrayBuilder<bool> instance = ArrayBuilder<bool>.GetInstance(64);
PooledStringBuilder instance2 = PooledStringBuilder.GetInstance();
StringBuilder builder = instance2.Builder;
int offset = 0;
int num = ReadInt32(bytes, ref offset);
ArrayBuilder<DynamicLocalInfo> instance3 = ArrayBuilder<DynamicLocalInfo>.GetInstance(num);
for (int i = 0; i < num; i++)
{
for (int j = 0; j < 64; j++)
{
instance.Add(ReadByte(bytes, ref offset) != 0);
}
int num2 = ReadInt32(bytes, ref offset);
if (num2 < instance.Count)
{
instance.Count = num2;
}
int slotId = ReadInt32(bytes, ref offset);
int num3 = offset + 128;
while (offset < num3)
{
char c = (char)ReadInt16(bytes, ref offset);
if (c == '\0')
{
offset = num3;
break;
}
builder.Append(c);
}
instance3.Add(new DynamicLocalInfo(instance.ToImmutable(), slotId, builder.ToString()));
instance.Clear();
builder.Clear();
}
instance.Free();
instance2.Free();
return instance3.ToImmutableAndFree();
}
public static ImmutableArray<TupleElementNamesInfo> DecodeTupleElementNamesRecord(ImmutableArray<byte> bytes)
{
int offset = 0;
int num = ReadInt32(bytes, ref offset);
ArrayBuilder<TupleElementNamesInfo> instance = ArrayBuilder<TupleElementNamesInfo>.GetInstance(num);
for (int i = 0; i < num; i++)
{
instance.Add(DecodeTupleElementNamesInfo(bytes, ref offset));
}
return instance.ToImmutableAndFree();
}
private static TupleElementNamesInfo DecodeTupleElementNamesInfo(ImmutableArray<byte> bytes, ref int offset)
{
int num = ReadInt32(bytes, ref offset);
ArrayBuilder<string> instance = ArrayBuilder<string>.GetInstance(num);
for (int i = 0; i < num; i++)
{
string text = ReadUtf8String(bytes, ref offset);
instance.Add(string.IsNullOrEmpty(text) ? null : text);
}
int slotIndex = ReadInt32(bytes, ref offset);
int scopeStart = ReadInt32(bytes, ref offset);
int scopeEnd = ReadInt32(bytes, ref offset);
string localName = ReadUtf8String(bytes, ref offset);
return new TupleElementNamesInfo(instance.ToImmutableAndFree(), slotIndex, localName, scopeStart, scopeEnd);
}
public static ImmutableArray<ImmutableArray<string>> GetCSharpGroupedImportStrings<TArg>(int methodToken, TArg arg, Func<int, TArg, byte[]> getMethodCustomDebugInfo, Func<int, TArg, ImmutableArray<string>> getMethodImportStrings, out ImmutableArray<string> externAliasStrings)
{
externAliasStrings = default(ImmutableArray<string>);
ImmutableArray<short> immutableArray = default(ImmutableArray<short>);
bool flag = false;
while (true)
{
IL_0012:
byte[] array = getMethodCustomDebugInfo(methodToken, arg);
if (array == null)
{
return default(ImmutableArray<ImmutableArray<string>>);
}
foreach (CustomDebugInfoRecord customDebugInfoRecord in GetCustomDebugInfoRecords(array))
{
switch (customDebugInfoRecord.Kind)
{
case CustomDebugInfoKind.UsingGroups:
if (!immutableArray.IsDefault)
{
throw new InvalidOperationException($"Expected at most one Using record for method {FormatMethodToken(methodToken)}");
}
immutableArray = DecodeUsingRecord(customDebugInfoRecord.Data);
break;
case CustomDebugInfoKind.ForwardMethodInfo:
if (!externAliasStrings.IsDefault)
{
throw new InvalidOperationException($"Did not expect both Forward and ForwardToModule records for method {FormatMethodToken(methodToken)}");
}
methodToken = DecodeForwardRecord(customDebugInfoRecord.Data);
if (!flag)
{
flag = true;
goto IL_0012;
}
break;
case CustomDebugInfoKind.ForwardModuleInfo:
{
if (!externAliasStrings.IsDefault)
{
throw new InvalidOperationException($"Expected at most one ForwardToModule record for method {FormatMethodToken(methodToken)}");
}
int arg2 = DecodeForwardToModuleRecord(customDebugInfoRecord.Data);
ImmutableArray<string> immutableArray2 = getMethodImportStrings(arg2, arg);
ArrayBuilder<string> instance = ArrayBuilder<string>.GetInstance();
ImmutableArray<string>.Enumerator enumerator2 = immutableArray2.GetEnumerator();
while (enumerator2.MoveNext())
{
string current2 = enumerator2.Current;
if (IsCSharpExternAliasInfo(current2))
{
instance.Add(current2);
}
}
externAliasStrings = instance.ToImmutableAndFree();
break;
}
}
}
break;
}
if (immutableArray.IsDefault)
{
return default(ImmutableArray<ImmutableArray<string>>);
}
ImmutableArray<string> immutableArray3 = getMethodImportStrings(methodToken, arg);
ArrayBuilder<ImmutableArray<string>> instance2 = ArrayBuilder<ImmutableArray<string>>.GetInstance(immutableArray.Length);
ArrayBuilder<string> instance3 = ArrayBuilder<string>.GetInstance();
int i = 0;
ImmutableArray<short>.Enumerator enumerator3 = immutableArray.GetEnumerator();
while (enumerator3.MoveNext())
{
short current3 = enumerator3.Current;
int num = 0;
while (num < current3)
{
if (i >= immutableArray3.Length)
{
throw new InvalidOperationException($"Group size indicates more imports than there are import strings (method {FormatMethodToken(methodToken)}).");
}
string text = immutableArray3[i];
if (IsCSharpExternAliasInfo(text))
{
throw new InvalidOperationException($"Encountered extern alias info before all import strings were consumed (method {FormatMethodToken(methodToken)}).");
}
instance3.Add(text);
num++;
i++;
}
instance2.Add(instance3.ToImmutable());
instance3.Clear();
}
if (externAliasStrings.IsDefault)
{
for (; i < immutableArray3.Length; i++)
{
string text2 = immutableArray3[i];
if (!IsCSharpExternAliasInfo(text2))
{
throw new InvalidOperationException($"Expected only extern alias info strings after consuming the indicated number of imports (method {FormatMethodToken(methodToken)}).");
}
instance3.Add(text2);
}
externAliasStrings = instance3.ToImmutableAndFree();
}
else
{
instance3.Free();
if (i < immutableArray3.Length)
{
throw new InvalidOperationException($"Group size indicates fewer imports than there are import strings (method {FormatMethodToken(methodToken)}).");
}
}
return instance2.ToImmutableAndFree();
}
public static ImmutableArray<string> GetVisualBasicImportStrings<TArg>(int methodToken, TArg arg, Func<int, TArg, ImmutableArray<string>> getMethodImportStrings)
{
ImmutableArray<string> result = getMethodImportStrings(methodToken, arg);
if (result.IsEmpty)
{
return ImmutableArray<string>.Empty;
}
string text = result[0];
if (text.Length >= 2 && text[0] == '@')
{
char c = text[1];
if (c >= '0' && c <= '9' && int.TryParse(text.Substring(1), NumberStyles.None, CultureInfo.InvariantCulture, out var result2))
{
result = getMethodImportStrings(result2, arg);
}
}
return result;
}
private static int ReadInt32(ImmutableArray<byte> bytes, ref int offset)
{
int num = offset;
if (num + 4 > bytes.Length)
{
throw new InvalidOperationException("Read out of buffer.");
}
offset += 4;
return bytes[num] | (bytes[num + 1] << 8) | (bytes[num + 2] << 16) | (bytes[num + 3] << 24);
}
private static short ReadInt16(ImmutableArray<byte> bytes, ref int offset)
{
int num = offset;
if (num + 2 > bytes.Length)
{
throw new InvalidOperationException("Read out of buffer.");
}
offset += 2;
return (short)(bytes[num] | (bytes[num + 1] << 8));
}
private static byte ReadByte(ImmutableArray<byte> bytes, ref int offset)
{
int num = offset;
if (num + 1 > bytes.Length)
{
throw new InvalidOperationException("Read out of buffer.");
}
offset++;
return bytes[num];
}
private static bool IsCSharpExternAliasInfo(string import)
{
if (import.Length > 0)
{
return import[0] == 'Z';
}
return false;
}
public static bool TryParseCSharpImportString(string import, out string alias, out string externAlias, out string target, out ImportTargetKind kind)
{
alias = null;
externAlias = null;
target = null;
kind = ImportTargetKind.Namespace;
if (string.IsNullOrEmpty(import))
{
return false;
}
switch (import[0])
{
case 'U':
alias = null;
externAlias = null;
target = import.Substring(1);
kind = ImportTargetKind.Namespace;
return true;
case 'E':
if (!TrySplit(import, 1, ' ', out target, out externAlias))
{
return false;
}
alias = null;
kind = ImportTargetKind.Namespace;
return true;
case 'T':
alias = null;
externAlias = null;
target = import.Substring(1);
kind = ImportTargetKind.Type;
return true;
case 'A':
if (!TrySplit(import, 1, ' ', out alias, out target))
{
return false;
}
switch (target[0])
{
case 'U':
kind = ImportTargetKind.Namespace;
target = target.Substring(1);
externAlias = null;
return true;
case 'T':
kind = ImportTargetKind.Type;
target = target.Substring(1);
externAlias = null;
return true;
case 'E':
kind = ImportTargetKind.Namespace;
if (!TrySplit(target, 1, ' ', out target, out externAlias))
{
return false;
}
return true;
default:
return false;
}
case 'X':
externAlias = null;
alias = import.Substring(1);
target = null;
kind = ImportTargetKind.Assembly;
return true;
case 'Z':
if (!TrySplit(import, 1, ' ', out alias, out target))
{
return false;
}
externAlias = null;
kind = ImportTargetKind.Assembly;
return true;
default:
return false;
}
}
public static bool TryParseVisualBasicImportString(string import, out string alias, out string target, out ImportTargetKind kind, out VBImportScopeKind scope)
{
alias = null;
target = null;
kind = ImportTargetKind.Namespace;
scope = VBImportScopeKind.Unspecified;
if (import == null)
{
return false;
}
if (import.Length == 0)
{
alias = null;
target = import;
kind = ImportTargetKind.CurrentNamespace;
scope = VBImportScopeKind.Unspecified;
return true;
}
int num = 0;
switch (import[num])
{
case '#':
case '$':
case '&':
alias = null;
target = import;
kind = ImportTargetKind.Defunct;
scope = VBImportScopeKind.Unspecified;
return true;
case '*':
num++;
alias = null;
target = import.Substring(num);
kind = ImportTargetKind.DefaultNamespace;
scope = VBImportScopeKind.Unspecified;
return true;
case '@':
num++;
if (num >= import.Length)
{
return false;
}
scope = VBImportScopeKind.Unspecified;
switch (import[num])
{
case 'F':
scope = VBImportScopeKind.File;
num++;
break;
case 'P':
scope = VBImportScopeKind.Project;
num++;
break;
}
if (num >= import.Length)
{
return false;
}
switch (import[num])
{
case 'A':
num++;
if (import[num] != ':')
{
return false;
}
num++;
if (!TrySplit(import, num, '=', out alias, out target))
{
return false;
}
kind = ImportTargetKind.NamespaceOrType;
return true;
case 'X':
num++;
if (import[num] != ':')
{
return false;
}
num++;
if (!TrySplit(import, num, '=', out alias, out target))
{
return false;
}
kind = ImportTargetKind.XmlNamespace;
return true;
case 'T':
num++;
if (import[num] != ':')
{
return false;
}
num++;
alias = null;
target = import.Substring(num);
kind = ImportTargetKind.Type;
return true;
case ':':
num++;
alias = null;
target = import.Substring(num);
kind = ImportTargetKind.Namespace;
return true;
default:
alias = null;
target = import.Substring(num);
kind = ImportTargetKind.MethodToken;
return true;
}
default:
alias = null;
target = import;
kind = ImportTargetKind.CurrentNamespace;
scope = VBImportScopeKind.Unspecified;
return true;
}
}
private static bool TrySplit(string input, int offset, char separator, out string before, out string after)
{
int num = input.IndexOf(separator, offset);
if (offset <= num && num < input.Length)
{
before = input.Substring(offset, num - offset);
after = ((num + 1 == input.Length) ? "" : input.Substring(num + 1));
return true;
}
before = null;
after = null;
return false;
}
private static string FormatMethodToken(int methodToken)
{
return $"0x{methodToken:x8}";
}
private static string ReadUtf8String(ImmutableArray<byte> bytes, ref int offset)
{
ArrayBuilder<byte> instance = ArrayBuilder<byte>.GetInstance();
while (true)
{
byte b = ReadByte(bytes, ref offset);
if (b == 0)
{
break;
}
instance.Add(b);
}
byte[] array = instance.ToArrayAndFree();
return Encoding.UTF8.GetString(array, 0, array.Length);
}
}