private void SetStacktraceInformation(StackFrame[] frames, bool generatedByException = false) { if (frames == null) { return; } int startingIndex = 0; foreach (var frame in frames) { string name; if (frame == null || frame.GetMethod() == null) { name = string.Empty; } else { name = frame.GetMethod().DeclaringType.ToString() ?? string.Empty; } if (name.ToLower().Contains("backtrace.unity")) { continue; } var backtraceFrame = new BacktraceStackFrame(frame, generatedByException); StackFrames.Insert(startingIndex, backtraceFrame); startingIndex++; } }
/// <summary> /// Try to convert Android stack frame string to Backtrace stack frame /// </summary> /// <param name="frameString">Android stack frame</param> /// <returns>Backtrace stack frame</returns> private BacktraceStackFrame SetAndroidStackTraceInformation(string frameString) { // validate if stack trace is from Android // try parse method and line number available in the function parameter var parameterStart = frameString.LastIndexOf('(') + 1; var parameterEnd = frameString.LastIndexOf(')'); var stackFrame = new BacktraceStackFrame(); stackFrame.StackFrameType = Types.BacktraceStackFrameType.Android; if (parameterStart != -1 && parameterEnd != -1 && parameterEnd - parameterStart > 1) { stackFrame.FunctionName = frameString.Substring(0, parameterStart - 1); var possibleSourceCodeInformation = frameString.Substring(parameterStart, parameterEnd - parameterStart); var sourceCodeInformation = possibleSourceCodeInformation.Split(':'); if (sourceCodeInformation.Length == 2) { stackFrame.Library = sourceCodeInformation[0]; int.TryParse(sourceCodeInformation[1], out stackFrame.Line); } else if (frameString.StartsWith("java.lang") || possibleSourceCodeInformation == "Unknown Source") { stackFrame.Library = possibleSourceCodeInformation; } } return(stackFrame); }
/// <summary> /// Try to convert native stack frame /// </summary> /// <param name="frameString">Native stack frame</param> /// <returns>Backtrace stack frame</returns> private BacktraceStackFrame SetNativeStackTraceInformation(string frameString) { var stackFrame = new BacktraceStackFrame(); stackFrame.StackFrameType = Types.BacktraceStackFrameType.Native; // parse address var addressSubstringIndex = frameString.IndexOf(' '); stackFrame.Address = frameString.Substring(0, addressSubstringIndex); var indexPointer = addressSubstringIndex + 1; // parse library if (frameString[indexPointer] == '(') { indexPointer = indexPointer + 1; var libraryNameSubstringIndex = frameString.IndexOf(')', indexPointer); stackFrame.Library = frameString.Substring(indexPointer, libraryNameSubstringIndex - indexPointer); indexPointer = libraryNameSubstringIndex + 2; } stackFrame.FunctionName = frameString.Substring(indexPointer); //cleanup function name if (stackFrame.FunctionName.StartsWith("(wrapper managed-to-native)")) { stackFrame.FunctionName = stackFrame.FunctionName.Replace("(wrapper managed-to-native)", string.Empty).Trim(); } if (stackFrame.FunctionName.StartsWith("(wrapper runtime-invoke)")) { stackFrame.FunctionName = stackFrame.FunctionName.Replace("(wrapper runtime-invoke)", string.Empty).Trim(); } // try to find source code information int sourceCodeStartIndex = stackFrame.FunctionName.IndexOf('['); int sourceCodeEndIndex = stackFrame.FunctionName.IndexOf(']'); if (sourceCodeStartIndex != -1 && sourceCodeEndIndex != -1) { sourceCodeStartIndex = sourceCodeStartIndex + 1; var sourceCodeInformation = stackFrame.FunctionName.Substring( sourceCodeStartIndex, sourceCodeEndIndex - sourceCodeStartIndex); var sourceCodeParts = sourceCodeInformation.Split(new char[] { ':' }, 2); if (sourceCodeParts.Length == 2) { int.TryParse(sourceCodeParts[1], out stackFrame.Line); stackFrame.Library = sourceCodeParts[0]; stackFrame.FunctionName = stackFrame.FunctionName.Substring(sourceCodeEndIndex + 2); } } return(stackFrame); }
/// <summary> /// Try to convert JIT stack trace /// </summary> /// <param name="frameString">JIT stack frame</param> /// <returns>Backtrace stack frame</returns> private BacktraceStackFrame SetJITStackTraceInformation(string frameString) { var stackFrame = new BacktraceStackFrame(); stackFrame.StackFrameType = Types.BacktraceStackFrameType.Native; if (!frameString.StartsWith("#")) { //handle sitaution when we detected jit stack trace // but jit stack trace doesn't start with # stackFrame.FunctionName = frameString; return(stackFrame); } frameString = frameString.Substring(frameString.IndexOf(' ')).Trim(); const string monoJitPrefix = "(Mono JIT Code)"; var monoPrefixIndex = frameString.IndexOf(monoJitPrefix); if (monoPrefixIndex != -1) { frameString = frameString.Substring(monoPrefixIndex + monoJitPrefix.Length).Trim(); } const string managedWraperPrefix = "(wrapper managed-to-native)"; var managedWraperIndex = frameString.IndexOf(managedWraperPrefix); if (managedWraperIndex != -1) { frameString = frameString.Substring(managedWraperIndex + managedWraperPrefix.Length).Trim(); } // right now we outfiltered all known prefixes // we should have only function name with parameters // filter parameters, if we can't use full frameString as function name var parametersStart = frameString.IndexOf('('); var parametersEnd = frameString.IndexOf(')'); if (parametersStart != -1 && parametersEnd != -1 && parametersEnd > parametersStart) { stackFrame.FunctionName = frameString.Substring(0, parametersStart).Trim(); } else { stackFrame.FunctionName = frameString; } return(stackFrame); }
private void SetStacktraceInformation(StackFrame[] frames, bool generatedByException = false) { if (frames == null || frames.Length == 0) { return; } int startingIndex = 0; foreach (var frame in frames) { var backtraceFrame = new BacktraceStackFrame(frame, generatedByException); if (backtraceFrame.InvalidFrame) { continue; } StackFrames.Insert(startingIndex, backtraceFrame); startingIndex++; } }
public static BacktraceReport Deserialize(string json) { var @object = BacktraceJObject.Parse(json); var attributesObject = @object["attributes"]; var attributes = new Dictionary <string, object>(); foreach (BacktraceJProperty keys in attributesObject) { attributes.Add(keys.Name, keys.Value.Value <string>()); } var exceptionStack = @object["diagnosticStack"]; var resultStack = new List <BacktraceStackFrame>(); foreach (var stack in exceptionStack) { var deserializedStack = BacktraceStackFrame.FromJson(stack.ToString()); resultStack.Add(deserializedStack); } var attachmentJson = @object["attachmentPaths"]; var attachments = attachmentJson.Select(n => n.Value <string>()).ToList(); return(new BacktraceReport(string.Empty) { Fingerprint = @object.Value <string>("Fingerprint"), Factor = @object.Value <string>("Factor"), Uuid = new Guid(@object.Value <string>("Uuid")), Timestamp = @object.Value <long>("Timestamp"), ExceptionTypeReport = @object.Value <bool>("ExceptionTypeReport"), Classifier = @object.Value <string>("Classifier"), Message = @object.Value <string>("message"), MinidumpFile = @object.Value <string>("minidumpFile"), Attributes = attributes, DiagnosticStack = resultStack, AttachmentPaths = attachments }); }
private void SetStacktraceInformation(StackFrame[] frames, bool generatedByException = false) { if (frames == null) { return; } int startingIndex = 0; //determine stack frames generated by Backtrace library //if we get stack frame from Backtrace we ignore them and reset stack frame stack var executedAssemblyName = Assembly.GetExecutingAssembly().GetName().Name; foreach (var frame in frames) { string name = frame?.GetMethod()?.DeclaringType.ToString() ?? string.Empty; if (name.ToLower().Contains("backtrace.unity")) { continue; } var backtraceFrame = new BacktraceStackFrame(frame, generatedByException); StackFrames.Insert(startingIndex, backtraceFrame); startingIndex++; } }
/// <summary> /// Convert Unity error log message to Stack trace that Backtrace uses /// in an exception report. Method below support default Unity and Android stack trace. /// </summary> private void ConvertStackFrames() { var frames = _stacktrace.Split('\n'); for (int frameIndex = 0; frameIndex < frames.Length; frameIndex++) { var frame = frames[frameIndex]; if (string.IsNullOrEmpty(frame)) { continue; } string frameString = frame.Trim(); // validate if stack trace has exception header int methodNameEndIndex = frameString.IndexOf(')'); if (methodNameEndIndex == -1) { // apply error message if (frameIndex == 0) { if (string.IsNullOrEmpty(_message)) { _message = frameString; } _header = true; continue; } else { //invalid stack frame continue; } } //methodname index should be greater than 0 AND '(' should be before ')' if (methodNameEndIndex < 1 && frameString[methodNameEndIndex - 1] != '(') { //invalid stack frame return; } BacktraceStackFrame stackFrame = null; if (frameString.StartsWith("0x")) { stackFrame = SetNativeStackTraceInformation(frameString); } else if (frameString.StartsWith("#")) { stackFrame = SetJITStackTraceInformation(frameString); } else if (frameString.IndexOf('(', methodNameEndIndex + 1) > -1) { stackFrame = SetDefaultStackTraceInformation(frameString); } else { stackFrame = SetAndroidStackTraceInformation(frameString); } // if function name is null - try to apply default parser if (stackFrame == null || string.IsNullOrEmpty(stackFrame.FunctionName)) { stackFrame = new BacktraceStackFrame() { FunctionName = frameString }; } StackFrames.Add(stackFrame); } }
/// <summary> /// Try to convert defalt unity stack frame to Backtrace stack frame /// </summary> /// <param name="frameString">Unity stack frame</param> /// <param name="sourceInformationStartIndex"></param> /// <returns></returns> private BacktraceStackFrame SetDefaultStackTraceInformation(string frameString) { const string wrapperPrefix = "(wrapper remoting-invoke-with-check)"; if (frameString.StartsWith(wrapperPrefix)) { frameString = frameString.Replace(wrapperPrefix, string.Empty); } // find method parameters int methodNameEndIndex = frameString.IndexOf(')'); // detect source code information - format : 'at (...)' // find source code start based on method parameter start index int sourceInformationStartIndex = frameString.IndexOf('(', methodNameEndIndex + 1); if (sourceInformationStartIndex == -1) { return(new BacktraceStackFrame() { FunctionName = frameString, StackFrameType = Types.BacktraceStackFrameType.Dotnet }); } // get source code information substring int sourceStringLength = frameString.Length - sourceInformationStartIndex; string sourceString = frameString.Trim() .Substring(sourceInformationStartIndex, sourceStringLength); int lineNumberSeparator = sourceString.LastIndexOf(':') + 1; int endLineNumberSeparator = sourceString.LastIndexOf(')') - lineNumberSeparator; var result = new BacktraceStackFrame() { FunctionName = frameString.Substring(0, methodNameEndIndex + 1).Trim(), StackFrameType = Types.BacktraceStackFrameType.Dotnet }; if (endLineNumberSeparator > 0 && lineNumberSeparator > 0) { string lineNumberString = sourceString.Substring(lineNumberSeparator, endLineNumberSeparator); int.TryParse(lineNumberString, out result.Line); } if (sourceString[0] == '(' && lineNumberSeparator != -1) { //avoid "at" or '(' int atSeparator = sourceString.StartsWith("(at") ? 3 : 1; int endLine = lineNumberSeparator == 0 ? sourceString.LastIndexOf(')') - atSeparator : lineNumberSeparator - 1 - atSeparator; var substring = sourceString.Substring(atSeparator, endLine); result.Library = (substring == null ? string.Empty : substring.Trim()); if (!string.IsNullOrEmpty(result.Library)) { var testString = string.Copy(result.Library); testString = testString.Replace("0", string.Empty); if (testString.Length <= 2) { result.Library = null; } } } return(result); }