Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to debug an iOS extension (.appex)?

How to make log prints appear in Xcode's lldb debugger from extension?

like image 573
Bartłomiej Semańczyk Avatar asked Nov 04 '15 14:11

Bartłomiej Semańczyk


People also ask

How do I debug a shared extension?

Go to that app on your device, create/choose whatever it is in the app that you want to share, click the share icon, choose your extension in the list of active sharing extensions. Then when your sharing extension starts up the debugger will automatically attach to it.


1 Answers

Simple answer:

  • log messages are not printed, however you can stop at breakpoints, and then print everything using lldb.
  1. Run your app
  2. While the app is running, go to Debug -> Attach to process by PID or name

enter image description here

  1. Write the name of your extension (as bundle-id does not work!?), and click "Attach".

enter image description here

  1. Then run your extension with any way you can do this on your device.
  2. Wait for Xcode's debugger to stop the extension at breakpoint, but some may need to call waitForDebugger (which is a custom function, see logic below).

Wait For Debugger example

public static func isDebuggerAttached() -> Bool {
    // Buffer for "sysctl(...)" call's result.
    var info = kinfo_proc()
    // Counts buffer's size in bytes (like C/C++'s `sizeof`).
    var size = MemoryLayout.stride(ofValue: info)
    // Tells we want info about own process.
    var mib : [Int32] = [CTL_KERN, KERN_PROC, KERN_PROC_PID, getpid()]
    // Call the API (and assert success).
    let junk = sysctl(&mib, UInt32(mib.count), &info, &size, nil, 0)
    assert(junk == 0, "sysctl failed")
    // Finally, checks if debugger's flag is present yet.
    return (info.kp_proc.p_flag & P_TRACED) != 0
}

@discardableResult
public static func waitForDebugger(_ timeout: Int = 30000) -> Bool {
    var now: UInt64 = DispatchTime.now().uptimeNanoseconds
    let begin = now
    repeat {
        if isDebuggerAttached() {
            // Wait a little bit longer,
            // because early breakpoints may still not work.
            Thread.sleep(forTimeInterval: 3.0)
            return true
        }
        Thread.sleep(forTimeInterval: 0.1)
        now = DispatchTime.now().uptimeNanoseconds
    } while Double(now - begin) / 1000000.0 < Double(timeout);
    return false;
}
like image 191
Bartłomiej Semańczyk Avatar answered Sep 30 '22 17:09

Bartłomiej Semańczyk