├── .gitignore ├── LICENSE ├── RCBacktrace.podspec ├── RCBacktrace.xcodeproj ├── project.pbxproj └── project.xcworkspace │ └── contents.xcworkspacedata ├── RCBacktrace ├── Demangler.swift ├── Info.plist ├── RCBacktrace.h ├── RCBacktrace.swift ├── StackSymbol.swift ├── mach_backtrace.c └── mach_backtrace.h ├── RCBacktraceDemo ├── AppDelegate.swift ├── Assets.xcassets │ ├── AppIcon.appiconset │ │ └── Contents.json │ └── Contents.json ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard ├── Info.plist ├── RCBacktraceDemo-Bridging-Header.h ├── SecondViewController.h ├── SecondViewController.m └── ViewController.swift └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## Build generated 6 | build/ 7 | DerivedData/ 8 | 9 | ## Various settings 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | xcuserdata/ 19 | IDEWorkspaceChecks.plist 20 | 21 | ## Other 22 | *.moved-aside 23 | *.xccheckout 24 | *.xcscmblueprint 25 | .DS_Store 26 | 27 | ## Obj-C/Swift specific 28 | *.hmap 29 | *.ipa 30 | *.dSYM.zip 31 | *.dSYM 32 | 33 | ## Playgrounds 34 | timeline.xctimeline 35 | playground.xcworkspace 36 | 37 | # Swift Package Manager 38 | # 39 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 40 | # Packages/ 41 | # Package.pins 42 | # Package.resolved 43 | .build/ 44 | 45 | # CocoaPods 46 | # 47 | # We recommend against adding the Pods directory to your .gitignore. However 48 | # you should judge for yourself, the pros and cons are mentioned at: 49 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 50 | Pods/ 51 | 52 | # Carthage 53 | # 54 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 55 | Carthage/Checkouts 56 | Carthage/Build 57 | 58 | # fastlane 59 | # 60 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 61 | # screenshots whenever they are needed. 62 | # For more information about the recommended setup visit: 63 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 64 | 65 | fastlane/report.xml 66 | fastlane/Preview.html 67 | fastlane/screenshots/**/*.png 68 | fastlane/test_output 69 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Kris 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /RCBacktrace.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |spec| 2 | spec.name = 'RCBacktrace' 3 | spec.version = '0.1.7' 4 | spec.license = 'MIT' 5 | spec.summary = 'Getting backtrace of any thread for Objective-C and Swift' 6 | spec.homepage = 'https://github.com/woshiccm/RCBacktrace' 7 | spec.author = "roy" 8 | spec.source = { :git => "https://github.com/woshiccm/RCBacktrace.git", :tag => spec.version } 9 | spec.license = 'Code is private.' 10 | 11 | spec.platforms = { :ios => '8.0' } 12 | spec.requires_arc = true 13 | 14 | spec.cocoapods_version = '>= 1.4' 15 | spec.swift_version = ['4.2', '5.0'] 16 | 17 | spec.source_files = 'RCBacktrace/**/*.{h,c,swift}' 18 | end 19 | -------------------------------------------------------------------------------- /RCBacktrace.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 50; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 9C2CA0A7231575770087D221 /* RCBacktrace.h in Headers */ = {isa = PBXBuildFile; fileRef = 9C2CA0A5231575770087D221 /* RCBacktrace.h */; settings = {ATTRIBUTES = (Public, ); }; }; 11 | 9C2CA0B3231575A50087D221 /* mach_backtrace.h in Headers */ = {isa = PBXBuildFile; fileRef = 9C2CA0AD231575A50087D221 /* mach_backtrace.h */; }; 12 | 9C2CA0B4231575A50087D221 /* StackSymbol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C2CA0AE231575A50087D221 /* StackSymbol.swift */; }; 13 | 9C2CA0B5231575A50087D221 /* Demangler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C2CA0AF231575A50087D221 /* Demangler.swift */; }; 14 | 9C2CA0B6231575A50087D221 /* mach_backtrace.c in Sources */ = {isa = PBXBuildFile; fileRef = 9C2CA0B0231575A50087D221 /* mach_backtrace.c */; }; 15 | 9C2CA0B7231575A50087D221 /* RCBacktrace.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C2CA0B1231575A50087D221 /* RCBacktrace.swift */; }; 16 | 9C2CA0DA231576170087D221 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C2CA0D9231576170087D221 /* AppDelegate.swift */; }; 17 | 9C2CA0DC231576170087D221 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C2CA0DB231576170087D221 /* ViewController.swift */; }; 18 | 9C2CA0DF231576170087D221 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 9C2CA0DD231576170087D221 /* Main.storyboard */; }; 19 | 9C2CA0E1231576170087D221 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 9C2CA0E0231576170087D221 /* Assets.xcassets */; }; 20 | 9C2CA0E4231576180087D221 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 9C2CA0E2231576180087D221 /* LaunchScreen.storyboard */; }; 21 | 9C2CA0EC231576370087D221 /* SecondViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 9C2CA0EB231576370087D221 /* SecondViewController.m */; }; 22 | 9C2CA15723165DBB0087D221 /* RCBacktrace.podspec in Resources */ = {isa = PBXBuildFile; fileRef = 9C2CA15623165DBB0087D221 /* RCBacktrace.podspec */; }; 23 | 9C95C50C231A83E1004AC8BE /* RCBacktrace.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9C2CA0A2231575770087D221 /* RCBacktrace.framework */; }; 24 | 9C95C50E231A84D1004AC8BE /* RCBacktrace.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9C2CA0A2231575770087D221 /* RCBacktrace.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 25 | /* End PBXBuildFile section */ 26 | 27 | /* Begin PBXContainerItemProxy section */ 28 | 9C95C50F231A84D1004AC8BE /* PBXContainerItemProxy */ = { 29 | isa = PBXContainerItemProxy; 30 | containerPortal = 9C2CA099231575770087D221 /* Project object */; 31 | proxyType = 1; 32 | remoteGlobalIDString = 9C2CA0A1231575770087D221; 33 | remoteInfo = RCBacktrace; 34 | }; 35 | /* End PBXContainerItemProxy section */ 36 | 37 | /* Begin PBXCopyFilesBuildPhase section */ 38 | 9C95C511231A84D1004AC8BE /* Embed Frameworks */ = { 39 | isa = PBXCopyFilesBuildPhase; 40 | buildActionMask = 2147483647; 41 | dstPath = ""; 42 | dstSubfolderSpec = 10; 43 | files = ( 44 | 9C95C50E231A84D1004AC8BE /* RCBacktrace.framework in Embed Frameworks */, 45 | ); 46 | name = "Embed Frameworks"; 47 | runOnlyForDeploymentPostprocessing = 0; 48 | }; 49 | /* End PBXCopyFilesBuildPhase section */ 50 | 51 | /* Begin PBXFileReference section */ 52 | 9C2CA0A2231575770087D221 /* RCBacktrace.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = RCBacktrace.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 53 | 9C2CA0A5231575770087D221 /* RCBacktrace.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RCBacktrace.h; sourceTree = ""; }; 54 | 9C2CA0A6231575770087D221 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 55 | 9C2CA0AD231575A50087D221 /* mach_backtrace.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mach_backtrace.h; sourceTree = ""; }; 56 | 9C2CA0AE231575A50087D221 /* StackSymbol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StackSymbol.swift; sourceTree = ""; }; 57 | 9C2CA0AF231575A50087D221 /* Demangler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Demangler.swift; sourceTree = ""; }; 58 | 9C2CA0B0231575A50087D221 /* mach_backtrace.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mach_backtrace.c; sourceTree = ""; }; 59 | 9C2CA0B1231575A50087D221 /* RCBacktrace.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RCBacktrace.swift; sourceTree = ""; }; 60 | 9C2CA0D7231576170087D221 /* RCBacktraceDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = RCBacktraceDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; 61 | 9C2CA0D9231576170087D221 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 62 | 9C2CA0DB231576170087D221 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 63 | 9C2CA0DE231576170087D221 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 64 | 9C2CA0E0231576170087D221 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 65 | 9C2CA0E3231576180087D221 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 66 | 9C2CA0E5231576180087D221 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 67 | 9C2CA0E9231576360087D221 /* RCBacktraceDemo-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "RCBacktraceDemo-Bridging-Header.h"; sourceTree = ""; }; 68 | 9C2CA0EA231576370087D221 /* SecondViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SecondViewController.h; sourceTree = ""; }; 69 | 9C2CA0EB231576370087D221 /* SecondViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SecondViewController.m; sourceTree = ""; }; 70 | 9C2CA15623165DBB0087D221 /* RCBacktrace.podspec */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = RCBacktrace.podspec; sourceTree = SOURCE_ROOT; }; 71 | /* End PBXFileReference section */ 72 | 73 | /* Begin PBXFrameworksBuildPhase section */ 74 | 9C2CA09F231575770087D221 /* Frameworks */ = { 75 | isa = PBXFrameworksBuildPhase; 76 | buildActionMask = 2147483647; 77 | files = ( 78 | ); 79 | runOnlyForDeploymentPostprocessing = 0; 80 | }; 81 | 9C2CA0D4231576170087D221 /* Frameworks */ = { 82 | isa = PBXFrameworksBuildPhase; 83 | buildActionMask = 2147483647; 84 | files = ( 85 | 9C95C50C231A83E1004AC8BE /* RCBacktrace.framework in Frameworks */, 86 | ); 87 | runOnlyForDeploymentPostprocessing = 0; 88 | }; 89 | /* End PBXFrameworksBuildPhase section */ 90 | 91 | /* Begin PBXGroup section */ 92 | 9C2CA098231575770087D221 = { 93 | isa = PBXGroup; 94 | children = ( 95 | 9C2CA0A4231575770087D221 /* RCBacktrace */, 96 | 9C2CA0D8231576170087D221 /* RCBacktraceDemo */, 97 | 9C2CA0A3231575770087D221 /* Products */, 98 | 9C95C50B231A83E1004AC8BE /* Frameworks */, 99 | ); 100 | sourceTree = ""; 101 | }; 102 | 9C2CA0A3231575770087D221 /* Products */ = { 103 | isa = PBXGroup; 104 | children = ( 105 | 9C2CA0A2231575770087D221 /* RCBacktrace.framework */, 106 | 9C2CA0D7231576170087D221 /* RCBacktraceDemo.app */, 107 | ); 108 | name = Products; 109 | sourceTree = ""; 110 | }; 111 | 9C2CA0A4231575770087D221 /* RCBacktrace */ = { 112 | isa = PBXGroup; 113 | children = ( 114 | 9C2CA0B0231575A50087D221 /* mach_backtrace.c */, 115 | 9C2CA0AD231575A50087D221 /* mach_backtrace.h */, 116 | 9C2CA0B1231575A50087D221 /* RCBacktrace.swift */, 117 | 9C2CA0AF231575A50087D221 /* Demangler.swift */, 118 | 9C2CA0AE231575A50087D221 /* StackSymbol.swift */, 119 | 9C2CA15623165DBB0087D221 /* RCBacktrace.podspec */, 120 | 9C2CA0A5231575770087D221 /* RCBacktrace.h */, 121 | 9C2CA0A6231575770087D221 /* Info.plist */, 122 | ); 123 | path = RCBacktrace; 124 | sourceTree = ""; 125 | }; 126 | 9C2CA0D8231576170087D221 /* RCBacktraceDemo */ = { 127 | isa = PBXGroup; 128 | children = ( 129 | 9C2CA0D9231576170087D221 /* AppDelegate.swift */, 130 | 9C2CA0DB231576170087D221 /* ViewController.swift */, 131 | 9C2CA0EA231576370087D221 /* SecondViewController.h */, 132 | 9C2CA0EB231576370087D221 /* SecondViewController.m */, 133 | 9C2CA0DD231576170087D221 /* Main.storyboard */, 134 | 9C2CA0E0231576170087D221 /* Assets.xcassets */, 135 | 9C2CA0E2231576180087D221 /* LaunchScreen.storyboard */, 136 | 9C2CA0E5231576180087D221 /* Info.plist */, 137 | 9C2CA0E9231576360087D221 /* RCBacktraceDemo-Bridging-Header.h */, 138 | ); 139 | path = RCBacktraceDemo; 140 | sourceTree = ""; 141 | }; 142 | 9C95C50B231A83E1004AC8BE /* Frameworks */ = { 143 | isa = PBXGroup; 144 | children = ( 145 | ); 146 | name = Frameworks; 147 | sourceTree = ""; 148 | }; 149 | /* End PBXGroup section */ 150 | 151 | /* Begin PBXHeadersBuildPhase section */ 152 | 9C2CA09D231575770087D221 /* Headers */ = { 153 | isa = PBXHeadersBuildPhase; 154 | buildActionMask = 2147483647; 155 | files = ( 156 | 9C2CA0B3231575A50087D221 /* mach_backtrace.h in Headers */, 157 | 9C2CA0A7231575770087D221 /* RCBacktrace.h in Headers */, 158 | ); 159 | runOnlyForDeploymentPostprocessing = 0; 160 | }; 161 | /* End PBXHeadersBuildPhase section */ 162 | 163 | /* Begin PBXNativeTarget section */ 164 | 9C2CA0A1231575770087D221 /* RCBacktrace */ = { 165 | isa = PBXNativeTarget; 166 | buildConfigurationList = 9C2CA0AA231575770087D221 /* Build configuration list for PBXNativeTarget "RCBacktrace" */; 167 | buildPhases = ( 168 | 9C2CA09D231575770087D221 /* Headers */, 169 | 9C2CA09E231575770087D221 /* Sources */, 170 | 9C2CA09F231575770087D221 /* Frameworks */, 171 | 9C2CA0A0231575770087D221 /* Resources */, 172 | ); 173 | buildRules = ( 174 | ); 175 | dependencies = ( 176 | ); 177 | name = RCBacktrace; 178 | productName = RCBacktrace; 179 | productReference = 9C2CA0A2231575770087D221 /* RCBacktrace.framework */; 180 | productType = "com.apple.product-type.framework"; 181 | }; 182 | 9C2CA0D6231576170087D221 /* RCBacktraceDemo */ = { 183 | isa = PBXNativeTarget; 184 | buildConfigurationList = 9C2CA0E8231576180087D221 /* Build configuration list for PBXNativeTarget "RCBacktraceDemo" */; 185 | buildPhases = ( 186 | 9C2CA0D3231576170087D221 /* Sources */, 187 | 9C2CA0D4231576170087D221 /* Frameworks */, 188 | 9C2CA0D5231576170087D221 /* Resources */, 189 | 9C95C511231A84D1004AC8BE /* Embed Frameworks */, 190 | ); 191 | buildRules = ( 192 | ); 193 | dependencies = ( 194 | 9C95C510231A84D1004AC8BE /* PBXTargetDependency */, 195 | ); 196 | name = RCBacktraceDemo; 197 | productName = RCBacktraceDemo; 198 | productReference = 9C2CA0D7231576170087D221 /* RCBacktraceDemo.app */; 199 | productType = "com.apple.product-type.application"; 200 | }; 201 | /* End PBXNativeTarget section */ 202 | 203 | /* Begin PBXProject section */ 204 | 9C2CA099231575770087D221 /* Project object */ = { 205 | isa = PBXProject; 206 | attributes = { 207 | LastSwiftUpdateCheck = 1020; 208 | LastUpgradeCheck = 1020; 209 | ORGANIZATIONNAME = roy; 210 | TargetAttributes = { 211 | 9C2CA0A1231575770087D221 = { 212 | CreatedOnToolsVersion = 10.2; 213 | }; 214 | 9C2CA0D6231576170087D221 = { 215 | CreatedOnToolsVersion = 10.2; 216 | LastSwiftMigration = 1020; 217 | }; 218 | }; 219 | }; 220 | buildConfigurationList = 9C2CA09C231575770087D221 /* Build configuration list for PBXProject "RCBacktrace" */; 221 | compatibilityVersion = "Xcode 9.3"; 222 | developmentRegion = en; 223 | hasScannedForEncodings = 0; 224 | knownRegions = ( 225 | en, 226 | Base, 227 | ); 228 | mainGroup = 9C2CA098231575770087D221; 229 | productRefGroup = 9C2CA0A3231575770087D221 /* Products */; 230 | projectDirPath = ""; 231 | projectRoot = ""; 232 | targets = ( 233 | 9C2CA0A1231575770087D221 /* RCBacktrace */, 234 | 9C2CA0D6231576170087D221 /* RCBacktraceDemo */, 235 | ); 236 | }; 237 | /* End PBXProject section */ 238 | 239 | /* Begin PBXResourcesBuildPhase section */ 240 | 9C2CA0A0231575770087D221 /* Resources */ = { 241 | isa = PBXResourcesBuildPhase; 242 | buildActionMask = 2147483647; 243 | files = ( 244 | 9C2CA15723165DBB0087D221 /* RCBacktrace.podspec in Resources */, 245 | ); 246 | runOnlyForDeploymentPostprocessing = 0; 247 | }; 248 | 9C2CA0D5231576170087D221 /* Resources */ = { 249 | isa = PBXResourcesBuildPhase; 250 | buildActionMask = 2147483647; 251 | files = ( 252 | 9C2CA0E4231576180087D221 /* LaunchScreen.storyboard in Resources */, 253 | 9C2CA0E1231576170087D221 /* Assets.xcassets in Resources */, 254 | 9C2CA0DF231576170087D221 /* Main.storyboard in Resources */, 255 | ); 256 | runOnlyForDeploymentPostprocessing = 0; 257 | }; 258 | /* End PBXResourcesBuildPhase section */ 259 | 260 | /* Begin PBXSourcesBuildPhase section */ 261 | 9C2CA09E231575770087D221 /* Sources */ = { 262 | isa = PBXSourcesBuildPhase; 263 | buildActionMask = 2147483647; 264 | files = ( 265 | 9C2CA0B4231575A50087D221 /* StackSymbol.swift in Sources */, 266 | 9C2CA0B7231575A50087D221 /* RCBacktrace.swift in Sources */, 267 | 9C2CA0B5231575A50087D221 /* Demangler.swift in Sources */, 268 | 9C2CA0B6231575A50087D221 /* mach_backtrace.c in Sources */, 269 | ); 270 | runOnlyForDeploymentPostprocessing = 0; 271 | }; 272 | 9C2CA0D3231576170087D221 /* Sources */ = { 273 | isa = PBXSourcesBuildPhase; 274 | buildActionMask = 2147483647; 275 | files = ( 276 | 9C2CA0EC231576370087D221 /* SecondViewController.m in Sources */, 277 | 9C2CA0DC231576170087D221 /* ViewController.swift in Sources */, 278 | 9C2CA0DA231576170087D221 /* AppDelegate.swift in Sources */, 279 | ); 280 | runOnlyForDeploymentPostprocessing = 0; 281 | }; 282 | /* End PBXSourcesBuildPhase section */ 283 | 284 | /* Begin PBXTargetDependency section */ 285 | 9C95C510231A84D1004AC8BE /* PBXTargetDependency */ = { 286 | isa = PBXTargetDependency; 287 | target = 9C2CA0A1231575770087D221 /* RCBacktrace */; 288 | targetProxy = 9C95C50F231A84D1004AC8BE /* PBXContainerItemProxy */; 289 | }; 290 | /* End PBXTargetDependency section */ 291 | 292 | /* Begin PBXVariantGroup section */ 293 | 9C2CA0DD231576170087D221 /* Main.storyboard */ = { 294 | isa = PBXVariantGroup; 295 | children = ( 296 | 9C2CA0DE231576170087D221 /* Base */, 297 | ); 298 | name = Main.storyboard; 299 | sourceTree = ""; 300 | }; 301 | 9C2CA0E2231576180087D221 /* LaunchScreen.storyboard */ = { 302 | isa = PBXVariantGroup; 303 | children = ( 304 | 9C2CA0E3231576180087D221 /* Base */, 305 | ); 306 | name = LaunchScreen.storyboard; 307 | sourceTree = ""; 308 | }; 309 | /* End PBXVariantGroup section */ 310 | 311 | /* Begin XCBuildConfiguration section */ 312 | 9C2CA0A8231575770087D221 /* Debug */ = { 313 | isa = XCBuildConfiguration; 314 | buildSettings = { 315 | ALWAYS_SEARCH_USER_PATHS = NO; 316 | CLANG_ANALYZER_NONNULL = YES; 317 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 318 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 319 | CLANG_CXX_LIBRARY = "libc++"; 320 | CLANG_ENABLE_MODULES = YES; 321 | CLANG_ENABLE_OBJC_ARC = YES; 322 | CLANG_ENABLE_OBJC_WEAK = YES; 323 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 324 | CLANG_WARN_BOOL_CONVERSION = YES; 325 | CLANG_WARN_COMMA = YES; 326 | CLANG_WARN_CONSTANT_CONVERSION = YES; 327 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 328 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 329 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 330 | CLANG_WARN_EMPTY_BODY = YES; 331 | CLANG_WARN_ENUM_CONVERSION = YES; 332 | CLANG_WARN_INFINITE_RECURSION = YES; 333 | CLANG_WARN_INT_CONVERSION = YES; 334 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 335 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 336 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 337 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 338 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 339 | CLANG_WARN_STRICT_PROTOTYPES = YES; 340 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 341 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 342 | CLANG_WARN_UNREACHABLE_CODE = YES; 343 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 344 | CODE_SIGN_IDENTITY = "iPhone Developer"; 345 | COPY_PHASE_STRIP = NO; 346 | CURRENT_PROJECT_VERSION = 1; 347 | DEBUG_INFORMATION_FORMAT = dwarf; 348 | ENABLE_STRICT_OBJC_MSGSEND = YES; 349 | ENABLE_TESTABILITY = YES; 350 | GCC_C_LANGUAGE_STANDARD = gnu11; 351 | GCC_DYNAMIC_NO_PIC = NO; 352 | GCC_NO_COMMON_BLOCKS = YES; 353 | GCC_OPTIMIZATION_LEVEL = 0; 354 | GCC_PREPROCESSOR_DEFINITIONS = ( 355 | "DEBUG=1", 356 | "$(inherited)", 357 | ); 358 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 359 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 360 | GCC_WARN_UNDECLARED_SELECTOR = YES; 361 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 362 | GCC_WARN_UNUSED_FUNCTION = YES; 363 | GCC_WARN_UNUSED_VARIABLE = YES; 364 | IPHONEOS_DEPLOYMENT_TARGET = 12.2; 365 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 366 | MTL_FAST_MATH = YES; 367 | ONLY_ACTIVE_ARCH = YES; 368 | SDKROOT = iphoneos; 369 | VERSIONING_SYSTEM = "apple-generic"; 370 | VERSION_INFO_PREFIX = ""; 371 | }; 372 | name = Debug; 373 | }; 374 | 9C2CA0A9231575770087D221 /* Release */ = { 375 | isa = XCBuildConfiguration; 376 | buildSettings = { 377 | ALWAYS_SEARCH_USER_PATHS = NO; 378 | CLANG_ANALYZER_NONNULL = YES; 379 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 380 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 381 | CLANG_CXX_LIBRARY = "libc++"; 382 | CLANG_ENABLE_MODULES = YES; 383 | CLANG_ENABLE_OBJC_ARC = YES; 384 | CLANG_ENABLE_OBJC_WEAK = YES; 385 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 386 | CLANG_WARN_BOOL_CONVERSION = YES; 387 | CLANG_WARN_COMMA = YES; 388 | CLANG_WARN_CONSTANT_CONVERSION = YES; 389 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 390 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 391 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 392 | CLANG_WARN_EMPTY_BODY = YES; 393 | CLANG_WARN_ENUM_CONVERSION = YES; 394 | CLANG_WARN_INFINITE_RECURSION = YES; 395 | CLANG_WARN_INT_CONVERSION = YES; 396 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 397 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 398 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 399 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 400 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 401 | CLANG_WARN_STRICT_PROTOTYPES = YES; 402 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 403 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 404 | CLANG_WARN_UNREACHABLE_CODE = YES; 405 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 406 | CODE_SIGN_IDENTITY = "iPhone Developer"; 407 | COPY_PHASE_STRIP = NO; 408 | CURRENT_PROJECT_VERSION = 1; 409 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 410 | ENABLE_NS_ASSERTIONS = NO; 411 | ENABLE_STRICT_OBJC_MSGSEND = YES; 412 | GCC_C_LANGUAGE_STANDARD = gnu11; 413 | GCC_NO_COMMON_BLOCKS = YES; 414 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 415 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 416 | GCC_WARN_UNDECLARED_SELECTOR = YES; 417 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 418 | GCC_WARN_UNUSED_FUNCTION = YES; 419 | GCC_WARN_UNUSED_VARIABLE = YES; 420 | IPHONEOS_DEPLOYMENT_TARGET = 12.2; 421 | MTL_ENABLE_DEBUG_INFO = NO; 422 | MTL_FAST_MATH = YES; 423 | SDKROOT = iphoneos; 424 | VALIDATE_PRODUCT = YES; 425 | VERSIONING_SYSTEM = "apple-generic"; 426 | VERSION_INFO_PREFIX = ""; 427 | }; 428 | name = Release; 429 | }; 430 | 9C2CA0AB231575770087D221 /* Debug */ = { 431 | isa = XCBuildConfiguration; 432 | buildSettings = { 433 | CODE_SIGN_IDENTITY = ""; 434 | CODE_SIGN_STYLE = Automatic; 435 | DEFINES_MODULE = YES; 436 | DEVELOPMENT_TEAM = Y7BCF82NHQ; 437 | DYLIB_COMPATIBILITY_VERSION = 1; 438 | DYLIB_CURRENT_VERSION = 1; 439 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 440 | INFOPLIST_FILE = RCBacktrace/Info.plist; 441 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 442 | IPHONEOS_DEPLOYMENT_TARGET = 12.0; 443 | LD_RUNPATH_SEARCH_PATHS = ( 444 | "$(inherited)", 445 | "@executable_path/Frameworks", 446 | "@loader_path/Frameworks", 447 | ); 448 | PRODUCT_BUNDLE_IDENTIFIER = com.roy.RCBacktrace; 449 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; 450 | SKIP_INSTALL = YES; 451 | SWIFT_VERSION = 5.0; 452 | TARGETED_DEVICE_FAMILY = "1,2"; 453 | }; 454 | name = Debug; 455 | }; 456 | 9C2CA0AC231575770087D221 /* Release */ = { 457 | isa = XCBuildConfiguration; 458 | buildSettings = { 459 | CODE_SIGN_IDENTITY = ""; 460 | CODE_SIGN_STYLE = Automatic; 461 | DEFINES_MODULE = YES; 462 | DEVELOPMENT_TEAM = Y7BCF82NHQ; 463 | DYLIB_COMPATIBILITY_VERSION = 1; 464 | DYLIB_CURRENT_VERSION = 1; 465 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 466 | INFOPLIST_FILE = RCBacktrace/Info.plist; 467 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 468 | IPHONEOS_DEPLOYMENT_TARGET = 12.0; 469 | LD_RUNPATH_SEARCH_PATHS = ( 470 | "$(inherited)", 471 | "@executable_path/Frameworks", 472 | "@loader_path/Frameworks", 473 | ); 474 | PRODUCT_BUNDLE_IDENTIFIER = com.roy.RCBacktrace; 475 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; 476 | SKIP_INSTALL = YES; 477 | SWIFT_VERSION = 5.0; 478 | TARGETED_DEVICE_FAMILY = "1,2"; 479 | }; 480 | name = Release; 481 | }; 482 | 9C2CA0E6231576180087D221 /* Debug */ = { 483 | isa = XCBuildConfiguration; 484 | buildSettings = { 485 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 486 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 487 | CLANG_ENABLE_MODULES = YES; 488 | CODE_SIGN_STYLE = Automatic; 489 | DEVELOPMENT_TEAM = Y7BCF82NHQ; 490 | INFOPLIST_FILE = RCBacktraceDemo/Info.plist; 491 | IPHONEOS_DEPLOYMENT_TARGET = 12.0; 492 | LD_RUNPATH_SEARCH_PATHS = ( 493 | "$(inherited)", 494 | "@executable_path/Frameworks", 495 | ); 496 | PRODUCT_BUNDLE_IDENTIFIER = com.roy.RCBacktraceDemo; 497 | PRODUCT_NAME = "$(TARGET_NAME)"; 498 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 499 | SWIFT_OBJC_BRIDGING_HEADER = "RCBacktraceDemo/RCBacktraceDemo-Bridging-Header.h"; 500 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 501 | SWIFT_VERSION = 5.0; 502 | TARGETED_DEVICE_FAMILY = "1,2"; 503 | }; 504 | name = Debug; 505 | }; 506 | 9C2CA0E7231576180087D221 /* Release */ = { 507 | isa = XCBuildConfiguration; 508 | buildSettings = { 509 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 510 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 511 | CLANG_ENABLE_MODULES = YES; 512 | CODE_SIGN_STYLE = Automatic; 513 | DEVELOPMENT_TEAM = Y7BCF82NHQ; 514 | INFOPLIST_FILE = RCBacktraceDemo/Info.plist; 515 | IPHONEOS_DEPLOYMENT_TARGET = 12.0; 516 | LD_RUNPATH_SEARCH_PATHS = ( 517 | "$(inherited)", 518 | "@executable_path/Frameworks", 519 | ); 520 | PRODUCT_BUNDLE_IDENTIFIER = com.roy.RCBacktraceDemo; 521 | PRODUCT_NAME = "$(TARGET_NAME)"; 522 | SWIFT_COMPILATION_MODE = wholemodule; 523 | SWIFT_OBJC_BRIDGING_HEADER = "RCBacktraceDemo/RCBacktraceDemo-Bridging-Header.h"; 524 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 525 | SWIFT_VERSION = 5.0; 526 | TARGETED_DEVICE_FAMILY = "1,2"; 527 | }; 528 | name = Release; 529 | }; 530 | /* End XCBuildConfiguration section */ 531 | 532 | /* Begin XCConfigurationList section */ 533 | 9C2CA09C231575770087D221 /* Build configuration list for PBXProject "RCBacktrace" */ = { 534 | isa = XCConfigurationList; 535 | buildConfigurations = ( 536 | 9C2CA0A8231575770087D221 /* Debug */, 537 | 9C2CA0A9231575770087D221 /* Release */, 538 | ); 539 | defaultConfigurationIsVisible = 0; 540 | defaultConfigurationName = Release; 541 | }; 542 | 9C2CA0AA231575770087D221 /* Build configuration list for PBXNativeTarget "RCBacktrace" */ = { 543 | isa = XCConfigurationList; 544 | buildConfigurations = ( 545 | 9C2CA0AB231575770087D221 /* Debug */, 546 | 9C2CA0AC231575770087D221 /* Release */, 547 | ); 548 | defaultConfigurationIsVisible = 0; 549 | defaultConfigurationName = Release; 550 | }; 551 | 9C2CA0E8231576180087D221 /* Build configuration list for PBXNativeTarget "RCBacktraceDemo" */ = { 552 | isa = XCConfigurationList; 553 | buildConfigurations = ( 554 | 9C2CA0E6231576180087D221 /* Debug */, 555 | 9C2CA0E7231576180087D221 /* Release */, 556 | ); 557 | defaultConfigurationIsVisible = 0; 558 | defaultConfigurationName = Release; 559 | }; 560 | /* End XCConfigurationList section */ 561 | }; 562 | rootObject = 9C2CA099231575770087D221 /* Project object */; 563 | } 564 | -------------------------------------------------------------------------------- /RCBacktrace.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /RCBacktrace/Demangler.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Demangler.swift 3 | // RCBacktrace 4 | // 5 | // Created by roy.cao on 2019/8/27. 6 | // Copyright © 2019 roy. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | @_silgen_name("swift_demangle") 12 | public 13 | func _stdlib_demangleImpl( 14 | mangledName: UnsafePointer?, 15 | mangledNameLength: UInt, 16 | outputBuffer: UnsafeMutablePointer?, 17 | outputBufferSize: UnsafeMutablePointer?, 18 | flags: UInt32 19 | ) -> UnsafeMutablePointer? 20 | 21 | public func _stdlib_demangleName(_ mangledName: String) -> String { 22 | return mangledName.utf8CString.withUnsafeBufferPointer { 23 | (mangledNameUTF8CStr) in 24 | 25 | let demangledNamePtr = _stdlib_demangleImpl( 26 | mangledName: mangledNameUTF8CStr.baseAddress, 27 | mangledNameLength: UInt(mangledNameUTF8CStr.count - 1), 28 | outputBuffer: nil, 29 | outputBufferSize: nil, 30 | flags: 0) 31 | 32 | if let demangledNamePtr = demangledNamePtr { 33 | let demangledName = String(cString: demangledNamePtr) 34 | free(demangledNamePtr) 35 | return demangledName 36 | } 37 | return mangledName 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /RCBacktrace/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | $(CURRENT_PROJECT_VERSION) 21 | 22 | 23 | -------------------------------------------------------------------------------- /RCBacktrace/RCBacktrace.h: -------------------------------------------------------------------------------- 1 | // 2 | // RCBacktrace.h 3 | // RCBacktrace 4 | // 5 | // Created by roy.cao on 2019/8/27. 6 | // Copyright © 2019 roy. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for RCBacktrace. 12 | FOUNDATION_EXPORT double RCBacktraceVersionNumber; 13 | 14 | //! Project version string for RCBacktrace. 15 | FOUNDATION_EXPORT const unsigned char RCBacktraceVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | 19 | 20 | -------------------------------------------------------------------------------- /RCBacktrace/RCBacktrace.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RCBacktrace.swift 3 | // RCBackTrace 4 | // 5 | // Created by roy.cao on 2019/8/27. 6 | // Copyright © 2019 roy. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | @_silgen_name("mach_backtrace") 12 | public func backtrace(_ thread: thread_t, stack: UnsafeMutablePointer!, _ maxSymbols: Int32) -> Int32 13 | 14 | @objc public class RCBacktrace: NSObject { 15 | 16 | public static var main_thread_t: mach_port_t? 17 | 18 | /// should call this method in main thread first 19 | public static func setup() { 20 | main_thread_t = mach_thread_self() 21 | } 22 | 23 | @objc public static func callstack(_ thread: Thread) -> [StackSymbol] { 24 | let mthread = machThread(from: thread) 25 | return mach_callstack(mthread) 26 | } 27 | 28 | @objc public static func mach_callstack(_ thread: thread_t) -> [StackSymbol] { 29 | guard main_thread_t != nil else { 30 | assertionFailure("❌ [Error]: should setup in main thread first") 31 | return [] 32 | } 33 | 34 | var symbols = [StackSymbol]() 35 | let stackSize: UInt32 = 128 36 | let addrs = UnsafeMutablePointer.allocate(capacity: Int(stackSize)) 37 | defer { addrs.deallocate() } 38 | let frameCount = backtrace(thread, stack: addrs, Int32(stackSize)) 39 | let buf = UnsafeBufferPointer(start: addrs, count: Int(frameCount)) 40 | 41 | for (index, addr) in buf.enumerated() { 42 | guard let addr = addr else { continue } 43 | let addrValue = UInt(bitPattern: addr) 44 | let symbol = StackSymbolFactory.create(address: addrValue, index: index) 45 | symbols.append(symbol) 46 | } 47 | return symbols 48 | } 49 | } 50 | 51 | extension RCBacktrace { 52 | 53 | static func machThread(from thread: Thread) -> thread_t { 54 | var name: [Int8] = [Int8]() 55 | var count: mach_msg_type_number_t = 0 56 | var threads: thread_act_array_t! 57 | 58 | guard task_threads(mach_task_self_, &(threads), &count) == KERN_SUCCESS else { 59 | return mach_thread_self() 60 | } 61 | 62 | if thread.isMainThread { 63 | return main_thread_t ?? mach_thread_self() 64 | } 65 | 66 | let originName = thread.name 67 | 68 | for i in 0...size * 256) 73 | if (strcmp(&name, (thread.name!.ascii)) == 0) { 74 | thread.name = originName 75 | return threads[index] 76 | } 77 | } 78 | } 79 | 80 | thread.name = originName 81 | return mach_thread_self() 82 | } 83 | } 84 | 85 | extension Character { 86 | var isAscii: Bool { 87 | return unicodeScalars.allSatisfy { $0.isASCII } 88 | } 89 | var ascii: UInt32? { 90 | return isAscii ? unicodeScalars.first?.value : nil 91 | } 92 | } 93 | 94 | extension String { 95 | var ascii : [Int8] { 96 | var unicodeValues = [Int8]() 97 | for code in unicodeScalars { 98 | unicodeValues.append(Int8(code.value)) 99 | } 100 | return unicodeValues 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /RCBacktrace/StackSymbol.swift: -------------------------------------------------------------------------------- 1 | // 2 | // StackFrame.swift 3 | // RCBacktrace 4 | // 5 | // Created by roy.cao on 2019/8/27. 6 | // Copyright © 2019 roy. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | public class StackSymbol: NSObject { 12 | public let symbol: String 13 | public let file: String 14 | public let address: UInt 15 | public let symbolAddress: UInt 16 | public let demangledSymbol: String 17 | public let image: String 18 | public let offset: Int 19 | public let index: Int 20 | 21 | public init(symbol: String, file: String, address: UInt, symbolAddress: UInt, image: String, offset: Int, index: Int) { 22 | self.symbol = symbol 23 | self.file = file 24 | self.address = address 25 | self.symbolAddress = symbolAddress 26 | self.demangledSymbol = _stdlib_demangleName(symbol) 27 | self.image = image 28 | self.offset = offset 29 | self.index = index 30 | } 31 | 32 | public override var description: String { 33 | return formattedDescription() 34 | } 35 | 36 | /// - parameter index: the stack frame index 37 | /// - returns: a formatted string matching that used by NSThread.callStackSymbols 38 | private func formattedDescription() -> String { 39 | return image.utf8CString.withUnsafeBufferPointer { (imageBuffer: UnsafeBufferPointer) -> String in 40 | #if arch(x86_64) || arch(arm64) 41 | return String(format: "%-4ld%-35s 0x%016llx %@ + %ld", index, UInt(bitPattern: imageBuffer.baseAddress), address, demangledSymbol, offset) 42 | #else 43 | return String(format: "%-4d%-35s 0x%08lx %@ + %d", index, UInt(bitPattern: imageBuffer.baseAddress), address, demangledSymbol, offset) 44 | #endif 45 | } 46 | } 47 | } 48 | 49 | class StackSymbolFactory { 50 | 51 | /// Address for which this struct was constructed 52 | static func create(address: UInt, index: Int) -> StackSymbol { 53 | var info = dl_info() 54 | dladdr(UnsafeRawPointer(bitPattern: address), &info) 55 | 56 | let stackSymbol = StackSymbol(symbol: symbol(info: info), 57 | file: String(cString: info.dli_fname), 58 | address: address, 59 | symbolAddress: unsafeBitCast(info.dli_saddr, to: UInt.self), 60 | image: image(info: info), 61 | offset: offset(info: info, address: address), 62 | index: index) 63 | return stackSymbol 64 | } 65 | 66 | /// thanks to https://github.com/mattgallagher/CwlUtils/blob/master/Sources/CwlUtils/CwlAddressInfo.swift 67 | /// returns: the "image" (shared object pathname) for the instruction 68 | private static func image(info: dl_info) -> String { 69 | if let dli_fname = info.dli_fname, let fname = String(validatingUTF8: dli_fname), let _ = fname.range(of: "/", options: .backwards, range: nil, locale: nil) { 70 | return (fname as NSString).lastPathComponent 71 | } else { 72 | return "???" 73 | } 74 | } 75 | 76 | /// returns: the symbol nearest the address 77 | private static func symbol(info: dl_info) -> String { 78 | if let dli_sname = info.dli_sname, let sname = String(validatingUTF8: dli_sname) { 79 | return sname 80 | } else if let dli_fname = info.dli_fname, let _ = String(validatingUTF8: dli_fname) { 81 | return image(info: info) 82 | } else { 83 | return String(format: "0x%1x", UInt(bitPattern: info.dli_saddr)) 84 | } 85 | } 86 | 87 | /// returns: the address' offset relative to the nearest symbol 88 | private static func offset(info: dl_info, address: UInt) -> Int { 89 | if let dli_sname = info.dli_sname, let _ = String(validatingUTF8: dli_sname) { 90 | return Int(address - UInt(bitPattern: info.dli_saddr)) 91 | } else if let dli_fname = info.dli_fname, let _ = String(validatingUTF8: dli_fname) { 92 | return Int(address - UInt(bitPattern: info.dli_fbase)) 93 | } else { 94 | return Int(address - UInt(bitPattern: info.dli_saddr)) 95 | } 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /RCBacktrace/mach_backtrace.c: -------------------------------------------------------------------------------- 1 | // 2 | // mach_backtrace.c 3 | // RCBacktrace 4 | // 5 | // Created by roy.cao on 2019/8/27. 6 | // Copyright © 2019 roy. All rights reserved. 7 | // 8 | // thanks to https://github.com/Sharalink/catchCrashInfoWithSuspendAllThread/blob/c5e44925468d50b478e831578d6b53e5440dd8b5/MachThreadBacktrace.c 9 | 10 | #include "mach_backtrace.h" 11 | #include 12 | #include 13 | #include 14 | 15 | // macro `MACHINE_THREAD_STATE` shipped with system header is wrong.. 16 | #if defined __i386__ 17 | #define THREAD_STATE_FLAVOR x86_THREAD_STATE 18 | #define THREAD_STATE_COUNT x86_THREAD_STATE_COUNT 19 | #define __framePointer __ebp 20 | 21 | #elif defined __x86_64__ 22 | #define THREAD_STATE_FLAVOR x86_THREAD_STATE64 23 | #define THREAD_STATE_COUNT x86_THREAD_STATE64_COUNT 24 | #define __framePointer __rbp 25 | 26 | #elif defined __arm__ 27 | #define THREAD_STATE_FLAVOR ARM_THREAD_STATE 28 | #define THREAD_STATE_COUNT ARM_THREAD_STATE_COUNT 29 | #define __framePointer __r[7] 30 | 31 | #elif defined __arm64__ 32 | #define THREAD_STATE_FLAVOR ARM_THREAD_STATE64 33 | #define THREAD_STATE_COUNT ARM_THREAD_STATE64_COUNT 34 | #define __framePointer __fp 35 | 36 | #else 37 | #error "Current CPU Architecture is not supported" 38 | #endif 39 | 40 | /** 41 | * fill a backtrace call stack array of given thread 42 | * 43 | * Stack frame structure for x86/x86_64: 44 | * 45 | * | ... | 46 | * +-----------------------+ hi-addr ------------------------ 47 | * | func0 ip | 48 | * +-----------------------+ 49 | * | func0 bp |--------| stack frame of func1 50 | * +-----------------------+ v 51 | * | saved registers | bp <- sp 52 | * +-----------------------+ | 53 | * | local variables... | | 54 | * +-----------------------+ | 55 | * | func2 args | | 56 | * +-----------------------+ | ------------------------ 57 | * | func1 ip | | 58 | * +-----------------------+ | 59 | * | func1 bp |<--+ stack frame of func2 60 | * +-----------------------+ 61 | * | ... | 62 | * +-----------------------+ lo-addr ------------------------ 63 | * 64 | * list we need to get is `ip` from bottom to top 65 | * 66 | * 67 | * Stack frame structure for arm/arm64: 68 | * 69 | * | ... | 70 | * +-----------------------+ hi-addr ------------------------ 71 | * | func0 lr | 72 | * +-----------------------+ 73 | * | func0 fp |--------| stack frame of func1 74 | * +-----------------------+ v 75 | * | saved registers | fp <- sp 76 | * +-----------------------+ | 77 | * | local variables... | | 78 | * +-----------------------+ | 79 | * | func2 args | | 80 | * +-----------------------+ | ------------------------ 81 | * | func1 lr | | 82 | * +-----------------------+ | 83 | * | func1 fp |<--+ stack frame of func2 84 | * +-----------------------+ 85 | * | ... | 86 | * +-----------------------+ lo-addr ------------------------ 87 | * 88 | * when function return, first jump to lr, then restore lr 89 | * (namely first address in list is current lr) 90 | * 91 | * fp (frame pointer) is r7 register under ARM and fp register in ARM64 92 | * reference: iOS ABI Function Call Guide https://developer.apple.com/library/ios/documentation/Xcode/Conceptual/iPhoneOSABIReference/Articles/ARMv7FunctionCallingConventions.html#//apple_ref/doc/uid/TP40009022-SW1 93 | * 94 | * @param thread mach thread for tracing 95 | * @param stack caller space for saving stack trace info 96 | * @param maxSymbols max stack array count 97 | * 98 | * @return call stack address array 99 | */ 100 | int mach_backtrace(thread_t thread, void** stack, int maxSymbols) { 101 | _STRUCT_MCONTEXT machineContext; 102 | mach_msg_type_number_t stateCount = THREAD_STATE_COUNT; 103 | 104 | kern_return_t kret = thread_get_state(thread, THREAD_STATE_FLAVOR, (thread_state_t)&(machineContext.__ss), &stateCount); 105 | if (kret != KERN_SUCCESS) { 106 | return 0; 107 | } 108 | 109 | int i = 0; 110 | #if defined(__arm__) || defined (__arm64__) 111 | stack[i] = (void *)machineContext.__ss.__lr; 112 | ++i; 113 | #endif 114 | void **currentFramePointer = (void **)machineContext.__ss.__framePointer; 115 | while (i < maxSymbols) { 116 | void **previousFramePointer = *currentFramePointer; 117 | if (!previousFramePointer) break; 118 | stack[i] = *(currentFramePointer+1); 119 | currentFramePointer = previousFramePointer; 120 | ++i; 121 | } 122 | return i; 123 | } 124 | -------------------------------------------------------------------------------- /RCBacktrace/mach_backtrace.h: -------------------------------------------------------------------------------- 1 | // 2 | // mach_backtrace.h 3 | // RCBacktrace 4 | // 5 | // Created by roy.cao on 2019/8/27. 6 | // Copyright © 2019 roy. All rights reserved. 7 | // 8 | 9 | #ifndef mach_backtrace_h 10 | #define mach_backtrace_h 11 | 12 | #include 13 | 14 | /** 15 | * fill a backtrace call stack array of given thread 16 | * 17 | * @param thread mach thread for tracing 18 | * @param stack caller space for saving stack trace info 19 | * @param maxSymbols max stack array count 20 | * 21 | * @return call stack address array 22 | */ 23 | int mach_backtrace(thread_t thread, void** stack, int maxSymbols); 24 | 25 | #endif /* mach_backtrace_h */ 26 | -------------------------------------------------------------------------------- /RCBacktraceDemo/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // RCBacktraceDemo 4 | // 5 | // Created by roy.cao on 2019/8/27. 6 | // Copyright © 2019 roy. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import RCBacktrace 11 | 12 | @UIApplicationMain 13 | class AppDelegate: UIResponder, UIApplicationDelegate { 14 | 15 | var window: UIWindow? 16 | 17 | 18 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 19 | RCBacktrace.setup() 20 | return true 21 | } 22 | 23 | func applicationWillResignActive(_ application: UIApplication) { 24 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 25 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 26 | } 27 | 28 | func applicationDidEnterBackground(_ application: UIApplication) { 29 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 30 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 31 | } 32 | 33 | func applicationWillEnterForeground(_ application: UIApplication) { 34 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 35 | } 36 | 37 | func applicationDidBecomeActive(_ application: UIApplication) { 38 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 39 | } 40 | 41 | func applicationWillTerminate(_ application: UIApplication) { 42 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 43 | } 44 | 45 | 46 | } 47 | 48 | -------------------------------------------------------------------------------- /RCBacktraceDemo/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "20x20", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "20x20", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "29x29", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "29x29", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "size" : "40x40", 66 | "scale" : "1x" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "size" : "40x40", 71 | "scale" : "2x" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "size" : "76x76", 76 | "scale" : "1x" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "size" : "76x76", 81 | "scale" : "2x" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "size" : "83.5x83.5", 86 | "scale" : "2x" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "size" : "1024x1024", 91 | "scale" : "1x" 92 | } 93 | ], 94 | "info" : { 95 | "version" : 1, 96 | "author" : "xcode" 97 | } 98 | } -------------------------------------------------------------------------------- /RCBacktraceDemo/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /RCBacktraceDemo/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /RCBacktraceDemo/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /RCBacktraceDemo/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UILaunchStoryboardName 24 | LaunchScreen 25 | UIMainStoryboardFile 26 | Main 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /RCBacktraceDemo/RCBacktraceDemo-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | // 2 | // Use this file to import your target's public headers that you would like to expose to Swift. 3 | // 4 | 5 | #import "SecondViewController.h" 6 | -------------------------------------------------------------------------------- /RCBacktraceDemo/SecondViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // SecondViewController.h 3 | // RCBacktraceDemo 4 | // 5 | // Created by roy.cao on 2019/8/27. 6 | // Copyright © 2019 roy. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface SecondViewController : UIViewController 14 | 15 | @end 16 | 17 | NS_ASSUME_NONNULL_END 18 | -------------------------------------------------------------------------------- /RCBacktraceDemo/SecondViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // SecondViewController.m 3 | // RCBacktraceDemo 4 | // 5 | // Created by roy.cao on 2019/8/27. 6 | // Copyright © 2019 roy. All rights reserved. 7 | // 8 | 9 | #import "SecondViewController.h" 10 | #import "RCBacktraceDemo-Swift.h" 11 | 12 | @interface SecondViewController () 13 | 14 | @end 15 | 16 | @implementation SecondViewController 17 | 18 | - (void)foo { 19 | [self bar]; 20 | } 21 | 22 | - (void)bar { 23 | [self baz]; 24 | } 25 | 26 | - (void)baz { 27 | while (true) { 28 | ; 29 | } 30 | } 31 | 32 | - (void)viewDidLoad { 33 | [super viewDidLoad]; 34 | self.title = @"second page"; 35 | self.view.backgroundColor = UIColor.whiteColor; 36 | } 37 | 38 | - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { 39 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ 40 | [Backtrace callstackWithThread:[NSThread mainThread]]; 41 | }); 42 | [self foo]; 43 | } 44 | 45 | /* 46 | #pragma mark - Navigation 47 | 48 | // In a storyboard-based application, you will often want to do a little preparation before navigation 49 | - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { 50 | // Get the new view controller using [segue destinationViewController]. 51 | // Pass the selected object to the new view controller. 52 | } 53 | */ 54 | 55 | @end 56 | -------------------------------------------------------------------------------- /RCBacktraceDemo/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // RCBacktraceDemo 4 | // 5 | // Created by roy.cao on 2019/8/27. 6 | // Copyright © 2019 roy. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import RCBacktrace 11 | 12 | @objcMembers public class Backtrace: NSObject { 13 | 14 | public static func callstack(thread: Thread) { 15 | let symbols = RCBacktrace.callstack(.main) 16 | for symbol in symbols { 17 | print(symbol.description) 18 | } 19 | } 20 | } 21 | 22 | class ViewController: UIViewController { 23 | 24 | override func viewDidLoad() { 25 | super.viewDidLoad() 26 | self.title = "first page" 27 | 28 | let button = UIButton(frame: CGRect(x: 100, y: 200, width: 60, height: 30)) 29 | button.backgroundColor = .orange 30 | button.setTitle("test", for: .normal) 31 | button.addTarget(self, action: #selector(tapTest), for: .touchUpInside) 32 | 33 | view.addSubview(button) 34 | } 35 | 36 | @objc func tapTest() { 37 | DispatchQueue.global().async { 38 | let symbols = RCBacktrace.callstack(.main) 39 | for symbol in symbols { 40 | print(symbol.description) 41 | } 42 | } 43 | 44 | foo() 45 | } 46 | 47 | override func touchesBegan(_ touches: Set, with event: UIEvent?) { 48 | self.navigationController?.pushViewController(SecondViewController(), animated: true) 49 | } 50 | 51 | func foo() { 52 | bar() 53 | } 54 | 55 | func bar() { 56 | baz() 57 | } 58 | 59 | func baz() { 60 | while true { 61 | 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # RCBacktrace 2 | 3 | ![badge-pms](https://img.shields.io/badge/languages-Swift|ObjC-orange.svg) 4 | ![badge-platforms](https://img.shields.io/cocoapods/p/RCBacktrace.svg?style=flat) 5 | ![badge-languages](https://img.shields.io/badge/supports-Carthage|CocoaPods|SwiftPM-green.svg) 6 | [![Swift Version](https://img.shields.io/badge/Swift-4.0--5.0.x-F16D39.svg?style=flat)](https://developer.apple.com/swift) 7 | 8 | Getting backtrace of any thread for Objective-C and Swift. Only a small amount of C code, almost all done in Swift. 9 | It is is much more powerful than Thread.callStackSymbols, callStackSymbols can only get the current thread call stack symbol, and the symbol not Name Mangling in Swift。 10 | 11 | ## Features 12 | 13 | - [x] Support both Objective-C and Swift 14 | - [x] Support get backtrace of any thread 15 | - [x] Support swift_demangle 16 | 17 | 18 | ## Usage 19 | 20 | ### setup 21 | 22 | ``` 23 | RCBacktrace.setup() 24 | 25 | ``` 26 | 27 | ### callstack of thead 28 | 29 | ``` 30 | let symbols = RCBacktrace.callstack(.main) 31 | for symbol in symbols { 32 | print(symbol.description) 33 | } 34 | 35 | ``` 36 | 37 | ![Screen Shot 2019-08-27 at 10.40.02 PM.png](https://upload-images.jianshu.io/upload_images/2086987-01248172e2c933e8.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 38 | 39 | 40 | 41 | ≈ Requirements 42 | 43 | - iOS 8.0+ 44 | - Swift 4.0-5.x 45 | 46 | 47 | ## Installation 48 | 49 | #### Carthage 50 | Add the following line to your [Cartfile](https://github.com/carthage/carthage) 51 | 52 | ``` 53 | git "https://github.com/woshiccm/RCBacktrace.git" "0.1.6" 54 | ``` 55 | 56 | ### CocoaPods 57 | [CocoaPods](https://cocoapods.org) is a dependency manager for Cocoa projects. To integrate Aspect into your Xcode project using CocoaPods, specify it in your `Podfile`: 58 | 59 | ``` 60 | source 'https://github.com/CocoaPods/Specs.git' 61 | platform :ios, '10.0' 62 | use_frameworks! 63 | 64 | target 'xxxx' do 65 | pod 'RCBacktrace', '~> 0.1.6' 66 | end 67 | 68 | ``` 69 | 70 | ## License 71 | 72 | Aspect is released under the MIT license. See LICENSE for details. 73 | --------------------------------------------------------------------------------