In daily opening, we inevitably encounter some crashes. In most cases, Xcode helped us find the problem, but in some cases, Xcode gave us unreadable addresses that made analyzing the problem much more difficult.
Here are a few ways to make an unreadable address understandable.
symbolicatecrash
The dSYM file
DSYM is a transfer file that stores the address mapping information of hexadecimal functions. All symbols we debug are included in this file. A new dSYM file is generated each time a project is compiled, and we should save the dSYM file for each official release so that we can better debug problems. DSYM and.app files are stored in the Archives. Path is:
~/Library/Developer/Xcode/Archives
Copy the code
DSYM files are not generated in debug mode by default, we go to Build Settings -> Debug Information Format and modify DWARF to DWARF with dSYM File. To create a.dsym file, go directly to the Products directory of the project.
What is “Symbols”?
To quote from The Self-Cultivation of the Programmer:
In links, we refer to functions and variables collectively as symbols, and the function or variable Name is the Symbol Name. We can think of symbols as the glue in the linking process, and it is based on symbols that the whole linking process can be done correctly.
So, symbols are function names or variable names.
Find symbolicatecrash
Symbolicatecrash is Xcode’s own crash log analysis tool. We need to find it first:
find /Applications/Xcode.app -name symbolicatecrash -type f
Copy the code
Several paths will be returned after execution. Mine is:
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/Library/PrivateFrameworks/DVTFou ndation.framework/symbolicatecrashCopy the code
Let’s go to this path and copy symbolicatecrash and put it in a folder.
Get the crash log file
We can write any code that forces a crash:
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
NSArray *arr = @[];
arr[100];
}
Copy the code
Then use the real machine to make a bag. After the package is packed, instead of using Xcode build, we can run the code that causes crash directly with the package, thus generating.crash log file.
After that, we go to Xcode -> Window -> Devices and Simulators or the shortcut Command + Shift + 2
Locate the.crash file for that point in time and right-click Export Log.
Get the.app file
The.app file can be compiled on the real machine and obtained from project Products or Archives.
Symbol resolution
Using the dSYM
Place.dsym,. Crash, and Symbolicatecrash in the same file and run:
/ symbolicatecrash. crash file path. dSYM File path > name. crashCopy the code
Using the app
Place.app,. Crash, and Symbolicatecrash in the same file and run the following command:
File path. app/appName Path > name. CrashCopy the code
Error may be reported:
Error: "DEVELOPER_DIR" is not defined at ./symbolicatecrash line 69.
Copy the code
Just execute the command:
export DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer
Copy the code
Then create a new.crash file.
We can compare unsymbolized and symbolized files. Here’s an example I tested myself, iPhone5, iOS 10.2, which might be different:
Last Exception Backtrace:
0 CoreFoundation 0x1df60df2 __exceptionPreprocess + 126
1 libobjc.A.dylib 0x1d1c3072 objc_exception_throw + 33
2 CoreFoundation 0x1dee62f2 -[__NSArray0 objectAtIndex:] + 105
3 DreamDemo 0x0008088e 0x7c000 + 18574
4 UIKit 0x2319eb44 forwardTouchMethod + 289
5 UIKit 0x2319ea10 -[UIResponder touchesBegan:withEvent:] + 29
6 UIKit 0x23041c58 -[UIWindow _sendTouchesForEvent:] + 1599
7 UIKit 0x2303ca62 -[UIWindow sendEvent:] + 2657
8 UIKit 0x2300d870 -[UIApplication sendEvent:] + 315
9 UIKit 0x237a8998 __dispatchPreprocessedEventFromEventQueue + 2615
10 UIKit 0x237a25de __handleEventQueue + 829
11 CoreFoundation 0x1df1c716 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 7
12 CoreFoundation 0x1df1c220 __CFRunLoopDoSources0 + 433
13 CoreFoundation 0x1df1a4f6 __CFRunLoopRun + 757
14 CoreFoundation 0x1de6952e CFRunLoopRunSpecific + 481
15 CoreFoundation 0x1de6933c CFRunLoopRunInMode + 99
16 GraphicsServices 0x1f640bf8 GSEventRunModal + 151
17 UIKit 0x230789a2 -[UIApplication _run] + 569
18 UIKit 0x230730cc UIApplicationMain + 145
19 DreamDemo 0x000834cc 0x7c000 + 29900
20 libdyld.dylib 0x1d633506 _dyld_process_info_notify_release + 23
Copy the code
The problem is obvious, but because the third line (DreamDemo) is not symbolized, we are not sure exactly where to call it.
Let’s look at the symbolized:
Last Exception Backtrace:
0 CoreFoundation 0x1df60df2 __exceptionPreprocess + 126
1 libobjc.A.dylib 0x1d1c3072 objc_exception_throw + 33
2 CoreFoundation 0x1dee62f2 -[__NSArray0 objectAtIndex:] + 105
3 DreamDemo 0x0008088e -[ViewController touchesBegan:withEvent:] + 18574 (ViewController.m:84)
4 UIKit 0x2319eb44 forwardTouchMethod + 289
5 UIKit 0x2319ea10 -[UIResponder touchesBegan:withEvent:] + 29
6 UIKit 0x23041c58 -[UIWindow _sendTouchesForEvent:] + 1599
7 UIKit 0x2303ca62 -[UIWindow sendEvent:] + 2657
8 UIKit 0x2300d870 -[UIApplication sendEvent:] + 315
9 UIKit 0x237a8998 __dispatchPreprocessedEventFromEventQueue + 2615
10 UIKit 0x237a25de __handleEventQueue + 829
11 CoreFoundation 0x1df1c716 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 7
12 CoreFoundation 0x1df1c220 __CFRunLoopDoSources0 + 433
13 CoreFoundation 0x1df1a4f6 __CFRunLoopRun + 757
14 CoreFoundation 0x1de6952e CFRunLoopRunSpecific + 481
15 CoreFoundation 0x1de6933c CFRunLoopRunInMode + 99
16 GraphicsServices 0x1f640bf8 GSEventRunModal + 151
17 UIKit 0x230789a2 -[UIApplication _run] + 569
18 UIKit 0x230730cc UIApplicationMain + 145
19 DreamDemo 0x000834cc main + 29900 (main.m:15)
20 libdyld.dylib 0x1d633506 _dyld_process_info_notify_release + 23
Copy the code
As you can see, the third line is parsed out, so that we can clearly see the specific page.
Use the command line tool ATos
Symbolicatecrash helps us analyze crash logs well, but it has limitations — it’s not flexible enough. We need symbolicatecrash,.crash, and.dsym files to parse.
The atos command is more flexible than symbolicatecrash, especially if you need to write an automated analysis script for crash files in different channels.
However, this approach also has an inconvenience: for an online App, users may use different versions, and each version corresponds to a different.dsym. To be properly symbolized, you must ensure that the.crash and.dsym files match, as long as they have the same UUID. Before that, a brief introduction to UUID:
What is a UUID?
A UUID is a set of 32 – digit hexadecimal numbers. Each executable program has a unique build UUID identifier. The crash log contains the build UUID of the application that crashed and the build UUID of all library files loaded by the application when the crash occurred.
Get UUID
.crash UUID
Execute command:
grep --after-context=2 "Binary Images:" *crash
Copy the code
Output:
T.crash:Binary Images:
T.crash-0x7c000 - 0x87fff DreamDemo armv7 <d009f8671129397a8aab9cb2b8e506ff> /var/containers/Bundle/Application/DEEBE571-D512-4E8F-B712-ED4D19CE64F9/DreamDemo.app/DreamDemo
T.crash-0xa9000 - 0xd4fff dyld armv7s <cd60ff3403063c0aa8e54dff11e42527> /usr/lib/dyld
Copy the code
See the above output is d009f8671129397a8aab9cb2b8e506ff DreamDemo UUID of the project.
.dSYM UUID
Execute command:
dwarfdump --uuid DreamDemo.app.dSYM
Copy the code
Output:
UUID: D009F867-1129-397A-8AAB-9CB2B8E506FF (armv7) DreamDemo.app.dSYM/Contents/Resources/DWARF/DreamDemo
Copy the code
.app UUID
Execute command:
dwarfdump --uuid DreamDemo.app/DreamDemo
Copy the code
Output:
UUID: D009F867-1129-397A-8AAB-9CB2B8E506FF (armv7) DreamDemo.app/DreamDemo
Copy the code
You can find that the UUID of the two files is the same, that is, the matching condition, can be correctly parsed!
Atos parsing
Let’s review the unparsed stack:
2 CoreFoundation 0x1dee62f2 -[__NSArray0 objectAtIndex:] + 105 3 DreamDemo 0x0008088e 0x7c000 + 18574 4 UIKit 0x2319eb44 forwardTouchMethod + 289 5 UIKit 0x2319ea10 -[UIResponder touchesBegan:withEvent:] + 29Copy the code
Execute command:
xcrun atos -o DreamDemo.app.dSYM/Contents/Resources/DWARF/DreamDemo -arch armv7 -l 0x7c000
Copy the code
Then enter the address 0x0008088e, and the terminal output is as follows:
As you can see, the correct resolution comes out!
In addition to match.dSYM
Files, we can also use.app
File to parse:
Execute command:
xcrun atos -o DreamDemo.app/DreamDemo -arch armv7 -l 0x7c000
Copy the code
Also enter the address 0x0008088e, the effect is the same.
tool
After all, there is a tool on GitHub that can help us parse dSYMTools, a Mac client interface that looks like this:
It’s also easy to use, just drag the corresponding dSYM file in and it automatically recognizes the UUID. Our corresponding input parameter address is ok:
Symbolic parsing of system libraries
Careful people can find that our above analysis is for DreamDemo, this own project. In fact, many system method stacks can be resolved because there are already system library symbolic files, stored in the following directory:
/ User/User name XXX/Resource library /Developer/Xcode/iOS DeviceSupportCopy the code
The versions of these libraries correspond to those in the.crash file:
OS Version: iPhone OS 10.2 (14C5077b)
Copy the code
Once I delete the 10.2 (14C5077b) system’s symbolic library, the.crash file will look like this:
Last Exception Backtrace: 0 CoreFoundation 0x1df60df2 0x1de5f000 + 1056242 1 libobjc.A.dylib 0x1d1c3072 0x1d1bc000 + 28786 2 CoreFoundation 0x1dee62f2 0x1de5f000 + 553714 3 DreamDemo 0x000bc66e -[ViewController touchesBegan:withEvent:] + 18030 (ViewController.m:78) 4 UIKit 0x2319eb44 0x22ffe000 + 1706820 5 UIKit 0x2319ea10 0x22ffe000 + 1706512 6 UIKit 0x23041c58 0x22ffe000 + 277592 7 UIKit 0x2303ca62 0x22ffe000 + 256610 8 UIKit 0x2300d870 0x22ffe000 + 63600 9 UIKit 0x237a8998 0x22ffe000 + 8038808 10 UIKit 0x237a25de 0x22ffe000 + 8013278 11 CoreFoundation 0x1df1c716 0x1de5f000 + 775958 12 CoreFoundation 0x1df1c220 0x1de5f000 + 774688 13 CoreFoundation 0x1df1a4f6 0x1de5f000 + 767222 14 CoreFoundation 0x1de6952e 0x1de5f000 + 42286 15 CoreFoundation 0x1de6933c 0x1de5f000 + 41788 16 GraphicsServices 0x1f640bf8 0x1f637000 + 39928 17 UIKit 0x230789a2 0x22ffe000 + 502178 18 UIKit 0x230730cc 0x22ffe000 + 479436 19 DreamDemo 0x000bf332 main + 29490 (main.m:15) 20 libdyld.dylib 0x1d633506 0x1d630000 + 13574Copy the code
It is obvious that the system library stack has become a stack of addresses.
The new version, whenever our phone is connected to Xcode, will automatically import the current version of the system symbol library into/user/user name XXX/repository /Developer/Xcode/iOS DeviceSupport directory. But there are so many iOS versions, how to get the old system symbol library before? Someone has sorted out ios-system-Symbols, so we just need to download the corresponding System symbolic file to the directory according to the version information of the. Crash file.
conclusion
- Using symbolicatecrash resolution, you can parse the entire
.crash
The log stack resolves, but due to dependenciessymbolicatecrash
,.crash
As well as.dSYM
Three files, or.app
、.crash
及symbolicatecrash
Three files, resulting in less flexibility. - using
atos
The command just needs to.crash
and.dSYM
Or,.crash
and.app
, the corresponding stack address can be parsed, which is convenient for automatic script analysis. However, crash stack may need to be collected by itself.
reference
Wufawei.com/2014/03/sym…