Symbols.cs 28 KB

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