2 // System.Diagnostics.StackTrace.cs
5 // Alexander Klyubin (klyubin@aqris.com)
6 // Dietmar Maurer (dietmar@ximian.com)
9 // Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com)
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:
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
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.
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.Security.Permissions;
39 using System.Threading;
42 namespace System.Diagnostics {
46 [MonoTODO ("Serialized objects are not compatible with .NET")]
47 public class StackTrace {
49 // TraceFormat is Used to specify options for how the
50 // string-representation of a StackTrace should be generated.
51 internal enum TraceFormat
54 TrailingNewLine, // include a trailing new line character
55 NoResourceLookup // to prevent infinite resource recusion
58 public const int METHODS_TO_SKIP = 0;
60 private StackFrame[] frames;
61 readonly StackTrace[] captured_traces;
62 private bool debug_info;
64 private static Dictionary<string, Func<StackTrace, string>> metadataHandlers;
66 [MethodImplAttribute (MethodImplOptions.NoInlining)]
69 init_frames (METHODS_TO_SKIP, false);
72 [MethodImplAttribute (MethodImplOptions.NoInlining)]
73 public StackTrace (bool fNeedFileInfo)
75 init_frames (METHODS_TO_SKIP, fNeedFileInfo);
78 [MethodImplAttribute (MethodImplOptions.NoInlining)]
79 public StackTrace (int skipFrames)
81 init_frames (skipFrames, false);
84 [MethodImplAttribute (MethodImplOptions.NoInlining)]
85 public StackTrace (int skipFrames, bool fNeedFileInfo)
87 init_frames (skipFrames, fNeedFileInfo);
90 [MethodImplAttribute (MethodImplOptions.NoInlining)]
91 void init_frames (int skipFrames, bool fNeedFileInfo)
94 throw new ArgumentOutOfRangeException ("< 0", "skipFrames");
97 var l = new List<StackFrame> ();
101 while ((sf = new StackFrame (skipFrames, fNeedFileInfo)) != null &&
102 sf.GetMethod () != null) {
108 debug_info = fNeedFileInfo;
109 frames = l.ToArray ();
112 [MethodImplAttribute(MethodImplOptions.InternalCall)]
113 extern static StackFrame [] get_trace (Exception e, int skipFrames, bool fNeedFileInfo);
115 public StackTrace (Exception e)
116 : this (e, METHODS_TO_SKIP, false)
120 public StackTrace (Exception e, bool fNeedFileInfo)
121 : this (e, METHODS_TO_SKIP, fNeedFileInfo)
125 public StackTrace (Exception e, int skipFrames)
126 : this (e, skipFrames, false)
130 public StackTrace (Exception e, int skipFrames, bool fNeedFileInfo)
133 throw new ArgumentNullException ("e");
135 throw new ArgumentOutOfRangeException ("< 0", "skipFrames");
137 frames = get_trace (e, skipFrames, fNeedFileInfo);
139 captured_traces = e.captured_traces;
142 public StackTrace (StackFrame frame)
144 this.frames = new StackFrame [1];
145 this.frames [0] = frame;
148 [MonoLimitation ("Not possible to create StackTraces from other threads")]
150 public StackTrace (Thread targetThread, bool needFileInfo)
152 if (targetThread == Thread.CurrentThread){
153 init_frames (METHODS_TO_SKIP, needFileInfo);
157 throw new NotImplementedException ();
160 internal StackTrace (StackFrame[] frames) {
161 this.frames = frames;
164 public virtual int FrameCount {
166 return (frames == null) ? 0 : frames.Length;
170 public virtual StackFrame GetFrame (int index)
172 if ((index < 0) || (index >= FrameCount)) {
176 return frames [index];
179 [ComVisibleAttribute (false)]
180 public virtual StackFrame[] GetFrames ()
185 bool AddFrames (StringBuilder sb)
188 string debugInfo, indentation;
189 string unknown = Locale.GetText ("<unknown method>");
192 debugInfo = Locale.GetText (" in {0}:{1} ");
194 var newline = String.Format ("{0}{1}{2} ", Environment.NewLine, indentation,
195 Locale.GetText ("at"));
198 for (i = 0; i < FrameCount; i++) {
199 StackFrame frame = GetFrame (i);
201 sb.AppendFormat ("{0}{1} ", indentation, Locale.GetText ("at"));
205 if (frame.GetMethod () == null) {
206 string internal_name = frame.GetInternalMethodName ();
207 if (internal_name != null)
208 sb.Append (internal_name);
210 sb.AppendFormat ("<0x{0:x5} + 0x{1:x5}> {2}", frame.GetMethodAddress (), frame.GetNativeOffset (), unknown);
212 GetFullNameForStackTrace (sb, frame.GetMethod ());
214 if (frame.GetILOffset () == -1) {
215 sb.AppendFormat (" <0x{0:x5} + 0x{1:x5}>", frame.GetMethodAddress (), frame.GetNativeOffset ());
216 if (frame.GetMethodIndex () != 0xffffff)
217 sb.AppendFormat (" {0}", frame.GetMethodIndex ());
219 sb.AppendFormat (" [0x{0:x5}]", frame.GetILOffset ());
222 sb.AppendFormat (debugInfo, frame.GetSecureFileName (),
223 frame.GetFileLineNumber ());
230 public static void GetFullNameForStackTrace (StringBuilder sb, MethodBase mi)
232 var declaringType = mi.DeclaringType;
233 if (declaringType.IsGenericType && !declaringType.IsGenericTypeDefinition)
234 declaringType = declaringType.GetGenericTypeDefinition ();
236 // Get generic definition
237 const BindingFlags bindingflags = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;
238 foreach (var m in declaringType.GetMethods (bindingflags)) {
239 if (m.MetadataToken == mi.MetadataToken) {
245 sb.Append (declaringType.ToString ());
250 if (mi.IsGenericMethod) {
251 Type[] gen_params = mi.GetGenericArguments ();
253 for (int j = 0; j < gen_params.Length; j++) {
256 sb.Append (gen_params [j].Name);
261 ParameterInfo[] p = mi.GetParameters ();
264 for (int i = 0; i < p.Length; ++i) {
268 Type pt = p[i].ParameterType;
269 if (pt.IsGenericType && ! pt.IsGenericTypeDefinition)
270 pt = pt.GetGenericTypeDefinition ();
272 sb.Append (pt.ToString());
274 if (p [i].Name != null) {
276 sb.Append (p [i].Name);
282 public override string ToString ()
284 StringBuilder sb = new StringBuilder ();
287 // Add traces captured using ExceptionDispatchInfo
289 if (captured_traces != null) {
290 foreach (var t in captured_traces) {
291 if (!t.AddFrames (sb))
296 sb.Append (Environment.NewLine);
297 sb.Append ("--- End of stack trace from previous location where exception was thrown ---");
298 sb.Append (Environment.NewLine);
305 return sb.ToString ();
308 void AddMetadata (StringBuilder sb)
310 if (metadataHandlers == null)
311 InitMetadataHandlers ();
313 foreach (var handler in metadataHandlers) {
314 var lines = handler.Value (this);
315 using (var reader = new StringReader (lines)) {
317 while ((line = reader.ReadLine()) != null) {
319 sb.AppendFormat ("[{0}] {1}", handler.Key, line);
325 internal String ToString (TraceFormat traceFormat)
331 static void InitMetadataHandlers ()
333 metadataHandlers = new Dictionary<string, Func<StackTrace, string>> (StringComparer.Ordinal);
335 var aotid = Assembly.GetAotId ();
337 AddMetadataHandler ("AOTID", st => { return new Guid (aotid).ToString ("N"); });
339 AddMetadataHandler ("MVID", st => {
340 var mvidLines = new Dictionary<Guid, List<int>> ();
341 var frames = st.GetFrames ();
342 for (var lineNumber = 0; lineNumber < frames.Length; lineNumber++) {
343 var method = frames[lineNumber].GetMethod ();
346 var mvid = method.Module.ModuleVersionId;
348 List<int> lines = null;
349 if (!mvidLines.TryGetValue (mvid, out lines)) {
350 lines = new List<int> ();
351 mvidLines.Add (mvid, lines);
354 lines.Add (lineNumber);
357 var mvids = new List<Guid> (mvidLines.Keys);
360 var sb = new StringBuilder ();
361 foreach (var mvid in mvids)
362 sb.AppendLine (string.Format ("{0} {1}", mvid.ToString ("N"), string.Join (",", mvidLines[mvid])));
364 return sb.ToString ();
368 // This method signature should not change, apps can use it with reflection to add custom metadata handlers.
369 private static void AddMetadataHandler (string id, Func<StackTrace, string> handler)
371 if (metadataHandlers == null)
372 InitMetadataHandlers ();
374 metadataHandlers.Add (id, handler);