StackTrace.cs 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  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.Generic;
  31. using System.Globalization;
  32. using System.Reflection;
  33. using System.Runtime.CompilerServices;
  34. using System.Runtime.InteropServices;
  35. using System.Security;
  36. using System.Security.Permissions;
  37. using System.Text;
  38. using System.Threading;
  39. namespace System.Diagnostics {
  40. [Serializable]
  41. [ComVisible (true)]
  42. [MonoTODO ("Serialized objects are not compatible with .NET")]
  43. public class StackTrace {
  44. // TraceFormat is Used to specify options for how the
  45. // string-representation of a StackTrace should be generated.
  46. internal enum TraceFormat
  47. {
  48. Normal,
  49. TrailingNewLine, // include a trailing new line character
  50. NoResourceLookup // to prevent infinite resource recusion
  51. }
  52. public const int METHODS_TO_SKIP = 0;
  53. private StackFrame[] frames;
  54. readonly StackTrace[] captured_traces;
  55. private bool debug_info;
  56. public StackTrace ()
  57. {
  58. init_frames (METHODS_TO_SKIP, false);
  59. }
  60. public StackTrace (bool fNeedFileInfo)
  61. {
  62. init_frames (METHODS_TO_SKIP, fNeedFileInfo);
  63. }
  64. public StackTrace (int skipFrames)
  65. {
  66. init_frames (skipFrames, false);
  67. }
  68. public StackTrace (int skipFrames, bool fNeedFileInfo)
  69. {
  70. init_frames (skipFrames, fNeedFileInfo);
  71. }
  72. void init_frames (int skipFrames, bool fNeedFileInfo)
  73. {
  74. if (skipFrames < 0)
  75. throw new ArgumentOutOfRangeException ("< 0", "skipFrames");
  76. StackFrame sf;
  77. var l = new List<StackFrame> ();
  78. skipFrames += 2;
  79. while ((sf = new StackFrame (skipFrames, fNeedFileInfo)) != null &&
  80. sf.GetMethod () != null) {
  81. l.Add (sf);
  82. skipFrames++;
  83. };
  84. debug_info = fNeedFileInfo;
  85. frames = l.ToArray ();
  86. }
  87. [MethodImplAttribute(MethodImplOptions.InternalCall)]
  88. extern static StackFrame [] get_trace (Exception e, int skipFrames, bool fNeedFileInfo);
  89. public StackTrace (Exception e)
  90. : this (e, METHODS_TO_SKIP, false)
  91. {
  92. }
  93. public StackTrace (Exception e, bool fNeedFileInfo)
  94. : this (e, METHODS_TO_SKIP, fNeedFileInfo)
  95. {
  96. }
  97. public StackTrace (Exception e, int skipFrames)
  98. : this (e, skipFrames, false)
  99. {
  100. }
  101. public StackTrace (Exception e, int skipFrames, bool fNeedFileInfo)
  102. {
  103. if (e == null)
  104. throw new ArgumentNullException ("e");
  105. if (skipFrames < 0)
  106. throw new ArgumentOutOfRangeException ("< 0", "skipFrames");
  107. frames = get_trace (e, skipFrames, fNeedFileInfo);
  108. captured_traces = e.captured_traces;
  109. }
  110. public StackTrace (StackFrame frame)
  111. {
  112. this.frames = new StackFrame [1];
  113. this.frames [0] = frame;
  114. }
  115. [MonoLimitation ("Not possible to create StackTraces from other threads")]
  116. [Obsolete]
  117. public StackTrace (Thread targetThread, bool needFileInfo)
  118. {
  119. if (targetThread == Thread.CurrentThread){
  120. init_frames (METHODS_TO_SKIP, needFileInfo);
  121. return;
  122. }
  123. throw new NotImplementedException ();
  124. }
  125. public virtual int FrameCount {
  126. get {
  127. return (frames == null) ? 0 : frames.Length;
  128. }
  129. }
  130. public virtual StackFrame GetFrame (int index)
  131. {
  132. if ((index < 0) || (index >= FrameCount)) {
  133. return null;
  134. }
  135. return frames [index];
  136. }
  137. [ComVisibleAttribute (false)]
  138. public virtual StackFrame[] GetFrames ()
  139. {
  140. return frames;
  141. }
  142. bool AddFrames (StringBuilder sb, bool isException = false)
  143. {
  144. bool printOffset;
  145. string debugInfo, indentation;
  146. string unknown = Locale.GetText ("<unknown method>");
  147. if (isException) {
  148. printOffset = true;
  149. indentation = " ";
  150. debugInfo = Locale.GetText (" in {0}:{1} ");
  151. } else {
  152. printOffset = false;
  153. indentation = " ";
  154. debugInfo = Locale.GetText (" in {0}:line {1}");
  155. }
  156. var newline = String.Format ("{0}{1}{2} ", Environment.NewLine, indentation,
  157. Locale.GetText ("at"));
  158. int i;
  159. for (i = 0; i < FrameCount; i++) {
  160. StackFrame frame = GetFrame (i);
  161. if (i == 0)
  162. sb.AppendFormat ("{0}{1} ", indentation, Locale.GetText ("at"));
  163. else
  164. sb.Append (newline);
  165. if (frame.GetMethod () == null) {
  166. string internal_name = frame.GetInternalMethodName ();
  167. if (internal_name != null)
  168. sb.Append (internal_name);
  169. else if (printOffset)
  170. sb.AppendFormat ("<0x{0:x5} + 0x{1:x5}> {2}", frame.GetMethodAddress (), frame.GetNativeOffset (), unknown);
  171. else
  172. sb.AppendFormat (unknown);
  173. } else {
  174. GetFullNameForStackTrace (sb, frame.GetMethod ());
  175. if (printOffset) {
  176. if (frame.GetILOffset () == -1) {
  177. sb.AppendFormat (" <0x{0:x5} + 0x{1:x5}>", frame.GetMethodAddress (), frame.GetNativeOffset ());
  178. if (frame.GetMethodIndex () != 0xffffff)
  179. sb.AppendFormat (" {0}", frame.GetMethodIndex ());
  180. } else {
  181. sb.AppendFormat (" [0x{0:x5}]", frame.GetILOffset ());
  182. }
  183. }
  184. sb.AppendFormat (debugInfo, frame.GetSecureFileName (),
  185. frame.GetFileLineNumber ());
  186. }
  187. }
  188. return i != 0;
  189. }
  190. // This method is also used with reflection by mono-symbolicate tool.
  191. // mono-symbolicate tool uses this method to check which method matches
  192. // the stack frame method signature.
  193. static void GetFullNameForStackTrace (StringBuilder sb, MethodBase mi)
  194. {
  195. var declaringType = mi.DeclaringType;
  196. if (declaringType.IsGenericType && !declaringType.IsGenericTypeDefinition)
  197. declaringType = declaringType.GetGenericTypeDefinition ();
  198. // Get generic definition
  199. var bindingflags = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;
  200. foreach (var m in declaringType.GetMethods (bindingflags)) {
  201. if (m.MetadataToken == mi.MetadataToken) {
  202. mi = m;
  203. break;
  204. }
  205. }
  206. sb.Append (declaringType.ToString ());
  207. sb.Append (".");
  208. sb.Append (mi.Name);
  209. if (mi.IsGenericMethod) {
  210. Type[] gen_params = mi.GetGenericArguments ();
  211. sb.Append ("[");
  212. for (int j = 0; j < gen_params.Length; j++) {
  213. if (j > 0)
  214. sb.Append (",");
  215. sb.Append (gen_params [j].Name);
  216. }
  217. sb.Append ("]");
  218. }
  219. ParameterInfo[] p = mi.GetParametersInternal ();
  220. sb.Append (" (");
  221. for (int i = 0; i < p.Length; ++i) {
  222. if (i > 0)
  223. sb.Append (", ");
  224. Type pt = p[i].ParameterType;
  225. if (pt.IsGenericType && ! pt.IsGenericTypeDefinition)
  226. pt = pt.GetGenericTypeDefinition ();
  227. if (pt.IsClass && !String.IsNullOrEmpty (pt.Namespace)) {
  228. sb.Append (pt.Namespace);
  229. sb.Append (".");
  230. }
  231. sb.Append (pt.Name);
  232. if (p [i].Name != null) {
  233. sb.Append (" ");
  234. sb.Append (p [i].Name);
  235. }
  236. }
  237. sb.Append (")");
  238. }
  239. public override string ToString ()
  240. {
  241. StringBuilder sb = new StringBuilder ();
  242. //
  243. // Add traces captured using ExceptionDispatchInfo
  244. //
  245. if (captured_traces != null) {
  246. foreach (var t in captured_traces) {
  247. if (!t.AddFrames (sb, true))
  248. continue;
  249. sb.Append (Environment.NewLine);
  250. sb.Append ("--- End of stack trace from previous location where exception was thrown ---");
  251. sb.Append (Environment.NewLine);
  252. }
  253. }
  254. AddFrames (sb);
  255. return sb.ToString ();
  256. }
  257. internal String ToString (TraceFormat traceFormat)
  258. {
  259. // TODO:
  260. return ToString ();
  261. }
  262. }
  263. }