mirror of
				https://github.com/mozilla/gecko-dev.git
				synced 2025-11-04 10:18:41 +02:00 
			
		
		
		
	Updating for the Xcode 15 user interface changes. Differential Revision: https://phabricator.services.mozilla.com/D195166
		
			
				
	
	
		
			356 lines
		
	
	
	
		
			16 KiB
		
	
	
	
		
			ReStructuredText
		
	
	
	
	
	
			
		
		
	
	
			356 lines
		
	
	
	
		
			16 KiB
		
	
	
	
		
			ReStructuredText
		
	
	
	
	
	
Debugging On macOS
 | 
						|
==================
 | 
						|
 | 
						|
This document explains how to debug Gecko-based applications such as
 | 
						|
Firefox, Thunderbird, and SeaMonkey on macOS using Xcode. If you want to
 | 
						|
debug from the terminal see :ref:`Debugging Mozilla with
 | 
						|
lldb <Debugging Firefox with LLDB>`. For specific
 | 
						|
information on a way to debug hangs, see :ref:`Debugging a hang on macOS <Debugging A Hang On macOS>`.
 | 
						|
 | 
						|
Creating a debuggable build
 | 
						|
---------------------------
 | 
						|
 | 
						|
First, you need to build the application you're going to debug using
 | 
						|
this in your .mozconfig
 | 
						|
 | 
						|
.. code::
 | 
						|
 | 
						|
   ac_add_options --disable-optimize
 | 
						|
   ac_add_options --enable-debug-symbols
 | 
						|
 | 
						|
you can also add this flag if you want assertions etc. compiled in
 | 
						|
 | 
						|
.. code::
 | 
						|
 | 
						|
   ac_add_options --enable-debug
 | 
						|
 | 
						|
See :ref:`Building Firefox for macOS <Building Firefox On MacOS>`
 | 
						|
if you need help creating your own build.
 | 
						|
 | 
						|
Debugging Firefox on macOS 10.14+
 | 
						|
---------------------------------
 | 
						|
 | 
						|
macOS 10.14 introduced Notarization and Hardened Runtime features for
 | 
						|
improved application security. macOS 10.15 went further, requiring
 | 
						|
applications to be Notarized with Hardened Runtime enabled in order to
 | 
						|
launch (ignoring workarounds). When run on earlier macOS versions,
 | 
						|
Notarization and Hardened Runtime settings have no effect.
 | 
						|
 | 
						|
Official Builds
 | 
						|
~~~~~~~~~~~~~~~
 | 
						|
 | 
						|
At this time, official builds of Firefox 69 and later are Notarized.
 | 
						|
**As a result, it is not possible to attach a debugger to these official
 | 
						|
Firefox releases on macOS 10.14+ without disabling System Integrity
 | 
						|
Protection (SIP).** This is due to Notarization requiring Hardened
 | 
						|
Runtime to be enabled with the ``com.apple.security.get-task-allow``
 | 
						|
entitlement disallowed. **Rather than disabling SIP (which has security
 | 
						|
implications), it is recommended to debug with try builds or local
 | 
						|
builds. The differences are explained below.**
 | 
						|
 | 
						|
try Server Builds
 | 
						|
~~~~~~~~~~~~~~~~~
 | 
						|
 | 
						|
In most cases, developers needing to debug a build as close as possible
 | 
						|
to the production environment should use a :ref:`try
 | 
						|
build <Pushing to Try>`. These
 | 
						|
builds enable Hardened Runtime and only differ from production builds in
 | 
						|
that they are not Notarized which should not otherwise affect
 | 
						|
functionality, (other than the ability to easily launch the browser on
 | 
						|
macOS 10.15+ -- see quarantine note below). At this time, developers can
 | 
						|
obtain a Hardened Runtime build with the
 | 
						|
``com.apple.security.get-task-allow`` entitlement allowed by submitting
 | 
						|
a try build and downloading the dmg generated by the "Rpk" shippable
 | 
						|
build job. A debugger can be attached to Firefox processes of these
 | 
						|
builds. try builds use the developer entitlement files from the
 | 
						|
source tree (allowing debugger attach) while production builds use
 | 
						|
the production versions (which must meet notarization requirements).
 | 
						|
**On macOS 10.15+, downloaded try builds will not launch by default
 | 
						|
because Notarization is required. To workaround this problem, remove the
 | 
						|
quarantine extended attribute from the downloaded Nightly:**
 | 
						|
 | 
						|
  ``$ xattr -r -d com.apple.quarantine /Path/to/Nightly.app``
 | 
						|
 | 
						|
Local Builds
 | 
						|
~~~~~~~~~~~~
 | 
						|
 | 
						|
Local builds of mozilla-central do not enable Hardened Runtime and hence
 | 
						|
do not have debugging restrictions. As a result, some functionality will
 | 
						|
be permitted on local builds, but blocked on production builds which
 | 
						|
have Hardened Runtime enabled. `Bug
 | 
						|
1522409 <https://bugzilla.mozilla.org/show_bug.cgi?id=1522409>`__ was
 | 
						|
filed to automate codesigning local builds to enable Hardened Runtime by
 | 
						|
default and eliminate this discrepancy.
 | 
						|
 | 
						|
Disabling System Integrity Protection (SIP)
 | 
						|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 | 
						|
 | 
						|
If debugging a production build is required, follow Apple's documented
 | 
						|
steps for disabling System Integrity Protection (SIP). Note that
 | 
						|
disabling SIP bypasses Hardened Runtime restrictions which can mask some
 | 
						|
bugs that only occur with Hardened Runtime so it is recommended to test
 | 
						|
fixes with SIP enabled. **Disabling SIP has system security implications
 | 
						|
that should be understood before taking this step.**
 | 
						|
 | 
						|
Creating an Xcode project
 | 
						|
-------------------------
 | 
						|
 | 
						|
If you try to create a new Xcode project in an existing directory
 | 
						|
then Xcode will delete its existing contents (Xcode will warn you
 | 
						|
beforehand). To work around that, the steps below have you initialize
 | 
						|
the project outside the Mozilla source tree, close the project, copy
 | 
						|
the .xcodeproj project "file" into the source tree, and then reopen
 | 
						|
the project to finish setting it up.
 | 
						|
 | 
						|
Note also that since Xcode 7.3.1 it doesn't seem to be possible to
 | 
						|
have the Xcode project live outside the source tree. If you try to do
 | 
						|
that then Xcode will simply **copy** the source files under the
 | 
						|
project directory rather than link to them which breaks debugging and the
 | 
						|
possibility to modify-rebuild-relaunch from inside Xcode.
 | 
						|
 | 
						|
These steps were last updated for Xcode 15:
 | 
						|
 | 
						|
#. Open Xcode, and create a new Project with File > New > Project.
 | 
						|
   Select the "Other" tab then select the "Empty" project type, then
 | 
						|
   click Next. Name the project and click Next again. Xcode will refuse
 | 
						|
   to create a new project in a non-empty directory, so create/select
 | 
						|
   a temporary directory to contain the project files, untick "Create
 | 
						|
   Git repository" and then click Create.
 | 
						|
#. Before going any further, close the project (File > Close Project).
 | 
						|
   Now open Finder, find the \*.xcodejproj directory in the temporary
 | 
						|
   directory, move it into the root directory of your Mozilla source
 | 
						|
   tree, then double-click on it to reopen it. (You can now delete the
 | 
						|
   temporary directory.)
 | 
						|
#. In the left-hand pane in Xcode you should see a tree item where the
 | 
						|
   root item has the project name. Now, right click on the root item,
 | 
						|
   select 'Add files to "<project-name>"', select all the files and
 | 
						|
   directories in your source directory, untick "Copy items if needed",
 | 
						|
   then click Add. (These will then be progressively added under the
 | 
						|
   root item <project-name> in the left-hand pane. Note that
 | 
						|
   subdirectories may initially appear to be empty, but they too will
 | 
						|
   progressively be  populated as Xcode processes the sourse files.
 | 
						|
   Once done, you should be able to open any file quickly by hitting
 | 
						|
   Cmd-Shift-O and typing in the name of a file.)
 | 
						|
#. In the Product menu, select Scheme > New Scheme and name your scheme
 | 
						|
   (for example, "Debug"). After you click OK, Xcode should open the
 | 
						|
   settings window for the new scheme. (If not, then open its settings
 | 
						|
   from the Product > Edit Scheme menu.)
 | 
						|
#. Select "Run" on the left-hand side of the settings window, then
 | 
						|
   select the "Info" tab. Set the Executable by clicking on "None" and
 | 
						|
   selecting "Other...". A new dialog titled "Choose an executable to
 | 
						|
   launch" will pop up. Browse to the ``.app`` file that you want to
 | 
						|
   debug (``Firefox.app``, ``Nightly``\ ``Debug.app`` etc). The ``.app``
 | 
						|
   file is typically found inside the ``dist`` folder in your build
 | 
						|
   directory.
 | 
						|
#. If you are debugging Firefox, Thunderbird, or some other application
 | 
						|
   that supports multiple profiles, using a separate profile for
 | 
						|
   debugging purposes is recommended. See "Having a profile for
 | 
						|
   debugging purposes" below. Select the "Arguments" tab in the scheme
 | 
						|
   editor, and click the '+' below the "Arguments passed on launch"
 | 
						|
   field. Add "-P *profilename*", where *profilename* is the name of a
 | 
						|
   profile you created previously. Repeat that to also add the argument
 | 
						|
   "-no-remote".
 | 
						|
#. Also in the "Arguments" panel, you may want to add an environment
 | 
						|
   variable MOZ_DEBUG_CHILD_PROCESS set to the value 1 to help with
 | 
						|
   debugging e10s.
 | 
						|
#. Select "Build" from the left of the scheme editor window, and check
 | 
						|
   that there is nothing listed under Targets (otherwise it may cause
 | 
						|
   problems when you try to run the executable for debugging since you
 | 
						|
   will get build errors).
 | 
						|
#. Click "Close" to close the scheme editor.
 | 
						|
 | 
						|
At this point you can run and debug the Mozilla application from Xcode
 | 
						|
(if the application doesn't appear to open, check whether it opened in
 | 
						|
the background). When it hits breakpoints, Xcode should open the
 | 
						|
correct source file at the correct line.
 | 
						|
 | 
						|
Setting up lldb
 | 
						|
---------------
 | 
						|
 | 
						|
``lldb`` is the debugger Xcode provides/uses.
 | 
						|
 | 
						|
.. warning::
 | 
						|
 | 
						|
   One important issue that the Mozilla .lldbinit file fixes is that by
 | 
						|
   default some breakpoints will be listed as "pending", and Xcode will
 | 
						|
   not stop at them. If you don't include the Mozilla's .lldbinit, you
 | 
						|
   must at least put
 | 
						|
   ``settings set target.inline-breakpoint-strategy always`` in your
 | 
						|
   ``$HOME/.lldbinit`` as recommended on :ref:`Debugging Firefox with
 | 
						|
   lldb <Debugging Firefox with LLDB>`.
 | 
						|
 | 
						|
The
 | 
						|
`.lldbinit <http://searchfox.org/mozilla-central/source/.lldbinit>`__
 | 
						|
file in the source tree imports many useful `Mozilla specific lldb
 | 
						|
settings, commands and
 | 
						|
formatters <https://searchfox.org/mozilla-central/source/python/lldbutils/README.txt>`__
 | 
						|
into ``lldb``, but you may need to take one of the following steps to
 | 
						|
make sure this file is used.
 | 
						|
 | 
						|
If you are using ``lldb`` on the command line (independently of Xcode)
 | 
						|
and you will always run it from either the top source directory, the
 | 
						|
object directory or else the dist/bin subdirectory of the object
 | 
						|
directory, then adding the following setting to your ``$HOME/.lldbinit``
 | 
						|
is sufficient:
 | 
						|
 | 
						|
::
 | 
						|
 | 
						|
   settings set target.load-cwd-lldbinit true
 | 
						|
 | 
						|
*However*, if you will run lldb from a different directory, or if you
 | 
						|
will be running it indirectly by debugging in Xcode (Xcode always runs
 | 
						|
lldb from "/"), then this setting will not help you. Instead, add the
 | 
						|
following to your ``$HOME/.lldbinit``:
 | 
						|
 | 
						|
::
 | 
						|
 | 
						|
   # This automatically sources the Mozilla project's .lldbinit as soon as lldb
 | 
						|
   # starts or attaches to a Mozilla app (that's in an object directory).
 | 
						|
   #
 | 
						|
   # This is mainly a workaround for Xcode not providing a way to specify that
 | 
						|
   # lldb should be run from a given directory.  (Xcode always runs lldb from "/",
 | 
						|
   # regardless of what directory Xcode was started from, and regardless of the
 | 
						|
   # value of the "Custom working directory" field in the Scheme's Run options.
 | 
						|
   # Therefore setting `settings set target.load-cwd-lldbinit true` can't help us
 | 
						|
   # without Xcode providing that functionality.)
 | 
						|
   #
 | 
						|
   # The following works by setting a one-shot breakpoint to break on a function
 | 
						|
   # that we know will both run early (which we want when we start first start the
 | 
						|
   # app) and run frequently (which we want so that it will trigger ASAP if we
 | 
						|
   # attach to an already running app).  The breakpoint runs some commands to
 | 
						|
   # figure out the object directory path from the attached target and then
 | 
						|
   # sources the .lldbinit from there.
 | 
						|
   #
 | 
						|
   # NOTE: This scripts actions take a few seconds to complete, so the custom
 | 
						|
   # formatters, commands etc. that are added may not be immediately available.
 | 
						|
   #
 | 
						|
   breakpoint set --name nsThread::ProcessNextEvent --thread-index 1 --auto-continue true --one-shot true
 | 
						|
   breakpoint command add -s python
 | 
						|
       # This script that we run does not work if we try to use the global 'lldb'
 | 
						|
       # object, since it is out of date at the time that the script runs (for
 | 
						|
       # example, `lldb.target.executable.fullpath` is empty).  Therefore we must
 | 
						|
       # get the following objects from the 'frame' object.
 | 
						|
       target = frame.GetThread().GetProcess().GetTarget()
 | 
						|
       debugger = target.GetDebugger()
 | 
						|
 | 
						|
       # Delete our breakpoint (not actually necessary with `--one-shot true`):
 | 
						|
       target.BreakpointDelete(bp_loc.GetBreakpoint().GetID())
 | 
						|
 | 
						|
       # For completeness, find and delete the dummy breakpoint (the breakpoint
 | 
						|
       # lldb creates when it can't initially find the method to set the
 | 
						|
       # breakpoint on):
 | 
						|
       # BUG WORKAROUND! GetID() on the *dummy* breakpoint appears to be returning
 | 
						|
       # the breakpoint index instead of its ID.  We have to add 1 to correct for
 | 
						|
       # that! :-(
 | 
						|
       dummy_bp_list = lldb.SBBreakpointList(target)
 | 
						|
       debugger.GetDummyTarget().FindBreakpointsByName("nsThread::ProcessNextEvent", dummy_bp_list)
 | 
						|
       dummy_bp_id = dummy_bp_list.GetBreakpointAtIndex(0).GetID() + 1
 | 
						|
       debugger.GetDummyTarget().BreakpointDelete(dummy_bp_id)
 | 
						|
 | 
						|
       # "source" the Mozilla project .lldbinit:
 | 
						|
       os.chdir(target.executable.fullpath.split("/dist/")[0])
 | 
						|
       debugger.HandleCommand("command source -s true " + os.path.join(os.getcwd(), ".lldbinit"))
 | 
						|
   DONE
 | 
						|
 | 
						|
see :ref:`Debugging Mozilla with
 | 
						|
lldb <Debugging Firefox with LLDB>`. for more information.
 | 
						|
 | 
						|
Having a profile for debugging purposes
 | 
						|
---------------------------------------
 | 
						|
 | 
						|
It is recommended to create a separate profile to debug with, whatever
 | 
						|
your task, so that you don't lose precious data like Bookmarks, saved
 | 
						|
passwords, etc. So that you're not bothered with the profile manager
 | 
						|
every time you start to debug, expand the "Executables" branch of the
 | 
						|
"Groups & Files" list and double click on the Executable you added for
 | 
						|
Mozilla. Click the plus icon under the "Arguments" list and type "-P
 | 
						|
<profile name>" (e.g. "-P MozillaDebug"). Close the window when you're
 | 
						|
done.
 | 
						|
 | 
						|
Running a debug session
 | 
						|
-----------------------
 | 
						|
 | 
						|
Make sure breakpoints are active (which implies running under the
 | 
						|
debugger) by opening the Product menu and selecting "Debug / Activate
 | 
						|
Breakpoints" (also shown by the "Breakpoints" button in the top right
 | 
						|
section of the main window). Then click the "Run" button or select "Run"
 | 
						|
from the Product menu.
 | 
						|
 | 
						|
Setting breakpoints
 | 
						|
~~~~~~~~~~~~~~~~~~~
 | 
						|
 | 
						|
Setting a breakpoint is easy. Just open the source file you want to
 | 
						|
debug in Xcode, and click in the margin to the left of the line of code
 | 
						|
where you want to break.
 | 
						|
 | 
						|
During the debugging session, each time that line is executed, the
 | 
						|
debugger will break there, and you will be able to debug it.
 | 
						|
 | 
						|
.. warning::
 | 
						|
 | 
						|
   Note that with the default configuration, some breakpoints will be
 | 
						|
   listed as "pending", and Xcode will not stop at them. If you don't
 | 
						|
   include the Mozilla's .lldbinit, you must at least put
 | 
						|
   ``settings set target.inline-breakpoint-strategy always`` in your
 | 
						|
   ``$HOME/.lldbinit`` as recommended on :ref:`Debugging Mozilla with
 | 
						|
   lldb <Debugging Firefox with LLDB>`.
 | 
						|
 | 
						|
Using Firefox-specific lldb commands
 | 
						|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 | 
						|
 | 
						|
If you included the .lldbinit when `Setting up
 | 
						|
lldb <#setting-up-lldb>`__, you can use Mozilla-specific lldb commands
 | 
						|
in the console, located in the Debug area of Xcode. For example, type
 | 
						|
``js`` to see the JavaScript stack. For more information, see :ref:`Debugging
 | 
						|
Mozilla with lldb <Debugging Firefox with LLDB>`.
 | 
						|
 | 
						|
Debugging e10s child processes
 | 
						|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 | 
						|
 | 
						|
Using Xcode to debug child processes created by an e10s-enabled browser
 | 
						|
is a little trickier than debugging a single-process browser, but it can
 | 
						|
be done. These directions were written using Xcode 6.3.1
 | 
						|
 | 
						|
#. Complete all the steps above under "Creating the Project"
 | 
						|
#. From the "Product" menu, ensure the scheme you created is selected
 | 
						|
   under "Scheme", then choose "Scheme > Edit Scheme"
 | 
						|
#. In the resulting popup, click "Duplicate Scheme"
 | 
						|
#. Give the resulting scheme a more descriptive name than "Copy of
 | 
						|
   Scheme"
 | 
						|
#. Select "Run" on the left-hand side of the settings window, then
 | 
						|
   select the "Info" tab. Set the Executable by clicking on the
 | 
						|
   "Executable" drop-down, and selecting the ``plugin-container.app``
 | 
						|
   that is inside the app bundle of the copy of Firefox you want to
 | 
						|
   debug.
 | 
						|
#. On the same tab, under "Launch" select "Wait for executable to be
 | 
						|
   launched"
 | 
						|
#. On the "Arguments" tab, remove all arguments passed on launch.
 | 
						|
 | 
						|
Now you're ready to start debugging:
 | 
						|
 | 
						|
#. From the "Product" menu, ensure the scheme you created above is
 | 
						|
   selected under "Scheme"
 | 
						|
#. Click the "Run" button. The information area at the top of the window
 | 
						|
   will show "Waiting for plugin-container to launch"
 | 
						|
#. From a command line, run your build of Firefox. When that launches a
 | 
						|
   child process (for example, when you start to load a webpage), Xcode
 | 
						|
   will notice and attach to that child process. You can then debug the
 | 
						|
   child process like you would any other process.
 | 
						|
#. When you are done debugging, click the "Stop" button and quit the
 | 
						|
   instance of Firefox that you were debugging in the normal way.
 | 
						|
 | 
						|
For some help on using lldb see :ref:`Debugging Mozilla with
 | 
						|
lldb <Debugging Firefox with LLDB>`.
 | 
						|
 | 
						|
Other resources
 | 
						|
---------------
 | 
						|
 | 
						|
Apple has an extensive list of `debugging tips and
 | 
						|
techniques <https://developer.apple.com/library/mac/#technotes/tn2124/_index.html>`__.
 | 
						|
 | 
						|
Questions? Problems?
 | 
						|
~~~~~~~~~~~~~~~~~~~~
 | 
						|
 | 
						|
Try asking in our Element channels
 | 
						|
`#developers <https://chat.mozilla.org/#/room/#developers:mozilla.org>`__ or
 | 
						|
`#macdev <https://chat.mozilla.org/#/room/#macdev:mozilla.org>`__.
 |