| File: Linker\CustomSymbolWriter.cs | Web Access |
| Project: src\runtime\src\tools\illink\src\linker\Mono.Linker.csproj (illink) |
// Copyright (c) .NET Foundation and contributors. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System.IO; using System.Text; using Mono.Cecil; using Mono.Cecil.Cil; namespace Mono.Linker { internal sealed class CustomSymbolWriterProvider : ISymbolWriterProvider { readonly DefaultSymbolWriterProvider _defaultProvider = new DefaultSymbolWriterProvider(); readonly bool _preserveSymbolPaths; public CustomSymbolWriterProvider(bool preserveSymbolPaths) => this._preserveSymbolPaths = preserveSymbolPaths; public ISymbolWriter GetSymbolWriter(ModuleDefinition module, string fileName) => new CustomSymbolWriter(_defaultProvider.GetSymbolWriter(module, fileName), module, _preserveSymbolPaths); public ISymbolWriter GetSymbolWriter(ModuleDefinition module, Stream symbolStream) => new CustomSymbolWriter(_defaultProvider.GetSymbolWriter(module, symbolStream), module, _preserveSymbolPaths); } internal sealed class CustomSymbolWriter : ISymbolWriter { // ASCII "RSDS": https://github.com/dotnet/runtime/blob/main/docs/design/specs/PE-COFF.md#codeview-debug-directory-entry-type-2 const int CodeViewSignature = 0x53445352; readonly ISymbolWriter _symbolWriter; readonly ModuleDefinition _module; readonly bool _preserveSymbolPaths; internal CustomSymbolWriter(ISymbolWriter defaultWriter, ModuleDefinition module, bool preserveSymbolPaths) { _symbolWriter = defaultWriter; _module = module; _preserveSymbolPaths = preserveSymbolPaths; } public ImageDebugHeader GetDebugHeader() { var header = _symbolWriter.GetDebugHeader(); if (!_preserveSymbolPaths) return header; if (!header.HasEntries) return header; for (int i = 0; i < header.Entries.Length; i++) { header.Entries[i] = ProcessEntry(header.Entries[i]); } return header; } ImageDebugHeaderEntry ProcessEntry(ImageDebugHeaderEntry entry) { if (entry.Directory.Type != ImageDebugType.CodeView) return entry; var reader = new BinaryReader(new MemoryStream(entry.Data)); var newDataStream = new MemoryStream(); var writer = new BinaryWriter(newDataStream); var sig = reader.ReadUInt32(); if (sig != CodeViewSignature) return entry; writer.Write(sig); writer.Write(reader.ReadBytes(16)); // MVID writer.Write(reader.ReadUInt32()); // Age writer.Write(Encoding.UTF8.GetBytes(GetOriginalPdbPath())); writer.Write((byte)0); var newData = newDataStream.ToArray(); var directory = entry.Directory; directory.SizeOfData = newData.Length; return new ImageDebugHeaderEntry(directory, newData); } string GetOriginalPdbPath() { if (!_module.HasDebugHeader) return string.Empty; var debugHeader = _module.GetDebugHeader(); foreach (var entry in debugHeader.Entries) { if (entry.Directory.Type != ImageDebugType.CodeView) continue; var reader = new BinaryReader(new MemoryStream(entry.Data)); var sig = reader.ReadUInt32(); if (sig != CodeViewSignature) return string.Empty; var stream = reader.BaseStream; stream.Seek(16 + 4, SeekOrigin.Current); // MVID and Age // Pdb path is NUL-terminated path at offset 24. // https://github.com/dotnet/runtime/blob/main/docs/design/specs/PE-COFF.md#codeview-debug-directory-entry-type-2 return Encoding.UTF8.GetString( reader.ReadBytes((int)(stream.Length - stream.Position - 1))); // remaining length - ending \0 } return string.Empty; } public ISymbolReaderProvider GetReaderProvider() => _symbolWriter.GetReaderProvider(); public void Write(MethodDebugInformation info) => _symbolWriter.Write(info); public void Write(ICustomDebugInformationProvider provider) => _symbolWriter.Write(provider); public void Write() => _symbolWriter.Write(); public void Dispose() => _symbolWriter.Dispose(); } }