summaryrefslogtreecommitdiffstats
path: root/docs/contributing/debugging/debugging_firefox_with_gdb.rst
blob: 8b188edc859d1b5bf6c72aacdf3984be5451b616 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
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>`__