diff options
Diffstat (limited to 'docs/contributing/debugging/debugging_firefox_with_gdb.rst')
-rw-r--r-- | docs/contributing/debugging/debugging_firefox_with_gdb.rst | 501 |
1 files changed, 501 insertions, 0 deletions
diff --git a/docs/contributing/debugging/debugging_firefox_with_gdb.rst b/docs/contributing/debugging/debugging_firefox_with_gdb.rst new file mode 100644 index 0000000000..8b188edc85 --- /dev/null +++ b/docs/contributing/debugging/debugging_firefox_with_gdb.rst @@ -0,0 +1,501 @@ +Debugging Firefox with GDB +========================== + ++--------------------------------------------------------------------+ +| This page is an import from MDN and the contents might be outdated | ++--------------------------------------------------------------------+ + +This page details how you can more easily debug Firefox and work around +some GDB problems. + +Use GDB 5, or higher. A more recent version of GDB can be obtained from +`sourceware <https://sourceware.org/gdb/>`__ or your Linux distro repo. +If you are running less than 256 MB of RAM, be sure to see `Using gdb on +wimpy computers <https://developer.mozilla.org/en/Using_gdb_on_wimpy_computers>`__. + +Where can I find general gdb documentation? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Using GDB is beyond the scope of this document. Documentation is likely +available on your system if you have GDB installed, in the form of +**info,** **man** pages, or the gnome help browser. Additionally, you +can use a graphical front-end to GDB like +`ddd <https://www.gnu.org/software/ddd/>`__ or +`insight <https://sourceware.org/insight/>`__. For more information see +https://sourceware.org/gdb/current/onlinedocs/gdb/ + +How do I run Firefox under gdb? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The preferred method, is using the +:ref:`mach` command-line tool to run the +debugger, which can bypass several optional defaults. Use "mach help +run" to get more details. If inside the source directory, you would use +"./mach". Please note that :ref:`mach is aware of mozconfigs <mach_and_mozconfigs>`. + +.. code:: bash + + $ ./mach run --debug [arguments to pass to firefox] + +If you need to direct arguments to gdb, you can use '--debugger-args' +options via the command line parser, taking care to adhere to shell +splitting rules. For example, if you wanted to run the command 'show +args' when gdb starts, you would use: + +.. code:: bash + + $ ./mach run --debug --debugger-args "-ex 'show args'" + +Alternatively, you can run gdb directly against Firefox. However, you +won't get some of the more useful capabilities this way. For example, +mach sets an environment variable (see below) to stop the JS engine from +generating synthetic segfaults to support the slower script dialoging +mechanism. + +.. code:: + + (gdb) OBJDIR/dist/bin/firefox + +How do I pass arguments in prun? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Set the arguments in GDB before calling prun. Here's an example on how +to do that: + +.. code:: + + (gdb) set args https://www.mozilla.org + (gdb) prun + +How do I set a breakpoint in a library that hasn't been loaded? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +GDB 6.1 and above has support for "pending breakpoints". This is +controlled by the "``set breakpoint pending``" setting, and is enabled +by default. If a breakpoint cannot be immediately resolved, it will be +re-checked each time a shared library is loaded, by the process being +debugged. If your GDB is older than this, you should upgrade. + +In older versions, there isn't a way to set breakpoints in a library +that has not yet been loaded. See more on `setting a breakpoint when a +component is +loaded <#How_do_I_set_a_breakpoint_when_a_component_is_loaded.3F>`__. If +you have to set a breakpoint you can set a breakpoint in ``_dl_open``. +This function is called when a new library is loaded, when you can +finally set your breakpoint. + +How do I set a breakpoint when a component is loaded? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +In Firefox Version 57 (and possibly earlier) XPCOM_BREAK_ON_LOAD does +not seem to exist. + +There's a facility in XPCOM which allows you to set an environment +variable to drop into the debugger when loading a certain component. You +have to set ``XPCOM_BREAK_ON_LOAD`` variable before you run Firefox, +setting it to a string containing the names of libraries you want to +load. For example, if you wish to stop when a library named ``raptor`` +or ``necko`` is loaded, you set the variable to ``raptor:necko``. Here's +an example: + +.. code:: + + (gdb) set env XPCOM_BREAK_ON_LOAD raptor:necko + (gdb) prun + +Why can't I set a breakpoint? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +You probably can't set a breakpoint because its library hasn't been +loaded. Most Firefox functionality is in libraries loaded mid-way +through the ``main()``\ function. If you break on ``main(),``\ and step +through until the libraries are loaded, with a call to +``InitCOMGlue()``, you should be able to set breakpoints on many more +symbols, source files, and continue running. + +.. code:: + + (gdb) break main + (gdb) run + Breakpoint 1, main(argc=4, argv=0x7fffffffde98, envp=0x7ffffffffdec0) ..... + 256 { + (gdb) next + ... + 293 nsresult rv = InitXPCOMGlue() + (gdb) next + +If you still can't set the breakpoints, you need to confirm the library +has loaded. You can't proceed until the library loads. See more on +`loading shared libraries <#How_do_I_load_shared_libraries.3F>`__. If +you wish to break as soon as the library is loaded, see the section on +`breaking when a component is +loaded <#How_do_I_set_a_breakpoint_when_a_component_is_loaded.3F>`__ and +`breaking on a library +load <#How_do_I_set_a_breakpoint_when_a_component_is_loaded.3F>`__. + +How do I display PRUnichar's? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +One suggestion is this: + +.. code:: + + (gdb) print ((PRUnichar*)uri.mBuffer)[0]@16 + $47 = {114, 100, 102, 58, 110, 117, 108, 108, 0, 0, 8, 0, 0, 0, 37432, + 16514} + + + +.. code:: + + (gdb) print aURI + $1 = (const PRUnichar *) 0x855e6e0 + (gdb) x/32ch aURI + 0x855e6e0: 104 'h' 116 't' 116 't' 112 'p' 58 ':' 47 '/' 47 '/' 119 'w' + 0x855e6f0: 119 'w' 119 'w' 46 '.' 109 'm' 111 'o' 122 'z' 105 'i' 108 'l' + 0x855e700: 108 'l' 97 'a' 46 '.' 111 'o' 114 'r' 103 'g' 47 '/' 115 's' + 0x855e710: 116 't' 97 'a' 114 'r' 116 't' 47 '/' 0 '\0' 25 '\031' 0 '\0' + (gdb) + +- Define helper functions in your .gdbinit + +.. code:: + + # Define a "pu" command to display PRUnichar * strings (100 chars max) + # Also allows an optional argument for how many chars to print as long as + # it's less than 100. + def pu + set $uni = $arg0 + if $argc == 2 + set $limit = $arg1 + if $limit > 100 + set $limit = 100 + end + else + set $limit = 100 + end + # scratch array with space for 100 chars plus null terminator. Make + # sure to not use ' ' as the char so this copy/pastes well. + set $scratch = "____________________________________________________________________________________________________" + set $i = 0 + set $scratch_idx = 0 + while (*$uni && $i++ < $limit) + if (*$uni < 0x80) + set $scratch[$scratch_idx++] = *(char*)$uni++ + else + if ($scratch_idx > 0) + set $scratch[$scratch_idx] = '\0' + print $scratch + set $scratch_idx = 0 + end + print /x *(short*)$uni++ + end + end + if ($scratch_idx > 0) + set $scratch[$scratch_idx] = '\0' + print $scratch + end + end + + # Define a "ps" command to display subclasses of nsAC?String. Note that + # this assumes strings as of Gecko 1.9 (well, and probably a few + # releases before that as well); going back far enough will get you + # to string classes that this function doesn't work for. + def ps + set $str = $arg0 + if (sizeof(*$str.mData) == 1 && ($str.mFlags & 1) != 0) + print $str.mData + else + pu $str.mData $str.mLength + end + end + +`This is hard. Give me a .gdbinit that already has the +functions. <#This_is_hard._Give_me_a_.gdbinit_that_works.>`__ + +- Define a small helper function "punichar" in #ifdef NS_DEBUG code + somewhere. + +How do I display an nsString? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +You can call the ToNewCString() method on the nsString. It leaks a +little memory but it shouldn't hurt anything if you only do it a few +times in one gdb session. (via akkana@netscape.com) + +.. code:: + + (gdb) p string.ToNewCString() + +Another method (via bent) is the following (replace ``n`` with: the +returned length of your string): + +.. code:: + + (gdb) p string.Length() + $1 = n + (gdb) x/ns string.BeginReading() + +You can of course use any of the above unichar-printing routines instead +of x/s. + +This is hard. Give me a .gdbinit that works. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +See `Boris Zbarsky's +.gdbinit <http://web.mit.edu/bzbarsky/www/gdbinit>`__. It contained +several function definitions including: + +- "prun" to start the browser and disable library loading. +- "pu" which will display a (PRUnichar \*) string. +- "ps" which will display a nsString. + +How do I determine the concrete type of an object pointed to by an interface pointer? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +You can determine the concrete type of any object pointed to, by an +XPCOM interface pointer, by looking at the mangled name of the symbol +for the object's vtable: + +.. code:: + + (gdb) p aKidFrame + $1 = (nsIFrame *) 0x85058d4 + (gdb) x/wa *(void**)aKidFrame + 0x4210d380 <__vt_14nsRootBoxFrame>: 0x0 + (gdb) p *(nsRootBoxFrame*)aKidFrame + [ all the member variables of aKidFrame ] + +If you're using gcc 3.x, the output is slightly different from the gcc +2.9x output above. Pay particular attention to the vtable symbol, in +this case ``__vt_14nsRootBoxFrame``. You won't get anything useful if +the shared library containing the object is not loaded. See `How do I +load shared libraries? <#How_do_I_load_shared_libraries.3F>`__ and `How +do I see what libraries I already have +loaded? <#How_do_I_see_what_libraries_I_already_have_loaded.3F>`__ + +Or use the gdb command ``set print object on``. + +How can I debug JavaScript from gdb? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If you have JavaScript Engine code on the stack, you'll probably want a +JS stack in addition to the C++ stack. + +.. code:: + + (gdb) call DumpJSStack() + +See `https://developer.mozilla.org/en-US/docs/Mozilla/Debugging/Debugging_JavaScript <https://developer.mozilla.org/en-US/docs/Mozilla/Debugging/Debugging_JavaScript>`__ +for more JS debugging tricks. + +How can I debug race conditions and/or how can I make something different happen at NS_ASSERTION time? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +| [submitted by Dan Mosedale] +| As Linux is unable to generate useful core files for multi-threaded + applications, tracking down race-conditions which don't show up under + the debugger can be a bit tricky. Unless you've given the + ``--enable-crash-on-assert`` switch to ``configure``, you can now + change the behavior of ``NS_ASSERTION`` (nsDebug::Break) using the + ``XPCOM_DEBUG_BREAK`` environment variable. + +How do I run the debugger in emacs/xemacs? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Emacs and XEmacs contain modes for doing visual debugging. However, you +might want to set up environment variables, specifying the loading of +symbols and components. The easiest way to set up these is to use the +``run-mozilla.sh`` script, located in the dist/bin directory of your +build. This script sets up the environment to run the editor, shell, +debugger, or defining a preferred setup and running any commands you +wish. For example: + +.. code:: bash + + $ ./run-mozilla.sh /bin/bash + MOZILLA_FIVE_HOME=/home/USER/src/mozilla/build/dist/bin + LD_LIBRARY_PATH=/home/USER/src/mozilla/build/dist/bin + LIBRARY_PATH=/home/USER/src/mozilla/build/dist/bin + SHLIB_PATH=/home/USER/src/mozilla/build/dist/bin + LIBPATH=/home/USER/src/mozilla/build/dist/bin + ADDON_PATH=/home/USER/src/mozilla/build/dist/bin + MOZ_PROGRAM=/bin/bash + MOZ_TOOLKIT= + moz_debug=0 + moz_debugger= + +GDB 5 used to work for me, but now Firefox won't start. What can I do? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +A recent threading change (see `bug +57051 <https://bugzilla.mozilla.org/show_bug.cgi?id=57051>`__ for +details) caused a problem on some systems. Firefox would get part-way +through its initialization, then stop before showing a window. A recent +change to gdb has fixed this. Download and build `the latest version of +Insight <https://sources.redhat.com/insight/>`__, or if you don't want a +GUI, `the latest version of gdb <https://sources.redhat.com/gdb/>`__. + +"run" or "prun" in GDB fails with "error in loading shared libraries." +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Running mozilla-bin inside GDB fails with an error message like: + +.. code:: + + Starting program: + /u/dmose/s/mozilla/mozilla-all/mozilla/dist/bin/./mozilla-bin + /u/dmose/s/mozilla/mozilla-all/mozilla/dist/bin/./mozilla-bin: error + in loading shared libraries: libraptorgfx.so: cannot open shared + object file: No such file or directory + +Your LD_LIBRARY_PATH is probably being reset by your .cshrc or .profile. +From the GDB manual: + +*\*Warning:\* GDB runs your program using the shell indicated by your +'SHELL' environment variable if it exists (or '/bin/sh' if not). If your +'SHELL' variable names a shell that runs an initialization file -- such +as '.cshrc' for C-shell, or '.bashrc' for BASH--any variables you set in +that file affect your program. You may wish to move the setting of +environment variables to files that are only run when you sign on, such +as '.login' or '.profile'.* + +Debian's GDB doesn't work. What do I do? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Debian's unstable distribution currently uses glibc 2.1 and GDB 4.18. +However, there is no package of GDB for Debian with the appropriate +threads patches that will work with glibc 2.1. I was able to get this to +work by getting the GDB 4.18 RPM from Red Hat's rawhide server and +installing that. It has all of the patches necessary for debugging +threaded software. These fixes are expected to be merged into GDB, which +will fix the problem for Debian Linux. (via `Bruce +Mitchener <mailto:bruce@cybersight.com>`__) + +Firefox is aborting. Where do I set a breakpoint to find out where it is exiting? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +On Linux there are two possible symbols that are causing this: +``PR_ASSERT()`` and ``NS_ASSERTION()``. To see where it's asserting you +can stop at two places: + +.. code:: + + (gdb) b abort + (gdb) b exit + +I keep getting a SIGSEGV in JS/JIT code under gdb even though there is no crash when gdb is not attached. How do I fix it? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Set the JS_DISABLE_SLOW_SCRIPT_SIGNALS environment variable (in FF33, +the shorter and easier-to-remember JS_NO_SIGNALS). For an explanation, +read `Jan's blog +post <https://www.jandemooij.nl/blog/2014/02/18/using-segfaults-to-interrupt-jit-code/>`__. + +I keep getting a SIG32 in the debugger. How do I fix it? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If you are getting a SIG32 while trying to debug Firefox you might have +turned off shared library loading before the pthreads library was +loaded. For example, ``set auto-solib-add 0`` in your ``.gdbinit`` file. +In this case, you can either: + +- Remove it and use the method explained in the section about `GDB's + memory + usage <#The_debugger_uses_a_lot_of_memory._How_do_I_fix_it.3F>`__ +- Use ``handle SIG32 noprint`` either in gdb or in your ``.gdbinit`` + file + +Alternatively, the problem might lie in your pthread library. If this +library has its symbols stripped, then GDB can't hook into thread +events, and you end up with SIG32 signals. You can check if your +libpthread is stripped in ``file /lib/libpthread*`` and looking for +``'stripped'.``\ To fix this problem on Gentoo Linux, you can re-emerge +glibc after adding ``"nostrip"`` to your ``FEATURES`` in +``/etc/make.conf``. + +How do I get useful stack traces inside system libraries? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Many Linux distributions provide separate packages with debugging +information for system libraries, such as gdb, Valgrind, profiling +tools, etc., to give useful stack traces via system libraries. + +Fedora +^^^^^^ + +On Fedora, you need to enable the debuginfo repositories, as the +packages are in separate repositories. Enable them permanently, so when +you get updates you also get security updates for these packages. A way +to do this is edit ``/etc/yum.repos.d/fedora.repo`` and +``fedora-updates.repo`` to change the ``enabled=0`` line in the +debuginfo section to ``enabled=1``. This may then flag a conflict when +upgrading to a new distribution version. You would the need to perform +this edit again. + +You can finally install debuginfo packages with yum or other package +management tools. The best way is install the ``yum-utils`` package, and +then use the ``debuginfo-install`` command to install all the debuginfo: + +.. code:: bash + + $ yum install yum-utils + $ debuginfo-install firefox + +This can be done manually using: + +.. code:: bash + + $ yum install GConf2-debuginfo ORBit2-debuginfo atk-debuginfo \ + cairo-debuginfo dbus-debuginfo dbus-glib-debuginfo expat-debuginfo \ + fontconfig-debuginfo freetype-debuginfo gcc-debuginfo glib2-debuginfo \ + glibc-debuginfo gnome-vfs2-debuginfo gtk2-debuginfo gtk2-engines-debuginfo \ + hal-debuginfo libX11-debuginfo libXcursor-debuginfo libXext-debuginfo \ + libXfixes-debuginfo libXft-debuginfo libXi-debuginfo libXinerama-debuginfo \ + libXrender-debuginfo libbonobo-debuginfo libgnome-debuginfo \ + libselinux-debuginfo pango-debuginfo popt-debuginfo scim-bridge-debuginfo + +Debugging electrolysis (e10s) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +``mach run`` and ``mach test`` both accept a ``--disable-e10s`` +argument. Some debuggers can't catch child-process crashes without it. + +You can find some (outdated) information on +https://wiki.mozilla.org/Electrolysis/Debugging. You may also like to +read +https://mikeconley.ca/blog/2014/04/25/electrolysis-debugging-child-processes-of-content-for-make-benefit-glorious-browser-of-firefox +for a more up-to-date blog post. + +To get the child process id use: + +.. code:: + + MOZ_DEBUG_CHILD_PROCESS=1 mach run + +See also +~~~~~~~~~ + +- `Debugging <https://developer.mozilla.org/En/Debugging>`__ +- `Performance tools <https://wiki.mozilla.org/Performance:Tools>`__ +- `Fun with + gdb <https://blog.mozilla.com/sfink/2011/02/22/fun-with-gdb/>`__ by + Steve Fink +- `Archer pretty printers for + SpiderMonkey <https://hg.mozilla.org/users/jblandy_mozilla.com/archer-mozilla>`__ + (`blog + post <https://itcouldbesomuchbetter.wordpress.com/2010/12/20/debugging-spidermonkey-with-archer-2/>`__) +- `More pretty + printers <https://hg.mozilla.org/users/josh_joshmatthews.net/archer-mozilla/>`__ + for Gecko internals (`blog + post <https://www.joshmatthews.net/blog/2011/06/nscomptr-has-never-been-so-pretty/>`__) + +.. container:: originaldocinfo + + .. rubric:: Original Document Information + :name: Original_Document_Information + + - `History <http://bonsai-www.mozilla.org/cvslog.cgi?file=mozilla-org/html/unix/debugging-faq.html&rev=&root=/www/>`__ + - Copyright Information: © 1998-2008 by individual mozilla.org + contributors; content available under a `Creative Commons + license <https://www.mozilla.org/foundation/licensing/website-content.html>`__ |