diff options
Diffstat (limited to 'Runtime/Export/StackTrace.cs')
-rw-r--r-- | Runtime/Export/StackTrace.cs | 368 |
1 files changed, 368 insertions, 0 deletions
diff --git a/Runtime/Export/StackTrace.cs b/Runtime/Export/StackTrace.cs new file mode 100644 index 0000000..6e61bd5 --- /dev/null +++ b/Runtime/Export/StackTrace.cs @@ -0,0 +1,368 @@ +using System; +using System.Diagnostics; +using System.Text; +using System.Reflection.Emit; +using System.Reflection; +using System.Runtime.Serialization; +using System.Collections; + +#if UNITY_WINRT +using SystemException = System.Exception; +#endif + +namespace UnityEngine +{ +#if !UNITY_WINRT +public class StackTraceUtility +{ + static string projectFolder = ""; + + static internal void SetProjectFolder (string folder) + { + projectFolder = folder; + } + + static public string ExtractStackTrace () + { + StackTrace trace = new StackTrace (1, true); + string traceString = ExtractFormattedStackTrace (trace).ToString (); + return traceString; + } + + static bool IsSystemStacktraceType (object name) + { + string casted = (string)name; + return casted.StartsWith ("UnityEditor.") || casted.StartsWith ("UnityEngine.") || casted.StartsWith ("System.") || casted.StartsWith ("UnityScript.Lang.") || casted.StartsWith ("Boo.Lang.") || casted.StartsWith ("UnityEngine.SetupCoroutine"); + } + + static public string ExtractStringFromException(System.Object exception) + { + string message = "", stackTrace = ""; + ExtractStringFromExceptionInternal(exception, out message, out stackTrace); + return message + "\n" + stackTrace; + } + + static internal void ExtractStringFromExceptionInternal(System.Object exceptiono, out string message, out string stackTrace) + { + if (exceptiono == null) throw new ArgumentException("ExtractStringFromExceptionInternal called with null exception"); + var exception = exceptiono as System.Exception; + if (exception == null) throw new ArgumentException("ExtractStringFromExceptionInternal called with an exceptoin that was not of type System.Exception"); + + // StackTrace might not be available + StringBuilder sb = new StringBuilder(exception.StackTrace == null ? 512 : exception.StackTrace.Length*2); + message = ""; + string traceString = ""; + while (exception != null) + { + if (traceString.Length == 0) + traceString = exception.StackTrace; + else + traceString = exception.StackTrace + "\n" + traceString; + + string thisMessage = exception.GetType ().Name; + string exceptionMessage = ""; + if (exception.Message!=null) exceptionMessage = exception.Message; + if (exceptionMessage.Trim().Length != 0) + { + thisMessage += ": "; + thisMessage += exceptionMessage; + } + message = thisMessage; + if (exception.InnerException != null) + { + traceString = "Rethrow as " + thisMessage + "\n" + traceString; + } + exception = exception.InnerException; + } + + sb.Append (traceString + "\n"); + + StackTrace trace = new StackTrace (1, true); + sb.Append (ExtractFormattedStackTrace (trace)); + + stackTrace = sb.ToString(); + } + + static internal string PostprocessStacktrace (string oldString, bool stripEngineInternalInformation) + { + if (oldString==null) return String.Empty; + string [] split = oldString.Split ('\n'); + StringBuilder sb = new StringBuilder(oldString.Length); + for (int i=0; i<split.Length; i++) + split[i] = split[i].Trim(); + + for (int i=0; i<split.Length; i++) + { + string newLine = split[i]; + + // Ignore empty lines + if (newLine.Length == 0 || newLine[0] == '\n') + continue; + + // Ignore unmanaged + if (newLine.StartsWith ("in (unmanaged)")) + continue; + // Make GameView GUI stack traces skip editor GUI part + if (stripEngineInternalInformation && newLine.StartsWith("UnityEditor.EditorGUIUtility:RenderGameViewCameras")) break; + // Ignore deep system stacktraces + if (stripEngineInternalInformation && i<split.Length-1 && IsSystemStacktraceType(newLine)) + { + if (IsSystemStacktraceType(split[i+1])) + continue; + int lineInfo = newLine.IndexOf(" (at"); + if (lineInfo != -1) + newLine = newLine.Substring (0, lineInfo); + } + // Ignore wrapper managed to native + if (newLine.IndexOf ("(wrapper managed-to-native)") != -1) + continue; + if (newLine.IndexOf ("(wrapper delegate-invoke)") != -1) + continue; + // Ignore unknown method + if (newLine.IndexOf ("at <0x00000> <unknown method>") != -1) + continue; + // Ignore C++ line information + if (stripEngineInternalInformation && newLine.StartsWith ("[") && newLine.EndsWith("]")) + continue; + // Ignore starting at + if (newLine.StartsWith ("at ")) + { + newLine = newLine.Remove (0, 3); + } + + // Remove square brace [0x00001] + int brace = newLine.IndexOf("[0x"); + int braceClose = -1; + if (brace != -1) + braceClose = newLine.IndexOf("]", brace); + if (brace != -1 && braceClose > brace) + { + newLine = newLine.Remove (brace, braceClose - brace + 1); + } + + newLine = newLine.Replace(" in <filename unknown>:0", ""); + + newLine = newLine.Replace(projectFolder, ""); + + // Unify path names to unix style + newLine = newLine.Replace('\\','/'); + + int inStart = newLine.LastIndexOf (" in "); + if (inStart != -1) + { + newLine = newLine.Remove(inStart, 5); + newLine = newLine.Insert(inStart, " (at "); + newLine = newLine.Insert(newLine.Length, ")"); + } + + sb.Append (newLine+"\n"); + } + + return sb.ToString (); + } + + static internal string ExtractFormattedStackTrace (StackTrace stackTrace) + { + StringBuilder sb = new StringBuilder(255); + int iIndex; + + // need to skip over "n" frames which represent the + // System.Diagnostics package frames + for (iIndex=0; iIndex < stackTrace.FrameCount; iIndex++) + { + StackFrame frame = stackTrace.GetFrame (iIndex); + + MethodBase mb = frame.GetMethod (); + if (mb == null) + continue; + + Type classType = mb.DeclaringType; + if (classType == null) + continue; + + // Add namespace.classname:MethodName + String ns = classType.Namespace; + if (ns != null && ns.Length != 0) + { + sb.Append (ns); + sb.Append ("."); + } + + sb.Append (classType.Name); + sb.Append (":"); + sb.Append (mb.Name); + sb.Append ("("); + + // Add parameters + int j=0; + ParameterInfo[] pi = mb.GetParameters(); + bool fFirstParam = true; + while (j < pi.Length) + { + if (fFirstParam == false) + sb.Append (", "); + else + fFirstParam = false; + + sb.Append (pi[j].ParameterType.Name); + j++; + } + sb.Append (")"); + + // Add path name and line number - unless it is a Debug.Log call, then we are only interested + // in the calling frame. + string path = frame.GetFileName (); + if (path != null && !(classType.Name == "Debug" && classType.Namespace == "UnityEngine")) + { + sb.Append (" (at "); + + if (path.StartsWith (projectFolder)) + { + path = path.Substring (projectFolder.Length, path.Length - projectFolder.Length); + } + sb.Append (path); + sb.Append (":"); + sb.Append (frame.GetFileLineNumber ().ToString ()); + sb.Append (")"); + } + + sb.Append ("\n"); + } + + return sb.ToString(); + } +} +#endif + +[Serializable] +public class UnityException : SystemException +{ + const int Result = unchecked ((int)0x80004003); + string unityStackTrace; + + // Constructors + public UnityException () + : base ("A Unity Runtime error occurred!") + { + HResult = Result; + } + + public UnityException (string message) + : base (message) + { + HResult = Result; + } + + public UnityException (string message, Exception innerException) + : base (message, innerException) + { + HResult = Result; + } +#if !UNITY_WINRT + protected UnityException (SerializationInfo info, StreamingContext context) + : base (info, context) + { + } +#endif +} + +[Serializable] +public class MissingComponentException : SystemException +{ + const int Result = unchecked ((int)0x80004003); + string unityStackTrace; + + // Constructors + public MissingComponentException () + : base ("A Unity Runtime error occurred!") + { + HResult = Result; + } + + public MissingComponentException (string message) + : base (message) + { + HResult = Result; + } + + public MissingComponentException (string message, Exception innerException) + : base (message, innerException) + { + HResult = Result; + } +#if !UNITY_WINRT + protected MissingComponentException (SerializationInfo info, StreamingContext context) + : base (info, context) + { + } +#endif +} + + +[Serializable] +public class UnassignedReferenceException : SystemException +{ + const int Result = unchecked ((int)0x80004003); + string unityStackTrace; + + // Constructors + public UnassignedReferenceException () + : base ("A Unity Runtime error occurred!") + { + HResult = Result; + } + + public UnassignedReferenceException (string message) + : base (message) + { + HResult = Result; + } + + public UnassignedReferenceException (string message, Exception innerException) + : base (message, innerException) + { + HResult = Result; + } +#if !UNITY_WINRT + protected UnassignedReferenceException (SerializationInfo info, StreamingContext context) + : base (info, context) + { + } +#endif +} + + +[Serializable] +public class MissingReferenceException : SystemException +{ + const int Result = unchecked ((int)0x80004003); + string unityStackTrace; + + // Constructors + public MissingReferenceException () + : base ("A Unity Runtime error occurred!") + { + HResult = Result; + } + + public MissingReferenceException (string message) + : base (message) + { + HResult = Result; + } + + public MissingReferenceException (string message, Exception innerException) + : base (message, innerException) + { + HResult = Result; + } +#if !UNITY_WINRT + protected MissingReferenceException (SerializationInfo info, StreamingContext context) + : base (info, context) + { + } +#endif +} + + +} |