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.

205 lines
6.1 KiB

  1. // Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team
  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.Diagnostics;
  20. using System.IO;
  21. using System.Reflection;
  22. using System.Reflection.Metadata.Ecma335;
  23. using System.Runtime.InteropServices;
  24. using System.Runtime.Serialization;
  25. using System.Security;
  26. using System.Text;
  27. using ICSharpCode.Decompiler.Metadata;
  28. using ICSharpCode.Decompiler.TypeSystem;
  29. namespace ICSharpCode.Decompiler
  30. {
  31. /// <summary>
  32. /// Description of DecompilerException.
  33. /// </summary>
  34. public class DecompilerException : Exception, ISerializable
  35. {
  36. public string AssemblyName => File.Name;
  37. public string FileName => File.FileName;
  38. public IEntity DecompiledEntity { get; }
  39. public IModule Module { get; }
  40. public MetadataFile File { get; }
  41. public DecompilerException(MetadataModule module, IEntity decompiledEntity,
  42. Exception innerException, string message = null)
  43. : base(message ?? GetDefaultMessage(decompiledEntity), innerException)
  44. {
  45. this.File = module.MetadataFile;
  46. this.Module = module;
  47. this.DecompiledEntity = decompiledEntity;
  48. }
  49. public DecompilerException(MetadataFile file, string message, Exception innerException)
  50. : base(message, innerException)
  51. {
  52. this.File = file;
  53. }
  54. static string GetDefaultMessage(IEntity entity)
  55. {
  56. if (entity == null)
  57. return "Error decompiling";
  58. return $"Error decompiling @{MetadataTokens.GetToken(entity.MetadataToken):X8} {entity.FullName}";
  59. }
  60. // This constructor is needed for serialization.
  61. protected DecompilerException(SerializationInfo info, StreamingContext context) : base(info, context)
  62. {
  63. }
  64. public override string StackTrace => GetStackTrace(this);
  65. public override string ToString() => ToString(this);
  66. string ToString(Exception exception)
  67. {
  68. if (exception == null)
  69. throw new ArgumentNullException(nameof(exception));
  70. string exceptionType = GetTypeName(exception);
  71. string stacktrace = GetStackTrace(exception);
  72. while (exception.InnerException != null)
  73. {
  74. exception = exception.InnerException;
  75. stacktrace = GetStackTrace(exception) + Environment.NewLine
  76. + "-- continuing with outer exception (" + exceptionType + ") --" + Environment.NewLine
  77. + stacktrace;
  78. exceptionType = GetTypeName(exception);
  79. }
  80. return this.Message + Environment.NewLine
  81. + $"in assembly \"{this.FileName}\"" + Environment.NewLine
  82. + " ---> " + exceptionType + ": " + exception.Message + Environment.NewLine
  83. + stacktrace;
  84. }
  85. static string GetTypeName(Exception exception)
  86. {
  87. string type = exception.GetType().FullName;
  88. if (exception is ExternalException || exception is IOException)
  89. return type + " (" + Marshal.GetHRForException(exception).ToString("x8") + ")";
  90. else
  91. return type;
  92. }
  93. static string GetStackTrace(Exception exception)
  94. {
  95. // Output stacktrace in custom format (very similar to Exception.StackTrace
  96. // property on English systems).
  97. // Include filenames where available, but no paths.
  98. StackTrace stackTrace = new StackTrace(exception, true);
  99. StringBuilder b = new StringBuilder();
  100. for (int i = 0; i < stackTrace.FrameCount; i++)
  101. {
  102. StackFrame frame = stackTrace.GetFrame(i);
  103. MethodBase method = frame.GetMethod();
  104. if (method == null)
  105. continue;
  106. if (b.Length > 0)
  107. b.AppendLine();
  108. b.Append(" at ");
  109. Type declaringType = method.DeclaringType;
  110. if (declaringType != null)
  111. {
  112. b.Append(declaringType.FullName.Replace('+', '.'));
  113. b.Append('.');
  114. }
  115. b.Append(method.Name);
  116. // output type parameters, if any
  117. if ((method is MethodInfo) && ((MethodInfo)method).IsGenericMethod)
  118. {
  119. Type[] genericArguments = ((MethodInfo)method).GetGenericArguments();
  120. b.Append('[');
  121. for (int j = 0; j < genericArguments.Length; j++)
  122. {
  123. if (j > 0)
  124. b.Append(',');
  125. b.Append(genericArguments[j].Name);
  126. }
  127. b.Append(']');
  128. }
  129. // output parameters, if any
  130. b.Append('(');
  131. ParameterInfo[] parameters = method.GetParameters();
  132. for (int j = 0; j < parameters.Length; j++)
  133. {
  134. if (j > 0)
  135. b.Append(", ");
  136. if (parameters[j].ParameterType != null)
  137. {
  138. b.Append(parameters[j].ParameterType.Name);
  139. }
  140. else
  141. {
  142. b.Append('?');
  143. }
  144. if (!string.IsNullOrEmpty(parameters[j].Name))
  145. {
  146. b.Append(' ');
  147. b.Append(parameters[j].Name);
  148. }
  149. }
  150. b.Append(')');
  151. // source location
  152. if (frame.GetILOffset() >= 0)
  153. {
  154. string filename = null;
  155. try
  156. {
  157. string fullpath = frame.GetFileName();
  158. if (fullpath != null)
  159. filename = Path.GetFileName(fullpath);
  160. }
  161. catch (SecurityException)
  162. {
  163. // StackFrame.GetFileName requires PathDiscovery permission
  164. }
  165. catch (ArgumentException)
  166. {
  167. // Path.GetFileName might throw on paths with invalid chars
  168. }
  169. b.Append(" in ");
  170. if (filename != null)
  171. {
  172. b.Append(filename);
  173. b.Append(":line ");
  174. b.Append(frame.GetFileLineNumber());
  175. }
  176. else
  177. {
  178. b.Append("offset ");
  179. b.Append(frame.GetILOffset());
  180. }
  181. }
  182. }
  183. return b.ToString();
  184. }
  185. }
  186. }