Robert Sesek | 92b004c | 2021-04-08 20:12:34 | [diff] [blame] | 1 | # Debugging Chromium on macOS |
| 2 | |
| 3 | [TOC] |
| 4 | |
Robert Sesek | 3b731b1 | 2021-04-14 21:54:03 | [diff] [blame] | 5 | ## Debug vs. Release Builds |
Robert Sesek | 92b004c | 2021-04-08 20:12:34 | [diff] [blame] | 6 | |
Robert Sesek | 3b731b1 | 2021-04-14 21:54:03 | [diff] [blame] | 7 | Debug builds are thedefault configurationforChromiumand can be explicitly |
| 8 | specifiedwith`is_debug=true`in the`args.gn` file of theout directory.Debug |
| 9 | builds are largerand non-portable because theydefault to |
| 10 | `is_component_build=true`, but they contain full debug information. |
Robert Sesek | 92b004c | 2021-04-08 20:12:34 | [diff] [blame] | 11 | |
Robert Sesek | 3b731b1 | 2021-04-14 21:54:03 | [diff] [blame] | 12 | If youset`is_debug=false`, a release build will be createdwithno symbol |
| 13 | information, which cannot be usedfor effective debugging. |
Robert Sesek | 92b004c | 2021-04-08 20:12:34 | [diff] [blame] | 14 | |
Robert Sesek | 3b731b1 | 2021-04-14 21:54:03 | [diff] [blame] | 15 | A middle-groundis toset`symbol_level=1`, which will produce a minimal symbol |
| 16 | table, capable of creating backtraces, but without frame-levellocal variables. |
| 17 | Thisis faster to build than a debug build, but itis less usefulfor debugging. |
Robert Sesek | 92b004c | 2021-04-08 20:12:34 | [diff] [blame] | 18 | |
Robert Sesek | 3b731b1 | 2021-04-14 21:54:03 | [diff] [blame] | 19 | When doing an`is_official_build=true` build(whichis meantfor producing |
| 20 | buildswith full compiler optimization suitablefor shipping to users), |
| 21 | `enable_dsyms`and`enable_stripping` bothgetset to`true`.The binary itself |
| 22 | will be stripped of its symbols, but the debug information will be saved off |
| 23 | into a dSYM file.Producing a dSYMis rather slow, so itis uncommonfor |
| 24 | developers to buildwiththis configuration. |
Robert Sesek | 92b004c | 2021-04-08 20:12:34 | [diff] [blame] | 25 | |
Robert Sesek | 3b731b1 | 2021-04-14 21:54:03 | [diff] [blame] | 26 | ### Chrome Builds |
Robert Sesek | 92b004c | 2021-04-08 20:12:34 | [diff] [blame] | 27 | |
Robert Sesek | 3b731b1 | 2021-04-14 21:54:03 | [diff] [blame] | 28 | The officialGoogleChrome build has published dSYMs that can be downloadedwith |
| 29 | the script at`tools/mac/download_symbols.py`orbyusing the LLDB integration |
| 30 | at`tools/lldb/lldb_chrome_symbols.py`. |
Robert Sesek | 92b004c | 2021-04-08 20:12:34 | [diff] [blame] | 31 | |
Robert Sesek | 3b731b1 | 2021-04-14 21:54:03 | [diff] [blame] | 32 | However, the officialChrome buildis |
| 33 | [codesigned](../../chrome/installer/mac/signing/README.md)with the`restrict` |
| 34 | and`runtime` options, which generally prohibit debuggersfrom attaching. |
Robert Sesek | 92b004c | 2021-04-08 20:12:34 | [diff] [blame] | 35 | |
Robert Liao | 45bc053 | 2025-06-03 00:35:36 | [diff] [blame] | 36 | In order to debug production/releasedChrome, you need todo one of two things |
| 37 | whileChromeisnot running: |
Robert Sesek | 92b004c | 2021-04-08 20:12:34 | [diff] [blame] | 38 | |
Robert Sesek | 3b731b1 | 2021-04-14 21:54:03 | [diff] [blame] | 39 | 1.Disable[SystemIntegrity |
| 40 | Protection](https://developer.apple.com/documentation/security/disabling_and_enabling_system_integrity_protection), |
| 41 | by: |
| 42 | 1.Rebootinginto macOS recovery mode |
| 43 | 2.LaunchingTerminal |
| 44 | 3.Running`csrutil enable --without debug` |
| 45 | 4.Rebooting |
| 46 | 2.Strippingor force-re-codesigning the binary tonotuse those options: |
Robert Liao | 45bc053 | 2025-06-03 00:35:36 | [diff] [blame] | 47 | `codesign --sign=- --deep --force path/to/Google\ Chrome.app` |
Robert Sesek | 92b004c | 2021-04-08 20:12:34 | [diff] [blame] | 48 | |
Robert Sesek | 3b731b1 | 2021-04-14 21:54:03 | [diff] [blame] | 49 | If you will frequently debug official builds,(1)is recommended.Note that |
| 50 | disabling SIP reduces the overall security of the system, so your system |
| 51 | administrator may frown upon it. |
Robert Sesek | 92b004c | 2021-04-08 20:12:34 | [diff] [blame] | 52 | |
Robert Sesek | 3b731b1 | 2021-04-14 21:54:03 | [diff] [blame] | 53 | ## The Debugger |
Robert Sesek | 92b004c | 2021-04-08 20:12:34 | [diff] [blame] | 54 | |
Robert Sesek | 3b731b1 | 2021-04-14 21:54:03 | [diff] [blame] | 55 | Thedebugger on macOSis`lldb`and itis includedin both a fullXcode install |
| 56 | and theCommandLineToolspackage.There are two ways touse LLDB: either |
| 57 | launchingChromium directlyin LLDB,or attaching to an existing process: |
Robert Sesek | 92b004c | 2021-04-08 20:12:34 | [diff] [blame] | 58 | |
Robert Sesek | 3b731b1 | 2021-04-14 21:54:03 | [diff] [blame] | 59 | lldb./out/debug/Chromium.app/Contents/MacOS/Chromium |
| 60 | lldb-p<pid> |
Robert Sesek | 92b004c | 2021-04-08 20:12:34 | [diff] [blame] | 61 | |
Robert Sesek | 3b731b1 | 2021-04-14 21:54:03 | [diff] [blame] | 62 | LLDB has an extensive help system which you can accessby typing`help` at the |
| 63 | `(lldb)` command prompt.The commands are organizedinto a functional hierarchy, |
| 64 | and you can explore the subcommands via`(lldb) help breakpoint`, etc.Commands |
| 65 | can take argumentsin a command-line flag style.Many commands also haveshort |
| 66 | mnemonics that match the`gdb` equivalents.You can also justuse enough letters |
| 67 | to form a unique prefix of the command hierarchy. E.g., these are equivalent: |
Robert Sesek | 92b004c | 2021-04-08 20:12:34 | [diff] [blame] | 68 | |
Robert Sesek | 3b731b1 | 2021-04-14 21:54:03 | [diff] [blame] | 69 | (lldb) help breakpointset |
| 70 | (lldb) h br s |
Robert Sesek | 92b004c | 2021-04-08 20:12:34 | [diff] [blame] | 71 | |
Robert Sesek | 3b731b1 | 2021-04-14 21:54:03 | [diff] [blame] | 72 | When the programis running, you canuse**Ctrl-C** to interrupt itand pause |
| 73 | thedebugger. |
Robert Sesek | 92b004c | 2021-04-08 20:12:34 | [diff] [blame] | 74 | |
Robert Sesek | 3b731b1 | 2021-04-14 21:54:03 | [diff] [blame] | 75 | ### Passing Arguments |
Robert Sesek | 92b004c | 2021-04-08 20:12:34 | [diff] [blame] | 76 | |
Robert Sesek | 3b731b1 | 2021-04-14 21:54:03 | [diff] [blame] | 77 | Topass arguments to LLDBwhen startingChromium,use a`--`: |
Robert Sesek | 92b004c | 2021-04-08 20:12:34 | [diff] [blame] | 78 | |
Robert Sesek | 3b731b1 | 2021-04-14 21:54:03 | [diff] [blame] | 79 | lldb./out/debug/Chromium.app/contents/MacOS/Chromium----renderer-startup-dialog |
Robert Sesek | 92b004c | 2021-04-08 20:12:34 | [diff] [blame] | 80 | |
Robert Sesek | 3b731b1 | 2021-04-14 21:54:03 | [diff] [blame] | 81 | ### Breakpoints |
Robert Sesek | 92b004c | 2021-04-08 20:12:34 | [diff] [blame] | 82 | |
Robert Sesek | 3b731b1 | 2021-04-14 21:54:03 | [diff] [blame] | 83 | Simplefunction-name breakpoints can be specifiedwith ashort mnemonic: |
Robert Sesek | 92b004c | 2021-04-08 20:12:34 | [diff] [blame] | 84 | |
Robert Sesek | 3b731b1 | 2021-04-14 21:54:03 | [diff] [blame] | 85 | (lldb) bBrowserWindow::Close |
Robert Sesek | 92b004c | 2021-04-08 20:12:34 | [diff] [blame] | 86 | |
Robert Sesek | 3b731b1 | 2021-04-14 21:54:03 | [diff] [blame] | 87 | But there are a range of other optionsfor setting breakpointsusing the, such |
| 88 | as: |
| 89 | *`-t` to limit the breakpoint to a specific thread |
| 90 | *`-s` to specify a specific shared library,if the same symbol nameis exported |
| 91 | by multiple libraries |
| 92 | *`-o`for a one-shot breakpoint(delete after first hit) |
Robert Sesek | 92b004c | 2021-04-08 20:12:34 | [diff] [blame] | 93 | |
Robert Sesek | 3b731b1 | 2021-04-14 21:54:03 | [diff] [blame] | 94 | See`(lldb) help br set`for full details. |
Robert Sesek | 92b004c | 2021-04-08 20:12:34 | [diff] [blame] | 95 | |
Robert Sesek | 3b731b1 | 2021-04-14 21:54:03 | [diff] [blame] | 96 | ### Navigating the Stack |
Robert Sesek | 92b004c | 2021-04-08 20:12:34 | [diff] [blame] | 97 | |
Robert Sesek | 3b731b1 | 2021-04-14 21:54:03 | [diff] [blame] | 98 | When thedebuggeris paused, you canget a backtraceby typing`bt`.To navigate |
| 99 | the stackby-1 type either`up`or`down`.You can also jump to a specific index |
| 100 | in the stackby typing`f #`(shortfor`frame select #`). |
| 101 | |
| 102 | To seelocal variables, type`v`(shortfor`frame variable`). |
| 103 | |
| 104 | ### Examining Execution |
| 105 | |
| 106 | To step through the program,use: |
| 107 | |
| 108 | *`s`or`si`for step-in |
| 109 | *`n`for step-over |
| 110 | *`c` tocontinue(resumeor go tonext breakpoint) |
| 111 | |
| 112 | ### Printing Values |
| 113 | |
| 114 | Toprint values,use the`p <value>` command,where`<value>` can be a variable, |
| 115 | a variable expression like`object->member_->sub_member_.value`,or an address. |
| 116 | |
| 117 | If`<value>`is a pointer to a structure,`p <value>` will usually justprint |
| 118 | the address.To show the contents of the structure, dereference the value. E.g.: |
| 119 | |
| 120 | (lldb) p item |
| 121 | (HistoryMenuBridge::HistoryItem*) $3=0x0000000245ef5b30 |
| 122 | (lldb) p*item |
| 123 | (HistoryMenuBridge::HistoryItem) $4={ |
| 124 | title= u"Google" |
| 125 | url={ |
| 126 | spec_="https://www.google.com/" |
| 127 | is_valid_=true |
| 128 | … |
| 129 | |
| 130 | Note above that LLDB has also stored the results of the expressions passed to |
| 131 | `p`into the variables`$3`and`$4`, which can be referencedin other LLDB |
| 132 | expressions. |
| 133 | |
| 134 | Often(and alwayswhen printing addresses) thereisnot type information to |
| 135 | enable printing the full structure of the referenced memory.In these cases,use |
| 136 | a C-style cast: |
| 137 | |
| 138 | (lldb) p0x0000000245ef5b30# Does not have type information |
| 139 | (long) $5=9763248944 |
| 140 | (lldb) p(HistoryMenuBridge::HistoryItem*)0x0000000245ef5b30 |
| 141 | (HistoryMenuBridge::HistoryItem*) $6=0x0000000245ef5b30 |
| 142 | (lldb) p*$6 |
| 143 | (HistoryMenuBridge::HistoryItem) $7={ |
| 144 | title= u"Google" |
| 145 | … |
| 146 | |
| 147 | *For printingCocoaNSObjects,use the`po` command toget the`-[NSObject description]`. |
| 148 | *If`uptr`is a`std::unique_ptr`, the address it wrapsis accessibleas |
| 149 | `uptr.__ptr_.__value_`. |
| 150 | *To pretty-print`std::u16string`, follow the instructions[here](../lldbinit.md). |
| 151 | |
| 152 | ## Multi-Process Debugging |
| 153 | |
| 154 | Chromeis splitinto multiple processes, which can mean that the logic you want |
| 155 | to debugisin a different process than the main browser/GUI process.There are |
| 156 | a few ways to debug the multi-process architecture, discussed below. |
| 157 | |
| 158 | ### (a) Attach to a Running Process |
| 159 | |
| 160 | You canuseChrome's Task Manager to associate specific sites with their PID. |
| 161 | Then simply attach with LLDB: |
| 162 | |
| 163 | lldb -p <pid> |
| 164 | |
| 165 | Or, if you have already been debugging a Chrome process and want to retain your |
| 166 | breakpoints: |
| 167 | |
| 168 | (lldb) attach <pid> |
| 169 | |
| 170 | ### (b) Debug Process Startup |
| 171 | |
| 172 | If you need to attach early in the child process's lifetime, you canuse one of |
| 173 | these startup-dialog switchesfor the relevant process type: |
| 174 | |
| 175 | *`--renderer-startup-dialog` |
| 176 | *`--utility-startup-dialog` |
Alex Gough | 2092674 | 2021-05-13 20:11:30 | [diff] [blame] | 177 | *`--utility-startup-dialog=data_decoder.mojom.DataDecoderService` |
Robert Sesek | 3b731b1 | 2021-04-14 21:54:03 | [diff] [blame] | 178 | |
| 179 | After the process launches, it willprint a message likethis to standard error: |
| 180 | |
| 181 | [80156:775:0414/130021.862239:ERROR:content_switches_internal.cc(112)]Renderer(80156) paused waitingfordebugger to attach.Send SIGUSR1 to unpause. |
| 182 | |
| 183 | Then attach the the process like abovein**(a)**,using the PIDin parenthesis |
| 184 | (e.g.*80156* above). |
| 185 | |
| 186 | ### (c) Run Chrome in a single process |
| 187 | |
| 188 | >This optionisnot recommended.Single-process modeisnot testedandis |
| 189 | > frequently broken. |
| 190 | |
| 191 | Chrome has an option to run all child processesas threads inside a single |
| 192 | process,using the`--single-process` command line flag.This can make debugging |
| 193 | easier. |
| 194 | |
| 195 | ## Debugging Out-of-Process Tests: |
| 196 | |
| 197 | Similar to debugging the renderer process, simply attaching LLDB to a |
Robert Sesek | 92b004c | 2021-04-08 20:12:34 | [diff] [blame] | 198 | out-of-process test like browser\_tests willnot hit the test code.In order to |
| 199 | debug a browser test, you need to run the test binarywith "`--single_process`" |
| 200 | (note the underscorein `single_process`).Because you can only run one browser |
| 201 | testin the same process, you're probably going to need to add `--gtest_filter` |
| 202 | as well. So your command will look like this: |
| 203 | |
Robert Sesek | 3b731b1 | 2021-04-14 21:54:03 | [diff] [blame] | 204 | /path/to/src/out/debug/browser_tests --single_process --gtest_filter=GoatTeleporterTest.DontTeleportSheep |
Robert Sesek | 92b004c | 2021-04-08 20:12:34 | [diff] [blame] | 205 | |
Robert Sesek | 3b731b1 | 2021-04-14 21:54:03 | [diff] [blame] | 206 | ## Working with Xcode |
Robert Sesek | 92b004c | 2021-04-08 20:12:34 | [diff] [blame] | 207 | |
Robert Sesek | 3b731b1 | 2021-04-14 21:54:03 | [diff] [blame] | 208 | If you'd prefer touseXcode GUI touse thedebugger, there are two options: |
Robert Sesek | 92b004c | 2021-04-08 20:12:34 | [diff] [blame] | 209 | |
Robert Sesek | 3b731b1 | 2021-04-14 21:54:03 | [diff] [blame] | 210 | ### (1) Empty Xcode Project |
Robert Sesek | 92b004c | 2021-04-08 20:12:34 | [diff] [blame] | 211 | |
Robert Sesek | 3b731b1 | 2021-04-14 21:54:03 | [diff] [blame] | 212 | This approach creates an emptyXcode project that only provides a GUIdebugger: |
Robert Sesek | 92b004c | 2021-04-08 20:12:34 | [diff] [blame] | 213 | |
Robert Sesek | 3b731b1 | 2021-04-14 21:54:03 | [diff] [blame] | 214 | 1.Select**File**>**New**>**Project...**and make anew project.Dump it |
| 215 | anywhere, call it anything.It doesn't matter. |
| 216 | 2. Launch Chromium. |
| 217 | 3. In Xcode, select **Debug** > **Attach to Process** > *Chromium*. |
| 218 | 4. You can now pause the process and set breakpoints. The debugger will also |
| 219 | activate if a crash occurs. |
Robert Sesek | 92b004c | 2021-04-08 20:12:34 | [diff] [blame] | 220 | |
Robert Sesek | 3b731b1 | 2021-04-14 21:54:03 | [diff] [blame] | 221 | ### (2) Use *gn* |
Robert Sesek | 92b004c | 2021-04-08 20:12:34 | [diff] [blame] | 222 | |
Robert Sesek | 3b731b1 | 2021-04-14 21:54:03 | [diff] [blame] | 223 | 1. Tell `gn` to generate an Xcode project for your out directory: |
Fumitoshi Ukai | a9d3d3a | 2025-05-07 08:51:50 | [diff] [blame] | 224 | `gn gen --ide=xcode out/debug --ninja-executable=autoninja` |
Robert Sesek | 3b731b1 | 2021-04-14 21:54:03 | [diff] [blame] | 225 | 2. Open *out/debug/all.xcodeproj* |
| 226 | 3. Have it automatically generate schemes for you |
| 227 | 4. You can now build targets from within Xcode, which will simply call out to |
Fumitoshi Ukai | a9d3d3a | 2025-05-07 08:51:50 | [diff] [blame] | 228 | `autoninja` via an Xcode script. But the resulting binaries are available as |
Robert Sesek | 3b731b1 | 2021-04-14 21:54:03 | [diff] [blame] | 229 | debuggable targets in Xcode. |
Robert Sesek | 92b004c | 2021-04-08 20:12:34 | [diff] [blame] | 230 | |
Robert Sesek | 3b731b1 | 2021-04-14 21:54:03 | [diff] [blame] | 231 | Note that any changes to the .xcodeproj will be overwritten; all changes to the |
| 232 | build system need to be done in GN. |
Robert Sesek | 92b004c | 2021-04-08 20:12:34 | [diff] [blame] | 233 | |
Robert Sesek | 3b731b1 | 2021-04-14 21:54:03 | [diff] [blame] | 234 | ## Debugging the Sandbox |
Robert Sesek | 92b004c | 2021-04-08 20:12:34 | [diff] [blame] | 235 | |
Robert Sesek | 3b731b1 | 2021-04-14 21:54:03 | [diff] [blame] | 236 | See the page on [sandbox debugging](sandbox_debugging.md). |
Robert Sesek | 92b004c | 2021-04-08 20:12:34 | [diff] [blame] | 237 | |
Robert Sesek | 3b731b1 | 2021-04-14 21:54:03 | [diff] [blame] | 238 | ## System Permission Prompts; Transparency, Consent, and Control (TCC) |
Robert Sesek | 92b004c | 2021-04-08 20:12:34 | [diff] [blame] | 239 | |
Robert Sesek | 3b731b1 | 2021-04-14 21:54:03 | [diff] [blame] | 240 | When debugging issues with OS-mediated permissions (e.g. Location, Camera, |
| 241 | etc.), you need to launch Chromium with LaunchServices rather than through a |
| 242 | shell. If you launch Chromium as a subprocess of your terminal shell, the |
| 243 | permission requests get attributed to the terminal app rather than Chromium. |
Robert Sesek | 92b004c | 2021-04-08 20:12:34 | [diff] [blame] | 244 | |
Robert Sesek | 3b731b1 | 2021-04-14 21:54:03 | [diff] [blame] | 245 | To launch Chromium via launch services, use the `open(1)` command: |
Robert Sesek | 92b004c | 2021-04-08 20:12:34 | [diff] [blame] | 246 | |
Robert Sesek | 3b731b1 | 2021-04-14 21:54:03 | [diff] [blame] | 247 | open ./out/debug/Chromium.app |
Robert Sesek | 92b004c | 2021-04-08 20:12:34 | [diff] [blame] | 248 | |
Robert Sesek | 3b731b1 | 2021-04-14 21:54:03 | [diff] [blame] | 249 | To pass command line arguments: |
Robert Sesek | 92b004c | 2021-04-08 20:12:34 | [diff] [blame] | 250 | |
Robert Sesek | 3b731b1 | 2021-04-14 21:54:03 | [diff] [blame] | 251 | open ./out/debug/Chromium.app -- --enable-features=MyCoolFeature |
Robert Sesek | 92b004c | 2021-04-08 20:12:34 | [diff] [blame] | 252 | |
| 253 | ## Taking CPU Samples |
| 254 | |
| 255 | A quick and easy way to investigate slow or hung processes is to use the sample |
| 256 | facility, which will generate a CPU sample trace. This can be done either in the |
| 257 | Terminal with the sample(1) command or by using Activity Monitor: |
| 258 | |
Robert Sesek | 3b731b1 | 2021-04-14 21:54:03 | [diff] [blame] | 259 | 1. Open Activity Monitor |
| 260 | 2. Find the process you want to sample (for "Helper" processes, you may want to |
| 261 | consult the Chrome Task Manager) |
| 262 | 3. Double-click on the row |
| 263 | 4. Click the **Sample** button in the process's information window |
Robert Sesek | 92b004c | 2021-04-08 20:12:34 | [diff] [blame] | 264 | |
| 265 | After a few seconds, the sample will be completed.For officialGoogleChrome |
| 266 | builds, the sample should be symbolizedusing |
| 267 | [crsym](https://goto.google.com/crsym/). If you do not have access to crsym, |
| 268 | save the*entire* contentsas a fileand attach it to a bug reportfor later |
| 269 | analysis. |
| 270 | |
| 271 | See also [How toObtain aHeap |
| 272 | Dump](../memory-infra/heap_profiler.md#how-to-obtain-a-heap-dump-m66_linux_macos_windows). |
Robert Sesek | 3b731b1 | 2021-04-14 21:54:03 | [diff] [blame] | 273 | |
Keren Zhu | f3ba98be6a | 2021-09-29 17:09:31 | [diff] [blame] | 274 | ## Profiling using Instruments Time Profiler |
| 275 | |
| 276 | For more sophisticated CPU sampling,use theTimeProfiler toolfromInstruments.Instrumentsis macOS's performance analysis toolkit that comes with Xcode. The following steps assume that you've installedXcode12.0or later. |
| 277 | |
| 278 | After installingXcode, run`xcode-select -s XCODE_FOLDER`from the command line toset up theXcode folderfor the command line tools.`XCODE_FOLDER`iswhere theXcodeis installed,and should be something like`/Applications/Xcode.app/Contents/Developer`. |
| 279 | |
| 280 | TimeProfiler provides a GUI to record traces, butis likely to be janky.To generate a tracefrom the terminal, |
| 281 | |
| 282 | 1.StartChrome. |
| 283 | 2.Run`xcrun xctrace record --template 'Time Profiler' --all-processes`in terminal to start tracing. |
| 284 | 3.Perform actions that you want to profile, e.g. open anew tab page. |
| 285 | 4.Back to the terminal, pressCtrl+C to terminate the profiling. A`.trace` profile file will be generated at the current working path. |
| 286 | |
| 287 | InStep2,if you know which process you are looking at, you can change the`--all-processes` to`--attach PID`. |
| 288 | |
| 289 | To visualize a trace, |
| 290 | |
| 291 | 1.InTimeProfiler, load the profile filebyFile>Open.You will see the traces of all threadsand other stats like theThermalState.You may filter the threads of your interest. |
| 292 | 2.For officialGoogleChrome builds, you need to follow[this doc](https://chromium.googlesource.com/chromium/src/+/refs/heads/main/docs/mac/debugging.md#chrome-builds) to download the dSYMs files for symbolization. |
| 293 | 3.InTimeProfiler,useFile>Symbols to load symbols.Loading symbols onlyfor the main executable(GoogleChrome) should be sufficientfor other executables(GoogleChromeHelperandRenderer)as well. |
| 294 | |
Robert Sesek | 3b731b1 | 2021-04-14 21:54:03 | [diff] [blame] | 295 | ## Working with Minidumps |
| 296 | |
| 297 | [Seethis |
| 298 | page.](https://sites.google.com/a/chromium.org/dev/developers/crash-reports) |
| 299 | |
| 300 | ## Disabling ReportCrash |
| 301 | |
| 302 | macOS helpfully tries to write a crash report every time a binary crashes– |
| 303 | which happensfor examplewhen a testin unit\_tests fails.SinceChromium's |
| 304 | debug binaries are huge, this takes forever. If this happens, "ReportCrash" will |
| 305 | be the top cpu consuming process in Activity Monitor. You should disable |
| 306 | ReportCrash while you work on Chromium. Run `man ReportCrash` to learn how to do |
| 307 | this on your version of macOS. On 10.15, the command is |
| 308 | |
| 309 | launchctl unload -w /System/Library/LaunchAgents/com.apple.ReportCrash.plist |
| 310 | sudo launchctl unload -w /System/Library/LaunchDaemons/com.apple.ReportCrash.Root.plist |
| 311 | |
| 312 | Yes, you need to run this for both the normal user and the admin user. |
| 313 | |
| 314 | ## Processing Apple Crash Reports |
| 315 | |
| 316 | If you get a Google Chrome crash report caught by ReportCrash/macOS, it will not |
| 317 | have symbols (every frame will be ChromeMain). To get a symbolized stack trace, |
| 318 | use the internal [crsym](httsp://goto.google.com/crsym) tool by simply pasting |
| 319 | the contents of an entire Apple crash report. |
| 320 | |
| 321 | ## Testing Other Locales |
| 322 | |
| 323 | To test Chrome in a different locale, change your system locale via the System |
| 324 | Preferences. (Keep the preferences window open so that you can change the |
| 325 | locale back without needing to navigate through menus in a language you may not |
| 326 | know.) |
| 327 | |
| 328 | ## Using DTrace |
| 329 | |
| 330 | DTrace is a powerful, kernel-level profiling and dynamic tracing utility. In |
| 331 | order to use DTrace, you need to (at least partially) disable System Integrity |
| 332 | Protection with ([see above](#Chrome-Builds)): |
| 333 | |
| 334 | csrutil enable --without dtrace |
| 335 | |
| 336 | Using DTrace is beyond the scope of this document, but the following resources |
| 337 | are useful: |
| 338 | |
| 339 | * [jgm's awesome introductory article](http://www.mactech.com/articles/mactech/Vol.23/23.11/ExploringLeopardwithDTrace/index.html) |
| 340 | *[BigNerdRanch's four-part series](https://www.bignerdranch.com/blog/hooked-on-dtrace-part-1/) |
| 341 | * [Defining static probes on macOS](http://www.macresearch.org/tuning-cocoa-applications-using-dtrace-custom-static-probes-and-instruments) |
| 342 | * [Examples](http://www.brendangregg.com/dtrace.html#Examples) |
| 343 | * [Tips from Sun](http://blogs.sun.com/bmc/resource/dtrace_tips.pdf) |
| 344 | |
| 345 | DTrace examples on macOS: `/usr/share/examples/DTTk` |
| 346 | |
| 347 | To get truss on macOS, use dtruss. That requires root, so use `sudo dtruss -p` |
| 348 | and to attach to a running non-root program. |
| 349 | |
| 350 | ## Memory/Heap Inspection |
| 351 | |
| 352 | Chrome has [built-in memory instrumentation](../memory-infra/README.md) that can |
| 353 | be used to identify allocations and potential leaks. |
| 354 | |
| 355 | MacOS also provides several low-level command-line tools that can be used to |
Sunny Sachanandani | b7a2bf4 | 2024-06-03 13:28:46 | [diff] [blame] | 356 | inspect what's going onwith memory inside a process.Note that most of these |
| 357 | tools only work effectivelywith system mallocandnotPartitionAlloc.Since |
| 358 | [PartitionAllocEverywhere](https://docs.google.com/document/d/1R1H9z5IVUAnXJgDjnts3nTJVcRbufWWT9ByXLgecSUM/preview), |
| 359 | you should additionally disablePartitionAllocwith these GN args: |
Robert Sesek | 3b731b1 | 2021-04-14 21:54:03 | [diff] [blame] | 360 | |
Sunny Sachanandani | b7a2bf4 | 2024-06-03 13:28:46 | [diff] [blame] | 361 | ``` |
| 362 | use_partition_alloc_as_malloc = false |
| 363 | enable_backup_ref_ptr_support = false |
| 364 | ``` |
| 365 | |
| 366 | Note thatPartitionAlloc will still be usedinBlink, justnotfor`malloc`in |
| 367 | other places anymore.See[PartitionAlloc build config](../../base/allocator/partition_allocator/build_config.md) |
| 368 | for disablingPartitionAlloc completely via GN arg`use_partition_alloc`. |
| 369 | |
| 370 | **`heap`** summarizes what's currently in the malloc heap(s) of a process. It |
Robert Sesek | 3b731b1 | 2021-04-14 21:54:03 | [diff] [blame] | 371 | shows a number of useful things: |
| 372 | |
| 373 | * How much of the heap is used or free |
| 374 | * The distribution of block sizes |
| 375 | * A listing of every C++, Objective-C and CoreFoundation class found in the |
| 376 | heap, with the number of instances, total size and average size. |
| 377 | |
| 378 | It identifies C++ objects by their vtables, so it can't identify vtable-less |
| 379 | classes, including a lot of the lower-levelWebCore ones likeStringImpl.To |
| 380 | work around, temporarily added the`virtual` keyword to`WTF::RefCounted`'s |
| 381 | destructor method, which forces every ref-counted object to include a vtable |
| 382 | pointer identifying its class. |
| 383 | |
| 384 | **`malloc_history`** identifies the stack backtrace that allocated every malloc |
| 385 | block in the heap. It lists every unique backtrace together with its number of |
| 386 | blocks and their total size. It requires that the process use malloc stack |
| 387 | logging, which is enabled if the environment variable MallocStackLogging is set |
| 388 | when it launches. The `env` command is handy for this: |
| 389 | |
| 390 | $ env MallocStackLogging=1 Chromium.app/Contents/MacOS/Chromium |
| 391 | |
| 392 | Then in another shell you run |
| 393 | |
Sunny Sachanandani | b7a2bf4 | 2024-06-03 13:28:46 | [diff] [blame] | 394 | $ malloc_history <pid> -allBySize |
Robert Sesek | 3b731b1 | 2021-04-14 21:54:03 | [diff] [blame] | 395 | |
| 396 | Watch out: the output is *big*. |
| 397 | |
| 398 | **`leaks`** finds malloc blocks that have no pointers to them and are probably |
| 399 | leaked. It doesn'trequireMallocStackLogging, but it's more useful if it's on |
| 400 | because it canthen show the backtrace that allocated each leaked block. |
| 401 | |
| 402 | **`vmmap`** shows all thevirtual-memory regionsin the process's address space. |
| 403 | This is less useful since it doesn't say anything about individual malloc blocks |
| 404 | (except huge ones) but it can be usefulfor looking at things likestatic data |
| 405 | size, mapped files,and how much memoryis pagedout.The"-resident" flag shows |
| 406 | how much of each allocationis currently pagedinto RAM.See the man pagefor |
| 407 | details. |
| 408 | |
| 409 | Notes: |
| 410 | |
| 411 | *These arenot going to be very useful on stripped binaries,and they're less |
| 412 | useful in release builds. |
| 413 | * All of these except vmmap take several *minutes* to run, apparently because |
| 414 | of the number of symbols in Chrome. They spend most of their time pegging |
| 415 | one CPU down inside system code that's reading symbol tablesfrom the |
| 416 | binary.Be patient. |
| 417 | *Instrumentsis an application bundledwithXcode that provides GUI interfaces |
| 418 | for many of these tools, including`sample`and`leaks`.MostChromies prefer |
| 419 | the command line tools, butInstruments can be useful.If runningInstruments |
| 420 | on alocal build, expect to wait a few minutesfor it to load symbols before |
| 421 | it starts recording useful data |
| 422 | |
| 423 | ## Resources |
| 424 | |
| 425 | The[Mac OS XDebuggingMagic |
| 426 | Technote](https://developer.apple.com/technotes/tn2004/tn2124.html) contains a |
| 427 | wealth of(mostly outdated) information about various debugging options builtin |
| 428 | to macOS. |