Debugging Krita on Android

 Debugging Krita on Android

Well, the easiest way is to use Android Studio.

Import the project in Android Studio as a gradle project and build the project. Krita build will fail when run from Android Studio. Now, to run it successfully, we’ll have to manually provide the path to installPrefix or comment out copyLibs dependency. Now, the project should build properly.

You might want to change the debug type to Native or Dual, as their Auto mode did not work for me. Open the C++ file in Android Studio and set a breakpoint. Click the bug icon, sit back and watch while Android Studio does all the magic for you.

And then it is usual lldb (in Android Studio) or GUI if that’s what you prefer.

Using command line:

Starting Android studio takes a lot of time and memory. Then, it builds which takes an additional few minutes, so it really isn’t a good idea to use it for debugging every time the app crashes. So, the less time consuming one and a bit complex method – here we go!

Assuming the app has been installed with the debug key. The first step is to launch it in debug mode, to do so:

# domain/(launcher activity or exported activity's class-path)
$ adb shell am start -D -n "org.kde.krita/org.krita.android.MainActivity"

Now the app on phone should launch and show Waiting for Debugger message. While it waits – open a terminal and enter $ adb shell, and then look for lldb-server in /data/local/tmp/. If you ever debugged app through Android Studio, then it should exist. If it does not, then launch Android Studio and run it in debug mode 😂…hahahaha.

Just kidding, push the file to that location.

$ adb push $ANDROID_SDK_ROOT/lldb/<version>/android/<abi>/lldb-server /data/local/tmp
$ adb shell chmod +x /data/local/tmp/lldb-server

(No lldb directory? See notes)

Then for us to access the libraries, we’ll have to copy it to /data/data/org.kde.krita, for that:

$ adb shell run-as org.kde.krita cp /data/local/tmp/lldb-server /data/data/org.kde.krita

(Why run-as? It is a setuid program and gives us the necessary permission to access the sandbox).

Now, enter the app sandbox by first entering the $ adb shell and then $ run-as org.kde.krita.

Run the lldb-server like you would if you were remote debugging.

$ ./lldb-server platform --server --listen "<incoming-ip>:<port>"
$ # Example: allow any ip on port 9999
$ ./lldb-server platform --server --listen "*:9999"

Now on the host machine, run lldb and then

(lldb) platform select remote-android
(lldb) platform connect connect://<ip>:<port>

On my machine:

(lldb) platform select remote-android
  Platform: remote-android
 Connected: no
(lldb) platform connect connect://localhost:9999
  Platform: remote-android
    Triple: arm-*-linux-android
OS Version: 28.0.0 (4.4.153-15659493)
    Kernel: #2 SMP PREEMPT Thu Apr 4 18:31:57 KST 2019
  Hostname: localhost
 Connected: yes
WorkingDir: /data/data/org.kde.krita

You can read more about what they do on LLVM’s website.
(This is one a time setup you can keep the server and client connected)

Remember, that our process is still Waiting for Debugger? :(
Let’s give it what it wants. Attach the debugger to the running process’s pid, which can be known by $ adb shell ps | grep "krita" or $ pgrep "krita"

To attach:

(lldb) attach <pid>
(lldb) # on my machine
(lldb) attach 1818
Process 1818 stopped
* thread #1, name = 'org.kde.krita', stop reason = signal SIGSTOP
    frame #0: 0xe8d35f7c libc.so`syscall + 28
<and much more>

Still didn’t continue? :-<
So, let’s finally resume it!

We’ll have to resume it over Java Debug Wire Protocol (JDWP), we’ll use jdb

$ adb forward tcp:12345 jdwp:<pid> # the same pid which we attached in lldb
$ jdb -attach localhost:12345

Now continue the process in lldb and we are done!

(This might seem like a lot, but it really isn’t. Every time the app crashes, I run in debug mode $ attach pid and I get the backtrace immediately!)

PS: When I was looking for it on the internet, I didn’t find much about it and had to spend a lot of time on this.
This method should work with debugging any android app with lldb, obv!
(I am really new to blogging. If it’s hard to understand or my formatting is bad, I am really sorry.)

Notes

  • I hate the extra jdb thing, and if the function which you want to debug is not going to be called during the early start up, you can use -N flag instead of -D with am.
  • Can’t find lldb directory in your SDK? Use platform tools to install it.
  • jdb doesn’t attach? $ killall android-studio && adb kill-server #_#

Resources

https://source.android.com/devices/tech/debug/gdb
https://android.googlesource.com/platform/ndk/+/master/ndk-gdb.py
https://lldb.llvm.org/use/remote.html

5 comments:

  1. Hi, I'm debugging an app in LLDB, but the following errors always happen.
    (lldb) platform select remote-android
    Platform: remote-android
    Connected: no
    (lldb) platform connect connect://localhost:6002
    Platform: remote-android
    Triple: aarch64-unknown-linux-android
    OS Version: 27 (3.10.73-ElementalX-N5X-6.12)
    Kernel: #1 SMP PREEMPT Mon Dec 3 15:39:39 EST 2018
    Hostname: localhost
    Connected: yes
    WorkingDir: /system/bin
    (lldb) process attach --pid 543
    Process 543 stopped
    * thread #1, name = 'e.myapplication', stop reason = signal SIGSTOP
    frame #0: 0x00000016fd40a3f8
    error: memory read failed for 0x16fd40a000
    thread #2, name = 'Jit thread pool', stop reason = signal SIGSTOP
    frame #0: 0x00000016fd3bd4ac
    error: memory read failed for 0x16fd3bd000
    thread #3, name = 'Signal Catcher', stop reason = signal SIGSTOP
    frame #0: 0x00000016fd40a5d8

    It fails to read memory in LLDB, do you know why it failed to read memory in LLDB? Thanks!

    ReplyDelete
    Replies
    1. Hello!

      Looking at the addresses and the triple returned by lldb. I am guessing you are using 64 bit `lldb-server` to debug a 32 bit binary. So, I would suggest you to push the 32 bit version, which should be in `$ANDROID_SDK_ROOT/lldb//android/armeabi/lldb-server` and then try to debug it.

      Delete
  2. Hi,

    The debugged app has a 64 bit so like the following.

    bullhead:/data/app/com.example.myapplication-2AqHZSk9eGrvrzCgS7aoVg==/lib/arm64 # ls
    libpl_droidsonroids_gif.so
    ile libpl_droidsonroids_gif.so <
    libpl_droidsonroids_gif.so: ELF shared object, 64-bit LSB arm64, BuildID=264656f26f9f1ea9cacd0c71c87b9c7bf64b4124, for Android 23, built by NDK r20b (5948944), stripped

    I pushed the 64 bit lldb-server into android device. My debugging device is LG Nexus 5x OS: andorid 8.1. The 0x00000016fd40a3f8 is a 64 bit memory address. lldb-server is /Users/kailu/Library/Android/sdk/lldb/3.1/android/arm64-v8a/lldb-server

    The following is the version info of lldb-server.

    bullhead:/data/local/tmp # lldb-server v
    lldb version 6.0.0 (https://us3-mirror-partner-android.googlesource.com/a/platform/external/lldb revision a7bde94648f7d808066e16b5aefb18b5cf06bd01)
    clang revision d4f31fa2ec80bbffa638d47ac9cd0997559fb215
    llvm revision 1f769b41e8cf646893a50ba8d9595ef6d913ad02
    bullhead:/data/local/tmp # file lldb-server
    lldb-server: ELF shared object, 64-bit LSB arm64, dynamic (/system/bin/linker64), for Android 21, built by NDK r15c (4203891), BuildID=16479c73b494c432c5f171db2bb68f29e033f157, stripped
    bullhead:/data/local/tmp #

    Any clue for it?

    ReplyDelete
    Replies
    1. I am afraid! No, I don't know what is causing this :(

      I would try to use gdbserver to see if I get any different results, and then probably report it to LLVM.

      Delete

Hello once again!

First of all, sorry for not making a blog post early on during the community bonding period. I couldn't because I was mostly busy with ...