| 
									
										
										
										
											2016-07-28 12:54:03 -07:00
										 |  |  | # Debugging on macOS
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | If you experience crashes or issues in Electron that you believe are not caused | 
					
						
							|  |  |  | by your JavaScript application, but instead by Electron itself, debugging can | 
					
						
							|  |  |  | be a little bit tricky, especially for developers not used to native/C++ | 
					
						
							| 
									
										
										
										
											2018-05-07 08:46:14 -07:00
										 |  |  | debugging. However, using lldb, and the Electron source code, you can enable | 
					
						
							|  |  |  | step-through debugging with breakpoints inside Electron's source code. | 
					
						
							| 
									
										
										
										
											2018-03-05 23:49:19 +05:30
										 |  |  | You can also use [XCode for debugging](debugging-instructions-macos-xcode.md) if | 
					
						
							|  |  |  | you prefer a graphical interface. | 
					
						
							| 
									
										
										
										
											2016-07-28 12:54:03 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | ## Requirements
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | * **A debug build of Electron**: The easiest way is usually building it | 
					
						
							|  |  |  |   yourself, using the tools and prerequisites listed in the | 
					
						
							| 
									
										
										
										
											2018-09-28 13:16:38 +10:00
										 |  |  |   [build instructions for macOS](build-instructions-macos.md). While you can | 
					
						
							| 
									
										
										
										
											2018-05-07 08:46:14 -07:00
										 |  |  |   attach to and debug Electron as you can download it directly, you will | 
					
						
							| 
									
										
										
										
											2016-07-28 12:54:03 -07:00
										 |  |  |   find that it is heavily optimized, making debugging substantially more | 
					
						
							|  |  |  |   difficult: The debugger will not be able to show you the content of all | 
					
						
							|  |  |  |   variables and the execution path can seem strange because of inlining, | 
					
						
							|  |  |  |   tail calls, and other compiler optimizations. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | * **Xcode**: In addition to Xcode, also install the Xcode command line tools. | 
					
						
							| 
									
										
										
										
											2017-05-10 13:42:21 -07:00
										 |  |  |   They include LLDB, the default debugger in Xcode on Mac OS X. It supports | 
					
						
							|  |  |  |   debugging C, Objective-C and C++ on the desktop and iOS devices and simulator. | 
					
						
							| 
									
										
										
										
											2016-07-28 12:54:03 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-27 08:10:25 -08:00
										 |  |  | * **.lldbinit**: Create or edit `~/.lldbinit` to allow Chromium code to be properly source-mapped. | 
					
						
							|  |  |  |    ```text | 
					
						
							|  |  |  |    command script import ~/electron/src/tools/lldb/lldbinit.py | 
					
						
							|  |  |  |    ``` | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-28 12:54:03 -07:00
										 |  |  | ## Attaching to and Debugging Electron
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-07 11:51:44 -08:00
										 |  |  | To start a debugging session, open up Terminal and start `lldb`, passing a non-release | 
					
						
							| 
									
										
										
										
											2016-07-28 12:54:03 -07:00
										 |  |  | build of Electron as a parameter. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-24 11:13:57 +01:00
										 |  |  | ```sh | 
					
						
							| 
									
										
										
										
											2019-11-07 11:51:44 -08:00
										 |  |  | $ lldb ./out/Testing/Electron.app | 
					
						
							|  |  |  | (lldb) target create "./out/Testing/Electron.app" | 
					
						
							|  |  |  | Current executable set to './out/Testing/Electron.app' (x86_64). | 
					
						
							| 
									
										
										
										
											2016-07-28 12:54:03 -07:00
										 |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ### Setting Breakpoints
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | LLDB is a powerful tool and supports multiple strategies for code inspection. For | 
					
						
							|  |  |  | this basic introduction, let's assume that you're calling a command from JavaScript | 
					
						
							|  |  |  | that isn't behaving correctly - so you'd like to break on that command's C++ | 
					
						
							|  |  |  | counterpart inside the Electron source. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-24 12:49:10 +02:00
										 |  |  | Relevant code files can be found in `./atom/`. | 
					
						
							| 
									
										
										
										
											2016-07-28 12:54:03 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | Let's assume that you want to debug `app.setName()`, which is defined in `browser.cc` | 
					
						
							|  |  |  | as `Browser::SetName()`. Set the breakpoint using the `breakpoint` command, specifying | 
					
						
							|  |  |  | file and line to break on: | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-24 11:13:57 +01:00
										 |  |  | ```sh | 
					
						
							| 
									
										
										
										
											2016-07-28 12:54:03 -07:00
										 |  |  | (lldb) breakpoint set --file browser.cc --line 117 | 
					
						
							|  |  |  | Breakpoint 1: where = Electron Framework`atom::Browser::SetName(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&) + 20 at browser.cc:118, address = 0x000000000015fdb4 | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Then, start Electron: | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-24 11:13:57 +01:00
										 |  |  | ```sh | 
					
						
							| 
									
										
										
										
											2016-07-28 12:54:03 -07:00
										 |  |  | (lldb) run | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | The app will immediately be paused, since Electron sets the app's name on launch: | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-24 11:13:57 +01:00
										 |  |  | ```sh | 
					
						
							| 
									
										
										
										
											2016-07-28 12:54:03 -07:00
										 |  |  | (lldb) run | 
					
						
							| 
									
										
										
										
											2019-11-07 11:51:44 -08:00
										 |  |  | Process 25244 launched: '/Users/fr/Code/electron/out/Testing/Electron.app/Contents/MacOS/Electron' (x86_64) | 
					
						
							| 
									
										
										
										
											2016-07-28 12:54:03 -07:00
										 |  |  | Process 25244 stopped | 
					
						
							|  |  |  | * thread #1: tid = 0x839a4c, 0x0000000100162db4 Electron Framework`atom::Browser::SetName(this=0x0000000108b14f20, name="Electron") + 20 at browser.cc:118, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1 | 
					
						
							|  |  |  |     frame #0: 0x0000000100162db4 Electron Framework`atom::Browser::SetName(this=0x0000000108b14f20, name="Electron") + 20 at browser.cc:118 | 
					
						
							|  |  |  |    115 	} | 
					
						
							|  |  |  |    116 | 
					
						
							|  |  |  |    117 	void Browser::SetName(const std::string& name) { | 
					
						
							|  |  |  | -> 118 	  name_override_ = name; | 
					
						
							|  |  |  |    119 	} | 
					
						
							|  |  |  |    120 | 
					
						
							|  |  |  |    121 	int Browser::GetBadgeCount() { | 
					
						
							|  |  |  | (lldb) | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | To show the arguments and local variables for the current frame, run `frame variable` (or `fr v`), | 
					
						
							| 
									
										
										
										
											2017-05-10 13:42:21 -07:00
										 |  |  | which will show you that the app is currently setting the name to "Electron". | 
					
						
							| 
									
										
										
										
											2016-07-28 12:54:03 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-24 11:13:57 +01:00
										 |  |  | ```sh | 
					
						
							| 
									
										
										
										
											2016-07-28 12:54:03 -07:00
										 |  |  | (lldb) frame variable | 
					
						
							|  |  |  | (atom::Browser *) this = 0x0000000108b14f20 | 
					
						
							|  |  |  | (const string &) name = "Electron": { | 
					
						
							|  |  |  |     [...] | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | To do a source level single step in the currently selected thread, execute `step` (or `s`). | 
					
						
							| 
									
										
										
										
											2017-07-17 12:12:44 -07:00
										 |  |  | This would take you into `name_override_.empty()`. To proceed and do a step over, | 
					
						
							| 
									
										
										
										
											2016-07-28 12:54:03 -07:00
										 |  |  | run `next` (or `n`). | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-24 11:13:57 +01:00
										 |  |  | ```sh | 
					
						
							| 
									
										
										
										
											2016-07-28 12:54:03 -07:00
										 |  |  | (lldb) step | 
					
						
							|  |  |  | Process 25244 stopped | 
					
						
							|  |  |  | * thread #1: tid = 0x839a4c, 0x0000000100162dcc Electron Framework`atom::Browser::SetName(this=0x0000000108b14f20, name="Electron") + 44 at browser.cc:119, queue = 'com.apple.main-thread', stop reason = step in | 
					
						
							|  |  |  |     frame #0: 0x0000000100162dcc Electron Framework`atom::Browser::SetName(this=0x0000000108b14f20, name="Electron") + 44 at browser.cc:119 | 
					
						
							|  |  |  |    116 | 
					
						
							|  |  |  |    117 	void Browser::SetName(const std::string& name) { | 
					
						
							|  |  |  |    118 	  name_override_ = name; | 
					
						
							|  |  |  | -> 119 	} | 
					
						
							|  |  |  |    120 | 
					
						
							|  |  |  |    121 	int Browser::GetBadgeCount() { | 
					
						
							|  |  |  |    122 	  return badge_count_; | 
					
						
							|  |  |  | ``` | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-27 08:10:25 -08:00
										 |  |  | **NOTE:** If you don't see source code when you think you should, you may not have added the `~/.lldbinit` file above. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-28 12:54:03 -07:00
										 |  |  | To finish debugging at this point, run `process continue`. You can also continue until a certain | 
					
						
							|  |  |  | line is hit in this thread (`thread until 100`). This command will run the thread in the current | 
					
						
							|  |  |  | frame till it reaches line 100 in this frame or stops if it leaves the current frame. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Now, if you open up Electron's developer tools and call `setName`, you will once again hit the | 
					
						
							|  |  |  | breakpoint. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ### Further Reading
 | 
					
						
							|  |  |  | LLDB is a powerful tool with a great documentation. To learn more about it, consider | 
					
						
							|  |  |  | Apple's debugging documentation, for instance the [LLDB Command Structure Reference][lldb-command-structure] | 
					
						
							|  |  |  | or the introduction to [Using LLDB as a Standalone Debugger][lldb-standalone]. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | You can also check out LLDB's fantastic [manual and tutorial][lldb-tutorial], which | 
					
						
							|  |  |  | will explain more complex debugging scenarios. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | [lldb-command-structure]: https://developer.apple.com/library/mac/documentation/IDEs/Conceptual/gdb_to_lldb_transition_guide/document/lldb-basics.html#//apple_ref/doc/uid/TP40012917-CH2-SW2 | 
					
						
							|  |  |  | [lldb-standalone]: https://developer.apple.com/library/mac/documentation/IDEs/Conceptual/gdb_to_lldb_transition_guide/document/lldb-terminal-workflow-tutorial.html | 
					
						
							|  |  |  | [lldb-tutorial]: http://lldb.llvm.org/tutorial.html |