Debugging Chromium on Windows
先参考get the code获取如果检出代码并编译。
你可以使用Visual Studio内置的编译器或者WinDBG来调试Chromium。你不必为了使用内置的调试器而去用IDE编译。Ninja 常用来编译Chromium,大部分开发者直接在命令行中使用它来编译Chromium,然后在必要的时候打开IDE来调试自己关注的部分。在命令行中开始调试一个exe:
devenv /debugexe out\Debug\chrome.exe
假设你已经安装了 Visual Studio,并且devenv.exe 路径也在你的PATH环境变量中。注意路径中必须使用反斜杠,并且必须包含最后的”.exe”后缀,否则仅仅是打开了Visual Studio,而没有启动调试。
Goma(Google内部的分布式编译器)默认使用的是 symbol_level = 1,这表示源码层的调试将不可用。如果你想要使用Goma来调试,你需要明确的设置 symbol_level = 2 & is_win_fastlink = true,但是,调试器可能会出错,所以使用时,请确保使用最新版本的调试器。
在你调试的时候,使用不同的配置文件是个好主意。如果你正在调试一个Google Chrome编译版的浏览器,或者一个Chromium 编译版的,因为配置文件的冲突,你将不能同时运行这两个版本的浏览器。将来可能会解决(Google Chrome 和 Chromium 默认使用不同目录的配置文件,所以不会冲突了)。使用命令行选项:
--user-data-dir=c:\tmp\my_debug_profile (replace the path as necessary)
在IDE中,选择 调试-属性,并在chrome工程中,设置以上命令行参数。
在启动调试的时候,传入--enable-logging --v=1
命令行参数,会启用Chrome 将调试日志写入文件。Debug版本的将chrome_debug.log
日志文件放在out\Debug
目录中。Release版本的放在user data顶层的目录中,具体与系统平台相关。更多信息请参考logging和user data directory。
如果你正在调试正式的Google Chrome发行版,使用这个符号服务器:
https://chromium-browser-symsrv.commondatastorage.googleapis.com.
Visual Studio的设置方法:工具-选项-调试-符号。如果你在本地设置一个缓存目录将会更快。
因为Chromium的multi-process architecture,使得调试Chromium变得很有挑战。当你在调试器中选择运行的时候,只有主进程将会被调试。渲染web页面的(Renderer进程)和插件的代码将运行在另外的进程中,所以就没有被调试。ProcessExplorer工具有一个进程树视图让你可以查看这些进程之间的关系。你也可以在Chrome Task Manager
中查看每个标签对应的进程id(右击浏览器窗口标题的空白部分选择打开)。
最简单的调试问题的方式就是使用单进程模式。这将会让你看到进程的整个状态,而没有其它额外的工作(尽管它仍然有很多线程)。添加命令行参数,来启用单进程模式:
--single-process
在这个模式下,有一些问题将不会表现出来,一些功能也不能正常运行,还有一些线程仍然会产生新的进程,所以,也不是很完美。
你可以使用调试器来附加到正在运行的子进程中来调试。选择 工具-附加到进程 并选择 你想调试的chrome.exe。在附加之前,确认你在Attach to Process
窗口中的Native cod
选项中选择了Native
。如果你忘记选择了,默认它会尝试用”WebKit”模式附加调试 JavaScript,并且你会得到一个”当前状态操作不合法”的错误消息。
现在你可以调试两个进程了,就好像一个一样。当你调试多个进程的时候,打开 调试-窗口-进程窗口 来切换它们。
有时候,你调试的东西可能只发生在启动的时候,想要在子进程启动的时候就看见它,使用:
--renderer-startup-dialog --no-sandbox
你必须禁用沙盒,否则弹出的对话框将被禁止显示。当对话框出现后,选择 工具-附加到进程 就附加到弹出对话框的进程了。现在,你就在调试Renderer进程了,并且可以单机对话框中OK按钮来继续执行。
其它进程类型也有这种模式的启动对话框:--gpu-startup-dialog, --ppapi-startup-dialog, --plugin-startup-dialog (for NPAPI)
。
你还可以使用vs谷歌插件the vs-chromium plug-in来附加到正确进程。
下面的参数,将会使子进程循环等待60秒的时间来让调试器附加。如果一旦附加上了,它将继续运行,没有异常会抛出。
--wait-for-debugger-children[=filter]
filter
参数选项,可以不提供,针对所有子进程。如果提供了,就匹配子进程的--type
参数。包括renderer, plugin (for NPAPI), ppapi, gpu-process, and utility
。
使用这个参数时,限制产生renderer进程的数量或许怼你会有帮助:
--renderer-process-limit=1
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.
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).
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:
<Function><Name>operator newName><Action>NoStepIntoAction>Function>
<Function><Name>operator deleteName><Action>NoStepIntoAction>Function>
<Function><Name>std::.*Name><Action>NoStepIntoAction>Function>
<Function><Name>WTF::.*Ptr<.*>::.*Name><Action>NoStepIntoAction>Function>
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 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"
GPU Acceleration of rendering can be more easily debugged with tools. See:
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:
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).
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
If you then ever suffer a browser memory leak, you can snarf a dump of the process with
umdh -p:<my browser pid> > chrome-browser-leak-umdh-dump.txt
which can then typically be “trivially” analyzed to find the culprit.
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.