Mobile/Fennec/Android/GDB: Difference between revisions

From MozillaWiki
< Mobile‎ | Fennec‎ | Android
Jump to navigation Jump to search
(Make it clear where the source for gdbserver comes from (i.e., you already have it))
(JimDB is no longer used. So add link to GV debugging document)
 
(47 intermediate revisions by 12 users not shown)
Line 1: Line 1:
Note: the names JimDB and moz-gdb seem to be used interchangeably, meaning the same thing.
= Deprecated =
This page is the information of deprecated debugging tools.  We recommend to use Android studio (https://mozilla.github.io/geckoview/tutorials/native-debugging.html).


= Using JimDB (Or, Android GDB with Niceness) =
= What JimDB? =
== Prebuilt binaries ==


=== Linux ===
JimDB is a fork of GDB used for simplifying Fennec development. It consists of two parts:


[https://github.com/darchons/android-gdb/downloads Download page]
* Binaries - the GDB/GDBServer binaries that include Android-specific patches (https://github.com/darchons/android-gdb)
* Scripts - the Python scripts that run under GDB to simplify common tasks (https://github.com/darchons/android-gdbutils)


Run 'git pull' inside the utils directory to get the latest GDB utilities.
Use #mobile on IRC for support.


=== GDB utilities ===
= Getting started =


A set of tools to make Fennec development on Android easier.
== Using mach ==


[http://github.com/darchons/android-gdbutils Source and documentation].
You can use mach to fetch, install, configure, and run JimDB with one simple command. Note that if you are on OS X, mach may install JimDB correctly, but then try to debug using lldb. If that happens, you can still run JimDB manually from your ~/.mozbuild folder (you can find the full path in the output below).


=== Careful of NDK versions ===
  $ ./mach run --debug
  JimDB (arm) not found: /home/gbrown/.mozbuild/android-device/jimdb-arm does not exist
  Download and setup JimDB (arm)? (Y/n) y
  Installing JimDB (linux64/arm). This may take a while...
  From https://github.com/darchons/android-gdbutils
  * [new branch]      master    -> origin/master
  * [new tag]        gdbutils-2 -> gdbutils-2
  * [new tag]        initial-release -> initial-release
  1:45.57 /home/gbrown/.mozbuild/android-device/jimdb-arm/bin/gdb -q --args
  Fennec GDB utilities
    (see utils/gdbinit and utils/gdbinit.local on how to configure settings)
  1. Debug Fennec (default)
  2. Debug Fennec with env vars and args
  3. Debug using jdb
  4. Debug content Mochitest
  5. Debug compiled-code unit test
  6. Debug Fennec with pid
  Enter option from above: 1
  New ADB device is "emulator-5554"
  Using device emulator-5554
  Using object directory: /home/gbrown/objdirs/droid
  Set sysroot to "/home/gbrown/.mozbuild/android-device/jimdb-arm/lib/emulator-5554".
  Updated solib-search-path.
  Ignoring BHM signal.
  Using package org.mozilla.fennec_gbrown.
  Launching org.mozilla.fennec_gbrown... Done
  Attaching to pid 674... Done
  Setting up remote debugging... Done
  Ready. Use "continue" to resume execution.
  : No such file or directory.
  (gdb)


The prebuilt binaries on github are build using an outdated version of the NDK. You should replace the "gdbserver" program by:
== Using pre-built binaries ==


  [http://people.mozilla.org/~nchen/gdbserver.tar.bz2]
=== Instructions ===


If that still does not work, #mobile on irc.mozilla.org is the place to go.
# Download the latest pre-built jimdb binaries for your host and device platforms from [https://people.mozilla.org/~nchen/jimdb this directory] (use 'jimdb-arm' for ARM devices and 'jimdb-x86' for x86 devices)
# Download the latest pre-built gdbserver binary for your device platform from [https://people.mozilla.org/~nchen/jimdb the same directory]
# Extract to a user-writable directory
# Replace the gdbserver binary in the jimdb-*/bin/ directory with the one you downloaded separately (it's newer)
# Run 'git pull' from inside the utils/ directory to get the latest scripts
# Launch bin/gdb to start using JimDB!
# OPTIONAL: For easier access, you can create a symlink to jimdb under, e.g., /usr/bin


== Building moz-gdb ==
=== Example ===


There are two things to build here: the gdb you'll run on your computer, and the gdbserver you'll install on the device. JimDB's gdb takes care of automatically running /data/local/gdbserver on the device, once it's correctly installed.
For ARM devices on Linux,
cd $HOME
wget https://people.mozilla.org/~nchen/jimdb/jimdb-arm-linux_x64.tar.bz2 # step 1
tar -xf jimdb-arm-linux_x64.tar.bz2 # step 3
cd jimdb-arm/utils && git pull # step 5
../bin/gdb # step 6
sudo ln -s $HOME/jimdb-arm/bin/gdb /usr/bin/jimdb # step 7


=== Building gdb ===
If you download the wrong x86 or x64 build, you might get an error like:
$ ./bin/gdb
./bin/gdb: error while loading shared libraries: libpython2.7.so.1.0: cannot open shared object file: No such file or directory
 
== Custom-building ==
 
=== Step 1. Compiling the binaries ===
 
There are two things to build here: gdb and gdbserver


==== Linux ====
==== Linux ====


Get required packages:
===== GDB =====
sudo apt-get install bison flex libncurses5-dev texinfo python2.7-dev


Get source:
# Clone [https://github.com/darchons/android-gdb the GitHub repo] (do not use the Zip archive, as the build system will try to obtain a git changeset id)
git clone git://github.com/darchons/android-gdb.git
# You may need to install additional packages in order to build GDB. For example,<pre>sudo apt-get build-dep gdb</pre>
  cd android-gdb
# Run configure inside the source directory<pre># ARM:&#10;./configure --target=arm-linux-android --with-python=yes --prefix=/nonexistent \&#10; --with-gdb-datadir=/nonexistent/utils --with-system-gdbinit=/nonexistent/utils/gdbinit&#10;# x86:&#10;./configure --target=i686-pc-linux-android --with-python=yes --prefix=/nonexistent \&#10;  --with-gdb-datadir=/nonexistent/utils --with-system-gdbinit=/nonexistent/utils/gdbinit</pre>
git checkout android-gdb_7_4
# Run make <pre>make -j8</pre>
# The compiled binary will be at gdb/gdb
If you see an error like:
<pre>
../../../../bfd/doc/bfd.texinfo:325: unknown command `colophon'
../../../../bfd/doc/bfd.texinfo:336: unknown command `cygnus'
Makefile:421: recipe for target 'bfd.info' failed
</pre>
you can fix this by running:
<pre>
sed -i -e 's/@colophon/@@colophon/' -e 's/doc@cygnus.com/doc@@cygnus.com/' bfd/doc/bfd.texinfo
</pre>
or by checking out a more recent branch (this bug is in the 7_5 branch).


Run configure and make:
===== GDBServer =====
mkdir android-gdb-objdir
cd android-gdb-objdir
export prefix=/nonexistent
/path/to/android-gdb/configure --target=arm-elf-linux --with-python=yes --prefix=$prefix \
  --with-gdb-datadir=$prefix/utils --with-system-gdbinit=$prefix/utils/gdbinit
make -j4


Reminder: Don't use ~ in the paths you pass here, as Bash wouldn't evaluate it!
Consider using the pre-built gdbserver binary from the "Using pre-built binaries" section above; gdbserver is not specific to your platform. Otherwise,
# Use the source directory from above
# Make sure you have a copy of the Android NDK
# Run configure inside the ''gdb/gdbserver directory'' (following is for NDK r8d)<pre>export NDK=/PATH/TO/NDK&#10;# ARM:&#10;export PATH=$PATH:$NDK/toolchains/arm-linux-androideabi-4.6/prebuilt/linux-x86/bin&#10;./configure --host=arm-linux-androideabi --with-sysroot=$NDK/platforms/android-9/arch-arm&#10;# x86:&#10;export PATH=$PATH:$NDK/toolchains/x86-4.6/prebuilt/linux-x86/bin&#10;./configure --host=i686-linux-android --with-sysroot=$NDK/platforms/android-9/arch-x86</pre>
# Run make <pre>make -j8</pre>
# The compiled binary will be at gdbserver


The gdb binary will be located at ''android-gdb-objdir/gdb/gdb''
==== Mac ====


==== Mac OS X ====
===== GDB =====


NOTES:
# Get a zip of the source from [https://github.com/darchons/android-gdb the GitHub repo] (Get the zip because cloning takes a lot longer)
*BenWa (2012/01/09): It failed to built with clang
# Extract the zip
*mcomella (2012/07/31): This worked for me, although I had issues when I ran ./configure from the root diretory before running the written commands (I had to "make distclean" after that). I used Lion dev tools.
# You may need to install additional packages in order to build GDB. For example,<pre>port install bison flex ncurses texinfo python27</pre>
*jchen (2012/10/17): I ran into a make error about missing python2.7. The cause is a bad config variable in the MacPorts python2.7 port. If I switch to using the native OSX python (by changing PATH), the problem goes away.
# Run configure inside the source directory<pre># ARM:&#10;./configure --target=arm-linux-android --with-python=yes --prefix=/nonexistent \&#10;  --with-gdb-datadir=/nonexistent/utils --with-system-gdbinit=/nonexistent/utils/gdbinit&#10;# x86:&#10;./configure --target=i686-pc-linux-android --with-python=yes --prefix=/nonexistent \&#10; --with-gdb-datadir=/nonexistent/utils --with-system-gdbinit=/nonexistent/utils/gdbinit</pre>
# Run make <pre>make -j8</pre>
Get required packages (unnecessary for OS X 10.8.2; they are include with Mountain Lion):
# The compiled binary will be at gdb/gdb
port install bison flex ncurses texinfo python27


Get source:
===== GDBServer =====
git clone git://github.com/darchons/android-gdb.git
cd android-gdb
git checkout android-gdb_7_4


Run configure and make:
Consider using the pre-built gdbserver binary from the "Using pre-built binaries" section above; gdbserver is not specific to your platform. Otherwise,
mkdir android-gdb-objdir
# Use the source directory from above
cd android-gdb-objdir
# Make sure you have a copy of the Android NDK
export prefix=/nonexistent
# Run configure inside the ''gdb/gdbserver directory'' (following is for NDK r8d)<pre>export NDK=/PATH/TO/NDK&#10;# ARM:&#10;export PATH=$PATH:$NDK/toolchains/arm-linux-androideabi-4.6/prebuilt/darwin-x86/bin&#10;./configure --host=arm-linux-androideabi --with-sysroot=$NDK/platforms/android-9/arch-arm&#10;# x86:&#10;export PATH=$PATH:$NDK/toolchains/x86-4.6/prebuilt/darwin-x86/bin&#10;./configure --host=i686-linux-android --with-sysroot=$NDK/platforms/android-9/arch-x86</pre>
/path/to/android-gdb/configure --target=arm-elf-linux --enable-targets=all --with-python=yes --prefix=$prefix \
# Run make <pre>make -j8</pre>
  --with-gdb-datadir=$prefix/utils --with-system-gdbinit=$prefix/utils/gdbinit
# The compiled binary will be at gdb/gdbserver/gdbserver
make -j4


Reminder: Don't use ~ in the paths you pass here, as Bash wouldn't evaluate it!
=== Step 2. Creating JimDB directory ===


The gdb binary will be located at ''android-gdb-objdir/gdb/gdb''
To get the most out of JimDB, in addition to the binaries, you need the Python scripts. But first, the scripts assume you have the following JimDB directory structure,


=== Building gdbserver ===
./bin/
    gdb
    gdbserver
./utils/
    gdbinit
    python/


==== Linux ====
Therefore, you'd need to,
# Make a JimDB directory
# Copy gdb and gdbserver from steps above to bin/
# Clone the Python scripts to utils/
# Run bin/gdb
 
For example,
mkdir -p jimdb/bin # step 1
cp /PATH/TO/SOURCE/gdb/gdb jimdb/bin # step 2
cp /PATH/TO/SOURCE/gdb/gdbserver/gdbserver jimdb/bin
git clone git://github.com/darchons/android-gdbutils.git jimdb/utils # step 3
jimdb/bin/gdb # step 4


Create an NDK toolchain:
= Using JimDB =
cd /PATH/TO/NDK
./build/tools/make-standalone-toolchain.sh


This will tell you that the toolchain was packaged somewhere like /tmp/ndk-username/arm-linux-androideabi-4.4.3.tar.bz2
== First run ==


Extract that toolchain somewhere:
In order to debug Fennec, JimDB needs a copy of your system libraries. When you try to debug Fennec on a particular device for the first time, JimDB will download the libraries from your device. This may take some time but will only need to run once. You may need to restart JimDB in order for debug symbols to work.
mkdir ~/android-toolchain
cd ~/android-toolchain
tar -xvf /tmp/ndk-username/arm-linux-androideabi-4.4.3.tar.bz2


Make sure NDK toolchain is in PATH:
== Configuring JimDB ==
export PATH=~/android-toolchain/arm-linux-androideabi-4.4.3/bin:$PATH


Run configure and make for gdbserver (gdbserver comes with the android-gdb repository your checked out earlier):
utils/gdbinit is the GDB command file that JimDB runs at launch. Open it in your favorite text editor to see configurable settings for JimDB.
cd android-gdb
mkdir android-gdbserver-objdir
cd android-gdbserver-objdir
/path/to/android-gdb/gdb/gdbserver/configure --host=arm-linux-androideabi \
  --with-sysroot=/PATH/TO/NDK/platforms/android-9/arch-arm
make -j4


The gdbserver binary will be located at ''android-gdbserver-objdir/gdbserver''.
utils/gdbinit also loads utils/gdbinit.local. Because utils/gdbinit can change frequently across updates, it's recommended to copy your custom settings to utils/gdbinit.local, so that updates do not override your settings.


Reminder: Don't use ~ in the paths you pass here, as Bash wouldn't evaluate it!
For example, to configure the feninit.default.objdir option, paste the following line anywhere inside utils/gdbinit.local,
python feninit.default.objdir = '/home/user/mozilla/central/objdir-android'


Install it on your device:
== FenInit ==


adb push gdbserver /data/local || adb push gdbserver /data/local/tmp
FenInit is the Python script that simplifies launching Fennec on your device and setting up a debug environment. When JimDB starts, FenInit runs automatically and presents several options,


On some Android models the /data/local is not writable so gdbserver needs to be pushed into /data/local/tmp/
# Debug Fennec (default)
# Debug Fennec with env vars and args
# Debug using jdb
# Debug content Mochitest
# Debug compiled-code unit test


==== Mac OS X ====
[[File:Jimdb-prompt.png]]


Setup a toolchain environment for your build, then run configure and make for gdbserver. The android-gdbserver-objdir directory can be anywhere, but creating it within the android-gdb git clone is convenient. The paths below do not necessarily need to be absolute paths, but it will make life easier.
=== Debug Fennec ===


Run configure and make for gdbserver (gdbserver comes with the android-gdb repository your checked out earlier):
This is the default option. Once you choose an object directory to use, the script will automatically launch Fennec, and run GDBServer to attach to Fennec.
cd android-gdb
mkdir android-gdbserver-objdir
cd android-gdbserver-objdir
/ABSOLUTE/PATH/TO/NDK/android-ndk-r5c/build/tools/make-standalone-toolchain.sh --install-dir=android-9-toolchain --platform=android-9
export PATH=android-9-toolchain/bin:$PATH
/ABSOLUTE/PATH/TO/GIT/CLONE/android-gdb/gdb/gdbserver/configure --host=arm-linux-androideabi
make -j4


The gdbserver binary will be located at ''android-gdbserver-objdir/gdbserver''.
The script tries to scan your user directory for object directories. For more control, see the [[#feninit.default.objdir|Configuration section]] on how to specify default object directories or where to scan for object directories.


Install it on your device:
=== Debug Fennec with env vars and args ===


adb push gdbserver /data/local | adb push gdbserver /data/local/tmp
This option gives you the additional ability to specify environment variables and arguments when launching Fennec. See the [[#feninit.default.env|Configuration section]] on how to specify additional default environment variables and arguments.


=== Create the moz-gdb directory ===
=== Debug using jdb ===


Once you've built JimDB, you need to create and populate a moz-gdb directory as explained below.
This option will let you use the Java debugger (jdb) to debug the native Java portion of Fennec. This is the default option if you already have a previous JimDB debugging session running.


Indeed, GDB utilities assume the following moz-gdb directory structure:
JDB support is experimental. It is able to at least set breakpoints, show source code, and examine objects.


./bin/
=== Debug content Mochitest ===
    gdb
    gdbserver
./utils/
    gdbinit
    python/


Execute the following commands to create and set up the moz-gdb directory:
This option will let you debug a regular Mochitest. Make sure Fennec is compiled with the '--enable-tests' option in the mozconfig file. Because running Mochitests require a copy of the XUL Runtime Environment (XRE), the script will offer to automatically download a copy of XRE for you, as well as launching the test harness. You can specify a file or a directory to test, or set TEST_PATH. Environment variables and arguments to the test harness are also supported.


mkdir -p moz-gdb/bin
=== Debug compiled-code unit test ===
cp android-gdb-objdir/gdb/gdb moz-gdb/bin
cp android-gdbserver-objdir/gdbserver moz-gdb/bin
git clone git://github.com/darchons/android-gdbutils.git moz-gdb/utils


== Set up the gdbinit file ==
This option will let you debug a C++ test. Environment variables and arguments are supported.


Now edit this file:
=== Configuration ===
==== feninit.default.objdir ====
* Set feninit.default.objdir to the default object directory. Note that once it is set, the script will not prompt you to choose an object directory.
* Alternatively, if your object directories are called 'obj*' under your source directory, you can set feninit.default.objdir to the source directory itself. The script will scan the source directory and list all the object directories that it found.
* Note that there have been problems in the past with using ~ and $HOME in the setting, so use absolute path for best results.
* PRO-TIP: Put the following code block inside gdbinit.local to always use the current directory as the object directory,
python
import os
feninit.default.objdir = os.getcwd()
end


moz-gdb/utils/gdbinit
==== feninit.default.srcroot ====
* Unlike the previous setting, feninit.default.srcroot specifies the directory containing all the source directories. This is convenient if you have 'src/mozilla-central', 'src/mozilla-inbound', 'src/mozilla-aurora', etc. In that case, you can set feninit.default.srcroot to 'src' and all the source directories will be scanned for object directories.
* Again, use absolute path for best results.
==== feninit.default.no_launch ====
* This settings is meant for B2G, and may not be useful for Fennec debugging.
==== feninit.default.gdbserver_port ====
* To debug Fennec on your device, GDB on your computer needs to talk to GDBServer on your device through a TCP port forwarded to your device through ADB.
* Normally, JimDB will use a random port. However, you can pick a specific port to use. This is useful in certain situations such as inside an SSH session. See [http://www.jnchen.com/blog/2012/11/tunnelling-adb this blog post].
==== feninit.default.jdwp_port ====
* Similar to feninit.default.gdbserver_port, except for using JDB for debugging.
==== feninit.default.env ====
* Specify the default environment variables to use when launching Fennec. Only used for the "Debug Fennec" options.
==== feninit.default.args ====
* Specify the default arguments to use when launching Fennec. Only used for the "Debug Fennec" options.
==== feninit.default.cpp_env ====
* Similar to [[#feninit.default.env|feninit.default.env]], except only used for the "Debug compiled-code unit test" option.
==== feninit.default.mochi_env ====
* Similar to [[#feninit.default.env|feninit.default.env]], except only used for the "Debug content Mochitest" option.
==== feninit.default.mochi_args ====
* Specify the default arguments to use when debugging Mochitest. Only used for the "Debug content Mochitest" option.
* Note that Mochitest arguments are arguments to the test harness (e.g. --remote-webserver), and not arguments to Fennec itself.
==== feninit.default.mochi_xre ====
* Specify the XRE directory to use, instead of letting the script download and manage an XRE copy.
==== feninit.default.mochi_harness ====
* Specify the directory containing the harness itself, i.e. "runtestsremote.py". Not needed normally.
==== feninit.default.mochi_xre_url ====
* Specify the directory on [https://ftp.mozilla.org ftp.mozilla.org] to use for downloading XRE. Not used if feninit.default.mochi_xre is specified.
==== feninit.default.mochi_xre_update ====
* Specify the XRE check for updates interval. Only used if the script is managing the XRE copy, and not used if feninit.default.mochi_xre_update is specified.


and uncomment (remove the #'s) and set the following variables:
== GDB commands specific to JimDB ==
  python feninit.default.objdir      # set it to your fennec object directory
=== set delay-add-remote-solibs ===
  python feninit.default.srcroot    # set it to your source directory
gdb> set delay-add-remote-solibs <0|1>
Default setting is 0. Set delay-add-remote-solibs to 1 to delay loading symbols when shared libraries are loaded. This may improve the set up time. However, you may need to use the "sharedlibrary" command to manually load symbols before using breakpoints.
=== monitor set ignore-ondemand ===
gdb> monitor set ignore-ondemand <0|1>
Default setting is 1. Set ignore-ondemand to 0 to not ignore segmentation faults generated by on-demand decompression. This setting may be needed to debug specific segmentation faults that are inadvertently being ignored. This command can only be run after attaching to the target, so it cannot be specified in gdbinit.local.


=== Linux ===
= FAQ =
Make sure your paths are absolute! The gdbinit file, even though it specifies relative paths by default, will not correctly load debug symbols unless you specify absolute paths.
<table style="border: 1px solid black;">
<tr>
<th style="background: rgb(250,35,35); color: black; font-weight: bold;">INCORRECT</th>
<th style="background: rgb(35,250,35); color: black; font-weight: bold;">CORRECT</th>
</tr>
<tr>
<td>
<code>
python feninit.default.objdir = '~/Source/mozilla-android/obj-android'
python feninit.default.srcroot = '~/Source/mozilla-central/mozilla'
</code>
</td>
<td>
<code>
python feninit.default.objdir = '/home/USERNAME/Source/mozilla-android/obj-android'
python feninit.default.srcroot = '/home/USERNAME/Source/mozilla-central/mozilla'
</code>
</td>
</tr>
</table>


== Running JimDB ==
=== What is moz-gdb? ===
* moz-gdb was a synonym for JimDB, but it's no longer used, to avoid confusion


Once JimDB is properly set up, with a moz-gdb directory as described above, running Fennec in GDB is very easy:
=== "configure: error: failure running python-config" when compiling GDB ===
* python may point to python3 on your machine. You need to specify where python2 is by using, for example, --with-python=python2 in your configure line


  ./moz-gdb/bin/gdb
=== "error while loading shared libraries: libtinfo.so.5" on Linux ===
* You may need to create a libtinfo.so.5 symlink to libncurses.so.5. For example,
sudo ln -s libncurses.so.5 /usr/lib/libtinfo.so.5


This will automatically start gdbserver and fennec on the device, and start gdb on your computer.
=== "Segmentation fault: 11" or "Illegal instruction: 4" on Mac OS X ===
* This may be due to incompatible OS X SDK versions. You should build your own JimDB binary to avoid the issue.


=== First run of JimDB ===
=== "cannot locate symbol "__exidx_end"" when starting to debug ===
* If you're using pre-built binaries, you need to update to a newer version of JimDB
* If you're using custom-built binaries, you need to recompile gdbserver using a newer version of the NDK


Run JimDB, type as usual 'continue' to actually start running Fennec, give it several seconds, and hit Ctrl+C to interrupt Fennec.
=== "No module named printing" when debugging Fennec with JimDB ===
* The JimDB Python scripts lack several scripts included in regular GDB packages. To fix that, simply copy your local copy of these scripts to the JimDB utils/python directory. For example, on a typical Linux system, run
cp -r /usr/share/gdb/python/gdb $jimdb/utils/python/
* If you don't have these files, they are available [https://people.mozilla.org/~nchen/jimdb/gdb-python-lib.tar.bz2 here]; just extract it under $jimdb/utils/python/


The first time, it will probably complain:
=== Random segmentation faults when debugging Fennec ===
* GDB can catch segmentation faults generated by on-demand decompression; just use "continue" to continue execution.
* Alternatively, specify the "MOZ_LINKER_ONDEMAND=0" environment variable when launching Fennec using Option 2. You can also put the option inside jimdb/utils/gdbinit.local.


  Program received signal SIGINT, Interrupt.
=== GDB crashed and Fennec is stuck. Halp!! ===
  warning: Could not load shared library symbols for org.mozilla.fennec_bjacob.
* GDBServer may still be attached to Fennec but is unable to communicate with GDB; try killing GDBServer
  Do you need "set solib-search-path" or "set sysroot"?
adb shell run-as org.mozilla.fennec_$USER kill `adb shell ps | grep gdb | awk '{print $2}'`


Do not worry about this. It will seem frozen for several seconds, but let it run. What's happening is that it's pulling all the libraries from the device into the moz-gdb directory. Ignore the suggestion about setting solib-search-path/sysroot, JimDB will do it all for you. Once it's done, you get a GDB invite as usual.
=== "make: `[path]/mochitest-remote' is up to date." while trying to run Mochitests ===
* Delete the mochitest-remote file.


Do this sanity check:
=== "failed to run gdbserver" ===


  (gdb) info shared
    "gdbserver" output:
    /system/bin/sh: /data/local/tmp/gdbserver: not executable: magic 7F45
    "run-as" output:
    /data/local/tmp/gdbserver[1]: syntax error: '(' unexpected
    "su -c" output:
    /system/bin/sh: su: not found
    [path]/jimdb-x86/bin/../utils/gdbinit:136: Error in sourced command file:
    failed to run gdbserver


For each loaded library you'll see whether symbols were found: Yes, No, or "Yes (*)" meaning no debug info. Press Enter until the listing is complete. You want to make two things sure:
You are probably trying to run the x86 version on an ARM device. Download the ARM version of JimDB instead.


Ensure that libXUL has debug info i.e. you should see a plain Yes for libxul.so. If not, that means that something is wrong with your fennec build (is it a non-debug build?) or with your gdbinit (see above).
Alternatively, you may just have an out-of-date version of gdbserver. Check for an updated version in the link posted above.


Ensure that no library has a No. Typically, some system libraries and drivers will give you a No. For each such library, you want to manually pull it from the device into moz-gdb/lib/<device hex id>/system/lib. These drivers are typically found in /vendor on your device. Do pull them into system/lib on your computer, as this is where JimDB will find them, even if on the device they are not in /system/lib. Here is an example script to pull all the files in a given directory (here /system/lib) at once:
    "gdbserver" output:
    error: only position independent executables (PIE) are supported.


  for file in $(adb shell ls /system/lib | tr "\n" " " | tr "\r" " "); do
This means your build of gdbserver is too old for the Android version you're debugging on. You may need a newer platform sysroot and/or to add flags to gdb/gdbserver/Makefile to build a position-independent executable.
    adb pull /system/lib/$file
  done


You may have to repeat this for other directories such as /vendor/lib for drivers.
    CFLAGS += -fvisibility=default -fPIE
    LDFLAGS += -rdynamic -fPIE -pie


=== JimDB sucks! Halp!! ===
* Come on #mobile on IRC
* Or file a bug under Firefox for Android, JimDB component


There is one dummy library about which GDB will still report "no":
=== JimDB is awesome now!! Can I buy you a $beverage? ===
Yes! See also {{bug|800000}}


  No          org.mozilla.fennec_foobar
=== Using `next` to traverse a function sometimes gets stuck with an error like "Unable to find end of function" ===
Try using the env-var MOZ_LINKER_ONDEMAND=0.


Do not worry about that one.
=== Execution pauses often for "Program received signal SIG33, Real-time event 33." ===
This should be caught automatically, but try:
    handle SIG33 pass nostop noprint


=== Troubleshooting ===
=== "Symbol not found: __PyErr_ReplaceException" ===
You should not use python 2.7.11.


* If debug info seems broken (e.g. breakpoints or stepping don't work well), make sure you're using a --disable-optimize --enable-debug build of Fennec. Just --enable-debug doesn't seem to always be enough.
See : https://github.com/conda/conda/issues/1367

Latest revision as of 04:26, 16 January 2019

Deprecated

This page is the information of deprecated debugging tools. We recommend to use Android studio (https://mozilla.github.io/geckoview/tutorials/native-debugging.html).

What JimDB?

JimDB is a fork of GDB used for simplifying Fennec development. It consists of two parts:

Use #mobile on IRC for support.

Getting started

Using mach

You can use mach to fetch, install, configure, and run JimDB with one simple command. Note that if you are on OS X, mach may install JimDB correctly, but then try to debug using lldb. If that happens, you can still run JimDB manually from your ~/.mozbuild folder (you can find the full path in the output below).

 $ ./mach run --debug
 JimDB (arm) not found: /home/gbrown/.mozbuild/android-device/jimdb-arm does not exist
 Download and setup JimDB (arm)? (Y/n) y
 Installing JimDB (linux64/arm). This may take a while...
 From https://github.com/darchons/android-gdbutils
  * [new branch]      master     -> origin/master
  * [new tag]         gdbutils-2 -> gdbutils-2
  * [new tag]         initial-release -> initial-release
  1:45.57 /home/gbrown/.mozbuild/android-device/jimdb-arm/bin/gdb -q --args 
 Fennec GDB utilities
   (see utils/gdbinit and utils/gdbinit.local on how to configure settings)
 1. Debug Fennec (default)
 2. Debug Fennec with env vars and args
 3. Debug using jdb
 4. Debug content Mochitest
 5. Debug compiled-code unit test
 6. Debug Fennec with pid
 Enter option from above: 1
 New ADB device is "emulator-5554"
 Using device emulator-5554
 Using object directory: /home/gbrown/objdirs/droid
 Set sysroot to "/home/gbrown/.mozbuild/android-device/jimdb-arm/lib/emulator-5554".
 Updated solib-search-path.
 Ignoring BHM signal.
 Using package org.mozilla.fennec_gbrown.
 Launching org.mozilla.fennec_gbrown... Done
 Attaching to pid 674... Done
 Setting up remote debugging... Done
 Ready. Use "continue" to resume execution.
 : No such file or directory.
 (gdb)

Using pre-built binaries

Instructions

  1. Download the latest pre-built jimdb binaries for your host and device platforms from this directory (use 'jimdb-arm' for ARM devices and 'jimdb-x86' for x86 devices)
  2. Download the latest pre-built gdbserver binary for your device platform from the same directory
  3. Extract to a user-writable directory
  4. Replace the gdbserver binary in the jimdb-*/bin/ directory with the one you downloaded separately (it's newer)
  5. Run 'git pull' from inside the utils/ directory to get the latest scripts
  6. Launch bin/gdb to start using JimDB!
  7. OPTIONAL: For easier access, you can create a symlink to jimdb under, e.g., /usr/bin

Example

For ARM devices on Linux,

cd $HOME
wget https://people.mozilla.org/~nchen/jimdb/jimdb-arm-linux_x64.tar.bz2 # step 1
tar -xf jimdb-arm-linux_x64.tar.bz2 # step 3
cd jimdb-arm/utils && git pull # step 5
../bin/gdb # step 6
sudo ln -s $HOME/jimdb-arm/bin/gdb /usr/bin/jimdb # step 7

If you download the wrong x86 or x64 build, you might get an error like:

$ ./bin/gdb
./bin/gdb: error while loading shared libraries: libpython2.7.so.1.0: cannot open shared object file: No such file or directory

Custom-building

Step 1. Compiling the binaries

There are two things to build here: gdb and gdbserver

Linux

GDB
  1. Clone the GitHub repo (do not use the Zip archive, as the build system will try to obtain a git changeset id)
  2. You may need to install additional packages in order to build GDB. For example,
    sudo apt-get build-dep gdb
  3. Run configure inside the source directory
    # ARM:
    ./configure --target=arm-linux-android --with-python=yes --prefix=/nonexistent \
      --with-gdb-datadir=/nonexistent/utils --with-system-gdbinit=/nonexistent/utils/gdbinit
    # x86:
    ./configure --target=i686-pc-linux-android --with-python=yes --prefix=/nonexistent \
      --with-gdb-datadir=/nonexistent/utils --with-system-gdbinit=/nonexistent/utils/gdbinit
  4. Run make
    make -j8
  5. The compiled binary will be at gdb/gdb

If you see an error like:

../../../../bfd/doc/bfd.texinfo:325: unknown command `colophon'
../../../../bfd/doc/bfd.texinfo:336: unknown command `cygnus'
Makefile:421: recipe for target 'bfd.info' failed

you can fix this by running:

sed -i -e 's/@colophon/@@colophon/' -e 's/doc@cygnus.com/doc@@cygnus.com/' bfd/doc/bfd.texinfo

or by checking out a more recent branch (this bug is in the 7_5 branch).

GDBServer

Consider using the pre-built gdbserver binary from the "Using pre-built binaries" section above; gdbserver is not specific to your platform. Otherwise,

  1. Use the source directory from above
  2. Make sure you have a copy of the Android NDK
  3. Run configure inside the gdb/gdbserver directory (following is for NDK r8d)
    export NDK=/PATH/TO/NDK
    # ARM:
    export PATH=$PATH:$NDK/toolchains/arm-linux-androideabi-4.6/prebuilt/linux-x86/bin
    ./configure --host=arm-linux-androideabi --with-sysroot=$NDK/platforms/android-9/arch-arm
    # x86:
    export PATH=$PATH:$NDK/toolchains/x86-4.6/prebuilt/linux-x86/bin
    ./configure --host=i686-linux-android --with-sysroot=$NDK/platforms/android-9/arch-x86
  4. Run make
    make -j8
  5. The compiled binary will be at gdbserver

Mac

GDB
  1. Get a zip of the source from the GitHub repo (Get the zip because cloning takes a lot longer)
  2. Extract the zip
  3. You may need to install additional packages in order to build GDB. For example,
    port install bison flex ncurses texinfo python27
  4. Run configure inside the source directory
    # ARM:
    ./configure --target=arm-linux-android --with-python=yes --prefix=/nonexistent \
      --with-gdb-datadir=/nonexistent/utils --with-system-gdbinit=/nonexistent/utils/gdbinit
    # x86:
    ./configure --target=i686-pc-linux-android --with-python=yes --prefix=/nonexistent \
      --with-gdb-datadir=/nonexistent/utils --with-system-gdbinit=/nonexistent/utils/gdbinit
  5. Run make
    make -j8
  6. The compiled binary will be at gdb/gdb
GDBServer

Consider using the pre-built gdbserver binary from the "Using pre-built binaries" section above; gdbserver is not specific to your platform. Otherwise,

  1. Use the source directory from above
  2. Make sure you have a copy of the Android NDK
  3. Run configure inside the gdb/gdbserver directory (following is for NDK r8d)
    export NDK=/PATH/TO/NDK
    # ARM:
    export PATH=$PATH:$NDK/toolchains/arm-linux-androideabi-4.6/prebuilt/darwin-x86/bin
    ./configure --host=arm-linux-androideabi --with-sysroot=$NDK/platforms/android-9/arch-arm
    # x86:
    export PATH=$PATH:$NDK/toolchains/x86-4.6/prebuilt/darwin-x86/bin
    ./configure --host=i686-linux-android --with-sysroot=$NDK/platforms/android-9/arch-x86
  4. Run make
    make -j8
  5. The compiled binary will be at gdb/gdbserver/gdbserver

Step 2. Creating JimDB directory

To get the most out of JimDB, in addition to the binaries, you need the Python scripts. But first, the scripts assume you have the following JimDB directory structure,

./bin/
    gdb
    gdbserver
./utils/
    gdbinit
    python/

Therefore, you'd need to,

  1. Make a JimDB directory
  2. Copy gdb and gdbserver from steps above to bin/
  3. Clone the Python scripts to utils/
  4. Run bin/gdb

For example,

mkdir -p jimdb/bin # step 1
cp /PATH/TO/SOURCE/gdb/gdb jimdb/bin # step 2
cp /PATH/TO/SOURCE/gdb/gdbserver/gdbserver jimdb/bin
git clone git://github.com/darchons/android-gdbutils.git jimdb/utils # step 3
jimdb/bin/gdb # step 4

Using JimDB

First run

In order to debug Fennec, JimDB needs a copy of your system libraries. When you try to debug Fennec on a particular device for the first time, JimDB will download the libraries from your device. This may take some time but will only need to run once. You may need to restart JimDB in order for debug symbols to work.

Configuring JimDB

utils/gdbinit is the GDB command file that JimDB runs at launch. Open it in your favorite text editor to see configurable settings for JimDB.

utils/gdbinit also loads utils/gdbinit.local. Because utils/gdbinit can change frequently across updates, it's recommended to copy your custom settings to utils/gdbinit.local, so that updates do not override your settings.

For example, to configure the feninit.default.objdir option, paste the following line anywhere inside utils/gdbinit.local,

python feninit.default.objdir = '/home/user/mozilla/central/objdir-android'

FenInit

FenInit is the Python script that simplifies launching Fennec on your device and setting up a debug environment. When JimDB starts, FenInit runs automatically and presents several options,

  1. Debug Fennec (default)
  2. Debug Fennec with env vars and args
  3. Debug using jdb
  4. Debug content Mochitest
  5. Debug compiled-code unit test

Jimdb-prompt.png

Debug Fennec

This is the default option. Once you choose an object directory to use, the script will automatically launch Fennec, and run GDBServer to attach to Fennec.

The script tries to scan your user directory for object directories. For more control, see the Configuration section on how to specify default object directories or where to scan for object directories.

Debug Fennec with env vars and args

This option gives you the additional ability to specify environment variables and arguments when launching Fennec. See the Configuration section on how to specify additional default environment variables and arguments.

Debug using jdb

This option will let you use the Java debugger (jdb) to debug the native Java portion of Fennec. This is the default option if you already have a previous JimDB debugging session running.

JDB support is experimental. It is able to at least set breakpoints, show source code, and examine objects.

Debug content Mochitest

This option will let you debug a regular Mochitest. Make sure Fennec is compiled with the '--enable-tests' option in the mozconfig file. Because running Mochitests require a copy of the XUL Runtime Environment (XRE), the script will offer to automatically download a copy of XRE for you, as well as launching the test harness. You can specify a file or a directory to test, or set TEST_PATH. Environment variables and arguments to the test harness are also supported.

Debug compiled-code unit test

This option will let you debug a C++ test. Environment variables and arguments are supported.

Configuration

feninit.default.objdir

  • Set feninit.default.objdir to the default object directory. Note that once it is set, the script will not prompt you to choose an object directory.
  • Alternatively, if your object directories are called 'obj*' under your source directory, you can set feninit.default.objdir to the source directory itself. The script will scan the source directory and list all the object directories that it found.
  • Note that there have been problems in the past with using ~ and $HOME in the setting, so use absolute path for best results.
  • PRO-TIP: Put the following code block inside gdbinit.local to always use the current directory as the object directory,
python
import os
feninit.default.objdir = os.getcwd()
end

feninit.default.srcroot

  • Unlike the previous setting, feninit.default.srcroot specifies the directory containing all the source directories. This is convenient if you have 'src/mozilla-central', 'src/mozilla-inbound', 'src/mozilla-aurora', etc. In that case, you can set feninit.default.srcroot to 'src' and all the source directories will be scanned for object directories.
  • Again, use absolute path for best results.

feninit.default.no_launch

  • This settings is meant for B2G, and may not be useful for Fennec debugging.

feninit.default.gdbserver_port

  • To debug Fennec on your device, GDB on your computer needs to talk to GDBServer on your device through a TCP port forwarded to your device through ADB.
  • Normally, JimDB will use a random port. However, you can pick a specific port to use. This is useful in certain situations such as inside an SSH session. See this blog post.

feninit.default.jdwp_port

  • Similar to feninit.default.gdbserver_port, except for using JDB for debugging.

feninit.default.env

  • Specify the default environment variables to use when launching Fennec. Only used for the "Debug Fennec" options.

feninit.default.args

  • Specify the default arguments to use when launching Fennec. Only used for the "Debug Fennec" options.

feninit.default.cpp_env

  • Similar to feninit.default.env, except only used for the "Debug compiled-code unit test" option.

feninit.default.mochi_env

feninit.default.mochi_args

  • Specify the default arguments to use when debugging Mochitest. Only used for the "Debug content Mochitest" option.
  • Note that Mochitest arguments are arguments to the test harness (e.g. --remote-webserver), and not arguments to Fennec itself.

feninit.default.mochi_xre

  • Specify the XRE directory to use, instead of letting the script download and manage an XRE copy.

feninit.default.mochi_harness

  • Specify the directory containing the harness itself, i.e. "runtestsremote.py". Not needed normally.

feninit.default.mochi_xre_url

  • Specify the directory on ftp.mozilla.org to use for downloading XRE. Not used if feninit.default.mochi_xre is specified.

feninit.default.mochi_xre_update

  • Specify the XRE check for updates interval. Only used if the script is managing the XRE copy, and not used if feninit.default.mochi_xre_update is specified.

GDB commands specific to JimDB

set delay-add-remote-solibs

gdb> set delay-add-remote-solibs <0|1>

Default setting is 0. Set delay-add-remote-solibs to 1 to delay loading symbols when shared libraries are loaded. This may improve the set up time. However, you may need to use the "sharedlibrary" command to manually load symbols before using breakpoints.

monitor set ignore-ondemand

gdb> monitor set ignore-ondemand <0|1>

Default setting is 1. Set ignore-ondemand to 0 to not ignore segmentation faults generated by on-demand decompression. This setting may be needed to debug specific segmentation faults that are inadvertently being ignored. This command can only be run after attaching to the target, so it cannot be specified in gdbinit.local.

FAQ

What is moz-gdb?

  • moz-gdb was a synonym for JimDB, but it's no longer used, to avoid confusion

"configure: error: failure running python-config" when compiling GDB

  • python may point to python3 on your machine. You need to specify where python2 is by using, for example, --with-python=python2 in your configure line

"error while loading shared libraries: libtinfo.so.5" on Linux

  • You may need to create a libtinfo.so.5 symlink to libncurses.so.5. For example,
sudo ln -s libncurses.so.5 /usr/lib/libtinfo.so.5

"Segmentation fault: 11" or "Illegal instruction: 4" on Mac OS X

  • This may be due to incompatible OS X SDK versions. You should build your own JimDB binary to avoid the issue.

"cannot locate symbol "__exidx_end"" when starting to debug

  • If you're using pre-built binaries, you need to update to a newer version of JimDB
  • If you're using custom-built binaries, you need to recompile gdbserver using a newer version of the NDK

"No module named printing" when debugging Fennec with JimDB

  • The JimDB Python scripts lack several scripts included in regular GDB packages. To fix that, simply copy your local copy of these scripts to the JimDB utils/python directory. For example, on a typical Linux system, run
cp -r /usr/share/gdb/python/gdb $jimdb/utils/python/
  • If you don't have these files, they are available here; just extract it under $jimdb/utils/python/

Random segmentation faults when debugging Fennec

  • GDB can catch segmentation faults generated by on-demand decompression; just use "continue" to continue execution.
  • Alternatively, specify the "MOZ_LINKER_ONDEMAND=0" environment variable when launching Fennec using Option 2. You can also put the option inside jimdb/utils/gdbinit.local.

GDB crashed and Fennec is stuck. Halp!!

  • GDBServer may still be attached to Fennec but is unable to communicate with GDB; try killing GDBServer
adb shell run-as org.mozilla.fennec_$USER kill `adb shell ps | grep gdb | awk '{print $2}'`

"make: `[path]/mochitest-remote' is up to date." while trying to run Mochitests

  • Delete the mochitest-remote file.

"failed to run gdbserver"

   "gdbserver" output:
    /system/bin/sh: /data/local/tmp/gdbserver: not executable: magic 7F45
   "run-as" output:
    /data/local/tmp/gdbserver[1]: syntax error: '(' unexpected
   "su -c" output:
    /system/bin/sh: su: not found
   [path]/jimdb-x86/bin/../utils/gdbinit:136: Error in sourced command file:
   failed to run gdbserver

You are probably trying to run the x86 version on an ARM device. Download the ARM version of JimDB instead.

Alternatively, you may just have an out-of-date version of gdbserver. Check for an updated version in the link posted above.

   "gdbserver" output:
   error: only position independent executables (PIE) are supported.

This means your build of gdbserver is too old for the Android version you're debugging on. You may need a newer platform sysroot and/or to add flags to gdb/gdbserver/Makefile to build a position-independent executable.

   CFLAGS += -fvisibility=default -fPIE
   LDFLAGS += -rdynamic -fPIE -pie

JimDB sucks! Halp!!

  • Come on #mobile on IRC
  • Or file a bug under Firefox for Android, JimDB component

JimDB is awesome now!! Can I buy you a $beverage?

Yes! See also bug 800000

Using `next` to traverse a function sometimes gets stuck with an error like "Unable to find end of function"

Try using the env-var MOZ_LINKER_ONDEMAND=0.

Execution pauses often for "Program received signal SIG33, Real-time event 33."

This should be caught automatically, but try:

   handle SIG33 pass nostop noprint

"Symbol not found: __PyErr_ReplaceException"

You should not use python 2.7.11.

See : https://github.com/conda/conda/issues/1367