Debugging Mozilla on Windows FAQ

  • Revision slug: Debugging_Mozilla_on_Windows_FAQ
  • Revision title: Debugging Mozilla on Windows FAQ
  • Revision id: 73947
  • Created:
  • Creator: Nickolay
  • Is current revision? No
  • Comment /* Debugging JavaScript */ DumpJSStack() tip

Revision Content

This document tries to answer the most common questions about how to effectively debug Mozilla on a 32-bit Microsoft Windows system. It assumes you already know how to use the Microsoft Visual C++ development environment and debugger.

These instructions were originally written for VC++ 6.0. Started adding notes where things are different with VC++ 7.0+ aka Visual Studio .NET 2003 and newer. VC++ 7.0 notes are still incomplete, so please add new instructions for VC++ 7.0.

Requirements

See the Windows Build Prerequisites.

Ways to start the debugger

Launch MSDEV, select File > Open Workspace... (Open Solution... in VC++ 7.0) and select a Mozilla executable. This will also create a Mozilla project. You can start a debug run by pressing F5.

From the command line, type <tt>msdev <program name></tt>. You might need to be in the same directory as the executable?

Run the program until you hit an assertion. You will get a dialog box asking if you would like to debug. Hit "Cancel". The MSDEV IDE will launch and load the file where the assertion happened. This will also create a Visual C++ Mozilla project in the directory of the executable by default.

Creating a Visual C++ project for Mozilla

This may no longer work:

You probably want to create a Mozilla project in the mozilla root directory. You do this by selecting File > Open Workspace... and opening <tt>client.mak</tt>. Visual C++ compains that it cannot read this project, and you can ignore this. It will also ask you to name the project file it should create. You probably want to say "mozilla". If you do File > Open Workspace... (Open Solution... in VC++ 7.0) and select an executable to open, VC++ creates a project in the directory of the executable by default. Once you have the project, do "Save All" to save all the workspace information. You will want to do this whenever you change some Visual C++ options. Before you actually start using the project it probably makes sense to set some options etc. so read on.

Changing/setting the executable to debug

VC++ 6.0: To change or set the executable to debug, go to Project > Settings..., Debug tab and select General from the drop down list. "Executable for debug session:" should show the executable you are debugging. If it is empty or incorrect, use the arrow button and select Browse... to locate the executable.

Command line parameters and environment variables

VC++ 6.0: To change or set the command line options, go to Project > Settings..., Debug tab and select General from the drop down list. "Program arguments:" should show the options.

Some common options would be the URL of the file you want the browser to open as soon as it starts, starting the Profile Manager, or selecting a profile. You can also redirect the console output to a file (by adding "<tt>> filename.txt</tt>" for example, without the quotes).

In VC 7 and 8 this option is called Project > Properties > Debugging > Command Arguments. VC 8 also allows you to set environment variables there.

Setting breakpoints in DLLs which are not yet loaded in memory

VC++ 6.0: Go to Project > Settings..., Debug tab and select "Additional DLLs" from the drop down list. Check "Locate Additional DLLs" option. For each DLL, click the "New" button which creates a new entry and then hit the "..." buttons which lets you browse to the DLL. You will only be able to add one DLL at a time.

VC++ 7.0 automatically finds additional DLLs.

Displaying Unicode string

VC++ 6.0: Select Tools > Options..., find Debug tab, and check the option "Display Unicode Strings".

VC++ 7.0 automatically displays Unicode strings.

Customizing the debugger's variable value view

You can customize how Visual C++ displays classes in the variable view. By default VC++ displays "{...}" and you need to click the small + icon to expand the members. You can change this behaviour, and make Visual C++ display whatever data member you want in whatever order, formatter however you like instead of just "{...}".

You need to locate a file called "AUTOEXP.DAT" in your Visual C++ installation. By default it will be:

VC++ 6.0:

C:\Program Files\Microsoft Visual Studio\Common\MSDev98\Bin\AUTOEXP.DAT

VC++ 7.0:

C:\Program Files\Microsoft Visual Studio .NET 2003\Common7\Packages\Debugger\AUTOEXP.DAT

The file has information about the format in the beginning, and after a little practice you should be well on your way. Here are some entries that will make your life easier:

;; Mozilla (1.7beta and later)
nsAutoString=<mData,su>
nsString=<mData,su>
nsCString=<mData,s>
nsRect=x=<x,d> y=<y,d> width=<width,d> height=<height,d>
nsIAtom=<mString,su>
nsCOMPtr<*>=<mRawPtr,x>

After you have made the changes and saved the file, you will need to restart Visual C++ for the changes to take effect.

Disabling ASSERTIONS

There are basically two ways to disable assertions. One requires setting an environment variable, while the other affects only the currently running program instance in memory.

Environment variable

There is an environment variable that can disable breaking for assertions. This is how you would normally set it:

set XPCOM_DEBUG_BREAK=warn

The environment variable takes also other values besides <tt>warn</tt>, see the Unix debugging FAQ for more details. Note, that unlike unix, the default for windows is not warn, it's to pop up a dialog.

Changing running code

You normally shouldn't need to do this (just quit the application, set the environment variable described above, and run it again). And this can be dangerous (like trashing your hard disc and corrupting your system). So unless you feel comfortable with this, don't do it. You have been warned!

It is possible to change the interrupt code in memory (which causes you to break into debugger) to be a NOP (no operation).

You do this by running the program in the debugger until you hit an assertion. You should see some assembly code. One assemly code instruction reads "int 3". Check the memory address for that line. Now open memory view. Type/copy/drag the memory address of "int 3" into the memory view to get it to update on that part of the memory. Change the value of the memory to "90", close the memory view and hit "F5" to continue.

Confused? See the screenshot below:
Screenshot of disabling assertions

VC++ 7.0?

Automatically handling ASSERTIONS without a debugger attached

When an assertion happens and there is not a debugger attached, a small helper application (<tt>windbgdlg.exe</tt>) is run. That application can automatically select a response to the "Do you want to debug" dialog instead of prompting if you configure it, for more info, see <tt>windbgdlg.exe</tt>.

Debugging optimized builds

To effectively debug optimized builds, you should enable profiling which effectively leaves the debug symbols in optimized code so you can still set breakpoints etc. Because the code is optimized, stepping through the code may occasionally provide small surpises when the debugger jumps over something.

You need to make sure this environment variable is set:

set MOZ_PROFILE=1

Running two instances of Mozilla simultaneously

You can run two instances of Mozilla (e.g. debug and optimized) simultaneously by setting the environment variable <tt>MOZ_NO_REMOTE</tt>:

set MOZ_NO_REMOTE=1

You can also specify the profile to use with the <tt>-p profile_name</tt> command-line argument.

Debugging JavaScript

Use Venkman, the JavaScript Debugger for Mozilla.

You can use helper functions from {{wiki.template('Named-source', [ "js/src/xpconnect/src/nsXPConnect.cpp#1395", "nsXPConnect.cpp" ])}} to inspect and modify the state of JavaScript code.

For example, to print curent JavaScript stack to stdout, evaluate this in QuickWatch window:

{,,xpc3250}DumpJSStack()

Got a tip?

If you think you know a cool Mozilla debugging trick, feel free to discuss it with #developers and then post it here.


Originally by Heikki Toivonen.

Revision Source

<p>This document tries to answer the most common questions about how to effectively debug Mozilla on a 32-bit Microsoft Windows system. It assumes you already know how to use the Microsoft Visual C++ development environment and debugger.
</p><p>These instructions were originally written for VC++ 6.0. Started adding notes where things are different with VC++ 7.0+ aka Visual Studio .NET 2003 and newer. VC++ 7.0 notes are still incomplete, so please add new instructions for VC++ 7.0.
</p><p><s id="req"></s>
</p>
<h3 name="Requirements"> Requirements </h3>
<p>See the <a href="en/Windows_Build_Prerequisites">Windows Build Prerequisites</a>.
</p><p><s id="start"></s>
</p>
<h3 name="Ways_to_start_the_debugger"> Ways to start the debugger </h3>
<p><b>Launch MSDEV, select File &gt; Open Workspace... (Open Solution... in VC++ 7.0) </b>
and select a Mozilla executable.<b> This will also create a Mozilla project. You </b>
can start a debug run by pressing F5.
</p><p><b>From the command line, type <tt>msdev &lt;program name&gt;</tt>.</b>
<span style="color:red;">You might need to be in the same directory as the executable?</span>
</p><p><b>Run the program until you hit an assertion.</b> You will get a dialog box asking
if you would like to debug. Hit "Cancel". The MSDEV IDE will launch and load
the file where the assertion happened. This will also create a Visual C++ Mozilla
project in the directory of the executable by default.
</p><p><s id="proj"></s>
</p>
<h3 name="Creating_a_Visual_C.2B.2B_project_for_Mozilla"> Creating a Visual C++ project for Mozilla </h3>
<p>This may no longer work:
</p>
<p style="margin-left: 2em;">You probably want to create a Mozilla project in the mozilla root directory. You do this by selecting File &gt; Open Workspace... and opening <tt>client.mak</tt>. Visual C++ compains that it cannot read this project, and you can ignore this. It will also ask you to name the project file it should create. You probably want to say "mozilla".

If you do File &gt; Open Workspace... (Open Solution... in VC++ 7.0) and select an executable to open, VC++ creates a project in the directory of the executable by default.

Once you have the project, do "Save All" to save all the workspace information. You
will want to do this whenever you change some Visual C++ options.

Before you actually start using the project it probably makes sense to set some options etc. so read on.

<s id="exe"></s>
</p><h3 name="Changing.2Fsetting_the_executable_to_debug"> Changing/setting the executable to debug </h3>
<p>VC++ 6.0:
To change or set the executable to debug, go to Project &gt; Settings..., Debug tab and select General from the drop down list. "Executable for debug session:" should show the executable you are debugging. If it is empty or incorrect, use the arrow button and select Browse... to locate the executable.
</p><p><s id="cmdline"></s>
</p>
<h3 name="Command_line_parameters_and_environment_variables"> Command line parameters and environment variables </h3>
<p>VC++ 6.0: To change or set the command line options, go to Project &gt; Settings..., Debug tab and select General from the drop down list. "Program arguments:" should show the options.
</p><p>Some common options would be the URL of the file you want the browser to open as soon as it starts, starting the Profile Manager, or selecting a profile. You can also redirect the console output to a file (by adding "<tt>&gt; filename.txt</tt>" for example, without the quotes).
</p><p>In VC 7 and 8 this option is called Project &gt; Properties &gt; Debugging &gt; Command Arguments. VC 8 also allows you to set environment variables there.
</p><p><s id="bp"></s>
</p>
<h3 name="Setting_breakpoints_in_DLLs_which_are_not_yet_loaded_in_memory"> Setting breakpoints in DLLs which are not yet loaded in memory </h3>
<p>VC++ 6.0:
Go to Project &gt; Settings..., Debug tab and select "Additional DLLs" from the drop down list. Check "Locate Additional DLLs" option. For each DLL, click the "New" button which creates a new entry and then hit the "..." buttons which lets you browse to the DLL. You will only be able to add one DLL at a time.
</p><p>VC++ 7.0 automatically finds additional DLLs.
</p><p><s id="unicode"></s>
</p>
<h3 name="Displaying_Unicode_string"> Displaying Unicode string </h3>
<p>VC++ 6.0:
Select Tools &gt; Options..., find Debug tab, and check the option "Display Unicode Strings".
</p><p>VC++ 7.0 automatically displays Unicode strings.
</p><p><s id="custom"></s>
</p>
<h3 name="Customizing_the_debugger.27s_variable_value_view"> Customizing the debugger's variable value view </h3>
<p>You can customize how Visual C++ displays classes in the variable view. By default VC++ displays "{...}" and you need to click the small + icon to expand the members. You can change this behaviour, and make Visual C++ display whatever data member you want in whatever order, formatter however you like instead of just "{...}".
</p><p>You need to locate a file called "AUTOEXP.DAT" in your Visual C++ installation. By default it will be:
</p><p>VC++ 6.0:
</p>
<pre class="eval">C:\Program Files\Microsoft Visual Studio\Common\MSDev98\Bin\AUTOEXP.DAT
</pre>
<p>VC++ 7.0:
</p>
<pre class="eval">C:\Program Files\Microsoft Visual Studio .NET 2003\Common7\Packages\Debugger\AUTOEXP.DAT
</pre>
<p>The file has information about the format in the beginning, and after a little practice you should be well on your way. Here are some entries that will make your life easier:
</p>
<pre>;; Mozilla (1.7beta and later)
nsAutoString=&lt;mData,su&gt;
nsString=&lt;mData,su&gt;
nsCString=&lt;mData,s&gt;
nsRect=x=&lt;x,d&gt; y=&lt;y,d&gt; width=&lt;width,d&gt; height=&lt;height,d&gt;
nsIAtom=&lt;mString,su&gt;
nsCOMPtr&lt;*&gt;=&lt;mRawPtr,x&gt;
</pre>
<p>After you have made the changes and saved the file, you will need to restart Visual C++ for the changes to take effect.
</p><p><s id="assert"></s>
</p>
<h3 name="Disabling_ASSERTIONS"> Disabling ASSERTIONS </h3>
<p>There are basically two ways to disable assertions. One requires setting an
environment variable, while the other affects only the currently running program instance in memory.
</p>
<h4 name="Environment_variable"> Environment variable </h4>
<p>There is an environment variable that can disable breaking for assertions.
This is how you would normally set it:
</p>
<pre class="eval">set XPCOM_DEBUG_BREAK=warn
</pre>
<p>The environment variable takes also other values besides <tt>warn</tt>, see the <a class="external" href="http://mozilla.org/unix/debugging-faq.html#assertion">Unix debugging FAQ</a> for more details.  Note, that unlike unix, the default for windows is not warn, it's to pop up a dialog.
</p>
<h4 name="Changing_running_code"> Changing running code </h4>
<p>You normally shouldn't need to do this (just quit the application, set the environment variable described above, and run it again). 
And this can be <b>dangerous</b> (like <b>trashing your hard disc and corrupting your system</b>). So unless you feel comfortable with this, don't do it. <b>You have been warned!</b>
</p><p>It is possible to change the interrupt code in memory (which causes you to break into debugger) to be a NOP (no operation).
</p><p>You do this by running the program in the debugger until you hit an assertion.
You should see some assembly code.
One assemly code instruction reads "int 3". Check the memory address for that
line. Now open memory view. Type/copy/drag the memory address of "int 3" into the
memory view to get it to update on that part of the memory. Change the value
of the memory to "90", close the memory view and hit "F5" to continue.
</p><p>Confused? See the screenshot below:<br>
<img alt="Screenshot of disabling assertions" src="File:en/Media_Gallery/Win32-debug-nop.png">
</p><p>VC++ 7.0?
</p><p><s id="handlingasserts"></s>
</p>
<h3 name="Automatically_handling_ASSERTIONS_without_a_debugger_attached"> Automatically handling ASSERTIONS without a debugger attached </h3>
<p>When an assertion happens and there is not a debugger attached, a small helper application (<a class="external" href="http://www.mozilla.org/build/windbgdlg.html"><tt>windbgdlg.exe</tt></a>) is run. That application can automatically select a response to the "Do you want to debug" dialog instead of prompting if you configure it, for more info, see <a class="external" href="http://www.mozilla.org/build/windbgdlg.html"><tt>windbgdlg.exe</tt></a>.
</p><p><s id="opt"></s>
</p>
<h3 name="Debugging_optimized_builds"> Debugging optimized builds </h3>
<p>To effectively debug optimized builds, you should enable profiling which effectively leaves the debug symbols in optimized code so you can still set breakpoints etc. Because the code is optimized, stepping through the code may occasionally provide small surpises when the debugger jumps over something.
</p><p>You need to make sure this environment variable is set:
</p>
<pre class="eval">set MOZ_PROFILE=1
</pre>
<p><s id="twomoz"></s>
</p>
<h3 name="Running_two_instances_of_Mozilla_simultaneously"> Running two instances of Mozilla simultaneously </h3>
<p>You can run two instances of Mozilla (e.g. debug and optimized) simultaneously
by setting the environment variable <tt>MOZ_NO_REMOTE</tt>:
</p>
<pre class="eval">set MOZ_NO_REMOTE=1
</pre>
<p>You can also specify the profile to use with the <tt>-p <i>profile_name</i></tt> command-line argument.
</p><p><s id="js"></s>
</p>
<h3 name="Debugging_JavaScript"> Debugging JavaScript </h3>
<p>Use <a href="en/Venkman">Venkman</a>, the JavaScript Debugger for Mozilla.
</p><p>You can use helper functions from {{wiki.template('Named-source', [ "js/src/xpconnect/src/nsXPConnect.cpp#1395", "nsXPConnect.cpp" ])}} to inspect and modify the state of JavaScript code.
</p><p>For example, to print curent JavaScript stack to stdout, evaluate this in QuickWatch window:
</p>
<pre class="eval">{,,xpc3250}DumpJSStack()
</pre>
<p><s id="q"></s>
</p>
<h3 name="Got_a_tip.3F"> Got a tip? </h3>
<p>If you think you know a cool Mozilla debugging trick, feel free to discuss it with <a class="external" href="irc://irc.mozilla.org/developers">#developers</a> and then post it here.
</p><p><br>
</p>
Originally by Heikki Toivonen.
Revert to this revision