Understanding and Analyzing Application Crash Reports

Nimo: this article for more than 1 w words, translation before and after about a month, “write” for three times: the first is a literal translation, the second time is to put the literal translation into a programmer looked at comfortable “jargon” and the third time is said in the original is too abstract or simple part with my annotations (you see all begin with nimo part). It was only after the post was published that I found out that this wasn’t the only translation for iOS Crash Report. Which is a better translation is a matter of opinion, but I hope this is the most carefully translated version.

When the app crashes, a crash report will be generated, which is very helpful for us to locate the cause of the crash. This document focuses on how to symbolize, understand and parse a crash Report.

Nimo: The opening chapter gives three stages of the document, from shallow to deep:

  1. Symbolic, turning unreadable documents into readable documents
  2. Yes, it means know what part of the document says what
  3. Parsing means being able to locate a problem in a document and obtain valuable information to solve the problem.

introduce

When an APP crashes, the system generates a crash report and stores it on the device. Crash Report will describe the situation in which the app is terminated by the system. In general, the description will include the complete thread call stack, which is very helpful for app debugging (and problem locating). So you should read these crash reports carefully to understand exactly what kind of crashes are happening in your app and try to fix them.

Crash reports, especially stack information, are unreadable until they are symbolized. Symbolization is the substitution of memory addresses with readable function names and line numbers. If you get crash logs not directly from the Device, but through Xcode’s Device Window(i.e. through view operations rather than the manual command line), they will be symbolized automatically after a few seconds. Of course, you can also add the.crash file to Xcode’s Device Window and symbolize it yourself.

Unlike other crash reports, the Low Memory Report has no stack information. When a crash occurs due to low memory, you must reflect on your memory usage patterns and how you respond to low memory warnings. This article will provide you with several reference implementations of memory management for your reference.

Get Crash Report and Low Memory Report

How to debug deployed iOS Apps Discussed how to get crash Reports and Low Memory reports directly from an iOS device. The analysis Crash Reports in the App Release Guide discusses how to view Crash Reports from both test users who downloaded from TestFlight and regular users who downloaded from the App Store.

Symbolizing a Crash report

Symbolization refers to the means by which stack information (binary information) is interpreted as method or function names in the source code, known as symbols. Only after symbolization is successful can crash Report help developers locate problems.

Note: Low Memory reports do not need to be symbolized (because there is no stack information). Note: Crash reports generated on the MacOS platform are generally fully or semi-symbolized when generated. Therefore, symbolization referred to in this section is aimed at crash report extracted from iOS, watchOS and even tvOS. In terms of the overall processing process, CarSH Report of macOS is similar.

  1. As the compiler converts your source code to machine code, it also generates a corresponding Debug symbol table. The Debug symbol table is actually a mapping table that maps each machine instruction hidden in the compiled binary information to each line of source code that generated them. Using the Debug Information Format(DEBUG_INFORMATION_FORMAT) in build Setting, these Debug symbol tables are either stored in compiled binary Information, Either store it in a separate Debug Symbol file (i.e., a dSYM file) : Generally speaking, apps built in Debug mode store the Debug symbol table ina compiled binary message, while apps built in release mode store the Debug symbol table ina dSYM file to save volume. At each build, the Debug symbol table and the app binary information are correlated by the build time UUID. Each build generates a new unique UUID that identifies that build, even if you use the same source code and compile the same setting. Correspondingly, dSYM files cannot be used to parse other binary information, even if built from the same source code.

Nimo: This means that app+dSYM+UUID is the same set for the same build. If the files are not part of the same build, even the same source code will not work with each other on the symbolization matter.

  1. When you select Archive to distribute your app, Xcode stores the app’s binary information and.dysm files somewhere in your home folder. You can find all your Archived apps by clicking “Archived” in Xcode’s Organizer. For more details on archiving your app, please click on official Documentation – Distribute your App.

Note: To parse crash reports from tests, app Reviews, or customers, you need to keep the built Archive files distributed.

  1. If you are distributing your App through the App Store or a beta version of your App distributed by Test Flight, you will see a “Upload with dSYM” option when uploading the Archive to ITC (iTunes Connect). In the upload dialog box, check “Include app symbol table in app”. Uploading your dYSM files is necessary to receive Crash reports from TestFlight users and customers, as well as customers willing to share diagnostic information. Please refer to the official documentation – Distribute your App for more details.

Note: Crash reports received from App Review will not be symbolized, even if you check to include dSYM files before uploading your App to ITC. Any crash report from App Review needs to be symbolized in Xcode.

  1. When your app crashes, an unsymbolized crash report will be created and stored on the device.

  2. Users can get crash reports directly from their devices by debugging the methods mentioned in the deployed iOS APP. If you distribute your app via AdHoc or corporate credentials, this is the only way you can get crash reports from users.

  3. Crash report obtained directly from the device is not symbolized, you need to use Xcode to symbolize. Xcode will combine the dSYM files with your app’s binary information to map each address in the stack to the source code. The result after processing is a symbolized crash report.

  4. If the user is willing to share diagnostic information with Apple, or if the user downloads a beta version of your app through TestFlight, the Crash Report will be uploaded to the App Store.

  5. After symbolizing crash report, App Store will summarize and group all the internal crash reports. Such aggregation method (similar to crash report) is called Crash clustering.

  6. These symbolized Crash reports can be viewed in your Xcode crash Organizer.

Bitcode

Bitcode is an intermediate representation of a compiled project. When you Archive an app with bitcode allowed, the compiler will include the bitcode in the binary instead of the machine code. Once the binary information is uploaded to the App Store, the Bitcode is compiled again into machine code. Perhaps the App Store will recompile Bitcode in the future, for example to improve compiler performance, etc. But it doesn’t matter, because everything is transparent to you, so you don’t have to do anything extra.

Since the final compilation of your binary information is displayed on the App Store, your Mac will not contain the dSYM necessary to symbolise Crash Reports retrieved from App Review or the user’s device.

Nimo: What nimo means is that everything you need is in the Cloud of the App Store, and everything is done automatically. See below.

Although dSYM files are created when you Archive your app, they can only be used in bitcode binary messages and cannot be used to symbolise crash reports. The App Store allows you to download dSYM files that are compiled with Bitcode from Xcode or the ITC website. In order to parse crash reports from App Review or users who sent you crash reports, you must download these dSYM files in order to symbolize crash reports. If a crash report is received from the Crash Reporting Service, symbolization is completed automatically.

Note: The UUID of the binary compiled on the App Store is different from that of the original submitted file.

Download the dSYM file from Xcode

  • In Archives Organizer, select the Archive file you previously submitted to the App Store
  • Select the Download dSYM button Archive

Xcode will download the dSYM files and insert them into the Archive of choice.

Download the dSYM file from the ITC website

  • Open the App details page
  • Click on the Activity
  • From all builds, select a version
  • Click the link to download the dSYM file

Restores the “hidden” symbol name to the original name

When you upload an app with bitcode to the App Store, you may not have checked the “upload your app’s symbol table information to receive a symbolized report from Apple” option in the submit dialog. When you choose not to send symbol table information to Apple, Xcode will replace the dSYM files in your app with obscure symbols such as “_hidden#109” before you send your app to ITC. Xcode creates a comparison table between the original and “hidden” symbols and stores it in a BCSymbolMap file in the Archive’s app file. Each dSYM file will have a corresponding BCSymbolMap file.

Before symbolizing crash Report, you need to parse the obscure information in dSYM files downloaded from ITC. If you use the Download dSYM button in Xcode, this parsing will be done automatically. However, if you download dSYM from the ITC website, you need to open Terminal and manually enter the following command to parse (replace the path information of Example with the dSYM information)

Xcrun dsymutil - symbol - map ~ / Library/Developer/Xcode/Archives / 2017-11-23 / MyGreatApp \ 2017-11-23 \ \ \ 12.00 PM.xcarchive/BCSymbolMaps ~/Downloads/dSYMs/3B15C133-88AA-35B0-B8BA-84AF76826CE0.dSYMCopy the code

Run this command once for each dSYM file in the dSYMs folder.

How to judge whether Crash Report has been symbolized

A crash report may be unsymbolized, fully symbolized, or partially symbolized. An unsymbolized Crash report does not contain method or function names in the stack information. Instead, you’ll find executable hexadecimal address information in the loaded binary information. In a fully symbolic Crash report, each line of hexadecimal address information in the stack is replaced with the corresponding symbol. In the partially symbolized crash report, only part of stack information is replaced with corresponding symbolic information.

Obviously, you should try to fully symbolize your Crash report, because then you can get the most valuable information from the Crash Report. A partially symbolized crash report may contain information that can be interpreted as a crash, depending on the type of crash and which part of the crash is successfully symbolized. An unsymbolized crash report is of limited use.

Use Xcode to symbolize iOS Crash report

In general, Xcode will automatically attempt to symbolize all of its Crash reports. So you just need to add crash Report to Xcode Organizer.

Note: Xcode only recognizes the suffix “crash report”. If you receive a crash report without a suffix or with a suffix of TXT, change it to.crash before performing the following steps.

  • Connect your iOS device to your Mac
  • Select Devices from the Window menu bar
  • On the left of Devices, select a device
  • Click the “View Device Logs” button on the right under “Device Information”
  • Drag and drop your Crash Report into the left panel
  • Xcode will automatically symbolize the Crash report and display the results

To symbolize a Crash report, Xcode needs to locate the following information:

  • The crashed app’s binary information and dSYM file
  • Binary information and dSYM files for all app associated custom framework. If the framework is built from an app, their dYSM is copied into the Archive along with the APP’s dSYM file. If it’s a third party framework, you need to go to the author and ask for the dYSM file.
  • Symbol table information of the OS on which the APP depends when a crash occurs. These symbol tables contain debugging information needed for the framework on a particular OS version, such as iOS9.3.3. The ARCHITECTURE of the OS symbol table is unique — a 64-bit iOS device will not include the ARMV7 symbol table. Xcode will automatically copy the symbol table of the particular version of the Mac to which you are connected.

In any of the above, you will not be able to symbolize a crash report without Xcode, or only partially symbolize a crash report.

Symbolized Crash report with ATOS

The ATos command replaces the number in an address with an equivalent symbol. If the debug symbol information is complete, the output of ATOS will contain the file name and the corresponding resource line number. The atos command can be used to individually symbolise unsymbolised or partially symbolised crash reports (addresses in stack information). To use ATOS to symbolize crash report, you can operate as follows:

  1. Find the line you want to symbolize and write down the binary information name in the second column and the address in the third column.
  2. Find the name in the binary list at the bottom of the Crash report and write down the schema name and the loading address.

Nimo: such as in The figure below, we want to symbolic part is 0 x00000001000effdc, binary information are The Elements that can be found at The bottom of The corresponding to The name of The schema name is arm64, is 0 x1000e4000 loading address.

  1. Locate the dSYM file corresponding to the binary. You can use Splotlight, combined with UUID, to find matching dSYM files. (See the section.) DSYM is a bundle that contains DWARF debugging information compiled by the compiler at build time (nimo: Debugging With opposed Record Formats DWARF, Debugging With opposed Record Formats, is a standard for Debugging file structures that are very complex. You’re usingatosMust provide the path to this file, not the dSYM bundle path.
  2. With this information, you can pass the addresses in the stackatosThe command is symbolized. You can symbolise multiple addresses, separated by Spaces.
atos -arch <Binary Architecture> -o <Path to dSYM file>/Contents/Resources/DWARF/<binary image name> -l <load address> <address to symbolicate>
Copy the code

Listing 1 shows an example using the ATOS command with the resulting output

$ atos -arch arm64 -o TheElements.app.dSYM/Contents/Resources/DWARF/TheElements -l 0x1000e4000 0x00000001000effdc
Copy the code
-[AtomicElementViewController myTransitionDidStop:finished:context:]
Copy the code

Use symbolization to identify problems

If Xcode does not fully encode a crash report, it is likely that your Mac lost the dSYM file corresponding to the app binary information, or one or more of the framework’s dSYM files associated with your app. It is also possible that the device symbol table of the APP at the OS level may be lost when a Crash occurs. The following steps show how to use Spotlight to determine if dSYM files that can symbolize the corresponding stack address information are on your Mac.

  1. Find a line in the stack that Xcode cannot symbolize. Note the binary information name in the second column.
  2. Find the name in the binary information list at the bottom of the Crash Report. This list contains the UUID of binary information that exists in the process at each crash site.

Nimo: this case is The name of The binary information need to pay attention to The Element, in The bottom of The list of The corresponding binary information b672e2b9f53b0f95adbc4f68cb80d6 UUID is 77

Listing 2 You can use the grep command to quickly find a list of binary information

$ grep --after-context=1000 "Binary Images:" <Path to Crash Report> | grep <Binary Name>
Copy the code
  1. Convert the UUID of binary information to a string of 32 characters in the format of 8-4-4-4-12 (XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX). Note that all letters must be capitalized.
  2. Use the mdfind command, combined with “com_apple_xcode_dsym_uuids ==” (including quotes), to find UUID information.

Listing 3 uses the mdfind command to find a dSYM file with a given UUID.

$ mdfind "com_apple_xcode_dsym_uuids == <UUID>"
Copy the code
  1. If Spotlight finds the dSYM file that corresponds to the UUID, MDFind prints out the path to the dSYM file and any archive files it might contain. If the dSYM file for a UUID is not found, mdfind simply exits.

If Spotlight finds the binary corresponding dSYM file, but Xcode does not successfully symbol the address with the binary information, then you should report a bug and attach the Crash report to the bug report with the corresponding dSYM file. As a stopgap, you can symbolize the address by hand with ATOS.

If Spotlight doesn’t find a dSYM file for the binaries, make sure you also have the Xcode archive for the version of your app that crashed, and that it’s somewhere Spotlight can find it. If your app is built with bitcode, make sure you have downloaded the dSYM file for the final build from the App Store.

If you think you have the correct dSYM file for the binary information, you can use dwarfdump to print the matching UUID. You can also print binary UUids using the dwarfdump command.

xcrun dwarfdump --uuid <Path to dSYM file>

Note: You must save the archive of your original crash App that you uploaded to the App Store. DSYM files and APP binaries are one-to-one and are different from one build to the next. Even with the same source code and configuration, the dSYM file generated cannot symbolically match the previous Crash Report. If you do not have the archived file, you should resubmit the new archived version to ensure that you can symbolise the crash report in the event of another crash.

Analysis of the Crash report

This section will discuss the meaning of chapters in a standard Crash report.

Header

Every crash report has a header.

Listing 4 Header sections of a crash report

Incident Identifier: B6FD1E8E-B39F-430B-ADDE-FC3A45ED368C CrashReporter Key: F04e68ec62d3c66057628c9ba9839e30d55937dc Hardware Model: iPad6, 8 Process: TheElements [303] the Path: /private/var/containers/Bundle/Application/888C1FA2-3666-4AE2-9E8E-62E2F787DEC1/TheElements.app/TheElements Identifier: Com.example.apple-samplecode.TheElements Version: 1.12 Code Type: ARM-64 (Native) Role: Foreground Parent Process: launchd [1] Coalition: com.example.apple-samplecode.TheElements [402] Date/Time: 2016-08-22 10:43:07. 5806-0700 Launch Time: 2016-08-22 10:43:01. 0293-0700 OS Version: IPhone OS 10.0 (14A5345a) Report Version: 104Copy the code

Most of the fields are self-explanatory, but a few are worth pointing out:

  • Incident Identifier: Unique ID of a crash report. Two reports will not use the same Incident Identifier.
  • CrashReporter Key: an anonymous device-related ID. Two crash reports on the same device will have the same CrashReporter Key.
  • Beta Identifier: An ID that integrates the device and vendor information on which crash App occurred. Two reports from the same vendor and device will contain the same ID value. This Field only appears when the app is distributed via TestFlight and appears where Crash Reporter Key Field should appear.
  • Process: indicates the Process name when a Crash occurs. This matches the value of the CFBundleExecutable Key in the APP info property list.
  • Version: indicates the Version of the crash. This value can be associated with the CFBundleVersion and CFBundleVersionString of the app where the crash occurred.
  • Code Type: the architecture environment in which the crash occurred. ARM – 64, ARM, X86 and X86-64.
  • Role: task_role of the process in the event of a crash.

Nimo: task_role is defined as follows:

enum task_role {
	TASK_RENICED = -1,
	TASK_UNSPECIFIED = 0,
	TASK_FOREGROUND_APPLICATION,
	TASK_BACKGROUND_APPLICATION,
	TASK_CONTROL_APPLICATION,
	TASK_GRAPHICS_SERVER,
	TASK_THROTTLE_APPLICATION,
	TASK_NONUI_APPLICATION,
	TASK_DEFAULT_APPLICATION
};
Copy the code
  • OS Version: OS Version, including the coding and decoding of the owning app when a crash occurs.

Exception information

Don’t be blindsided when you encounter Objective-C/C++ (even if some of them Crash). This chapter lists the Mach exception types and corresponding field information that can provide hints of a crash. Of course, not all fields will appear in every Crash Report.

Listing 5 An excerpt from the crash report where the process was stopped due to an uncaught Objective-C exception

Exception Type: EXC_CRASH (SIGABRT)
Exception Codes: 0x0000000000000000, 0x0000000000000000
Exception Note: EXC_CORPSE_NOTIFY
Triggered by Thread: 0
Copy the code

Listing 6 is an excerpt from the Crash report in which the process was terminated due to a backreference to a NULL pointer

Exception Type: EXC_BAD_ACCESS (SIGSEGV)
Exception Subtype: KERN_INVALID_ADDRESS at 0x0000000000000000
Termination Signal: Segmentation fault: 11
Termination Reason: Namespace SIGNAL, Code 0xb
Terminating Process: exc handler [0]
Triggered by Thread: 0
Copy the code

Some of the fields that may appear in this chapter are read below.

  • Exception Codes: Processor-specific information related to exceptions that are encoded as one or more 64-bit binary digits. In general, this field should not exist because crash report generation converts exception code into readable information that is reflected in other fields.
  • Exception Subtype: The name of the readable Exception code.
  • Exception Message: Additional readable information parsed from Exception code.
  • Exception Note: Additional information that does not specifically refer to an Exception. If this field contains “SIMULATED” (instead of Crash), the process does not Crash, but is killed at the system level, such as the watchdog mechanism.

Nimo: To prevent an application from taking up too much system resources, Apple engineers designed a “watchdog” mechanism. The watchdog monitors the performance of the application. If the running time specified for the scenario is exceeded, the watchdog forces the application to terminate. Developers will see error codes like 0x8BadF00D in the Crashlog (it looks like bad food, the watchdog ate the bad food). The watchdog trigger conditions are as follows:

trigger The time of the guard dog
Start the 20 seconds
resume 10 seconds
Suspension process 10 seconds
Quit the application 6 seconds
The background Ten minutes
  • Termination Reason: Indicates the Reason and information when the process is terminated. Critical information modules, whether in process or out of process, encounter a fatal error (e.g. bad code signature, missing dependent library, improper access to private sensitive information, etc.). MacOS Sierra,iOS 10, Watch OS3, and tvOS 10 have implemented new architectures to log these error messages, Therefore, crash reports in these systems will describe the error message in the Termination Reason field.
  • Triggered by Thread: Specifies the Thread in which an exception is Triggered

The following sections explain common types of exceptions:

Bad Memory Access [EXC_BAD_ACCESS // SIGSEGV // SIGBUS]

A process attempts to access memory that is not valid, or attempts to access memory in ways that are not allowed (such as writing to read-only memory). Kern_return_t in the Exception Subtype field indicates that the memory address space has been improperly accessed. Here are a few tips for debugging bad Memory crashes:

  • If objc_msgSend or objc_Release appeared near the crash thread, the process might try to send a message to a freed object. You should run the profile in Zombie Instrument to get a better idea of what happened.
  • If gpus_ReturnNotPermittedKillClient in recent crash near the thread of the process may be tried in the background by OpenGL ES or Metal for rendering. See QA1766: How to Fix OpenGL ES Application Crashes when moving to the background
  • By checking Address Sanitizer when you run your app. Address Sanitizer adds extra operations to memory access during compilation, and When your app is running, Xcode will alert you when memory crashes.

Abnormal Exit [EXC_CRASH // SIGABRT]

The process exits unexpectedly. Procedure The most common cause of this exception is an uncaught Objective-c /C++ exception that calls abort(). App Extensions (nimo: App Extensions, such as input methods) that take too long to initialize will exit with this exception (watchdog). If the extension is killed due to hanging at startup, the Exception Subtype field in the report will say LAUNCH_HANG. Since the extension App does not have a main function, any initialization times in static constructors and +load methods will be reflected in your extension or dependency library. So you should postpone this logic as long as possible.

Trace Trap [EXC_BREAKPOINT // SIGTRAP]

Similar to Abnormal Exit, this exception is caused by adding a debugger debug node to a particular node. You can raise this in your own code by using the __builtin_trap() function. If no debugger exists, the thread is terminated and a crash report is generated. Underlying libraries (such as libDispatch) fall into this trap when they encounter fatal errors. Information about the error can be found in the Crash Report section or in the device printout. Swift code throws this exception when encountering the following problems at runtime:

  • A non-optional type is assigned a nil value
  • A failed cast

When encountering such an error, look up the stack information and figure out where unexpected conditions are encountered. Additional information may also appear in the log on the device’s console. You should try to modify your code to handle such runtime errors gracefully. For example, if an optional value is processed, its value is obtained by an optional binding rather than by forced unpacking.

Nimo: Optional binding, which is similar to the following statement

if let actualValue = maybeHasValue(){
	foo(actualValue)
}
Copy the code

Illegal Instruction [EXC_BAD_INSTRUCTION // SIGILL]

Raised when an attempt is made to execute an invalid or undefined instruction. It is possible that the thread attempted to jump to an invalid address after being misled by a misconfigured function pointer. On Intel processors, the UD2 opcode causes an EXC_BAD_INSTRUCTIONY exception, but this is usually used for debugging purposes. On Intel processors, Swift is stopped when it encounters an unknown condition at runtime. For details, see Trace Trap.

Quit [SIGQUIT]

This exception is caused by another process that has a high priority and can manage the process (and thus be killed by the high priority process). SIGQUIT does not mean that the process crashed, but it does indicate some unreasonable behavior. On iOS, keyboard extensions will die with the host app if they take too long. Therefore, it is unlikely that reasonable readable exception code will appear in Crash Report under such exceptions. Most likely, some other code took too long to start but ended successfully before the total time limit (the watchdog time limit, see table above), but the execution logic was incorrectly executed when extension exited. You should run the Profile, take a close look at the time consumed parts of the extension, and put the logic that takes a lot of time into background or defer it (until the extension loads).

Killed[SIGKILL]

The process received a system command and was killed. Check the Termination Reason to find out why the thread was killed. The Termination Reason field contains a namespace and code. The following code is for watchOS only:

  • code0xc51bad01Indicates that watchOS takes up too much CPU time in background tasks and causes the Watch app to be killed. To solve this problem, optimize background tasks to improve CPU execution efficiency, or reduce the number of tasks running in the background.
  • code0xc51bad02It means that the watch app is killed because the specified background task is not completed within the specified time in the background. To solve this problem, you need to reduce the number of app processing tasks while the app is running in the background.
  • code0xc51bad03It means that the Watch app does not complete the background task within the specified time, and the system is always very busy so that the APP cannot obtain enough CPU time to complete the background task. While an app can avoid this problem by reducing the number of tasks it has to run in the background0xc51bad03This error points to high system load, not something wrong with the app itself.

Guarded Resource Violation [EXC_GUARD]

The process improperly accessed a protected resource. Procedure System libraries mark specific file descriptors as protected, so any general operations on these file descriptors throw EXC_GUARD exceptions (NIMO: when systems want to operate on these file descriptors, they use a special authorized private API). So you can quickly detect things like secretly closing open file descriptors on the system. For example, if an app closes the file descriptor for SQLite files that used to support Core Data storage, you’ll find Core Data mysteriously crash after a while. Guard exceptions will be noticed after a while and make them easier to debug. Newer versions of iOS Crash Report include readable details about EXC_GUARD exceptions in the Exception Subtype and Exception Message fields. In the Crash Report on macOS or older versions of iOS, this message is encrypted into the first Exception Code and presented as a bit message, which can be read as follows:

  • [63:61] – Guard Type: indicates the Type of the resource to be protected. The value 0x2 indicates that the resource is a file descriptor.
  • [60:32] -flavor: A problem that occurs in what condition. If the first (1<<0)bit is set, the process tries to call close() on a protected file descriptor

If the second (1<<1)bit is set, the process attempts to call the dup(), dup2(), or FCNTL () command on the protected file descriptor with either F_DUPFD or F_DUPFD_CLOEXEC.

If the third (1<<2)bit is set, the process tries to send a protected file descriptor through the socket.

If the fifth (1<<4)bit is set, the process tries to write a protected file descriptor.

  • [31:0] -File Descriptor: A process tries to modify the protected File Descriptor.

Resource Limit [EXC_RESOURCE]

The resources of the process exceeded the threshold. Procedure This push was sent by the OS to indicate that the process was occupying too many resources. The exact resources are listed in the Exception Subtype field. If the Exception Note field contains a non-fatal CONDITION, the process will not be killed even if a crash report is generated.

  • ifEXCEPTION SUBTYPEinMEMORYIndicates that process usage has exceeded the system limit. If a process is killed later because the system is occupied too much, it may be related to this.
  • ifEXCEPTION SUBTYPEinWAKEUPThe implication is that the thread is being woken up too many times per second by the process, causing the CPU to wake up too often and causing power loss. Typically, this happens with interprocess communication (throughpeformSelector:onThread:ordispatch_async) and will happen far more often than expected. Because the communication that occurs with this exception is triggered so frequently, many background processes have stacks that are highly identical to each other — indicating exactly where they came from.

Other Exception Types

Some crash reports may have an unnamed Exception Type, in which case a pure hexadecimal value (e.g. 00000020) appears in this field. If you receive a crash report like this, go directly to Exception Code for more information.

  • If the Exception Code is0xbaaaaaadThis indicates that logs are system stack snapshots rather than crash reports. A stack snapshot can be taken by pressing the side button and volume button at the same time. Typically, these logs are generated by the user unintentionally and do not indicate errors.
  • If the Exception Code is0xbad22222Indicates that a VoIP application is terminated by the iOS system because of frequent pauses.
  • If the Exception Code is0x8badf00d(pronounced “badfood”) indicates that an app has been terminated by iOS because it triggered the watchdog mechanism, either because the app took too long to start, terminate, or in response to a system event. One common reason is to do network synchronization logic on the main thread. Whatever Thread0 (the main thread) wants to do (important things) should either be moved to the background thread or fired in a different way so that it doesn’t block the main thread.
  • If the Exception Code is0xc00010ffThe app was killed by iOS due to overheating. This may be related to the specific device in which the crash occurred, or to the environment in which it occurred. For more tips on how to run apps efficiently, check out WWDC’s article:iOS Performance and Power Optimization with Instruments.
  • If the Exception Code is0xdead10cc(reads like deadlock) indicates that an application has been terminated by the system because a file lock was acquired while the application was suspended or the SQLite database was held for a long time until it was frozen. If your app gets a file lock or SQLite database lock while suspended, it must request additional background execution time (request additional background execution time) and complete the unlock operation before being suspended.
  • If the Exception Code is0x2bad45ecIt indicates that the APP is terminated by the iOS system because of illegal operations (security violations). The termination description will say: “Process was detected performing unsafe operations in safe mode,” implying that the app is trying to draw the screen when it is disabled, such as when the screen is locked. Users may ignore this exception, especially if the screen is off or locks the screen when the termination occurs.

Note: Crash Report will not be generated on App Switcher. Once the app enters the suspended state, it is reasonable for iOS to terminate it at any time, so crash report will not be generated at this time.

Additional diagnostic information

This section contains additional diagnostic information related to termination, including:

  • Application-specific information: Frame error messages that were captured before the process was terminated
  • Kernel information: Details about code signing issues
  • Dyld (dynamic link library) error message: Error message submitted by the dynamic linker

Starting with macOS Sierra, iOS 10, watchOS 3, and tvOS 10, most of this Information is in the Termination Reason field of Exception Information. You should read this chapter to better understand what happens when a process is terminated.

Table 7: An excerpt from a crash report where the process was terminated because the link library could not be found

Dyld Error Message:
Dyld Message: Library not loaded: @rpath/MyCustomFramework.framework/MyCustomFramework
  Referenced from: /private/var/containers/Bundle/Application/CD9DB546-A449-41A4-A08B-87E57EE11354/TheElements.app/TheElements
  Reason: no suitable image found.
Copy the code

Table 8: An excerpt from a crash report in which the process was terminated because the initial View Controller could not be loaded quickly

Application Specific Information: Com.example.apple-samplecode.TheElements failed to scene-create after 19.81s (launch took 0.19s of total time)limitElapsed total CPU time (seconds): Elapsed CPU time (seconds): Elapsed CPU time (seconds): Elapsed CPU time (seconds): Elapsed CPU time (seconds): Elapsed CPU time (seconds): Elapsed CPU time (seconds): Elapsed CPU time (seconds): Elapsed CPU time (seconds): Elapsed CPU time (secondsCopy the code

The stack information

The most interesting part of a crash report must be the stack information for each thread when it terminates. These messages are similar to what you see in debug.

Listing 9: A partial stack excerpt from a fully symbolic Crash report

Thread 0 name: Dispatch queue: com.apple.main-thread Thread 0 Crashed: 0 TheElements 0x000000010006bc20 -[AtomicElementViewController myTransitionDidStop:finished:context:] (AtomicElementViewController.m:203) 1 UIKit 0x0000000194cef0f0 -[UIViewAnimationState sendDelegateAnimationDidStop:finished:] + 312 2 UIKit 0x0000000194ceef30 -[UIViewAnimationState animationDidStop:finished:] + 160 3 QuartzCore 0x0000000192178404 CA::Layer::run_animation_callbacks(void*) + 260 4 libdispatch.dylib 0x000000018dd6d1c0 _dispatch_client_callout + 16 5 libdispatch.dylib 0x000000018dd71d6c _dispatch_main_queue_callback_4CF + 1000 6 CoreFoundation 0x000000018ee91f2c __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 12 7 CoreFoundation 0x000000018ee8fb18 __CFRunLoopRun + 1660 8 CoreFoundation 0x000000018edbe048 CFRunLoopRunSpecific + 444 9 GraphicsServices 0x000000019083f198 GSEventRunModal + 180  10 UIKit 0x0000000194d21bd0 -[UIApplication _run] + 684 11 UIKit 0x0000000194d1c908 UIApplicationMain + 208 12 TheElements 0x00000001000653c0 main (main.m:55) 13 libdyld.dylib 0x000000018dda05b8 start + 4 Thread 1: 0 libsystem_kernel.dylib 0x000000018deb2a88 __workq_kernreturn + 8 1 libsystem_pthread.dylib 0x000000018df75188 _pthread_wqthread + 968 2 libsystem_pthread.dylib 0x000000018df74db4 start_wqthread + 4 ...Copy the code

The first line lists the current thread number, along with the ID of the current execution queue. The rest of the columns and columns show the stack fragment information in each stack, from left to right:

  • Stack fragment number. The stack is presented in the same order as it was called, with fragment 0 being the function executed when the program was terminated. Fragment 1 is the function that calls fragment 0, and so on.
  • The name of the executing function that resides in the stack fragment
  • Fragment 0 represents the address of the machine instruction in the terminated life. The other fragments represent the address of the next fragment to be executed if fragment 0 completes execution
  • In a symbolic crash report, represents the name of a function in a stack fragment

abnormal

Exceptions in Objective-C are often used to indicate code errors that occur at run time, such as overreaching arrays, or changing immutable objects, failing to implement methods that must be implemented in protocol, or sending messages to objects that are not recognized by the receiver.

Note: before to release the object sends the message triggers NSInvalidArgumentException exception, in turn, crash, rather than the memory access violation. This happens when the new variable occupies the memory where it was released. If your app because NSInvalidArgumentException crash (in stack information view [NSObject (NSObject) doesNotRecognizeSelector:]), Consider profiling your application via Zombies Instrument to eliminate the memory management issues mentioned earlier.

If the exception is not caught, it is intercepted by a method called uncaught Exception. The default uncaught exception log is displayed on the console of the device, and the process is terminated. The Exception stack information is placed under the Last Exception Backtrace in the generated crash report, as shown in Listing 10. Abnormal messages are ignored by the Crash Report. If you receive a crash report with a Last Exception Backtrace, you should retrieve the original device and its console log information to better understand the cause of the crash.

List10: Unsymbolized crash report excerpt of the Last Exception Backtrace that occurred

Last Exception Backtrace: (0x18eee41c0 0x18d91c55c 0x18eee3e88 0x18f8ea1a0 0x195013fe4 0x1951acf20 0x18ee03dc4 0x1951ab8f4 0x195458128 0x19545fa20  0x19545fc7c 0x19545ff70 0x194de4594 0x194e94e8c 0x194f47d8c 0x194f39b40 0x194ca92ac 0x18ee917dc 0x18ee8f40c 0x18ee8f89c 0x18edbe048 0x19083f198 0x194d21bd0 0x194d1c908 0x1000ad45c 0x18dda05b8)
Copy the code

A crash log containing only hexadecimal information with Last Exception Backtrace information must be symbolized to retrieve valuable stack information, as shown in Listing 11.

Listing 11: A symbolic crash report containing Last Exception Backtrace information. This exception occurs when the storyboard of the app is loaded, and the corresponding element of the IBOutlet that needs to respond is lost.

Last Exception Backtrace:

0   CoreFoundation                	0x18eee41c0 __exceptionPreprocess + 124
1   libobjc.A.dylib               	0x18d91c55c objc_exception_throw + 56
2   CoreFoundation                	0x18eee3e88 -[NSException raise] + 12
3   Foundation                    	0x18f8ea1a0 -[NSObject(NSKeyValueCoding) setValue:forKey:] + 272
4   UIKit                         	0x195013fe4 -[UIViewController setValue:forKey:] + 104 5 UIKit 0x1951acf20 -[UIRuntimeOutletConnection connect] + 124 6 CoreFoundation 0x18ee03dc4 -[NSArray makeObjectsPerformSelector:] + 232 7 UIKit 0x1951ab8f4 -[UINib instantiateWithOwner:options:] + 1756 8 UIKit 0x195458128  -[UIStoryboard instantiateViewControllerWithIdentifier:] + 196 9 UIKit 0x19545fa20 -[UIStoryboardSegueTemplate instantiateOrFindDestinationViewControllerWithSender:] + 92 10 UIKit 0x19545fc7c -[UIStoryboardSegueTemplate _perform:] + 56 11 UIKit 0x19545ff70 -[UIStoryboardSegueTemplate perform:] + 160 12 UIKit  0x194de4594 -[UITableView _selectRowAtIndexPath:animated:scrollPosition:notifyDelegate:] + 1352 13 UIKit 0x194e94e8c -[UITableView _userSelectRowAtPendingSelectionIndexPath:] + 268 14 UIKit 0x194f47d8c _runAfterCACommitDeferredBlocks + 292 15 UIKit 0x194f39b40 _cleanUpAfterCAFlushAndRunDeferredBlocks + 560 16 UIKit 0x194ca92ac _afterCACommitHandler + 168  17 CoreFoundation 0x18ee917dc __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 32 18 CoreFoundation 0x18ee8f40c __CFRunLoopDoObservers + 372 19 CoreFoundation 0x18ee8f89c __CFRunLoopRun + 1024 20 CoreFoundation 0x18edbe048 CFRunLoopRunSpecific + 444 21 GraphicsServices 0x19083f198 GSEventRunModal + 180 22 UIKit 0x194d21bd0 -[UIApplication _run] + 684 23 UIKit 0x194d1c908 UIApplicationMain + 208 24 TheElements 0x1000ad45c main (main.m:55)Copy the code

If you find that an exception that should have been caught was not, make sure that you did not add the -no_compact_unwind tag to your building application or library.

64-bit IOS uses the zero-cost exception implementation mechanism. In a zero-cost system, each function has an additional piece of data that describes how to expand the stack if an exception is implemented across the function scope. If an exception occurs on multiple stacks but there is no data to expand, then the exception handler cannot naturally track and log it. There may be exception handlers very high up on the stack, but if there is no piece of expandable information there, there is no way to get there from where the exception occurred. Specifying the -no_compact_unwind tag means that your code has no unwinding information, so you can’t throw an exception across functions (that is, you can’t catch the current function’s exception through another function).

Thread State

This chapter lists the thread states of the crash thread. The registered values are listed here. It is not necessary to know thread state when you read a crash report, but it may be helpful if you want to better understand the details of the crash.

Listing 12: A Thread State excerpt from the Crash report for ARM64 devices

Thread 0 crashed with ARM Thread State (64-bit):

    x0: 0x0000000000000000   x1: 0x000000019ff776c8   x2: 0x0000000000000000   x3: 0x000000019ff776c8
    x4: 0x0000000000000000   x5: 0x0000000000000001   x6: 0x0000000000000000   x7: 0x00000000000000d0
    x8: 0x0000000100023920   x9: 0x0000000000000000  x10: 0x000000019ff7dff0  x11: 0x0000000c0000000f
   x12: 0x000000013e63b4d0  x13: 0x000001a19ff75009  x14: 0x0000000000000000  x15: 0x0000000000000000
   x16: 0x0000000187b3f1b9  x17: 0x0000000181ed488c  x18: 0x0000000000000000  x19: 0x000000013e544780
   x20: 0x000000013fa49560  x21: 0x0000000000000001  x22: 0x000000013fc05f90  x23: 0x000000010001e069
   x24: 0x0000000000000000  x25: 0x000000019ff776c8  x26: 0xee009ec07c8c24c7  x27: 0x0000000000000020
   x28: 0x0000000000000000  fp: 0x000000016fdf29e0   lr: 0x0000000100017cf8
    sp: 0x000000016fdf2980   pc: 0x0000000100017d14 cpsr: 0x60000000
Copy the code

Binary Images

This chapter lists the binary images that are loaded into a process when it is terminated.

Listing 13: A complete binary excerpt from crash Report

Binary Images:

0x100060000 - 0x100073fff TheElements arm64 <2defdbea0c873a52afa458cf14cd169e> /var/containers/Bundle/Application/888C1FA2-3666-4AE2-9E8E-62E2F787DEC1/TheElements.app/TheElements

...
Copy the code

Each line contains the following details of a binary:

  • The address space of the binary file in the process
  • A binary name or bundle ID (for macOS only). A MacOS crash report, if binary is part of the OS, will be added to the fronta.
  • (macOS only) Short version and bundle version of binary, separated by dashes.
  • (iOS only) The schema name of the binary file. A binary may contain multiple shards, each of which it supports. Only one of these can be loaded into the process.
  • An ID, or UUID, that uniquely identifies the binary file. This value changes with each build, and it is used to locate the dSYM files that need to be symbolized.
  • Path of binary files on disk.

Read Low Memory Reports

When the system detects insufficient memory, the virtual memory system in iOS collaborates with other applications to release memory. Each running application receives a low-memory notification from the system asking for free memory space to reduce overall memory consumption. If the memory stress persists, the system may terminate the background process to relieve the memory stress. If you free enough memory, your application will continue to run. Otherwise, your app will be terminated by iOS because there is not enough Memory for your app to run, and a low-memory Report will be generated and stored on your device. The format of the low-memory report is slightly different from other Crash reports in that it does not have the applied stack information. A low-memory report Header will look similar to a crash report Header. The Header is followed by system-level memory statistics for each field. Record the Page Size field. The memory footprint of each process is reported based on the number of pages in memory. The most important part of a low-memory report is the process table. This table lists all running processes, including the system’s daemons when generating low-memory reports. If a process is “abandoned”, a specific reason is attached to the “reason” column. A process may be abandoned for the following reasons:

  • [per-process-limit]: the process has exceeded its maximum memory usage. The resident memory limit for each process is already allocated by the system for each application. Exceeding this limit will cause the process to be killed by the system.

Note: Extensions (nimo: Extension app, such as input methods, etc.) have less maximum memory. Some technologies, such as map view and SpriteKit, take up too much of the base memory to be used in extensions.

  • [VM-pageshortage]/[VM-thrashing]/[VM]: Killed due to system memory stress.
  • [vnode-limit]: Too many files open.

Note: The system tries to avoid killing high-frequency apps when the VNodes are exhausted. So your application can be killed in the background, even if it’s not using any VNodes.

  • [highwater]: a system daemon has passed its memory usage highwater level.
  • [Jettisoned]: A process was killed for some other reason that cannot be described.

If you don’t see the cause in your application or extension, then the cause of crash is not low memory stress. Take a closer look at the. Crash file (described in the previous section).

When you find a low memory crash, rather than worrying about which part of your code is in trouble, you should take a close look at your memory usage habits and how to handle low-memory warnings. Locating Memory Issues in Your App lists how to use the Leaks Instrument tool to check for Memory Leaks, and how to use Allocations Instrument’s Mark Heap feature to avoid Memory waste. The Memory Usage Performance Guidelines discuss how to handle receiving low Memory alarms and how to use Memory efficiently. It is also recommended that you check out the Advanced Memory Analysis with Instruments section in WWDC 2010.

Important :Leaks and Allocation tools don’t detect all memory usage. You will need to run it with the VM Tracker tool (included in the Allocation tool) to see how much memory you are running. The default VM Tracker is not available. To profile your application with VM Tracker, click the Instrument tool and select the “Automatic Snapshotting” TAB or manually click the “Snapshot Now” button.

The related documents

To see how to use the Zombies Template tool to restore a memory free crash, see Eradicating Zombies with the Zombies Trace Template. For archived information, see the App Distribution Guide. For more information about crash logs, see Understanding Crash Reports on iPhone OS WWDC 2010 Session.