Electrolysis/Debugging
Windows
Debugging under Windows is very straightforward using Microsoft Visual Studio 2005 (MSVC8).
Note : Debugging E10s using MSVC9 should not be any different from MSVC8.
Creating a project
First you need a 'Makefile' project. Open the "New Project" windows by hitting CTRL-SHIFT-N. Choose "Win32 Console Application" and type in whatever name and location you want for your new project. Hit the "OK" button.
Then, open your project's properties by right-clicking the project name in the "Solution Explorer" view. Choose "Makefile" for the "Configuration Type" field in the "Configuration Properties / General" section. Click the "Apply" button now.
In "General Properties / NMake" section, do the following :
- type whatever make commands you want to use for building electrolysis, in the "general" subsection.
- type "OS_WIN;WIN32;XP_WIN;DEBUG;_DEBUG;MOZ_IPC" in the "Preprocessor Definitions" field of the "Intellisense" subsection.
In "General Properties / Debugging" section, do the following :
- type "<your_objdir>\browser\dist\bin\firefox.exe"
- type "-no-remote -P <your_electrolysis_profile_if_any> -chrome chrome://global/content/test-ipc.xul"
- type "MOZ_DEBUG_CHILD_PROCESS=1" in the "Environment" field
Debugging E10s
First, make sure you've got a DEBUG build. If that's the case, you're all set ! Just hit F5 in MSVC. You should see the program's console with the main process output in it.
Now when the output stops updating, it means it's reached this code in nsEmbedFunctions.cpp :
if (PR_GetEnv("MOZ_DEBUG_CHILD_PROCESS")) { #ifdef OS_POSIX printf("\n\nCHILDCHILDCHILDCHILD\n debug me @%d\n\n", getpid()); sleep(30); #elif defined(OS_WIN) Sleep(30000); #endif }
You now have 30 seconds to hook up to the newly created child process. Do the following :
- Hit CTRL-ALT-P to bring up the "attach to process" dialog
- Double-click "mozilla-runtime.exe" in the "Available Processes" listbox.
MSVC is going to load all the symbols from that newly attached process and, basically, you're done ! You should see two processes in your "processes" windows. You can break either one, or break all. You can switch from one to another by double-clicking on it, etc...
And for a better debugging experience, don't forget to add breakpoints ! heh!
Linux
To debug only the parent process
With GDB: just pass "-g" to your regular command line, ex:
$objdir/dist/bin/firefox -no-remote -P JunkProfile -g -chrome chrome://global/content/test-ipc.xul
With emacs gud-gdb: run
M-x gdb, gdb --annotate 3 --args $objdir/dist/bin/firefox-bin -no-remote -P JunkProfile -chrome chrome://global/content/test-ipc.xul
as you would for any other process.
NOTE: you'll need to make sure firefox's $objdir/dist/lib is in your LD_LIBRARY_PATH. Normally firefox -g would do this, but it doesn't play well with gud-gdb. Rather than add $objdir/dist/lib to your main LD_LIBRARY_PATH, you can set it only for gdb by adding this line to your ~/.gdbinit
set environment LD_LIBRARY_PATH=$objdir/dist/lib:/usr/lib/debug
(On Ubuntu, /usr/lib/debug contains libraries with better debug info if they're installed. If you don't have them installed or you use another another distro, you probably want /usr/lib instead.)
WARNING: if the first time you run firefox after a rebuild is from within gdb, gdb will crash when firefox restarts itself. You can stop firefox from restarting itself by setting the NO_EM_RESTART environment variable. Or you can just run firefox once from the shell, outside of gdb.
WARNING: if you send an interrupt to the terminal (^C), it will send a SIGINT to all processes attached to that terminal. gdb will catch this signal for the parent process and pause it, but, if there are no debuggers attached to child processes, then they will terminate. To only interrupt the parent process, either "kill -INT [PID]" in a separate shell, or start the application without the debugger and then attach a debugger from a separate terminal (as described for child processes below).
To debug child processes only
Run firefox from the shell as
MOZ_DEBUG_CHILD_PROCESS=1 $objdir/dist/bin/firefox -no-remote -P JunkProfile -chrome chrome://global/content/test-ipc.xul
Each time a child process is launched, lines like this will be printed
CHILDCHILDCHILD debug me @ [PID]
(If you don't see this message, make sure you have set "dom.ipc.tabs.enabled" to "true", as described the Build and Run Instructions)
You can attach to the newly launched child process with "gdb attach [PID]", or, for emacs gud-gdb, with M-x gdb, gdb --annotate 3 attach PID.
The same gdb session can be used to debug subsequent child processes. However, even if the previous process has exited, an explicit "detach" is required before the next "attach [NEWPID]" to persuade gdb to reread the shared library mappings so that symbols have the right addresses.
To debug both the parent and children
Make sure MOZ_DEBUG_CHILD_PROCESS is set in the environment you'll launch the parent from, and launch the parent process as above. Unfortunately, at the time of writing this, gud-gdb can't handle multiple gdb sessions. So to debug child processes, you'll need to pull up a new shell or a new emacs for each and attach to them as described for child processes above.
More Resources
Don't forget to check out the main Mozilla gdb guide.
Also the Google Chromium debugging guide for Linux has some tips that also apply to our codebase, but we don't support all the tricks they show yet.
TODO other debuggers?
IPDL
To see all IPC messages as they are sent, received, and processed set the environment variable
MOZ_IPC_MESSAGE_LOG=1
in the environment of the processes for which you wish to see messages.
To profile those messages, use the tool in bug 596725. You will get summarized output by message count and latency.