/Mono.Cecil.Cil/Symbols.cs

http://github.com/jbevain/cecil · C# · 1164 lines · 895 code · 256 blank · 13 comment · 124 complexity · d38b7c5e9999be051e679e5770a133e1 MD5 · raw file

  1. //
  2. // Author:
  3. // Jb Evain (jbevain@gmail.com)
  4. //
  5. // Copyright (c) 2008 - 2015 Jb Evain
  6. // Copyright (c) 2008 - 2011 Novell, Inc.
  7. //
  8. // Licensed under the MIT/X11 license.
  9. //
  10. using System;
  11. using System.Collections.Generic;
  12. using System.IO;
  13. using System.Runtime.InteropServices;
  14. using System.Threading;
  15. using SR = System.Reflection;
  16. using Mono.Collections.Generic;
  17. using Mono.Cecil.Cil;
  18. using Mono.Cecil.PE;
  19. namespace Mono.Cecil.Cil {
  20. [StructLayout (LayoutKind.Sequential)]
  21. public struct ImageDebugDirectory {
  22. public const int Size = 28;
  23. public int Characteristics;
  24. public int TimeDateStamp;
  25. public short MajorVersion;
  26. public short MinorVersion;
  27. public ImageDebugType Type;
  28. public int SizeOfData;
  29. public int AddressOfRawData;
  30. public int PointerToRawData;
  31. }
  32. public enum ImageDebugType {
  33. CodeView = 2,
  34. Deterministic = 16,
  35. EmbeddedPortablePdb = 17,
  36. }
  37. public sealed class ImageDebugHeader {
  38. readonly ImageDebugHeaderEntry [] entries;
  39. public bool HasEntries {
  40. get { return !entries.IsNullOrEmpty (); }
  41. }
  42. public ImageDebugHeaderEntry [] Entries {
  43. get { return entries; }
  44. }
  45. public ImageDebugHeader (ImageDebugHeaderEntry [] entries)
  46. {
  47. this.entries = entries ?? Empty<ImageDebugHeaderEntry>.Array;
  48. }
  49. public ImageDebugHeader ()
  50. : this (Empty<ImageDebugHeaderEntry>.Array)
  51. {
  52. }
  53. public ImageDebugHeader (ImageDebugHeaderEntry entry)
  54. : this (new [] { entry })
  55. {
  56. }
  57. }
  58. public sealed class ImageDebugHeaderEntry {
  59. ImageDebugDirectory directory;
  60. readonly byte [] data;
  61. public ImageDebugDirectory Directory {
  62. get { return directory; }
  63. internal set { directory = value; }
  64. }
  65. public byte [] Data {
  66. get { return data; }
  67. }
  68. public ImageDebugHeaderEntry (ImageDebugDirectory directory, byte [] data)
  69. {
  70. this.directory = directory;
  71. this.data = data ?? Empty<byte>.Array;
  72. }
  73. }
  74. public sealed class ScopeDebugInformation : DebugInformation {
  75. internal InstructionOffset start;
  76. internal InstructionOffset end;
  77. internal ImportDebugInformation import;
  78. internal Collection<ScopeDebugInformation> scopes;
  79. internal Collection<VariableDebugInformation> variables;
  80. internal Collection<ConstantDebugInformation> constants;
  81. public InstructionOffset Start {
  82. get { return start; }
  83. set { start = value; }
  84. }
  85. public InstructionOffset End {
  86. get { return end; }
  87. set { end = value; }
  88. }
  89. public ImportDebugInformation Import {
  90. get { return import; }
  91. set { import = value; }
  92. }
  93. public bool HasScopes {
  94. get { return !scopes.IsNullOrEmpty (); }
  95. }
  96. public Collection<ScopeDebugInformation> Scopes {
  97. get {
  98. if (scopes == null)
  99. Interlocked.CompareExchange (ref scopes, new Collection<ScopeDebugInformation> (), null);
  100. return scopes;
  101. }
  102. }
  103. public bool HasVariables {
  104. get { return !variables.IsNullOrEmpty (); }
  105. }
  106. public Collection<VariableDebugInformation> Variables {
  107. get {
  108. if (variables == null)
  109. Interlocked.CompareExchange (ref variables, new Collection<VariableDebugInformation> (), null);
  110. return variables;
  111. }
  112. }
  113. public bool HasConstants {
  114. get { return !constants.IsNullOrEmpty (); }
  115. }
  116. public Collection<ConstantDebugInformation> Constants {
  117. get {
  118. if (constants == null)
  119. Interlocked.CompareExchange (ref constants, new Collection<ConstantDebugInformation> (), null);
  120. return constants;
  121. }
  122. }
  123. internal ScopeDebugInformation ()
  124. {
  125. this.token = new MetadataToken (TokenType.LocalScope);
  126. }
  127. public ScopeDebugInformation (Instruction start, Instruction end)
  128. : this ()
  129. {
  130. if (start == null)
  131. throw new ArgumentNullException ("start");
  132. this.start = new InstructionOffset (start);
  133. if (end != null)
  134. this.end = new InstructionOffset (end);
  135. }
  136. public bool TryGetName (VariableDefinition variable, out string name)
  137. {
  138. name = null;
  139. if (variables == null || variables.Count == 0)
  140. return false;
  141. for (int i = 0; i < variables.Count; i++) {
  142. if (variables [i].Index == variable.Index) {
  143. name = variables [i].Name;
  144. return true;
  145. }
  146. }
  147. return false;
  148. }
  149. }
  150. public struct InstructionOffset {
  151. readonly Instruction instruction;
  152. readonly int? offset;
  153. public int Offset {
  154. get {
  155. if (instruction != null)
  156. return instruction.Offset;
  157. if (offset.HasValue)
  158. return offset.Value;
  159. throw new NotSupportedException ();
  160. }
  161. }
  162. public bool IsEndOfMethod {
  163. get { return instruction == null && !offset.HasValue; }
  164. }
  165. public InstructionOffset (Instruction instruction)
  166. {
  167. if (instruction == null)
  168. throw new ArgumentNullException ("instruction");
  169. this.instruction = instruction;
  170. this.offset = null;
  171. }
  172. public InstructionOffset (int offset)
  173. {
  174. this.instruction = null;
  175. this.offset = offset;
  176. }
  177. }
  178. [Flags]
  179. public enum VariableAttributes : ushort {
  180. None = 0,
  181. DebuggerHidden = 1,
  182. }
  183. public struct VariableIndex {
  184. readonly VariableDefinition variable;
  185. readonly int? index;
  186. public int Index {
  187. get {
  188. if (variable != null)
  189. return variable.Index;
  190. if (index.HasValue)
  191. return index.Value;
  192. throw new NotSupportedException ();
  193. }
  194. }
  195. public VariableIndex (VariableDefinition variable)
  196. {
  197. if (variable == null)
  198. throw new ArgumentNullException ("variable");
  199. this.variable = variable;
  200. this.index = null;
  201. }
  202. public VariableIndex (int index)
  203. {
  204. this.variable = null;
  205. this.index = index;
  206. }
  207. }
  208. public abstract class DebugInformation : ICustomDebugInformationProvider {
  209. internal MetadataToken token;
  210. internal Collection<CustomDebugInformation> custom_infos;
  211. public MetadataToken MetadataToken {
  212. get { return token; }
  213. set { token = value; }
  214. }
  215. public bool HasCustomDebugInformations {
  216. get { return !custom_infos.IsNullOrEmpty (); }
  217. }
  218. public Collection<CustomDebugInformation> CustomDebugInformations {
  219. get {
  220. if (custom_infos == null)
  221. Interlocked.CompareExchange (ref custom_infos, new Collection<CustomDebugInformation> (), null);
  222. return custom_infos;
  223. }
  224. }
  225. internal DebugInformation ()
  226. {
  227. }
  228. }
  229. public sealed class VariableDebugInformation : DebugInformation {
  230. string name;
  231. ushort attributes;
  232. internal VariableIndex index;
  233. public int Index {
  234. get { return index.Index; }
  235. }
  236. public string Name {
  237. get { return name; }
  238. set { name = value; }
  239. }
  240. public VariableAttributes Attributes {
  241. get { return (VariableAttributes) attributes; }
  242. set { attributes = (ushort) value; }
  243. }
  244. public bool IsDebuggerHidden {
  245. get { return attributes.GetAttributes ((ushort) VariableAttributes.DebuggerHidden); }
  246. set { attributes = attributes.SetAttributes ((ushort) VariableAttributes.DebuggerHidden, value); }
  247. }
  248. internal VariableDebugInformation (int index, string name)
  249. {
  250. if (name == null)
  251. throw new ArgumentNullException ("name");
  252. this.index = new VariableIndex (index);
  253. this.name = name;
  254. }
  255. public VariableDebugInformation (VariableDefinition variable, string name)
  256. {
  257. if (variable == null)
  258. throw new ArgumentNullException ("variable");
  259. if (name == null)
  260. throw new ArgumentNullException ("name");
  261. this.index = new VariableIndex (variable);
  262. this.name = name;
  263. this.token = new MetadataToken (TokenType.LocalVariable);
  264. }
  265. }
  266. public sealed class ConstantDebugInformation : DebugInformation {
  267. string name;
  268. TypeReference constant_type;
  269. object value;
  270. public string Name {
  271. get { return name; }
  272. set { name = value; }
  273. }
  274. public TypeReference ConstantType {
  275. get { return constant_type; }
  276. set { constant_type = value; }
  277. }
  278. public object Value {
  279. get { return value; }
  280. set { this.value = value; }
  281. }
  282. public ConstantDebugInformation (string name, TypeReference constant_type, object value)
  283. {
  284. if (name == null)
  285. throw new ArgumentNullException ("name");
  286. this.name = name;
  287. this.constant_type = constant_type;
  288. this.value = value;
  289. this.token = new MetadataToken (TokenType.LocalConstant);
  290. }
  291. }
  292. public enum ImportTargetKind : byte {
  293. ImportNamespace = 1,
  294. ImportNamespaceInAssembly = 2,
  295. ImportType = 3,
  296. ImportXmlNamespaceWithAlias = 4,
  297. ImportAlias = 5,
  298. DefineAssemblyAlias = 6,
  299. DefineNamespaceAlias = 7,
  300. DefineNamespaceInAssemblyAlias = 8,
  301. DefineTypeAlias = 9,
  302. }
  303. public sealed class ImportTarget {
  304. internal ImportTargetKind kind;
  305. internal string @namespace;
  306. internal TypeReference type;
  307. internal AssemblyNameReference reference;
  308. internal string alias;
  309. public string Namespace {
  310. get { return @namespace; }
  311. set { @namespace = value; }
  312. }
  313. public TypeReference Type {
  314. get { return type; }
  315. set { type = value; }
  316. }
  317. public AssemblyNameReference AssemblyReference {
  318. get { return reference; }
  319. set { reference = value; }
  320. }
  321. public string Alias {
  322. get { return alias; }
  323. set { alias = value; }
  324. }
  325. public ImportTargetKind Kind {
  326. get { return kind; }
  327. set { kind = value; }
  328. }
  329. public ImportTarget (ImportTargetKind kind)
  330. {
  331. this.kind = kind;
  332. }
  333. }
  334. public sealed class ImportDebugInformation : DebugInformation {
  335. internal ImportDebugInformation parent;
  336. internal Collection<ImportTarget> targets;
  337. public bool HasTargets {
  338. get { return !targets.IsNullOrEmpty (); }
  339. }
  340. public Collection<ImportTarget> Targets {
  341. get
  342. {
  343. if (targets == null)
  344. Interlocked.CompareExchange (ref targets, new Collection<ImportTarget> (), null);
  345. return targets;
  346. }
  347. }
  348. public ImportDebugInformation Parent {
  349. get { return parent; }
  350. set { parent = value; }
  351. }
  352. public ImportDebugInformation ()
  353. {
  354. this.token = new MetadataToken (TokenType.ImportScope);
  355. }
  356. }
  357. public interface ICustomDebugInformationProvider : IMetadataTokenProvider {
  358. bool HasCustomDebugInformations { get; }
  359. Collection<CustomDebugInformation> CustomDebugInformations { get; }
  360. }
  361. public enum CustomDebugInformationKind {
  362. Binary,
  363. StateMachineScope,
  364. DynamicVariable,
  365. DefaultNamespace,
  366. AsyncMethodBody,
  367. EmbeddedSource,
  368. SourceLink,
  369. }
  370. public abstract class CustomDebugInformation : DebugInformation {
  371. Guid identifier;
  372. public Guid Identifier {
  373. get { return identifier; }
  374. }
  375. public abstract CustomDebugInformationKind Kind { get; }
  376. internal CustomDebugInformation (Guid identifier)
  377. {
  378. this.identifier = identifier;
  379. this.token = new MetadataToken (TokenType.CustomDebugInformation);
  380. }
  381. }
  382. public sealed class BinaryCustomDebugInformation : CustomDebugInformation {
  383. byte [] data;
  384. public byte [] Data {
  385. get { return data; }
  386. set { data = value; }
  387. }
  388. public override CustomDebugInformationKind Kind {
  389. get { return CustomDebugInformationKind.Binary; }
  390. }
  391. public BinaryCustomDebugInformation (Guid identifier, byte [] data)
  392. : base (identifier)
  393. {
  394. this.data = data;
  395. }
  396. }
  397. public sealed class AsyncMethodBodyDebugInformation : CustomDebugInformation {
  398. internal InstructionOffset catch_handler;
  399. internal Collection<InstructionOffset> yields;
  400. internal Collection<InstructionOffset> resumes;
  401. internal Collection<MethodDefinition> resume_methods;
  402. public InstructionOffset CatchHandler {
  403. get { return catch_handler; }
  404. set { catch_handler = value; }
  405. }
  406. public Collection<InstructionOffset> Yields {
  407. get {
  408. if (yields == null)
  409. Interlocked.CompareExchange (ref yields, new Collection<InstructionOffset> (), null);
  410. return yields;
  411. }
  412. }
  413. public Collection<InstructionOffset> Resumes {
  414. get {
  415. if (resumes == null)
  416. Interlocked.CompareExchange (ref resumes, new Collection<InstructionOffset> (), null);
  417. return resumes;
  418. }
  419. }
  420. public Collection<MethodDefinition> ResumeMethods {
  421. get { return resume_methods ?? (resume_methods = new Collection<MethodDefinition> ()); }
  422. }
  423. public override CustomDebugInformationKind Kind {
  424. get { return CustomDebugInformationKind.AsyncMethodBody; }
  425. }
  426. public static Guid KindIdentifier = new Guid ("{54FD2AC5-E925-401A-9C2A-F94F171072F8}");
  427. internal AsyncMethodBodyDebugInformation (int catchHandler)
  428. : base (KindIdentifier)
  429. {
  430. this.catch_handler = new InstructionOffset (catchHandler);
  431. }
  432. public AsyncMethodBodyDebugInformation (Instruction catchHandler)
  433. : base (KindIdentifier)
  434. {
  435. this.catch_handler = new InstructionOffset (catchHandler);
  436. }
  437. public AsyncMethodBodyDebugInformation ()
  438. : base (KindIdentifier)
  439. {
  440. this.catch_handler = new InstructionOffset (-1);
  441. }
  442. }
  443. public sealed class StateMachineScope {
  444. internal InstructionOffset start;
  445. internal InstructionOffset end;
  446. public InstructionOffset Start {
  447. get { return start; }
  448. set { start = value; }
  449. }
  450. public InstructionOffset End {
  451. get { return end; }
  452. set { end = value; }
  453. }
  454. internal StateMachineScope (int start, int end)
  455. {
  456. this.start = new InstructionOffset (start);
  457. this.end = new InstructionOffset (end);
  458. }
  459. public StateMachineScope (Instruction start, Instruction end)
  460. {
  461. this.start = new InstructionOffset (start);
  462. this.end = end != null ? new InstructionOffset (end) : new InstructionOffset ();
  463. }
  464. }
  465. public sealed class StateMachineScopeDebugInformation : CustomDebugInformation {
  466. internal Collection<StateMachineScope> scopes;
  467. public Collection<StateMachineScope> Scopes {
  468. get { return scopes ?? (scopes = new Collection<StateMachineScope> ()); }
  469. }
  470. public override CustomDebugInformationKind Kind {
  471. get { return CustomDebugInformationKind.StateMachineScope; }
  472. }
  473. public static Guid KindIdentifier = new Guid ("{6DA9A61E-F8C7-4874-BE62-68BC5630DF71}");
  474. public StateMachineScopeDebugInformation ()
  475. : base (KindIdentifier)
  476. {
  477. }
  478. }
  479. public sealed class EmbeddedSourceDebugInformation : CustomDebugInformation {
  480. internal byte [] content;
  481. internal bool compress;
  482. public byte [] Content {
  483. get { return content; }
  484. set { content = value; }
  485. }
  486. public bool Compress {
  487. get { return compress; }
  488. set { compress = value; }
  489. }
  490. public override CustomDebugInformationKind Kind {
  491. get { return CustomDebugInformationKind.EmbeddedSource; }
  492. }
  493. public static Guid KindIdentifier = new Guid ("{0E8A571B-6926-466E-B4AD-8AB04611F5FE}");
  494. public EmbeddedSourceDebugInformation (byte [] content, bool compress)
  495. : base (KindIdentifier)
  496. {
  497. this.content = content;
  498. this.compress = compress;
  499. }
  500. }
  501. public sealed class SourceLinkDebugInformation : CustomDebugInformation {
  502. internal string content;
  503. public string Content {
  504. get { return content; }
  505. set { content = value; }
  506. }
  507. public override CustomDebugInformationKind Kind {
  508. get { return CustomDebugInformationKind.SourceLink; }
  509. }
  510. public static Guid KindIdentifier = new Guid ("{CC110556-A091-4D38-9FEC-25AB9A351A6A}");
  511. public SourceLinkDebugInformation (string content)
  512. : base (KindIdentifier)
  513. {
  514. this.content = content;
  515. }
  516. }
  517. public sealed class MethodDebugInformation : DebugInformation {
  518. internal MethodDefinition method;
  519. internal Collection<SequencePoint> sequence_points;
  520. internal ScopeDebugInformation scope;
  521. internal MethodDefinition kickoff_method;
  522. internal int code_size;
  523. internal MetadataToken local_var_token;
  524. public MethodDefinition Method {
  525. get { return method; }
  526. }
  527. public bool HasSequencePoints {
  528. get { return !sequence_points.IsNullOrEmpty (); }
  529. }
  530. public Collection<SequencePoint> SequencePoints {
  531. get {
  532. if (sequence_points == null)
  533. Interlocked.CompareExchange (ref sequence_points, new Collection<SequencePoint> (), null);
  534. return sequence_points;
  535. }
  536. }
  537. public ScopeDebugInformation Scope {
  538. get { return scope; }
  539. set { scope = value; }
  540. }
  541. public MethodDefinition StateMachineKickOffMethod {
  542. get { return kickoff_method; }
  543. set { kickoff_method = value; }
  544. }
  545. internal MethodDebugInformation (MethodDefinition method)
  546. {
  547. if (method == null)
  548. throw new ArgumentNullException ("method");
  549. this.method = method;
  550. this.token = new MetadataToken (TokenType.MethodDebugInformation, method.MetadataToken.RID);
  551. }
  552. public SequencePoint GetSequencePoint (Instruction instruction)
  553. {
  554. if (!HasSequencePoints)
  555. return null;
  556. for (int i = 0; i < sequence_points.Count; i++)
  557. if (sequence_points [i].Offset == instruction.Offset)
  558. return sequence_points [i];
  559. return null;
  560. }
  561. public IDictionary<Instruction, SequencePoint> GetSequencePointMapping ()
  562. {
  563. var instruction_mapping = new Dictionary<Instruction, SequencePoint> ();
  564. if (!HasSequencePoints || !method.HasBody)
  565. return instruction_mapping;
  566. var offset_mapping = new Dictionary<int, SequencePoint> (sequence_points.Count);
  567. for (int i = 0; i < sequence_points.Count; i++) {
  568. if (!offset_mapping.ContainsKey (sequence_points [i].Offset))
  569. offset_mapping.Add (sequence_points [i].Offset, sequence_points [i]);
  570. }
  571. var instructions = method.Body.Instructions;
  572. for (int i = 0; i < instructions.Count; i++) {
  573. SequencePoint sequence_point;
  574. if (offset_mapping.TryGetValue (instructions [i].Offset, out sequence_point))
  575. instruction_mapping.Add (instructions [i], sequence_point);
  576. }
  577. return instruction_mapping;
  578. }
  579. public IEnumerable<ScopeDebugInformation> GetScopes ()
  580. {
  581. if (scope == null)
  582. return Empty<ScopeDebugInformation>.Array;
  583. return GetScopes (new[] { scope });
  584. }
  585. static IEnumerable<ScopeDebugInformation> GetScopes (IList<ScopeDebugInformation> scopes)
  586. {
  587. for (int i = 0; i < scopes.Count; i++) {
  588. var scope = scopes [i];
  589. yield return scope;
  590. if (!scope.HasScopes)
  591. continue;
  592. foreach (var sub_scope in GetScopes (scope.Scopes))
  593. yield return sub_scope;
  594. }
  595. }
  596. public bool TryGetName (VariableDefinition variable, out string name)
  597. {
  598. name = null;
  599. var has_name = false;
  600. var unique_name = "";
  601. foreach (var scope in GetScopes ()) {
  602. string slot_name;
  603. if (!scope.TryGetName (variable, out slot_name))
  604. continue;
  605. if (!has_name) {
  606. has_name = true;
  607. unique_name = slot_name;
  608. continue;
  609. }
  610. if (unique_name != slot_name)
  611. return false;
  612. }
  613. name = unique_name;
  614. return has_name;
  615. }
  616. }
  617. public interface ISymbolReader : IDisposable {
  618. ISymbolWriterProvider GetWriterProvider ();
  619. bool ProcessDebugHeader (ImageDebugHeader header);
  620. MethodDebugInformation Read (MethodDefinition method);
  621. }
  622. public interface ISymbolReaderProvider {
  623. ISymbolReader GetSymbolReader (ModuleDefinition module, string fileName);
  624. ISymbolReader GetSymbolReader (ModuleDefinition module, Stream symbolStream);
  625. }
  626. #if !NET_CORE
  627. [Serializable]
  628. #endif
  629. public sealed class SymbolsNotFoundException : FileNotFoundException {
  630. public SymbolsNotFoundException (string message) : base (message)
  631. {
  632. }
  633. #if !NET_CORE
  634. SymbolsNotFoundException (
  635. System.Runtime.Serialization.SerializationInfo info,
  636. System.Runtime.Serialization.StreamingContext context)
  637. : base (info, context)
  638. {
  639. }
  640. #endif
  641. }
  642. #if !NET_CORE
  643. [Serializable]
  644. #endif
  645. public sealed class SymbolsNotMatchingException : InvalidOperationException {
  646. public SymbolsNotMatchingException (string message) : base (message)
  647. {
  648. }
  649. #if !NET_CORE
  650. SymbolsNotMatchingException (
  651. System.Runtime.Serialization.SerializationInfo info,
  652. System.Runtime.Serialization.StreamingContext context)
  653. : base (info, context)
  654. {
  655. }
  656. #endif
  657. }
  658. public class DefaultSymbolReaderProvider : ISymbolReaderProvider {
  659. readonly bool throw_if_no_symbol;
  660. public DefaultSymbolReaderProvider ()
  661. : this (throwIfNoSymbol: true)
  662. {
  663. }
  664. public DefaultSymbolReaderProvider (bool throwIfNoSymbol)
  665. {
  666. throw_if_no_symbol = throwIfNoSymbol;
  667. }
  668. public ISymbolReader GetSymbolReader (ModuleDefinition module, string fileName)
  669. {
  670. if (module.Image.HasDebugTables ())
  671. return null;
  672. if (module.HasDebugHeader) {
  673. var header = module.GetDebugHeader ();
  674. var entry = header.GetEmbeddedPortablePdbEntry ();
  675. if (entry != null)
  676. return new EmbeddedPortablePdbReaderProvider ().GetSymbolReader (module, fileName);
  677. }
  678. var pdb_file_name = Mixin.GetPdbFileName (fileName);
  679. if (File.Exists (pdb_file_name)) {
  680. if (Mixin.IsPortablePdb (Mixin.GetPdbFileName (fileName)))
  681. return new PortablePdbReaderProvider ().GetSymbolReader (module, fileName);
  682. try {
  683. return SymbolProvider.GetReaderProvider (SymbolKind.NativePdb).GetSymbolReader (module, fileName);
  684. } catch (Exception) {
  685. // We might not include support for native pdbs.
  686. }
  687. }
  688. var mdb_file_name = Mixin.GetMdbFileName (fileName);
  689. if (File.Exists (mdb_file_name)) {
  690. try {
  691. return SymbolProvider.GetReaderProvider (SymbolKind.Mdb).GetSymbolReader (module, fileName);
  692. } catch (Exception) {
  693. // We might not include support for mdbs.
  694. }
  695. }
  696. if (throw_if_no_symbol)
  697. throw new SymbolsNotFoundException (string.Format ("No symbol found for file: {0}", fileName));
  698. return null;
  699. }
  700. public ISymbolReader GetSymbolReader (ModuleDefinition module, Stream symbolStream)
  701. {
  702. if (module.Image.HasDebugTables ())
  703. return null;
  704. if (module.HasDebugHeader) {
  705. var header = module.GetDebugHeader ();
  706. var entry = header.GetEmbeddedPortablePdbEntry ();
  707. if (entry != null)
  708. return new EmbeddedPortablePdbReaderProvider ().GetSymbolReader (module, "");
  709. }
  710. Mixin.CheckStream (symbolStream);
  711. Mixin.CheckReadSeek (symbolStream);
  712. var position = symbolStream.Position;
  713. const int portablePdbHeader = 0x424a5342;
  714. var reader = new BinaryStreamReader (symbolStream);
  715. var intHeader = reader.ReadInt32 ();
  716. symbolStream.Position = position;
  717. if (intHeader == portablePdbHeader) {
  718. return new PortablePdbReaderProvider ().GetSymbolReader (module, symbolStream);
  719. }
  720. const string nativePdbHeader = "Microsoft C/C++ MSF 7.00";
  721. var bytesHeader = reader.ReadBytes (nativePdbHeader.Length);
  722. symbolStream.Position = position;
  723. var isNativePdb = true;
  724. for (var i = 0; i < bytesHeader.Length; i++) {
  725. if (bytesHeader [i] != (byte) nativePdbHeader [i]) {
  726. isNativePdb = false;
  727. break;
  728. }
  729. }
  730. if (isNativePdb) {
  731. try {
  732. return SymbolProvider.GetReaderProvider (SymbolKind.NativePdb).GetSymbolReader (module, symbolStream);
  733. } catch (Exception) {
  734. // We might not include support for native pdbs.
  735. }
  736. }
  737. const long mdbHeader = 0x45e82623fd7fa614;
  738. var longHeader = reader.ReadInt64 ();
  739. symbolStream.Position = position;
  740. if (longHeader == mdbHeader) {
  741. try {
  742. return SymbolProvider.GetReaderProvider (SymbolKind.Mdb).GetSymbolReader (module, symbolStream);
  743. } catch (Exception) {
  744. // We might not include support for mdbs.
  745. }
  746. }
  747. if (throw_if_no_symbol)
  748. throw new SymbolsNotFoundException (string.Format ("No symbols found in stream"));
  749. return null;
  750. }
  751. }
  752. enum SymbolKind {
  753. NativePdb,
  754. PortablePdb,
  755. EmbeddedPortablePdb,
  756. Mdb,
  757. }
  758. static class SymbolProvider {
  759. static SR.AssemblyName GetSymbolAssemblyName (SymbolKind kind)
  760. {
  761. if (kind == SymbolKind.PortablePdb)
  762. throw new ArgumentException ();
  763. var suffix = GetSymbolNamespace (kind);
  764. var cecil_name = typeof (SymbolProvider).Assembly.GetName ();
  765. var name = new SR.AssemblyName {
  766. Name = cecil_name.Name + "." + suffix,
  767. Version = cecil_name.Version,
  768. #if NET_CORE
  769. CultureName = cecil_name.CultureName,
  770. #else
  771. CultureInfo = cecil_name.CultureInfo,
  772. #endif
  773. };
  774. name.SetPublicKeyToken (cecil_name.GetPublicKeyToken ());
  775. return name;
  776. }
  777. static Type GetSymbolType (SymbolKind kind, string fullname)
  778. {
  779. var type = Type.GetType (fullname);
  780. if (type != null)
  781. return type;
  782. var assembly_name = GetSymbolAssemblyName (kind);
  783. type = Type.GetType (fullname + ", " + assembly_name.FullName);
  784. if (type != null)
  785. return type;
  786. try {
  787. var assembly = SR.Assembly.Load (assembly_name);
  788. if (assembly != null)
  789. return assembly.GetType (fullname);
  790. } catch (FileNotFoundException) {
  791. } catch (FileLoadException) {
  792. }
  793. return null;
  794. }
  795. public static ISymbolReaderProvider GetReaderProvider (SymbolKind kind)
  796. {
  797. if (kind == SymbolKind.PortablePdb)
  798. return new PortablePdbReaderProvider ();
  799. if (kind == SymbolKind.EmbeddedPortablePdb)
  800. return new EmbeddedPortablePdbReaderProvider ();
  801. var provider_name = GetSymbolTypeName (kind, "ReaderProvider");
  802. var type = GetSymbolType (kind, provider_name);
  803. if (type == null)
  804. throw new TypeLoadException ("Could not find symbol provider type " + provider_name);
  805. return (ISymbolReaderProvider) Activator.CreateInstance (type);
  806. }
  807. static string GetSymbolTypeName (SymbolKind kind, string name)
  808. {
  809. return "Mono.Cecil" + "." + GetSymbolNamespace (kind) + "." + kind + name;
  810. }
  811. static string GetSymbolNamespace (SymbolKind kind)
  812. {
  813. if (kind == SymbolKind.PortablePdb || kind == SymbolKind.EmbeddedPortablePdb)
  814. return "Cil";
  815. if (kind == SymbolKind.NativePdb)
  816. return "Pdb";
  817. if (kind == SymbolKind.Mdb)
  818. return "Mdb";
  819. throw new ArgumentException ();
  820. }
  821. }
  822. public interface ISymbolWriter : IDisposable {
  823. ISymbolReaderProvider GetReaderProvider ();
  824. ImageDebugHeader GetDebugHeader ();
  825. void Write (MethodDebugInformation info);
  826. }
  827. public interface ISymbolWriterProvider {
  828. ISymbolWriter GetSymbolWriter (ModuleDefinition module, string fileName);
  829. ISymbolWriter GetSymbolWriter (ModuleDefinition module, Stream symbolStream);
  830. }
  831. public class DefaultSymbolWriterProvider : ISymbolWriterProvider {
  832. public ISymbolWriter GetSymbolWriter (ModuleDefinition module, string fileName)
  833. {
  834. var reader = module.SymbolReader;
  835. if (reader == null)
  836. throw new InvalidOperationException ();
  837. if (module.Image != null && module.Image.HasDebugTables ())
  838. return null;
  839. return reader.GetWriterProvider ().GetSymbolWriter (module, fileName);
  840. }
  841. public ISymbolWriter GetSymbolWriter (ModuleDefinition module, Stream symbolStream)
  842. {
  843. throw new NotSupportedException ();
  844. }
  845. }
  846. }
  847. namespace Mono.Cecil {
  848. static partial class Mixin {
  849. public static ImageDebugHeaderEntry GetCodeViewEntry (this ImageDebugHeader header)
  850. {
  851. return GetEntry (header, ImageDebugType.CodeView);
  852. }
  853. public static ImageDebugHeaderEntry GetDeterministicEntry (this ImageDebugHeader header)
  854. {
  855. return GetEntry (header, ImageDebugType.Deterministic);
  856. }
  857. public static ImageDebugHeader AddDeterministicEntry (this ImageDebugHeader header)
  858. {
  859. var entry = new ImageDebugHeaderEntry (new ImageDebugDirectory { Type = ImageDebugType.Deterministic }, Empty<byte>.Array);
  860. if (header == null)
  861. return new ImageDebugHeader (entry);
  862. var entries = new ImageDebugHeaderEntry [header.Entries.Length + 1];
  863. Array.Copy (header.Entries, entries, header.Entries.Length);
  864. entries [entries.Length - 1] = entry;
  865. return new ImageDebugHeader (entries);
  866. }
  867. public static ImageDebugHeaderEntry GetEmbeddedPortablePdbEntry (this ImageDebugHeader header)
  868. {
  869. return GetEntry (header, ImageDebugType.EmbeddedPortablePdb);
  870. }
  871. private static ImageDebugHeaderEntry GetEntry (this ImageDebugHeader header, ImageDebugType type)
  872. {
  873. if (!header.HasEntries)
  874. return null;
  875. for (var i = 0; i < header.Entries.Length; i++) {
  876. var entry = header.Entries [i];
  877. if (entry.Directory.Type == type)
  878. return entry;
  879. }
  880. return null;
  881. }
  882. public static string GetPdbFileName (string assemblyFileName)
  883. {
  884. return Path.ChangeExtension (assemblyFileName, ".pdb");
  885. }
  886. public static string GetMdbFileName (string assemblyFileName)
  887. {
  888. return assemblyFileName + ".mdb";
  889. }
  890. public static bool IsPortablePdb (string fileName)
  891. {
  892. using (var file = new FileStream (fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
  893. return IsPortablePdb (file);
  894. }
  895. public static bool IsPortablePdb (Stream stream)
  896. {
  897. const uint ppdb_signature = 0x424a5342;
  898. if (stream.Length < 4) return false;
  899. var position = stream.Position;
  900. try {
  901. var reader = new BinaryReader (stream);
  902. return reader.ReadUInt32 () == ppdb_signature;
  903. } finally {
  904. stream.Position = position;
  905. }
  906. }
  907. }
  908. }