forked from mirrors/gecko-dev
		
	 630511a83a
			
		
	
	
		630511a83a
		
	
	
	
	
		
			
			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>`__.
 |