What I was trying to ask is something different:
Thanks for the clarification.
It’s easy to recognise when an app crashes due to an unhandled language exception. Specifically:
See the discussion of this in Identifying the Cause of Common Crashes.
In this case the exception message is logged to the system log but it is not captured by the crash report. If you’re working with a user who is having a problem like this, you can ask them to send you a sysdiagnose log taken shortly after the crash. That’ll include the system log and hence the exception message.
If not, things get trickier. There’s a couple of things you can do:
-
If, as in the case with your +[NSJSONSerialization dataWithJSONObject:…]
example, there’s only a few likely candidates for the problem, you can write code that triggers the exception and run it locally. You can then map the offset within the function of your crash to the same offset in your crash report. If they match then you know that the exception message you’re seeing also applies to your crash report.
-
If there aren’t any obvious candidates then the next step is to disassemble the crashed routine to see how the exception message is generated. I’ve included an example of this below.
The biggest drawback with these techniques is that they require you run on the same OS release as the user who hit the crash report. You can match that up using the UUID in the Binary Images section of the crash report.
Consider this snippet for the Last Exception Backtrace:
0 CoreFoundation … __exceptionPreprocess + 220
1 libobjc.A.dylib … objc_exception_throw + 59
2 Foundation … +[NSJSONSerialization dataWithJSONObject:options:error:] + 315
3 MyApp … -[MainViewController tableView:didSelectRowAtIndexPath:] + 26728 (MainViewController.m:17)
Which exception is being thrown in frame 2? If you disassemble the routine you see this:
(lldb) disas -n '+[NSJSONSerialization dataWithJSONObject:options:error:]'
Foundation`+[NSJSONSerialization dataWithJSONObject:options:error:]:
0x1907914e0 <+0>: pacibsp
0x1907914e4 <+4>: sub sp, sp, #0x50 ; =0x50
0x1907914e8 <+8>: stp x24, x23, [sp, #0x10]
0x1907914ec <+12>: stp x22, x21, [sp, #0x20]
0x1907914f0 <+16>: stp x20, x19, [sp, #0x30]
0x1907914f4 <+20>: stp x29, x30, [sp, #0x40]
0x1907914f8 <+24>: add x29, sp, #0x40 ; =0x40
0x1907914fc <+28>: mov x22, x1
0x190791500 <+32>: mov x23, x0
0x190791504 <+36>: cbz x2, 0x190791594 ; <+180>
0x190791508 <+40>: mov x19, x4
0x19079150c <+44>: mov x20, x3
0x190791510 <+48>: mov x21, x2
0x190791514 <+52>: tbnz w20, #0x2, 0x190791530 ; <+80>
0x190791518 <+56>: mov x0, x21
0x19079151c <+60>: bl 0x18f4db7f0 ; _NSIsNSArray
0x190791520 <+64>: tbnz w0, #0x0, 0x190791530 ; <+80>
0x190791524 <+68>: mov x0, x21
0x190791528 <+72>: bl 0x18f4db988 ; _NSIsNSDictionary
0x19079152c <+76>: tbz w0, #0x0, 0x1907915c0 ; <+224>
0x190791530 <+80>: adrp x8, 348516
0x190791534 <+84>: ldr x0, [x8, #0x450]
0x190791538 <+88>: bl 0x18f54fbd0 ; symbol stub for: objc_alloc_init
0x19079153c <+92>: bl 0x18f54fbf0 ; symbol stub for: objc_autorelease
0x190791540 <+96>: mov x22, x0
0x190791544 <+100>: adrp x8, 322262
0x190791548 <+104>: add x1, x8, #0xc72 ; =0xc72
0x19079154c <+108>: mov x2, x21
0x190791550 <+112>: mov x3, x20
0x190791554 <+116>: bl 0x18f0f4830
0x190791558 <+120>: mov x20, x0
0x19079155c <+124>: cbz x19, 0x190791578 ; <+152>
0x190791560 <+128>: cbnz x20, 0x190791578 ; <+152>
0x190791564 <+132>: adrp x8, 321279
0x190791568 <+136>: add x1, x8, #0x4b4 ; =0x4b4
0x19079156c <+140>: mov x0, x22
0x190791570 <+144>: bl 0x18f0f4830
0x190791574 <+148>: str x0, [x19]
0x190791578 <+152>: mov x0, x20
0x19079157c <+156>: ldp x29, x30, [sp, #0x40]
0x190791580 <+160>: ldp x20, x19, [sp, #0x30]
0x190791584 <+164>: ldp x22, x21, [sp, #0x20]
0x190791588 <+168>: ldp x24, x23, [sp, #0x10]
0x19079158c <+172>: add sp, sp, #0x50 ; =0x50
0x190791590 <+176>: retab
0x190791594 <+180>: adrp x8, 348515
0x190791598 <+184>: ldr x19, [x8, #0x4c0]
0x19079159c <+188>: mov x0, x23
0x1907915a0 <+192>: mov x1, x22
0x1907915a4 <+196>: bl 0x19086ec68 ; _NSMethodExceptionProem
0x1907915a8 <+200>: adrp x8, 348507
0x1907915ac <+204>: ldr x1, [x8, #0xbd0]
0x1907915b0 <+208>: str x0, [sp]
0x1907915b4 <+212>: adrp x2, 402695
0x1907915b8 <+216>: add x2, x2, #0xbe0 ; =0xbe0
0x1907915bc <+220>: b 0x1907915e8 ; <+264>
0x1907915c0 <+224>: adrp x8, 348515
0x1907915c4 <+228>: ldr x19, [x8, #0x4c0]
0x1907915c8 <+232>: mov x0, x23
0x1907915cc <+236>: mov x1, x22
0x1907915d0 <+240>: bl 0x19086ec68 ; _NSMethodExceptionProem
0x1907915d4 <+244>: adrp x8, 348507
0x1907915d8 <+248>: ldr x1, [x8, #0xbd0]
0x1907915dc <+252>: str x0, [sp]
0x1907915e0 <+256>: adrp x2, 402695
0x1907915e4 <+260>: add x2, x2, #0xc00 ; =0xc00
0x1907915e8 <+264>: mov x0, x19
0x1907915ec <+268>: bl 0x18f0f4830
0x1907915f0 <+272>: mov x3, x0
0x1907915f4 <+276>: adrp x8, 348515
0x1907915f8 <+280>: ldr x0, [x8, #0x510]
0x1907915fc <+284>: adrp x8, 348478
0x190791600 <+288>: ldr x8, [x8, #0xd08]
0x190791604 <+292>: ldr x2, [x8]
0x190791608 <+296>: adrp x8, 319561
0x19079160c <+300>: add x1, x8, #0x57c ; =0x57c
0x190791610 <+304>: mov x4, #0x0
0x190791614 <+308>: bl 0x18f0f4830
0x190791618 <+312>: bl 0x18f54fcb0 ; symbol stub for: objc_exception_throw
The instruction at +312 is what actually throws the exception. If you look through the code you see there are two ways into this:
-
At +36 there’s a test for nil
which branches to +180. At +220 this branches to +264, which gets you to the code that throws the exception.
-
At +76 there’s a type test which branches to +224. This falls through to the exception throwing code at +264.
In each case the message is set up at the end of the block. Consider this:
0x1907915b4 <+212>: adrp x2, 402695
0x1907915b8 <+216>: add x2, x2, #0xbe0 ; =0xbe0
This is a key structure in 64-bit Arm code in that it calculates a PC-relative address. The adrp
instruction takes the PC, masks off the bottom 12 bits, then adds in the argument shifted left by 12 bits. And the add
instruction just adds the immediate value to its input. Together these form an expression like this:
(lldb) p/a (0x1907915b4 & ~0x0fff) + (402695 << 12) + 0xbe0
(long) $8 = 0x00000001f2c98be0 @"%@: value parameter is nil"
LLDB is smart enough to work out that this is an NSString
pointer and print the literal. Yay!
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"