Using GDB

The GNU Project debugger (GDB) is a commonly used UNIX debugger. This page details using gdb to debug Android apps and processes for platform developers. For third-party app development, see Debug your app.

Prerequisites

To use GDB for debugging apps and processes:

  • Set up environment with the envsetup.sh command.
  • Run the lunch command.

For more help with setting up your environment, see Set up environment.

Debugging running apps or processes

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

gdbclient.py -p 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 a 64-bit executable:

adb shell gdbserver64 :5039 /system/bin/MY_TEST_64_BIT_APP

For a 32-bit executable:

adb shell gdbserver :5039 /system/bin/MY_TEST_32_BIT_APP

Example output:

Process MY_TEST_64_BIT_APP created; pid = 3460
Listening on port 5039

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

gdbclient.py -p APP_PID

Finally, enter continue at the gdb prompt.

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 happened 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) doesn't 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 click Wait for debugger.
  2. Start the app, either from the launcher or by using the command line to run:
    adb shell 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 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 that you can attach gdb, set the appropriate property:

  • Android 7.0 Nougat and higher
    
    adb shell setprop debug.debuggerd.wait_for_gdb true
    
  • Android 6.0 Marshmallow and lower
    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.py -p PID

Debugging without symbols

For 32-bit ARM, if you don’t have symbols, gdb can't determine which instruction set it's 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

Debugging with VS Code

GDB supports debugging platform code on Visual Studio Code. You can use the VS Code debugger frontend instead of the GDB CLI interface to control and debug native code running on devices.

Before using VS Code for debugging, install the C/C++ extension.

To debug code using VS Code:

  1. Ensure that all build artifacts (such as symbols) required to run gdbclient.py are present.
  2. Run the following command:
    gdbclient.py -p pid | -n proc-name |
    -r ... --setup-forwarding vscode ANY_OTHER_FLAGS

    This prints a JSON object and gdbclient.py continues running. This is expected; don't kill the gdbclient.py program.

  3. In the debugging tab in VS Code, select add configuration, then select C/C++ gdb attach. This opens a launch.json file and adds a new JSON object to a list.
  4. Delete the newly added debugger configuration.
  5. Copy the JSON object printed by gdbclient.py and paste it into the object you just deleted. Save the changes.
  6. To reload the window to refresh the debugger list, press Ctrl+Shift+P and type reload window.
  7. Select the new debugger configuration and press run. The debugger should connect after 10 to 30 seconds.
  8. When you're done debugging, go to the terminal running gdbclient.py and press Enter to end the gdbclient.py program.

After setting up the debugger configuration for the first time, you can skip steps 3 through 6.