void ResolveStacktraces(string symbolPath, Regex regex) { m_ResolvedStacktraces = String.Empty; if (string.IsNullOrEmpty(m_Text)) { m_ResolvedStacktraces = string.Format(" <color={0}>(Please add some log with addresses first)</color>", m_RedColor); return; } var lines = m_Text.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); foreach (var l in lines) { string address; string library; if (!ParseLine(regex, l, out address, out library)) { m_ResolvedStacktraces += l; } else { string resolved = string.Format(" <color={0}>(Not resolved)</color>", m_RedColor); var symbolFile = GetSymbolFile(symbolPath, library); if (string.IsNullOrEmpty(symbolFile)) { resolved = string.Format(" <color={0}>({1} not found)</color>", m_RedColor, library); } else { try { var result = Addr2LineWrapper.Run("\"" + symbolFile + "\"", new[] { address }); AndroidLogcatInternalLog.Log("addr2line \"{0}\" {1}", symbolFile, address); if (!string.IsNullOrEmpty(result[0])) { resolved = string.Format(" <color={0}>({1})</color>", m_GreenColor, result[0].Trim()); } } catch (Exception ex) { m_ResolvedStacktraces = string.Format("Exception while running addr2line ('{0}', {1}):\n{2}", symbolFile, address, ex.Message); return; } } m_ResolvedStacktraces += l.Replace(address, address + resolved); } m_ResolvedStacktraces += Environment.NewLine; } }
private void ResolveStackTrace(List <LogEntry> entries) { var unresolvedAddresses = new Dictionary <KeyValuePair <BuildInfo, string>, List <UnresolvedAddress> >(); // Gather unresolved address if there are any for (int i = 0; i < entries.Count; i++) { var entry = entries[i]; // Only process stacktraces from Error/Fatal priorities if (entry.priority != Priority.Error && entry.priority != Priority.Fatal) { continue; } // Only process stacktraces if tag is "CRASH" or "DEBUG" if (entry.tag.GetHashCode() != kCrashHashCode && entry.tag.GetHashCode() != kDebugHashCode) { continue; } BuildInfo buildInfo; // Unknown build info, that means we don't know where the symbols are located if (!m_BuildInfos.TryGetValue(entry.processId, out buildInfo)) { continue; } string address, libName; if (!ParseCrashMessage(entry.message, out address, out libName)) { continue; } List <UnresolvedAddress> addresses; var key = new KeyValuePair <BuildInfo, string>(buildInfo, libName); if (!unresolvedAddresses.TryGetValue(key, out addresses)) { unresolvedAddresses[key] = new List <UnresolvedAddress>(); } unresolvedAddresses[key].Add(new UnresolvedAddress() { logEntryIndex = i, unresolvedAddress = address }); } var engineDirectory = BuildPipeline.GetPlaybackEngineDirectory(BuildTarget.Android, BuildOptions.None); // Resolve addresses foreach (var u in unresolvedAddresses) { var buildInfo = u.Key.Key; var libName = u.Key.Value; var addresses = u.Value; string[] paths = { engineDirectory, "Variations", buildInfo.scriptingImplementation, buildInfo.buildType, "Symbols", buildInfo.cpu, libName }; var libpath = CombinePaths(paths); // For optimizations purposes, we batch addresses which belong to same library, so addr2line can be ran less try { var result = Addr2LineWrapper.Run(libpath, addresses.Select(m => m.unresolvedAddress)); for (int i = 0; i < addresses.Count; i++) { var idx = addresses[i].logEntryIndex; var append = string.IsNullOrEmpty(result[i]) ? "(Not Resolved)" : result[i]; entries[idx] = new LogEntry(entries[idx]) { message = ModifyLogEntry(entries[idx].message, append, false) }; } } catch (Exception ex) { for (int i = 0; i < addresses.Count; i++) { var idx = addresses[i].logEntryIndex; entries[idx] = new LogEntry(entries[idx]) { message = ModifyLogEntry(entries[idx].message, "(Addr2Line failure)", true) }; var errorMessage = new StringBuilder(); errorMessage.AppendLine("Addr2Line failure"); errorMessage.AppendLine("Scripting Backend: " + buildInfo.scriptingImplementation); errorMessage.AppendLine("Build Type: " + buildInfo.buildType); errorMessage.AppendLine("CPU: " + buildInfo.cpu); errorMessage.AppendLine(ex.Message); UnityEngine.Debug.LogError(errorMessage.ToString()); } } } }