Files
TheDeclineOfWarriors/Assets/FishNet/CodeGenerating/cecil-0.11.4/Mono.Cecil.Cil/Symbols.cs
T
2026-03-30 20:11:57 +07:00

1183 lines
35 KiB
C#

//
// Author:
// Jb Evain (jbevain@gmail.com)
//
// Copyright (c) 2008 - 2015 Jb Evain
// Copyright (c) 2008 - 2011 Novell, Inc.
//
// Licensed under the MIT/X11 license.
//
using MonoFN.Cecil.Cil;
using MonoFN.Cecil.PE;
using MonoFN.Collections.Generic;
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
using System.Threading;
using MonoFN.Cecil.Metadata;
using SR = System.Reflection;
namespace MonoFN.Cecil.Cil
{
[StructLayout(LayoutKind.Sequential)]
public struct ImageDebugDirectory
{
public const int Size = 28;
public int Characteristics;
public int TimeDateStamp;
public short MajorVersion;
public short MinorVersion;
public ImageDebugType Type;
public int SizeOfData;
public int AddressOfRawData;
public int PointerToRawData;
}
public enum ImageDebugType
{
CodeView = 2,
Deterministic = 16,
EmbeddedPortablePdb = 17
}
public sealed class ImageDebugHeader
{
public bool HasEntries
{
get { return !Entries.IsNullOrEmpty(); }
}
public ImageDebugHeaderEntry[] Entries { get; }
public ImageDebugHeader(ImageDebugHeaderEntry[] entries)
{
this.Entries = entries ?? Empty<ImageDebugHeaderEntry>.Array;
}
public ImageDebugHeader() : this(Empty<ImageDebugHeaderEntry>.Array) { }
public ImageDebugHeader(ImageDebugHeaderEntry entry) : this(new[] { entry }) { }
}
public sealed class ImageDebugHeaderEntry
{
public ImageDebugDirectory Directory { get; internal set; }
public byte[] Data { get; }
public ImageDebugHeaderEntry(ImageDebugDirectory directory, byte[] data)
{
this.Directory = directory;
this.Data = data ?? Empty<byte>.Array;
}
}
public sealed class ScopeDebugInformation : DebugInformation
{
internal InstructionOffset start;
internal InstructionOffset end;
internal ImportDebugInformation import;
internal Collection<ScopeDebugInformation> scopes;
internal Collection<VariableDebugInformation> variables;
internal Collection<ConstantDebugInformation> constants;
public InstructionOffset Start
{
get { return start; }
set { start = value; }
}
public InstructionOffset End
{
get { return end; }
set { end = value; }
}
public ImportDebugInformation Import
{
get { return import; }
set { import = value; }
}
public bool HasScopes
{
get { return !scopes.IsNullOrEmpty(); }
}
public Collection<ScopeDebugInformation> Scopes
{
get
{
if (scopes == null)
Interlocked.CompareExchange(ref scopes, new(), null);
return scopes;
}
}
public bool HasVariables
{
get { return !variables.IsNullOrEmpty(); }
}
public Collection<VariableDebugInformation> Variables
{
get
{
if (variables == null)
Interlocked.CompareExchange(ref variables, new(), null);
return variables;
}
}
public bool HasConstants
{
get { return !constants.IsNullOrEmpty(); }
}
public Collection<ConstantDebugInformation> Constants
{
get
{
if (constants == null)
Interlocked.CompareExchange(ref constants, new(), null);
return constants;
}
}
internal ScopeDebugInformation()
{
token = new(TokenType.LocalScope);
}
public ScopeDebugInformation(Instruction start, Instruction end) : this()
{
if (start == null)
throw new ArgumentNullException("start");
this.start = new(start);
if (end != null)
this.end = new(end);
}
public bool TryGetName(VariableDefinition variable, out string name)
{
name = null;
if (variables == null || variables.Count == 0)
return false;
for (int i = 0; i < variables.Count; i++)
{
if (variables[i].Index == variable.Index)
{
name = variables[i].Name;
return true;
}
}
return false;
}
}
public struct InstructionOffset
{
private readonly int? offset;
public int Offset
{
get
{
if (ResolvedInstruction != null)
return ResolvedInstruction.Offset;
if (offset.HasValue)
return offset.Value;
throw new NotSupportedException();
}
}
public bool IsEndOfMethod
{
get { return ResolvedInstruction == null && !offset.HasValue; }
}
internal bool IsResolved => ResolvedInstruction != null || !offset.HasValue;
internal Instruction ResolvedInstruction { get; }
public InstructionOffset(Instruction instruction)
{
if (instruction == null)
throw new ArgumentNullException("instruction");
this.ResolvedInstruction = instruction;
offset = null;
}
public InstructionOffset(int offset)
{
ResolvedInstruction = null;
this.offset = offset;
}
}
[Flags]
public enum VariableAttributes : ushort
{
None = 0,
DebuggerHidden = 1
}
public struct VariableIndex
{
private readonly int? index;
public int Index
{
get
{
if (ResolvedVariable != null)
return ResolvedVariable.Index;
if (index.HasValue)
return index.Value;
throw new NotSupportedException();
}
}
internal bool IsResolved => ResolvedVariable != null;
internal VariableDefinition ResolvedVariable { get; }
public VariableIndex(VariableDefinition variable)
{
if (variable == null)
throw new ArgumentNullException("variable");
this.ResolvedVariable = variable;
index = null;
}
public VariableIndex(int index)
{
ResolvedVariable = null;
this.index = index;
}
}
public abstract class DebugInformation : ICustomDebugInformationProvider
{
internal MetadataToken token;
internal Collection<CustomDebugInformation> custom_infos;
public MetadataToken MetadataToken
{
get { return token; }
set { token = value; }
}
public bool HasCustomDebugInformations
{
get { return !custom_infos.IsNullOrEmpty(); }
}
public Collection<CustomDebugInformation> CustomDebugInformations
{
get
{
if (custom_infos == null)
Interlocked.CompareExchange(ref custom_infos, new(), null);
return custom_infos;
}
}
internal DebugInformation() { }
}
public sealed class VariableDebugInformation : DebugInformation
{
private ushort attributes;
internal VariableIndex index;
public int Index
{
get { return index.Index; }
}
public string Name { get; set; }
public VariableAttributes Attributes
{
get { return (VariableAttributes)attributes; }
set { attributes = (ushort)value; }
}
public bool IsDebuggerHidden
{
get { return attributes.GetAttributes((ushort)VariableAttributes.DebuggerHidden); }
set { attributes = attributes.SetAttributes((ushort)VariableAttributes.DebuggerHidden, value); }
}
internal VariableDebugInformation(int index, string name)
{
if (name == null)
throw new ArgumentNullException("name");
this.index = new(index);
this.Name = name;
}
public VariableDebugInformation(VariableDefinition variable, string name)
{
if (variable == null)
throw new ArgumentNullException("variable");
if (name == null)
throw new ArgumentNullException("name");
index = new(variable);
this.Name = name;
token = new(TokenType.LocalVariable);
}
}
public sealed class ConstantDebugInformation : DebugInformation
{
public string Name { get; set; }
public TypeReference ConstantType { get; set; }
public object Value { get; set; }
public ConstantDebugInformation(string name, TypeReference constant_type, object value)
{
if (name == null)
throw new ArgumentNullException("name");
this.Name = name;
this.ConstantType = constant_type;
this.Value = value;
token = new(TokenType.LocalConstant);
}
}
public enum ImportTargetKind : byte
{
ImportNamespace = 1,
ImportNamespaceInAssembly = 2,
ImportType = 3,
ImportXmlNamespaceWithAlias = 4,
ImportAlias = 5,
DefineAssemblyAlias = 6,
DefineNamespaceAlias = 7,
DefineNamespaceInAssemblyAlias = 8,
DefineTypeAlias = 9
}
public sealed class ImportTarget
{
internal ImportTargetKind kind;
internal string @namespace;
internal TypeReference type;
internal AssemblyNameReference reference;
internal string alias;
public string Namespace
{
get { return @namespace; }
set { @namespace = value; }
}
public TypeReference Type
{
get { return type; }
set { type = value; }
}
public AssemblyNameReference AssemblyReference
{
get { return reference; }
set { reference = value; }
}
public string Alias
{
get { return alias; }
set { alias = value; }
}
public ImportTargetKind Kind
{
get { return kind; }
set { kind = value; }
}
public ImportTarget(ImportTargetKind kind)
{
this.kind = kind;
}
}
public sealed class ImportDebugInformation : DebugInformation
{
internal ImportDebugInformation parent;
internal Collection<ImportTarget> targets;
public bool HasTargets
{
get { return !targets.IsNullOrEmpty(); }
}
public Collection<ImportTarget> Targets
{
get
{
if (targets == null)
Interlocked.CompareExchange(ref targets, new(), null);
return targets;
}
}
public ImportDebugInformation Parent
{
get { return parent; }
set { parent = value; }
}
public ImportDebugInformation()
{
token = new(TokenType.ImportScope);
}
}
public interface ICustomDebugInformationProvider : IMetadataTokenProvider
{
bool HasCustomDebugInformations { get; }
Collection<CustomDebugInformation> CustomDebugInformations { get; }
}
public enum CustomDebugInformationKind
{
Binary,
StateMachineScope,
DynamicVariable,
DefaultNamespace,
AsyncMethodBody,
EmbeddedSource,
SourceLink
}
public abstract class CustomDebugInformation : DebugInformation
{
public Guid Identifier { get; }
public abstract CustomDebugInformationKind Kind { get; }
internal CustomDebugInformation(Guid identifier)
{
this.Identifier = identifier;
token = new(TokenType.CustomDebugInformation);
}
}
public sealed class BinaryCustomDebugInformation : CustomDebugInformation
{
public byte[] Data { get; set; }
public override CustomDebugInformationKind Kind
{
get { return CustomDebugInformationKind.Binary; }
}
public BinaryCustomDebugInformation(Guid identifier, byte[] data) : base(identifier)
{
this.Data = data;
}
}
public sealed class AsyncMethodBodyDebugInformation : CustomDebugInformation
{
internal InstructionOffset catch_handler;
internal Collection<InstructionOffset> yields;
internal Collection<InstructionOffset> resumes;
internal Collection<MethodDefinition> resume_methods;
public InstructionOffset CatchHandler
{
get { return catch_handler; }
set { catch_handler = value; }
}
public Collection<InstructionOffset> Yields
{
get
{
if (yields == null)
Interlocked.CompareExchange(ref yields, new(), null);
return yields;
}
}
public Collection<InstructionOffset> Resumes
{
get
{
if (resumes == null)
Interlocked.CompareExchange(ref resumes, new(), null);
return resumes;
}
}
public Collection<MethodDefinition> ResumeMethods
{
get { return resume_methods ?? (resume_methods = new()); }
}
public override CustomDebugInformationKind Kind
{
get { return CustomDebugInformationKind.AsyncMethodBody; }
}
public static Guid KindIdentifier = new("{54FD2AC5-E925-401A-9C2A-F94F171072F8}");
internal AsyncMethodBodyDebugInformation(int catchHandler) : base(KindIdentifier)
{
catch_handler = new(catchHandler);
}
public AsyncMethodBodyDebugInformation(Instruction catchHandler) : base(KindIdentifier)
{
catch_handler = new(catchHandler);
}
public AsyncMethodBodyDebugInformation() : base(KindIdentifier)
{
catch_handler = new(-1);
}
}
public sealed class StateMachineScope
{
internal InstructionOffset start;
internal InstructionOffset end;
public InstructionOffset Start
{
get { return start; }
set { start = value; }
}
public InstructionOffset End
{
get { return end; }
set { end = value; }
}
internal StateMachineScope(int start, int end)
{
this.start = new(start);
this.end = new(end);
}
public StateMachineScope(Instruction start, Instruction end)
{
this.start = new(start);
this.end = end != null ? new(end) : new InstructionOffset();
}
}
public sealed class StateMachineScopeDebugInformation : CustomDebugInformation
{
internal Collection<StateMachineScope> scopes;
public Collection<StateMachineScope> Scopes
{
get { return scopes ?? (scopes = new()); }
}
public override CustomDebugInformationKind Kind
{
get { return CustomDebugInformationKind.StateMachineScope; }
}
public static Guid KindIdentifier = new("{6DA9A61E-F8C7-4874-BE62-68BC5630DF71}");
public StateMachineScopeDebugInformation() : base(KindIdentifier) { }
}
public sealed class EmbeddedSourceDebugInformation : CustomDebugInformation
{
internal uint index;
internal MetadataReader debug_reader;
internal bool resolved;
internal byte[] content;
internal bool compress;
public byte[] Content
{
get
{
if (!resolved)
Resolve();
return content;
}
set
{
content = value;
resolved = true;
}
}
public bool Compress
{
get
{
if (!resolved)
Resolve();
return compress;
}
set
{
compress = value;
resolved = true;
}
}
public override CustomDebugInformationKind Kind
{
get { return CustomDebugInformationKind.EmbeddedSource; }
}
public static Guid KindIdentifier = new("{0E8A571B-6926-466E-B4AD-8AB04611F5FE}");
internal EmbeddedSourceDebugInformation(uint index, MetadataReader debug_reader) : base(KindIdentifier)
{
this.index = index;
this.debug_reader = debug_reader;
}
public EmbeddedSourceDebugInformation(byte[] content, bool compress) : base(KindIdentifier)
{
resolved = true;
this.content = content;
this.compress = compress;
}
internal byte[] ReadRawEmbeddedSourceDebugInformation()
{
if (debug_reader == null)
throw new InvalidOperationException();
return debug_reader.ReadRawEmbeddedSourceDebugInformation(index);
}
private void Resolve()
{
if (resolved)
return;
if (debug_reader == null)
throw new InvalidOperationException();
Row<byte[], bool> row = debug_reader.ReadEmbeddedSourceDebugInformation(index);
content = row.Col1;
compress = row.Col2;
resolved = true;
}
}
public sealed class SourceLinkDebugInformation : CustomDebugInformation
{
internal string content;
public string Content
{
get { return content; }
set { content = value; }
}
public override CustomDebugInformationKind Kind
{
get { return CustomDebugInformationKind.SourceLink; }
}
public static Guid KindIdentifier = new("{CC110556-A091-4D38-9FEC-25AB9A351A6A}");
public SourceLinkDebugInformation(string content) : base(KindIdentifier)
{
this.content = content;
}
}
public sealed class MethodDebugInformation : DebugInformation
{
internal MethodDefinition method;
internal Collection<SequencePoint> sequence_points;
internal ScopeDebugInformation scope;
internal MethodDefinition kickoff_method;
internal int code_size;
internal MetadataToken local_var_token;
public MethodDefinition Method
{
get { return method; }
}
public bool HasSequencePoints
{
get { return !sequence_points.IsNullOrEmpty(); }
}
public Collection<SequencePoint> SequencePoints
{
get
{
if (sequence_points == null)
Interlocked.CompareExchange(ref sequence_points, new(), null);
return sequence_points;
}
}
public ScopeDebugInformation Scope
{
get { return scope; }
set { scope = value; }
}
public MethodDefinition StateMachineKickOffMethod
{
get { return kickoff_method; }
set { kickoff_method = value; }
}
internal MethodDebugInformation(MethodDefinition method)
{
if (method == null)
throw new ArgumentNullException("method");
this.method = method;
token = new(TokenType.MethodDebugInformation, method.MetadataToken.RID);
}
public SequencePoint GetSequencePoint(Instruction instruction)
{
if (!HasSequencePoints)
return null;
for (int i = 0; i < sequence_points.Count; i++)
if (sequence_points[i].Offset == instruction.Offset)
return sequence_points[i];
return null;
}
public IDictionary<Instruction, SequencePoint> GetSequencePointMapping()
{
Dictionary<Instruction, SequencePoint> instruction_mapping = new();
if (!HasSequencePoints || !method.HasBody)
return instruction_mapping;
Dictionary<int, SequencePoint> offset_mapping = new(sequence_points.Count);
for (int i = 0; i < sequence_points.Count; i++)
{
if (!offset_mapping.ContainsKey(sequence_points[i].Offset))
offset_mapping.Add(sequence_points[i].Offset, sequence_points[i]);
}
Collection<Instruction> instructions = method.Body.Instructions;
for (int i = 0; i < instructions.Count; i++)
{
SequencePoint sequence_point;
if (offset_mapping.TryGetValue(instructions[i].Offset, out sequence_point))
instruction_mapping.Add(instructions[i], sequence_point);
}
return instruction_mapping;
}
public IEnumerable<ScopeDebugInformation> GetScopes()
{
if (scope == null)
return Empty<ScopeDebugInformation>.Array;
return GetScopes(new[] { scope });
}
private static IEnumerable<ScopeDebugInformation> GetScopes(IList<ScopeDebugInformation> scopes)
{
for (int i = 0; i < scopes.Count; i++)
{
ScopeDebugInformation scope = scopes[i];
yield return scope;
if (!scope.HasScopes)
continue;
foreach (ScopeDebugInformation sub_scope in GetScopes(scope.Scopes))
yield return sub_scope;
}
}
public bool TryGetName(VariableDefinition variable, out string name)
{
name = null;
bool has_name = false;
string unique_name = "";
foreach (ScopeDebugInformation scope in GetScopes())
{
string slot_name;
if (!scope.TryGetName(variable, out slot_name))
continue;
if (!has_name)
{
has_name = true;
unique_name = slot_name;
continue;
}
if (unique_name != slot_name)
return false;
}
name = unique_name;
return has_name;
}
}
public interface ISymbolReader : IDisposable
{
ISymbolWriterProvider GetWriterProvider();
bool ProcessDebugHeader(ImageDebugHeader header);
MethodDebugInformation Read(MethodDefinition method);
}
public interface ISymbolReaderProvider
{
ISymbolReader GetSymbolReader(ModuleDefinition module, string fileName);
ISymbolReader GetSymbolReader(ModuleDefinition module, Stream symbolStream);
}
#if !NET_CORE
[Serializable]
#endif
public sealed class SymbolsNotFoundException : FileNotFoundException
{
public SymbolsNotFoundException(string message) : base(message) { }
#if !NET_CORE
private SymbolsNotFoundException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) : base(info, context) { }
#endif
}
#if !NET_CORE
[Serializable]
#endif
public sealed class SymbolsNotMatchingException : InvalidOperationException
{
public SymbolsNotMatchingException(string message) : base(message) { }
#if !NET_CORE
private SymbolsNotMatchingException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) : base(info, context) { }
#endif
}
public class DefaultSymbolReaderProvider : ISymbolReaderProvider
{
private readonly bool throw_if_no_symbol;
public DefaultSymbolReaderProvider() : this(throwIfNoSymbol: true) { }
public DefaultSymbolReaderProvider(bool throwIfNoSymbol)
{
throw_if_no_symbol = throwIfNoSymbol;
}
public ISymbolReader GetSymbolReader(ModuleDefinition module, string fileName)
{
if (module.Image.HasDebugTables())
return null;
if (module.HasDebugHeader)
{
ImageDebugHeader header = module.GetDebugHeader();
ImageDebugHeaderEntry entry = header.GetEmbeddedPortablePdbEntry();
if (entry != null)
return new EmbeddedPortablePdbReaderProvider().GetSymbolReader(module, fileName);
}
string pdb_file_name = Mixin.GetPdbFileName(fileName);
if (File.Exists(pdb_file_name))
{
if (Mixin.IsPortablePdb(Mixin.GetPdbFileName(fileName)))
return new PortablePdbReaderProvider().GetSymbolReader(module, fileName);
try
{
return SymbolProvider.GetReaderProvider(SymbolKind.NativePdb).GetSymbolReader(module, fileName);
}
catch (Exception)
{
// We might not include support for native pdbs.
}
}
string mdb_file_name = Mixin.GetMdbFileName(fileName);
if (File.Exists(mdb_file_name))
{
try
{
return SymbolProvider.GetReaderProvider(SymbolKind.Mdb).GetSymbolReader(module, fileName);
}
catch (Exception)
{
// We might not include support for mdbs.
}
}
if (throw_if_no_symbol)
throw new SymbolsNotFoundException(string.Format("No symbol found for file: {0}", fileName));
return null;
}
public ISymbolReader GetSymbolReader(ModuleDefinition module, Stream symbolStream)
{
if (module.Image.HasDebugTables())
return null;
if (module.HasDebugHeader)
{
ImageDebugHeader header = module.GetDebugHeader();
ImageDebugHeaderEntry entry = header.GetEmbeddedPortablePdbEntry();
if (entry != null)
return new EmbeddedPortablePdbReaderProvider().GetSymbolReader(module, "");
}
Mixin.CheckStream(symbolStream);
Mixin.CheckReadSeek(symbolStream);
long position = symbolStream.Position;
const int portablePdbHeader = 0x424a5342;
BinaryStreamReader reader = new(symbolStream);
int intHeader = reader.ReadInt32();
symbolStream.Position = position;
if (intHeader == portablePdbHeader)
{
return new PortablePdbReaderProvider().GetSymbolReader(module, symbolStream);
}
const string nativePdbHeader = "Microsoft C/C++ MSF 7.00";
byte[] bytesHeader = reader.ReadBytes(nativePdbHeader.Length);
symbolStream.Position = position;
bool isNativePdb = true;
for (int i = 0; i < bytesHeader.Length; i++)
{
if (bytesHeader[i] != (byte)nativePdbHeader[i])
{
isNativePdb = false;
break;
}
}
if (isNativePdb)
{
try
{
return SymbolProvider.GetReaderProvider(SymbolKind.NativePdb).GetSymbolReader(module, symbolStream);
}
catch (Exception)
{
// We might not include support for native pdbs.
}
}
const long mdbHeader = 0x45e82623fd7fa614;
long longHeader = reader.ReadInt64();
symbolStream.Position = position;
if (longHeader == mdbHeader)
{
try
{
return SymbolProvider.GetReaderProvider(SymbolKind.Mdb).GetSymbolReader(module, symbolStream);
}
catch (Exception)
{
// We might not include support for mdbs.
}
}
if (throw_if_no_symbol)
throw new SymbolsNotFoundException(string.Format("No symbols found in stream"));
return null;
}
}
internal enum SymbolKind
{
NativePdb,
PortablePdb,
EmbeddedPortablePdb,
Mdb
}
internal static class SymbolProvider
{
private static SR.AssemblyName GetSymbolAssemblyName(SymbolKind kind)
{
if (kind == SymbolKind.PortablePdb)
throw new ArgumentException();
string suffix = GetSymbolNamespace(kind);
SR.AssemblyName cecil_name = typeof(SymbolProvider).Assembly.GetName();
SR.AssemblyName name = new()
{
Name = cecil_name.Name + "." + suffix,
Version = cecil_name.Version,
#if NET_CORE
CultureName = cecil_name.CultureName,
#else
CultureInfo = cecil_name.CultureInfo,
#endif
};
name.SetPublicKeyToken(cecil_name.GetPublicKeyToken());
return name;
}
private static Type GetSymbolType(SymbolKind kind, string fullname)
{
Type type = Type.GetType(fullname);
if (type != null)
return type;
SR.AssemblyName assembly_name = GetSymbolAssemblyName(kind);
type = Type.GetType(fullname + ", " + assembly_name.FullName);
if (type != null)
return type;
try
{
SR.Assembly assembly = SR.Assembly.Load(assembly_name);
if (assembly != null)
return assembly.GetType(fullname);
}
catch (FileNotFoundException) { }
catch (FileLoadException) { }
return null;
}
public static ISymbolReaderProvider GetReaderProvider(SymbolKind kind)
{
if (kind == SymbolKind.PortablePdb)
return new PortablePdbReaderProvider();
if (kind == SymbolKind.EmbeddedPortablePdb)
return new EmbeddedPortablePdbReaderProvider();
string provider_name = GetSymbolTypeName(kind, "ReaderProvider");
Type type = GetSymbolType(kind, provider_name);
if (type == null)
throw new TypeLoadException("Could not find symbol provider type " + provider_name);
return (ISymbolReaderProvider)Activator.CreateInstance(type);
}
private static string GetSymbolTypeName(SymbolKind kind, string name)
{
return "MonoFN.Cecil" + "." + GetSymbolNamespace(kind) + "." + kind + name;
}
private static string GetSymbolNamespace(SymbolKind kind)
{
if (kind == SymbolKind.PortablePdb || kind == SymbolKind.EmbeddedPortablePdb)
return "Cil";
if (kind == SymbolKind.NativePdb)
return "Pdb";
if (kind == SymbolKind.Mdb)
return "Mdb";
throw new ArgumentException();
}
}
public interface ISymbolWriter : IDisposable
{
ISymbolReaderProvider GetReaderProvider();
ImageDebugHeader GetDebugHeader();
void Write(MethodDebugInformation info);
}
public interface ISymbolWriterProvider
{
ISymbolWriter GetSymbolWriter(ModuleDefinition module, string fileName);
ISymbolWriter GetSymbolWriter(ModuleDefinition module, Stream symbolStream);
}
public class DefaultSymbolWriterProvider : ISymbolWriterProvider
{
public ISymbolWriter GetSymbolWriter(ModuleDefinition module, string fileName)
{
ISymbolReader reader = module.SymbolReader;
if (reader == null)
throw new InvalidOperationException();
if (module.Image != null && module.Image.HasDebugTables())
return null;
return reader.GetWriterProvider().GetSymbolWriter(module, fileName);
}
public ISymbolWriter GetSymbolWriter(ModuleDefinition module, Stream symbolStream)
{
throw new NotSupportedException();
}
}
}
namespace MonoFN.Cecil
{
internal static partial class Mixin
{
public static ImageDebugHeaderEntry GetCodeViewEntry(this ImageDebugHeader header)
{
return GetEntry(header, ImageDebugType.CodeView);
}
public static ImageDebugHeaderEntry GetDeterministicEntry(this ImageDebugHeader header)
{
return GetEntry(header, ImageDebugType.Deterministic);
}
public static ImageDebugHeader AddDeterministicEntry(this ImageDebugHeader header)
{
ImageDebugHeaderEntry entry = new(new() { Type = ImageDebugType.Deterministic }, Empty<byte>.Array);
if (header == null)
return new(entry);
ImageDebugHeaderEntry[] entries = new ImageDebugHeaderEntry [header.Entries.Length + 1];
Array.Copy(header.Entries, entries, header.Entries.Length);
entries[entries.Length - 1] = entry;
return new(entries);
}
public static ImageDebugHeaderEntry GetEmbeddedPortablePdbEntry(this ImageDebugHeader header)
{
return GetEntry(header, ImageDebugType.EmbeddedPortablePdb);
}
private static ImageDebugHeaderEntry GetEntry(this ImageDebugHeader header, ImageDebugType type)
{
if (!header.HasEntries)
return null;
for (int i = 0; i < header.Entries.Length; i++)
{
ImageDebugHeaderEntry entry = header.Entries[i];
if (entry.Directory.Type == type)
return entry;
}
return null;
}
public static string GetPdbFileName(string assemblyFileName)
{
return Path.ChangeExtension(assemblyFileName, ".pdb");
}
public static string GetMdbFileName(string assemblyFileName)
{
return assemblyFileName + ".mdb";
}
public static bool IsPortablePdb(string fileName)
{
using (FileStream file = new(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
return IsPortablePdb(file);
}
}
public static bool IsPortablePdb(Stream stream)
{
const uint ppdb_signature = 0x424a5342;
if (stream.Length < 4)
return false;
long position = stream.Position;
try
{
BinaryReader reader = new(stream);
return reader.ReadUInt32() == ppdb_signature;
}
finally
{
stream.Position = position;
}
}
}
}