Debugging Chromium on Windows

First see get the code for checkout and build instructions.

Getting started

You can use Visual Studio‘s built-in debugger or WinDBG to debug Chromium. You don’t need to use the IDE to build in order to use the debugger: most developers use Ninja to build, and then open the IDE for debugging as necessary. To start debugging an executable from the command line:

**devenv **/debugexe out\Debug\chrome.exe

This assumes you have Visual Studio installed and have devenv.exe on your path. Note that the path to the binary must use backslashes and must include the “.exe” suffix or Visual Studio will open and do nothing.

Goma (the internal Google distributed build) will not produce symbols so most debugging won't work (see discussion thread). You will want to do local builds when using a debugger.

Profiles

It‘s a good idea to use a different profile for your debugging. If you are debugging Google Chrome branded builds, or use a Chromium build as your primary browser, the profiles can collide so you can’t run both at once, and your stable browser might see profile versions from the future (Google Chrome and Chromium use different profile directories by default so won't collide). Use the command-line option:

--user-data-dir=c:\tmp\my_debug_profile (replace the path as necessary)

Using the IDE, go to the Debugging tab of the properties of the chrome project, and set the Command Arguments.

Chrome debug log

Enable Chrome debug logging to a file by passing --enable-logging --v=1 command-line flags at startup. Debug builds place the chrome_debug.log file in the out\Debug directory. Release builds place the file in the top level of the user data Chromium app directory, which is OS-version-dependent. For more information, see logging and user data directory details.

Symbol server

If you are debugging official Google Chrome release builds, use the symbol server:

https://chromium-browser-symsrv.commondatastorage.googleapis.com.

In Visual Studio, this goes in Tools > Options under Debugging > Symbols. It will be faster if you set up a local cache in a empty directory on your computer.

Multi-process issues

Chromium can be challenging to debug because of its multi-process architecture. When you select Run in the debugger, only the main browser process will be debugged. The code that actually renders web pages (the Renderer) and the plugins will be in separate processes that's not (yet!) being debugged. The ProcessExplorer tool has a process tree view where you can see how these processes are related. You can also get the process IDs associated with each tab from the Chrome Task Manager (right-click on an empty area of the window title bar to open).

Single-process mode

The easiest way to debug issues is to run Chromium in single-process mode. This will allow you to see the entire state of the program without extra work (although it will still have many threads). To use single-process mode, add the command-line flag

--single-process

This approach isn‘t perfect because some problems won’t manifest themselves in this mode and some features don't work and worker threads are still spawned into new processes.

Manually attaching to a child process

You can attach to the running child processes with the debugger. Select

**Tools > Attach**** to Process** and click the **chrome.exe** process you
want to attach to. Before attaching, make sure you have selected only Native
code when attaching to the process This is done by clicking Select... in the
Attach to Process window and only checking Native. If you forget this, it
may attempt to attach in "WebKit" mode to debug JavaScript, and you'll get
an error message "An operation is not legal in the current state."

You can now debug the two processes as if they were one. When you are

debugging multiple processes, open the **Debug > Windows > Processes**
window to switch between them.

Sometimes you are debugging something that only happens on startup, and want

to see the child process as soon as it starts. Use:

--renderer-startup-dialog --no-sandbox

You have to disable the sandbox or the dialog box will be prohibited from

showing. When the dialog appears, visit Tools > Attach to Process and attach
to the process showing the Renderer startup dialog. Now you're debugging in
the renderer and can continue execution by pressing OK in the dialog.

Startup dialogs also exist for other child process types:

--gpu-startup-dialog, --ppapi-startup-dialog, --plugin-startup-dialog (for
NPAPI).

You can also try [the vs-chromium

plug-in](http://chromium.github.io/vs-chromium/#attach-to-chrome) to attach
to the right processes.

Semi-automatically attaching the debugger to child processes

The following flags cause child processes to wait for 60 seconds in a busy

loop for a debugger to attach to the process. Once either condition is true,
it continues on; no exception is thrown.

--wait-for-debugger-children[=filter] The filter, if provided, will fire

only if it matches the --type parameter to the process. Values include
renderer, plugin (for NPAPI), ppapi, gpu-process, and utility.

When using this option, it may be helpful to limit the number of renderer

processes spawned, using:

--renderer-process-limit=1

Image File Execution Options

Using Image File Execution Options (IFEO) will not work because CreateProcess() returns the handle to the debugger process instead of the intended child process. There are also issues with the sandbox.

Visual Studio hints

Debug visualizers

Chrome's custom debug visualizers should be added to the pdb files and automatically picked up by Visual Studio. The definitions are in //tools/win/DebugVisualizers if you need to modify them (the BUILD.gn file there has additional instructions).

Don't step into trivial functions

The debugger can be configured to automatically not step into functions based on regular expression. Edit default.natstepfilter in the following directory:

  • For Visual Studio 2015: C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\Packages\Debugger\Visualizers (for all users) or %USERPROFILE%\My Documents\Visual Studio 2015\Visualizers (for the current user only)
  • For Visual Studio 2017 Pro: C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\Common7\Packages\Debugger\Visualizers (for all users) or %USERPROFILE%\My Documents\Visual Studio 2017\Visualizers (for the current user only)

Add regular expressions of functions to not step into. Remember to regex-escape and XML-escape them, e.g. < for < and \. for a literal dot. Example:

operator newNoStepInto

operator deleteNoStepInto

std::.*NoStepInto

WTF::.*Ptr<.*>::.*NoStepInto

This file is read at start of a debugging session (F5), so you don't need to restart Visual Studio after changing it.

More info: Andy Pennel's Blog, microsoft email thread

V8 and Chromium

V8 supports many command-line flags that are useful for debugging. V8 command-line flags can be set via the Chromium command-line flag --js-flags; for instance:

chrome.exe --js-flags=“--trace_exception --heap_stats”

Note that some V8 command-line flags exist only in the debug build of V8. For a list of all V8 flags try:

chrome.exe --js-flags=“--help”

Graphics debugging

GPU Acceleration of rendering can be more easily debugged with tools. See:

Debugging on another machine

Sometimes it's useful to debug installation and execution on a machine other than your primary build box. To run the installer on said other machine, first build the mini_installer target on your main build machine (e.g., ninja -C out\Debug mini_installer). Next, on the debug machine:

  • Make the build machine's build volume available on the debug machine either by mounting it locally (e.g., Z:\) or by crafting a UNC path to it (e.g., \\builder\src)
  • Open up a command prompt and change to a local disk
  • Run src\tools\win\copy-installer.bat in the remote checkout by way of the mount (e.g., Z:\PATHTOCHECKOUT\src\...) or UNC path (e.g., \\builder\src\...). This will copy the installer, DLLs, and PDBs into your debug machine‘s C:\out or C:\build (depending on if you’re rocking the component=shared_library build or not)
  • Run C:\out\Debug\mini_installer.exe with the flags of your choice to install Chrome. This can take some time, especially on a slow machine. Watch the Task Manager and wait until mini_installer.exe exits before trying to launch Chrome (by way of the shortcut(s) created by the installer)
  • For extra pleasure, add C:\out\Debug to your _NT_SYMBOL_PATH environment variable

Consider reading the documentation at the top of copy-installer.bat to see how you can run it. It tries to be smart and copy the right things, but you may need to be explicit (e.g., “copy-installer.bat out Debug”). It is safe to re-run the script to copy only modified files (after a rebuild, for example).

Find memory leaks

The Windows heap manager has a really useful debug flag, where it can be asked to capture and store a stack trace with every allocation. The tool to scrape these stack traces out of processes is UMDH, which comes with WinDbg.

UMDH is great. It will capture a snapshot of the heap state as many times as you like, and it‘ll do it fairly quickly. You then run it again against either a single snapshot, or a pair of snapshots, at which time it’ll symbolize the stack traces and aggregate usage up to unique stack traces.

Turning on the user stack trace database for chrome.exe with gflags.exe makes it run unbearably slowly; however, turning on the user stack trace database on for the browser alone is just fine.

While it‘s possible to turn on the user stack database with the “!gflag” debugging extension, it’s too late to do this by the time the initial debugger breakpoint hits. The only reasonable way to do this is to

  1. Launch GFlags.exe,
  2. Enable the user stack trace database (per image below),
  3. Launch Chrome under the debugger.
  4. Set a breakpont when chrome.dll loads with “sxe ld chrome.dll”.
  5. Step up, to allow Chrome.dll to initialize.
  6. Disable the stack trace database in GFlags.exe.
  7. Continue chrome, optionally detaching the debugger.

image

GFlags.exe settings for user mode stack trace database.

If you then ever suffer a browser memory leak, you can snarf a dump of the process with

umdh -p: > chrome-browser-leak-umdh-dump.txt

which can then typically be “trivially” analyzed to find the culprit.

Miscellaneous

  • Application Verifier is a free tool from Microsoft. For the tool to run, you must disable the sandbox (--no-sandbox) and run all app-verified processes in a debugger. This means that you must run the renderer and plugin processes in a debugger or they will fail in mysterious ways. Use any of the methods mentioned above to attach to the renderer processes when they run.

  • To put a breakpoint on CreateFile(), add this break point:

{,,kernel32.dll}_CreateFileW@28

*   {,,kernel32.dll}specifies the DLL (context operator).
*   _ prefix means extern "C".
*   @28 postfix means _stdcall with the stack pop at the end of the
    function. i.e. the number of arguments in BYTES.
  • You can use DebugView from SysInternals or sawbuck to view LOG() messages that normally goes to stderr on POSIX.