debugging_firefox_with_gdb.rst (10782B)
1 Debugging Firefox with GDB 2 ========================== 3 4 This page details how you can more easily debug Firefox with gdb. :ref:`rr 5 <Debugging Firefox with rr>` is most often a better choice to debug a problem, 6 but sometimes it isn't possible to use it, such as attempting to reproduce a 7 race condition or when performance is important to reproduce an issue. ``rr`` 8 chaos mode allows reproducing a lot of issues though, and should be tried. 9 10 Where can I find general gdb documentation? 11 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 12 13 Using GDB is beyond the scope of this document. Documentation is likely 14 available on your system if you have GDB installed, in the form of 15 **info,** **man** pages, or the gnome help browser. Additionally, you 16 can use a graphical front-end to GDB like 17 `ddd <https://www.gnu.org/software/ddd/>`__ or 18 `insight <https://sourceware.org/insight/>`__. For more information see 19 https://sourceware.org/gdb/current/onlinedocs/gdb/ 20 21 How to debug Firefox with gdb? 22 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 23 24 Firefox is a multiprocess application, with a parent process, and several child 25 processes, each specialized and sandboxed differently. 26 27 .. code:: bash 28 29 $ ./mach run --debugger=gdb 30 31 allows running Firefox in gdb, and debug the parent process. You can substitute 32 ``run`` with another action, such as ``test``, ``mochitest``, ``xpcshell-test``, 33 etc. 34 35 Debugging child processes can be done by attaching the debugger. 36 37 .. code:: bash 38 39 $ gdb --pid <pid> 40 41 There's a number of ways to find the PID of a process: hovering over a tab for a 42 content process, opening ``about:processes``, using ``ps ... | grep firefox`` on 43 the command line, etc. 44 45 Sometimes, it is desirable to attach to a child process at startup, to diagnose 46 something very close to the start of the process. Setting the environment 47 variable ``MOZ_DEBUG_CHILD_PROCESS=10`` will make each new process print an few 48 informative lines, including the process type and its PID. The process with then 49 sleep for a number of seconds equal to the value of the environment variable, 50 allowing to attach a debugger. 51 52 .. code:: bash 53 54 $ MOZ_DEBUG_CHILD_PROCESS=10 ./mach run 55 ... 56 ... 57 ... 58 59 CHILDCHILDCHILDCHILD (process type tab) 60 debug me @ 65230 61 62 ... 63 ... 64 ... 65 66 Attaching gdb to Firefox might fail on Linux distributions that enable common 67 kernel hardening features such as the Yama security module. If you encounter the 68 following error when attaching: 69 70 .. code:: bash 71 72 $ gdb --pid <pid> 73 ... 74 ... 75 76 Attaching to process <pid> 77 ptrace: Operation not permitted. 78 79 Check the contents of `/proc/sys/kernel/yama/ptrace_scope`. If it set to `1` 80 you won't be able to attach to processes, set it to `0` from a root shell: 81 82 .. code:: bash 83 84 \# echo 0 > /proc/sys/kernel/yama/ptrace_scope 85 86 If you still can't attach check your setup carefully. Do not, under any 87 circumstances, run gdb as root. Since gdb can execute arbitrary code and spawn 88 shells it can be extremely dangerous to use it with root permissions. 89 90 91 Advanced gdb configuration 92 ~~~~~~~~~~~~~~~~~~~~~~~~~~ 93 94 The preferred method, is using the 95 :ref:`mach` command-line tool to run the 96 debugger, which can bypass several optional defaults. Use "mach help 97 run" to get more details. If inside the source directory, you would use 98 "./mach". Please note that 99 :ref:`mach is aware of mozconfigs <Configuring Build Options>`. 100 101 .. code:: bash 102 103 $ ./mach run --debug [arguments to pass to firefox] 104 105 If you need to direct arguments to gdb, you can use '--debugger-args' 106 options via the command line parser, taking care to adhere to shell 107 splitting rules. For example, if you wanted to run the command 'show 108 args' when gdb starts, you would use: 109 110 .. code:: bash 111 112 $ ./mach run --debug --debugger-args "-ex 'show args'" 113 114 Alternatively, you can run gdb directly against Firefox. However, you 115 won't get some of the more useful capabilities this way. For example, 116 mach sets an environment variable (see below) to stop the JS engine from 117 generating synthetic segfaults to support the slower script dialoging 118 mechanism. 119 120 .. code:: 121 122 (gdb) $OBJDIR/dist/bin/firefox 123 124 How to debug a Firefox in the field (not compiled on the host) 125 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 126 127 If you need to attach to a Firefox process live on a machine, and this Firefox 128 was built by Mozilla, or by certain Linux distros, it's possible to get symbols 129 and sources using the Mozilla symbol server, see :ref:`this section <Downloading 130 symbols on Linux / Mac OS X>` for setup instructions, it's just a matter of 131 sourcing a python script in ``.gdbinit``. 132 133 Debugging then works as usual, except the build probably has a very high 134 optimization level. 135 136 How do I pass arguments in prun? 137 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 138 139 Set the arguments in GDB before calling prun. Here's an example on how 140 to do that: 141 142 .. code:: 143 144 (gdb) set args https://www.mozilla.org 145 (gdb) prun 146 147 Why breakpoints seem to not be hit? 148 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 149 150 The most likely cause is that `gdb` hasn't been attached to the process in which 151 the code to diagnose is ran. Enabling the relevant `MOZ_LOG` modules can help, 152 since by default it prints the process type and pid of all logging statements. 153 154 `break list` will display a list of breakpoints, and whether or not they're 155 enabled. C++ namespaces need to be specified entirely, and it's sometimes hard 156 to break in lambda. Breaking by line number is an alternative strategy that 157 often works in this case. 158 159 How do I display an nsString? 160 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 161 162 .. code:: 163 164 (gdb) p ToNewCString(string); 165 166 This leaks a bit of memory but it doesn't really matter. 167 168 How do I determine the concrete type of an object pointed to by an interface pointer? 169 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 170 171 You can determine the concrete type of any object pointed to, by an 172 XPCOM interface pointer, by looking at the mangled name of the symbol 173 for the object's vtable: 174 175 .. code:: 176 177 (gdb) p aKidFrame 178 $1 = (nsIFrame *) 0x85058d4 179 (gdb) x/wa *(void**)aKidFrame 180 0x4210d380 <__vt_14nsRootBoxFrame>: 0x0 181 (gdb) p *(nsRootBoxFrame*)aKidFrame 182 [ all the member variables of aKidFrame ] 183 184 Or use the gdb command ``set print object on``. 185 186 How can I debug JavaScript from gdb? 187 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 188 189 If you have JavaScript Engine code on the stack, you'll probably want a 190 JS stack in addition to the C++ stack. 191 192 .. code:: 193 194 (gdb) call DumpJSStack() 195 196 Please note that if `gdb` has been attached to a process, the stack might be 197 printed in the terminal window in which Firefox was started. 198 199 See 200 `this MDN page 201 <https://developer.mozilla.org/en-US/docs/Mozilla/Debugging/Debugging_JavaScript>`__ 202 for more JS debugging tricks. 203 204 How can I debug race conditions 205 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 206 207 Try :ref:`rr <Debugging Firefox with rr>` first. If this doesn't work, good 208 luck, maybe try :ref:`logging <Gecko Logging>` or sprinkling assertions. 209 210 I keep getting a SIGSYS, or SIGSEGV in JS/JIT code under gdb even though there is no crash when gdb is not attached. How do I fix it? 211 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 212 213 Allow gdb to read mozilla-central's .gdbinit, located at `build/.gdbinit`. In 214 your own `.gdbinit`, add the line: 215 216 .. code:: 217 218 add-auto-load-safe-path /path/to/mozilla-central 219 220 How do I get useful stack traces inside system libraries? 221 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 222 223 Many Linux distributions provide separate packages with debugging 224 information for system libraries, such as gdb, Valgrind, profiling 225 tools, etc., to give useful stack traces via system libraries. 226 227 The modern way to do this is to enable ``debuginfod``. This can be done by adding: 228 229 .. code:: 230 231 set debuginfod enabled on 232 233 in your ``.gdbinit``, but there might be distro-specific instructions. 234 Alternatively, you can install the packages that contain the debug symbols for 235 the libraries you want to debug. 236 237 When using ``debuginfod``, the correct information will be downloaded 238 automatically when needed (and subsequently cached). 239 240 If you're not sure what to use, there's a federated debuginfod server that 241 provides debug information for most mainstream distributions. You can use it 242 by adding the following line to your ``.gdbinit`` file: 243 244 .. code:: 245 246 set debuginfod urls "https://debuginfod.elfutils.org/" 247 248 Keep in mind that it might take a while to download debug information the 249 very first time. This queries all the servers of multiple distributions 250 sequentially and debug information tends to be large. It will be cached for the 251 next run though. 252 253 Fedora 254 ^^^^^^ 255 256 On Fedora, you need to enable the debuginfo repositories, as the 257 packages are in separate repositories. Enable them permanently, so when 258 you get updates you also get security updates for these packages. A way 259 to do this is edit ``/etc/yum.repos.d/fedora.repo`` and 260 ``fedora-updates.repo`` to change the ``enabled=0`` line in the 261 debuginfo section to ``enabled=1``. This may then flag a conflict when 262 upgrading to a new distribution version. You would the need to perform 263 this edit again. 264 265 You can finally install debuginfo packages with yum or other package 266 management tools. The best way is install the ``yum-utils`` package, and 267 then use the ``debuginfo-install`` command to install all the debuginfo: 268 269 .. code:: bash 270 271 $ yum install yum-utils 272 $ debuginfo-install firefox 273 274 This can be done manually using: 275 276 .. code:: bash 277 278 $ yum install GConf2-debuginfo ORBit2-debuginfo atk-debuginfo \ 279 cairo-debuginfo dbus-debuginfo expat-debuginfo \ 280 fontconfig-debuginfo freetype-debuginfo gcc-debuginfo glib2-debuginfo \ 281 glibc-debuginfo gnome-vfs2-debuginfo gtk2-debuginfo gtk2-engines-debuginfo \ 282 hal-debuginfo libX11-debuginfo libXcursor-debuginfo libXext-debuginfo \ 283 libXfixes-debuginfo libXft-debuginfo libXi-debuginfo libXinerama-debuginfo \ 284 libXrender-debuginfo libbonobo-debuginfo libgnome-debuginfo \ 285 libselinux-debuginfo pango-debuginfo popt-debuginfo scim-bridge-debuginfo 286 287 Disabling multiprocess 288 ~~~~~~~~~~~~~~~~~~~~~~ 289 290 ``mach run`` and ``mach test`` both accept a ``--disable-e10s`` argument. Some 291 debuggers can't catch child-process crashes without it. This is sometimes a 292 viable alternative to attaching, but these days it changes enough thing that 293 it's not always a usable option. 294 295 See also 296 ~~~~~~~~~ 297 298 299 - `Mike Conley's blog post <https://mikeconley.ca/blog/2014/04/25/electrolysis-debugging-child-processes-of-content-for-make-benefit-glorious-browser-of-firefox>`__ 300 - `Performance tools <https://wiki.mozilla.org/Performance:Tools>`__ 301 - `Fun with 302 gdb <https://blog.mozilla.com/sfink/2011/02/22/fun-with-gdb/>`__ by 303 Steve Fink