diff --git a/Bugsnag/Assets/Bugsnag/Runtime/Native/Cocoa/LoadedImages.cs b/Bugsnag/Assets/Bugsnag/Runtime/Native/Cocoa/LoadedImages.cs index 88a91f859..df29474e2 100644 --- a/Bugsnag/Assets/Bugsnag/Runtime/Native/Cocoa/LoadedImages.cs +++ b/Bugsnag/Assets/Bugsnag/Runtime/Native/Cocoa/LoadedImages.cs @@ -15,6 +15,13 @@ class LoadedImages /// public void Refresh() { + UInt64 loadedNativeImagesAt = NativeCode.bugsnag_lastChangedLoadedImages(); + if (loadedNativeImagesAt == lastLoadedNativeImagesAt) + { + return; + } + lastLoadedNativeImagesAt = loadedNativeImagesAt; + // Ask for the current count * 2 in case new images get added between calls var nativeImages = new NativeLoadedImage[NativeCode.bugsnag_getLoadedImageCount() * 2]; var count = NativeCode.bugsnag_getLoadedImages(nativeImages, (UInt64)nativeImages.LongLength); @@ -54,6 +61,7 @@ public LoadedImage FindImageAtAddress(UInt64 address) /// The currently loaded images, as of the last call to Refresh(). /// public LoadedImage[] Images; + private UInt64 lastLoadedNativeImagesAt = 0; private class AddressToImageComparator : IComparer { diff --git a/Bugsnag/Assets/Bugsnag/Runtime/Native/Cocoa/NativeCode.cs b/Bugsnag/Assets/Bugsnag/Runtime/Native/Cocoa/NativeCode.cs index ba6bd5d81..1ddddd40b 100644 --- a/Bugsnag/Assets/Bugsnag/Runtime/Native/Cocoa/NativeCode.cs +++ b/Bugsnag/Assets/Bugsnag/Runtime/Native/Cocoa/NativeCode.cs @@ -59,6 +59,13 @@ partial class NativeCode [DllImport(Import)] internal static extern UInt64 bugsnag_getLoadedImages([In, Out] NativeLoadedImage[] images, UInt64 capacity); + /// + /// Marker for the last time the loaded images list was changed. If this value changes, + /// the loaded images have been changed. + /// + [DllImport(Import)] + internal static extern UInt64 bugsnag_lastChangedLoadedImages(); + /// /// Unlock the mutex protecting the loaded images list. /// diff --git a/Bugsnag/Assets/Bugsnag/Runtime/Payload/ErrorBuilder.cs b/Bugsnag/Assets/Bugsnag/Runtime/Payload/ErrorBuilder.cs index f725ee5a4..db16d05a2 100644 --- a/Bugsnag/Assets/Bugsnag/Runtime/Payload/ErrorBuilder.cs +++ b/Bugsnag/Assets/Bugsnag/Runtime/Payload/ErrorBuilder.cs @@ -45,10 +45,10 @@ internal Error FromUnityLogMessage(UnityLogMessage logMessage, System.Diagnostic { var match = Regex.Match(logMessage.Condition, ERROR_CLASS_MESSAGE_PATTERN, RegexOptions.Singleline); - var lines = new StackTrace(logMessage.StackTrace).StackTraceLines; + var lines = new PayloadStackTrace(logMessage.StackTrace).StackTraceLines; if (lines.Length == 0) { - lines = new StackTrace(fallbackStackFrames).StackTraceLines; + lines = new PayloadStackTrace(fallbackStackFrames).StackTraceLines; } var handledState = forceUnhandled @@ -67,7 +67,7 @@ internal Error FromUnityLogMessage(UnityLogMessage logMessage, System.Diagnostic var androidErrorData = ProcessAndroidError(message); errorClass = androidErrorData[0]; message = androidErrorData[1]; - lines = new StackTrace(logMessage.StackTrace, StackTraceFormat.AndroidJava).StackTraceLines; + lines = new PayloadStackTrace(logMessage.StackTrace, StackTraceFormat.AndroidJava).StackTraceLines; handledState = HandledState.ForUnhandledException(); } return new Error(errorClass, message, lines, handledState, isAndroidJavaException); @@ -81,14 +81,14 @@ internal Error FromUnityLogMessage(UnityLogMessage logMessage, System.Diagnostic internal Error FromStringInfo(string name, string message, string stacktrace) { - var stackFrames = new StackTrace(stacktrace).StackTraceLines; + var stackFrames = new PayloadStackTrace(stacktrace).StackTraceLines; return new Error(name, message, stackFrames); } internal Error FromSystemException(System.Exception exception, string stackTrace) { var errorClass = exception.GetType().Name; - var lines = new StackTrace(stackTrace).StackTraceLines; + var lines = new PayloadStackTrace(stackTrace).StackTraceLines; return new Error(errorClass, exception.Message, lines); } @@ -103,7 +103,7 @@ internal Error FromSystemException(System.Exception exception, System.Diagnostic var androidErrorData = ProcessAndroidError(exception.Message); var androidErrorClass = androidErrorData[0]; var androidErrorMessage = androidErrorData[1]; - var lines = new StackTrace(exception.StackTrace, StackTraceFormat.AndroidJava).StackTraceLines; + var lines = new PayloadStackTrace(exception.StackTrace, StackTraceFormat.AndroidJava).StackTraceLines; return new Error(androidErrorClass, androidErrorMessage, lines, HandledState.ForUnhandledException(), true); } else @@ -111,11 +111,11 @@ internal Error FromSystemException(System.Exception exception, System.Diagnostic StackTraceLine[] lines; if (!string.IsNullOrEmpty(exception.StackTrace)) { - lines = new StackTrace(exception.StackTrace).StackTraceLines; + lines = new PayloadStackTrace(exception.StackTrace).StackTraceLines; } else { - lines = new StackTrace(alternativeStackTrace).StackTraceLines; + lines = new PayloadStackTrace(alternativeStackTrace).StackTraceLines; } return new Error(errorClass, exception.Message, lines); } diff --git a/Bugsnag/Assets/Bugsnag/Runtime/Payload/StackTraceLine.cs b/Bugsnag/Assets/Bugsnag/Runtime/Payload/StackTraceLine.cs index d98bd02f4..c40ad6ff5 100644 --- a/Bugsnag/Assets/Bugsnag/Runtime/Payload/StackTraceLine.cs +++ b/Bugsnag/Assets/Bugsnag/Runtime/Payload/StackTraceLine.cs @@ -14,11 +14,11 @@ internal enum StackTraceFormat { Standard, AndroidJava }; /// Represents a set of Bugsnag payload stacktrace lines that are generated from a single StackTrace provided /// by the runtime. /// - class StackTrace : IEnumerable + class PayloadStackTrace : IEnumerable { public StackTraceLine[] StackTraceLines { get; private set; } - internal StackTrace(StackFrame[] stackFrames) + internal PayloadStackTrace(StackFrame[] stackFrames) { StackTraceLines = new StackTraceLine[stackFrames.Length]; for (int i = 0; i < stackFrames.Length; i++) @@ -27,9 +27,9 @@ internal StackTrace(StackFrame[] stackFrames) } } - internal StackTrace(string stackTrace) : this(stackTrace, StackTraceFormat.Standard) { } + internal PayloadStackTrace(string stackTrace) : this(stackTrace, StackTraceFormat.Standard) { } - internal StackTrace(string stackTrace, StackTraceFormat format) + internal PayloadStackTrace(string stackTrace, StackTraceFormat format) { string[] lines = stackTrace.Split(new[] {"\r\n","\r","\n", System.Environment.NewLine }, System.StringSplitOptions.RemoveEmptyEntries); diff --git a/Bugsnag/NativeSrc/Cocoa/BugsnagUnity.mm b/Bugsnag/NativeSrc/Cocoa/BugsnagUnity.mm index 1a77b3550..228665077 100644 --- a/Bugsnag/NativeSrc/Cocoa/BugsnagUnity.mm +++ b/Bugsnag/NativeSrc/Cocoa/BugsnagUnity.mm @@ -123,6 +123,7 @@ bool isValid() const { // All currently loaded images. This MUST be kept ordered: LoadAddress low to high. static std::vector allImages; static std::mutex allImagesMutex; +static uint64_t lastChangedLoadedImages; static void add_image(const struct mach_header *header, intptr_t slide) { NativeLoadedImage image(header); @@ -132,6 +133,7 @@ static void add_image(const struct mach_header *header, intptr_t slide) { std::lock_guard guard(allImagesMutex); allImages.push_back(std::move(image)); std::sort(allImages.begin(), allImages.end()); + lastChangedLoadedImages = CFAbsoluteTimeGetCurrent() * 1000000000ULL; } static void remove_image(const struct mach_header *header, intptr_t slide) { @@ -144,6 +146,7 @@ static void remove_image(const struct mach_header *header, intptr_t slide) { if (foundImage != allImages.end()) { allImages.erase(foundImage); } + lastChangedLoadedImages = CFAbsoluteTimeGetCurrent() * 1000000000ULL; } static void register_for_dyld_changes(void) { @@ -163,6 +166,10 @@ uint64_t bugsnag_getLoadedImageCount() { return allImages.size(); } +uint64_t bugsnag_lastChangedLoadedImages() { + return lastChangedLoadedImages; +} + uint64_t bugsnag_getLoadedImages(NativeLoadedImage *images, uint64_t capacity) { // Lock and hold the lock until bugsnag_unlockLoadedImages() is called. // We do this to allow the C# side time to copy over FileName and UUID.