tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

debugging_on_macos.rst (16516B)


      1 Debugging On macOS
      2 ==================
      3 
      4 This document explains how to debug Gecko-based applications such as
      5 Firefox, Thunderbird, and SeaMonkey on macOS using Xcode. If you want to
      6 debug from the terminal see :ref:`Debugging Mozilla with
      7 lldb <Debugging Firefox with LLDB>`. For specific
      8 information on a way to debug hangs, see :ref:`Debugging a hang on macOS <Debugging A Hang On macOS>`.
      9 
     10 Creating a debuggable build
     11 ---------------------------
     12 
     13 First, you need to build the application you're going to debug using
     14 this in your .mozconfig
     15 
     16 .. code::
     17 
     18   ac_add_options --disable-optimize
     19   ac_add_options --enable-debug-symbols
     20 
     21 you can also add this flag if you want assertions etc. compiled in
     22 
     23 .. code::
     24 
     25   ac_add_options --enable-debug
     26 
     27 See :ref:`Building Firefox for macOS <Building Firefox On MacOS>`
     28 if you need help creating your own build.
     29 
     30 Debugging Firefox on macOS 10.14+
     31 ---------------------------------
     32 
     33 macOS 10.14 introduced Notarization and Hardened Runtime features for
     34 improved application security. macOS 10.15 went further, requiring
     35 applications to be Notarized with Hardened Runtime enabled in order to
     36 launch (ignoring workarounds). When run on earlier macOS versions,
     37 Notarization and Hardened Runtime settings have no effect.
     38 
     39 Official Builds
     40 ~~~~~~~~~~~~~~~
     41 
     42 At this time, official builds of Firefox 69 and later are Notarized.
     43 **As a result, it is not possible to attach a debugger to these official
     44 Firefox releases on macOS 10.14+ without disabling System Integrity
     45 Protection (SIP).** This is due to Notarization requiring Hardened
     46 Runtime to be enabled with the ``com.apple.security.get-task-allow``
     47 entitlement disallowed. **Rather than disabling SIP (which has security
     48 implications), it is recommended to debug with try builds or local
     49 builds. The differences are explained below.**
     50 
     51 try Server Builds
     52 ~~~~~~~~~~~~~~~~~
     53 
     54 In most cases, developers needing to debug a build as close as possible
     55 to the production environment should use a :ref:`try
     56 build <Pushing to Try>`. These
     57 builds enable Hardened Runtime and only differ from production builds in
     58 that they are not Notarized which should not otherwise affect
     59 functionality, (other than the ability to easily launch the browser on
     60 macOS 10.15+ -- see quarantine note below). At this time, developers can
     61 obtain a Hardened Runtime build with the
     62 ``com.apple.security.get-task-allow`` entitlement allowed by submitting
     63 a try build and downloading the dmg generated by the "Rpk" shippable
     64 build job. A debugger can be attached to Firefox processes of these
     65 builds. try builds use the developer entitlement files from the
     66 source tree (allowing debugger attach) while production builds use
     67 the production versions (which must meet notarization requirements).
     68 **On macOS 10.15+, downloaded try builds will not launch by default
     69 because Notarization is required. To workaround this problem, remove the
     70 quarantine extended attribute from the downloaded Nightly:**
     71 
     72  ``$ xattr -r -d com.apple.quarantine /Path/to/Nightly.app``
     73 
     74 Local Builds
     75 ~~~~~~~~~~~~
     76 
     77 Local builds of mozilla-central do not enable Hardened Runtime and hence
     78 do not have debugging restrictions. As a result, some functionality will
     79 be permitted on local builds, but blocked on production builds which
     80 have Hardened Runtime enabled. `Bug
     81 1522409 <https://bugzilla.mozilla.org/show_bug.cgi?id=1522409>`__ was
     82 filed to automate codesigning local builds to enable Hardened Runtime by
     83 default and eliminate this discrepancy.
     84 
     85 Disabling System Integrity Protection (SIP)
     86 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     87 
     88 If debugging a production build is required, follow Apple's documented
     89 steps for disabling System Integrity Protection (SIP). Note that
     90 disabling SIP bypasses Hardened Runtime restrictions which can mask some
     91 bugs that only occur with Hardened Runtime so it is recommended to test
     92 fixes with SIP enabled. **Disabling SIP has system security implications
     93 that should be understood before taking this step.**
     94 
     95 Creating an Xcode project
     96 -------------------------
     97 
     98 If you try to create a new Xcode project in an existing directory
     99 then Xcode will delete its existing contents (Xcode will warn you
    100 beforehand). To work around that, the steps below have you initialize
    101 the project outside the Mozilla source tree, close the project, copy
    102 the .xcodeproj project "file" into the source tree, and then reopen
    103 the project to finish setting it up.
    104 
    105 Note also that since Xcode 7.3.1 it doesn't seem to be possible to
    106 have the Xcode project live outside the source tree. If you try to do
    107 that then Xcode will simply **copy** the source files under the
    108 project directory rather than link to them which breaks debugging and the
    109 possibility to modify-rebuild-relaunch from inside Xcode.
    110 
    111 These steps were last updated for Xcode 15:
    112 
    113 #. Open Xcode, and create a new Project with File > New > Project.
    114   Select the "Other" tab then select the "Empty" project type, then
    115   click Next. Name the project and click Next again. Xcode will refuse
    116   to create a new project in a non-empty directory, so create/select
    117   a temporary directory to contain the project files, untick "Create
    118   Git repository" and then click Create.
    119 #. Before going any further, close the project (File > Close Project).
    120   Now open Finder, find the \*.xcodejproj directory in the temporary
    121   directory, move it into the root directory of your Mozilla source
    122   tree, then double-click on it to reopen it. (You can now delete the
    123   temporary directory.)
    124 #. In the left-hand pane in Xcode you should see a tree item where the
    125   root item has the project name. Now, right click on the root item,
    126   select 'Add files to "<project-name>"', select all the files and
    127   directories in your source directory, untick "Copy items if needed",
    128   then click Add. (These will then be progressively added under the
    129   root item <project-name> in the left-hand pane. Note that
    130   subdirectories may initially appear to be empty, but they too will
    131   progressively be  populated as Xcode processes the sourse files.
    132   Once done, you should be able to open any file quickly by hitting
    133   Cmd-Shift-O and typing in the name of a file.)
    134 #. In the Product menu, select Scheme > New Scheme and name your scheme
    135   (for example, "Debug"). After you click OK, Xcode should open the
    136   settings window for the new scheme. (If not, then open its settings
    137   from the Product > Edit Scheme menu.)
    138 #. Select "Run" on the left-hand side of the settings window, then
    139   select the "Info" tab. Set the Executable by clicking on "None" and
    140   selecting "Other...". A new dialog titled "Choose an executable to
    141   launch" will pop up. Browse to the ``.app`` file that you want to
    142   debug (``Firefox.app``, ``Nightly``\ ``Debug.app`` etc). The ``.app``
    143   file is typically found inside the ``dist`` folder in your build
    144   directory.
    145 #. If you are debugging Firefox, Thunderbird, or some other application
    146   that supports multiple profiles, using a separate profile for
    147   debugging purposes is recommended. See "Having a profile for
    148   debugging purposes" below. Select the "Arguments" tab in the scheme
    149   editor, and click the '+' below the "Arguments passed on launch"
    150   field. Add "-P *profilename*", where *profilename* is the name of a
    151   profile you created previously.
    152 #. Also in the "Arguments" panel, you may want to add an environment
    153   variable MOZ_DEBUG_CHILD_PROCESS set to the value 1 to help with
    154   debugging e10s.
    155 #. Select "Build" from the left of the scheme editor window, and check
    156   that there is nothing listed under Targets (otherwise it may cause
    157   problems when you try to run the executable for debugging since you
    158   will get build errors).
    159 #. Click "Close" to close the scheme editor.
    160 
    161 At this point you can run and debug the Mozilla application from Xcode
    162 (if the application doesn't appear to open, check whether it opened in
    163 the background). When it hits breakpoints, Xcode should open the
    164 correct source file at the correct line.
    165 
    166 Setting up lldb
    167 ---------------
    168 
    169 ``lldb`` is the debugger Xcode provides/uses.
    170 
    171 .. warning::
    172 
    173   One important issue that the Mozilla .lldbinit file fixes is that by
    174   default some breakpoints will be listed as "pending", and Xcode will
    175   not stop at them. If you don't include the Mozilla's .lldbinit, you
    176   must at least put
    177   ``settings set target.inline-breakpoint-strategy always`` in your
    178   ``$HOME/.lldbinit`` as recommended on :ref:`Debugging Firefox with
    179   lldb <Debugging Firefox with LLDB>`.
    180 
    181 The
    182 `.lldbinit <http://searchfox.org/mozilla-central/source/.lldbinit>`__
    183 file in the source tree imports many useful `Mozilla specific lldb
    184 settings, commands and
    185 formatters <https://searchfox.org/mozilla-central/source/python/lldbutils/README.txt>`__
    186 into ``lldb``, but you may need to take one of the following steps to
    187 make sure this file is used.
    188 
    189 If you are using ``lldb`` on the command line (independently of Xcode)
    190 and you will always run it from either the top source directory, the
    191 object directory or else the dist/bin subdirectory of the object
    192 directory, then adding the following setting to your ``$HOME/.lldbinit``
    193 is sufficient:
    194 
    195 ::
    196 
    197   settings set target.load-cwd-lldbinit true
    198 
    199 *However*, if you will run lldb from a different directory, or if you
    200 will be running it indirectly by debugging in Xcode (Xcode always runs
    201 lldb from "/"), then this setting will not help you. Instead, add the
    202 following to your ``$HOME/.lldbinit``:
    203 
    204 ::
    205 
    206   # This automatically sources the Mozilla project's .lldbinit as soon as lldb
    207   # starts or attaches to a Mozilla app (that's in an object directory).
    208   #
    209   # This is mainly a workaround for Xcode not providing a way to specify that
    210   # lldb should be run from a given directory.  (Xcode always runs lldb from "/",
    211   # regardless of what directory Xcode was started from, and regardless of the
    212   # value of the "Custom working directory" field in the Scheme's Run options.
    213   # Therefore setting `settings set target.load-cwd-lldbinit true` can't help us
    214   # without Xcode providing that functionality.)
    215   #
    216   # The following works by setting a one-shot breakpoint to break on a function
    217   # that we know will both run early (which we want when we start first start the
    218   # app) and run frequently (which we want so that it will trigger ASAP if we
    219   # attach to an already running app).  The breakpoint runs some commands to
    220   # figure out the object directory path from the attached target and then
    221   # sources the .lldbinit from there.
    222   #
    223   # NOTE: This scripts actions take a few seconds to complete, so the custom
    224   # formatters, commands etc. that are added may not be immediately available.
    225   #
    226   breakpoint set --name nsThread::ProcessNextEvent --thread-index 1 --auto-continue true --one-shot true
    227   breakpoint command add -s python
    228       # This script that we run does not work if we try to use the global 'lldb'
    229       # object, since it is out of date at the time that the script runs (for
    230       # example, `lldb.target.executable.fullpath` is empty).  Therefore we must
    231       # get the following objects from the 'frame' object.
    232       target = frame.GetThread().GetProcess().GetTarget()
    233       debugger = target.GetDebugger()
    234 
    235       # Delete our breakpoint (not actually necessary with `--one-shot true`):
    236       target.BreakpointDelete(bp_loc.GetBreakpoint().GetID())
    237 
    238       # For completeness, find and delete the dummy breakpoint (the breakpoint
    239       # lldb creates when it can't initially find the method to set the
    240       # breakpoint on):
    241       # BUG WORKAROUND! GetID() on the *dummy* breakpoint appears to be returning
    242       # the breakpoint index instead of its ID.  We have to add 1 to correct for
    243       # that! :-(
    244       dummy_bp_list = lldb.SBBreakpointList(target)
    245       debugger.GetDummyTarget().FindBreakpointsByName("nsThread::ProcessNextEvent", dummy_bp_list)
    246       dummy_bp_id = dummy_bp_list.GetBreakpointAtIndex(0).GetID() + 1
    247       debugger.GetDummyTarget().BreakpointDelete(dummy_bp_id)
    248 
    249       # "source" the Mozilla project .lldbinit:
    250       os.chdir(target.executable.fullpath.split("/dist/")[0])
    251       debugger.HandleCommand("command source -s true " + os.path.join(os.getcwd(), ".lldbinit"))
    252   DONE
    253 
    254 see :ref:`Debugging Mozilla with
    255 lldb <Debugging Firefox with LLDB>`. for more information.
    256 
    257 Having a profile for debugging purposes
    258 ---------------------------------------
    259 
    260 It is recommended to create a separate profile to debug with, whatever
    261 your task, so that you don't lose precious data like Bookmarks, saved
    262 passwords, etc. So that you're not bothered with the profile manager
    263 every time you start to debug, expand the "Executables" branch of the
    264 "Groups & Files" list and double click on the Executable you added for
    265 Mozilla. Click the plus icon under the "Arguments" list and type "-P
    266 <profile name>" (e.g. "-P MozillaDebug"). Close the window when you're
    267 done.
    268 
    269 Running a debug session
    270 -----------------------
    271 
    272 Make sure breakpoints are active (which implies running under the
    273 debugger) by opening the Product menu and selecting "Debug / Activate
    274 Breakpoints" (also shown by the "Breakpoints" button in the top right
    275 section of the main window). Then click the "Run" button or select "Run"
    276 from the Product menu.
    277 
    278 Setting breakpoints
    279 ~~~~~~~~~~~~~~~~~~~
    280 
    281 Setting a breakpoint is easy. Just open the source file you want to
    282 debug in Xcode, and click in the margin to the left of the line of code
    283 where you want to break.
    284 
    285 During the debugging session, each time that line is executed, the
    286 debugger will break there, and you will be able to debug it.
    287 
    288 .. warning::
    289 
    290   Note that with the default configuration, some breakpoints will be
    291   listed as "pending", and Xcode will not stop at them. If you don't
    292   include the Mozilla's .lldbinit, you must at least put
    293   ``settings set target.inline-breakpoint-strategy always`` in your
    294   ``$HOME/.lldbinit`` as recommended on :ref:`Debugging Mozilla with
    295   lldb <Debugging Firefox with LLDB>`.
    296 
    297 Using Firefox-specific lldb commands
    298 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    299 
    300 If you included the .lldbinit when `Setting up
    301 lldb <#setting-up-lldb>`__, you can use Mozilla-specific lldb commands
    302 in the console, located in the Debug area of Xcode. For example, type
    303 ``js`` to see the JavaScript stack. For more information, see :ref:`Debugging
    304 Mozilla with lldb <Debugging Firefox with LLDB>`.
    305 
    306 Debugging e10s child processes
    307 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    308 
    309 Using Xcode to debug child processes created by an e10s-enabled browser
    310 is a little trickier than debugging a single-process browser, but it can
    311 be done. These directions were written using Xcode 6.3.1
    312 
    313 #. Complete all the steps above under "Creating the Project"
    314 #. From the "Product" menu, ensure the scheme you created is selected
    315   under "Scheme", then choose "Scheme > Edit Scheme"
    316 #. In the resulting popup, click "Duplicate Scheme"
    317 #. Give the resulting scheme a more descriptive name than "Copy of
    318   Scheme"
    319 #. Select "Run" on the left-hand side of the settings window, then
    320   select the "Info" tab. Set the Executable by clicking on the
    321   "Executable" drop-down, and selecting the ``plugin-container.app``
    322   that is inside the app bundle of the copy of Firefox you want to
    323   debug.
    324 #. On the same tab, under "Launch" select "Wait for executable to be
    325   launched"
    326 #. On the "Arguments" tab, remove all arguments passed on launch.
    327 
    328 Now you're ready to start debugging:
    329 
    330 #. From the "Product" menu, ensure the scheme you created above is
    331   selected under "Scheme"
    332 #. Click the "Run" button. The information area at the top of the window
    333   will show "Waiting for plugin-container to launch"
    334 #. From a command line, run your build of Firefox. When that launches a
    335   child process (for example, when you start to load a webpage), Xcode
    336   will notice and attach to that child process. You can then debug the
    337   child process like you would any other process.
    338 #. When you are done debugging, click the "Stop" button and quit the
    339   instance of Firefox that you were debugging in the normal way.
    340 
    341 For some help on using lldb see :ref:`Debugging Mozilla with
    342 lldb <Debugging Firefox with LLDB>`.
    343 
    344 Other resources
    345 ---------------
    346 
    347 Apple has an extensive list of `debugging tips and
    348 techniques <https://developer.apple.com/library/mac/#technotes/tn2124/_index.html>`__.
    349 
    350 Questions? Problems?
    351 ~~~~~~~~~~~~~~~~~~~~
    352 
    353 Try asking in our Element channels
    354 `#developers <https://chat.mozilla.org/#/room/#developers:mozilla.org>`__ or
    355 `#macdev <https://chat.mozilla.org/#/room/#macdev:mozilla.org>`__.