Electrolysis/Debugging

From MozillaWiki
< Electrolysis
Revision as of 21:05, 15 September 2010 by Azakai (talk | contribs) (→‎IPDL)
Jump to navigation Jump to search

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.