blob: 72530aa39a0b91c7e1c1e352bab604d8306b7fc6 [file] [log] [blame] [view]
andybonse6a8f2bd2015-08-31 22:46:011# Tips for debugging on Linux
andybons3322f762015-08-24 21:37:092
andybonsad92aa32015-08-31 02:27:443This page is for Chromium-specific debugging tips; learning how to run gdb is
4out of scope.
andybons3322f762015-08-24 21:37:095
andybonsad92aa32015-08-31 02:27:446[TOC]
andybons3322f762015-08-24 21:37:097
8## Symbolized stack trace
9
andybonsad92aa32015-08-31 02:27:4410The sandbox can interfere with the internal symbolizer. Use `--no-sandbox` (but
11keep this temporary) or an external symbolizer (see
12`tools/valgrind/asan/asan_symbolize.py`).
andybons3322f762015-08-24 21:37:0913
andybonsad92aa32015-08-31 02:27:4414Generally, do not use `--no-sandbox` on waterfall bots, sandbox testing is
15needed. Talk to security@chromium.org.
andybons3322f762015-08-24 21:37:0916
17## GDB
andybonsad92aa32015-08-31 02:27:4418
nodira6074d4c2015-09-01 04:26:4519*** promo
20GDB-7.7 is required in order to debug Chrome on Linux.
21***
andybons3322f762015-08-24 21:37:0922
23Any prior version will fail to resolve symbols or segfault.
24
Brett Wilson41a7de02023-04-27 18:56:5425### Setup
26
27#### Build setup
28
29In your build set the GN build variable `symbol_level = 2` for interactive
30debugging. (`symbol_level = 1` only provides backtrace information). And while
31release-mode debugging is possible, things will be much easier in a debug build.
32Set your build args with `gn args out/<your_dir>` (substituting your build
33directory), and set:
34
35```
36is_debug = true
37symbol_level = 2
38```
39
40#### GDB setup
41
42The Chrome build requires some GDB configuration for it to be able to find
Taiyo Mizuhashid0f90c9d2023-05-31 00:55:2343source files. See [gdbinit](../gdbinit.md) to configure GDB. There is a similar
44process for [LLDB](../lldbinit.md).
Brett Wilson41a7de02023-04-27 18:56:5445
andybons3322f762015-08-24 21:37:0946### Basic browser process debugging
47
andybonsad92aa32015-08-31 02:27:4448 gdb -tui -ex=r --args out/Debug/chrome --disable-seccomp-sandbox \
49 http://google.com
andybons3322f762015-08-24 21:37:0950
51### Allowing attaching to foreign processes
andybonsad92aa32015-08-31 02:27:4452
53On distributions that use the
54[Yama LSM](https://www.kernel.org/doc/Documentation/security/Yama.txt) (that
55includes Ubuntu and Chrome OS), process A can attach to process B only if A is
56an ancestor of B.
andybons3322f762015-08-24 21:37:0957
58You will probably want to disable this feature by using
andybonsad92aa32015-08-31 02:27:4459
60 echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope
andybons3322f762015-08-24 21:37:0961
62If you don't you'll get an error message such as "Could not attach to process".
63
andybonsad92aa32015-08-31 02:27:4464Note that you'll also probably want to use `--no-sandbox`, as explained below.
andybons3322f762015-08-24 21:37:0965
66### Multiprocess Tricks
andybonsad92aa32015-08-31 02:27:4467
andybons3322f762015-08-24 21:37:0968#### Getting renderer subprocesses into gdb
andybonsad92aa32015-08-31 02:27:4469
70Since Chromium itself spawns the renderers, it can be tricky to grab a
71particular with gdb. This command does the trick:
72
andybons3322f762015-08-24 21:37:0973```
74chrome --no-sandbox --renderer-cmd-prefix='xterm -title renderer -e gdb --args'
75```
andybonsad92aa32015-08-31 02:27:4476
77The `--no-sandbox` flag is needed because otherwise the seccomp sandbox will
78kill the renderer process on startup, or the setuid sandbox will prevent xterm's
79execution. The "xterm" is necessary or gdb will run in the current terminal,
80which can get particularly confusing since it's running in the background, and
81if you're also running the main process in gdb, won't work at all (the two
82instances will fight over the terminal). To auto-start the renderers in the
83debugger, send the "run" command to the debugger:
84
nodira6074d4c2015-09-01 04:26:4585 chrome --no-sandbox --renderer-cmd-prefix='xterm -title renderer -e gdb \
Zhang Haoa95224882021-05-12 11:26:3686 -ex run --args'
andybonsad92aa32015-08-31 02:27:4487
andybons3322f762015-08-24 21:37:0988If you're using Emacs and `M-x gdb`, you can do
andybons3322f762015-08-24 21:37:0989
andybonsad92aa32015-08-31 02:27:4490 chrome "--renderer-cmd-prefix=gdb --args"
andybons3322f762015-08-24 21:37:0991
nodira6074d4c2015-09-01 04:26:4592*** note
andybonsad92aa32015-08-31 02:27:4493Note: using the `--renderer-cmd-prefix` option bypasses the zygote launcher, so
94the renderers won't be sandboxed. It is generally not an issue, except when you
95are trying to debug interactions with the sandbox. If that's what you are doing,
96you will need to attach your debugger to a running renderer process (see below).
nodira6074d4c2015-09-01 04:26:4597***
andybons3322f762015-08-24 21:37:0998
andybonsad92aa32015-08-31 02:27:4499You may also want to pass `--disable-hang-monitor` to suppress the hang monitor,
100which is rather annoying.
101
102You can also use `--renderer-startup-dialog` and attach to the process in order
103to debug the renderer code. Go to
xiaoyin.l1003c0b2016-12-06 02:51:17104https://www.chromium.org/blink/getting-started-with-blink-debugging for more
andybonsad92aa32015-08-31 02:27:44105information on how this can be done.
andybons3322f762015-08-24 21:37:09106
Alex Gough20926742021-05-13 20:11:30107For utilities you can use `--utility-startup-dialog` to have all utilities
108prompt, or `--utility-startup-dialog=data_decoder.mojom.DataDecoderService`
109to debug only a particular service type.
110
andybons3322f762015-08-24 21:37:09111#### Choosing which renderers to debug
andybons3322f762015-08-24 21:37:09112
andybonsad92aa32015-08-31 02:27:44113If you are starting multiple renderers then the above means that multiple gdb's
114start and fight over the console. Instead, you can set the prefix to point to
115this shell script:
116
117```sh
andybons3322f762015-08-24 21:37:09118#!/bin/sh
119
120echo "**** Child $$ starting: y to debug"
121read input
122if [ "$input" = "y" ] ; then
123 gdb --args $*
124else
125 $*
126fi
127```
128
Robert Flackcdbf8c4a2022-11-18 18:12:34129#### Choosing renderer to debug by URL
130
131In most cases you'll want to debug the renderer which is loading a particular
132site. If you want a script which will automatically debug the renderer which has
133visited a given target URL and continue all other renderers, you can use the
134following:
135
136```sh
137./third_party/blink/tools/debug_renderer out/Default/content_shell https://example.domain/path
138```
139
140The script also supports specifying a different URL than the navigation URL.
141This is useful when the renderer you want to debug is not the top frame but one
142of the subframes on the page. For example, you could debug a particular subframe
143on a page with:
144
145```sh
146./third_party/blink/tools/debug_renderer -d https://subframe.url/path out/Default/content_shell https://example.domain/path
147```
148
149However, if you need more fine-grained control over which renderers to debug
150you can run chrome or content_shell directly with the
151`--wait-for-debugger-on-navigation` flag which will pause each renderer at the
152point of navigation (when the URL is known).
153
154This will result in a series of lines such as the following in the output:
155```
156...:content_switches_internal.cc(119)] Renderer url="https://example.domain/path" (PID) paused waiting for debugger to attach. Send SIGUSR1 to unpause.
157```
158
159You can signal the renderers you aren't interested in to continue running with:
160```sh
161kill -s SIGUSR1 <pid>
162```
163
164And debug the renderer you are interested in debugging with:
165```sh
166gdb -p <pid>
167```
168
Robert Flack6bbefe72023-02-24 18:49:51169#### Debugging run_web_tests.py renderers
170
171The `debug_renderer` script can also be used to debug the renderer running
Jonathan Leee95877f2023-09-26 21:16:30172a web test. To do so, simply call `run_{web,wpt}_tests.py` from `debug_renderer`
173with all of the standard arguments for `run_{web,wpt}_tests.py`. For example:
Robert Flack6bbefe72023-02-24 18:49:51174
175```sh
176./third_party/blink/tools/debug_renderer ./third_party/blink/tools/run_web_tests.py [run_web_test args]
177```
178
andybons3322f762015-08-24 21:37:09179#### Selective breakpoints
andybonsad92aa32015-08-31 02:27:44180
181When debugging both the browser and renderer process, you might want to have
182separate set of breakpoints to hit. You can use gdb's command files to
183accomplish this by putting breakpoints in separate files and instructing gdb to
184load them.
andybons3322f762015-08-24 21:37:09185
186```
andybonsad92aa32015-08-31 02:27:44187gdb -x ~/debug/browser --args chrome --no-sandbox --disable-hang-monitor \
188 --renderer-cmd-prefix='xterm -title renderer -e gdb -x ~/debug/renderer \
189 --args '
andybons3322f762015-08-24 21:37:09190```
191
andybonsad92aa32015-08-31 02:27:44192Also, instead of running gdb, you can use the script above, which let's you
193select which renderer process to debug. Note: you might need to use the full
194path to the script and avoid `$HOME` or `~/.`
andybons3322f762015-08-24 21:37:09195
196#### Connecting to a running renderer
197
andybonsad92aa32015-08-31 02:27:44198Usually `ps aux | grep chrome` will not give very helpful output. Try
199`pstree -p | grep chrome` to get something like
andybons3322f762015-08-24 21:37:09200
201```
202 | |-bash(21969)---chrome(672)-+-chrome(694)
203 | | |-chrome(695)---chrome(696)-+-{chrome}(697)
204 | | | \-{chrome}(709)
205 | | |-{chrome}(675)
206 | | |-{chrome}(678)
207 | | |-{chrome}(679)
208 | | |-{chrome}(680)
209 | | |-{chrome}(681)
210 | | |-{chrome}(682)
211 | | |-{chrome}(684)
212 | | |-{chrome}(685)
213 | | |-{chrome}(705)
214 | | \-{chrome}(717)
215```
216
andybonsad92aa32015-08-31 02:27:44217Most of those are threads. In this case the browser process would be 672 and the
218(sole) renderer process is 696. You can use `gdb -p 696` to attach.
219Alternatively, you might find out the process ID from Chrome's built-in Task
220Manager (under the Tools menu). Right-click on the Task Manager, and enable
221"Process ID" in the list of columns.
andybons3322f762015-08-24 21:37:09222
andybonsad92aa32015-08-31 02:27:44223Note: by default, sandboxed processes can't be attached by a debugger. To be
224able to do so, you will need to pass the `--allow-sandbox-debugging` option.
andybons3322f762015-08-24 21:37:09225
andybonsad92aa32015-08-31 02:27:44226If the problem only occurs with the seccomp sandbox enabled (and the previous
227tricks don't help), you could try enabling core-dumps (see the **Core files**
228section). That would allow you to get a backtrace and see some local variables,
229though you won't be able to step through the running program.
andybons3322f762015-08-24 21:37:09230
andybonsad92aa32015-08-31 02:27:44231Note: If you're interested in debugging LinuxSandboxIPC process, you can attach
232to 694 in the above diagram. The LinuxSandboxIPC process has the same command
233line flag as the browser process so that it's easy to identify it if you run
234`pstree -pa`.
andybons3322f762015-08-24 21:37:09235
236#### Getting GPU subprocesses into gdb
andybons3322f762015-08-24 21:37:09237
andybonsad92aa32015-08-31 02:27:44238Use `--gpu-launcher` flag instead of `--renderer-cmd-prefix` in the instructions
239for renderer above.
240
241#### Getting `browser_tests` launched browsers into gdb
242
243Use environment variable `BROWSER_WRAPPER` instead of `--renderer-cmd-prefix`
244switch in the instructions above.
andybons3322f762015-08-24 21:37:09245
246Example:
andybonsad92aa32015-08-31 02:27:44247
248```shell
249BROWSER_WRAPPER='xterm -title renderer -e gdb --eval-command=run \
250 --eval-command=quit --args' out/Debug/browser_tests --gtest_filter=Print
251```
andybons3322f762015-08-24 21:37:09252
253#### Plugin Processes
andybons3322f762015-08-24 21:37:09254
andybonsad92aa32015-08-31 02:27:44255Same strategies as renderers above, but the flag is called `--plugin-launcher`:
256
257 chrome --plugin-launcher='xterm -e gdb --args'
258
nodira6074d4c2015-09-01 04:26:45259*** note
260Note: For now, this does not currently apply to PPAPI plugins because they
261currently run in the renderer process.
262***
andybons3322f762015-08-24 21:37:09263
264#### Single-Process mode
andybons3322f762015-08-24 21:37:09265
andybonsad92aa32015-08-31 02:27:44266Depending on whether it's relevant to the problem, it's often easier to just run
267in "single process" mode where the renderer threads are in-process. Then you can
268just run gdb on the main process.
andybons3322f762015-08-24 21:37:09269
andybonsad92aa32015-08-31 02:27:44270 gdb --args chrome --single-process
271
272Currently, the `--disable-gpu` flag is also required, as there are known crashes
273that occur under TextureImageTransportSurface without it. The crash described in
xiaoyin.l1003c0b2016-12-06 02:51:17274https://crbug.com/361689 can also sometimes occur, but that crash can be
andybonsad92aa32015-08-31 02:27:44275continued from without harm.
276
277Note that for technical reasons plugins cannot be in-process, so
278`--single-process` only puts the renderers in the browser process. The flag is
279still useful for debugging plugins (since it's only two processes instead of
280three) but you'll still need to use `--plugin-launcher` or another approach.
andybons3322f762015-08-24 21:37:09281
282### Printing Chromium types
andybons3322f762015-08-24 21:37:09283
Tom Andersonf06ac382019-04-10 03:49:38284gdb 7 lets us use Python to write pretty-printers for Chromium types. See
Taiyo Mizuhashid0f90c9d2023-05-31 00:55:23285[gdbinit](../gdbinit.md)
Tom Andersonf06ac382019-04-10 03:49:38286to enable pretty-printing of Chromium types. This will import Blink
287pretty-printers as well.
Kenichi Ishibashie17b8d9f2018-04-26 03:32:46288
andybonsad92aa32015-08-31 02:27:44289Pretty printers for std types shouldn't be necessary in gdb 7, but they're
290provided here in case you're using an older gdb. Put the following into
291`~/.gdbinit`:
292
andybons3322f762015-08-24 21:37:09293```
294# Print a C++ string.
295define ps
296 print $arg0.c_str()
297end
298
299# Print a C++ wstring or wchar_t*.
300define pws
301 printf "\""
302 set $c = (wchar_t*)$arg0
303 while ( *$c )
304 if ( *$c > 0x7f )
305 printf "[%x]", *$c
306 else
307 printf "%c", *$c
308 end
309 set $c++
310 end
311 printf "\"\n"
312end
313```
314
315[More STL GDB macros](http://www.yolinux.com/TUTORIALS/src/dbinit_stl_views-1.01.txt)
316
Christian Biesinger3332bb3a2019-08-13 05:45:23317### JsDbg -- visualize data structures in the browser
318
319JsDbg is a debugger plugin to display various Chrome data structures in a
320browser window, such as the accessibility tree, layout object tree, DOM tree,
321and others.
322[Installation instructions are here](https://github.com/MicrosoftEdge/JsDbg),
323and see [here](https://github.com/MicrosoftEdge/JsDbg/blob/master/docs/FEATURES.md)
324for screenshots and an introduction.
325
326For Googlers, please see [go/jsdbg](https://goto.google.com/jsdbg) for
327installation instructions.
328
329### Time travel debugging with rr
330
331You can use [rr](https://rr-project.org) for time travel debugging, so you
332can also step or execute backwards. This works by first recording a trace
L. David Barone99d91eb2021-03-30 20:18:00333and then debugging based on that.
Christian Biesinger3332bb3a2019-08-13 05:45:23334
Jie Sheng01180e62025-03-29 03:48:01335For Googlers, if you have a remote cloud machine, please follow this
336[instruction](https://engdoc.corp.google.com/eng/doc/devguide/debugging/rr.md#setting-up-rr)
337to set up the machine in order to use the rr tool.
338
Steve Kobes8ce3e44d2022-01-28 22:36:59339You need an up-to-date version of rr, since rr is frequently updated to support
340new parts of the Linux system call API surface that Chromium uses. If you have
341any issues with the latest release version, try compiling rr
L. David Barone99d91eb2021-03-30 20:18:00342[from source](https://github.com/rr-debugger/rr/wiki/Building-And-Installing).
Robert Flackc9e69952020-05-13 19:52:31343
Christian Biesinger3332bb3a2019-08-13 05:45:23344Once installed, you can use it like this:
345```
Steve Kobes8ce3e44d2022-01-28 22:36:59346rr record out/Debug/content_shell --single-process
Christian Biesinger3332bb3a2019-08-13 05:45:23347rr replay
Steve Kobes8ce3e44d2022-01-28 22:36:59348(rr) c
349(rr) break blink::NGBlockNode::Layout
350(rr) rc # reverse-continue to the last Layout call
351(rr) jsdbg # run JsDbg as described above to find the interesting object
352(rr) watch -l box_->frame_rect_.size_.width_.value_
353(rr) rc # reverse-continue to the last time the width was changed
354(rr) rn # reverse-next to the previous line
355(rr) reverse-fin # run to where this function was called from
Christian Biesinger3332bb3a2019-08-13 05:45:23356```
357
L. David Barone99d91eb2021-03-30 20:18:00358You can debug multi-process chrome using `rr -f [PID]`
Steve Kobes8ce3e44d2022-01-28 22:36:59359for processes `fork()`ed from a [zygote process](zygote.md) without exec,
360which includes renderer processes,
361or `rr -p [PID]` for other processes.
362To find the process id you can either run `rr ps` after recording, or for
363renderer processes use `--vmodule=render_frame_impl=1` which will log a
364message on navigations. Example:
Robert Flacke13e0b12020-04-16 17:03:58365
366```
Steve Kobes8ce3e44d2022-01-28 22:36:59367$ rr record out/Debug/content_shell --disable-hang-monitor --vmodule=render_frame_impl=1 https://www.google.com/
Robert Flacke13e0b12020-04-16 17:03:58368rr: Saving execution to trace directory `...'.
369...
370[128515:128515:0320/164124.768687:VERBOSE1:render_frame_impl.cc(4244)] Committed provisional load: https://www.google.com/
371```
372
373From the log message we can see that the site was loaded into process 128515
374and can set a breakpoint for when that process is forked.
375
376```
377rr replay -f 128515
378```
379
L. David Barone99d91eb2021-03-30 20:18:00380If you want to call debugging functions from gdb that use `LOG()`,
Steve Kobes8ce3e44d2022-01-28 22:36:59381then those functions need to disable the printing of timestamps using
382[`SetLogItems`](https://source.chromium.org/search?q=SetLogItems&sq=&ss=chromium%2Fchromium%2Fsrc).
383See `LayoutObject::ShowLayoutObject()` for an example of this, and
384[issue 2829](https://github.com/rr-debugger/rr/issues/2829) for why it is needed.
L. David Barone99d91eb2021-03-30 20:18:00385
Steve Kobes8ce3e44d2022-01-28 22:36:59386If rr doesn't work correctly, the rr developers are generally quite responsive
387to [bug reports](https://github.com/rr-debugger/rr/issues),
L. David Barone99d91eb2021-03-30 20:18:00388especially ones that have enough information so that
389they don't have to build Chromium.
390
391See Also:
Steve Kobes8ce3e44d2022-01-28 22:36:59392
L. David Barone99d91eb2021-03-30 20:18:00393* [The Chromium Chronicle #13: Time-Travel Debugging with RR](https://developer.chrome.com/blog/chromium-chronicle-13/)
Steve Kobes8ce3e44d2022-01-28 22:36:59394* [@davidbaron demo using rr](https://twitter.com/davidbaron/status/1473761042278887433)
395* [@davidbaron demo using pernosco](https://twitter.com/davidbaron/status/1475836824409022469)
396(Googlers: see [go/pernosco](https://goto.google.com/pernosco))
L. David Barone99d91eb2021-03-30 20:18:00