forked from mirrors/gecko-dev
449 lines
16 KiB
ReStructuredText
449 lines
16 KiB
ReStructuredText
Debugging On Windows
|
|
====================
|
|
|
|
+--------------------------------------------------------------------+
|
|
| This page is an import from MDN and the contents might be outdated |
|
|
+--------------------------------------------------------------------+
|
|
|
|
This document explains how to debug Gecko based applications such as
|
|
Firefox, Thunderbird, and SeaMonkey on Windows using the Visual C++ IDE.
|
|
|
|
If VC++ and your Gecko application hang shortly after you launch the
|
|
application under the debugger, see `Problems Loading Debug
|
|
Symbols <#problems-loading-debug-symbols>`__.
|
|
|
|
Ways to start the debugger
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
First of all, it's necessary to install a Visual Studio extension to be
|
|
able to follow child processes as they are created. Firefox, in general,
|
|
and even in non-e10s mode, does not start the main process directly, it
|
|
starts it via a Launcher Process. This means that Visual Studio will
|
|
only attach to the first process it finds, and will not hit any
|
|
break-point (and even notifies you that it cannot find their location).
|
|
`Microsoft Child Process Debugging Power
|
|
Tool <https://marketplace.visualstudio.com/items?itemName=vsdbgplat.MicrosoftChildProcessDebuggingPowerTool>`__
|
|
allows automatically attaching to child processes, such as Web Content
|
|
process, GPU process, etc. Enable it by going its configuration menu in
|
|
"Debug > Other debugging targets > Child process debugging settings",
|
|
and ticking the box.
|
|
|
|
If you have followed the steps in :ref:`Building Firefox for
|
|
Windows <Building Firefox On Windows>`
|
|
and have a local debug build, you can **execute this command from same command line.**
|
|
|
|
.. code::
|
|
|
|
./mach run --debug
|
|
|
|
It would open Visual Studio with Firefox's
|
|
run options configured. You can **click "Start" button** to run Firefox
|
|
then, already attached in the debugger.
|
|
|
|
Alternatively, if you have generated the Visual Studio solution, via
|
|
``./mach build-backend -b VisualStudio``, opening this solution allows
|
|
you to run ``firefox.exe`` directly in the debugger. Making it the
|
|
startup project, by right clicking on it (it appears bold when it's the
|
|
case) can be useful. Breakpoints are kept across runs, this can be a
|
|
good way to debug startup issues.
|
|
|
|
**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.
|
|
|
|
**Attach the debugger to an existing Mozilla process**. In the Visual
|
|
Studio, select Debug > Attach to Process. If you want to debug a content
|
|
process, you can **hover on the tab** of page you want to debug, which
|
|
would show the pid. You can then select the process from dialog opened
|
|
from "Attach to Process". For more information, see `Attach to Running
|
|
Processes with the Visual Studio
|
|
Debugger <http://msdn.microsoft.com/en-us/library/vstudio/3s68z0b3.aspx>`__.
|
|
|
|
**Starting an MSIX installed Firefox with the debugger**. In Visual
|
|
Studio, select Debug -> Other Debug Targets -> Debug Installed App Package.
|
|
In the dialog, select the installed Firefox package you wish to debug
|
|
and click "Start".
|
|
|
|
Debugging Release and Nightly Builds
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
Refer to the steps to :ref:`use the Mozilla symbol
|
|
server <Using The Mozilla Symbol Server>` and :ref:`source
|
|
server <Using The Mozilla Source Server>`
|
|
|
|
Creating a Visual C++ project for Firefox
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
Please refer to :ref:`this <Visual Studio Projects>`.
|
|
|
|
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
|
|
"``> filename.txt``" 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.
|
|
|
|
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:
|
|
|
|
.. code::
|
|
|
|
C:\Program Files\Microsoft Visual Studio\Common\MSDev98\Bin\AUTOEXP.DAT
|
|
|
|
VC++ 7.0:
|
|
|
|
.. code::
|
|
|
|
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>
|
|
nsCAutoString=<mData,s>
|
|
nsRect=x=<x,d> y=<y,d> width=<width,d>; height=<height,d>
|
|
nsStaticAtomWrapper=<mStaticAtom->mString,s>
|
|
nsIAtom=<mString,su>
|
|
; the following are not necessary in vc8
|
|
nsCOMPtr<*>=<mRawPtr,x>
|
|
nsRefPtr=<mRawPtr,x>
|
|
nsAutoPtr=<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.
|
|
|
|
For XPCOM Strings (the "external" string API) you can use the following
|
|
values:
|
|
|
|
::
|
|
|
|
;; Mozilla (1.9)
|
|
; Internal Strings
|
|
nsAString_internal=<mData,su>, length=<mLength,u>
|
|
nsACString_internal=<mData,s>, length=<mLength,u>
|
|
; XPCOM Strings
|
|
nsAString=<nsStringContainer.v,su>, length=<nsStringContainer.d1,u>
|
|
nsACString=<nsCStringContainer.v,s>, length=<nsCStringContainer.d1,u>
|
|
nsStringContainer=<v,su>, length=<d1,u>
|
|
nsCStringContainer=<v,s>, length=<d1,u>
|
|
|
|
There is a more extensive version of this file in progress in
|
|
`AutoExpForVC8. <https://developer.mozilla.org/en-US/docs/Mozilla/Debugging/AutoExpForVC8>`__
|
|
|
|
Avoiding stepping into certain functions
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
You can avoid stepping into certain functions, such as nsCOMPtr methods,
|
|
using an undocumented feature of VC. See the blog post `How to Not Step
|
|
Into Functions using the Visual C++
|
|
Debugger <http://blogs.msdn.com/andypennell/archive/2004/02/06/69004.aspx>`__
|
|
for details.
|
|
|
|
Here are some wildcards you can use (tested with VC 8):
|
|
|
|
.. code::
|
|
|
|
nsCOMPtr.*\:\:.*=NoStepInto
|
|
(nsG|g)etter_*AddRefs.*=NoStepInto
|
|
NS_ConvertUTF.*
|
|
; Might be too broad:
|
|
(ns|Promise)[^\:]*[sS]tring.*
|
|
...add common functions to this list
|
|
|
|
should probably make a .reg file for easy importing
|
|
|
|
Obtaining ``stdout`` and other ``FILE`` handles
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
Running the following command in the Command Window in Visual Studio
|
|
returns the value of ``stdout``, which can be used with various
|
|
debugging methods (such as ``nsGenericElement::List``) that take a
|
|
``FILE*`` param:
|
|
|
|
.. code::
|
|
|
|
Debug.EvaluateStatement {,,msvcr80d}(&__iob_func()[1])
|
|
|
|
(Alternatively you can evaluate ``{,,msvcr80d}(&__iob_func()[1])`` in
|
|
the QuickWatch window)
|
|
|
|
Similarly, you can open a file on the disk using ``fopen``:
|
|
|
|
.. code::
|
|
|
|
>Debug.EvaluateStatement {,,msvcr80d}fopen("c:\\123", "w")
|
|
0x10311dc0 { ..snip.. }
|
|
>Debug.EvaluateStatement ((nsGenericElement*)0x03f0e710)->List((FILE*)0x10311dc0, 1)
|
|
<void>
|
|
>Debug.EvaluateStatement {,,msvcr80d}fclose((FILE*)0x10311dc0)
|
|
0x00000000
|
|
|
|
Note that you may not see the debugging output until you flush or close
|
|
the file handle.
|
|
|
|
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:
|
|
|
|
.. code::
|
|
|
|
set XPCOM_DEBUG_BREAK=warn
|
|
|
|
The environment variable takes also other values besides ``warn``, see
|
|
``XPCOM_DEBUG_BREAK`` for more details.
|
|
|
|
Note that unlike Unix, the default for Windows is not warn, it's to pop
|
|
up a dialog. To set the environment variable for Visual Studio, use
|
|
Project > Properties > Debugging > Environment and click the little box.
|
|
Then use
|
|
|
|
.. code::
|
|
|
|
XPCOM_DEBUG_BREAK=warn
|
|
|
|
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 assembly 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
|
|
(```windbgdlg.exe`` </En/Automatically_Handle_Failed_Asserts_in_Debug_Builds>`__)
|
|
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
|
|
```windbgdlg.exe`` </En/Automatically_Handle_Failed_Asserts_in_Debug_Builds>`__.
|
|
|
|
Debugging optimized builds
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
To effectively debug optimized builds, you should enable debugging
|
|
information 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 surprises when
|
|
the debugger jumps over something.
|
|
|
|
You need to make sure this configure parameter is set:
|
|
|
|
.. code::
|
|
|
|
--enable-debugger-info-modules=yes
|
|
|
|
You can also choose to include or exclude specific modules. This is
|
|
particularly useful to avoid linking layout with debugging information.
|
|
|
|
Console debugging
|
|
~~~~~~~~~~~~~~~~~
|
|
|
|
When printing to STDOUT from a content process, the console message will
|
|
not appear on Windows. One way to view it is simply to disable e10s
|
|
(``./mach run --disable-e10s``) but in order to debug with e10s enabled
|
|
one can run
|
|
|
|
::
|
|
|
|
./mach run ... 2>&1 | tee
|
|
|
|
It may also be necessary to disable the content sandbox
|
|
(``MOZ_DISABLE_CONTENT_SANDBOX=1 ./mach run ...``).
|
|
|
|
Running two instances of Mozilla simultaneously
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
You can run two instances of Mozilla (e.g. debug and optimized)
|
|
simultaneously by setting the environment variable ``MOZ_NO_REMOTE``:
|
|
|
|
.. code::
|
|
|
|
set MOZ_NO_REMOTE=1
|
|
|
|
Or, starting with Firefox 2 and other Gecko 1.8.1-based applications,
|
|
you can use the ``-no-remote`` command-line switch instead (implemented
|
|
in
|
|
`bug 325509 <https://bugzilla.mozilla.org/show_bug.cgi?id=325509>`__).
|
|
|
|
You can also specify the profile to use with the ``-P profile_name``
|
|
command-line argument.
|
|
|
|
Debugging JavaScript
|
|
~~~~~~~~~~~~~~~~~~~~
|
|
|
|
Use `Venkman <https://developer.mozilla.org/en-US/docs/Archive/Mozilla/Venkman>`__, the JavaScript Debugger for Mozilla.
|
|
|
|
You can use helper functions from
|
|
`nsXPConnect.cpp <https://searchfox.org/mozilla-central/source/js/xpconnect/src/nsXPConnect.cpp>`__
|
|
to inspect and modify the state of JavaScript code from the MSVS
|
|
debugger.
|
|
|
|
For example, to print current JavaScript stack to stdout, evaluate this
|
|
in QuickWatch window:
|
|
|
|
.. code::
|
|
|
|
{,,xul}DumpJSStack()
|
|
|
|
Visual C++ will show you something in the quick watch window, but
|
|
not the stack, you have to look in the OS console for the output.
|
|
|
|
Also this magical command only works when the VC++ stack is in certain
|
|
states. It works when you have js_Interpret() in the newest stackframe
|
|
|
|
Debugging minidumps
|
|
~~~~~~~~~~~~~~~~~~~
|
|
|
|
See :ref:`debugging a minidump <Debugging A Minidump>`.
|
|
|
|
Debugging treeherder builds
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
See `Running Windows Debug Builds <https://developer.mozilla.org/en-US/docs/Archive/Mozilla/Running_Windows_Debug_Builds>`__
|
|
|
|
Problems Loading Debug Symbols
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
If both your application and Visual C++ hang shortly after launching the
|
|
application under the debugger, you may be hitting a known deadlock in
|
|
the way Visual Studio downloads debug symbols for the system libraries;
|
|
see
|
|
https://connect.microsoft.com/VisualStudio/feedback/details/422970/hang-loading-rasapi32-pdb-when-using-symbol-server.
|
|
|
|
There are two ways to work around this problem:
|
|
|
|
#. Turn off automatic symbol downloading for system libraries: in Tools
|
|
> Options > Debugging > Symbols, uncheck the Microsoft symbol server.
|
|
#. Pre-load all the Windows debug symbols. These instructions apply to
|
|
Visual Studio 10 on Windows 7; other software versions likely need to
|
|
have file paths adjusted.
|
|
|
|
#. Locate the Microsoft utility "SymChk.exe" on your system (it will
|
|
likely be in the installation directory of your Windows Debugging
|
|
Tools).
|
|
|
|
#. Find the directory where Visual Studio caches downloaded symbols;
|
|
in VC++ 10 open the menu to Tools > Options > Debugging > Symbols
|
|
and copy the field "Cache symbols in this directory".
|
|
|
|
#. In a command window, run
|
|
|
|
::
|
|
|
|
symchk.exe /r C:\windows\SysWOW64\ /s "SRV*<your cache symbols directory>\MicrosoftPublicSymbols*http://msdl.microsoft.com/download/symbols"
|
|
|
|
|
|
|
| Note the "``\MicrosoftPublicSymbols``" appended to the cache
|
|
directory configured in Visual Studio.
|
|
|
|
Downloading all symbols can take a long time; you can replace
|
|
C:\windows\SysWOW64\\ with the name of a single .DLL to download symbols
|
|
only for the specific libraries you are trying to debug. Unfortunately,
|
|
it's hard to know which symbols to download without having VS hang and
|
|
seeing the "Downloading symbols for <library>" status at the bottom left
|
|
of the main window.
|
|
|
|
Problems post-mortem debugging on Windows 7 SP1 x64?
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
If you attempt to use ``NS_DebugBreak`` etc to perform post-mortem
|
|
debugging on a 64bit Windows 7, but as soon as you try and continue
|
|
debugging the program crashes with an Access Violation, you may be
|
|
hitting a Windows bug relating to AVX support. For more details,
|
|
including a work-around see `this blog
|
|
post <http://www.os2museum.com/wp/?p=960>`__ or `this social.msdn
|
|
thread <http://social.msdn.microsoft.com/Forums/vstudio/en-US/392ca62c-e502-42d9-adbc-b4e22d5da0c3/jit-debugging-32bit-app-crashing-with-access-violation>`__.
|
|
(And just in-case those links die, the work-around is to execute
|
|
|
|
::
|
|
|
|
bcdedit /set xsavedisable 1
|
|
|
|
from an elevated command-prompt to disable AVX support.)
|
|
|
|
Got a tip?
|
|
~~~~~~~~~~
|
|
|
|
If you think you know a cool Mozilla debugging trick, feel free to
|
|
discuss it with `#developers <https://chat.mozilla.org/#/room/#developers:mozilla.org>`__ and
|
|
then post it here.
|
|
|
|
.. |Screenshot of disabling assertions| image:: https://developer.mozilla.org/@api/deki/files/420/=Win32-debug-nop.png
|
|
:class: internal
|