StackTrace.cs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392
  1. //
  2. // System.Diagnostics.StackTrace.cs
  3. //
  4. // Author:
  5. // Alexander Klyubin ([email protected])
  6. // Dietmar Maurer ([email protected])
  7. //
  8. // (C) 2001
  9. // Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com)
  10. //
  11. // Permission is hereby granted, free of charge, to any person obtaining
  12. // a copy of this software and associated documentation files (the
  13. // "Software"), to deal in the Software without restriction, including
  14. // without limitation the rights to use, copy, modify, merge, publish,
  15. // distribute, sublicense, and/or sell copies of the Software, and to
  16. // permit persons to whom the Software is furnished to do so, subject to
  17. // the following conditions:
  18. //
  19. // The above copyright notice and this permission notice shall be
  20. // included in all copies or substantial portions of the Software.
  21. //
  22. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  23. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  24. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  25. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  26. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  27. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  28. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  29. //
  30. using System.Collections;
  31. using System.Collections.Generic;
  32. using System.Globalization;
  33. using System.Reflection;
  34. using System.Runtime.CompilerServices;
  35. using System.Runtime.InteropServices;
  36. using System.Security;
  37. using System.Text;
  38. using System.Threading;
  39. using System.IO;
  40. namespace System.Diagnostics {
  41. [Serializable]
  42. [ComVisible (true)]
  43. #if !NETCORE
  44. [MonoTODO ("Serialized objects are not compatible with .NET")]
  45. #endif
  46. public class StackTrace {
  47. // TraceFormat is Used to specify options for how the
  48. // string-representation of a StackTrace should be generated.
  49. internal enum TraceFormat
  50. {
  51. Normal,
  52. TrailingNewLine, // include a trailing new line character
  53. NoResourceLookup // to prevent infinite resource recusion
  54. }
  55. public const int METHODS_TO_SKIP = 0;
  56. const string prefix = " at ";
  57. private StackFrame[] frames;
  58. readonly StackTrace[] captured_traces;
  59. #pragma warning disable 414
  60. private bool debug_info;
  61. #pragma warning restore
  62. [MethodImplAttribute (MethodImplOptions.NoInlining)]
  63. public StackTrace ()
  64. {
  65. init_frames (METHODS_TO_SKIP, false);
  66. }
  67. [MethodImplAttribute (MethodImplOptions.NoInlining)]
  68. public StackTrace (bool fNeedFileInfo)
  69. {
  70. init_frames (METHODS_TO_SKIP, fNeedFileInfo);
  71. }
  72. [MethodImplAttribute (MethodImplOptions.NoInlining)]
  73. public StackTrace (int skipFrames)
  74. {
  75. init_frames (skipFrames, false);
  76. }
  77. [MethodImplAttribute (MethodImplOptions.NoInlining)]
  78. public StackTrace (int skipFrames, bool fNeedFileInfo)
  79. {
  80. init_frames (skipFrames, fNeedFileInfo);
  81. }
  82. [MethodImplAttribute (MethodImplOptions.NoInlining)]
  83. void init_frames (int skipFrames, bool fNeedFileInfo)
  84. {
  85. if (skipFrames < 0)
  86. throw new ArgumentOutOfRangeException ("< 0", "skipFrames");
  87. StackFrame sf;
  88. var l = new List<StackFrame> ();
  89. skipFrames += 2;
  90. while ((sf = new StackFrame (skipFrames, fNeedFileInfo)) != null &&
  91. sf.GetMethod () != null) {
  92. l.Add (sf);
  93. skipFrames++;
  94. };
  95. debug_info = fNeedFileInfo;
  96. frames = l.ToArray ();
  97. }
  98. [MethodImplAttribute(MethodImplOptions.InternalCall)]
  99. extern static StackFrame [] get_trace (Exception e, int skipFrames, bool fNeedFileInfo);
  100. public StackTrace (Exception e)
  101. : this (e, METHODS_TO_SKIP, false)
  102. {
  103. }
  104. public StackTrace (Exception e, bool fNeedFileInfo)
  105. : this (e, METHODS_TO_SKIP, fNeedFileInfo)
  106. {
  107. }
  108. public StackTrace (Exception e, int skipFrames)
  109. : this (e, skipFrames, false)
  110. {
  111. }
  112. public StackTrace (Exception e, int skipFrames, bool fNeedFileInfo)
  113. {
  114. if (e == null)
  115. throw new ArgumentNullException ("e");
  116. if (skipFrames < 0)
  117. throw new ArgumentOutOfRangeException ("< 0", "skipFrames");
  118. frames = get_trace (e, skipFrames, fNeedFileInfo);
  119. captured_traces = e.captured_traces;
  120. }
  121. public StackTrace (StackFrame frame)
  122. {
  123. this.frames = new StackFrame [1];
  124. this.frames [0] = frame;
  125. }
  126. #if !NETCORE
  127. [MonoLimitation ("Not possible to create StackTraces from other threads")]
  128. #endif
  129. [Obsolete]
  130. public StackTrace (Thread targetThread, bool needFileInfo)
  131. {
  132. if (targetThread == Thread.CurrentThread){
  133. init_frames (METHODS_TO_SKIP, needFileInfo);
  134. return;
  135. }
  136. throw new NotImplementedException ();
  137. }
  138. internal StackTrace (StackFrame[] frames) {
  139. this.frames = frames;
  140. }
  141. public virtual int FrameCount {
  142. get {
  143. return (frames == null) ? 0 : frames.Length;
  144. }
  145. }
  146. public virtual StackFrame GetFrame (int index)
  147. {
  148. if ((index < 0) || (index >= FrameCount)) {
  149. return null;
  150. }
  151. return frames [index];
  152. }
  153. [ComVisibleAttribute (false)]
  154. public virtual StackFrame[] GetFrames ()
  155. {
  156. if (captured_traces == null)
  157. return frames;
  158. var accum = new List<StackFrame> ();
  159. foreach (var t in captured_traces) {
  160. for (int i = 0; i < t.FrameCount; i++)
  161. accum.Add (t.GetFrame (i));
  162. }
  163. accum.AddRange (frames);
  164. return accum.ToArray ();
  165. }
  166. static bool isAotidSet;
  167. static string aotid;
  168. static string GetAotId ()
  169. {
  170. if (!isAotidSet) {
  171. aotid = RuntimeAssembly.GetAotId ();
  172. if (aotid != null)
  173. aotid = new Guid (aotid).ToString ("N");
  174. isAotidSet = true;
  175. }
  176. return aotid;
  177. }
  178. bool AddFrames (StringBuilder sb, bool separator, out bool isAsync)
  179. {
  180. isAsync = false;
  181. bool any_frame = false;
  182. for (int i = 0; i < FrameCount; i++) {
  183. StackFrame frame = GetFrame (i);
  184. if (frame.GetMethod () == null) {
  185. if (any_frame || separator)
  186. sb.Append (Environment.NewLine);
  187. sb.Append (prefix);
  188. string internal_name = frame.GetInternalMethodName ();
  189. if (internal_name != null)
  190. sb.Append (internal_name);
  191. else
  192. sb.AppendFormat ("<0x{0:x5} + 0x{1:x5}> <unknown method>", frame.GetMethodAddress (), frame.GetNativeOffset ());
  193. } else {
  194. GetFullNameForStackTrace (sb, frame.GetMethod (), any_frame || separator, out var skipped, out isAsync);
  195. if (skipped)
  196. continue;
  197. if (frame.GetILOffset () == -1) {
  198. sb.AppendFormat (" <0x{0:x5} + 0x{1:x5}>", frame.GetMethodAddress (), frame.GetNativeOffset ());
  199. if (frame.GetMethodIndex () != 0xffffff)
  200. sb.AppendFormat (" {0}", frame.GetMethodIndex ());
  201. } else {
  202. sb.AppendFormat (" [0x{0:x5}]", frame.GetILOffset ());
  203. }
  204. var filename = frame.GetSecureFileName ();
  205. if (filename[0] == '<') {
  206. var mvid = frame.GetMethod ().Module.ModuleVersionId.ToString ("N");
  207. var aotid = GetAotId ();
  208. if (frame.GetILOffset () != -1 || aotid == null) {
  209. filename = string.Format ("<{0}>", mvid);
  210. } else {
  211. filename = string.Format ("<{0}#{1}>", mvid, aotid);
  212. }
  213. }
  214. sb.AppendFormat (" in {0}:{1} ", filename, frame.GetFileLineNumber ());
  215. }
  216. any_frame = true;
  217. }
  218. return any_frame;
  219. }
  220. void GetFullNameForStackTrace (StringBuilder sb, MethodBase mi, bool needsNewLine, out bool skipped, out bool isAsync)
  221. {
  222. Type declaringType = mi.DeclaringType;
  223. // Get generic definition
  224. if (declaringType.IsGenericType && !declaringType.IsGenericTypeDefinition) {
  225. declaringType = declaringType.GetGenericTypeDefinition ();
  226. const BindingFlags bindingflags = BindingFlags.Instance | BindingFlags.Static |
  227. BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly;
  228. foreach (var m in declaringType.GetMethods (bindingflags)) {
  229. if (m.MetadataToken == mi.MetadataToken) {
  230. mi = m;
  231. break;
  232. }
  233. }
  234. }
  235. isAsync = typeof (IAsyncStateMachine).IsAssignableFrom (declaringType);
  236. skipped = mi.IsDefined (typeof (StackTraceHiddenAttribute)) || declaringType.IsDefined (typeof (StackTraceHiddenAttribute));
  237. if (skipped)
  238. return;
  239. if (isAsync) {
  240. ConvertAsyncStateMachineMethod (ref mi, ref declaringType);
  241. }
  242. if (needsNewLine)
  243. sb.Append (Environment.NewLine);
  244. sb.Append (prefix);
  245. sb.Append (declaringType.ToString ());
  246. sb.Append (".");
  247. sb.Append (mi.Name);
  248. if (mi.IsGenericMethod) {
  249. mi = ((MethodInfo)mi).GetGenericMethodDefinition ();
  250. Type[] gen_params = mi.GetGenericArguments ();
  251. sb.Append ("[");
  252. for (int j = 0; j < gen_params.Length; j++) {
  253. if (j > 0)
  254. sb.Append (",");
  255. sb.Append (gen_params [j].Name);
  256. }
  257. sb.Append ("]");
  258. }
  259. ParameterInfo[] p = mi.GetParameters ();
  260. sb.Append (" (");
  261. for (int i = 0; i < p.Length; ++i) {
  262. if (i > 0)
  263. sb.Append (", ");
  264. Type pt = p[i].ParameterType;
  265. if (pt.IsGenericType && ! pt.IsGenericTypeDefinition)
  266. pt = pt.GetGenericTypeDefinition ();
  267. sb.Append (pt.ToString());
  268. if (p [i].Name != null) {
  269. sb.Append (" ");
  270. sb.Append (p [i].Name);
  271. }
  272. }
  273. sb.Append (")");
  274. }
  275. static void ConvertAsyncStateMachineMethod (ref MethodBase method, ref Type declaringType)
  276. {
  277. Type parentType = declaringType.DeclaringType;
  278. if (parentType == null)
  279. return;
  280. MethodInfo[] methods = parentType.GetMethods (BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance | BindingFlags.DeclaredOnly);
  281. if (methods == null)
  282. return;
  283. foreach (MethodInfo candidateMethod in methods) {
  284. var attributes = candidateMethod.GetCustomAttributes<AsyncStateMachineAttribute> ();
  285. if (attributes == null)
  286. continue;
  287. foreach (var attr in attributes) {
  288. if (attr.StateMachineType == declaringType) {
  289. method = candidateMethod;
  290. declaringType = candidateMethod.DeclaringType;
  291. return;
  292. }
  293. }
  294. }
  295. }
  296. public override string ToString ()
  297. {
  298. StringBuilder sb = new StringBuilder ();
  299. //
  300. // Add traces captured using ExceptionDispatchInfo
  301. //
  302. bool has_frames = false;
  303. if (captured_traces != null) {
  304. foreach (var t in captured_traces) {
  305. has_frames = t.AddFrames (sb, has_frames, out var isAsync);
  306. if (!has_frames)
  307. continue;
  308. if (!isAsync) {
  309. sb.Append (Environment.NewLine);
  310. sb.Append ("--- End of stack trace from previous location where exception was thrown ---");
  311. sb.Append (Environment.NewLine);
  312. }
  313. }
  314. }
  315. AddFrames (sb, has_frames, out _);
  316. return sb.ToString ();
  317. }
  318. internal String ToString (TraceFormat traceFormat)
  319. {
  320. // TODO:
  321. return ToString ();
  322. }
  323. }
  324. }