123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365 |
- //
- // 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 System;
- using System.Collections.Generic;
- using System.IO;
- using System.Linq;
- using System.Text;
- using ILRuntime.Mono.Cecil.Cil;
- using ILRuntime.Mono.Cecil.PE;
- using ILRuntime.Mono.Collections.Generic;
- namespace ILRuntime.Mono.Cecil.Pdb {
- public class NativePdbWriter : ISymbolWriter {
- readonly ModuleDefinition module;
- readonly MetadataBuilder metadata;
- readonly SymWriter writer;
- readonly Dictionary<string, SymDocumentWriter> documents;
- readonly Dictionary<ImportDebugInformation, MetadataToken> import_info_to_parent;
- internal NativePdbWriter (ModuleDefinition module, SymWriter writer)
- {
- this.module = module;
- this.metadata = module.metadata_builder;
- this.writer = writer;
- this.documents = new Dictionary<string, SymDocumentWriter> ();
- this.import_info_to_parent = new Dictionary<ImportDebugInformation, MetadataToken> ();
- }
- public ISymbolReaderProvider GetReaderProvider ()
- {
- return new NativePdbReaderProvider ();
- }
- public ImageDebugHeader GetDebugHeader ()
- {
- ImageDebugDirectory directory;
- var data = writer.GetDebugInfo (out directory);
- directory.TimeDateStamp = (int) module.timestamp;
- return new ImageDebugHeader (new ImageDebugHeaderEntry (directory, data));
- }
- public void Write (MethodDebugInformation info)
- {
- var method_token = info.method.MetadataToken;
- var sym_token = method_token.ToInt32 ();
- if (!info.HasSequencePoints && info.scope == null && !info.HasCustomDebugInformations && info.StateMachineKickOffMethod == null)
- return;
- writer.OpenMethod (sym_token);
- if (!info.sequence_points.IsNullOrEmpty ())
- DefineSequencePoints (info.sequence_points);
- var import_parent = new MetadataToken ();
- if (info.scope != null)
- DefineScope (info.scope, info, out import_parent);
- DefineCustomMetadata (info, import_parent);
- writer.CloseMethod ();
- }
- void DefineCustomMetadata (MethodDebugInformation info, MetadataToken import_parent)
- {
- var metadata = new CustomMetadataWriter (this.writer);
- if (import_parent.RID != 0) {
- metadata.WriteForwardInfo (import_parent);
- } else if (info.scope != null && info.scope.Import != null && info.scope.Import.HasTargets) {
- metadata.WriteUsingInfo (info.scope.Import);
- }
- if (info.Method.HasCustomAttributes) {
- foreach (var attribute in info.Method.CustomAttributes) {
- const string compiler_services = "System.Runtime.CompilerServices";
- var attribute_type = attribute.AttributeType;
- if (!attribute_type.IsTypeOf (compiler_services, "IteratorStateMachineAttribute") && !attribute_type.IsTypeOf (compiler_services, "AsyncStateMachineAttribute"))
- continue;
- var type = attribute.ConstructorArguments [0].Value as TypeReference;
- if (type == null)
- continue;
- metadata.WriteForwardIterator (type);
- }
- }
- if (info.HasCustomDebugInformations) {
- var state_machine = info.CustomDebugInformations.FirstOrDefault (cdi => cdi.Kind == CustomDebugInformationKind.StateMachineScope) as StateMachineScopeDebugInformation;
- if (state_machine != null)
- metadata.WriteIteratorScopes (state_machine, info);
- }
- metadata.WriteCustomMetadata ();
- DefineAsyncCustomMetadata (info);
- }
- void DefineAsyncCustomMetadata (MethodDebugInformation info)
- {
- if (!info.HasCustomDebugInformations)
- return;
- foreach (var custom_info in info.CustomDebugInformations) {
- var async_debug_info = custom_info as AsyncMethodBodyDebugInformation;
- if (async_debug_info == null)
- continue;
- using (var stream = new MemoryStream ()) {
- var async_metadata = new BinaryStreamWriter (stream);
- async_metadata.WriteUInt32 (info.StateMachineKickOffMethod != null ? info.StateMachineKickOffMethod.MetadataToken.ToUInt32 () : 0);
- async_metadata.WriteUInt32 ((uint) async_debug_info.CatchHandler.Offset);
- async_metadata.WriteUInt32 ((uint) async_debug_info.Resumes.Count);
- for (int i = 0; i < async_debug_info.Resumes.Count; ++i) {
- async_metadata.WriteUInt32 ((uint) async_debug_info.Yields [i].Offset);
- async_metadata.WriteUInt32 (async_debug_info.resume_methods [i].MetadataToken.ToUInt32 ());
- async_metadata.WriteUInt32 ((uint) async_debug_info.Resumes [i].Offset);
- }
- writer.DefineCustomMetadata ("asyncMethodInfo", stream.ToArray ());
- }
- }
- }
- void DefineScope (ScopeDebugInformation scope, MethodDebugInformation info, out MetadataToken import_parent)
- {
- var start_offset = scope.Start.Offset;
- var end_offset = scope.End.IsEndOfMethod
- ? info.code_size
- : scope.End.Offset;
- import_parent = new MetadataToken (0u);
- writer.OpenScope (start_offset);
- if (scope.Import != null && scope.Import.HasTargets && !import_info_to_parent.TryGetValue (info.scope.Import, out import_parent)) {
- foreach (var target in scope.Import.Targets) {
- switch (target.Kind) {
- case ImportTargetKind.ImportNamespace:
- writer.UsingNamespace ("U" + target.@namespace);
- break;
- case ImportTargetKind.ImportType:
- writer.UsingNamespace ("T" + TypeParser.ToParseable (target.type));
- break;
- case ImportTargetKind.DefineNamespaceAlias:
- writer.UsingNamespace ("A" + target.Alias + " U" + target.@namespace);
- break;
- case ImportTargetKind.DefineTypeAlias:
- writer.UsingNamespace ("A" + target.Alias + " T" + TypeParser.ToParseable (target.type));
- break;
- }
- }
- import_info_to_parent.Add (info.scope.Import, info.method.MetadataToken);
- }
- var sym_token = info.local_var_token.ToInt32 ();
- if (!scope.variables.IsNullOrEmpty ()) {
- for (int i = 0; i < scope.variables.Count; i++) {
- var variable = scope.variables [i];
- DefineLocalVariable (variable, sym_token, start_offset, end_offset);
- }
- }
- if (!scope.constants.IsNullOrEmpty ()) {
- for (int i = 0; i < scope.constants.Count; i++) {
- var constant = scope.constants [i];
- DefineConstant (constant);
- }
- }
- if (!scope.scopes.IsNullOrEmpty ()) {
- for (int i = 0; i < scope.scopes.Count; i++) {
- MetadataToken _;
- DefineScope (scope.scopes [i], info, out _);
- }
- }
- writer.CloseScope (end_offset);
- }
- void DefineSequencePoints (Collection<SequencePoint> sequence_points)
- {
- for (int i = 0; i < sequence_points.Count; i++) {
- var sequence_point = sequence_points [i];
- writer.DefineSequencePoints (
- GetDocument (sequence_point.Document),
- new [] { sequence_point.Offset },
- new [] { sequence_point.StartLine },
- new [] { sequence_point.StartColumn },
- new [] { sequence_point.EndLine },
- new [] { sequence_point.EndColumn });
- }
- }
- void DefineLocalVariable (VariableDebugInformation variable, int local_var_token, int start_offset, int end_offset)
- {
- writer.DefineLocalVariable2 (
- variable.Name,
- variable.Attributes,
- local_var_token,
- variable.Index,
- 0,
- 0,
- start_offset,
- end_offset);
- }
- void DefineConstant (ConstantDebugInformation constant)
- {
- var row = metadata.AddStandAloneSignature (metadata.GetConstantTypeBlobIndex (constant.ConstantType));
- var token = new MetadataToken (TokenType.Signature, row);
- writer.DefineConstant2 (constant.Name, constant.Value, token.ToInt32 ());
- }
- SymDocumentWriter GetDocument (Document document)
- {
- if (document == null)
- return null;
- SymDocumentWriter doc_writer;
- if (documents.TryGetValue (document.Url, out doc_writer))
- return doc_writer;
- doc_writer = writer.DefineDocument (
- document.Url,
- document.LanguageGuid,
- document.LanguageVendorGuid,
- document.TypeGuid);
- if (!document.Hash.IsNullOrEmpty ())
- doc_writer.SetCheckSum (document.HashAlgorithmGuid, document.Hash);
- documents [document.Url] = doc_writer;
- return doc_writer;
- }
- public void Dispose ()
- {
- var entry_point = module.EntryPoint;
- if (entry_point != null)
- writer.SetUserEntryPoint (entry_point.MetadataToken.ToInt32 ());
- writer.Close ();
- }
- }
- enum CustomMetadataType : byte {
- UsingInfo = 0,
- ForwardInfo = 1,
- IteratorScopes = 3,
- ForwardIterator = 4,
- }
- class CustomMetadataWriter : IDisposable {
- readonly SymWriter sym_writer;
- readonly MemoryStream stream;
- readonly BinaryStreamWriter writer;
- int count;
- const byte version = 4;
- public CustomMetadataWriter (SymWriter sym_writer)
- {
- this.sym_writer = sym_writer;
- this.stream = new MemoryStream ();
- this.writer = new BinaryStreamWriter (stream);
- writer.WriteByte (version);
- writer.WriteByte (0); // count
- writer.Align (4);
- }
- public void WriteUsingInfo (ImportDebugInformation import_info)
- {
- Write (CustomMetadataType.UsingInfo, () => {
- writer.WriteUInt16 ((ushort) 1);
- writer.WriteUInt16 ((ushort) import_info.Targets.Count);
- });
- }
- public void WriteForwardInfo (MetadataToken import_parent)
- {
- Write (CustomMetadataType.ForwardInfo, () => writer.WriteUInt32 (import_parent.ToUInt32 ()));
- }
- public void WriteIteratorScopes (StateMachineScopeDebugInformation state_machine, MethodDebugInformation debug_info)
- {
- Write (CustomMetadataType.IteratorScopes, () => {
- var scopes = state_machine.Scopes;
- writer.WriteInt32 (scopes.Count);
- foreach (var scope in scopes) {
- var start = scope.Start.Offset;
- var end = scope.End.IsEndOfMethod ? debug_info.code_size : scope.End.Offset;
- writer.WriteInt32 (start);
- writer.WriteInt32 (end - 1);
- }
- });
- }
- public void WriteForwardIterator (TypeReference type)
- {
- Write (CustomMetadataType.ForwardIterator, () => writer.WriteBytes(Encoding.Unicode.GetBytes(type.Name)));
- }
- void Write (CustomMetadataType type, Action write)
- {
- count++;
- writer.WriteByte (version);
- writer.WriteByte ((byte) type);
- writer.Align (4);
- var length_position = writer.Position;
- writer.WriteUInt32 (0);
- write ();
- writer.Align (4);
- var end = writer.Position;
- var length = end - length_position + 4; // header is 4 bytes long
- writer.Position = length_position;
- writer.WriteInt32 (length);
- writer.Position = end;
- }
- public void WriteCustomMetadata ()
- {
- if (count == 0)
- return;
- writer.BaseStream.Position = 1;
- writer.WriteByte ((byte) count);
- writer.Flush ();
- sym_writer.DefineCustomMetadata ("MD2", stream.ToArray ());
- }
- public void Dispose ()
- {
- stream.Dispose ();
- }
- }
- }
|