xamarin-macios/tools/linker/CustomSymbolWriter.cs

86 строки
3.0 KiB
C#

using System;
using System.IO;
using System.Text;
using Mono.Cecil;
using Mono.Cecil.Cil;
namespace Xamarin.Linker {
public sealed class CustomSymbolWriterProvider : ISymbolWriterProvider {
readonly DefaultSymbolWriterProvider default_symbol_writer_provider = new DefaultSymbolWriterProvider ();
public ISymbolWriter GetSymbolWriter (ModuleDefinition module, string filename)
=> new CustomSymbolWriter (default_symbol_writer_provider.GetSymbolWriter (module, filename));
public ISymbolWriter GetSymbolWriter (ModuleDefinition module, Stream symbolStream)
=> new CustomSymbolWriter (default_symbol_writer_provider.GetSymbolWriter (module, symbolStream));
}
// This is symbol writer wraps another symbol writer, and changes one thing:
// it writes the filename part of the pdb (as opposed to the full path), in the debug header of the dll.
// References:
// https://bugzilla.xamarin.com/show_bug.cgi?id=54578 (Assemblies are duplicated in fat apps when built with .pdb, because pdb paths are different)
// https://github.com/jbevain/cecil/issues/372 (first attempt at a fix: make cecil write the filename only)
// https://github.com/jbevain/cecil/pull/554 (first fix attempt broke something else, so it had to be reverted)
public sealed class CustomSymbolWriter : ISymbolWriter {
readonly ISymbolWriter _symbolWriter;
public CustomSymbolWriter (ISymbolWriter symbolWriter)
{
_symbolWriter = symbolWriter;
}
public ImageDebugHeader GetDebugHeader ()
{
var header = _symbolWriter.GetDebugHeader ();
if (!header.HasEntries)
return header;
for (int i = 0; i < header.Entries.Length; i++) {
header.Entries [i] = ProcessEntry (header.Entries [i]);
}
return header;
}
static 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 != 0x53445352)
return entry;
writer.Write (sig); // RSDS
writer.Write (reader.ReadBytes (16)); // MVID
writer.Write (reader.ReadUInt32 ()); // Age
var fullPath = Encoding.UTF8.GetString (reader.ReadBytes (entry.Data.Length - 1 - 24)); // length - ending \0 - RSDS+MVID+AGE
writer.Write (Encoding.UTF8.GetBytes (Path.GetFileName (fullPath)));
writer.Write ((byte) 0);
var newData = newDataStream.ToArray ();
var directory = entry.Directory;
directory.SizeOfData = newData.Length;
return new ImageDebugHeaderEntry (directory, newData);
}
public ISymbolReaderProvider GetReaderProvider () => _symbolWriter.GetReaderProvider ();
public void Write (MethodDebugInformation info) => _symbolWriter.Write (info);
public void Write () => _symbolWriter.Write ();
public void Dispose () => _symbolWriter.Dispose ();
#if NET
public void Write (ICustomDebugInformationProvider provider) => _symbolWriter.Write (provider);
#endif
}
}