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 = AndroidLogcatUtilities.GetSymbolFile(symbolPath, library); if (string.IsNullOrEmpty(symbolFile)) { resolved = string.Format(" <color={0}>({1} not found)</color>", m_RedColor, library); } else { try { var result = AndroidLogcatManager.instance.Runtime.Tools.RunAddr2Line(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 (!AndroidLogcatUtilities.ParseCrashLine(m_Runtime.Settings.StacktraceResolveRegex, 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; var symbolPath = CombinePaths(engineDirectory, "Variations", buildInfo.scriptingImplementation, buildInfo.buildType, "Symbols", buildInfo.cpu); var libpath = AndroidLogcatUtilities.GetSymbolFile(symbolPath, libName); // For optimizations purposes, we batch addresses which belong to same library, so addr2line can be ran less try { string[] result; if (!string.IsNullOrEmpty(libpath)) { result = m_Runtime.Tools.RunAddr2Line(libpath, addresses.Select(m => m.unresolvedAddress).ToArray()); } else { result = new string[addresses.Count]; for (int i = 0; i < addresses.Count; i++) { result[i] = string.Empty; } } 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("Full Entry Message: " + entries[idx].message); 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()); } } } }
internal static string ResolveAddresses(string[] lines, IReadOnlyList <ReordableListItem> regexes, IReadOnlyList <ReordableListItem> symbolPaths, AndroidTools tools) { var output = string.Empty; // Calling addr2line for every address is costly, that's why we need to do it in batch var unresolved = new UnresolvedAddresses(); foreach (var l in lines) { string address; string library; if (!AndroidLogcatUtilities.ParseCrashLine(regexes, l, out address, out library)) { continue; } unresolved.CreateAddressEntry(library, address); } var libraries = unresolved.GetAllLibraries(); foreach (var library in libraries) { var addresses = unresolved.GetAllAddresses(library); var symbolFile = AndroidLogcatUtilities.GetSymbolFile(symbolPaths, library); // Symbol file not found, set 'not found' messages for all addresses of this library if (string.IsNullOrEmpty(symbolFile)) { var value = $"<color={m_RedColor}>({library} not found)</color>"; foreach (var a in addresses) { unresolved.SetAddressValue(library, a, value); } continue; } try { var result = tools.RunAddr2Line(symbolFile, addresses.ToArray()); if (result.Length != addresses.Count) { return($"Failed to run addr2line, expected to receive {addresses.Count} addresses, but received {result.Length}"); } for (int i = 0; i < addresses.Count; i++) { AndroidLogcatInternalLog.Log($"{addresses[i]} ---> {result[i]}"); unresolved.SetAddressValue(library, addresses[i], $"<color={m_GreenColor}>({result[i].Trim()})</color>"); } } catch (Exception ex) { return($"Exception while running addr2line:\n{ex.Message}"); } } foreach (var l in lines) { string address; string library; if (!AndroidLogcatUtilities.ParseCrashLine(regexes, l, out address, out library)) { output += l; } else { /* * string resolved = string.Format(" <color={0}>(Not resolved)</color>", m_RedColor); * var symbolFile = AndroidLogcatUtilities.GetSymbolFile(symbolPaths, library); * if (string.IsNullOrEmpty(symbolFile)) * { * resolved = string.Format(" <color={0}>({1} not found)</color>", m_RedColor, library); * } * else * { * try * { * var result = tools.RunAddr2Line(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) * { * return string.Format("Exception while running addr2line ('{0}', {1}):\n{2}", symbolFile, address, ex.Message); * } * } */ output += l.Replace(address, address + " " + unresolved.GetAddressValue(library, address)); } output += Environment.NewLine; } return(output); }
internal static string ResolveAddresses(string[] lines, IReadOnlyList <ReordableListItem> regexes, IReadOnlyList <ReordableListItem> symbolPaths, AndroidTools tools) { var output = string.Empty; // Calling addr2line for every address is costly, that's why we need to do it in batch var unresolved = new UnresolvedAddresses(); foreach (var l in lines) { string address; string library; string abi; if (!AndroidLogcatUtilities.ParseCrashLine(regexes, l, out abi, out address, out library)) { continue; } unresolved.CreateAddressEntry(new UnresolvedAddresses.AddressKey() { ABI = abi, Library = library }, address); } var keys = unresolved.GetKeys(); foreach (var key in keys) { var addresses = unresolved.GetAllAddresses(key); var symbolFile = AndroidLogcatUtilities.GetSymbolFile(symbolPaths, key.ABI, key.Library); // Symbol file not found, set 'not found' messages for all addresses of this library if (string.IsNullOrEmpty(symbolFile)) { var value = $"<color={m_RedColor}>({key.Library} not found)</color>"; foreach (var a in addresses) { unresolved.SetAddressValue(key, a, value); } continue; } try { var result = tools.RunAddr2Line(symbolFile, addresses.ToArray()); if (result.Length != addresses.Count) { return($"Failed to run addr2line, expected to receive {addresses.Count} addresses, but received {result.Length}"); } for (int i = 0; i < addresses.Count; i++) { AndroidLogcatInternalLog.Log($"{addresses[i]} ---> {result[i]}"); unresolved.SetAddressValue(key, addresses[i], $"<color={m_GreenColor}>({result[i].Trim()})</color>"); } } catch (Exception ex) { return($"Exception while running addr2line:\n{ex.Message}"); } } foreach (var l in lines) { string address; string library; string abi; if (!AndroidLogcatUtilities.ParseCrashLine(regexes, l, out abi, out address, out library)) { output += l; } else { output += l.Replace(address, address + " " + unresolved.GetAddressValue(new UnresolvedAddresses.AddressKey() { ABI = abi, Library = library }, address)); } output += Environment.NewLine; } return(output); }