Search code examples
iosxamarinxamarin.ioslldbxamarin-studio

Use lldb to debug native libraries with Xamarin


The Xamarin debugging documentation indicates:

Use Xamarin Studio's native debugging support for debugging C# and other managed languages code and use LLDB when you need to debug C, C++ or Objective C codethat you might be linking with your Xamarin.iOS project.

However I cannot find any documentation on how to use LLDB to debug a Xamarin app. If I run my app in the iPhone Simulator and try to attach to it using LLDB I get the following error:

(lldb) attach --pid 37993
Process 37993 exited with status = -1 (0xffffffff) lost connection

error: attach failed: lost connection

Attaching using Xcode doesn't work either. I tried different variations of attach but none of them worked.

Can someone point me in the correct direction on how to debug Xamarin apps with LLDB? Moreover is this something I could do on the device and not just in the simulator? I didn't find any information on how to use LLDB to attach to a process on a device.

Update

It looks like the debugserver process is crashing whenever I use lldb to connect to my binary. Here is a link to the crash report for debugserver: https://www.dropbox.com/s/9lizhl2quj9n0cc/debugserver_2015-07-07-131423_gauss.crash?dl=0

Update 2

When I run dtruss on the app it prints the system calls till it encounters

dtrace: error on enabled probe ID 2475 (ID 194: syscall::ptrace:return): invalid user access in action #5 at DIF offset 0

which happens when something calls ptrace(PT_DENY_ATTACH, 0, 0, 0); Why is PT_DENY_ATTACH called?

Update 3

I traced the ptrace system call to this function: mono_assembly_init_with_opt which happens very early in the life of the program. All that function does is call ptrace, so if I just return early from that function, I can debug with lldb.

Basically, I can do:

(lldb) process attach --name AppName --waitfor
# when the process starts
(lldb) b mono_assembly_init_with_opt    
(lldb) c
# when the thread breaks
(lldb) thread return 0
(lldb) c

and now I can happily debug with lldb.

But, I shouldn't have to do this. Is there something wrong with my project config (I can debug simpler apps with lldb) or is Xamarin being evil?


Solution

  • This happens to be a limitation imposed by Xamarin in the trial version. After upgrading to a paid license, this is no longer an issue. Even though Xamarin's website says:

    When you begin a Xamarin Trial, you get access to the full Xamarin Business feature set for 30 days.

    It's clearly not the full feature set since they explicitly disable attaching lldb to the app if you are using a native library. I'm not sure the reason for doing so, maybe someone from Xamarin can comment on it.

    Explanation

    Thanks to Jim Ingham for pointing me in the right direction. The way Xamarin events debuggers from attaching to the app is by calling ptrace with PT_DENY_ATTACH. This system call enables the process to deny requests for debugging. (Detailed Explanation).

    Moreover rather than calling the ptrace function directly, Xamarin tries to hide the call by using the syscall method (link).

    Workaround

    If you really need to debug your app and are still using the trial version, here is a workaround. The ptrace system call is made in the function mono_assembly_init_with_opt which happens very early in the life of the program. That function doesn't do anything else and can be skipped. Since the function is called right in the beginning of the process, we need to attach lldb before the function is called.

    The steps are as follows:

    1. Start lldb and wait for the app to start.
    2. When the app starts, add a break point for mono_assembly_init_with_opt
    3. Resume the app and when it stops at that function, return early without executing that function.
    4. After this you can use lldb or attach Xcode to the app and debug your native code as usual.

    Steps in lldb:

    (lldb) process attach --name AppName --waitfor
    (lldb) b mono_assembly_init_with_opt    
    (lldb) c
    # when the thread breaks
    (lldb) thread return 0
    (lldb) c