diff --git a/.clang-format-ignore b/.clang-format-ignore
index e866a0e03..fe95f175d 100644
--- a/.clang-format-ignore
+++ b/.clang-format-ignore
@@ -1,5 +1,5 @@
Sources/KSCrashRecordingCore/KSObjCApple.h
-Sources/KSCrashRecordingCore/llvm/*
-Sources/KSCrashRecordingCore/llvm/*/*
-Sources/KSCrashRecordingCore/swift/*
-Sources/KSCrashRecordingCore/swift/*/*
+Sources/KSCrashDemangleFilter/llvm/*
+Sources/KSCrashDemangleFilter/llvm/*/*
+Sources/KSCrashDemangleFilter/swift/*
+Sources/KSCrashDemangleFilter/swift/*/*
diff --git a/.swiftpm/xcode/xcshareddata/xcschemes/KSCrash-Package.xcscheme b/.swiftpm/xcode/xcshareddata/xcschemes/KSCrash-Package.xcscheme
index aa89a5e89..cb5c54638 100644
--- a/.swiftpm/xcode/xcshareddata/xcschemes/KSCrash-Package.xcscheme
+++ b/.swiftpm/xcode/xcshareddata/xcschemes/KSCrash-Package.xcscheme
@@ -91,6 +91,20 @@
ReferencedContainer = "container:">
+
+
+
+
+
+
+
+
#import
+namespace sample_namespace
+{
+class Report
+{
+ public:
+ static void crash() { throw std::runtime_error("C++ exception"); }
+};
+} // namespace sample_namespace
+
@implementation KSCrashTriggersList
+ (void)trigger_nsException_genericNSException
@@ -46,7 +55,7 @@ + (void)trigger_nsException_nsArrayOutOfBounds
+ (void)trigger_cpp_runtimeException
{
- throw std::runtime_error("C++ exception");
+ sample_namespace::Report::crash();
}
+ (void)trigger_mach_badAccess
diff --git a/Samples/Common/Sources/LibraryBridge/ReportingSample.swift b/Samples/Common/Sources/LibraryBridge/ReportingSample.swift
index a2cf3610f..a21510ca1 100644
--- a/Samples/Common/Sources/LibraryBridge/ReportingSample.swift
+++ b/Samples/Common/Sources/LibraryBridge/ReportingSample.swift
@@ -28,6 +28,7 @@ import Foundation
import KSCrashRecording
import KSCrashFilters
import KSCrashSinks
+import KSCrashDemangleFilter
import Logging
public class ReportingSample {
@@ -58,6 +59,7 @@ public class ReportingSample {
public static func sampleLogToConsole() {
KSCrash.shared.sink = CrashReportFilterPipeline(filtersArray: [
+ CrashReportFilterDemangle(),
SampleFilter(),
SampleSink(),
])
diff --git a/Sources/KSCrashDemangleFilter/KSCrashReportFilterDemangle.m b/Sources/KSCrashDemangleFilter/KSCrashReportFilterDemangle.m
new file mode 100644
index 000000000..e12870be8
--- /dev/null
+++ b/Sources/KSCrashDemangleFilter/KSCrashReportFilterDemangle.m
@@ -0,0 +1,171 @@
+//
+// KSCrashReportFilterDemangle.m
+//
+// Created by Nikolay Volosatov on 2024-08-16.
+//
+// Copyright (c) 2012 Karl Stenerud. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall remain in place
+// in this source code.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+#import "KSCrashReportFilterDemangle.h"
+
+#import "KSCrashReport.h"
+#import "KSCrashReportFields.h"
+#import "KSDemangle_CPP.h"
+#import "KSSystemCapabilities.h"
+#if KSCRASH_HAS_SWIFT
+#import "KSDemangle_Swift.h"
+#endif
+
+// #define KSLogger_LocalLevel TRACE
+#import "KSLogger.h"
+
+@interface KSCrashReportFilterDemangle ()
+
+@end
+
+@implementation KSCrashReportFilterDemangle
+
++ (NSString *)demangledCppSymbol:(NSString *)symbol
+{
+ char *demangled = ksdm_demangleCPP(symbol.UTF8String);
+ if (demangled != NULL) {
+ NSString *result = [[NSString alloc] initWithBytesNoCopy:demangled
+ length:strlen(demangled)
+ encoding:NSUTF8StringEncoding
+ freeWhenDone:YES];
+ KSLOG_DEBUG(@"Demangled a C++ symbol '%@' -> '%@'", symbol, result);
+ return result;
+ }
+ return nil;
+}
+
++ (NSString *)demangledSwiftSymbol:(NSString *)symbol
+{
+#if KSCRASH_HAS_SWIFT
+ char *demangled = ksdm_demangleSwift(symbol.UTF8String);
+ if (demangled != NULL) {
+ NSString *result = [[NSString alloc] initWithBytesNoCopy:demangled
+ length:strlen(demangled)
+ encoding:NSUTF8StringEncoding
+ freeWhenDone:YES];
+ KSLOG_DEBUG(@"Demangled a Swift symbol '%@' -> '%@'", symbol, result);
+ return result;
+ }
+#endif
+ return nil;
+}
+
++ (NSString *)demangledSymbol:(NSString *)symbol
+{
+ return [self demangledCppSymbol:symbol] ?: [self demangledSwiftSymbol:symbol];
+}
+
+/** Recurcively demangles strings within the report.
+ * @param reportObj An object within the report (dictionary, array, string etc)
+ * @param path An array of strings representing keys in dictionaries. An empty key means an itteration within the array.
+ * @param depth Current depth of the path
+ * @return An updated object or `nil` if no changes were applied.
+ */
++ (id)demangleReportObj:(id)reportObj path:(NSArray *)path depth:(NSUInteger)depth
+{
+ // Check for NSString and try demangle
+ if (depth == path.count) {
+ if ([reportObj isKindOfClass:[NSString class]] == NO) {
+ return nil;
+ }
+ NSString *demangled = [self demangledSymbol:reportObj];
+ return demangled;
+ }
+
+ NSString *pathComponent = path[depth];
+
+ // NSArray:
+ if (pathComponent.length == 0) {
+ if ([reportObj isKindOfClass:[NSArray class]] == NO) {
+ return nil;
+ }
+ NSArray *reportArray = reportObj;
+ NSMutableArray *__block result = nil;
+ [reportArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *_Nonnull stop) {
+ id demangled = [self demangleReportObj:obj path:path depth:depth + 1];
+ if (demangled != nil && result == nil) {
+ // Initializing the updated array only on first demangled result
+ result = [NSMutableArray arrayWithCapacity:reportArray.count];
+ for (NSUInteger subIdx = 0; subIdx < idx; ++subIdx) {
+ [result addObject:reportArray[subIdx]];
+ }
+ }
+ result[idx] = demangled ?: obj;
+ }];
+ return [result copy];
+ }
+
+ // NSDictionary:
+ if ([reportObj isKindOfClass:[NSDictionary class]] == NO) {
+ return nil;
+ }
+ NSDictionary *reportDict = reportObj;
+ id demangledElement = [self demangleReportObj:reportDict[pathComponent] path:path depth:depth + 1];
+ if (demangledElement == nil) {
+ return nil;
+ }
+ NSMutableDictionary *result = [reportDict mutableCopy];
+ result[pathComponent] = demangledElement;
+ return [result copy];
+}
+
+#pragma mark - KSCrashReportFilter
+
+- (void)filterReports:(NSArray> *)reports onCompletion:(KSCrashReportFilterCompletion)onCompletion
+{
+ NSArray *demanglePaths = @[
+ @[
+ KSCrashField_Crash, KSCrashField_Threads, @"", KSCrashField_Backtrace, KSCrashField_Contents, @"",
+ KSCrashField_SymbolName
+ ],
+ @[
+ KSCrashField_RecrashReport, KSCrashField_Crash, KSCrashField_Threads, @"", KSCrashField_Backtrace,
+ KSCrashField_Contents, @"", KSCrashField_SymbolName
+ ],
+ @[ KSCrashField_Crash, KSCrashField_Error, KSCrashField_CPPException, KSCrashField_Name ],
+ @[
+ KSCrashField_RecrashReport, KSCrashField_Crash, KSCrashField_Error, KSCrashField_CPPException,
+ KSCrashField_Name
+ ],
+ ];
+
+ NSMutableArray> *filteredReports = [NSMutableArray arrayWithCapacity:[reports count]];
+ for (KSCrashReportDictionary *report in reports) {
+ if ([report isKindOfClass:[KSCrashReportDictionary class]] == NO) {
+ KSLOG_ERROR(@"Unexpected non-dictionary report: %@", report);
+ continue;
+ }
+ NSDictionary *reportDict = report.value;
+ for (NSArray *path in demanglePaths) {
+ reportDict = [[self class] demangleReportObj:reportDict path:path depth:0] ?: reportDict;
+ }
+ [filteredReports addObject:[KSCrashReportDictionary reportWithValue:reportDict]];
+ }
+
+ kscrash_callCompletion(onCompletion, filteredReports, YES, nil);
+}
+
+@end
diff --git a/Sources/KSCrashRecordingCore/KSDemangle_CPP.cpp b/Sources/KSCrashDemangleFilter/KSDemangle_CPP.cpp
similarity index 100%
rename from Sources/KSCrashRecordingCore/KSDemangle_CPP.cpp
rename to Sources/KSCrashDemangleFilter/KSDemangle_CPP.cpp
diff --git a/Sources/KSCrashRecordingCore/include/KSDemangle_CPP.h b/Sources/KSCrashDemangleFilter/KSDemangle_CPP.h
similarity index 100%
rename from Sources/KSCrashRecordingCore/include/KSDemangle_CPP.h
rename to Sources/KSCrashDemangleFilter/KSDemangle_CPP.h
diff --git a/Sources/KSCrashRecordingCore/KSDemangle_Swift.cpp b/Sources/KSCrashDemangleFilter/KSDemangle_Swift.cpp
similarity index 94%
rename from Sources/KSCrashRecordingCore/KSDemangle_Swift.cpp
rename to Sources/KSCrashDemangleFilter/KSDemangle_Swift.cpp
index bf738aac5..0e24c8e59 100644
--- a/Sources/KSCrashRecordingCore/KSDemangle_Swift.cpp
+++ b/Sources/KSCrashDemangleFilter/KSDemangle_Swift.cpp
@@ -32,7 +32,7 @@ extern "C" char *ksdm_demangleSwift(const char *mangledSymbol)
{
swift::Demangle::DemangleOptions options = swift::Demangle::DemangleOptions::SimplifiedUIDemangleOptions();
std::string demangled = swift::Demangle::demangleSymbolAsString(mangledSymbol, options);
- if (demangled.length() == 0) {
+ if (demangled.length() == 0 || strcmp(mangledSymbol, demangled.c_str()) == 0) {
return NULL;
}
return strdup(demangled.c_str());
diff --git a/Sources/KSCrashRecordingCore/include/KSDemangle_Swift.h b/Sources/KSCrashDemangleFilter/KSDemangle_Swift.h
similarity index 100%
rename from Sources/KSCrashRecordingCore/include/KSDemangle_Swift.h
rename to Sources/KSCrashDemangleFilter/KSDemangle_Swift.h
diff --git a/Sources/KSCrashDemangleFilter/Resources/PrivacyInfo.xcprivacy b/Sources/KSCrashDemangleFilter/Resources/PrivacyInfo.xcprivacy
new file mode 100644
index 000000000..0d1c54ca4
--- /dev/null
+++ b/Sources/KSCrashDemangleFilter/Resources/PrivacyInfo.xcprivacy
@@ -0,0 +1,14 @@
+
+
+
+
+ NSPrivacyTracking
+
+ NSPrivacyTrackingDomains
+
+ NSPrivacyCollectedDataTypes
+
+ NSPrivacyAccessedAPITypes
+
+
+
diff --git a/Sources/KSCrashDemangleFilter/include/KSCrashReportFilterDemangle.h b/Sources/KSCrashDemangleFilter/include/KSCrashReportFilterDemangle.h
new file mode 100644
index 000000000..e0ba776c9
--- /dev/null
+++ b/Sources/KSCrashDemangleFilter/include/KSCrashReportFilterDemangle.h
@@ -0,0 +1,60 @@
+//
+// KSCrashReportFilterDemangle.h
+//
+// Created by Nikolay Volosatov on 2024-08-16.
+//
+// Copyright (c) 2012 Karl Stenerud. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall remain in place
+// in this source code.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+#import "KSCrashReportFilter.h"
+#import "KSJSONCodecObjC.h"
+
+#import
+
+NS_ASSUME_NONNULL_BEGIN
+
+/** Demangle symbols in raw crash reports.
+ *
+ * Input: NSDictionary
+ * Output: NSDictionary
+ */
+NS_SWIFT_NAME(CrashReportFilterDemangle)
+@interface KSCrashReportFilterDemangle : NSObject
+
+/** Demangles a C++ symbol.
+ *
+ * @param symbol The mangled symbol.
+ *
+ * @return A demangled symbol, or `nil` if demangling failed.
+ */
++ (NSString *)demangledCppSymbol:(NSString *)symbol;
+
+/** Demangles a Swift symbol.
+ *
+ * @param symbol The mangled symbol.
+ *
+ * @return A demangled symbol, or `nil` if demangling failed.
+ */
++ (NSString *)demangledSwiftSymbol:(NSString *)symbol;
+
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/Sources/KSCrashRecordingCore/llvm/ADT/KSOptional.h b/Sources/KSCrashDemangleFilter/llvm/ADT/KSOptional.h
similarity index 100%
rename from Sources/KSCrashRecordingCore/llvm/ADT/KSOptional.h
rename to Sources/KSCrashDemangleFilter/llvm/ADT/KSOptional.h
diff --git a/Sources/KSCrashRecordingCore/llvm/ADT/None.h b/Sources/KSCrashDemangleFilter/llvm/ADT/None.h
similarity index 100%
rename from Sources/KSCrashRecordingCore/llvm/ADT/None.h
rename to Sources/KSCrashDemangleFilter/llvm/ADT/None.h
diff --git a/Sources/KSCrashRecordingCore/llvm/ADT/StringRef.h b/Sources/KSCrashDemangleFilter/llvm/ADT/StringRef.h
similarity index 100%
rename from Sources/KSCrashRecordingCore/llvm/ADT/StringRef.h
rename to Sources/KSCrashDemangleFilter/llvm/ADT/StringRef.h
diff --git a/Sources/KSCrashRecordingCore/llvm/Config/llvm-config.h b/Sources/KSCrashDemangleFilter/llvm/Config/llvm-config.h
similarity index 100%
rename from Sources/KSCrashRecordingCore/llvm/Config/llvm-config.h
rename to Sources/KSCrashDemangleFilter/llvm/Config/llvm-config.h
diff --git a/Sources/KSCrashRecordingCore/llvm/LICENSE.TXT b/Sources/KSCrashDemangleFilter/llvm/LICENSE.TXT
similarity index 100%
rename from Sources/KSCrashRecordingCore/llvm/LICENSE.TXT
rename to Sources/KSCrashDemangleFilter/llvm/LICENSE.TXT
diff --git a/Sources/KSCrashRecordingCore/llvm/Support/AlignOf.h b/Sources/KSCrashDemangleFilter/llvm/Support/AlignOf.h
similarity index 100%
rename from Sources/KSCrashRecordingCore/llvm/Support/AlignOf.h
rename to Sources/KSCrashDemangleFilter/llvm/Support/AlignOf.h
diff --git a/Sources/KSCrashRecordingCore/llvm/Support/Casting.h b/Sources/KSCrashDemangleFilter/llvm/Support/Casting.h
similarity index 100%
rename from Sources/KSCrashRecordingCore/llvm/Support/Casting.h
rename to Sources/KSCrashDemangleFilter/llvm/Support/Casting.h
diff --git a/Sources/KSCrashRecordingCore/llvm/Support/Compiler.h b/Sources/KSCrashDemangleFilter/llvm/Support/Compiler.h
similarity index 100%
rename from Sources/KSCrashRecordingCore/llvm/Support/Compiler.h
rename to Sources/KSCrashDemangleFilter/llvm/Support/Compiler.h
diff --git a/Sources/KSCrashRecordingCore/llvm/Support/type_traits.h b/Sources/KSCrashDemangleFilter/llvm/Support/type_traits.h
similarity index 100%
rename from Sources/KSCrashRecordingCore/llvm/Support/type_traits.h
rename to Sources/KSCrashDemangleFilter/llvm/Support/type_traits.h
diff --git a/Sources/KSCrashRecordingCore/swift/Basic/Config.h b/Sources/KSCrashDemangleFilter/swift/Basic/Config.h
similarity index 100%
rename from Sources/KSCrashRecordingCore/swift/Basic/Config.h
rename to Sources/KSCrashDemangleFilter/swift/Basic/Config.h
diff --git a/Sources/KSCrashRecordingCore/swift/Basic/Context.cpp b/Sources/KSCrashDemangleFilter/swift/Basic/Context.cpp
similarity index 100%
rename from Sources/KSCrashRecordingCore/swift/Basic/Context.cpp
rename to Sources/KSCrashDemangleFilter/swift/Basic/Context.cpp
diff --git a/Sources/KSCrashRecordingCore/swift/Basic/Demangle.cpp b/Sources/KSCrashDemangleFilter/swift/Basic/Demangle.cpp
similarity index 100%
rename from Sources/KSCrashRecordingCore/swift/Basic/Demangle.cpp
rename to Sources/KSCrashDemangleFilter/swift/Basic/Demangle.cpp
diff --git a/Sources/KSCrashRecordingCore/swift/Basic/Demangle.h b/Sources/KSCrashDemangleFilter/swift/Basic/Demangle.h
similarity index 100%
rename from Sources/KSCrashRecordingCore/swift/Basic/Demangle.h
rename to Sources/KSCrashDemangleFilter/swift/Basic/Demangle.h
diff --git a/Sources/KSCrashRecordingCore/swift/Basic/DemangleNodes.def b/Sources/KSCrashDemangleFilter/swift/Basic/DemangleNodes.def
similarity index 100%
rename from Sources/KSCrashRecordingCore/swift/Basic/DemangleNodes.def
rename to Sources/KSCrashDemangleFilter/swift/Basic/DemangleNodes.def
diff --git a/Sources/KSCrashRecordingCore/swift/Basic/DemangleNodes.h b/Sources/KSCrashDemangleFilter/swift/Basic/DemangleNodes.h
similarity index 100%
rename from Sources/KSCrashRecordingCore/swift/Basic/DemangleNodes.h
rename to Sources/KSCrashDemangleFilter/swift/Basic/DemangleNodes.h
diff --git a/Sources/KSCrashRecordingCore/swift/Basic/Demangler.cpp b/Sources/KSCrashDemangleFilter/swift/Basic/Demangler.cpp
similarity index 100%
rename from Sources/KSCrashRecordingCore/swift/Basic/Demangler.cpp
rename to Sources/KSCrashDemangleFilter/swift/Basic/Demangler.cpp
diff --git a/Sources/KSCrashRecordingCore/swift/Basic/Demangler.h b/Sources/KSCrashDemangleFilter/swift/Basic/Demangler.h
similarity index 100%
rename from Sources/KSCrashRecordingCore/swift/Basic/Demangler.h
rename to Sources/KSCrashDemangleFilter/swift/Basic/Demangler.h
diff --git a/Sources/KSCrashRecordingCore/swift/Basic/Fallthrough.h b/Sources/KSCrashDemangleFilter/swift/Basic/Fallthrough.h
similarity index 100%
rename from Sources/KSCrashRecordingCore/swift/Basic/Fallthrough.h
rename to Sources/KSCrashDemangleFilter/swift/Basic/Fallthrough.h
diff --git a/Sources/KSCrashRecordingCore/swift/Basic/LLVM.h b/Sources/KSCrashDemangleFilter/swift/Basic/LLVM.h
similarity index 100%
rename from Sources/KSCrashRecordingCore/swift/Basic/LLVM.h
rename to Sources/KSCrashDemangleFilter/swift/Basic/LLVM.h
diff --git a/Sources/KSCrashRecordingCore/swift/Basic/Malloc.h b/Sources/KSCrashDemangleFilter/swift/Basic/Malloc.h
similarity index 100%
rename from Sources/KSCrashRecordingCore/swift/Basic/Malloc.h
rename to Sources/KSCrashDemangleFilter/swift/Basic/Malloc.h
diff --git a/Sources/KSCrashRecordingCore/swift/Basic/ManglingMacros.h b/Sources/KSCrashDemangleFilter/swift/Basic/ManglingMacros.h
similarity index 100%
rename from Sources/KSCrashRecordingCore/swift/Basic/ManglingMacros.h
rename to Sources/KSCrashDemangleFilter/swift/Basic/ManglingMacros.h
diff --git a/Sources/KSCrashRecordingCore/swift/Basic/ManglingUtils.cpp b/Sources/KSCrashDemangleFilter/swift/Basic/ManglingUtils.cpp
similarity index 100%
rename from Sources/KSCrashRecordingCore/swift/Basic/ManglingUtils.cpp
rename to Sources/KSCrashDemangleFilter/swift/Basic/ManglingUtils.cpp
diff --git a/Sources/KSCrashRecordingCore/swift/Basic/ManglingUtils.h b/Sources/KSCrashDemangleFilter/swift/Basic/ManglingUtils.h
similarity index 100%
rename from Sources/KSCrashRecordingCore/swift/Basic/ManglingUtils.h
rename to Sources/KSCrashDemangleFilter/swift/Basic/ManglingUtils.h
diff --git a/Sources/KSCrashRecordingCore/swift/Basic/NodePrinter.cpp b/Sources/KSCrashDemangleFilter/swift/Basic/NodePrinter.cpp
similarity index 100%
rename from Sources/KSCrashRecordingCore/swift/Basic/NodePrinter.cpp
rename to Sources/KSCrashDemangleFilter/swift/Basic/NodePrinter.cpp
diff --git a/Sources/KSCrashRecordingCore/swift/Basic/OldDemangler.cpp b/Sources/KSCrashDemangleFilter/swift/Basic/OldDemangler.cpp
similarity index 100%
rename from Sources/KSCrashRecordingCore/swift/Basic/OldDemangler.cpp
rename to Sources/KSCrashDemangleFilter/swift/Basic/OldDemangler.cpp
diff --git a/Sources/KSCrashRecordingCore/swift/Basic/Platform.h b/Sources/KSCrashDemangleFilter/swift/Basic/Platform.h
similarity index 100%
rename from Sources/KSCrashRecordingCore/swift/Basic/Platform.h
rename to Sources/KSCrashDemangleFilter/swift/Basic/Platform.h
diff --git a/Sources/KSCrashRecordingCore/swift/Basic/Punycode.cpp b/Sources/KSCrashDemangleFilter/swift/Basic/Punycode.cpp
similarity index 100%
rename from Sources/KSCrashRecordingCore/swift/Basic/Punycode.cpp
rename to Sources/KSCrashDemangleFilter/swift/Basic/Punycode.cpp
diff --git a/Sources/KSCrashRecordingCore/swift/Basic/Punycode.h b/Sources/KSCrashDemangleFilter/swift/Basic/Punycode.h
similarity index 100%
rename from Sources/KSCrashRecordingCore/swift/Basic/Punycode.h
rename to Sources/KSCrashDemangleFilter/swift/Basic/Punycode.h
diff --git a/Sources/KSCrashRecordingCore/swift/Basic/ReferenceStorage.def b/Sources/KSCrashDemangleFilter/swift/Basic/ReferenceStorage.def
similarity index 100%
rename from Sources/KSCrashRecordingCore/swift/Basic/ReferenceStorage.def
rename to Sources/KSCrashDemangleFilter/swift/Basic/ReferenceStorage.def
diff --git a/Sources/KSCrashRecordingCore/swift/Basic/STLExtras.h b/Sources/KSCrashDemangleFilter/swift/Basic/STLExtras.h
similarity index 100%
rename from Sources/KSCrashRecordingCore/swift/Basic/STLExtras.h
rename to Sources/KSCrashDemangleFilter/swift/Basic/STLExtras.h
diff --git a/Sources/KSCrashRecordingCore/swift/Basic/StandardTypesMangling.def b/Sources/KSCrashDemangleFilter/swift/Basic/StandardTypesMangling.def
similarity index 100%
rename from Sources/KSCrashRecordingCore/swift/Basic/StandardTypesMangling.def
rename to Sources/KSCrashDemangleFilter/swift/Basic/StandardTypesMangling.def
diff --git a/Sources/KSCrashRecordingCore/swift/Basic/SwiftDemangle.h b/Sources/KSCrashDemangleFilter/swift/Basic/SwiftDemangle.h
similarity index 100%
rename from Sources/KSCrashRecordingCore/swift/Basic/SwiftDemangle.h
rename to Sources/KSCrashDemangleFilter/swift/Basic/SwiftDemangle.h
diff --git a/Sources/KSCrashRecordingCore/swift/Basic/ValueWitnessMangling.def b/Sources/KSCrashDemangleFilter/swift/Basic/ValueWitnessMangling.def
similarity index 100%
rename from Sources/KSCrashRecordingCore/swift/Basic/ValueWitnessMangling.def
rename to Sources/KSCrashDemangleFilter/swift/Basic/ValueWitnessMangling.def
diff --git a/Sources/KSCrashRecordingCore/swift/Basic/Visibility.h b/Sources/KSCrashDemangleFilter/swift/Basic/Visibility.h
similarity index 100%
rename from Sources/KSCrashRecordingCore/swift/Basic/Visibility.h
rename to Sources/KSCrashDemangleFilter/swift/Basic/Visibility.h
diff --git a/Sources/KSCrashRecordingCore/swift/LICENSE.txt b/Sources/KSCrashDemangleFilter/swift/LICENSE.txt
similarity index 100%
rename from Sources/KSCrashRecordingCore/swift/LICENSE.txt
rename to Sources/KSCrashDemangleFilter/swift/LICENSE.txt
diff --git a/Sources/KSCrashRecordingCore/swift/SwiftStrings.h b/Sources/KSCrashDemangleFilter/swift/SwiftStrings.h
similarity index 100%
rename from Sources/KSCrashRecordingCore/swift/SwiftStrings.h
rename to Sources/KSCrashDemangleFilter/swift/SwiftStrings.h
diff --git a/Sources/KSCrashInstallations/KSCrashInstallation.m b/Sources/KSCrashInstallations/KSCrashInstallation.m
index e12f43637..f004fd202 100644
--- a/Sources/KSCrashInstallations/KSCrashInstallation.m
+++ b/Sources/KSCrashInstallations/KSCrashInstallation.m
@@ -32,6 +32,7 @@
#import "KSCrashInstallation+Private.h"
#import "KSCrashReportFilterAlert.h"
#import "KSCrashReportFilterBasic.h"
+#import "KSCrashReportFilterDemangle.h"
#import "KSJSONCodecObjC.h"
#import "KSLogger.h"
#import "KSNSErrorHelper.h"
@@ -144,6 +145,7 @@ - (id)init
- (id)initWithRequiredProperties:(NSArray *)requiredProperties
{
if ((self = [super init])) {
+ _isDemangleEnabled = YES;
_crashHandlerDataBacking =
[NSMutableData dataWithLength:sizeof(*self.crashHandlerData) +
sizeof(*self.crashHandlerData->reportFields) * kMaxProperties];
@@ -311,7 +313,14 @@ - (void)sendAllReportsWithCompletion:(KSCrashReportFilterCompletion)onCompletion
return;
}
- sink = [KSCrashReportFilterPipeline filterWithFilters:self.prependedFilters, sink, nil];
+ NSMutableArray *sinkFilters = [@[
+ self.prependedFilters,
+ sink,
+ ] mutableCopy];
+ if (self.isDemangleEnabled) {
+ [sinkFilters insertObject:[KSCrashReportFilterDemangle new] atIndex:0];
+ }
+ sink = [KSCrashReportFilterPipeline filterWithFiltersArray:sinkFilters];
KSCrash *handler = [KSCrash sharedInstance];
handler.sink = sink;
diff --git a/Sources/KSCrashInstallations/include/KSCrashInstallation.h b/Sources/KSCrashInstallations/include/KSCrashInstallation.h
index 7131799de..100518078 100644
--- a/Sources/KSCrashInstallations/include/KSCrashInstallation.h
+++ b/Sources/KSCrashInstallations/include/KSCrashInstallation.h
@@ -50,6 +50,12 @@ NS_SWIFT_NAME(CrashInstallation)
*/
@property(atomic, readwrite, assign, nullable) KSReportWriteCallback onCrash;
+/** Flag for disabling built-in demangling pre-filter.
+ * If enabled an additional KSCrashReportFilterDemangle filter will be applied first.
+ * @note Enabled by-default.
+ */
+@property(nonatomic, assign) BOOL isDemangleEnabled;
+
/** Install this crash handler with a specific configuration.
* Call this method instead of `-[KSCrash installWithConfiguration:error:]` to set up the crash handler
* tailored for your specific backend requirements.
diff --git a/Sources/KSCrashRecording/KSCrashReportFixer.c b/Sources/KSCrashRecording/KSCrashReportFixer.c
index d97076ab2..1030f3135 100644
--- a/Sources/KSCrashRecording/KSCrashReportFixer.c
+++ b/Sources/KSCrashRecording/KSCrashReportFixer.c
@@ -24,18 +24,14 @@
// THE SOFTWARE.
//
-#include "KSCrashReportFields.h"
-#include "KSDemangle_CPP.h"
-#include "KSJSONCodec.h"
-#include "KSSystemCapabilities.h"
-#if KSCRASH_HAS_SWIFT
-#include "KSDemangle_Swift.h"
-#endif
#include
#include
+#include "KSCrashReportFields.h"
#include "KSDate.h"
+#include "KSJSONCodec.h"
#include "KSLogger.h"
+#include "KSSystemCapabilities.h"
#define MAX_DEPTH 100
#define MAX_NAME_LENGTH 100
@@ -47,17 +43,6 @@ static const char *datePaths[][MAX_DEPTH] = {
};
static int datePathsCount = sizeof(datePaths) / sizeof(*datePaths);
-static const char *demanglePaths[][MAX_DEPTH] = {
- { "", KSCrashField_Crash, KSCrashField_Threads, "", KSCrashField_Backtrace, KSCrashField_Contents, "",
- KSCrashField_SymbolName },
- { "", KSCrashField_RecrashReport, KSCrashField_Crash, KSCrashField_Threads, "", KSCrashField_Backtrace,
- KSCrashField_Contents, "", KSCrashField_SymbolName },
- { "", KSCrashField_Crash, KSCrashField_Error, KSCrashField_CPPException, KSCrashField_Name },
- { "", KSCrashField_RecrashReport, KSCrashField_Crash, KSCrashField_Error, KSCrashField_CPPException,
- KSCrashField_Name },
-};
-static int demanglePathsCount = sizeof(demanglePaths) / sizeof(*demanglePaths);
-
static const char *versionPaths[][MAX_DEPTH] = {
{ "", KSCrashField_Report, KSCrashField_Version },
{ "", KSCrashField_RecrashReport, KSCrashField_Report, KSCrashField_Version },
@@ -134,11 +119,6 @@ static bool matchesMinVersion(FixupContext *context, int major, int minor, int p
return result;
}
-static bool shouldDemangle(FixupContext *context, const char *name)
-{
- return matchesAPath(context, name, demanglePaths, demanglePathsCount);
-}
-
static bool shouldFixDate(FixupContext *context, const char *name)
{
return matchesAPath(context, name, datePaths, datePathsCount);
@@ -197,22 +177,7 @@ static int onStringElement(const char *const name, const char *const value, void
{
FixupContext *context = (FixupContext *)userData;
const char *stringValue = value;
- char *demangled = NULL;
- if (shouldDemangle(context, name)) {
- demangled = ksdm_demangleCPP(value);
-#if KSCRASH_HAS_SWIFT
- if (demangled == NULL) {
- demangled = ksdm_demangleSwift(value);
- }
-#endif
- if (demangled != NULL) {
- stringValue = demangled;
- }
- }
int result = ksjson_addStringElement(context->encodeContext, name, stringValue, (int)strlen(stringValue));
- if (demangled != NULL) {
- free(demangled);
- }
if (shouldSaveVersion(context, name)) {
memset(context->reportVersionComponents, 0, sizeof(context->reportVersionComponents));
int versionPartsIndex = 0;
diff --git a/Tests/KSCrashDemangleFilterTests/KSCrashReportFilterDemangle_Tests.m b/Tests/KSCrashDemangleFilterTests/KSCrashReportFilterDemangle_Tests.m
new file mode 100644
index 000000000..5dac3daba
--- /dev/null
+++ b/Tests/KSCrashDemangleFilterTests/KSCrashReportFilterDemangle_Tests.m
@@ -0,0 +1,161 @@
+//
+// KSCrashReportFilterDemangle_Tests.m
+//
+// Created by Nikolay Volosatov on 2024-08-25.
+//
+// Copyright (c) 2012 Karl Stenerud. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall remain in place
+// in this source code.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+
+#import
+
+#import "KSCrashReport.h"
+#import "KSCrashReportFilterDemangle.h"
+
+@interface KSCrashReportFilterDemangle_Tests : XCTestCase
+
+@end
+
+@implementation KSCrashReportFilterDemangle_Tests
+
+- (void)setUp
+{
+}
+
+#pragma mark – C++ demangling
+
+- (void)testIncorrectCppSymbols
+{
+ XCTAssertNil([KSCrashReportFilterDemangle demangledCppSymbol:@""]);
+ XCTAssertNil([KSCrashReportFilterDemangle demangledCppSymbol:@"23"]);
+ XCTAssertNil([KSCrashReportFilterDemangle demangledCppSymbol:@"Not a symbol"]);
+ XCTAssertNil([KSCrashReportFilterDemangle
+ demangledCppSymbol:@"sScS12ContinuationV5yieldyAB11YieldResultOyx__GxnF"]); // Swift
+}
+
+- (void)testCorrectCppSymbols
+{
+ XCTAssertEqualObjects([KSCrashReportFilterDemangle demangledCppSymbol:@"_Z3foov"], @"foo()");
+ XCTAssertEqualObjects(
+ [KSCrashReportFilterDemangle demangledCppSymbol:@"_ZN6Widget14setStyleOptionERK12StyleOptionsb"],
+ @"Widget::setStyleOption(StyleOptions const&, bool)");
+ XCTAssertEqualObjects([KSCrashReportFilterDemangle demangledCppSymbol:@"_ZNSt8ios_base15sync_with_stdioEb"],
+ @"std::ios_base::sync_with_stdio(bool)");
+ XCTAssertEqualObjects([KSCrashReportFilterDemangle demangledCppSymbol:@"_ZNKSt5ctypeIcE13_M_widen_initEv"],
+ @"std::ctype::_M_widen_init() const");
+}
+
+#pragma mark – Swift demangling
+
+- (void)testIncorrectSwiftSymbols
+{
+ XCTAssertNil([KSCrashReportFilterDemangle demangledSwiftSymbol:@""]);
+ XCTAssertNil([KSCrashReportFilterDemangle demangledSwiftSymbol:@"23"]);
+ XCTAssertNil([KSCrashReportFilterDemangle demangledSwiftSymbol:@"Not a symbol"]);
+ XCTAssertNil([KSCrashReportFilterDemangle demangledSwiftSymbol:@"_ZNSt8ios_base15sync_with_stdioEb"]); // C++
+}
+
+- (void)testCorrectSwiftSymbols
+{
+ XCTAssertEqualObjects([KSCrashReportFilterDemangle demangledSwiftSymbol:@"$s5HelloAAC8sayHelloyyF"],
+ @"Hello.sayHello()");
+ XCTAssertEqualObjects([KSCrashReportFilterDemangle demangledSwiftSymbol:@"$s3Foo3BarC11doSomethingyyFZ"],
+ @"static Bar.doSomething()");
+ XCTAssertEqualObjects([KSCrashReportFilterDemangle demangledSwiftSymbol:@"$s3app5ModelC5valueSSvg"],
+ @"Model.value.getter");
+ XCTAssertEqualObjects([KSCrashReportFilterDemangle demangledSwiftSymbol:@"$s3Foo3BarC11doSomethingySiSS_SbtF"],
+ @"Bar.doSomething(_:_:)");
+}
+
+#pragma mark - Report
+
+- (void)testReportDemangle
+{
+ KSCrashReportFilterDemangle *filter = [KSCrashReportFilterDemangle new];
+ KSCrashReportDictionary *mangledReport = [KSCrashReportDictionary reportWithValue:@{
+ @"other_root_key" : @"A",
+ KSCrashField_Crash : @ {
+ @"other_crash_key" : @"B",
+ KSCrashField_Threads : @[
+ @{
+ KSCrashField_Backtrace : @ {
+ @"other_backtrace_key" : @"C",
+ KSCrashField_Contents : @[
+ @{
+ @"other_symbol_key" : @"D",
+ KSCrashField_SymbolName : @"_Z3foov",
+ },
+ @{
+ KSCrashField_SymbolName : @"$s5HelloAAC8sayHelloyyF",
+ },
+ @{
+ KSCrashField_SymbolName : @"Not_Mangled()",
+ },
+ ],
+ },
+ },
+ @{
+ @"empty_thread_key" : @"F",
+ },
+ ],
+ },
+ }];
+
+ KSCrashReportDictionary *expectedReport = [KSCrashReportDictionary reportWithValue:@{
+ @"other_root_key" : @"A",
+ KSCrashField_Crash : @ {
+ @"other_crash_key" : @"B",
+ KSCrashField_Threads : @[
+ @{
+ KSCrashField_Backtrace : @ {
+ @"other_backtrace_key" : @"C",
+ KSCrashField_Contents : @[
+ @{
+ @"other_symbol_key" : @"D",
+ KSCrashField_SymbolName : @"foo()",
+ },
+ @{
+ KSCrashField_SymbolName : @"Hello.sayHello()",
+ },
+ @{
+ KSCrashField_SymbolName : @"Not_Mangled()",
+ },
+ ],
+ },
+ },
+ @{
+ @"empty_thread_key" : @"F",
+ },
+ ],
+ },
+ }];
+
+ XCTestExpectation *expectation = [self expectationWithDescription:@"Filter callback called"];
+ [filter filterReports:@[ mangledReport ]
+ onCompletion:^(NSArray> *filteredReports, BOOL completed, NSError *error) {
+ KSCrashReportDictionary *demangledReport = filteredReports.firstObject;
+ XCTAssertEqualObjects(demangledReport, expectedReport);
+ [expectation fulfill];
+ }];
+
+ [self waitForExpectations:@[ expectation ] timeout:0.1];
+}
+
+@end
diff --git a/Tests/KSCrashRecordingTests/Resources/processed.json b/Tests/KSCrashRecordingTests/Resources/processed.json
index 7f72b9b17..55f684ceb 100644
--- a/Tests/KSCrashRecordingTests/Resources/processed.json
+++ b/Tests/KSCrashRecordingTests/Resources/processed.json
@@ -2044,7 +2044,7 @@
{
"object_name": "Crash-Tester",
"object_addr": 929792,
- "symbol_name": "MyCPPClass::throwAnException()",
+ "symbol_name": "_ZN10MyCPPClass16throwAnExceptionEv",
"symbol_addr": 940800,
"instruction_addr": 940935
},
@@ -2570,7 +2570,7 @@
"reason": "Something bad happened...",
"type": "cpp_exception",
"cpp_exception": {
- "name": "MyException"
+ "name": "11MyException"
}
}
},