├── .gitignore ├── CHANGES.md ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md ├── build.rs ├── debug-here-gdb-wrapper ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md └── src │ └── main.rs ├── debug-me ├── Cargo.toml └── src │ ├── another_module.rs │ └── main.rs └── src ├── internal.rs └── lib.rs /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | **/*.rs.bk 3 | Cargo.lock 4 | -------------------------------------------------------------------------------- /CHANGES.md: -------------------------------------------------------------------------------- 1 | # 0.2.2 2 | 3 | - Fix README.md slogan to reflect new windows support 4 | 5 | # 0.2.1 6 | 7 | - Add support for windows, using the just-in-time debugging mechanism 8 | - Update documentation to reflect windows support 9 | - Drop `nix` as a dependency 10 | 11 | # 0.2.0 12 | 13 | - Add support for macos 14 | - Add support for using rust-lldb as a backend 15 | - Add ability to choose your own backend 16 | - Remove need for rust-here-gdb-wrapper unless you are using xterm 17 | 18 | # 0.1.2 19 | 20 | - Add support for alacritty 21 | - Don't require include of `debug_here` in submodules (thanks @untitaker) 22 | - Tweak a few error messages. 23 | 24 | # 0.1.1 25 | 26 | The Initial Release 27 | - Only supported linux and rust-gdb 28 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "debug-here" 3 | version = "0.2.2" 4 | authors = ["Ethan Pailes "] 5 | readme = "README.md" 6 | license = "MIT/Apache-2.0" 7 | repository = "https://github.com/ethanpailes/debug-here" 8 | documentation = "https://docs.rs/debug-here" 9 | homepage = "https://github.com/ethanpailes/debug-here" 10 | description = """ 11 | A macro to shave precious seconds off the time it takes to start debugging. 12 | """ 13 | 14 | [workspace] 15 | members = [ 16 | "debug-me", 17 | "debug-here-gdb-wrapper", 18 | ] 19 | 20 | [dependencies] 21 | lazy_static = "1.1.0" 22 | which = "2.0" 23 | 24 | [target.'cfg(windows)'.dependencies] 25 | winapi = { version = "0.3", features = ["debugapi"] } 26 | -------------------------------------------------------------------------------- /LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright 2018-2019 Ethan Pailes 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2018-2019 Ethan Pailes 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # debug-here: a cross platform rust debugger hook 2 | 3 | ### The Problem 4 | 5 | Debuggers are a great way to examine the state of a program 6 | you are trying to understand, but actually beginning to use 7 | one can have a bit of ceremony involved. You have to figure 8 | out the name of the executable you care about. This can be 9 | harder than it might initially seem if you are running 10 | your program through several layers of scripts that someone else 11 | wrote, or even that you wrote. Once you've got your executable 12 | name you have to start it with `rust-gdb exe` (if you use a wrapper 13 | script, you have to arrange for your script to do so). Now that 14 | you've started your program under gdb you have to set your break 15 | point. It's not that much work, but I find myself doing it a fair 16 | amount, so it can get annoying. 17 | 18 | One alternative is to arrange for your program to enter some sort 19 | of sleep or looping state, rummage around for the PID on the command 20 | line, then attach with `gdb -pid`. Usually this ends up being a bit 21 | more work (again, not much work, but enough to be annoying), so people 22 | only do it if it is not convenient to launch the program in question 23 | from the terminal. 24 | 25 | ### Making getting to the debugger easier in rust 26 | 27 | This crate automates the process of convincing your program to 28 | wait around for a debugger to attach to it. Entering the debugger should 29 | be just as easy as writing a `println!` statement. This crate makes it 30 | so. 31 | 32 | ## Setup 33 | 34 | ### Linux Specific Setup 35 | 36 | If you are using linux and you want to use `xterm` for your terminal 37 | emulator, you need to install the debugger wrapper 38 | (which is called `debug-here-gdb-wrapper` for historical reasons). 39 | Not all terminal emulators allow you to pass extra arguments to the 40 | program you invoke as your shell, so `debug-here-gdb-wrapper` will 41 | arrange for your debugger backend to execute all the right commands. 42 | Note that you never need to call `debug-here-gdb-wrapper` directly, 43 | it just needs to be somewhere on your path, so that the `debug_here!()` 44 | macro can call it. 45 | 46 | ``` 47 | cargo install debug-here-gdb-wrapper 48 | ``` 49 | 50 | Alternatively, you could use [alacritty](https://github.com/jwilm/alacritty) 51 | as your terminal emulator, in which case you don't need to bother with 52 | the debug-here-gdb-wrapper. If you have alacritty on your path, `debug-here` 53 | will automatically chose to use it over xterm, so there is no special 54 | setup required after you've installed it. 55 | 56 | ### Windows Specific Setup 57 | 58 | `debug-here` uses windows Just-In-Time Debugging to allow you to use visual 59 | studio to debug your code, so you have to have a working visual studio 60 | installation. 61 | 62 | ### General Setup 63 | 64 | Just add debug-here to the dependencies of a crate you want to work on. 65 | 66 | ``` 67 | debug-here = "0.2" 68 | ``` 69 | 70 | ## Usage 71 | 72 | Drop the usual `#[macro_use] extern crate debug_here;` somewhere in your 73 | `lib.rs` or `main.rs`, then just write `debug_here!()` 74 | wherever you want to get dropped into the debugger. When your 75 | program reaches that point for the first time, it will launch 76 | a debugger appropriate for your platform attached to your process 77 | right after the `debug_here!()` macro. You can poke around 78 | and start stepping through your program. If you reach another 79 | `debug_here!()` macro invocation, you don't have to worry about 80 | more debugger terminals spawning left and right. `debug_here!()` only 81 | fires once per program. 82 | 83 | ### Windows Usage Notes 84 | 85 | Visual Studio will drop you into the debugger right at the end of the 86 | `debug_break_wrapper` function. You can just mash F10 a few times to 87 | get back to your code where the `debug_here!()` macro was invoked. 88 | 89 | Visual Studio is the only debugger supported on windows. 90 | 91 | ### Unixy Usage Notes 92 | 93 | On linux and macos you can choose to use either `rust-gdb` or `rust-lldb` 94 | as debugger backends. If you plan to leave `debug_here!()` macros 95 | in your code, you should avoid forcing a particular backend because not 96 | all backends work well on all platforms. Windows will not work with 97 | `gdb` or `lldb` for example. 98 | 99 | #### Supported Terminal Emulators 100 | 101 | Currently `debug-here` supports `alacritty` and `xterm` on linux, and 102 | `Terminal.app` on macos. If you have `alacritty` on your path, it will use that, 103 | on the theory that you would rather use a less standard terminal emulator 104 | if you went to all the trouble of installing it. If you don't have 105 | `alacritty` on your path, it will fall back on `xterm`. 106 | 107 | ## Platforms 108 | 109 | Right now `debug-here` only works on linux, macos and windows. 110 | `debug-here` defaults to using `rust-gdb` on linux, `rust-lldb` on macos, 111 | and Visual Studio on windows. The primary reason for defaulting to `rust-lldb` 112 | on macos is to avoid the pain of getting a properly code-signed gdb. 113 | 114 | `debug-here` probably won't grow support for any more platforms, though it's 115 | possible that windows will grow support for gdb and lldb. I'm happy to take 116 | patches for more exotic platforms, though testing may be an issue. 117 | 118 | ## An Example: Bad Factorials 119 | 120 | I have a very important rust program called `debug-me` which computes 121 | the factorial of 5. Or at least its supposed to. Right now it is 122 | telling me that the factorial of 5 is 0, which doesn't seem right. 123 | Here is my `main.rs`. 124 | 125 | ```rust 126 | fn factorial(n: usize) -> usize { 127 | let mut res = 1; 128 | for i in 0..n { 129 | res *= i; 130 | } 131 | res 132 | } 133 | 134 | fn main() { 135 | println!("The factorial of 5 is {}!", factorial(5)); 136 | } 137 | ``` 138 | 139 | You can probably see the problem, but I can't because I'm helpless without 140 | a debugger. In order to figure out what is going on, I'm going to pull 141 | in debug-here to help me out. First, I'll make sure that the debug-here 142 | debugger shim is installed with `cargo install debug-here-gdb-wrapper`. 143 | Now, I'll add debug-here to my factorial crate's `Cargo.toml`. 144 | 145 | ``` 146 | [dependencies] 147 | debug-here = "0.1" 148 | ``` 149 | 150 | And I'll add the line 151 | 152 | ``` 153 | #[macro_use] extern crate debug_here; 154 | ``` 155 | 156 | to my source file. Now it looks like this: 157 | 158 | ```rust 159 | #[macro_use] extern crate debug_here; 160 | 161 | fn factorial(n: usize) -> usize { 162 | let mut res = 1; 163 | for i in 0..n { 164 | res *= i; 165 | } 166 | res 167 | } 168 | 169 | fn main() { 170 | println!("The factorial of 5 is {}!", factorial(5)); 171 | } 172 | ``` 173 | 174 | My loop is definitely counting up and multiplying the result variable 175 | by bigger and bigger numbers. I feel like it should work, but I'm 176 | going to step through the loop a few times to see what's going on. 177 | Time to set my breakpoint with debug-here. 178 | 179 | ```rust 180 | #[macro_use] extern crate debug_here; 181 | 182 | fn factorial(n: usize) -> usize { 183 | let mut res = 1; 184 | debug_here!(); 185 | for i in 0..n { 186 | res *= i; 187 | } 188 | res 189 | } 190 | 191 | fn main() { 192 | println!("The factorial of 5 is {}!", factorial(5)); 193 | } 194 | ``` 195 | 196 | As easy as `println!`! Now I run my program with `cargo run`. 197 | An terminal window pops up with a gdb shell that says: 198 | 199 | ``` 200 | debug_me::factorial (n=5) at debug-me/src/main.rs:6 201 | 6 for i in 0..n { 202 | (gdb) 203 | ``` 204 | 205 | Looking at my source code, it seems like `res` is an interesting 206 | variable to keep track of, so I'll ask gdb to keep me informed. 207 | 208 | ``` 209 | (gdb) disp res 210 | 1: res = 1 211 | ``` 212 | 213 | Now, I'll step through the loop a few times. 214 | 215 | ``` 216 | (gdb) n 217 | 7 res *= i; 218 | 1: res = 1 219 | (gdb) n 220 | 6 for i in 0..n { 221 | 1: res = 0 222 | (gdb) n 223 | 7 res *= i; 224 | 1: res = 0 225 | ``` 226 | 227 | It looks like `res` went to 0 in the first loop iteration. Looking back 228 | at the source, I can see that this is because the counter starts at 0. I'll 229 | quit out of the debugger and fix it. 230 | 231 | If you want to play with this example yourself, you can just clone the 232 | repo at `https://github.com/ethanpailes/debug-here` and run the following 233 | commands: 234 | 235 | ``` 236 | > cargo install debug-here-gdb-wrapper # if you are on linux 237 | > cd debug-here/debug-me 238 | > cargo run 239 | ``` 240 | 241 | You should see a terminal pop up with a debugger shell ready to go. There 242 | is another bug in the factorial routine. Try finding it. 243 | -------------------------------------------------------------------------------- /build.rs: -------------------------------------------------------------------------------- 1 | fn main() -> Result<(), Box> { 2 | let triple = std::env::var("TARGET").unwrap(); 3 | if triple.contains("macabi") { 4 | println!("cargo:rustc-cfg=mac_catalyst"); 5 | } 6 | 7 | Ok(()) 8 | } 9 | -------------------------------------------------------------------------------- /debug-here-gdb-wrapper/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "debug-here-gdb-wrapper" 3 | version = "0.2.0" 4 | authors = ["Ethan Pailes "] 5 | workspace = ".." 6 | readme = "README.md" 7 | license = "MIT/Apache-2.0" 8 | repository = "https://github.com/ethanpailes/debug-here" 9 | documentation = "https://docs.rs/debug-here-gdb-wrapper" 10 | homepage = "https://github.com/ethanpailes/debug-here" 11 | description = """ 12 | A shim to help debug-here launch debuggers. 13 | """ 14 | categories = ["development-tools::debugging"] 15 | 16 | [dependencies] 17 | -------------------------------------------------------------------------------- /debug-here-gdb-wrapper/LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright 2018 Ethan Pailes 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /debug-here-gdb-wrapper/LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright (c) 2018 Ethan Pailes 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /debug-here-gdb-wrapper/README.md: -------------------------------------------------------------------------------- 1 | # debug-here-gdb-wrapper 2 | 3 | This program is what debug-here tells new terminals to use as a shell. 4 | It is very simple. All it does is examine the `RUST_DEBUG_HERE_LIFELINE` 5 | environment variable, then becomes `rust-gdb` via exec and hooks into 6 | the part of the source code that called the `debug_here!()` macro. 7 | As a user, you mostly shouldn't have to worry about what this program 8 | does. You just need to have it somewhere on your path in order to use 9 | `debug_here!()`. The easiest way to do that is with 10 | `cargo install debug-here-gdb-wrapper`. 11 | -------------------------------------------------------------------------------- /debug-here-gdb-wrapper/src/main.rs: -------------------------------------------------------------------------------- 1 | use std::{process, env}; 2 | use std::os::unix::process::CommandExt; 3 | 4 | fn main() { 5 | match inner() { 6 | Ok(()) => {}, 7 | Err(errstr) => { 8 | eprintln!("debug-here-gdb-wrapper: {}", errstr); 9 | eprintln!("\n\n\n"); 10 | eprintln!( 11 | r#"This terminal is just here to display the above error 12 | message, and won't respond to any input. When you are 13 | done looking, just close the window. 14 | "#); 15 | 16 | 17 | // Do nothing, but don't exit either, so the user can see 18 | // our error message. 19 | loop { 20 | std::thread::sleep(std::time::Duration::new(1000, 0)); 21 | } 22 | } 23 | } 24 | } 25 | 26 | fn inner() -> Result<(), String> { 27 | let params = env::var("RUST_DEBUG_HERE_LIFELINE") 28 | .map_err(|_| 29 | r#"Expected RUST_DEBUG_HERE_LIFELINE to be defined. 30 | This is a bug with debug-here. Please report it 31 | at `https://github.com/ethanpailes/debug-here/issues`. 32 | "#.to_string())?; 33 | env::remove_var("RUST_DEBUG_HERE_LIFELINE"); 34 | 35 | let mut params = params.split(","); 36 | let fmt_version_no = params 37 | .next() 38 | .ok_or("Couldn't split out version number.".to_string()) 39 | .and_then(|v| v.parse::().map_err(|e| e.to_string())) 40 | .map_err(|e| format!("Failed to parse version number: {}", e))?; 41 | 42 | if fmt_version_no > 2 { 43 | return Err( 44 | format!("Don't know what to do with this debug-here protocol 45 | version ({}). You might want to re-install 46 | debug-here-gdb-wrapper.", 47 | fmt_version_no)); 48 | } 49 | 50 | let pid = params 51 | .next() 52 | .ok_or("Failed to get the PID of the program to be debugged." 53 | .to_string())?; 54 | 55 | let mut debugger = "rust-gdb"; 56 | if fmt_version_no > 1 { 57 | debugger = params 58 | .next() 59 | .ok_or("Failed to get the name of the debugger to use." 60 | .to_string())?; 61 | } 62 | 63 | if debugger == "rust-gdb" { 64 | // Hopefully, this won't return, but if it does we want to display 65 | // the error. 66 | Err(process::Command::new(debugger) 67 | .arg("-pid").arg(&pid) 68 | .arg("-ex").arg("set variable looping = 0") 69 | .arg("-ex").arg("finish") 70 | .exec() 71 | .to_string()) 72 | } else if debugger == "rust-lldb" { 73 | Err(process::Command::new(debugger) 74 | .arg("-p").arg(&pid) 75 | .arg("-o").arg("expression looping = 0") 76 | .arg("-o").arg("finish") 77 | .exec() 78 | .to_string()) 79 | } else { 80 | Err(format!("Unknown debugger: {}", debugger)) 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /debug-me/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "debug-me" 3 | version = "0.1.1" 4 | authors = ["Ethan Pailes "] 5 | workspace = ".." 6 | 7 | [dependencies] 8 | debug-here = { version = "0.2", path = ".." } 9 | -------------------------------------------------------------------------------- /debug-me/src/another_module.rs: -------------------------------------------------------------------------------- 1 | 2 | // Notice that we don't have to re-import `debug-here`. As long 3 | // as we've #[macro_used] it in main.rs (or lib.rs for a library), 4 | // it will work anywhere in the project. 5 | pub fn factorial(n: usize) -> usize { 6 | let mut res = 1; 7 | debug_here!(); 8 | for i in 0..n { 9 | res *= i; 10 | } 11 | res 12 | } 13 | -------------------------------------------------------------------------------- /debug-me/src/main.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] extern crate debug_here; 2 | 3 | mod another_module; 4 | 5 | fn factorial(n: usize) -> usize { 6 | let mut res = 1; 7 | // Try changing the debugger backend by replacing this with 8 | // 9 | // debug_here!(lldb); 10 | // 11 | // or 12 | // 13 | // debug_here!(gdb); 14 | debug_here!(); 15 | for i in 0..n { 16 | res *= i; 17 | } 18 | res 19 | } 20 | 21 | fn main() { 22 | // only the first of these will fire, but try commenting out the 23 | // call to our local version of broken `factorial`. 24 | 25 | println!("The factorial of 5 is {}!", factorial(5)); 26 | 27 | println!("The factorial of 4 is {}!", another_module::factorial(4)); 28 | } 29 | -------------------------------------------------------------------------------- /src/internal.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2018-2019 Ethan Pailes. See the COPYRIGHT 2 | // file at the top-level directory of this distribution. 3 | // 4 | // Licensed under the Apache License, Version 2.0 or the MIT license 6 | // , at your 7 | // option. This file may not be copied, modified, or distributed 8 | // except according to those terms. 9 | 10 | /*! 11 | This module contains the internal implementation of debug-here. Nothing 12 | in this module is part of the public api of debug-here, even if it is 13 | marked `pub`. 14 | 15 | Certain functions must be marked `pub` in order for the `debug_here!()` 16 | macro to call them, but user code should never call them directly. 17 | */ 18 | 19 | use std::sync::Mutex; 20 | use std::process; 21 | 22 | #[cfg(target_os = "linux")] 23 | use std::{fs, env}; 24 | 25 | #[cfg(target_os = "windows")] 26 | use winapi::um::debugapi; 27 | #[cfg(target_os = "windows")] 28 | use std::{path, thread}; 29 | #[cfg(target_os = "windows")] 30 | use std::time::Duration; 31 | 32 | #[cfg(not(any(target_os = "linux", target_os = "macos", mac_catalyst, target_os = "windows")))] 33 | compile_error!("debug-here: this crate currently only builds on linux, macos, and windows"); 34 | 35 | fn already_entered() -> bool { 36 | lazy_static! { 37 | static ref GUARD: Mutex = Mutex::new(false); 38 | } 39 | 40 | // just propogate the thread poisoning with unwrap. 41 | let mut entered = GUARD.lock().unwrap(); 42 | 43 | let ret = *entered; 44 | *entered = true; 45 | return ret; 46 | } 47 | 48 | /// The function responsible for actually launching the debugger. 49 | /// 50 | /// If we have never launched a debugger before, we do so. Otherwise, 51 | /// we just don't do anything on the theory that if you are debugging 52 | /// something in a loop, you probably don't want a new debugger 53 | /// every time you step through your `debug_here!()`. 54 | /// 55 | /// Before spawning the debugger we examine the execution environment 56 | /// a bit to try to help users through any configuration errors. 57 | /// 58 | /// Don't use this directly. 59 | #[cfg(not(target_os = "windows"))] 60 | pub fn debug_here_unixy_impl(debugger: Option<&str>) { 61 | if already_entered() { 62 | return; 63 | } 64 | 65 | 66 | #[cfg(target_os = "linux")] 67 | let sane_env = linux_check(); 68 | #[cfg(any(target_os = "macos", mac_catalyst))] 69 | let sane_env = macos_check(); 70 | 71 | if let Err(e) = sane_env { 72 | eprintln!("debug-here: {}", e); 73 | return 74 | } 75 | 76 | #[cfg(target_os = "linux")] 77 | let debugger = debugger.unwrap_or("rust-gdb"); 78 | #[cfg(any(target_os = "macos", mac_catalyst))] 79 | let debugger = debugger.unwrap_or("rust-lldb"); 80 | 81 | if which::which(debugger).is_err() { 82 | eprintln!("debug-here: can't find {} on your path. Bailing.", debugger); 83 | return; 84 | } 85 | 86 | if which::which("debug-here-gdb-wrapper").is_err() { 87 | eprintln!(r#"debug-here: 88 | Can't find debug-here-gdb-wrapper on your path. To get it 89 | you can run `cargo install debug-here-gdb-wrapper` 90 | "#); 91 | return; 92 | } 93 | 94 | // `looping` is a magic variable name that debug-here-gdb-wrapper knows to 95 | // set to false in order to unstick us. We set it before launching the 96 | // debugger to avoid a race condition. 97 | let looping = true; 98 | 99 | #[cfg(target_os = "linux")] 100 | let launch_stat = linux_launch_term(debugger); 101 | #[cfg(any(target_os = "macos", mac_catalyst))] 102 | let launch_stat = macos_launch_term(debugger); 103 | 104 | if let Err(e) = launch_stat { 105 | eprintln!("debug-here: {}", e); 106 | return; 107 | } 108 | 109 | // Now we enter an infinite loop and wait for the debugger to come to 110 | // our rescue 111 | while looping {} 112 | } 113 | 114 | /// Pop open a debugger on windows. 115 | /// 116 | /// Windows has native just-in-time debugging capabilities via the debugapi 117 | /// winapi module, so we use that instead of manually popping open a termianl 118 | /// and launching the debugger in that. 119 | /// 120 | /// We perform the same re-entry check as we do for non-windows platforms. 121 | /// 122 | /// This approach pretty directly taken from: 123 | /// https://stackoverflow.com/questions/20337870/what-is-the-equivalent-of-system-diagnostics-debugger-launch-in-unmanaged-code 124 | /// 125 | /// Don't use this directly. 126 | #[cfg(target_os = "windows")] 127 | pub fn debug_here_win_impl() { 128 | if already_entered() { 129 | return; 130 | } 131 | 132 | let jitdbg_exe = r#"c:\windows\system32\vsjitdebugger.exe"#; 133 | if !path::Path::new(jitdbg_exe).exists() { 134 | eprintln!("debug-here: could not find '{}'.", jitdbg_exe); 135 | return; 136 | } 137 | 138 | 139 | let pid = process::id(); 140 | 141 | let mut cmd = process::Command::new(jitdbg_exe); 142 | cmd.stdin(process::Stdio::null()) 143 | .stdout(process::Stdio::null()) 144 | .stderr(process::Stdio::null()); 145 | cmd.arg("-p").arg(pid.to_string()); 146 | 147 | if let Err(e) = cmd.spawn() { 148 | eprintln!("debug-here: failed to launch '{}': {}", jitdbg_exe, e); 149 | return; 150 | } 151 | 152 | // Argument for safty: this unsafe call doesn't manipulate memory 153 | // in any way. 154 | while unsafe { debugapi::IsDebuggerPresent() } == 0 { 155 | thread::sleep(Duration::from_millis(100)); 156 | } 157 | 158 | // Just mash F10 until you see your own code 159 | unsafe { debugapi::DebugBreak(); } 160 | } 161 | 162 | 163 | /// The args required to launch the given debugger and attach to the 164 | /// current debugger. 165 | #[cfg(not(target_os = "windows"))] 166 | fn debugger_args(debugger: &str) -> Vec { 167 | if debugger == "rust-lldb" { 168 | vec!["-p".to_string(), 169 | process::id().to_string(), 170 | "-o".to_string(), 171 | "expression looping = 0".to_string(), 172 | "-o".to_string(), 173 | "finish".to_string()] 174 | } else if debugger == "rust-gdb" { 175 | vec!["-pid".to_string(), 176 | process::id().to_string(), 177 | "-ex".to_string(), 178 | "set variable looping = 0".to_string(), 179 | "-ex".to_string(), 180 | "finish".to_string()] 181 | } else { 182 | panic!("unknown debugger: {}", debugger); 183 | } 184 | } 185 | 186 | /// Perform sanity checks specific to a linux environment 187 | /// 188 | /// Returns true on success, false if we should terminate early 189 | #[cfg(target_os = "linux")] 190 | fn linux_check() -> Result<(), String> { 191 | let the_kids_are_ok = 192 | fs::read("/proc/sys/kernel/yama/ptrace_scope") 193 | .map(|contents| 194 | std::str::from_utf8(&contents[..1]).unwrap_or("1") == "0") 195 | .unwrap_or(false); 196 | if !the_kids_are_ok { 197 | return Err(format!(r#" 198 | ptrace_scope must be set to 0 for debug-here to work. 199 | This will allow any process with a given uid to rummage around 200 | in the memory of any other process with the same uid, so there 201 | are some security risks. To set ptrace_scope for just this 202 | session you can do: 203 | 204 | echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope 205 | 206 | Giving up on debugging for now. 207 | "#)); 208 | } 209 | 210 | Ok(()) 211 | } 212 | 213 | /// Launch a terminal in a linux environment 214 | #[cfg(target_os = "linux")] 215 | fn linux_launch_term(debugger: &str) -> Result<(), String> { 216 | // Set up a magic environment variable telling debug-here-gdb-wrapper 217 | // where to enter the program to be debugged. 218 | // 219 | // It is nicer to use an environment variable instead of a magic file 220 | // or named pipe or something because that way only our kids will get 221 | // to see it. 222 | // 223 | // The format here is `,`. 224 | // 225 | // We have to do this in the linux-specific launch routine becuase 226 | // macos is weird about how you can lauch a new terminal window, 227 | // and doesn't just put new windows in a subprocess. 228 | if debugger == "rust-gdb" { 229 | // If we are being asked to launch rust-gdb, that can be handled with 230 | // protocol version 1, so there is no need to pester users to upgrade. 231 | env::set_var("RUST_DEBUG_HERE_LIFELINE", 232 | format!("1,{}", process::id())); 233 | } else { 234 | env::set_var("RUST_DEBUG_HERE_LIFELINE", 235 | format!("2,{},{}", process::id(), debugger)); 236 | } 237 | 238 | let term = match which::which("alacritty").or(which::which("xterm")) { 239 | Ok(t) => t, 240 | Err(_) => { 241 | return Err(format!(r#" 242 | can't find alacritty or xterm on your path. Those are the 243 | only terminal emulators currently supported on linux. 244 | "#)); 245 | } 246 | }; 247 | let term_cmd = term.clone(); 248 | 249 | let mut cmd = process::Command::new(term_cmd); 250 | cmd.stdin(process::Stdio::null()) 251 | .stdout(process::Stdio::null()) 252 | .stderr(process::Stdio::null()); 253 | 254 | // Alacritty doesn't need the shim 255 | if term.ends_with("alacritty") { 256 | cmd.arg("-e"); 257 | cmd.arg(debugger); 258 | cmd.args(debugger_args(debugger)); 259 | } else { 260 | cmd.arg("debug-here-gdb-wrapper"); 261 | } 262 | 263 | match cmd.spawn() { 264 | Ok(_) => Ok(()), 265 | Err(e) => Err( 266 | format!("failed to launch rust-gdb in {:?}: {}", term, e)) 267 | } 268 | } 269 | 270 | /// sanity check the environment in a macos environment 271 | #[cfg(any(target_os = "macos", mac_catalyst))] 272 | fn macos_check() -> Result<(), String> { 273 | if which::which("osascript").is_err() { 274 | return Err(format!("debug-here: can't find osascript. Bailing.")); 275 | } 276 | 277 | Ok(()) 278 | } 279 | 280 | /// Launch a terminal in a macos environment 281 | #[cfg(any(target_os = "macos", mac_catalyst))] 282 | fn macos_launch_term(debugger: &str) -> Result<(), String> { 283 | let launch_script = 284 | format!(r#"tell app "Terminal" 285 | do script "exec {} {}" 286 | end tell"#, debugger, 287 | debugger_args(debugger).into_iter() 288 | .map(|a| if a.contains(" ") { format!("'{}'", a) } else { a } ) 289 | .collect::>().join(" ")); 290 | 291 | let mut cmd = process::Command::new("osascript"); 292 | cmd.arg("-e") 293 | .arg(launch_script) 294 | .stdin(process::Stdio::null()) 295 | .stdout(process::Stdio::null()) 296 | .stderr(process::Stdio::null()); 297 | 298 | match cmd.spawn() { 299 | Ok(_) => Ok(()), 300 | Err(e) => Err( 301 | format!("failed to launch {} in Terminal.app: {}", debugger, e)) 302 | } 303 | } 304 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2018-2019 Ethan Pailes. See the COPYRIGHT 2 | // file at the top-level directory of this distribution. 3 | // 4 | // Licensed under the Apache License, Version 2.0 or the MIT license 6 | // , at your 7 | // option. This file may not be copied, modified, or distributed 8 | // except according to those terms. 9 | 10 | /*! 11 | This crate provides a macro for launching the debugger most appropriate for 12 | your platform in a new terminal. The first time a program executes the 13 | `debug_here!()` macro, it launches a new terminal and automatically 14 | attaches either rust-gdb or rust-lldb to your program at the location 15 | of the macro. 16 | 17 | [The README](https://github.com/ethanpailes/debug-here/blob/master/README.md) 18 | contains more details and examples. 19 | 20 | The [debug-me](https://github.com/ethanpailes/debug-here/tree/master/debug-me) 21 | program provides a concrete usage example. 22 | */ 23 | 24 | #[macro_use] extern crate lazy_static; 25 | 26 | #[cfg(not(target_os = "windows"))] 27 | extern crate which; 28 | #[cfg(target_os = "windows")] 29 | extern crate winapi; 30 | 31 | pub mod internal; 32 | 33 | /// The debug here macro. Just invoke this macro somewhere in your 34 | /// source, and when your program reaches it a terminal running 35 | /// `rust-gdb` or `rust-lldb` will launch. 36 | /// 37 | /// If you want to force a specific debugger backend, you can write 38 | /// `debug_here!(gdb)` or `debug_here!(lldb)`. 39 | #[cfg(not(target_os = "windows"))] 40 | #[macro_export] 41 | macro_rules! debug_here { 42 | () => { 43 | ::debug_here::internal::debug_here_unixy_impl(None); 44 | }; 45 | ( gdb ) => { 46 | ::debug_here::internal::debug_here_unixy_impl(Some("rust-gdb")); 47 | }; 48 | ( lldb ) => { 49 | ::debug_here::internal::debug_here_unixy_impl(Some("rust-lldb")); 50 | }; 51 | } 52 | 53 | #[cfg(target_os = "windows")] 54 | #[macro_export] 55 | macro_rules! debug_here { 56 | () => { 57 | ::debug_here::internal::debug_here_win_impl(); 58 | }; 59 | ( gdb ) => { 60 | compile_error!("debug-here: gdb is not supported on windows"); 61 | }; 62 | ( lldb ) => { 63 | compile_error!("debug-here: lldb is not supported on windows"); 64 | }; 65 | } 66 | --------------------------------------------------------------------------------