What would be the best approach patch-finding the pointer of a certain function on the XNU Kernel? - ios

I am currently working on an iOS Jailbreak for iOS 13.7.
As part of the jailbreak, I need to do a series of patches to the XNU Kernel live in the memory.
Of course, the kernel is protected by kASLR, KPP / KTRR, and other memory watchdogs that would trigger a Kernel Panic if something is modified.
As luck would have it, KTRR (Kernel Text Ready Only Region) can only protect, well, static data that is not supposed to change (i.e. the TEXT section and constants). The variables can still be altered.
I am building a PatchFinder which is supposed to locate a function or a variable in the XNU memory based on tell-tale symbols and I am wondering what would be the most effective approach for this.
I am currently adapting on top of the PatchFinder made publicly available back in the iOS 8 era by in7egal which looks like this:
uint32_t find_cs_enforcement_disable_amfi(uint32_t region, uint8_t* kdata, size_t ksize)
{
// Find a function referencing cs_enforcement_disable_amfi
const uint8_t search_function[] = {0x20, 0x68, 0x40, 0xF4, 0x40, 0x70, 0x20, 0x60, 0x00, 0x20, 0x90, 0xBD};
uint8_t* ptr = memmem(kdata, ksize, search_function, sizeof(search_function));
if(!ptr)
return 0;
// Only LDRB in there should try to dereference cs_enforcement_disable_amfi
uint16_t* ldrb = find_last_insn_matching(region, kdata, ksize, (uint16_t*) ptr, insn_is_ldrb_imm);
if(!ldrb)
return 0;
// Weird, not the right one.
if(insn_ldrb_imm_imm(ldrb) != 0 || insn_ldrb_imm_rt(ldrb) > 12)
return 0;
// See what address that LDRB is dereferencing
return find_pc_rel_value(region, kdata, ksize, ldrb, insn_ldrb_imm_rn(ldrb));
}
I wonder if there is any faster way or a more reliable way to locate the cs_enforcement_disable_amfi.
Once found by the PatchFinder in the XNU Kernel memory, it's used like this:
uint32_t cs_enforcement_disable_amfi = find_cs_enforcement_disable_amfi(kernel_base, kdata, ksize);
printf("cs_enforcement_disable_amfi is at=0x%08x\n",cs_enforcement_disable_amfi);
if (cs_enforcement_disable_amfi){
char patch[] ="\x00\xbf\x00\xbf\x00\xbf\x00\xbf\x00\xbf";
kern_return_t kernret = vm_write(proccessTask, cs_enforcement_disable_amfi+kernel_base, patch, sizeof(patch)-1);
if (kernret == KERN_SUCCESS){
printf("Successfully patched cs_enforcement_disable_amfi\n");
}
}
So the PatchFinder has to be able to reliably return the pointer to cs_enforcement_disable_amfi otherwise I am blindly writing to an invalid (or valid but different) address which almost certainly will trigger memory corruption.
The current code does return a valid pointer to cs_enforcement_disable_amfi most of the time, but randomly panics the kernel about 10-15% of the time which means the address it returns 10-15% of the time is invalid. Not sure how to make it more reliable.

The variable you're looking for doesn't exist anymore.
The bytes in your first snippet make up Thumb instructions, which find this function in AMFI in a 32bit kernelcache:
0x8074ad04 90b5 push {r4, r7, lr}
0x8074ad06 01af add r7, sp, 4
0x8074ad08 0d48 ldr r0, [0x8074ad40]
0x8074ad0a 7844 add r0, pc
0x8074ad0c 0078 ldrb r0, [r0]
0x8074ad0e 0128 cmp r0, 1
0x8074ad10 03d1 bne 0x8074ad1a
0x8074ad12 0020 movs r0, 0
0x8074ad14 00f04efa bl 0x8074b1b4
0x8074ad18 30b9 cbnz r0, 0x8074ad28
0x8074ad1a 7c69 ldr r4, [r7, 0x14]
0x8074ad1c 002c cmp r4, 0
0x8074ad1e 05d0 beq 0x8074ad2c
0x8074ad20 2068 ldr r0, [r4]
0x8074ad22 40f44070 orr r0, r0, 0x300
0x8074ad26 2060 str r0, [r4]
0x8074ad28 0020 movs r0, 0
0x8074ad2a 90bd pop {r4, r7, pc}
Given the magic constant 0x300 and the fact that AMFI's __TEXT_EXEC segment is quite small, we can easily find this in other kernels, including 64bit ones.
This is what it looks like on an iPhone 5s on 8.4:
0xffffff800268d2e4 f44fbea9 stp x20, x19, [sp, -0x20]!
0xffffff800268d2e8 fd7b01a9 stp x29, x30, [sp, 0x10]
0xffffff800268d2ec fd430091 add x29, sp, 0x10
0xffffff800268d2f0 f30307aa mov x19, x7
0xffffff800268d2f4 e8fc1110 adr x8, section.com.apple.driver.AppleMobileFileIntegrity.10.__DATA.__bss
0xffffff800268d2f8 1f2003d5 nop
0xffffff800268d2fc 08054039 ldrb w8, [x8, 1]
0xffffff800268d300 a8000037 tbnz w8, 0, 0xffffff800268d314
0xffffff800268d304 130100b4 cbz x19, 0xffffff800268d324
0xffffff800268d308 680240b9 ldr w8, [x19]
0xffffff800268d30c 08051832 orr w8, w8, 0x300
0xffffff800268d310 680200b9 str w8, [x19]
0xffffff800268d314 00008052 mov w0, 0
0xffffff800268d318 fd7b41a9 ldp x29, x30, [sp, 0x10]
0xffffff800268d31c f44fc2a8 ldp x20, x19, [sp], 0x20
0xffffff800268d320 c0035fd6 ret
But by the time of iOS 11, the variable is gone:
0xfffffff006245d84 f44fbea9 stp x20, x19, [sp, -0x20]!
0xfffffff006245d88 fd7b01a9 stp x29, x30, [sp, 0x10]
0xfffffff006245d8c fd430091 add x29, sp, 0x10
0xfffffff006245d90 f30307aa mov x19, x7
0xfffffff006245d94 130100b4 cbz x19, 0xfffffff006245db4
0xfffffff006245d98 680240b9 ldr w8, [x19]
0xfffffff006245d9c 08051832 orr w8, w8, 0x300
0xfffffff006245da0 680200b9 str w8, [x19]
0xfffffff006245da4 00008052 mov w0, 0
0xfffffff006245da8 fd7b41a9 ldp x29, x30, [sp, 0x10]
0xfffffff006245dac f44fc2a8 ldp x20, x19, [sp], 0x20
0xfffffff006245db0 c0035fd6 ret
Looking at iOS 12.0b1, we can learn the signature of that function:
_vnode_check_exec(ucred*, vnode*, vnode*, label*, label*, label*, componentname*, unsigned int*, void*, unsigned long)
So yeah, finding this function is really easy:
Find AMFI's __TEXT_EXEC segment.
Find an orr wN, wN, 0x300 in it.
But that won't help you unless you defeat kernel integrity.

Related

overreleased while already deallocating (object set to nil) for SCNNodes in iOS SceneKit

Seeking for help for an issue, apologize if it is obvious as I am not experienced. My environment is Xcode 10.1 and Swift.
weak var node = Label(geometry: label, labelType: labelType, index: index)
if node != nil {
transformTextNodeCenter(for: node!) //move pivot to center
node!.scale = SCNVector3(x: parameters.textScaleRatio, y: parameters.textScaleRatio, z: parameters.textScaleRatio) //rescale the textnode
print(node!) //print no.1
print(node!.labelType, node!.index, node!.boundingBox) //print no.2
let textWidth = node!.boundingBox.max.x - node!.boundingBox.min.x //<- This is the line generate error
let textHeight = node!.boundingBox.max.y - node!.boundingBox.min.y
let maxWidth = max(textWidth, recordedWidth)
node!.position = position + SCNVector3(x: extra.x * textWidth, y: extra.y * textWidth, z: extra.z * textWidth)
node!.eulerAngles = eulerAngles
node!.name = String("\(name)\(text)")
self.label[labelArray].append(node!)
//self.label.insert(node)
self.addChildNode(node!)
} else {
print("node == nil")
}
The purpose of the function is to add SCNText into my scene, but there is a possibility my textnode will be deallocated in the middle of function (I put it in a for loop and it runs randomly several loop before crash) see pic. 1
It looks like the node initialed properly as it can pass the if node != nil" statement, and print no.2 as follows
"row 0 (min: __C.SCNVector3(x: 0.7861328, y: 1.2421875, z: 0.0), max: __C.SCNVector3(x: 18.325195, y: 10.211914, z: 0.0))"
This makes me believe I have successfully receive boundingBox of the textnode. But it failed at the next line "let textHeight = node!.boundingBox.max.y - node!.boundingBox.min.y".
When crashed, I try to trace it and it shows the node is nil as pic. 2
& pic. 3.
I read some post on so and follow the instruction to set break point on objc_overrelease_during_dealloc_error, but it leads me to "SCNBoundingVolume.boundingBox.getter"
libswiftSceneKit.dylib(extension in SceneKit):__C.SCNBoundingVolume.boundingBox.getter : (min: __C.SCNVector3, max: __C.SCNVector3):
0x10205167c <+0>: sub sp, sp, #0x30 ; =0x30
0x102051680 <+4>: stp x29, x30, [sp, #0x20]
0x102051684 <+8>: add x29, sp, #0x20 ; =0x20
0x102051688 <+12>: nop
0x10205168c <+16>: ldr x8, #0x29d4 ; (void *)0x000000021e95aa28: SCNVector3Zero
0x102051690 <+20>: ldp w9, w10, [x8]
0x102051694 <+24>: ldr w8, [x8, #0x8]
0x102051698 <+28>: stp w9, w10, [sp, #0x10]
0x10205169c <+32>: str w8, [sp, #0x18]
0x1020516a0 <+36>: stp w9, w10, [sp]
0x1020516a4 <+40>: str w8, [sp, #0x8]
0x1020516a8 <+44>: nop
0x1020516ac <+48>: ldr x1, #0x2e9c ; "getBoundingBoxMin:max:"
0x1020516b0 <+52>: add x2, sp, #0x10 ; =0x10
0x1020516b4 <+56>: mov x3, sp
0x1020516b8 <+60>: mov x0, x20
0x1020516bc <+64>: bl 0x102053310 ; symbol stub for: objc_msgSend
0x1020516c0 <+68>: ldr w1, [sp, #0x18]
0x1020516c4 <+72>: ldr x0, [sp, #0x10]
0x1020516c8 <+76>: ldr w8, [sp]
0x1020516cc <+80>: ldur x2, [sp, #0x4]
0x1020516d0 <+84>: bfi x1, x8, #32, #32
0x1020516d4 <+88>: ldp x29, x30, [sp, #0x20]
0x1020516d8 <+92>: add sp, sp, #0x30 ; =0x30
0x1020516dc <+96>: ret
And I can't find a way to interpret it.
P.S. strong var still result to crash but with different error message "EXC_BAD_ACCESS" as pic4.

HomeKit crashes reason: '-[__NSDate length]: but Bool sent

tl;dr - The code in the question is correct. Reason for crash at another party.
The challenge is to control an Elgato Eve Energy HomeKit enabled outlet.
Up til where the code starts, everything is working OK, so the correct room, accessory and so on is selected. The code does turn off the outlet, but right afterwards the app crashes.
guard let services = accessory?.services else {
print("No Service")
return
}
for service in services {
if service.serviceType == HMServiceTypeOutlet {
for characteristic in service.characteristics {
print(characteristic.characteristicType)
if characteristic.characteristicType == HMCharacteristicTypePowerState {
print(characteristic.metadata!)
dump(characteristic)
// Turning off the outlet
characteristic.writeValue(false, completionHandler: { (error: Error?) -> Void in
if error == nil {
print("Yep")
} else {
print("Nop")
}
})
}
}
}
}
Log
00000023-0000-1000-8000-0026BB765291
00000025-0000-1000-8000-0026BB765291
[%# Format: bool, Manufacturer Description: Power State ]
- <HMCharacteristic: 0x1702c23e0> #0
- super: NSObject
00000026-0000-1000-8000-0026BB765291
E863F10A-079E-48FF-8F27-9C2605A29F52
E863F126-079E-48FF-8F27-9C2605A29F52
E863F10D-079E-48FF-8F27-9C2605A29F52
E863F10C-079E-48FF-8F27-9C2605A29F52
2017-02-07 23:19:59.725340 POS[499:100178] -[__NSDate length]: unrecognized selector sent to instance 0x170007710
2017-02-07 23:19:59.725767 POS[499:100178] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSDate length]: unrecognized selector sent to instance 0x170007710'
*** First throw call stack:
(0x188a291b8 0x18746055c 0x188a30268 0x188a2d270 0x18892680c 0x1895be458 0x1895be350 0x1895be698 0x1006328f8 0x1a249ac8c 0x199674f34 0x19966c588 0x1a249d194 0x101951258 0x101951218 0x10195eaec 0x101954ce0 0x10195f088 0x101960e2c 0x101960b78 0x187abb2a0 0x187abad8c)
libc++abi.dylib: terminating with uncaught exception of type NSException
Sym
2017-02-08 10:17:47.804825 POS[602:171994] -[__NSDate length]: unrecognized selector sent to instance 0x1740169c0
iZettlePayments`-[NSDictionary(Fractionized) dateForKey:]:
0x100973d88 <+0>: stp x22, x21, [sp, #-48]!
0x100973d8c <+4>: stp x20, x19, [sp, #16]
0x100973d90 <+8>: stp x29, x30, [sp, #32]
0x100973d94 <+12>: add x29, sp, #32 ; =32
0x100973d98 <+16>: mov x19, x0
0x100973d9c <+20>: nop
0x100973da0 <+24>: ldr x20, #861056 ; (void *)0x00000001ad8966b8: NSDateFormatter
0x100973da4 <+28>: nop
0x100973da8 <+32>: ldr x21, #851248 ; "izDateFormatterUsingISO8601"
0x100973dac <+36>: mov x0, x2
0x100973db0 <+40>: bl 0x1009e9b54 ; symbol stub for: objc_retain
0x100973db4 <+44>: mov x22, x0
0x100973db8 <+48>: mov x0, x20
0x100973dbc <+52>: mov x1, x21
0x100973dc0 <+56>: bl 0x1009e9b30 ; symbol stub for: objc_msgSend
0x100973dc4 <+60>: mov x29, x29
0x100973dc8 <+64>: bl 0x1009e9b78 ; symbol stub for: objc_retainAutoreleasedReturnValue
0x100973dcc <+68>: mov x20, x0
0x100973dd0 <+72>: nop
0x100973dd4 <+76>: ldr x1, #849044 ; "valueForKey:"
0x100973dd8 <+80>: mov x0, x19
0x100973ddc <+84>: mov x2, x22
0x100973de0 <+88>: bl 0x1009e9b30 ; symbol stub for: objc_msgSend
0x100973de4 <+92>: mov x19, x0
0x100973de8 <+96>: mov x0, x22
0x100973dec <+100>: bl 0x1009e9b48 ; symbol stub for: objc_release
0x100973df0 <+104>: mov x0, x19
0x100973df4 <+108>: bl 0x1009e9b78 ; symbol stub for: objc_retainAutoreleasedReturnValue
0x100973df8 <+112>: mov x19, x0
0x100973dfc <+116>: nop
0x100973e00 <+120>: ldr x1, #851168 ; "dateFromString:"
0x100973e04 <+124>: mov x0, x20
0x100973e08 <+128>: mov x2, x19
0x100973e0c <+132>: bl 0x1009e9b30 ; symbol stub for: objc_msgSend
0x100973e10 <+136>: mov x29, x29
0x100973e14 <+140>: bl 0x1009e9b78 ; symbol stub for: objc_retainAutoreleasedReturnValue
0x100973e18 <+144>: mov x21, x0
0x100973e1c <+148>: mov x0, x19
0x100973e20 <+152>: bl 0x1009e9b48 ; symbol stub for: objc_release
0x100973e24 <+156>: mov x0, x20
0x100973e28 <+160>: bl 0x1009e9b48 ; symbol stub for: objc_release
0x100973e2c <+164>: mov x0, x21
0x100973e30 <+168>: ldp x29, x30, [sp, #32]
0x100973e34 <+172>: ldp x20, x19, [sp, #16]
0x100973e38 <+176>: ldp x22, x21, [sp], #48
0x100973e3c <+180>: b 0x1009e9ac4 ; symbol stub for: objc_autoreleaseReturnValue
Browsing the Elgato Eve services and characteristics, shows the first characteristic in the array is the one holding the name, and the second one is the one I need to manipulate. The printed metadata shows its a bool, and confirms its the Power State, and its both readable and writable, as described in the table linked to before.
Since I write a false to the correct characteristic, the outlet turns off, but a couple of seconds later, the app crashes. I have removed any observers and delegate methods that could interfere. This really baffles me.
Further, the code does not crash on iOS 9, just iOS 10.2, as well as the 10.3 betas
Solution
Sorry guys, after a whole lot of swearing, a bruised toe, and a lot less hair, and 24 hours later, I found the culprit. Im using iZettle, a payment device, and as soon as the libraries was added to the project, it crashed. The guys over at iZettle admitted they had an extension on NSDictionary
#interface NSDictionary (Fractionized)
- (NSDate *)dateForKey:(id)aKey;
#end
This one collides with an extension in HomeKit, so thats the reason for the problem. The result is they have to add a prefix to their extension and compile the libraries again.
While a symbolicated stack trace would help, there is one symbol in your logs that may provide a useful hint: something is trying to ask an NSDate for length. In my experience, this happens when a library expects something to be an NSString and it's about to parse it or print it or what have you.
Perhaps you know where NSDates are being used. It will also help to know if the crash is on the same thread that is executing your above code. Given that you are experiencing a slight delay, it's hard to say if it is related to that code at all! Perhaps elsewhere in your app, you are responding to the device itself giving you a status update, and maybe printing a value that you think is a string but is really a date?

How do I track down this exception

I am getting this exception thrown at a certain point in the App but can't track down the cause. I assume its simply a UI call being made from a background thread but I can't find any UI calls that are not made on the main thread.
BTW all UI calls are wrapped in DispatchQueue.main.async{}, presumably I missed something but can't figure out how to track it down.
Any suggestion how to figure out what call is leading to this - there are a few background threads running concurrently as well as events from SNS and Bluetooth.
This application is modifying the autolayout engine from a background thread after the engine was accessed from the main thread. This can lead to engine corruption and weird crashes.
Stack:(
0 CoreFoundation 0x000000018fc8e1d8 <redacted> + 148
1 libobjc.A.dylib 0x000000018e6c855c objc_exception_throw + 56
2 CoreFoundation 0x000000018fc8e108 <redacted> + 0
3 Foundation 0x0000000190875ea4 <redacted> + 192
4 Foundation 0x00000001906bd3fc <redacted> + 36
5 UIKit 0x0000000196434770 <redacted> + 72
6 UIKit 0x0000000195ae61e8 <redacted> + 1140
7 QuartzCore 0x0000000192fa6188 <redacted> + 148
8 QuartzCore 0x0000000192f9ae64 <redacted> + 292
9 QuartzCore 0x0000000192f9ad24 <redacted> + 32
10 QuartzCore 0x0000000192f177ec <redacted> + 252
11 QuartzCore 0x0000000192f3ec58 <redacted> + 512
12 QuartzCore 0x0000000192f3f124 <redacted> + 660
13 libsystem_pthread.dylib 0x000000018ed22fbc <redacted> + 572
14 libsystem_pthread.dylib 0x000000018ed22ce4 <redacted> + 200
15 libsystem_pthread.dylib 0x000000018ed22378 pthread_mutex_lock + 0
16 libsystem_pthread.dylib 0x000000018ed21da4 start_wqthread + 4
)
OK So I added the Breakpoint but I just get the following on thread 10 (!) I can't figure out what could be running on Thread 10 or what UI code is being called.
libobjc.A.dylib`objc_exception_throw:
-> 0x18e6c8524 <+0>: stp x28, x27, [sp, #-64]!
0x18e6c8528 <+4>: stp x22, x21, [sp, #16]
0x18e6c852c <+8>: stp x20, x19, [sp, #32]
0x18e6c8530 <+12>: stp x29, x30, [sp, #48]
0x18e6c8534 <+16>: add x29, sp, #48 ; =48
0x18e6c8538 <+20>: sub sp, sp, #4032 ; =4032
0x18e6c853c <+24>: mov x20, x0
0x18e6c8540 <+28>: orr w0, wzr, #0x20
0x18e6c8544 <+32>: bl 0x18e6b6c24 ; __cxa_allocate_exception
0x18e6c8548 <+36>: mov x19, x0
0x18e6c854c <+40>: adrp x8, 157305
0x18e6c8550 <+44>: ldr x8, [x8, #408]
0x18e6c8554 <+48>: mov x0, x20
0x18e6c8558 <+52>: blr x8
0x18e6c855c <+56>: mov x20, x0
0x18e6c8560 <+60>: adrp x8, 151285
0x18e6c8564 <+64>: ldr x1, [x8]
0x18e6c8568 <+68>: bl 0x18e6daf20 ; objc_msgSend
0x18e6c856c <+72>: str x20, [x19]
0x18e6c8570 <+76>: adrp x8, 151286
0x18e6c8574 <+80>: add x8, x8, #160 ; =160
0x18e6c8578 <+84>: add x8, x8, #16 ; =16
0x18e6c857c <+88>: mov x21, x19
0x18e6c8580 <+92>: str x8, [x21, #8]!
0x18e6c8584 <+96>: mov x0, x20
0x18e6c8588 <+100>: bl 0x18e6c681c ; object_getClassName
0x18e6c858c <+104>: str x0, [x19, #16]
0x18e6c8590 <+108>: cbnz x20, 0x18e6c859c ; <+120>
0x18e6c8594 <+112>: movz x8, #0
0x18e6c8598 <+116>: b 0x18e6c85e0 ; <+188>
0x18e6c859c <+120>: tbz x20, #63, 0x18e6c85d8 ; <+180>
0x18e6c85a0 <+124>: lsr x8, x20, #60
0x18e6c85a4 <+128>: cmp x8, #15 ; =15
0x18e6c85a8 <+132>: lsr x8, x20, #57
0x18e6c85ac <+136>: and x8, x8, #0x78
0x18e6c85b0 <+140>: adrp x9, 157305
0x18e6c85b4 <+144>: add x9, x9, #544 ; =544
0x18e6c85b8 <+148>: add x8, x9, x8
0x18e6c85bc <+152>: lsr x9, x20, #52
0x18e6c85c0 <+156>: adrp x10, 157305
0x18e6c85c4 <+160>: add x10, x10, #672 ; =672
0x18e6c85c8 <+164>: add x9, x10, w9, uxtb #3
0x18e6c85cc <+168>: csel x8, x8, x9, lo
0x18e6c85d0 <+172>: ldr x8, [x8]
0x18e6c85d4 <+176>: b 0x18e6c85e0 ; <+188>
0x18e6c85d8 <+180>: ldr x8, [x20]
0x18e6c85dc <+184>: and x8, x8, #0xffffffff8
0x18e6c85e0 <+188>: str x8, [x19, #24]
0x18e6c85e4 <+192>: adrp x22, 151466
0x18e6c85e8 <+196>: add x22, x22, #1958 ; =1958
0x18e6c85ec <+200>: ldrb w8, [x22]
0x18e6c85f0 <+204>: cbz w8, 0x18e6c8610 ; <+236>
0x18e6c85f4 <+208>: mov x0, x20
0x18e6c85f8 <+212>: bl 0x18e6c681c ; object_getClassName
0x18e6c85fc <+216>: stp x20, x0, [sp, #8]
0x18e6c8600 <+220>: str x19, [sp]
0x18e6c8604 <+224>: adrp x0, 29
0x18e6c8608 <+228>: add x0, x0, #2192 ; =2192
0x18e6c860c <+232>: bl 0x18e6c7f00 ; _objc_inform
0x18e6c8610 <+236>: adrp x8, 151466
0x18e6c8614 <+240>: add x8, x8, #1959 ; =1959
0x18e6c8618 <+244>: ldrb w8, [x8]
0x18e6c861c <+248>: cbz w8, 0x18e6c8674 ; <+336>
0x18e6c8620 <+252>: ldrb w8, [x22]
0x18e6c8624 <+256>: cbnz w8, 0x18e6c8644 ; <+288>
0x18e6c8628 <+260>: mov x0, x20
0x18e6c862c <+264>: bl 0x18e6c681c ; object_getClassName
0x18e6c8630 <+268>: stp x20, x0, [sp, #8]
0x18e6c8634 <+272>: str x19, [sp]
0x18e6c8638 <+276>: adrp x0, 29
0x18e6c863c <+280>: add x0, x0, #2192 ; =2192
0x18e6c8640 <+284>: bl 0x18e6c7f00 ; _objc_inform
0x18e6c8644 <+288>: movz w1, #0x1f4
0x18e6c8648 <+292>: add x0, sp, #32 ; =32
0x18e6c864c <+296>: bl 0x18eb7709c ; backtrace
0x18e6c8650 <+300>: mov x22, x0
0x18e6c8654 <+304>: adrp x8, 132269
0x18e6c8658 <+308>: ldr x8, [x8, #48]
0x18e6c865c <+312>: ldr x0, [x8]
0x18e6c8660 <+316>: bl 0x18eb7a548 ; fileno
0x18e6c8664 <+320>: mov x2, x0
0x18e6c8668 <+324>: add x0, sp, #32 ; =32
0x18e6c866c <+328>: mov x1, x22
0x18e6c8670 <+332>: bl 0x18eb86804 ; backtrace_symbols_fd
0x18e6c8674 <+336>: mov x0, x20
0x18e6c8678 <+340>: nop
0x18e6c867c <+344>: adrp x2, 0
0x18e6c8680 <+348>: add x2, x2, #1680 ; =1680
0x18e6c8684 <+352>: mov x0, x19
0x18e6c8688 <+356>: mov x1, x21
0x18e6c868c <+360>: bl 0x18e6e4764 ; symbol stub for: +[NSObject resolveInstanceMethod:]
EDIT:
OK I got lucky and found a notification that was not wrapped in a main thread call. Turns out it was a property changed from a background thread triggering a notification. Surprisingly difficult to find the UI Code that was being called. I must be doing something wrong.
Try implementing UI changes in main queue.
Swift 3:
OperationQueue.main.addOperation({
// Update UI
})
Did you add all exception break point? It can help.
You are right, it's due to UI modification from background. Can you add an exception breakpoint in xCode and try to determine, where is this call?
After that, you can place this call in
DispatchQueue.main.async { your call }
for swift, or gcd version for Objective C
I'll add a few steps to #mkeremkeskin's answer:
Step by step:
Go to the Breakpoint Navigator: Breakpoint Navigator
Add an Exception Breakpoint: Exception Breakpoint
Make it throw on All Exceptions
You should be able to track down the exception now.
You shouldn't do any changes related to UIKit objects in background thread. They should be done in main thread as stated by Apple in it's developer documentation.
Note
For the most part, use UIKit classes only from your app’s main thread. This is particularly true for classes derived from UIResponder or that involve manipulating your app’s user interface in any way.
If you're doing some operations in background thread and need to update UIKit elements. You can do it in the following way
dispatch_async(dispatch_get_main_queue(), ^{
});
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
}];
In swift3,
DispatchQueue.main.async {
}
OperationQueue.main.addOperation {
}
For detecting where you're getting exception, you can do that using exception breakpoint. You can do that as shown in the pictures given below:

Bare metal assembly - data not initialized

I wrote some very simple code, aimed to work on bare metal RaspberryPi. My code consists of gpio.s (with function "flash", which turns LED on and off) and main.s, shown below.
.section .init
.globl _start
_start:
mov sp, $0x8000
b main
.section .text
.globl main
main:
ldr r5, =variable
ldr r4, [r5]
cmp r4, $100
bleq flash
loop:
b loop
.section .data
.align 4
.globl variable
variable:
.word 100
So r4 should be filled with 100 => condition flag should be eq => LED should flash! But it does not. Why?
Apart from that example, function "flash" works, as well as in the case of adding these lines after "ldr r5, =variable":
mov r1, $100
str r1, [r5]
So it seems like memory is accessible, but doesn't get initialized. I would be grateful for your explanations.
Disassembly:
./build/output.elf: file format elf32-littlearm
Disassembly of section .init:
00000000 <_start>:
0: e3a0d902 mov sp, #32768 ; 0x8000
4: ea00205c b 817c <main>
Disassembly of section .text:
00008000 <getGpioAddr>:
8000: e59f0170 ldr r0, [pc, #368] ; 8178 <flash2+0x14>
8004: e1a0f00e mov pc, lr
00008008 <setGpioFunct>:
8008: e3500035 cmp r0, #53 ; 0x35
800c: 93510007 cmpls r1, #7 ; 0x7
8010: 83a00001 movhi r0, #1 ; 0x1
8014: 81a0f00e movhi pc, lr
8018: e92d0030 push {r4, r5}
801c: e1a02001 mov r2, r1
8020: e1a01000 mov r1, r0
8024: e92d4000 push {lr}
8028: ebfffff4 bl 8000 <getGpioAddr>
802c: e8bd4000 pop {lr}
8030: e3a04000 mov r4, #0 ; 0x0
00008034 <subTen>:
8034: e351000a cmp r1, #10 ; 0xa
8038: 2241100a subcs r1, r1, #10 ; 0xa
803c: 22844001 addcs r4, r4, #1 ; 0x1
8040: 2afffffb bcs 8034 <subTen>
8044: e3a05004 mov r5, #4 ; 0x4
8048: e0030594 mul r3, r4, r5
804c: e0800003 add r0, r0, r3
8050: e3a05003 mov r5, #3 ; 0x3
8054: e0030591 mul r3, r1, r5
8058: e1a02312 lsl r2, r2, r3
805c: e3e0430e mvn r4, #939524096 ; 0x38000000
8060: e3a05009 mov r5, #9 ; 0x9
8064: e0451001 sub r1, r5, r1
8068: e3a05003 mov r5, #3 ; 0x3
806c: e0030591 mul r3, r1, r5
8070: e1a04374 ror r4, r4, r3
8074: e5905000 ldr r5, [r0]
8078: e0055004 and r5, r5, r4
807c: e1855002 orr r5, r5, r2
8080: e5805000 str r5, [r0]
8084: e8bd0030 pop {r4, r5}
8088: e3a00000 mov r0, #0 ; 0x0
808c: e1a0f00e mov pc, lr
00008090 <setPin>:
8090: e3500035 cmp r0, #53 ; 0x35
8094: 83a00001 movhi r0, #1 ; 0x1
8098: 81a0f00e movhi pc, lr
809c: e92d0020 push {r5}
80a0: e3500020 cmp r0, #32 ; 0x20
80a4: 22401020 subcs r1, r0, #32 ; 0x20
80a8: 31a01000 movcc r1, r0
80ac: 23a02020 movcs r2, #32 ; 0x20
80b0: 33a0201c movcc r2, #28 ; 0x1c
80b4: e92d4000 push {lr}
80b8: ebffffd0 bl 8000 <getGpioAddr>
80bc: e8bd4000 pop {lr}
80c0: e3a05001 mov r5, #1 ; 0x1
80c4: e1a05115 lsl r5, r5, r1
80c8: e7805002 str r5, [r0, r2]
80cc: e3a00000 mov r0, #0 ; 0x0
80d0: e8bd0020 pop {r5}
80d4: e1a0f00e mov pc, lr
000080d8 <clearPin>:
80d8: e3500035 cmp r0, #53 ; 0x35
80dc: 83a00001 movhi r0, #1 ; 0x1
80e0: 81a0f00e movhi pc, lr
80e4: e92d0020 push {r5}
80e8: e3500020 cmp r0, #32 ; 0x20
80ec: 22401020 subcs r1, r0, #32 ; 0x20
80f0: 31a01000 movcc r1, r0
80f4: 23a0202c movcs r2, #44 ; 0x2c
80f8: 33a02028 movcc r2, #40 ; 0x28
80fc: e92d4000 push {lr}
8100: ebffffbe bl 8000 <getGpioAddr>
8104: e8bd4000 pop {lr}
8108: e3a05001 mov r5, #1 ; 0x1
810c: e1a05115 lsl r5, r5, r1
8110: e7805002 str r5, [r0, r2]
8114: e3a00000 mov r0, #0 ; 0x0
8118: e8bd0020 pop {r5}
811c: e1a0f00e mov pc, lr
00008120 <flash>:
8120: e92d4013 push {r0, r1, r4, lr}
8124: e3a00010 mov r0, #16 ; 0x10
8128: e3a01001 mov r1, #1 ; 0x1
812c: ebffffb5 bl 8008 <setGpioFunct>
8130: e3a00010 mov r0, #16 ; 0x10
8134: ebffffe7 bl 80d8 <clearPin>
8138: eb000004 bl 8150 <wait>
813c: e3a00010 mov r0, #16 ; 0x10
8140: ebffffd2 bl 8090 <setPin>
8144: eb000001 bl 8150 <wait>
8148: e8bd4013 pop {r0, r1, r4, lr}
814c: e1a0f00e mov pc, lr
00008150 <wait>:
8150: e3a0583f mov r5, #4128768 ; 0x3f0000
00008154 <loop>:
8154: e2455001 sub r5, r5, #1 ; 0x1
8158: e3550000 cmp r5, #0 ; 0x0
815c: 1afffffc bne 8154 <loop>
8160: e1a0f00e mov pc, lr
00008164 <flash2>:
8164: e92d4000 push {lr}
8168: ebffffec bl 8120 <flash>
816c: ebffffeb bl 8120 <flash>
8170: e8bd4000 pop {lr}
8174: e1a0f00e mov pc, lr
8178: 20200000 .word 0x20200000
0000817c <main>:
817c: e59f500c ldr r5, [pc, #12] ; 8190 <loop+0x4>
8180: e5954000 ldr r4, [r5]
8184: e3540064 cmp r4, #100 ; 0x64
8188: 0bffffe4 bleq 8120 <flash>
0000818c <loop>:
818c: eafffffe b 818c <loop>
8190: 00008194 .word 0x00008194
Disassembly of section .data:
00008194 <variable>:
8194: 00000064 .word 0x00000064
Linker scripts, makefile etc. taken from: http://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/ok01.html
from your link (you should not ask questions here using links, put the code in the question)
0000817c <main>:
817c: e59f500c ldr r5, [pc, #12] ; 8190 <loop+0x4>
8180: e3a01064 mov r1, #100 ; 0x64
8184: e3540064 cmp r4, #100 ; 0x64
8188: 0bffffe4 bleq 8120 <flash>
0000818c <loop>:
818c: eafffffe b 818c <loop>
8190: 000081a0 .word 0x000081a0
Disassembly of section .data:
000081a0 <variable>:
81a0: 00000064 .word 0x00000064
...
you are moving r1 a 100 but comparing r4 which has not been initialized at least in this code, so that is unpredictable what will happen. if you replace that with a mov r4,[r5] it should work as desired as r5 is getting the address of the word that contains the #100 and then you read from that address into r4.
I assume you have verified that if you simply bl flash it works (not a conditional but always go there) as desired?
In this bare metal mode you definitely have access to read/write memory, no worries there.
David
Memory is normally initialized as part of the C runtime code. If you are writing bare-metal assembly without including the functionality of the C runtime then your variables in RAM will not be initialized. You need to explicitly initialize the value of variable in your own code.
Finally found out! Really subtle, and it's not my fault indeed. I had taken the makefile and linker script from Alex Chadwick tutorial, and the linker script looked like that:
SECTIONS {
/*
* First and formost we need the .init section, containing the IVT.
*/
.init 0x0000 : {
*(.init)
}
/*
* We allow room for the ATAGs and the stack and then start our code at
* 0x8000.
*/
.text 0x8000 : {
*(.text)
}
/*
* Next we put the data.
*/
.data : {
*(.data)
}
/*
* Finally comes everything else. A fun trick here is to put all other
* sections into this section, which will be discarded by default.
*/
/DISCARD/ : {
*(*)
}
}
.init section was based at 0x0000, and then the .text started at 0x8000. But actually, kernel.img is loaded at address 0x8000 by Pi (real address of .init was 0x8000), so: whole .text section (as well as the following sections) were shifted - due to that fact, addresses of labels were misassumed at the assembling-linking time. Only pc-relative addressing could work, as PC was set correctly. The solution is to start the image at 0x8000:
SECTIONS {
/*
* First and formost we need the .init section, containing the IVT.
*/
.init 0x8000 : {
*(.init)
}
.text : {
*(.text)
}
/*
* Next we put the data.
*/
.data : {
*(.data)
}
/*
* Finally comes everything else. A fun trick here is to put all other
* sections into this section, which will be discarded by default.
*/
/DISCARD/ : {
*(*)
}
}
I've just checked the template on his website and it's corrected now, so there is no point contacting him. I must have downloaded template before this correction. Thank you guys for your attempts.

Use of stack pointer (sp) in arm assembly

I'm slightly confused by the following bit of disassembly:
_GSEventLockDevice:
000047d8 b5f0 push {r4, r5, r6, r7, lr}
000047da af03 add r7, sp, #12
000047dc b08d sub sp, #52
000047de f7ffffb3 bl _GSGetPurpleSystemEventPort
000047e2 466d mov r5, sp
000047e4 2234 movs r2, #52
000047e6 2100 movs r1, #0
000047e8 4604 mov r4, r0
000047ea 4628 mov r0, r5
000047ec f005e8b0 blx 0x9950 # symbol stub for: _memset
000047f0 2600 movs r6, #0
000047f2 f24030f6 movw r0, 0x3f6
000047f6 4621 mov r1, r4
000047f8 e88d0041 stmia.w sp, {r0, r6}
000047fc 4628 mov r0, r5
000047fe f7fffaf7 bl _GSSendEvent
00004802 b00d add sp, #52
00004804 bdf0 pop {r4, r5, r6, r7, pc}
00004806 bf00 nop
I don't get how this would go in C. The only bit I get is:
memset(whateverTheStackPointerIs, 0, 52);
But how do I know what sp is and how would it look in C?
The
sub sp, #52
reserves 52 bytes of space for local variables on the stack; afterwards sp will point to the first of those 52 bytes. They are all then zeroed with the memset call. After the memset, stmia stores particular values in the first two words. So the C equivalent would be something like
GEEventLockDecvice() {
int tmp = GSGetPurpleSystemEventPort();
int localdata[13] = {0};
localdata[0] = *0x3f6;
localdata[1] = 0;
return GSSendEvent(&localdata, tmp);
}

Resources