├── .gitignore ├── 3rdParty ├── README ├── libdwarf-20140519.tar.gz ├── libdwarf.a ├── libdwarf.h └── libelf.a ├── README.md ├── Symbolicator.xcodeproj └── project.pbxproj └── Symbolicator ├── AppDelegate.h ├── AppDelegate.m ├── Base.lproj └── MainMenu.xib ├── BinaryImageLine.h ├── BinaryImageLine.m ├── CrashReportLine.h ├── CrashReportParser.h ├── CrashReportParser.m ├── DwarfReader.h ├── DwarfReader.m ├── ExceptionTraceLine.h ├── ExceptionTraceLine.m ├── Images.xcassets └── AppIcon.appiconset │ └── Contents.json ├── Info.plist ├── InformationalLine.h ├── InformationalLine.m ├── MachONList.h ├── MachONList.m ├── MachOReader.h ├── MachOReader.m ├── MachOSection.h ├── MachOSection.m ├── MachOSegment.h ├── MachOSegment.m ├── SectionLine.h ├── SectionLine.m ├── StackFrameLine.h ├── StackFrameLine.m ├── SymbolicationTasksBlackboard.h ├── SymbolicationTasksBlackboard.m ├── Symbolicator.entitlements ├── ThinMachObject.h ├── ThinMachObject.mm ├── main.m └── workaround.c /.gitignore: -------------------------------------------------------------------------------- 1 | xcuserdata 2 | *.xcworkspace 3 | !default.xcworkspace 4 | build 5 | builds 6 | English.lproj/.DS_Store 7 | .DS_Store -------------------------------------------------------------------------------- /3rdParty/README: -------------------------------------------------------------------------------- 1 | libelf was taken from the dtrace project on opensource.apple.com. 2 | 3 | There is a SHIM function in msg.h that is part of dtrace. It cannot be removed, and I don't understand why. Instead there is the workaround.c file. 4 | -------------------------------------------------------------------------------- /3rdParty/libdwarf-20140519.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agentsim/Symbolicator/7909d18f0dba8294a4eb34649c17dc5d3fad9227/3rdParty/libdwarf-20140519.tar.gz -------------------------------------------------------------------------------- /3rdParty/libdwarf.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agentsim/Symbolicator/7909d18f0dba8294a4eb34649c17dc5d3fad9227/3rdParty/libdwarf.a -------------------------------------------------------------------------------- /3rdParty/libelf.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/agentsim/Symbolicator/7909d18f0dba8294a4eb34649c17dc5d3fad9227/3rdParty/libelf.a -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This is a simple replacement for Xcode/symbolicatecrash for iOS/OSX crash dumps. 2 | 3 | It *should* support 32-bit/64-bit ARM and x86 crash reports. It uses Spotlight to locate dSYMs much the same way symbolicatecrash does. 4 | It should be simple enough to extend it to allow you to specify the build to use for symbols allowing you to rebuild with a known codebase if you no longer have the original build. 5 | Some pretty-ing up of the output is probably in order ;) 6 | 7 | Just drag a crash report onto the Dock icon and Symbolicator will spit out a .symbolicated file in the same directory as the source file. 8 | -------------------------------------------------------------------------------- /Symbolicator.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 0552721D19CCAE4C004D643F /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 0552721C19CCAE4C004D643F /* main.m */; }; 11 | 0552722019CCAE4C004D643F /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 0552721F19CCAE4C004D643F /* AppDelegate.m */; }; 12 | 0552722219CCAE4C004D643F /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0552722119CCAE4C004D643F /* Images.xcassets */; }; 13 | 0552722519CCAE4C004D643F /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 0552722319CCAE4C004D643F /* MainMenu.xib */; }; 14 | 0552727519CCB021004D643F /* CrashReportParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 0552727419CCB021004D643F /* CrashReportParser.m */; }; 15 | 0552727819CCB0BB004D643F /* StackFrameLine.m in Sources */ = {isa = PBXBuildFile; fileRef = 0552727719CCB0BB004D643F /* StackFrameLine.m */; }; 16 | 057D3C1B19D61F080093AC60 /* ThinMachObject.mm in Sources */ = {isa = PBXBuildFile; fileRef = 057D3C1A19D61F080093AC60 /* ThinMachObject.mm */; }; 17 | 057D3C2119D6410E0093AC60 /* MachOSegment.m in Sources */ = {isa = PBXBuildFile; fileRef = 057D3C2019D6410E0093AC60 /* MachOSegment.m */; }; 18 | 057D3C2419D651D90093AC60 /* MachONList.m in Sources */ = {isa = PBXBuildFile; fileRef = 057D3C2319D651D90093AC60 /* MachONList.m */; }; 19 | 057F6A6D19D5F01900336891 /* MachOReader.m in Sources */ = {isa = PBXBuildFile; fileRef = 057F6A6C19D5F01900336891 /* MachOReader.m */; }; 20 | 05B5320419D1C60600697884 /* SymbolicationTasksBlackboard.m in Sources */ = {isa = PBXBuildFile; fileRef = 05B5320319D1C60600697884 /* SymbolicationTasksBlackboard.m */; }; 21 | 05D2220719D7A0B1003DBD53 /* DwarfReader.m in Sources */ = {isa = PBXBuildFile; fileRef = 05D2220619D7A0B1003DBD53 /* DwarfReader.m */; }; 22 | 05D2220819D7A4D7003DBD53 /* libdwarf.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 05D2220119D79C39003DBD53 /* libdwarf.a */; }; 23 | 05D2220B19D7A511003DBD53 /* libelf.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 05D2220A19D7A511003DBD53 /* libelf.a */; }; 24 | 05DB021219D7AA1800DBC8DE /* workaround.c in Sources */ = {isa = PBXBuildFile; fileRef = 05DB021119D7AA1800DBC8DE /* workaround.c */; }; 25 | 05DB021519D7B0AE00DBC8DE /* MachOSection.m in Sources */ = {isa = PBXBuildFile; fileRef = 05DB021419D7B0AE00DBC8DE /* MachOSection.m */; }; 26 | 05E4A76019D07B4800F6842A /* BinaryImageLine.m in Sources */ = {isa = PBXBuildFile; fileRef = 05E4A75F19D07B4800F6842A /* BinaryImageLine.m */; }; 27 | 05E4A76319D089C000F6842A /* SectionLine.m in Sources */ = {isa = PBXBuildFile; fileRef = 05E4A76219D089C000F6842A /* SectionLine.m */; }; 28 | 05E594A119CE064800ACB1F1 /* ExceptionTraceLine.m in Sources */ = {isa = PBXBuildFile; fileRef = 05E594A019CE064800ACB1F1 /* ExceptionTraceLine.m */; }; 29 | 05E594A419CE0B9000ACB1F1 /* InformationalLine.m in Sources */ = {isa = PBXBuildFile; fileRef = 05E594A319CE0B9000ACB1F1 /* InformationalLine.m */; }; 30 | /* End PBXBuildFile section */ 31 | 32 | /* Begin PBXFileReference section */ 33 | 052B48BB19D3511D0072AADA /* Symbolicator.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = Symbolicator.entitlements; sourceTree = ""; }; 34 | 0552721719CCAE4C004D643F /* Symbolicator.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Symbolicator.app; sourceTree = BUILT_PRODUCTS_DIR; }; 35 | 0552721B19CCAE4C004D643F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 36 | 0552721C19CCAE4C004D643F /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 37 | 0552721E19CCAE4C004D643F /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 38 | 0552721F19CCAE4C004D643F /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 39 | 0552722119CCAE4C004D643F /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 40 | 0552722419CCAE4C004D643F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; 41 | 0552727319CCB021004D643F /* CrashReportParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CrashReportParser.h; sourceTree = ""; }; 42 | 0552727419CCB021004D643F /* CrashReportParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CrashReportParser.m; sourceTree = ""; }; 43 | 0552727619CCB0BB004D643F /* StackFrameLine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StackFrameLine.h; sourceTree = ""; }; 44 | 0552727719CCB0BB004D643F /* StackFrameLine.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = StackFrameLine.m; sourceTree = ""; }; 45 | 057D3C1919D61F080093AC60 /* ThinMachObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ThinMachObject.h; sourceTree = ""; }; 46 | 057D3C1A19D61F080093AC60 /* ThinMachObject.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ThinMachObject.mm; sourceTree = ""; }; 47 | 057D3C1F19D6410E0093AC60 /* MachOSegment.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MachOSegment.h; sourceTree = ""; }; 48 | 057D3C2019D6410E0093AC60 /* MachOSegment.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MachOSegment.m; sourceTree = ""; }; 49 | 057D3C2219D651D90093AC60 /* MachONList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MachONList.h; sourceTree = ""; }; 50 | 057D3C2319D651D90093AC60 /* MachONList.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MachONList.m; sourceTree = ""; }; 51 | 057F6A6B19D5F01900336891 /* MachOReader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MachOReader.h; sourceTree = ""; }; 52 | 057F6A6C19D5F01900336891 /* MachOReader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MachOReader.m; sourceTree = ""; }; 53 | 05B5320219D1C60600697884 /* SymbolicationTasksBlackboard.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SymbolicationTasksBlackboard.h; sourceTree = ""; }; 54 | 05B5320319D1C60600697884 /* SymbolicationTasksBlackboard.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SymbolicationTasksBlackboard.m; sourceTree = ""; }; 55 | 05D2220119D79C39003DBD53 /* libdwarf.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libdwarf.a; path = 3rdParty/libdwarf.a; sourceTree = SOURCE_ROOT; }; 56 | 05D2220319D79D68003DBD53 /* libdwarf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = libdwarf.h; path = 3rdParty/libdwarf.h; sourceTree = SOURCE_ROOT; }; 57 | 05D2220519D7A0B1003DBD53 /* DwarfReader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DwarfReader.h; sourceTree = ""; }; 58 | 05D2220619D7A0B1003DBD53 /* DwarfReader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DwarfReader.m; sourceTree = ""; }; 59 | 05D2220A19D7A511003DBD53 /* libelf.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libelf.a; path = ../3rdParty/libelf.a; sourceTree = ""; }; 60 | 05DB021119D7AA1800DBC8DE /* workaround.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = workaround.c; sourceTree = ""; }; 61 | 05DB021319D7B0AE00DBC8DE /* MachOSection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MachOSection.h; sourceTree = ""; }; 62 | 05DB021419D7B0AE00DBC8DE /* MachOSection.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MachOSection.m; sourceTree = ""; }; 63 | 05E4A75E19D07B4800F6842A /* BinaryImageLine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BinaryImageLine.h; sourceTree = ""; }; 64 | 05E4A75F19D07B4800F6842A /* BinaryImageLine.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BinaryImageLine.m; sourceTree = ""; }; 65 | 05E4A76119D089C000F6842A /* SectionLine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SectionLine.h; sourceTree = ""; }; 66 | 05E4A76219D089C000F6842A /* SectionLine.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SectionLine.m; sourceTree = ""; }; 67 | 05E5949F19CE064800ACB1F1 /* ExceptionTraceLine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ExceptionTraceLine.h; sourceTree = ""; }; 68 | 05E594A019CE064800ACB1F1 /* ExceptionTraceLine.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ExceptionTraceLine.m; sourceTree = ""; }; 69 | 05E594A219CE0B9000ACB1F1 /* InformationalLine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InformationalLine.h; sourceTree = ""; }; 70 | 05E594A319CE0B9000ACB1F1 /* InformationalLine.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = InformationalLine.m; sourceTree = ""; }; 71 | 05E594A519CE0BF900ACB1F1 /* CrashReportLine.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CrashReportLine.h; sourceTree = ""; }; 72 | /* End PBXFileReference section */ 73 | 74 | /* Begin PBXFrameworksBuildPhase section */ 75 | 0552721419CCAE4C004D643F /* Frameworks */ = { 76 | isa = PBXFrameworksBuildPhase; 77 | buildActionMask = 2147483647; 78 | files = ( 79 | 05D2220B19D7A511003DBD53 /* libelf.a in Frameworks */, 80 | 05D2220819D7A4D7003DBD53 /* libdwarf.a in Frameworks */, 81 | ); 82 | runOnlyForDeploymentPostprocessing = 0; 83 | }; 84 | /* End PBXFrameworksBuildPhase section */ 85 | 86 | /* Begin PBXGroup section */ 87 | 0552720E19CCAE4C004D643F = { 88 | isa = PBXGroup; 89 | children = ( 90 | 0552721919CCAE4C004D643F /* Symbolicator */, 91 | 0552721A19CCAE4C004D643F /* Supporting Files */, 92 | 0552721819CCAE4C004D643F /* Products */, 93 | ); 94 | sourceTree = ""; 95 | }; 96 | 0552721819CCAE4C004D643F /* Products */ = { 97 | isa = PBXGroup; 98 | children = ( 99 | 0552721719CCAE4C004D643F /* Symbolicator.app */, 100 | ); 101 | name = Products; 102 | sourceTree = ""; 103 | }; 104 | 0552721919CCAE4C004D643F /* Symbolicator */ = { 105 | isa = PBXGroup; 106 | children = ( 107 | 05E4A79E19D0D7D700F6842A /* 3rdParty */, 108 | 057F6A6E19D5F0A500336891 /* Mach Reader */, 109 | 0552721E19CCAE4C004D643F /* AppDelegate.h */, 110 | 0552721F19CCAE4C004D643F /* AppDelegate.m */, 111 | 05E4A75E19D07B4800F6842A /* BinaryImageLine.h */, 112 | 05E4A75F19D07B4800F6842A /* BinaryImageLine.m */, 113 | 05E594A519CE0BF900ACB1F1 /* CrashReportLine.h */, 114 | 0552727319CCB021004D643F /* CrashReportParser.h */, 115 | 0552727419CCB021004D643F /* CrashReportParser.m */, 116 | 05E5949F19CE064800ACB1F1 /* ExceptionTraceLine.h */, 117 | 05E594A019CE064800ACB1F1 /* ExceptionTraceLine.m */, 118 | 05E594A219CE0B9000ACB1F1 /* InformationalLine.h */, 119 | 05E594A319CE0B9000ACB1F1 /* InformationalLine.m */, 120 | 0552722319CCAE4C004D643F /* MainMenu.xib */, 121 | 05E4A76119D089C000F6842A /* SectionLine.h */, 122 | 05E4A76219D089C000F6842A /* SectionLine.m */, 123 | 0552727619CCB0BB004D643F /* StackFrameLine.h */, 124 | 0552727719CCB0BB004D643F /* StackFrameLine.m */, 125 | 05B5320219D1C60600697884 /* SymbolicationTasksBlackboard.h */, 126 | 05B5320319D1C60600697884 /* SymbolicationTasksBlackboard.m */, 127 | 05DB021119D7AA1800DBC8DE /* workaround.c */, 128 | ); 129 | path = Symbolicator; 130 | sourceTree = ""; 131 | }; 132 | 0552721A19CCAE4C004D643F /* Supporting Files */ = { 133 | isa = PBXGroup; 134 | children = ( 135 | 052B48BB19D3511D0072AADA /* Symbolicator.entitlements */, 136 | 0552722119CCAE4C004D643F /* Images.xcassets */, 137 | 0552721B19CCAE4C004D643F /* Info.plist */, 138 | 0552721C19CCAE4C004D643F /* main.m */, 139 | ); 140 | name = "Supporting Files"; 141 | path = Symbolicator; 142 | sourceTree = ""; 143 | }; 144 | 057F6A6E19D5F0A500336891 /* Mach Reader */ = { 145 | isa = PBXGroup; 146 | children = ( 147 | 05D2220519D7A0B1003DBD53 /* DwarfReader.h */, 148 | 05D2220619D7A0B1003DBD53 /* DwarfReader.m */, 149 | 057D3C2219D651D90093AC60 /* MachONList.h */, 150 | 057D3C2319D651D90093AC60 /* MachONList.m */, 151 | 057F6A6B19D5F01900336891 /* MachOReader.h */, 152 | 057F6A6C19D5F01900336891 /* MachOReader.m */, 153 | 05DB021319D7B0AE00DBC8DE /* MachOSection.h */, 154 | 05DB021419D7B0AE00DBC8DE /* MachOSection.m */, 155 | 057D3C1F19D6410E0093AC60 /* MachOSegment.h */, 156 | 057D3C2019D6410E0093AC60 /* MachOSegment.m */, 157 | 057D3C1919D61F080093AC60 /* ThinMachObject.h */, 158 | 057D3C1A19D61F080093AC60 /* ThinMachObject.mm */, 159 | ); 160 | name = " Mach Reader"; 161 | sourceTree = ""; 162 | }; 163 | 05E4A79E19D0D7D700F6842A /* 3rdParty */ = { 164 | isa = PBXGroup; 165 | children = ( 166 | 05D2220A19D7A511003DBD53 /* libelf.a */, 167 | 05D2220319D79D68003DBD53 /* libdwarf.h */, 168 | 05D2220119D79C39003DBD53 /* libdwarf.a */, 169 | ); 170 | name = " 3rdParty"; 171 | sourceTree = ""; 172 | }; 173 | /* End PBXGroup section */ 174 | 175 | /* Begin PBXNativeTarget section */ 176 | 0552721619CCAE4C004D643F /* Symbolicator */ = { 177 | isa = PBXNativeTarget; 178 | buildConfigurationList = 0552723419CCAE4C004D643F /* Build configuration list for PBXNativeTarget "Symbolicator" */; 179 | buildPhases = ( 180 | 0552721319CCAE4C004D643F /* Sources */, 181 | 0552721419CCAE4C004D643F /* Frameworks */, 182 | 0552721519CCAE4C004D643F /* Resources */, 183 | ); 184 | buildRules = ( 185 | ); 186 | dependencies = ( 187 | ); 188 | name = Symbolicator; 189 | productName = Symbolicator; 190 | productReference = 0552721719CCAE4C004D643F /* Symbolicator.app */; 191 | productType = "com.apple.product-type.application"; 192 | }; 193 | /* End PBXNativeTarget section */ 194 | 195 | /* Begin PBXProject section */ 196 | 0552720F19CCAE4C004D643F /* Project object */ = { 197 | isa = PBXProject; 198 | attributes = { 199 | LastUpgradeCheck = 0600; 200 | ORGANIZATIONNAME = "Spectrum Data Technologies"; 201 | TargetAttributes = { 202 | 0552721619CCAE4C004D643F = { 203 | CreatedOnToolsVersion = 6.0.1; 204 | SystemCapabilities = { 205 | com.apple.Sandbox = { 206 | enabled = 0; 207 | }; 208 | }; 209 | }; 210 | }; 211 | }; 212 | buildConfigurationList = 0552721219CCAE4C004D643F /* Build configuration list for PBXProject "Symbolicator" */; 213 | compatibilityVersion = "Xcode 3.2"; 214 | developmentRegion = English; 215 | hasScannedForEncodings = 0; 216 | knownRegions = ( 217 | en, 218 | Base, 219 | ); 220 | mainGroup = 0552720E19CCAE4C004D643F; 221 | productRefGroup = 0552721819CCAE4C004D643F /* Products */; 222 | projectDirPath = ""; 223 | projectRoot = ""; 224 | targets = ( 225 | 0552721619CCAE4C004D643F /* Symbolicator */, 226 | ); 227 | }; 228 | /* End PBXProject section */ 229 | 230 | /* Begin PBXResourcesBuildPhase section */ 231 | 0552721519CCAE4C004D643F /* Resources */ = { 232 | isa = PBXResourcesBuildPhase; 233 | buildActionMask = 2147483647; 234 | files = ( 235 | 0552722219CCAE4C004D643F /* Images.xcassets in Resources */, 236 | 0552722519CCAE4C004D643F /* MainMenu.xib in Resources */, 237 | ); 238 | runOnlyForDeploymentPostprocessing = 0; 239 | }; 240 | /* End PBXResourcesBuildPhase section */ 241 | 242 | /* Begin PBXSourcesBuildPhase section */ 243 | 0552721319CCAE4C004D643F /* Sources */ = { 244 | isa = PBXSourcesBuildPhase; 245 | buildActionMask = 2147483647; 246 | files = ( 247 | 0552722019CCAE4C004D643F /* AppDelegate.m in Sources */, 248 | 05DB021519D7B0AE00DBC8DE /* MachOSection.m in Sources */, 249 | 057D3C1B19D61F080093AC60 /* ThinMachObject.mm in Sources */, 250 | 0552727819CCB0BB004D643F /* StackFrameLine.m in Sources */, 251 | 057D3C2119D6410E0093AC60 /* MachOSegment.m in Sources */, 252 | 05E4A76019D07B4800F6842A /* BinaryImageLine.m in Sources */, 253 | 05DB021219D7AA1800DBC8DE /* workaround.c in Sources */, 254 | 057F6A6D19D5F01900336891 /* MachOReader.m in Sources */, 255 | 0552721D19CCAE4C004D643F /* main.m in Sources */, 256 | 057D3C2419D651D90093AC60 /* MachONList.m in Sources */, 257 | 05E594A119CE064800ACB1F1 /* ExceptionTraceLine.m in Sources */, 258 | 05E4A76319D089C000F6842A /* SectionLine.m in Sources */, 259 | 05B5320419D1C60600697884 /* SymbolicationTasksBlackboard.m in Sources */, 260 | 0552727519CCB021004D643F /* CrashReportParser.m in Sources */, 261 | 05E594A419CE0B9000ACB1F1 /* InformationalLine.m in Sources */, 262 | 05D2220719D7A0B1003DBD53 /* DwarfReader.m in Sources */, 263 | ); 264 | runOnlyForDeploymentPostprocessing = 0; 265 | }; 266 | /* End PBXSourcesBuildPhase section */ 267 | 268 | /* Begin PBXVariantGroup section */ 269 | 0552722319CCAE4C004D643F /* MainMenu.xib */ = { 270 | isa = PBXVariantGroup; 271 | children = ( 272 | 0552722419CCAE4C004D643F /* Base */, 273 | ); 274 | name = MainMenu.xib; 275 | sourceTree = ""; 276 | }; 277 | /* End PBXVariantGroup section */ 278 | 279 | /* Begin XCBuildConfiguration section */ 280 | 0552723219CCAE4C004D643F /* Debug */ = { 281 | isa = XCBuildConfiguration; 282 | buildSettings = { 283 | ALWAYS_SEARCH_USER_PATHS = NO; 284 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 285 | CLANG_CXX_LIBRARY = "libc++"; 286 | CLANG_ENABLE_MODULES = YES; 287 | CLANG_ENABLE_OBJC_ARC = YES; 288 | CLANG_WARN_BOOL_CONVERSION = YES; 289 | CLANG_WARN_CONSTANT_CONVERSION = YES; 290 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 291 | CLANG_WARN_EMPTY_BODY = YES; 292 | CLANG_WARN_ENUM_CONVERSION = YES; 293 | CLANG_WARN_INT_CONVERSION = YES; 294 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 295 | CLANG_WARN_UNREACHABLE_CODE = YES; 296 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 297 | CODE_SIGN_IDENTITY = "-"; 298 | COPY_PHASE_STRIP = NO; 299 | ENABLE_STRICT_OBJC_MSGSEND = YES; 300 | GCC_C_LANGUAGE_STANDARD = gnu99; 301 | GCC_DYNAMIC_NO_PIC = NO; 302 | GCC_OPTIMIZATION_LEVEL = 0; 303 | GCC_PREPROCESSOR_DEFINITIONS = ( 304 | "DEBUG=1", 305 | "$(inherited)", 306 | ); 307 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 308 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 309 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 310 | GCC_WARN_UNDECLARED_SELECTOR = YES; 311 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 312 | GCC_WARN_UNUSED_FUNCTION = YES; 313 | GCC_WARN_UNUSED_VARIABLE = YES; 314 | HEADER_SEARCH_PATHS = ( 315 | "$(inherited)", 316 | /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, 317 | "$(PROJECT_DIR)/3rdParty/atosl", 318 | ); 319 | MACOSX_DEPLOYMENT_TARGET = 10.10; 320 | MTL_ENABLE_DEBUG_INFO = YES; 321 | ONLY_ACTIVE_ARCH = YES; 322 | SDKROOT = macosx; 323 | }; 324 | name = Debug; 325 | }; 326 | 0552723319CCAE4C004D643F /* Release */ = { 327 | isa = XCBuildConfiguration; 328 | buildSettings = { 329 | ALWAYS_SEARCH_USER_PATHS = NO; 330 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 331 | CLANG_CXX_LIBRARY = "libc++"; 332 | CLANG_ENABLE_MODULES = YES; 333 | CLANG_ENABLE_OBJC_ARC = YES; 334 | CLANG_WARN_BOOL_CONVERSION = YES; 335 | CLANG_WARN_CONSTANT_CONVERSION = YES; 336 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 337 | CLANG_WARN_EMPTY_BODY = YES; 338 | CLANG_WARN_ENUM_CONVERSION = YES; 339 | CLANG_WARN_INT_CONVERSION = YES; 340 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 341 | CLANG_WARN_UNREACHABLE_CODE = YES; 342 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 343 | CODE_SIGN_IDENTITY = "-"; 344 | COPY_PHASE_STRIP = YES; 345 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 346 | ENABLE_NS_ASSERTIONS = NO; 347 | ENABLE_STRICT_OBJC_MSGSEND = YES; 348 | GCC_C_LANGUAGE_STANDARD = gnu99; 349 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 350 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 351 | GCC_WARN_UNDECLARED_SELECTOR = YES; 352 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 353 | GCC_WARN_UNUSED_FUNCTION = YES; 354 | GCC_WARN_UNUSED_VARIABLE = YES; 355 | HEADER_SEARCH_PATHS = ( 356 | "$(inherited)", 357 | /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, 358 | "$(PROJECT_DIR)/3rdParty/atosl", 359 | ); 360 | MACOSX_DEPLOYMENT_TARGET = 10.10; 361 | MTL_ENABLE_DEBUG_INFO = NO; 362 | SDKROOT = macosx; 363 | }; 364 | name = Release; 365 | }; 366 | 0552723519CCAE4C004D643F /* Debug */ = { 367 | isa = XCBuildConfiguration; 368 | buildSettings = { 369 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 370 | CODE_SIGN_ENTITLEMENTS = Symbolicator/Symbolicator.entitlements; 371 | COMBINE_HIDPI_IMAGES = YES; 372 | INFOPLIST_FILE = Symbolicator/Info.plist; 373 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; 374 | LIBRARY_SEARCH_PATHS = ( 375 | "$(inherited)", 376 | "$(PROJECT_DIR)/3rdParty", 377 | ); 378 | PRODUCT_NAME = "$(TARGET_NAME)"; 379 | }; 380 | name = Debug; 381 | }; 382 | 0552723619CCAE4C004D643F /* Release */ = { 383 | isa = XCBuildConfiguration; 384 | buildSettings = { 385 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 386 | CODE_SIGN_ENTITLEMENTS = Symbolicator/Symbolicator.entitlements; 387 | COMBINE_HIDPI_IMAGES = YES; 388 | INFOPLIST_FILE = Symbolicator/Info.plist; 389 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; 390 | LIBRARY_SEARCH_PATHS = ( 391 | "$(inherited)", 392 | "$(PROJECT_DIR)/3rdParty", 393 | ); 394 | PRODUCT_NAME = "$(TARGET_NAME)"; 395 | }; 396 | name = Release; 397 | }; 398 | /* End XCBuildConfiguration section */ 399 | 400 | /* Begin XCConfigurationList section */ 401 | 0552721219CCAE4C004D643F /* Build configuration list for PBXProject "Symbolicator" */ = { 402 | isa = XCConfigurationList; 403 | buildConfigurations = ( 404 | 0552723219CCAE4C004D643F /* Debug */, 405 | 0552723319CCAE4C004D643F /* Release */, 406 | ); 407 | defaultConfigurationIsVisible = 0; 408 | defaultConfigurationName = Release; 409 | }; 410 | 0552723419CCAE4C004D643F /* Build configuration list for PBXNativeTarget "Symbolicator" */ = { 411 | isa = XCConfigurationList; 412 | buildConfigurations = ( 413 | 0552723519CCAE4C004D643F /* Debug */, 414 | 0552723619CCAE4C004D643F /* Release */, 415 | ); 416 | defaultConfigurationIsVisible = 0; 417 | defaultConfigurationName = Release; 418 | }; 419 | /* End XCConfigurationList section */ 420 | }; 421 | rootObject = 0552720F19CCAE4C004D643F /* Project object */; 422 | } 423 | -------------------------------------------------------------------------------- /Symbolicator/AppDelegate.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface AppDelegate : NSObject 4 | @end 5 | 6 | -------------------------------------------------------------------------------- /Symbolicator/AppDelegate.m: -------------------------------------------------------------------------------- 1 | #import "AppDelegate.h" 2 | #import "CrashReportParser.h" 3 | #import "libdwarf.h" 4 | #import "MachOReader.h" 5 | 6 | @interface AppDelegate () 7 | @property (nonatomic, strong) CrashReportParser *hack; 8 | @property (weak) IBOutlet NSWindow *window; 9 | @end 10 | 11 | @implementation AppDelegate 12 | 13 | - (void)applicationDidFinishLaunching:(NSNotification *)aNotification { 14 | } 15 | 16 | - (void)applicationWillTerminate:(NSNotification *)aNotification { 17 | } 18 | 19 | - (BOOL)application:(NSApplication *)sender openFile:(NSString *)filename { 20 | CrashReportParser *parser = [CrashReportParser buildForFile:filename]; 21 | 22 | self.hack = parser; 23 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 24 | [parser parse]; 25 | //[parser write]; 26 | }); 27 | return parser != nil; 28 | } 29 | 30 | @end 31 | -------------------------------------------------------------------------------- /Symbolicator/Base.lproj/MainMenu.xib: -------------------------------------------------------------------------------- 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 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | 451 | 452 | 453 | 454 | 455 | 456 | 457 | 458 | 459 | 460 | 461 | 462 | 463 | 464 | 465 | 466 | 467 | 468 | 469 | 470 | 471 | 472 | 473 | 474 | 475 | 476 | 477 | 478 | 479 | 480 | 481 | 482 | 483 | 484 | 485 | 486 | 487 | 488 | 489 | 490 | 491 | 492 | 493 | 494 | 495 | 496 | 497 | 498 | 499 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 509 | 510 | 511 | 512 | 513 | 514 | 515 | 516 | 517 | 518 | 519 | 520 | 521 | 522 | 523 | 524 | 525 | 526 | 527 | 528 | 529 | 530 | 531 | 532 | 533 | 534 | 535 | Default 536 | 537 | 538 | 539 | 540 | 541 | 542 | Left to Right 543 | 544 | 545 | 546 | 547 | 548 | 549 | Right to Left 550 | 551 | 552 | 553 | 554 | 555 | 556 | 557 | 558 | 559 | 560 | Default 561 | 562 | 563 | 564 | 565 | 566 | 567 | Left to Right 568 | 569 | 570 | 571 | 572 | 573 | 574 | Right to Left 575 | 576 | 577 | 578 | 579 | 580 | 581 | 582 | 583 | 584 | 585 | 586 | 587 | 588 | 589 | 590 | 591 | 592 | 593 | 594 | 595 | 596 | 597 | 598 | 599 | 600 | 601 | 602 | 603 | 604 | 605 | 606 | 607 | 608 | 609 | 610 | 611 | 612 | 613 | 614 | 615 | 616 | 617 | 618 | 619 | 620 | 621 | 622 | 623 | 624 | 625 | 626 | 627 | 628 | 629 | 630 | 631 | 632 | 633 | 634 | 635 | 636 | 637 | 638 | 639 | 640 | 641 | 642 | 643 | 644 | 645 | 646 | 647 | 648 | 649 | 650 | 651 | 652 | 653 | 654 | 655 | 656 | 657 | 658 | 659 | 660 | 661 | 662 | 663 | 664 | 665 | 666 | 667 | 668 | -------------------------------------------------------------------------------- /Symbolicator/BinaryImageLine.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import "CrashReportLine.h" 3 | 4 | @interface BinaryImageLine : NSObject 5 | 6 | @property (nonatomic, assign) uint64_t loadAddress; 7 | @property (nonatomic, assign) uint64_t endAddress; 8 | @property (nonatomic, strong) NSString *name; 9 | @property (nonatomic, strong) NSString *arch; 10 | @property (nonatomic, strong) NSString *uuid; 11 | @property (nonatomic, strong) NSString *rawUuid; 12 | @property (nonatomic, strong) NSString *path; 13 | 14 | + (instancetype)buildWithLine:(NSString *)line; 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /Symbolicator/BinaryImageLine.m: -------------------------------------------------------------------------------- 1 | #import "BinaryImageLine.h" 2 | 3 | /* 4 | ^\s* (\w+) \s* \- \s* (\w+) \s* (?# the range base and extent [1,2] ) 5 | (\+)? (?# the application may have a + in front of the name [3] ) 6 | (.+) (?# bundle name [4] ) 7 | \s+ ('.$architectures.') \s+ (?# the image arch [5] ) 8 | \? (?# possible UUID [6] ) 9 | \s* (\/.*)\s*$ (?# first fwdslash to end we hope is path [7] ) 10 | */ 11 | 12 | #define REGEX @"^\\s*(0x[\\dabcdef]+)\\s*\\-\\s*(0x[\\dabcdef]+)\\s*\\+?(.+)\\s+(.+)\\s+\\<(.+)\\>\\s+(\\/.*)\\s*$" // \\s* \(\\+)? (.+) \\s 13 | 14 | @interface BinaryImageLine() 15 | @property (nonatomic, strong) NSString *line; 16 | @end 17 | 18 | @implementation BinaryImageLine 19 | 20 | #pragma mark - 21 | #pragma mark NSCopying 22 | 23 | - (id)copyWithZone:(NSZone *)zone { 24 | BinaryImageLine *rc = [[[self class] allocWithZone:zone] init]; 25 | 26 | rc.loadAddress = self.loadAddress; 27 | rc.endAddress = self.endAddress; 28 | rc.name = [self.name copy]; 29 | rc.arch = [self.arch copy]; 30 | rc.uuid = [self.uuid copy]; 31 | rc.rawUuid = [self.rawUuid copy]; 32 | rc.path = [self.path copy]; 33 | return rc; 34 | } 35 | 36 | - (NSUInteger)hash { 37 | return [self.uuid hash]; 38 | } 39 | 40 | - (BOOL)isEqual:(id)object { 41 | return [self.uuid isEqual:[object uuid]]; 42 | } 43 | 44 | #pragma mark - 45 | #pragma mark BinaryImageLine 46 | 47 | + (instancetype)buildWithLine:(NSString *)line { 48 | NSError *err = nil; 49 | NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:REGEX 50 | options:NSRegularExpressionCaseInsensitive 51 | error:&err]; 52 | __block NSMutableArray *parts = [NSMutableArray array]; 53 | 54 | [regex enumerateMatchesInString:line 55 | options:0 56 | range:NSMakeRange(0, line.length) 57 | usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) { 58 | for (int group = 1; group <= regex.numberOfCaptureGroups; group++) { 59 | NSRange r = [result rangeAtIndex:group]; 60 | 61 | [parts addObject:[line substringWithRange:r]]; 62 | } 63 | }]; 64 | 65 | if (parts.count == 6) { 66 | BinaryImageLine *rc = [[BinaryImageLine alloc] init]; 67 | 68 | rc.line = line; 69 | rc.loadAddress = strtoll([parts[0] UTF8String], NULL, 16); 70 | rc.endAddress = strtoll([parts[1] UTF8String], NULL, 16); 71 | rc.name = parts[2]; 72 | rc.arch = [parts[3] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]; 73 | rc.rawUuid = parts[4]; 74 | rc.uuid = [rc fixUUID:rc.rawUuid]; 75 | rc.path = parts[5]; 76 | return rc; 77 | } 78 | 79 | return nil; 80 | 81 | } 82 | 83 | - (NSString *)symbolicate { 84 | return self.line; 85 | } 86 | 87 | #pragma mark - 88 | #pragma mark BinaryImageLine Private Methods 89 | 90 | - (NSString *)fixUUID:(NSString *)uuid { 91 | if (uuid.length == 32) { 92 | NSMutableString *rc = [[NSMutableString alloc] init]; 93 | 94 | uuid = [uuid uppercaseString]; 95 | [rc appendString:[uuid substringWithRange:NSMakeRange(0, 8)]]; 96 | [rc appendString:@"-"]; 97 | [rc appendString:[uuid substringWithRange:NSMakeRange(8, 4)]]; 98 | [rc appendString:@"-"]; 99 | [rc appendString:[uuid substringWithRange:NSMakeRange(12, 4)]]; 100 | [rc appendString:@"-"]; 101 | [rc appendString:[uuid substringWithRange:NSMakeRange(16, 4)]]; 102 | [rc appendString:@"-"]; 103 | [rc appendString:[uuid substringWithRange:NSMakeRange(20, 12)]]; 104 | return rc; 105 | } else if (uuid.length == 36) { 106 | return [uuid uppercaseString]; 107 | } 108 | 109 | return nil; 110 | } 111 | 112 | @end 113 | -------------------------------------------------------------------------------- /Symbolicator/CrashReportLine.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @protocol CrashReportLine 4 | 5 | - (NSString *)symbolicate; 6 | 7 | @end 8 | -------------------------------------------------------------------------------- /Symbolicator/CrashReportParser.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface CrashReportParser : NSObject 4 | 5 | + (instancetype)buildForFile:(NSString *)file; 6 | 7 | - (void)parse; 8 | - (void)write; 9 | 10 | @end 11 | -------------------------------------------------------------------------------- /Symbolicator/CrashReportParser.m: -------------------------------------------------------------------------------- 1 | #import "CrashReportParser.h" 2 | #import "BinaryImageLine.h" 3 | #import "ExceptionTraceLine.h" 4 | #import "InformationalLine.h" 5 | #import "SectionLine.h" 6 | #import "StackFrameLine.h" 7 | #import "SymbolicationTasksBlackboard.h" 8 | 9 | @interface CrashReportParser() 10 | @property (nonatomic, strong) NSString *outFile; 11 | @property (nonatomic, strong) NSArray *lines; 12 | @property (nonatomic, strong) NSMutableArray *parsedLines; 13 | @property (nonatomic, strong) NSMutableArray *queries; 14 | @property (nonatomic, strong) NSMutableArray *binaryImageLines; 15 | @property (nonatomic, strong) NSMutableArray *paths; 16 | @property (nonatomic, strong) NSOperationQueue *opQ; 17 | @property (nonatomic, strong) SymbolicationTasksBlackboard *bb; 18 | @property (nonatomic, strong) id observerHandle; 19 | @end 20 | 21 | @implementation CrashReportParser 22 | 23 | #pragma mark - 24 | #pragma mark NSObject 25 | 26 | - (void)dealloc { 27 | if (self.observerHandle) 28 | [[NSNotificationCenter defaultCenter] removeObserver:self.observerHandle]; 29 | } 30 | 31 | #pragma mark - 32 | #pragma mark CrashReportParser 33 | 34 | + (instancetype)buildForFile:(NSString *)file { 35 | CrashReportParser *rc = [[self alloc] init]; 36 | NSString *str = [NSString stringWithContentsOfFile:file encoding:NSUTF8StringEncoding error:nil]; 37 | 38 | rc.bb = [SymbolicationTasksBlackboard build]; 39 | rc.parsedLines = [NSMutableArray array]; 40 | rc.binaryImageLines = [NSMutableArray array]; 41 | rc.queries = [NSMutableArray array]; 42 | rc.paths = [NSMutableArray array]; 43 | rc.lines = [str componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]]; 44 | rc.outFile = [file stringByAppendingPathExtension:@"symbolicated"]; 45 | rc.opQ = [[NSOperationQueue alloc] init]; 46 | rc.observerHandle = [[NSNotificationCenter defaultCenter] addObserverForName:NSMetadataQueryDidFinishGatheringNotification 47 | object:nil 48 | queue:nil 49 | usingBlock:^(NSNotification *note) { 50 | @synchronized(rc) { 51 | NSMetadataQuery *query = (NSMetadataQuery *)note.object; 52 | 53 | if ([rc.queries containsObject:query]) { 54 | [query enumerateResultsUsingBlock:^(id result, NSUInteger idx, BOOL *stop) { 55 | NSMetadataItem *item = result; 56 | NSString *path = [item valueForKey:NSMetadataItemPathKey]; 57 | NSArray *dSyms = [item valueForKey:@"com_apple_xcode_dsym_paths"]; 58 | 59 | if (dSyms.count > 0) { 60 | for (NSString *sym in dSyms) 61 | [rc.paths addObject:[path stringByAppendingPathComponent:sym]]; 62 | } 63 | }]; 64 | 65 | [query stopQuery]; 66 | [rc.queries removeObject:query]; 67 | 68 | if (rc.queries.count == 0) { 69 | [rc.bb symbolicateWithPaths:rc.paths binaryInfo:rc.binaryImageLines]; 70 | [rc write]; 71 | } 72 | } 73 | } 74 | }]; 75 | return rc; 76 | } 77 | 78 | - (void)parse { 79 | [self readLines]; 80 | } 81 | 82 | - (void)write { 83 | NSMutableString *symbolicated = [[NSMutableString alloc] init]; 84 | 85 | [self.parsedLines enumerateObjectsUsingBlock:^(id line, NSUInteger idx, BOOL *stop) { 86 | [symbolicated appendString:[line symbolicate]]; 87 | [symbolicated appendString:@"\n"]; 88 | }]; 89 | 90 | [symbolicated writeToFile:self.outFile atomically:YES encoding:NSUTF8StringEncoding error:nil]; 91 | } 92 | 93 | #pragma mark - 94 | #pragma mark CrashReportParser Private Methods 95 | 96 | - (void)readLines { 97 | __block SectionLine *currentSection; 98 | 99 | [self.lines enumerateObjectsUsingBlock:^(NSString *line, NSUInteger idx, BOOL *stop) { 100 | NSInteger count = self.parsedLines.count; 101 | 102 | if ([currentSection.sectionName hasPrefix:@"Last Exception Backtrace"]) { 103 | ExceptionTraceLine *etl = [ExceptionTraceLine buildWithLine:line andBlackboard:self.bb]; 104 | StackFrameLine *stl = [StackFrameLine buildWithLine:line andBlackboard:self.bb]; 105 | 106 | if (stl) { 107 | [self.parsedLines addObject:stl]; 108 | } else { 109 | if (etl) 110 | [self.parsedLines addObject:etl]; 111 | else 112 | NSLog(@"Expected exception backtrace at line: %lu", idx); 113 | 114 | currentSection = nil; 115 | } 116 | } else if ([currentSection.sectionName hasPrefix:@"Binary Images"]) { 117 | BinaryImageLine *bil = [BinaryImageLine buildWithLine:line]; 118 | 119 | if (bil) { 120 | [self.parsedLines addObject:bil]; 121 | [self.binaryImageLines addObject:bil]; 122 | dispatch_async(dispatch_get_main_queue(), ^{ 123 | NSPredicate *pred = [NSPredicate predicateWithFormat:@"com_apple_xcode_dsym_uuids LIKE %@", bil.uuid]; 124 | NSMetadataQuery *query = [[NSMetadataQuery alloc] init]; 125 | 126 | [self.queries addObject:query]; 127 | [query setOperationQueue:self.opQ]; 128 | [query setPredicate:pred]; 129 | [query startQuery]; 130 | }); 131 | } else { 132 | NSLog(@"Expected binary image description at line: %lu", idx); 133 | } 134 | } else if ([currentSection.sectionName hasPrefix:@"Thread"]) { 135 | StackFrameLine *stl = [StackFrameLine buildWithLine:line andBlackboard:self.bb]; 136 | 137 | if (stl) 138 | [self.parsedLines addObject:stl]; 139 | else if (line.length == 0) 140 | currentSection = nil; 141 | else 142 | NSLog(@"Expected stack frame at line: %lu", idx); 143 | } else { 144 | currentSection = [SectionLine buildWithLine:line]; 145 | 146 | if (currentSection) 147 | [self.parsedLines addObject:currentSection]; 148 | } 149 | 150 | if (self.parsedLines.count == count) 151 | [self.parsedLines addObject:[InformationalLine buildWithLine:line]]; 152 | }]; 153 | } 154 | 155 | @end 156 | -------------------------------------------------------------------------------- /Symbolicator/DwarfReader.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface DwarfReader : NSObject 4 | 5 | + (DwarfReader *)buildWithSections:(NSArray *)sections forPath:(NSString *)path; 6 | 7 | - (NSDictionary *)symbolicate:(NSMutableDictionary *)addressToSymbol; 8 | 9 | @end 10 | -------------------------------------------------------------------------------- /Symbolicator/DwarfReader.m: -------------------------------------------------------------------------------- 1 | #import "DwarfReader.h" 2 | #import "libdwarf.h" 3 | #import "MachONList.h" 4 | #import "MachOSection.h" 5 | 6 | @interface DwarfReader() 7 | @property (nonatomic, strong) NSArray *sections; 8 | @property (nonatomic, strong) NSFileHandle *fH; 9 | @property (nonatomic, assign) Dwarf_Obj_Access_Interface dwarfInterface; 10 | @property (nonatomic, assign) Dwarf_Obj_Access_Methods dwarfMethods; 11 | @property (nonatomic, assign) Dwarf_Debug dbg; 12 | @end 13 | 14 | void dwarfPrintf(void *p, const char *l) { 15 | NSLog(@"%s", l); 16 | } 17 | 18 | void dwarfErrHandler(Dwarf_Error err, Dwarf_Ptr ptr) { 19 | NSLog(@"Dwarf Error: %s", dwarf_errmsg(err)); 20 | } 21 | 22 | Dwarf_Endianness dwarfGetByteOrder(void *obj) { 23 | return DW_OBJECT_LSB; 24 | } 25 | 26 | // XXX: Should this be 8 for 64-bit? 27 | Dwarf_Small dwarfGetLengthSize(void *obj) { 28 | return 4; 29 | } 30 | 31 | // XXX: Should this be 8 for 64-bit? 32 | Dwarf_Small dwarfGetPtrSize(void *obj) { 33 | return 4; 34 | } 35 | 36 | Dwarf_Unsigned dwarfGetSectionCount(void *obj) { 37 | DwarfReader *reader = (__bridge DwarfReader *)obj; 38 | 39 | return reader.sections.count; 40 | } 41 | 42 | int dwarfGetSectionInfo(void* obj, Dwarf_Half section_index, Dwarf_Obj_Access_Section* return_section, int* error) { 43 | DwarfReader *reader = (__bridge DwarfReader *)obj; 44 | MachOSection *section; 45 | 46 | if (section_index >= reader.sections.count) { 47 | *error = DW_DLE_IA; 48 | return DW_DLV_ERROR; 49 | } 50 | 51 | section = reader.sections[section_index]; 52 | return_section -> addr = section.addr; 53 | return_section -> size = section.size; 54 | ((char *)section.name.mutableBytes)[1] = '.'; 55 | return_section -> name = (char *)section.name.bytes + 1; 56 | return_section -> link = 0; 57 | return_section -> entrysize = 0; 58 | return DW_DLV_OK; 59 | } 60 | 61 | int dwarfLoadSection(void* obj, Dwarf_Half section_index, Dwarf_Small** return_data, int* error) { 62 | DwarfReader *reader = (__bridge DwarfReader *)obj; 63 | MachOSection *section; 64 | NSData *data; 65 | 66 | if (section_index >= reader.sections.count) { 67 | *error = DW_DLE_IA; 68 | return DW_DLV_ERROR; 69 | } 70 | 71 | section = reader.sections[section_index]; 72 | [reader.fH seekToFileOffset:section.offset]; 73 | 74 | *return_data = malloc(section.size); 75 | 76 | if (!*return_data) { 77 | *error = DW_DLE_MAF; 78 | return DW_DLV_ERROR; 79 | } 80 | 81 | data = [reader.fH readDataOfLength:section.size]; 82 | memcpy(*return_data, data.bytes, section.size); 83 | return DW_DLV_OK; 84 | } 85 | 86 | int dwarfRelocateASection(void* obj, Dwarf_Half section_index, Dwarf_Debug dbg, int* error) { 87 | *error = DW_DLE_IA; 88 | return DW_DLV_ERROR; 89 | } 90 | 91 | @implementation DwarfReader 92 | 93 | + (DwarfReader *)buildWithSections:(NSArray *)sections forPath:(NSString *)path { 94 | DwarfReader *rc = [[DwarfReader alloc] init]; 95 | 96 | rc.sections = sections; 97 | rc.fH = [NSFileHandle fileHandleForReadingAtPath:path]; 98 | 99 | [rc configureMethods]; 100 | if ([rc load]) 101 | return rc; 102 | 103 | return nil; 104 | } 105 | 106 | - (NSDictionary *)symbolicate:(NSMutableDictionary *)addressToSymbol { 107 | Dwarf_Arange *addressRangesBuffer = 0; 108 | Dwarf_Signed totalRanges = 0; 109 | Dwarf_Error err; 110 | NSMutableDictionary *rc = [NSMutableDictionary dictionary]; 111 | 112 | if (dwarf_get_aranges(self.dbg, &addressRangesBuffer, &totalRanges, &err) != DW_DLV_OK) { 113 | NSLog(@"Error reading aranges: %s", dwarf_errmsg(err)); 114 | return nil; 115 | } 116 | 117 | [addressToSymbol enumerateKeysAndObjectsUsingBlock:^(NSNumber *a, MachONList *symbol, BOOL *stop) { 118 | Dwarf_Error err; 119 | NSInteger addr = [a integerValue] + symbol.segment.vmaddr; 120 | Dwarf_Arange arange; 121 | 122 | if (dwarf_get_arange(addressRangesBuffer, totalRanges, addr, &arange, &err) == DW_DLV_OK) { 123 | Dwarf_Unsigned segment; 124 | Dwarf_Unsigned segmentEntrySize; 125 | Dwarf_Addr start; 126 | Dwarf_Unsigned length; 127 | Dwarf_Off cuDieOffset; 128 | 129 | if (dwarf_get_arange_info_b(arange, &segment, &segmentEntrySize, &start, &length, &cuDieOffset, &err) == DW_DLV_OK) { 130 | Dwarf_Die cuDie; 131 | 132 | if (dwarf_offdie(self.dbg, cuDieOffset, &cuDie, &err) == DW_DLV_OK) { 133 | Dwarf_Line *lineBuffer; 134 | Dwarf_Signed totalLines; 135 | 136 | if (dwarf_srclines(cuDie, &lineBuffer, &totalLines, &err) == DW_DLV_OK) { 137 | NSString *symbol = [self symbolForAddress:addr fromLines:lineBuffer count:totalLines]; 138 | 139 | if (symbol) 140 | rc[a] = symbol; 141 | 142 | dwarf_srclines_dealloc(self.dbg, lineBuffer, totalLines); 143 | } else { 144 | NSLog(@"dwarf_srclines failed: %s", dwarf_errmsg(err)); 145 | } 146 | } else { 147 | NSLog(@"dwarf_offdie failed: %s", dwarf_errmsg(err)); 148 | } 149 | } else { 150 | NSLog(@"Failed to get arange info for addr %@: %s", a, dwarf_errmsg(err)); 151 | } 152 | 153 | } else { 154 | NSLog(@"Failed to get arange for addr %@: %s", a, dwarf_errmsg(err)); 155 | } 156 | }]; 157 | 158 | dwarf_dealloc(self.dbg, addressRangesBuffer, DW_DLA_ARANGE); 159 | 160 | return rc; 161 | } 162 | 163 | #pragma mark - 164 | #pragma mark DwarfReader Private Methods 165 | 166 | - (void)configureMethods { 167 | _dwarfMethods.get_byte_order = dwarfGetByteOrder; 168 | _dwarfMethods.get_length_size = dwarfGetLengthSize; 169 | _dwarfMethods.get_pointer_size = dwarfGetPtrSize; 170 | _dwarfMethods.get_section_count = dwarfGetSectionCount; 171 | _dwarfMethods.get_section_info = dwarfGetSectionInfo; 172 | _dwarfMethods.load_section = dwarfLoadSection; 173 | _dwarfMethods.relocate_a_section = dwarfRelocateASection; 174 | _dwarfInterface.methods = &_dwarfMethods; 175 | _dwarfInterface.object = (__bridge void *)self; 176 | } 177 | 178 | - (BOOL)load { 179 | Dwarf_Error err = 0; 180 | int code; 181 | 182 | 183 | if ((code = dwarf_object_init(&_dwarfInterface, dwarfErrHandler, 0, &_dbg, &err)) != DW_DLV_OK) { 184 | NSLog(@"Init error: %s", dwarf_errmsg(err)); 185 | return NO; 186 | } 187 | 188 | struct Dwarf_Printf_Callback_Info_s i = { 0}; 189 | i.dp_fptr = dwarfPrintf; 190 | dwarf_register_printf_callback(self.dbg, &i); 191 | 192 | return YES; 193 | } 194 | 195 | - (NSString *)symbolForAddress:(NSInteger)addr fromLines:(Dwarf_Line *)lines count:(Dwarf_Signed)count { 196 | Dwarf_Error err; 197 | 198 | for (int i = 0; i < count; i++) { 199 | Dwarf_Addr lowAddr; 200 | Dwarf_Addr highAddr; 201 | 202 | if (i == 0) { 203 | dwarf_lineaddr(lines[i], &lowAddr, &err); 204 | } else { 205 | dwarf_lineaddr(lines[i - 1], &lowAddr, &err); 206 | //lowAddr++; 207 | } 208 | 209 | if (i == count - 1) { 210 | dwarf_lineaddr(lines[i], &highAddr, &err); 211 | } else { 212 | dwarf_lineaddr(lines[i + 1], &highAddr, &err); 213 | //highAddr--; 214 | } 215 | 216 | if (addr >= lowAddr && addr <= highAddr) { 217 | char *fileName; 218 | Dwarf_Unsigned lineNumber; 219 | NSString *rc; 220 | 221 | dwarf_linesrc(lines[i], &fileName, &err); 222 | dwarf_lineno(lines[i], &lineNumber, &err); 223 | rc = [NSString stringWithFormat:@"%@:%llu", [[NSString stringWithFormat:@"%s", fileName] lastPathComponent], lineNumber]; 224 | dwarf_dealloc(self.dbg, fileName, DW_DLA_STRING); 225 | return rc; 226 | } 227 | } 228 | 229 | return nil; 230 | } 231 | 232 | @end 233 | -------------------------------------------------------------------------------- /Symbolicator/ExceptionTraceLine.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import "CrashReportLine.h" 3 | #import "SymbolicationTasksBlackboard.h" 4 | 5 | @interface ExceptionTraceLine : NSObject 6 | 7 | + (instancetype)buildWithLine:(NSString *)line andBlackboard:(SymbolicationTasksBlackboard *)bb; 8 | 9 | @end 10 | -------------------------------------------------------------------------------- /Symbolicator/ExceptionTraceLine.m: -------------------------------------------------------------------------------- 1 | #import "ExceptionTraceLine.h" 2 | 3 | // XXX: Improve, enforce starting with '(' ending with ')' last backtrace having no space before final ')' 4 | #define REGEX @"(0x[\\dabcdef]+)" 5 | 6 | @interface ExceptionTraceLine() 7 | @property (nonatomic, strong) NSString *origLine; 8 | @property (nonatomic, strong) NSArray *backtrace; 9 | @property (nonatomic, weak) SymbolicationTasksBlackboard *bb; 10 | @end 11 | 12 | @implementation ExceptionTraceLine 13 | 14 | + (instancetype)buildWithLine:(NSString *)line andBlackboard:(SymbolicationTasksBlackboard *)bb { 15 | NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:REGEX 16 | options:NSRegularExpressionCaseInsensitive 17 | error:nil]; 18 | 19 | if (line.length > 0 && [line characterAtIndex:0] == '(' && [line characterAtIndex:line.length - 1] == ')') { 20 | __block NSMutableArray *parts = [NSMutableArray array]; 21 | 22 | [regex enumerateMatchesInString:line 23 | options:0 24 | range:NSMakeRange(0, line.length) 25 | usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) { 26 | for (int group = 1; group <= regex.numberOfCaptureGroups; group++) { 27 | NSRange r = [result rangeAtIndex:group]; 28 | 29 | [parts addObject:[line substringWithRange:r]]; 30 | } 31 | }]; 32 | 33 | if (parts.count > 0) { 34 | ExceptionTraceLine *rc = [[ExceptionTraceLine alloc] init]; 35 | 36 | [parts enumerateObjectsUsingBlock:^(NSString *hexAddr, NSUInteger idx, BOOL *stop) { 37 | uint64_t addr = strtoll([hexAddr UTF8String], NULL, 16); 38 | 39 | [bb addAddress:addr]; 40 | }]; 41 | 42 | rc.origLine = line; 43 | rc.backtrace = parts; 44 | rc.bb = bb; 45 | return rc; 46 | } 47 | } 48 | 49 | return nil; 50 | } 51 | 52 | - (NSString *)symbolicate { 53 | BOOL isSymbolicated = NO; 54 | NSMutableString *result = [[NSMutableString alloc] init]; 55 | 56 | for (NSString *addrStr in self.backtrace) { 57 | uint64_t addr = strtoll([addrStr UTF8String], NULL, 16); 58 | NSString *symbolicated = [self.bb symbolicatedAddress:addr]; 59 | 60 | if (symbolicated != (id)[NSNull null]) { 61 | [result appendString:symbolicated]; 62 | [result appendString:@"\n"]; 63 | isSymbolicated = YES; 64 | } else { 65 | [result appendString:addrStr]; 66 | [result appendString:@"\n"]; 67 | } 68 | } 69 | 70 | if (!isSymbolicated) 71 | return self.origLine; 72 | 73 | return result; 74 | } 75 | 76 | @end 77 | -------------------------------------------------------------------------------- /Symbolicator/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "size" : "16x16", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "mac", 10 | "size" : "16x16", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "mac", 15 | "size" : "32x32", 16 | "scale" : "1x" 17 | }, 18 | { 19 | "idiom" : "mac", 20 | "size" : "32x32", 21 | "scale" : "2x" 22 | }, 23 | { 24 | "idiom" : "mac", 25 | "size" : "128x128", 26 | "scale" : "1x" 27 | }, 28 | { 29 | "idiom" : "mac", 30 | "size" : "128x128", 31 | "scale" : "2x" 32 | }, 33 | { 34 | "idiom" : "mac", 35 | "size" : "256x256", 36 | "scale" : "1x" 37 | }, 38 | { 39 | "idiom" : "mac", 40 | "size" : "256x256", 41 | "scale" : "2x" 42 | }, 43 | { 44 | "idiom" : "mac", 45 | "size" : "512x512", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "mac", 50 | "size" : "512x512", 51 | "scale" : "2x" 52 | } 53 | ], 54 | "info" : { 55 | "version" : 1, 56 | "author" : "xcode" 57 | } 58 | } -------------------------------------------------------------------------------- /Symbolicator/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDocumentTypes 8 | 9 | 10 | CFBundleTypeExtensions 11 | 12 | crash 13 | 14 | CFBundleTypeName 15 | Crash Report 16 | CFBundleTypeRole 17 | Editor 18 | LSTypeIsPackage 19 | 0 20 | 21 | 22 | CFBundleExecutable 23 | $(EXECUTABLE_NAME) 24 | CFBundleIconFile 25 | 26 | CFBundleIdentifier 27 | com.spectrumdt.$(PRODUCT_NAME:rfc1034identifier) 28 | CFBundleInfoDictionaryVersion 29 | 6.0 30 | CFBundleName 31 | $(PRODUCT_NAME) 32 | CFBundlePackageType 33 | APPL 34 | CFBundleShortVersionString 35 | 1.0 36 | CFBundleSignature 37 | ???? 38 | CFBundleVersion 39 | 1 40 | LSMinimumSystemVersion 41 | $(MACOSX_DEPLOYMENT_TARGET) 42 | NSHumanReadableCopyright 43 | Copyright © 2014 Spectrum Data Technologies. All rights reserved. 44 | NSMainNibFile 45 | MainMenu 46 | NSPrincipalClass 47 | NSApplication 48 | 49 | 50 | -------------------------------------------------------------------------------- /Symbolicator/InformationalLine.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import "CrashReportLine.h" 3 | 4 | @interface InformationalLine : NSObject 5 | 6 | + (instancetype)buildWithLine:(NSString *)line; 7 | 8 | @end 9 | -------------------------------------------------------------------------------- /Symbolicator/InformationalLine.m: -------------------------------------------------------------------------------- 1 | #import "InformationalLine.h" 2 | 3 | @interface InformationalLine() 4 | @property (nonatomic, strong) NSString *line; 5 | @end 6 | 7 | @implementation InformationalLine 8 | 9 | + (instancetype)buildWithLine:(NSString *)line { 10 | InformationalLine *rc = [[self alloc] init]; 11 | 12 | rc.line = line; 13 | return rc; 14 | } 15 | 16 | - (NSString *)symbolicate { 17 | return self.line; 18 | } 19 | 20 | @end 21 | -------------------------------------------------------------------------------- /Symbolicator/MachONList.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import "MachOSegment.h" 3 | 4 | @interface MachONList : NSObject 5 | 6 | @property (nonatomic, assign) NSInteger idx; 7 | @property (nonatomic, assign) NSInteger section; 8 | @property (nonatomic, assign) NSInteger value; 9 | @property (nonatomic, strong) NSString *symbol; 10 | 11 | // Useful property 12 | @property (nonatomic, strong) MachOSegment *segment; 13 | 14 | @end 15 | -------------------------------------------------------------------------------- /Symbolicator/MachONList.m: -------------------------------------------------------------------------------- 1 | #import "MachONList.h" 2 | 3 | @implementation MachONList 4 | @end 5 | -------------------------------------------------------------------------------- /Symbolicator/MachOReader.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | #import "ThinMachObject.h" 4 | 5 | @interface MachOReader : NSObject 6 | 7 | @property (nonatomic, readonly) NSInteger totalArchitectures; 8 | @property (nonatomic, readonly) NSArray *allThinObjects; 9 | 10 | + (instancetype)buildWithFile:(NSString *)file; 11 | 12 | - (BOOL)hasArch:(NSString *)arch; 13 | - (ThinMachObject *)objectForArch:(NSString *)arch; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /Symbolicator/MachOReader.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | #import "MachOReader.h" 4 | #import "ThinMachObject.h" 5 | 6 | @interface MachOReader() 7 | @property (nonatomic, strong) NSString *path; 8 | @property (nonatomic, strong) NSFileHandle *fH; 9 | @property (nonatomic, strong) NSMutableDictionary *thinMachObjects; 10 | @end 11 | 12 | @implementation MachOReader 13 | 14 | + (instancetype)buildWithFile:(NSString *)file { 15 | MachOReader *rc = [[self alloc] init]; 16 | 17 | rc.path = file; 18 | rc.thinMachObjects = [NSMutableDictionary dictionary]; 19 | rc.fH = [NSFileHandle fileHandleForReadingAtPath:file]; 20 | [rc readInitialHeaders]; 21 | return rc; 22 | } 23 | 24 | - (NSInteger)totalArchitectures { 25 | return self.thinMachObjects.count; 26 | } 27 | 28 | - (NSArray *)allThinObjects { 29 | return [self.thinMachObjects allValues]; 30 | } 31 | 32 | - (BOOL)hasArch:(NSString *)arch { 33 | return self.thinMachObjects[arch] != nil; 34 | } 35 | 36 | - (ThinMachObject *)objectForArch:(NSString *)arch { 37 | return self.thinMachObjects[arch]; 38 | } 39 | 40 | #pragma mark - 41 | #pragma mark MachOReader Private Methods 42 | 43 | - (void)readInitialHeaders { 44 | uint32_t magic = 0; 45 | NSData *d = [self.fH readDataOfLength:sizeof(magic)]; 46 | 47 | magic = *((uint32_t *)d.bytes); 48 | [self.fH seekToFileOffset:0]; 49 | 50 | if (magic == FAT_CIGAM) { 51 | [self readFatHeaders]; 52 | } else { 53 | ThinMachObject *o = nil; 54 | NSInteger size; 55 | 56 | [self.fH seekToEndOfFile]; 57 | size = self.fH.offsetInFile; 58 | [self.fH seekToFileOffset:0]; 59 | o = [ThinMachObject buildWithHandle:self.fH size:size forPath:self.path]; 60 | 61 | if (o) 62 | self.thinMachObjects[o.arch] = o; 63 | } 64 | } 65 | 66 | - (void)readFatHeaders { 67 | struct fat_header header = { 0 }; 68 | struct fat_arch *archs = 0; 69 | NSInteger archBytes; 70 | NSData *d = [self.fH readDataOfLength:sizeof(header)]; 71 | 72 | header = *((struct fat_header *)d.bytes); 73 | header.nfat_arch = CFSwapInt32BigToHost(header.nfat_arch); 74 | 75 | archBytes = sizeof(struct fat_arch) * header.nfat_arch; 76 | d = [self.fH readDataOfLength:archBytes]; 77 | archs = (struct fat_arch *)d.bytes; 78 | 79 | for (int i = 0; i < header.nfat_arch; i++) { 80 | NSInteger offset = CFSwapInt32BigToHost(archs[i].offset); 81 | ThinMachObject *o = nil; 82 | 83 | [self.fH seekToFileOffset:offset]; 84 | o = [ThinMachObject buildWithHandle:self.fH size:CFSwapInt32BigToHost(archs[i].size) forPath:(NSString *)self.path]; 85 | 86 | if (o) 87 | self.thinMachObjects[o.arch] = o; 88 | } 89 | } 90 | 91 | @end 92 | -------------------------------------------------------------------------------- /Symbolicator/MachOSection.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface MachOSection : NSObject 4 | 5 | @property (nonatomic, strong) NSMutableData *name; 6 | @property (nonatomic, assign) NSInteger addr; 7 | @property (nonatomic, assign) NSInteger size; 8 | @property (nonatomic, assign) NSInteger offset; 9 | @property (nonatomic, assign) NSInteger align; 10 | @property (nonatomic, assign) NSInteger reloff; 11 | @property (nonatomic, assign) NSInteger flags; 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /Symbolicator/MachOSection.m: -------------------------------------------------------------------------------- 1 | // 2 | // MachOSection.m 3 | // Symbolicator 4 | // 5 | // Created by Tim Murison on 2014-09-27. 6 | // Copyright (c) 2014 Spectrum Data Technologies. All rights reserved. 7 | // 8 | 9 | #import "MachOSection.h" 10 | 11 | @implementation MachOSection 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /Symbolicator/MachOSegment.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface MachOSegment : NSObject 4 | 5 | @property (nonatomic, strong) NSString *name; 6 | @property (nonatomic, assign) NSInteger cmd; 7 | @property (nonatomic, assign) NSInteger cmdSize; 8 | @property (nonatomic, assign) NSInteger vmaddr; 9 | @property (nonatomic, assign) NSInteger vmsize; 10 | @property (nonatomic, assign) NSInteger fileoff; 11 | @property (nonatomic, assign) NSInteger filesize; 12 | @property (nonatomic, assign) NSInteger nsects; 13 | @property (nonatomic, assign) NSInteger flags; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /Symbolicator/MachOSegment.m: -------------------------------------------------------------------------------- 1 | #import "MachOSegment.h" 2 | 3 | @implementation MachOSegment 4 | @end 5 | -------------------------------------------------------------------------------- /Symbolicator/SectionLine.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import "CrashReportLine.h" 3 | 4 | @interface SectionLine : NSObject 5 | 6 | @property (nonatomic, strong) NSString *sectionName; 7 | @property (nonatomic, strong) NSString *sectionValue; 8 | 9 | + (instancetype)buildWithLine:(NSString *)line; 10 | 11 | @end 12 | -------------------------------------------------------------------------------- /Symbolicator/SectionLine.m: -------------------------------------------------------------------------------- 1 | #import "SectionLine.h" 2 | 3 | #define REGEX @"^(.+):(?\\s*(.+))$" 4 | 5 | @interface SectionLine() 6 | @property (nonatomic, strong) NSString *line; 7 | @end 8 | 9 | @implementation SectionLine 10 | 11 | + (instancetype)buildWithLine:(NSString *)line { 12 | NSRange range = [line rangeOfString:@":"]; 13 | 14 | if (range.location != NSNotFound) { 15 | SectionLine *rc = [[SectionLine alloc] init]; 16 | 17 | rc.line = line; 18 | rc.sectionName = [line substringToIndex:range.location]; 19 | 20 | if (range.location + 1 < line.length) 21 | rc.sectionValue = [line substringFromIndex:range.location + 1]; 22 | 23 | return rc; 24 | } 25 | 26 | return nil; 27 | } 28 | 29 | - (NSString *)symbolicate { 30 | return self.line; 31 | } 32 | 33 | @end 34 | -------------------------------------------------------------------------------- /Symbolicator/StackFrameLine.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import "CrashReportLine.h" 3 | #import "SymbolicationTasksBlackboard.h" 4 | 5 | @interface StackFrameLine : NSObject 6 | 7 | + (instancetype)buildWithLine:(NSString *)line andBlackboard:(SymbolicationTasksBlackboard *)bb; 8 | 9 | @end 10 | -------------------------------------------------------------------------------- /Symbolicator/StackFrameLine.m: -------------------------------------------------------------------------------- 1 | #import "StackFrameLine.h" 2 | 3 | #define REGEX @"^([\\d]+)\\s*([\\S+]+)\\s+(0x[\\dabcdef]+)\\s+(.*)$" 4 | 5 | @interface StackFrameLine() 6 | @property (nonatomic, strong) NSString *origLine; 7 | @property (nonatomic, assign) NSInteger frameNumber; 8 | @property (nonatomic, strong) NSString *binaryName; 9 | @property (nonatomic, assign) uint64_t address; 10 | @property (nonatomic, strong) NSString *symbolName; 11 | @property (nonatomic, weak) SymbolicationTasksBlackboard *bb; 12 | @end 13 | 14 | @implementation StackFrameLine 15 | 16 | + (instancetype)buildWithLine:(NSString *)line andBlackboard:(SymbolicationTasksBlackboard *)bb { 17 | NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:REGEX 18 | options:NSRegularExpressionCaseInsensitive 19 | error:nil]; 20 | __block NSMutableArray *parts = [NSMutableArray array]; 21 | 22 | [regex enumerateMatchesInString:line 23 | options:0 24 | range:NSMakeRange(0, line.length) 25 | usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) { 26 | for (int group = 1; group <= regex.numberOfCaptureGroups; group++) { 27 | NSRange r = [result rangeAtIndex:group]; 28 | 29 | [parts addObject:[line substringWithRange:r]]; 30 | } 31 | }]; 32 | 33 | if (parts.count == 4) { 34 | StackFrameLine *rc = [[self alloc] init]; 35 | 36 | rc.origLine = line; 37 | rc.frameNumber = [parts[0] integerValue]; 38 | rc.binaryName = parts[1]; 39 | rc.address = strtoll([parts[2] UTF8String], NULL, 16); 40 | rc.symbolName = parts[3]; 41 | rc.bb = bb; 42 | [bb addAddress:rc.address]; 43 | return rc; 44 | } 45 | 46 | return nil; 47 | } 48 | 49 | - (NSString *)symbolicate { 50 | NSString *result = [self.bb symbolicatedAddress:self.address]; 51 | 52 | if (result == (id)[NSNull null]) 53 | return self.origLine; 54 | 55 | return result; 56 | } 57 | 58 | @end 59 | -------------------------------------------------------------------------------- /Symbolicator/SymbolicationTasksBlackboard.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import "BinaryImageLine.h" 3 | 4 | @interface SymbolicationTasksBlackboard : NSObject 5 | 6 | + (instancetype)build; 7 | 8 | - (void)addAddress:(uint64_t)address; 9 | - (NSString *)symbolicatedAddress:(uint64_t)address; 10 | - (void)symbolicateWithPaths:(NSArray *)paths binaryInfo:(NSArray *)binaryLines; 11 | 12 | @end 13 | -------------------------------------------------------------------------------- /Symbolicator/SymbolicationTasksBlackboard.m: -------------------------------------------------------------------------------- 1 | #include 2 | #import "MachOReader.h" 3 | #import "SymbolicationTasksBlackboard.h" 4 | 5 | @interface SymbolicationTasksBlackboard() 6 | @property (nonatomic, strong) NSMutableDictionary *addressesAndResults; 7 | @end 8 | 9 | @implementation SymbolicationTasksBlackboard 10 | 11 | + (instancetype)build { 12 | SymbolicationTasksBlackboard *rc = [[self alloc] init]; 13 | 14 | rc.addressesAndResults = [NSMutableDictionary dictionary]; 15 | return rc; 16 | } 17 | 18 | - (void)addAddress:(uint64_t)address { 19 | self.addressesAndResults[@(address)] = [NSNull null]; 20 | } 21 | 22 | - (NSString *)symbolicatedAddress:(uint64_t)address { 23 | return self.addressesAndResults[@(address)]; 24 | } 25 | 26 | - (void)symbolicateWithPaths:(NSArray *)paths binaryInfo:(NSArray *)binaryLines { 27 | NSMutableSet *dirs = [NSMutableSet setWithArray:paths]; 28 | NSString *dir = [[NSString stringWithUTF8String:getpwuid(getuid())->pw_dir] stringByAppendingPathComponent:@"/Library/Developer/Xcode/iOS DeviceSupport"]; 29 | NSMutableSet *symbolFilesNeeded = [NSMutableSet set]; 30 | NSMutableDictionary *binaryToAddress = [NSMutableDictionary dictionary]; 31 | __block NSString *arch = nil; 32 | void (^symbolicator)(NSString *) = ^(NSString *f) { 33 | if ([symbolFilesNeeded containsObject:[f lastPathComponent]]) { 34 | MachOReader *reader = [MachOReader buildWithFile:f]; 35 | __block ThinMachObject *thinMach = nil; 36 | 37 | if (arch) { 38 | thinMach = [reader objectForArch:arch]; 39 | [thinMach parse]; 40 | } else { 41 | for (ThinMachObject *potentialObj in reader.allThinObjects) { 42 | [potentialObj parse]; 43 | [binaryToAddress enumerateKeysAndObjectsUsingBlock:^(BinaryImageLine *bil, NSArray *addrs, BOOL *stop) { 44 | if ([bil.uuid isEqualToString:potentialObj.uuid]) { 45 | arch = potentialObj.arch; 46 | thinMach = potentialObj; 47 | *stop = YES; 48 | } 49 | }]; 50 | } 51 | } 52 | 53 | if (thinMach) { 54 | __block NSArray *addresses = nil; 55 | __block BinaryImageLine *binary; 56 | 57 | [binaryToAddress enumerateKeysAndObjectsUsingBlock:^(BinaryImageLine *bil, NSArray *addrs, BOOL *stop) { 58 | if ([bil.uuid isEqualToString:thinMach.uuid]) { 59 | binary = bil; 60 | addresses = addrs; 61 | *stop = YES; 62 | } 63 | }]; 64 | 65 | if (addresses.count > 0) { 66 | NSDictionary *d = [thinMach symbolicate:addresses]; 67 | 68 | if (d) { 69 | [d enumerateKeysAndObjectsUsingBlock:^(NSNumber *address, NSString *symbol, BOOL *stop) { 70 | self.addressesAndResults[@([address integerValue] + binary.loadAddress)] = symbol; 71 | }]; 72 | [binaryToAddress removeObjectForKey:binary]; 73 | } 74 | } 75 | } 76 | } 77 | }; 78 | 79 | [dirs addObject:dir]; 80 | [self.addressesAndResults enumerateKeysAndObjectsUsingBlock:^(NSNumber *a, id obj, BOOL *stop) { 81 | NSInteger addr = [a integerValue]; 82 | 83 | for (BinaryImageLine *bil in binaryLines) { 84 | if (bil.loadAddress <= addr && bil.endAddress >= addr) { 85 | NSMutableArray *addresses = binaryToAddress[bil]; 86 | 87 | if (!addresses) { 88 | addresses = [NSMutableArray array]; 89 | binaryToAddress[bil] = addresses; 90 | } 91 | 92 | [addresses addObject:@(addr - bil.loadAddress)]; 93 | [symbolFilesNeeded addObject:[bil.path lastPathComponent]]; 94 | break; 95 | } 96 | } 97 | }]; 98 | 99 | [dirs enumerateObjectsUsingBlock:^(NSString *dir, BOOL *stop) { 100 | NSFileManager *fm = [NSFileManager defaultManager]; 101 | NSDirectoryEnumerator *e = [fm enumeratorAtPath:dir]; 102 | NSString *f; 103 | BOOL isDir; 104 | 105 | if ([fm fileExistsAtPath:dir isDirectory:&isDir] && isDir) { 106 | while ((f = [e nextObject]) && binaryToAddress.count > 0) { 107 | @autoreleasepool { 108 | f = [dir stringByAppendingPathComponent:f]; 109 | 110 | if ([fm fileExistsAtPath:f isDirectory:&isDir] && !isDir) 111 | symbolicator(f); 112 | } 113 | } 114 | } else { 115 | symbolicator(dir); 116 | } 117 | 118 | if (binaryToAddress.count == 0) 119 | *stop = YES; 120 | }]; 121 | } 122 | 123 | @end 124 | -------------------------------------------------------------------------------- /Symbolicator/Symbolicator.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.temporary-exception.files.absolute-path.read-only 6 | 7 | /Applications/Xcode.app/Contents/Developer/Platforms 8 | 9 | com.apple.security.temporary-exception.files.home-relative-path.read-only 10 | 11 | /Library/ 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /Symbolicator/ThinMachObject.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface ThinMachObject : NSObject 4 | 5 | @property (nonatomic, strong) NSString *arch; 6 | @property (nonatomic, strong) NSString *uuid; 7 | 8 | + (instancetype)buildWithHandle:(NSFileHandle *)fH size:(NSInteger)size forPath:(NSString *)path; 9 | 10 | - (void)parse; 11 | - (NSDictionary *)symbolicate:(NSArray *)addresses; 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /Symbolicator/ThinMachObject.mm: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | #import 4 | #import 5 | #import "DwarfReader.h" 6 | #import "MachONList.h" 7 | #import "MachOSection.h" 8 | #import "MachOSegment.h" 9 | #import "ThinMachObject.h" 10 | 11 | @interface ThinMachObject() 12 | @property (nonatomic, strong) NSString *path; 13 | @property (nonatomic, assign) BOOL is64Bit; 14 | @property (nonatomic, assign) struct mach_header header; 15 | @property (nonatomic, assign) NSInteger offset; 16 | @property (nonatomic, assign) NSInteger start; 17 | @property (nonatomic, assign) NSInteger end; 18 | @property (nonatomic, strong) NSFileHandle *fH; 19 | @property (nonatomic, strong) NSMutableArray *segments; 20 | @property (nonatomic, strong) NSMutableArray *symbolTable; 21 | @property (nonatomic, strong) DwarfReader *dwarfReader; 22 | @end 23 | 24 | @implementation ThinMachObject 25 | 26 | + (instancetype)buildWithHandle:(NSFileHandle *)fH size:(NSInteger)size forPath:(NSString *)path { 27 | ThinMachObject *rc = [[self alloc] init]; 28 | 29 | rc.path = path; 30 | rc.fH = fH; 31 | rc.start = fH.offsetInFile; 32 | rc.end = fH.offsetInFile + size; 33 | rc.segments = [NSMutableArray array]; 34 | rc.symbolTable = [NSMutableArray array]; 35 | [rc readHeader]; 36 | return rc; 37 | } 38 | 39 | - (NSDictionary *)symbolicate:(NSArray *)addresses { 40 | NSMutableDictionary *rc = [NSMutableDictionary dictionary]; 41 | NSMutableDictionary *addressToSymbol = [NSMutableDictionary dictionary]; 42 | NSDictionary *addressToLineNum; 43 | 44 | if (self.symbolTable.count < 2) 45 | return nil; 46 | 47 | for (NSNumber *a in addresses) { 48 | NSInteger addr = [a integerValue]; 49 | MachONList *best = nil; 50 | NSInteger bestOffset = 0; 51 | NSInteger adjAddr; 52 | 53 | for (MachONList *nlist in self.symbolTable) { 54 | MachOSegment *s = nlist.segment; 55 | 56 | if (nlist.value - s.vmaddr < addr) { 57 | best = nlist; 58 | adjAddr = addr + s.vmaddr; 59 | bestOffset = addr - nlist.value + s.vmaddr; 60 | } else { 61 | break; 62 | } 63 | } 64 | 65 | if (best) 66 | addressToSymbol[a] = best; 67 | } 68 | 69 | addressToLineNum = [self.dwarfReader symbolicate:addressToSymbol]; 70 | 71 | [addressToSymbol enumerateKeysAndObjectsUsingBlock:^(NSNumber *a, MachONList *best, BOOL *stop) { 72 | int status = 0; 73 | const char *cppname = [best.symbol UTF8String]; 74 | NSString *symbol = best.symbol; 75 | const char *name = NULL; 76 | NSString *lineNumberSymbol = addressToLineNum[a]; 77 | 78 | if (cppname[0] == '_') 79 | name = abi::__cxa_demangle(cppname + 1, 0, 0, &status); 80 | else 81 | name = abi::__cxa_demangle(cppname, 0, 0, &status); 82 | 83 | if (name) { 84 | if (status == 0) 85 | symbol = [NSString stringWithUTF8String:name]; 86 | 87 | free((void *)name); 88 | } 89 | 90 | if (lineNumberSymbol) 91 | rc[a] = [NSString stringWithFormat:@"%@ %@", symbol, lineNumberSymbol]; 92 | else 93 | rc[a] = [NSString stringWithFormat:@"%@ + %ld", symbol, [a integerValue] - best.value + best.segment.vmaddr]; 94 | }]; 95 | 96 | return rc; 97 | } 98 | 99 | #pragma mark - 100 | #pragma ThinMachObject Private Methods 101 | 102 | - (void)readHeader { 103 | NSData *d = [self.fH readDataOfLength:sizeof(struct mach_header)]; 104 | 105 | self.header = *((struct mach_header *)d.bytes); 106 | 107 | if (self.header.magic == MH_CIGAM || self.header.magic == MH_CIGAM_64) 108 | assert(false); // For arm and x86, this should never happen, little-endian archs all around 109 | 110 | if (self.header.cputype == CPU_TYPE_X86_64 || self.header.cputype == CPU_TYPE_ARM64) { 111 | self.is64Bit = YES; 112 | [self.fH seekToFileOffset:self.fH.offsetInFile + sizeof(struct mach_header_64) - sizeof(struct mach_header)]; 113 | } 114 | 115 | self.arch = [self prettyArchFromCPUType:self.header.cputype andSubType:self.header.cpusubtype]; 116 | self.offset = self.fH.offsetInFile; 117 | } 118 | 119 | - (NSString *)prettyArchFromCPUType:(cpu_type_t)type andSubType:(cpu_subtype_t)subType { 120 | NSString *rc = nil; 121 | 122 | if (type == CPU_TYPE_I386) { 123 | rc = @"i386"; 124 | } else if (type == CPU_TYPE_X86_64) { 125 | rc = @"x86_64"; 126 | } else if (type == CPU_TYPE_ARM) { 127 | if (subType == CPU_SUBTYPE_ARM_V6) 128 | rc = @"armv6"; 129 | else if (subType == CPU_SUBTYPE_ARM_V7) 130 | rc = @"armv7"; 131 | else if (subType == CPU_SUBTYPE_ARM_V7S) 132 | rc = @"armv7s"; 133 | else if (subType == CPU_SUBTYPE_ARM_V8) 134 | rc = @"armv8"; 135 | } else if (type == CPU_TYPE_ARM64) { 136 | rc = @"arm64"; 137 | } 138 | 139 | return rc; 140 | } 141 | 142 | - (void)parse { 143 | [self.fH seekToFileOffset:self.offset]; 144 | 145 | for (int i = 0; i < self.header.ncmds; i++) { 146 | @autoreleasepool { 147 | NSData *d = [self.fH readDataOfLength:sizeof(struct load_command)]; 148 | struct load_command *lc = (struct load_command *)d.bytes; 149 | 150 | if (lc -> cmd == LC_UUID) { 151 | [self readUUID]; 152 | } else if (lc -> cmd == LC_SEGMENT || lc -> cmd == LC_SEGMENT_64) { 153 | [self.fH seekToFileOffset:self.fH.offsetInFile - sizeof(struct load_command)]; 154 | [self readSegment]; 155 | } else if (lc -> cmd == LC_SYMTAB) { 156 | [self.fH seekToFileOffset:self.fH.offsetInFile - sizeof(struct load_command)]; 157 | [self readSymtab]; 158 | } else { 159 | [self.fH seekToFileOffset:self.fH.offsetInFile - sizeof(struct load_command) + lc -> cmdsize]; 160 | } 161 | } 162 | } 163 | 164 | for (MachONList *nlist in self.symbolTable) { 165 | if (nlist.section != NO_SECT) { 166 | __block NSInteger sectionStart = 0; 167 | 168 | [self.segments enumerateObjectsUsingBlock:^(MachOSegment *seg, NSUInteger idx, BOOL *stop) { 169 | if (seg.nsects + sectionStart >= nlist.section) { 170 | nlist.segment = seg; 171 | *stop = YES; 172 | } else { 173 | sectionStart += seg.nsects; 174 | } 175 | }]; 176 | } else { 177 | assert(false); 178 | } 179 | } 180 | } 181 | 182 | - (void)readUUID { 183 | NSData *d = [self.fH readDataOfLength:16]; 184 | 185 | self.uuid = [[NSUUID alloc] initWithUUIDBytes:(const unsigned char *)d.bytes].UUIDString; 186 | } 187 | 188 | - (void)readSegment { 189 | NSData *d = [self.fH readDataOfLength:self.is64Bit ? sizeof(struct segment_command_64) : sizeof(struct segment_command)]; 190 | MachOSegment *segment = [self parseSegment:d]; 191 | 192 | [self.segments addObject:segment]; 193 | [self.fH seekToFileOffset:self.fH.offsetInFile - d.length + segment.cmdSize]; 194 | } 195 | 196 | - (void)readSymtab { 197 | NSData *d = [self.fH readDataOfLength:sizeof(struct symtab_command)]; 198 | NSData *syms = nil; 199 | NSData *strs = nil; 200 | struct symtab_command *symtab = (struct symtab_command *)d.bytes; 201 | NSInteger offset = self.fH.offsetInFile; 202 | 203 | [self.fH seekToFileOffset:self.start + symtab -> symoff]; 204 | syms = [self.fH readDataOfLength:symtab -> nsyms * (self.is64Bit ? sizeof(struct nlist_64) : sizeof(struct nlist))]; 205 | [self.fH seekToFileOffset:self.start + symtab -> stroff]; 206 | strs = [self.fH readDataOfLength:symtab -> strsize]; 207 | 208 | [self parseSymbolTable:symtab withTableData:syms andStringData:strs]; 209 | [self.fH seekToFileOffset:offset]; 210 | } 211 | 212 | - (MachOSegment *)parseSegment:(NSData *)d { 213 | MachOSegment *rc = [[MachOSegment alloc] init]; 214 | 215 | if (self.is64Bit) { 216 | struct segment_command_64 *sc = (struct segment_command_64 *)d.bytes; 217 | 218 | rc.name = [[NSString alloc] initWithBytes:sc -> segname length:16 encoding:NSUTF8StringEncoding]; 219 | rc.cmd = sc -> cmd; 220 | rc.cmdSize = sc -> cmdsize; 221 | rc.vmaddr = sc -> vmaddr; 222 | rc.vmsize = sc -> vmsize; 223 | rc.fileoff = sc -> fileoff; 224 | rc.filesize = sc -> filesize; 225 | rc.nsects = sc -> nsects; 226 | rc.flags = sc -> flags; 227 | } else { 228 | struct segment_command *sc = (struct segment_command *)d.bytes; 229 | 230 | rc.name = [[NSString alloc] initWithBytes:sc -> segname length:16 encoding:NSUTF8StringEncoding]; 231 | rc.cmd = sc -> cmd; 232 | rc.cmdSize = sc -> cmdsize; 233 | rc.vmaddr = sc -> vmaddr; 234 | rc.vmsize = sc -> vmsize; 235 | rc.fileoff = sc -> fileoff; 236 | rc.filesize = sc -> filesize; 237 | rc.nsects = sc -> nsects; 238 | rc.flags = sc -> flags; 239 | } 240 | 241 | if ([rc.name hasPrefix:@"__DWARF"]) 242 | [self parseDwarfSegment:rc]; 243 | 244 | return rc; 245 | } 246 | 247 | - (void)parseSymbolTable:(struct symtab_command *)symtab withTableData:(NSData *)syms andStringData:(NSData *)strs { 248 | assert(self.symbolTable.count == 0); 249 | 250 | if (self.is64Bit) { 251 | struct nlist_64 *nlist = (struct nlist_64 *)syms.bytes; 252 | 253 | for (int i = 0; i < symtab -> nsyms; i++) { 254 | if ((nlist[i].n_type & N_TYPE) == N_SECT) { 255 | MachONList *n = [[MachONList alloc] init]; 256 | 257 | n.idx = nlist[i].n_un.n_strx; 258 | n.section = nlist[i].n_sect; 259 | n.value = nlist[i].n_value; 260 | 261 | if (n.idx != 0) 262 | n.symbol = [NSString stringWithUTF8String:(char *)strs.bytes + n.idx]; 263 | 264 | [self.symbolTable addObject:n]; 265 | } 266 | } 267 | } else { 268 | struct nlist *nlist = (struct nlist *)syms.bytes; 269 | 270 | for (int i = 0; i < symtab -> nsyms; i++) { 271 | if ((nlist[i].n_type & N_TYPE) == N_SECT && (nlist[i].n_type & N_STAB) == 0) { 272 | MachONList *n = [[MachONList alloc] init]; 273 | 274 | n.idx = nlist[i].n_un.n_strx; 275 | n.section = nlist[i].n_sect; 276 | n.value = nlist[i].n_value; 277 | 278 | if (n.idx != 0) 279 | n.symbol = [NSString stringWithUTF8String:(char *)strs.bytes + n.idx]; 280 | 281 | [self.symbolTable addObject:n]; 282 | } 283 | } 284 | } 285 | 286 | [self.symbolTable sortUsingComparator:^NSComparisonResult(MachONList *l, MachONList *r) { 287 | if (l.value < r.value) 288 | return NSOrderedAscending; 289 | 290 | if (l.value > r.value) 291 | return NSOrderedDescending; 292 | 293 | return NSOrderedSame; 294 | }]; 295 | } 296 | 297 | - (void)parseDwarfSegment:(MachOSegment *)segment { 298 | NSMutableArray *sections = [NSMutableArray array]; 299 | 300 | for (int i = 0; i < segment.nsects; i++) { 301 | MachOSection *s = [self parseSection:[self.fH readDataOfLength:self.is64Bit ? sizeof(struct section_64) : sizeof(struct section)]]; 302 | 303 | [sections addObject:s]; 304 | } 305 | 306 | self.dwarfReader = [DwarfReader buildWithSections:sections forPath:self.path]; 307 | } 308 | 309 | - (MachOSection *)parseSection:(NSData *)d { 310 | MachOSection *rc = [[MachOSection alloc] init]; 311 | 312 | if (self.is64Bit) { 313 | struct section_64 *s = (struct section_64 *)d.bytes; 314 | 315 | rc.name = [NSMutableData dataWithBytes:s -> sectname length:16]; 316 | rc.addr = s -> addr; 317 | rc.size = s -> size; 318 | rc.offset = self.start + s -> offset; 319 | rc.align = s -> align; 320 | rc.reloff = s -> reloff; 321 | rc.flags = s -> flags; 322 | } else { 323 | struct section *s = (struct section *)d.bytes; 324 | 325 | rc.name = [NSMutableData dataWithBytes:s -> sectname length:16]; 326 | rc.addr = s -> addr; 327 | rc.size = s -> size; 328 | rc.offset = self.start + s -> offset; 329 | rc.align = s -> align; 330 | rc.reloff = s -> reloff; 331 | rc.flags = s -> flags; 332 | } 333 | 334 | return rc; 335 | } 336 | 337 | @end 338 | -------------------------------------------------------------------------------- /Symbolicator/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // Symbolicator 4 | // 5 | // Created by Tim Murison on 2014-09-19. 6 | // Copyright (c) 2014 Spectrum Data Technologies. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | int main(int argc, const char * argv[]) { 12 | return NSApplicationMain(argc, argv); 13 | } 14 | -------------------------------------------------------------------------------- /Symbolicator/workaround.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | // XXX: Trying to fix this directly in libelf results in *very* weird behaviour. 4 | 5 | void _elf_seterr(int, int); 6 | 7 | void _SHIM_elf_seterr(int x) { 8 | _elf_seterr(0, x); 9 | } --------------------------------------------------------------------------------