tor-browser

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

native-debugging.rst (10242B)


      1 .. -*- Mode: rst; fill-column: 80; -*-
      2 
      3 =====================
      4 Debugging Native Code
      5 =====================
      6 
      7 Table of contents
      8 =================
      9 
     10 .. contents:: :local:
     11 
     12 Debugging Native Code in Android Studio.
     13 ========================================
     14 
     15 If you want to work on the C++ code that powers GeckoView, you will need
     16 to be able to perform native debugging inside Android Studio. This
     17 article will guide you through how to do that.
     18 
     19 If you need to get set up with GeckoView for the first time, follow the
     20 `Quick Start Guide <geckoview-quick-start.html>`_.
     21 
     22 Perform a debug build of Gecko.
     23 -------------------------------
     24 
     25 1. Edit your ``mozconfig`` file and add the following lines. These will
     26   ensure that the build includes debug checks and symbols.
     27 
     28 .. code:: text
     29 
     30   ac_add_options --enable-debug
     31 
     32 2. Ensure that the following lines are commented out in your
     33   ``mozconfig`` if present. ``./mach configure`` will not allow
     34   artifact builds to be enabled when generating a debug build.
     35 
     36 .. code:: text
     37 
     38   # ac_add_options --enable-artifact-builds
     39 
     40 3. To be absolutely sure that Android Studio will pick up your debug
     41   symbols, the first time you perform a debug build it is best to
     42   clobber your ``MOZ_OBJDIR``. Subsequent builds should not need this
     43   step.
     44 
     45 .. code:: bash
     46 
     47   ./mach clobber
     48 
     49 4. Build as usual. Because this is a debug build, and because you have
     50   clobbered your ``MOZ_OBJDIR``, this will take a long time. Subsequent
     51   builds will be incremental and take less time, so go make yourself a
     52   cup of your favourite beverage.
     53 
     54 .. code:: bash
     55 
     56   ./mach build
     57 
     58 Set up lldb to find your symbols
     59 --------------------------------
     60 
     61 Edit your ``~/.lldbinit`` file (or create one if one does not already
     62 exist) and add the following lines.
     63 
     64 The first line tells LLDB to enable inline breakpoints - Android Studio
     65 will need this if you want to use visual breakpoints.
     66 
     67 The next line tells LLDB where to go to find the symbols for debugging.
     68 
     69 .. code:: bash
     70 
     71   settings set target.inline-breakpoint-strategy always
     72   settings append target.exec-search-paths <PATH>/objdir-android-opt/dist/bin
     73 
     74 Set up Android Studio to perform native debugging.
     75 ==================================================
     76 
     77 1. Edit the configuration that you want to debug by clicking
     78   ``Run -> Edit Configurations...`` and selecting the correct
     79   configuration from the options on the left hand side of the resulting
     80   window.
     81 2. Select the ``Debugger`` tab.
     82 3. Select ``Dual`` from the ``Debug type`` select box. Dual will allow
     83   debugging of both native and Java code in the same session. It is
     84   possible to use ``Native``, but it will only allow for debugging
     85   native code, and it’s frequently necessary to break in the Java code
     86   that configures Gecko and child processes in order to attach
     87   debuggers at the correct times.
     88 4. Under ``Symbol Directories``, add a new path pointing to
     89   ``<PATH>/objdir-android-opt/dist/bin``, the same path that you
     90   entered into your ``.lldbinit`` file.
     91 5. Select ``Apply`` and ``OK`` to close the window.
     92 
     93 Debug Native code in Android Studio
     94 ===================================
     95 
     96 1. The first time you are running a debug session for your app, it’s
     97   best to start from a completely clean build. Click
     98   ``Build -> Rebuild Project`` to clean and rebuild. You can also
     99   choose to remove any existing builds from your emulator to be
    100   completely sure, but this may not be necessary.
    101 2. If using Android Studio visual breakpoints, set your breakpoints in
    102   your native code.
    103 3. Run the app in debug mode as usual.
    104 4. When debugging Fennec or geckoview_example, you will almost
    105   immediately hit a breakpoint in ``ElfLoader.cpp``. This is expected.
    106   If you are not using Android Studio visual breakpoints, you can set
    107   your breakpoints here using the lldb console that is available now
    108   this breakpoint has been hit. To set a breakpoint, select the app tab
    109   (if running Dual, there will also be an ``<app> java`` tab) from the
    110   debug window, and then select the ``lldb`` console tab. Type the
    111   following into the console:
    112 
    113 .. code:: text
    114 
    115   b <file>.cpp:<line number>
    116 
    117 5. Once your breakpoints have been set, click the continue execution
    118   button to move beyond the ``ElfLoader`` breakpoint and your newly set
    119   native breakpoints should be hit. Debug as usual.
    120 
    121 Attaching debuggers to content and other child processes
    122 --------------------------------------------------------
    123 
    124 Internally, GeckoView has a multi-process architecture. The main Gecko
    125 process lives in the main Android process, but content rendering and
    126 some other functions live in child processes. This balances load,
    127 ensures certain critical security properties, and allows GeckoView to
    128 recover if content processes become unresponsive or crash. However, it’s
    129 generally delicate to debug child processes because they come and go.
    130 
    131 The general approach is to make the Java code in the child process that
    132 you want to debug wait for a Java debugger at startup, and then to
    133 connect such a Java debugger manually from the Android Studio UI.
    134 
    135 `Bug 1522318 <https://bugzilla.mozilla.org/show_bug.cgi?id=1522318>`__
    136 added environment variables that makes GeckoView wait for Java debuggers
    137 to attach, making this debug process more developer-friendly. See
    138 `Configuring GeckoView for Automation <../consumer/automation.html>`__
    139 for instructions on how to set environment variables that configure
    140 GeckoView’s runtime environment.
    141 
    142 Making processes wait for a Java debugger
    143 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    144 
    145 The ``set-debug-app`` command will make Android wait for a debugger before
    146 running an app or service. e.g., to make GeckoViewExample wait, run the
    147 following:
    148 
    149 .. code:: shell
    150 
    151   adb shell am set-debug-app -w --persistent org.mozilla.geckoview_example
    152 
    153 The above command works with child processes too, e.g. to make the GPU
    154 process wait for a debugger, run:
    155 
    156 .. code:: shell
    157 
    158   adb shell am set-debug-app -w --persistent org.mozilla.geckoview_example:gpu
    159 
    160 
    161 Attaching a Java debugger to a waiting child process
    162 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    163 
    164 This is standard: follow the `Android Studio instructions <https://developer.android.com/studio/debug/index.html#attach-debugger>`_.
    165 You must attach a Java debugger, so you almost certainly want to attach
    166 a ``Dual`` debugger and you definitely can’t attach only a ``Native``
    167 debugger.
    168 
    169 Determining the correct process to attach to is a little tricky because
    170 the mapping from process ID (pid) to process name is not always clear.
    171 Gecko content child processes are suffixed ``:tab`` at this time.
    172 
    173 If you attach ``Dual`` debuggers to both the main process and a content
    174 child process, you will have four (4!) debug tabs to manage in Android
    175 Studio, which is awkward. Android Studio doesn’t appear to configure
    176 attached debuggers in the same way that it configures debuggers
    177 connecting to launched Run Configurations, so you may need to manually
    178 configure search paths – i.e., you may need to invoke the contents of
    179 your ``lldbinit`` file in the appropriate ``lldb`` console by hand,
    180 using an invocation like
    181 ``command source /absolute/path/to/topobjdir/lldbinit``.
    182 
    183 Android Studio also doesn’t appear to support targeting breakpoints from
    184 the UI (say, from clicking in a gutter) to specific debug tabs, so you
    185 may also need to set breakpoints in the appropriate ``lldb`` console by
    186 hand.
    187 
    188 Managing more debug tabs may require different approaches.
    189 
    190 Debug Native Memory Allocations
    191 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    192 
    193 Android Studio includes a `Native Memory Profiler
    194 <https://developer.android.com/studio/profile/memory-profiler#native-memory-profiler>`_
    195 which works for physical devices running Android 10 and later.  In order to
    196 track allocations correctly Gecko must be built with ``jemalloc`` disabled.
    197 Additionally, the native memory profiler appears to only work with ``aarch64``
    198 builds.  The following must therefore be present in your ``mozconfig`` file:
    199 
    200 .. code:: text
    201 
    202   ac_add_options --target=aarch64
    203   ac_add_options --disable-jemalloc
    204 
    205 The resulting profiles are symbolicated correctly in debug builds, however, you
    206 may prefer to use a release build when profiling. Unfortunately a method to
    207 symbolicate using local symbols from the development machine has not yet been
    208 found, therefore in order for the profile to be symbolicated you must prevent
    209 symbols being stripped during the build process. To do so, add the following to
    210 your ``mozconfig``:
    211 
    212 .. code:: text
    213 
    214   ac_add_options STRIP_FLAGS=--strip-debug
    215 
    216 And the following to ``mobile/android/geckoview/build.gradle``, and additionally
    217 to ``mobile/android/geckoview_example/build.gradle`` if profiling GeckoView
    218 Example, or ``app/build.gradle`` if profiling Fenix, for example.
    219 
    220 .. code:: groovy
    221 
    222    android {
    223        packagingOptions {
    224            doNotStrip "**/*.so"
    225        }
    226    }
    227 
    228 Using Android Studio on Windows
    229 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    230 
    231 You can now use :ref:`artifact builds <Understanding Artifact Builds>`
    232 mode on `MozillaBuild environment <https://wiki.mozilla.org/MozillaBuild>`_ even if you are
    233 not using WSL. If you want to debug GeckoView using Android Studio on
    234 Windows, you have to set an additional environment variable via the
    235 Control Panel to run the gradle script. The ``mach`` command sets these
    236 variables automatically, but Android Studio cannot.
    237 
    238 If you install MozillaBuild tools to ``C:\mozilla-build`` (default
    239 installation path), you have to set the ``MOZILLABUILD`` environment
    240 variable to recognize MozillaBuild installation path.
    241 
    242 To set environment variable on Windows 10, open the ``Control Panel``
    243 from ``Windows System``, then select ``System and Security`` -
    244 ``System`` - ``Advanced system settings`` -
    245 ``Environment Variables ...``.
    246 
    247 To set the ``MOZILLABUILD`` variable, click ``New...`` in
    248 ``User variables for``, then ``Variable name:`` is ``MOZILLABUILD`` and
    249 ``Variable value:`` is ``C:\mozilla-build``.
    250 
    251 You also have to append some tool paths to the ``Path`` environment
    252 variable.
    253 
    254 To append the variables to PATH, double click ``Path`` in
    255 ``User Variables for``, then click ``New``. And append the following
    256 variables to ``Path``.
    257 
    258 -  ``%MOZILLABUILD%\msys\bin``
    259 -  ``%MOZILLABUILD%\bin``