Files
2026-08-27 10:56:38 -06:00

647 lines
14 KiB
C#

using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
namespace Microsoft.DiaSymReader;
internal sealed class SymUnmanagedWriterImpl : SymUnmanagedWriter
{
private static readonly object s_zeroInt32 = 0;
private ISymUnmanagedWriter5 _symWriter;
private readonly ComMemoryStream _pdbStream;
private readonly List<ISymUnmanagedDocumentWriter> _documentWriters;
private readonly string _symWriterModuleName;
private bool _disposed;
public override int DocumentTableCapacity
{
get
{
return _documentWriters.Capacity;
}
set
{
if (value > _documentWriters.Count)
{
_documentWriters.Capacity = value;
}
}
}
internal SymUnmanagedWriterImpl(ComMemoryStream pdbStream, ISymUnmanagedWriter5 symWriter, string symWriterModuleName)
{
_pdbStream = pdbStream;
_symWriter = symWriter;
_documentWriters = new List<ISymUnmanagedDocumentWriter>();
_symWriterModuleName = symWriterModuleName;
}
private ISymUnmanagedWriter5 GetSymWriter()
{
return _symWriter ?? throw _disposed ? new ObjectDisposedException("SymUnmanagedWriterImpl") : new InvalidOperationException();
}
private ISymUnmanagedWriter8 GetSymWriter8()
{
if (!(GetSymWriter() is ISymUnmanagedWriter8 result))
{
throw PdbWritingException(new NotSupportedException());
}
return result;
}
private Exception PdbWritingException(Exception inner)
{
return new SymUnmanagedWriterException(inner, _symWriterModuleName);
}
public override void WriteTo(Stream stream)
{
if (stream == null)
{
throw new ArgumentNullException("stream");
}
CloseSymWriter();
try
{
_pdbStream.CopyTo(stream);
}
catch (Exception inner)
{
throw PdbWritingException(inner);
}
}
public override void Dispose()
{
DisposeImpl();
GC.SuppressFinalize(this);
}
~SymUnmanagedWriterImpl()
{
DisposeImpl();
}
private void DisposeImpl()
{
try
{
CloseSymWriter();
}
catch
{
}
_disposed = true;
}
private void CloseSymWriter()
{
ISymUnmanagedWriter5 symUnmanagedWriter = Interlocked.Exchange(ref _symWriter, null);
if (symUnmanagedWriter == null)
{
return;
}
try
{
symUnmanagedWriter.Close();
}
catch (Exception inner)
{
throw PdbWritingException(inner);
}
finally
{
_documentWriters.Clear();
}
}
public override IEnumerable<ArraySegment<byte>> GetUnderlyingData()
{
GetSymWriter().Commit();
return _pdbStream.GetChunks();
}
public unsafe override int DefineDocument(string name, Guid language, Guid vendor, Guid type, Guid algorithmId, ReadOnlySpan<byte> checksum, ReadOnlySpan<byte> source)
{
if (name == null)
{
throw new ArgumentNullException("name");
}
ISymUnmanagedWriter5 symWriter = GetSymWriter();
int count = _documentWriters.Count;
ISymUnmanagedDocumentWriter symUnmanagedDocumentWriter;
try
{
symUnmanagedDocumentWriter = symWriter.DefineDocument(name, ref language, ref vendor, ref type);
}
catch (Exception inner)
{
throw PdbWritingException(inner);
}
_documentWriters.Add(symUnmanagedDocumentWriter);
if (algorithmId != default(Guid) && checksum.Length > 0)
{
try
{
fixed (byte* checkSum = checksum)
{
symUnmanagedDocumentWriter.SetCheckSum(algorithmId, (uint)checksum.Length, checkSum);
}
}
catch (Exception inner2)
{
throw PdbWritingException(inner2);
}
}
if (source != null)
{
try
{
fixed (byte* source2 = source)
{
symUnmanagedDocumentWriter.SetSource((uint)source.Length, source2);
}
}
catch (Exception inner3)
{
throw PdbWritingException(inner3);
}
}
return count;
}
public override void DefineSequencePoints(int documentIndex, int count, int[] offsets, int[] startLines, int[] startColumns, int[] endLines, int[] endColumns)
{
if (documentIndex < 0 || documentIndex >= _documentWriters.Count)
{
throw new ArgumentOutOfRangeException("documentIndex");
}
if (offsets == null)
{
throw new ArgumentNullException("offsets");
}
if (startLines == null)
{
throw new ArgumentNullException("startLines");
}
if (startColumns == null)
{
throw new ArgumentNullException("startColumns");
}
if (endLines == null)
{
throw new ArgumentNullException("endLines");
}
if (endColumns == null)
{
throw new ArgumentNullException("endColumns");
}
if (count < 0 || count > startLines.Length || count > startColumns.Length || count > endLines.Length || count > endColumns.Length)
{
throw new ArgumentOutOfRangeException("count");
}
ISymUnmanagedWriter5 symWriter = GetSymWriter();
try
{
symWriter.DefineSequencePoints(_documentWriters[documentIndex], count, offsets, startLines, startColumns, endLines, endColumns);
}
catch (Exception inner)
{
throw PdbWritingException(inner);
}
}
public override void OpenMethod(int methodToken)
{
ISymUnmanagedWriter5 symWriter = GetSymWriter();
try
{
symWriter.OpenMethod((uint)methodToken);
}
catch (Exception inner)
{
throw PdbWritingException(inner);
}
}
public override void CloseMethod()
{
ISymUnmanagedWriter5 symWriter = GetSymWriter();
try
{
symWriter.CloseMethod();
}
catch (Exception inner)
{
throw PdbWritingException(inner);
}
}
public override void OpenScope(int startOffset)
{
ISymUnmanagedWriter5 symWriter = GetSymWriter();
try
{
symWriter.OpenScope(startOffset);
}
catch (Exception inner)
{
throw PdbWritingException(inner);
}
}
public override void CloseScope(int endOffset)
{
ISymUnmanagedWriter5 symWriter = GetSymWriter();
try
{
symWriter.CloseScope(endOffset);
}
catch (Exception inner)
{
throw PdbWritingException(inner);
}
}
public override void DefineLocalVariable(int index, string name, int attributes, int localSignatureToken)
{
ISymUnmanagedWriter5 symWriter = GetSymWriter();
try
{
symWriter.DefineLocalVariable2(name, attributes, localSignatureToken, 1u, index, 0u, 0u, 0u, 0u);
}
catch (Exception inner)
{
throw PdbWritingException(inner);
}
}
public override bool DefineLocalConstant(string name, object value, int constantSignatureToken)
{
ISymUnmanagedWriter5 symWriter = GetSymWriter();
if (!(value is string value2))
{
if (value is DateTime date)
{
try
{
symWriter.DefineConstant2(name, new VariantStructure(date), constantSignatureToken);
}
catch (Exception inner)
{
throw PdbWritingException(inner);
}
return true;
}
try
{
DefineLocalConstantImpl(symWriter, name, value ?? s_zeroInt32, constantSignatureToken);
}
catch (Exception inner2)
{
throw PdbWritingException(inner2);
}
return true;
}
return DefineLocalStringConstant(symWriter, name, value2, constantSignatureToken);
}
private unsafe void DefineLocalConstantImpl(ISymUnmanagedWriter5 symWriter, string name, object value, int constantSignatureToken)
{
VariantStructure value2 = default(VariantStructure);
Marshal.GetNativeVariantForObject(value, new IntPtr(&value2));
symWriter.DefineConstant2(name, value2, constantSignatureToken);
}
private bool DefineLocalStringConstant(ISymUnmanagedWriter5 symWriter, string name, string value, int constantSignatureToken)
{
int num;
if (!IsValidUnicodeString(value))
{
byte[] bytes = Encoding.UTF8.GetBytes(value);
num = bytes.Length;
value = Encoding.UTF8.GetString(bytes, 0, bytes.Length);
}
else
{
num = Encoding.UTF8.GetByteCount(value);
}
num++;
if (num > 2032)
{
return false;
}
try
{
DefineLocalConstantImpl(symWriter, name, value, constantSignatureToken);
}
catch (ArgumentException)
{
return false;
}
catch (Exception inner)
{
throw PdbWritingException(inner);
}
return true;
}
private static bool IsValidUnicodeString(string str)
{
int num = 0;
while (num < str.Length)
{
char c = str[num++];
if (char.IsHighSurrogate(c))
{
if (num >= str.Length || !char.IsLowSurrogate(str[num]))
{
return false;
}
num++;
}
else if (char.IsLowSurrogate(c))
{
return false;
}
}
return true;
}
public override void UsingNamespace(string importString)
{
if (importString == null)
{
throw new ArgumentNullException("importString");
}
ISymUnmanagedWriter5 symWriter = GetSymWriter();
try
{
symWriter.UsingNamespace(importString);
}
catch (Exception inner)
{
throw PdbWritingException(inner);
}
}
public unsafe override void SetAsyncInfo(int moveNextMethodToken, int kickoffMethodToken, int catchHandlerOffset, ReadOnlySpan<int> yieldOffsets, ReadOnlySpan<int> resumeOffsets)
{
if (yieldOffsets == null)
{
throw new ArgumentNullException("yieldOffsets");
}
if (resumeOffsets == null)
{
throw new ArgumentNullException("resumeOffsets");
}
if (yieldOffsets.Length != resumeOffsets.Length)
{
throw new ArgumentOutOfRangeException("yieldOffsets");
}
if (!(GetSymWriter() is ISymUnmanagedAsyncMethodPropertiesWriter symUnmanagedAsyncMethodPropertiesWriter))
{
return;
}
int length = yieldOffsets.Length;
if (length > 0)
{
int[] array = new int[length];
for (int i = 0; i < length; i++)
{
array[i] = moveNextMethodToken;
}
try
{
fixed (int* yieldOffsets2 = yieldOffsets)
{
fixed (int* breakpointOffset = resumeOffsets)
{
fixed (int* breakpointMethod = array)
{
symUnmanagedAsyncMethodPropertiesWriter.DefineAsyncStepInfo(length, yieldOffsets2, breakpointOffset, breakpointMethod);
}
}
}
}
catch (Exception inner)
{
throw PdbWritingException(inner);
}
}
try
{
if (catchHandlerOffset >= 0)
{
symUnmanagedAsyncMethodPropertiesWriter.DefineCatchHandlerILOffset(catchHandlerOffset);
}
symUnmanagedAsyncMethodPropertiesWriter.DefineKickoffMethod(kickoffMethodToken);
}
catch (Exception inner2)
{
throw PdbWritingException(inner2);
}
}
public unsafe override void DefineCustomMetadata(byte[] metadata)
{
if (metadata == null)
{
throw new ArgumentNullException("metadata");
}
if (metadata.Length == 0)
{
return;
}
ISymUnmanagedWriter5 symWriter = GetSymWriter();
try
{
fixed (byte* data = metadata)
{
symWriter.SetSymAttribute(0u, "MD2", metadata.Length, data);
}
}
catch (Exception inner)
{
throw PdbWritingException(inner);
}
}
public override void SetEntryPoint(int entryMethodToken)
{
ISymUnmanagedWriter5 symWriter = GetSymWriter();
try
{
symWriter.SetUserEntryPoint(entryMethodToken);
}
catch (Exception inner)
{
throw PdbWritingException(inner);
}
}
public override void UpdateSignature(Guid guid, uint stamp, int age)
{
ISymUnmanagedWriter8 symWriter = GetSymWriter8();
try
{
symWriter.UpdateSignature(guid, stamp, age);
}
catch (Exception inner)
{
throw PdbWritingException(inner);
}
}
public unsafe override void SetSourceServerData(byte[] data)
{
if (data == null)
{
throw new ArgumentNullException("data");
}
if (data.Length == 0)
{
return;
}
ISymUnmanagedWriter8 symWriter = GetSymWriter8();
try
{
fixed (byte* data2 = data)
{
symWriter.SetSourceServerData(data2, data.Length);
}
}
catch (Exception inner)
{
throw PdbWritingException(inner);
}
}
public unsafe override void SetSourceLinkData(byte[] data)
{
if (data == null)
{
throw new ArgumentNullException("data");
}
if (data.Length == 0)
{
return;
}
ISymUnmanagedWriter8 symWriter = GetSymWriter8();
try
{
fixed (byte* data2 = data)
{
symWriter.SetSourceLinkData(data2, data.Length);
}
}
catch (Exception inner)
{
throw PdbWritingException(inner);
}
}
public override void OpenTokensToSourceSpansMap()
{
ISymUnmanagedWriter5 symWriter = GetSymWriter();
try
{
symWriter.OpenMapTokensToSourceSpans();
}
catch (Exception inner)
{
throw PdbWritingException(inner);
}
}
public override void MapTokenToSourceSpan(int token, int documentIndex, int startLine, int startColumn, int endLine, int endColumn)
{
if (documentIndex < 0 || documentIndex >= _documentWriters.Count)
{
throw new ArgumentOutOfRangeException("documentIndex");
}
ISymUnmanagedWriter5 symWriter = GetSymWriter();
try
{
symWriter.MapTokenToSourceSpan(token, _documentWriters[documentIndex], startLine, startColumn, endLine, endColumn);
}
catch (Exception inner)
{
throw PdbWritingException(inner);
}
}
public override void CloseTokensToSourceSpansMap()
{
ISymUnmanagedWriter5 symWriter = GetSymWriter();
try
{
symWriter.CloseMapTokensToSourceSpans();
}
catch (Exception inner)
{
throw PdbWritingException(inner);
}
}
public unsafe override void GetSignature(out Guid guid, out uint stamp, out int age)
{
ISymUnmanagedWriter5 symWriter = GetSymWriter();
ImageDebugDirectory debugDirectory = default(ImageDebugDirectory);
uint dataCountPtr;
try
{
symWriter.GetDebugInfo(ref debugDirectory, 0u, out dataCountPtr, null);
}
catch (Exception inner)
{
throw PdbWritingException(inner);
}
byte[] array = new byte[dataCountPtr];
fixed (byte* data = array)
{
try
{
symWriter.GetDebugInfo(ref debugDirectory, dataCountPtr, out dataCountPtr, data);
}
catch (Exception inner2)
{
throw PdbWritingException(inner2);
}
}
byte[] array2 = new byte[16];
Buffer.BlockCopy(array, 4, array2, 0, array2.Length);
guid = new Guid(array2);
((IPdbWriter)symWriter).GetSignatureAge(out stamp, out age);
}
public override void AddCompilerInfo(ushort major, ushort minor, ushort build, ushort revision, string name)
{
if (name == null)
{
throw new ArgumentNullException("name");
}
if (!(GetSymWriter() is ISymUnmanagedCompilerInfoWriter symUnmanagedCompilerInfoWriter))
{
return;
}
try
{
symUnmanagedCompilerInfoWriter.AddCompilerInfo(major, minor, build, revision, name);
}
catch (Exception inner)
{
throw PdbWritingException(inner);
}
}
}