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

600 lines
19 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.Metadata;
using MonoFN.Cecil.PE;
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
namespace MonoFN.Cecil.Cil
{
public sealed class PortablePdbReaderProvider : ISymbolReaderProvider
{
public ISymbolReader GetSymbolReader(ModuleDefinition module, string fileName)
{
Mixin.CheckModule(module);
Mixin.CheckFileName(fileName);
FileStream file = File.OpenRead(Mixin.GetPdbFileName(fileName));
return GetSymbolReader(module, Disposable.Owned(file as Stream), file.Name);
}
public ISymbolReader GetSymbolReader(ModuleDefinition module, Stream symbolStream)
{
Mixin.CheckModule(module);
Mixin.CheckStream(symbolStream);
return GetSymbolReader(module, Disposable.NotOwned(symbolStream), symbolStream.GetFileName());
}
private ISymbolReader GetSymbolReader(ModuleDefinition module, Disposable<Stream> symbolStream, string fileName)
{
return new PortablePdbReader(ImageReader.ReadPortablePdb(symbolStream, fileName), module);
}
}
public sealed class PortablePdbReader : ISymbolReader
{
private readonly Image image;
private readonly ModuleDefinition module;
private readonly MetadataReader reader;
private readonly MetadataReader debug_reader;
private bool IsEmbedded
{
get { return reader.image == debug_reader.image; }
}
internal PortablePdbReader(Image image, ModuleDefinition module)
{
this.image = image;
this.module = module;
reader = module.reader;
debug_reader = new(image, module, reader);
}
public ISymbolWriterProvider GetWriterProvider()
{
return new PortablePdbWriterProvider();
}
public bool ProcessDebugHeader(ImageDebugHeader header)
{
if (image == module.Image)
return true;
foreach (ImageDebugHeaderEntry entry in header.Entries)
{
if (!IsMatchingEntry(image.PdbHeap, entry))
continue;
ReadModule();
return true;
}
return false;
}
private static bool IsMatchingEntry(PdbHeap heap, ImageDebugHeaderEntry entry)
{
if (entry.Directory.Type != ImageDebugType.CodeView)
return false;
byte[] data = entry.Data;
if (data.Length < 24)
return false;
int magic = ReadInt32(data, 0);
if (magic != 0x53445352)
return false;
byte[] buffer = new byte [16];
Buffer.BlockCopy(data, 4, buffer, 0, 16);
Guid module_guid = new(buffer);
Buffer.BlockCopy(heap.Id, 0, buffer, 0, 16);
Guid pdb_guid = new(buffer);
return module_guid == pdb_guid;
}
private static int ReadInt32(byte[] bytes, int start)
{
return bytes[start] | (bytes[start + 1] << 8) | (bytes[start + 2] << 16) | (bytes[start + 3] << 24);
}
private void ReadModule()
{
module.custom_infos = debug_reader.GetCustomDebugInformation(module);
}
public MethodDebugInformation Read(MethodDefinition method)
{
MethodDebugInformation info = new(method);
ReadSequencePoints(info);
ReadScope(info);
ReadStateMachineKickOffMethod(info);
ReadCustomDebugInformations(info);
return info;
}
private void ReadSequencePoints(MethodDebugInformation method_info)
{
method_info.sequence_points = debug_reader.ReadSequencePoints(method_info.method);
}
private void ReadScope(MethodDebugInformation method_info)
{
method_info.scope = debug_reader.ReadScope(method_info.method);
}
private void ReadStateMachineKickOffMethod(MethodDebugInformation method_info)
{
method_info.kickoff_method = debug_reader.ReadStateMachineKickoffMethod(method_info.method);
}
private void ReadCustomDebugInformations(MethodDebugInformation info)
{
info.method.custom_infos = debug_reader.GetCustomDebugInformation(info.method);
}
public void Dispose()
{
if (IsEmbedded)
return;
image.Dispose();
}
}
public sealed class EmbeddedPortablePdbReaderProvider : ISymbolReaderProvider
{
public ISymbolReader GetSymbolReader(ModuleDefinition module, string fileName)
{
Mixin.CheckModule(module);
ImageDebugHeader header = module.GetDebugHeader();
ImageDebugHeaderEntry entry = header.GetEmbeddedPortablePdbEntry();
if (entry == null)
throw new InvalidOperationException();
return new EmbeddedPortablePdbReader((PortablePdbReader)new PortablePdbReaderProvider().GetSymbolReader(module, GetPortablePdbStream(entry)));
}
private static Stream GetPortablePdbStream(ImageDebugHeaderEntry entry)
{
MemoryStream compressed_stream = new(entry.Data);
BinaryStreamReader reader = new(compressed_stream);
reader.ReadInt32(); // signature
int length = reader.ReadInt32();
MemoryStream decompressed_stream = new(length);
using (DeflateStream deflate_stream = new(compressed_stream, CompressionMode.Decompress, leaveOpen: true))
{
deflate_stream.CopyTo(decompressed_stream);
}
return decompressed_stream;
}
public ISymbolReader GetSymbolReader(ModuleDefinition module, Stream symbolStream)
{
throw new NotSupportedException();
}
}
public sealed class EmbeddedPortablePdbReader : ISymbolReader
{
private readonly PortablePdbReader reader;
internal EmbeddedPortablePdbReader(PortablePdbReader reader)
{
if (reader == null)
throw new ArgumentNullException();
this.reader = reader;
}
public ISymbolWriterProvider GetWriterProvider()
{
return new EmbeddedPortablePdbWriterProvider();
}
public bool ProcessDebugHeader(ImageDebugHeader header)
{
return reader.ProcessDebugHeader(header);
}
public MethodDebugInformation Read(MethodDefinition method)
{
return reader.Read(method);
}
public void Dispose()
{
reader.Dispose();
}
}
public sealed class PortablePdbWriterProvider : ISymbolWriterProvider
{
public ISymbolWriter GetSymbolWriter(ModuleDefinition module, string fileName)
{
Mixin.CheckModule(module);
Mixin.CheckFileName(fileName);
FileStream file = File.OpenWrite(Mixin.GetPdbFileName(fileName));
return GetSymbolWriter(module, Disposable.Owned(file as Stream));
}
public ISymbolWriter GetSymbolWriter(ModuleDefinition module, Stream symbolStream)
{
Mixin.CheckModule(module);
Mixin.CheckStream(symbolStream);
return GetSymbolWriter(module, Disposable.NotOwned(symbolStream));
}
private ISymbolWriter GetSymbolWriter(ModuleDefinition module, Disposable<Stream> stream)
{
MetadataBuilder metadata = new(module, this);
ImageWriter writer = ImageWriter.CreateDebugWriter(module, metadata, stream);
return new PortablePdbWriter(metadata, module, writer);
}
}
public sealed class PortablePdbWriter : ISymbolWriter
{
private readonly MetadataBuilder pdb_metadata;
private readonly ModuleDefinition module;
private readonly ImageWriter writer;
private MetadataBuilder module_metadata;
private bool IsEmbedded
{
get { return writer == null; }
}
internal PortablePdbWriter(MetadataBuilder pdb_metadata, ModuleDefinition module)
{
this.pdb_metadata = pdb_metadata;
this.module = module;
module_metadata = module.metadata_builder;
if (module_metadata != pdb_metadata)
this.pdb_metadata.metadata_builder = module_metadata;
pdb_metadata.AddCustomDebugInformations(module);
}
internal PortablePdbWriter(MetadataBuilder pdb_metadata, ModuleDefinition module, ImageWriter writer) : this(pdb_metadata, module)
{
this.writer = writer;
}
public ISymbolReaderProvider GetReaderProvider()
{
return new PortablePdbReaderProvider();
}
public ImageDebugHeader GetDebugHeader()
{
if (IsEmbedded)
return new();
ImageDebugDirectory directory = new()
{
MajorVersion = 256,
MinorVersion = 20557,
Type = ImageDebugType.CodeView,
TimeDateStamp = (int)module.timestamp
};
ByteBuffer buffer = new();
// RSDS
buffer.WriteUInt32(0x53445352);
// Module ID
buffer.WriteBytes(module.Mvid.ToByteArray());
// PDB Age
buffer.WriteUInt32(1);
// PDB Path
string fileName = writer.BaseStream.GetFileName();
if (string.IsNullOrEmpty(fileName))
{
fileName = module.Assembly.Name.Name + ".pdb";
}
buffer.WriteBytes(System.Text.Encoding.UTF8.GetBytes(fileName));
buffer.WriteByte(0);
byte[] data = new byte [buffer.length];
Buffer.BlockCopy(buffer.buffer, 0, data, 0, buffer.length);
directory.SizeOfData = data.Length;
return new(new ImageDebugHeaderEntry(directory, data));
}
public void Write(MethodDebugInformation info)
{
CheckMethodDebugInformationTable();
pdb_metadata.AddMethodDebugInformation(info);
}
private void CheckMethodDebugInformationTable()
{
MethodDebugInformationTable mdi = pdb_metadata.table_heap.GetTable<MethodDebugInformationTable>(Table.MethodDebugInformation);
if (mdi.length > 0)
return;
// The MethodDebugInformation table has the same length as the Method table
mdi.rows = new Row<uint, uint> [module_metadata.method_rid - 1];
mdi.length = mdi.rows.Length;
}
public void Dispose()
{
if (IsEmbedded)
return;
WritePdbFile();
}
private void WritePdbFile()
{
WritePdbHeap();
WriteTableHeap();
writer.BuildMetadataTextMap();
writer.WriteMetadataHeader();
writer.WriteMetadata();
writer.Flush();
writer.stream.Dispose();
}
private void WritePdbHeap()
{
PdbHeapBuffer pdb_heap = pdb_metadata.pdb_heap;
pdb_heap.WriteBytes(module.Mvid.ToByteArray());
pdb_heap.WriteUInt32(module_metadata.timestamp);
pdb_heap.WriteUInt32(module_metadata.entry_point.ToUInt32());
TableHeapBuffer table_heap = module_metadata.table_heap;
MetadataTable[] tables = table_heap.tables;
ulong valid = 0;
for (int i = 0; i < tables.Length; i++)
{
if (tables[i] == null || tables[i].Length == 0)
continue;
valid |= 1UL << i;
}
pdb_heap.WriteUInt64(valid);
for (int i = 0; i < tables.Length; i++)
{
if (tables[i] == null || tables[i].Length == 0)
continue;
pdb_heap.WriteUInt32((uint)tables[i].Length);
}
}
private void WriteTableHeap()
{
pdb_metadata.table_heap.string_offsets = pdb_metadata.string_heap.WriteStrings();
pdb_metadata.table_heap.ComputeTableInformations();
pdb_metadata.table_heap.WriteTableHeap();
}
}
public sealed class EmbeddedPortablePdbWriterProvider : ISymbolWriterProvider
{
public ISymbolWriter GetSymbolWriter(ModuleDefinition module, string fileName)
{
Mixin.CheckModule(module);
Mixin.CheckFileName(fileName);
MemoryStream stream = new();
PortablePdbWriter pdb_writer = (PortablePdbWriter)new PortablePdbWriterProvider().GetSymbolWriter(module, stream);
return new EmbeddedPortablePdbWriter(stream, pdb_writer);
}
public ISymbolWriter GetSymbolWriter(ModuleDefinition module, Stream symbolStream)
{
throw new NotSupportedException();
}
}
public sealed class EmbeddedPortablePdbWriter : ISymbolWriter
{
private readonly Stream stream;
private readonly PortablePdbWriter writer;
internal EmbeddedPortablePdbWriter(Stream stream, PortablePdbWriter writer)
{
this.stream = stream;
this.writer = writer;
}
public ISymbolReaderProvider GetReaderProvider()
{
return new EmbeddedPortablePdbReaderProvider();
}
public ImageDebugHeader GetDebugHeader()
{
writer.Dispose();
ImageDebugDirectory directory = new()
{
Type = ImageDebugType.EmbeddedPortablePdb,
MajorVersion = 0x0100,
MinorVersion = 0x0100
};
MemoryStream data = new();
BinaryStreamWriter w = new(data);
w.WriteByte(0x4d);
w.WriteByte(0x50);
w.WriteByte(0x44);
w.WriteByte(0x42);
w.WriteInt32((int)stream.Length);
stream.Position = 0;
using (DeflateStream compress_stream = new(data, CompressionMode.Compress, leaveOpen: true))
{
stream.CopyTo(compress_stream);
}
directory.SizeOfData = (int)data.Length;
return new(new[]
{
writer.GetDebugHeader().Entries[0],
new ImageDebugHeaderEntry(directory, data.ToArray())
});
}
public void Write(MethodDebugInformation info)
{
writer.Write(info);
}
public void Dispose() { }
}
internal static class PdbGuidMapping
{
private static readonly Dictionary<Guid, DocumentLanguage> guid_language = new();
private static readonly Dictionary<DocumentLanguage, Guid> language_guid = new();
static PdbGuidMapping()
{
AddMapping(DocumentLanguage.C, new("63a08714-fc37-11d2-904c-00c04fa302a1"));
AddMapping(DocumentLanguage.Cpp, new("3a12d0b7-c26c-11d0-b442-00a0244a1dd2"));
AddMapping(DocumentLanguage.CSharp, new("3f5162f8-07c6-11d3-9053-00c04fa302a1"));
AddMapping(DocumentLanguage.Basic, new("3a12d0b8-c26c-11d0-b442-00a0244a1dd2"));
AddMapping(DocumentLanguage.Java, new("3a12d0b4-c26c-11d0-b442-00a0244a1dd2"));
AddMapping(DocumentLanguage.Cobol, new("af046cd1-d0e1-11d2-977c-00a0c9b4d50c"));
AddMapping(DocumentLanguage.Pascal, new("af046cd2-d0e1-11d2-977c-00a0c9b4d50c"));
AddMapping(DocumentLanguage.Cil, new("af046cd3-d0e1-11d2-977c-00a0c9b4d50c"));
AddMapping(DocumentLanguage.JScript, new("3a12d0b6-c26c-11d0-b442-00a0244a1dd2"));
AddMapping(DocumentLanguage.Smc, new("0d9b9f7b-6611-11d3-bd2a-0000f80849bd"));
AddMapping(DocumentLanguage.MCpp, new("4b35fde8-07c6-11d3-9053-00c04fa302a1"));
AddMapping(DocumentLanguage.FSharp, new("ab4f38c9-b6e6-43ba-be3b-58080b2ccce3"));
}
private static void AddMapping(DocumentLanguage language, Guid guid)
{
guid_language.Add(guid, language);
language_guid.Add(language, guid);
}
private static readonly Guid type_text = new("5a869d0b-6611-11d3-bd2a-0000f80849bd");
public static DocumentType ToType(this Guid guid)
{
if (guid == type_text)
return DocumentType.Text;
return DocumentType.Other;
}
public static Guid ToGuid(this DocumentType type)
{
if (type == DocumentType.Text)
return type_text;
return new();
}
private static readonly Guid hash_md5 = new("406ea660-64cf-4c82-b6f0-42d48172a799");
private static readonly Guid hash_sha1 = new("ff1816ec-aa5e-4d10-87f7-6f4963833460");
private static readonly Guid hash_sha256 = new("8829d00f-11b8-4213-878b-770e8597ac16");
public static DocumentHashAlgorithm ToHashAlgorithm(this Guid guid)
{
if (guid == hash_md5)
return DocumentHashAlgorithm.MD5;
if (guid == hash_sha1)
return DocumentHashAlgorithm.SHA1;
if (guid == hash_sha256)
return DocumentHashAlgorithm.SHA256;
return DocumentHashAlgorithm.None;
}
public static Guid ToGuid(this DocumentHashAlgorithm hash_algo)
{
if (hash_algo == DocumentHashAlgorithm.MD5)
return hash_md5;
if (hash_algo == DocumentHashAlgorithm.SHA1)
return hash_sha1;
if (hash_algo == DocumentHashAlgorithm.SHA256)
return hash_sha256;
return new();
}
public static DocumentLanguage ToLanguage(this Guid guid)
{
DocumentLanguage language;
if (!guid_language.TryGetValue(guid, out language))
return DocumentLanguage.Other;
return language;
}
public static Guid ToGuid(this DocumentLanguage language)
{
Guid guid;
if (!language_guid.TryGetValue(language, out guid))
return new();
return guid;
}
private static readonly Guid vendor_ms = new("994b45c4-e6e9-11d2-903f-00c04fa302a1");
public static DocumentLanguageVendor ToVendor(this Guid guid)
{
if (guid == vendor_ms)
return DocumentLanguageVendor.Microsoft;
return DocumentLanguageVendor.Other;
}
public static Guid ToGuid(this DocumentLanguageVendor vendor)
{
if (vendor == DocumentLanguageVendor.Microsoft)
return vendor_ms;
return new();
}
}
}