Using GDB

The GNU Project debugger (GDB) is a commonly used Unix debugger. This page details using gdb to debug Android apps and processes.

Debugging running apps or processes

To connect to an already-running app or native daemon, use gdbclient with a PID. For example, to debug the process with PID 1234, run:

gdbclient 1234

The script sets up port forwarding, starts the appropriate gdbserver on the device, starts the appropriate gdb on the host, configures gdb to find symbols, and connects gdb to the remote gdbserver.

Debugging native process startup

To debug a process as it starts, use gdbserver or gdbserver64 (for 64-bit processes). For example:

adb shell gdbserver :5039 /system/bin/MY_TEST_APP

Example output:

Process MY_TEST_APP created; pid = 3460
Listening on port 5039

Next, identify the application PID from the gdbserver output and use it in another terminal window:

gdbclient APP_PID

Finally, enter continue at the gdb prompt.

Note: If you specify the wrong gdbserver, you'll get an unhelpful error message (such as "Reply contains invalid hex digit 59").

Debugging app startup

Sometimes you want to debug an app as it starts, such as when there's a crash and you want to step through code to see what happens before the crash. Attaching works in some cases, but in other cases is impossible because the app crashes before you can attach. The logwrapper approach (used for strace and valgrind) does not always work because the app might not have permissions to open a port, and gdbserver inherits that restriction.

To debug app startup, use the developer options in Settings to instruct the app to wait for a Java debugger to attach:

  1. Go to Settings > Developer options > Select debug app and choose your app from the list, then press Wait for debugger.
  2. Start the app, either from the launcher or by using the command line to run:
    am start -a android.intent.action.MAIN -n APP_NAME/.APP_ACTIVITY
    
  3. Wait for the app to load and a dialog to appear telling you the app is waiting for a debugger.
  4. Attach gdbserver/gdbclient normally, set breakpoints, then continue the process.

To let the app actually run, attach a Java Debug Wire Protocol (JDWP) debugger such as Java Debugger (jdb):

adb forward tcp:12345 jdwp:XXX  # (Where XXX is the pid of the debugged process.)
jdb -attach localhost:12345

Debugging apps or processes that crash

If you want debuggerd to suspend crashed processes so you can attach gdb, set the appropriate property:

# Android 7.0 Nougat and later.
adb shell setprop debug.debuggerd.wait_for_gdb true
# Android 6.0 Marshmallow and earlier.
adb shell setprop debug.db.uid 999999

At the end of the usual crash output, debuggerd provides instructions on how to connect gdb using the command:

gdbclient PID

Debugging without symbols

For 32-bit ARM, if you don’t have symbols, gdb can get confused about the instruction set it is disassembling (ARM or Thumb). To specify the instruction set chosen as the default when symbol information is missing, set the following property:

set arm fallback-mode arm  # or thumb