You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

136 lines
4.5 KiB

  1. // Copyright (c) 2018 Siegfried Pammer
  2. //
  3. // Permission is hereby granted, free of charge, to any person obtaining a copy of this
  4. // software and associated documentation files (the "Software"), to deal in the Software
  5. // without restriction, including without limitation the rights to use, copy, modify, merge,
  6. // publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
  7. // to whom the Software is furnished to do so, subject to the following conditions:
  8. //
  9. // The above copyright notice and this permission notice shall be included in all copies or
  10. // substantial portions of the Software.
  11. //
  12. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
  13. // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
  14. // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
  15. // FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
  16. // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  17. // DEALINGS IN THE SOFTWARE.
  18. using System;
  19. using System.Collections.Generic;
  20. using System.IO;
  21. using System.Linq;
  22. using System.Reflection.Metadata.Ecma335;
  23. using ICSharpCode.Decompiler.DebugInfo;
  24. using ICSharpCode.Decompiler.Metadata;
  25. using ICSharpCode.Decompiler.Util;
  26. using Mono.Cecil;
  27. using Mono.Cecil.Pdb;
  28. using SRM = System.Reflection.Metadata;
  29. namespace ICSharpCode.Decompiler.PdbProvider
  30. {
  31. public class MonoCecilDebugInfoProvider : IDebugInfoProvider
  32. {
  33. readonly Dictionary<SRM.MethodDefinitionHandle, (IList<SequencePoint> SequencePoints, IList<Variable> Variables)> debugInfo;
  34. public unsafe MonoCecilDebugInfoProvider(PEFile module, string pdbFileName, string description = null)
  35. {
  36. if (module == null)
  37. {
  38. throw new ArgumentNullException(nameof(module));
  39. }
  40. if (!module.Reader.IsEntireImageAvailable)
  41. {
  42. throw new ArgumentException("This provider needs access to the full image!");
  43. }
  44. this.Description = description ?? $"Loaded from PDB file: {pdbFileName}";
  45. this.SourceFileName = pdbFileName;
  46. var image = module.Reader.GetEntireImage();
  47. this.debugInfo = new Dictionary<SRM.MethodDefinitionHandle, (IList<SequencePoint> SequencePoints, IList<Variable> Variables)>();
  48. using (UnmanagedMemoryStream stream = new UnmanagedMemoryStream(image.Pointer, image.Length))
  49. using (var moduleDef = ModuleDefinition.ReadModule(stream))
  50. {
  51. moduleDef.ReadSymbols(new PdbReaderProvider().GetSymbolReader(moduleDef, pdbFileName));
  52. foreach (var method in module.Metadata.MethodDefinitions)
  53. {
  54. var cecilMethod = moduleDef.LookupToken(MetadataTokens.GetToken(method)) as MethodDefinition;
  55. var debugInfo = cecilMethod?.DebugInformation;
  56. if (debugInfo == null)
  57. continue;
  58. IList<SequencePoint> sequencePoints = EmptyList<SequencePoint>.Instance;
  59. if (debugInfo.HasSequencePoints)
  60. {
  61. sequencePoints = new List<SequencePoint>(debugInfo.SequencePoints.Count);
  62. foreach (var point in debugInfo.SequencePoints)
  63. {
  64. sequencePoints.Add(new SequencePoint {
  65. Offset = point.Offset,
  66. StartLine = point.StartLine,
  67. StartColumn = point.StartColumn,
  68. EndLine = point.EndLine,
  69. EndColumn = point.EndColumn,
  70. DocumentUrl = point.Document.Url
  71. });
  72. }
  73. }
  74. var variables = new List<Variable>();
  75. foreach (var scope in debugInfo.GetScopes())
  76. {
  77. if (!scope.HasVariables)
  78. continue;
  79. foreach (var v in scope.Variables)
  80. {
  81. variables.Add(new Variable(v.Index, v.Name));
  82. }
  83. }
  84. this.debugInfo.Add(method, (sequencePoints, variables));
  85. }
  86. }
  87. }
  88. public string Description { get; }
  89. public string SourceFileName { get; }
  90. public IList<SequencePoint> GetSequencePoints(SRM.MethodDefinitionHandle handle)
  91. {
  92. if (!debugInfo.TryGetValue(handle, out var info))
  93. {
  94. return EmptyList<SequencePoint>.Instance;
  95. }
  96. return info.SequencePoints;
  97. }
  98. public IList<Variable> GetVariables(SRM.MethodDefinitionHandle handle)
  99. {
  100. if (!debugInfo.TryGetValue(handle, out var info))
  101. {
  102. return EmptyList<Variable>.Instance;
  103. }
  104. return info.Variables;
  105. }
  106. public bool TryGetName(SRM.MethodDefinitionHandle handle, int index, out string name)
  107. {
  108. name = null;
  109. if (!debugInfo.TryGetValue(handle, out var info))
  110. {
  111. return false;
  112. }
  113. var variable = info.Variables.FirstOrDefault(v => v.Index == index);
  114. name = variable.Name;
  115. return name != null;
  116. }
  117. }
  118. }