| # Debugging the compiler | |
| This chapter contains a few tips to debug the compiler. | |
| These tips aim to be useful no matter what you are working on. | |
| Some of the other chapters have | |
| advice about specific parts of the compiler (e.g. the [Queries Debugging and | |
| Testing chapter](./incrcomp-debugging.md) or the [LLVM Debugging chapter](./backend/debugging.md)). | |
| ## Configuring the compiler | |
| By default, rustc is built without most debug information. | |
| To enable debug info, | |
| set `rust.debug = true` in your bootstrap.toml. | |
| Setting `rust.debug = true` turns on many different debug options (e.g., `debug-assertions`, | |
| `debug-logging`, etc.) which can be individually tweaked if you want to, but many people | |
| simply set `rust.debug = true`. | |
| If you want to use GDB to debug rustc, please set `bootstrap.toml` with options: | |
| ```toml | |
| rust.debug = true | |
| rust.debuginfo-level = 2 | |
| ``` | |
| > NOTE: | |
| > This will use a lot of disk space | |
| > (upwards of <!-- date-check Aug 2022 --> 35GB), | |
| > and will take a lot more compile time. | |
| > With `debuginfo-level = 1` (the default when `debug = true`), | |
| > you will be able to track the execution path, | |
| > but will lose the symbol information for debugging. | |
| The default configuration will enable `symbol-mangling-version` v0. | |
| This requires at least GDB v10.2, | |
| otherwise you need to disable new symbol-mangling-version in `bootstrap.toml`. | |
| ```toml | |
| rust.new-symbol-mangling = false | |
| ``` | |
| > See the comments in `bootstrap.example.toml` for more info. | |
| You will need to rebuild the compiler after changing any configuration option. | |
| ## Suppressing the ICE file | |
| By default, if rustc encounters an Internal Compiler Error (ICE) it will dump the ICE contents to an | |
| ICE file within the current working directory named `rustc-ice-<timestamp>-<pid>.txt`. | |
| If this is not desirable, you can prevent the ICE file from being created with `RUSTC_ICE=0`. | |
| ## Getting a backtrace | |
| [getting-a-backtrace]: #getting-a-backtrace | |
| When you have an ICE (panic in the compiler), you can set | |
| `RUST_BACKTRACE=1` to get the stack trace of the `panic!` like in normal Rust programs. | |
| IIRC backtraces **don't work** on MinGW, sorry. | |
| If you have trouble or the backtraces are full of `unknown`, | |
| you might want to find some way to use Linux, Mac, or MSVC on Windows. | |
| In the default configuration (without `debug` set to `true`), you don't have line numbers | |
| enabled, so the backtrace looks like this: | |
| ```text | |
| stack backtrace: | |
| 0: std::sys::imp::backtrace::tracing::imp::unwind_backtrace | |
| 1: std::sys_common::backtrace::_print | |
| 2: std::panicking::default_hook::{{closure}} | |
| 3: std::panicking::default_hook | |
| 4: std::panicking::rust_panic_with_hook | |
| 5: std::panicking::begin_panic | |
| (~~~~ LINES REMOVED BY ME FOR BREVITY ~~~~) | |
| 32: rustc_typeck::check_crate | |
| 33: <std::thread::local::LocalKey<T>>::with | |
| 34: <std::thread::local::LocalKey<T>>::with | |
| 35: rustc::ty::context::TyCtxt::create_and_enter | |
| 36: rustc_driver::driver::compile_input | |
| 37: rustc_driver::run_compiler | |
| ``` | |
| If you set `debug = true`, you will get line numbers for the stack trace. | |
| Then the backtrace will look like this: | |
| ```text | |
| stack backtrace: | |
| (~~~~ LINES REMOVED BY ME FOR BREVITY ~~~~) | |
| at /home/user/rust/compiler/rustc_typeck/src/check/cast.rs:110 | |
| 7: rustc_typeck::check::cast::CastCheck::check | |
| at /home/user/rust/compiler/rustc_typeck/src/check/cast.rs:572 | |
| at /home/user/rust/compiler/rustc_typeck/src/check/cast.rs:460 | |
| at /home/user/rust/compiler/rustc_typeck/src/check/cast.rs:370 | |
| (~~~~ LINES REMOVED BY ME FOR BREVITY ~~~~) | |
| 33: rustc_driver::driver::compile_input | |
| at /home/user/rust/compiler/rustc_driver/src/driver.rs:1010 | |
| at /home/user/rust/compiler/rustc_driver/src/driver.rs:212 | |
| 34: rustc_driver::run_compiler | |
| at /home/user/rust/compiler/rustc_driver/src/lib.rs:253 | |
| ``` | |
| ## `-Z` flags | |
| The compiler has a bunch of `-Z *` flags. | |
| These are unstable flags that are only enabled on nightly. | |
| Many of them are useful for debugging. | |
| To get a full listing of `-Z` flags, use `-Z help`. | |
| One useful flag is `-Z verbose-internals`, which generally enables printing more | |
| info that could be useful for debugging. | |
| Right below you can find elaborate explainers on a selected few. | |
| ### Getting a backtrace for errors | |
| [getting-a-backtrace-for-errors]: #getting-a-backtrace-for-errors | |
| If you want to get a backtrace to the point where the compiler emits an | |
| error message, you can pass the `-Z treat-err-as-bug=n`, which will make | |
| the compiler panic on the `nth` error. | |
| If you leave off `=n`, the compiler will | |
| assume `1` for `n` and thus panic on the first error it encounters. | |
| For example: | |
| ```bash | |
| $ cat error.rs | |
| ``` | |
| ```rust | |
| fn main() { | |
| 1 + (); | |
| } | |
| ``` | |
| ``` | |
| $ rustc +stage1 error.rs | |
| error[E0277]: cannot add `()` to `{integer}` | |
| --> error.rs:2:7 | |
| | | |
| 2 | 1 + (); | |
| | ^ no implementation for `{integer} + ()` | |
| | | |
| = help: the trait `Add<()>` is not implemented for `{integer}` | |
| error: aborting due to previous error | |
| ``` | |
| Now, where does the error above come from? | |
| ``` | |
| $ RUST_BACKTRACE=1 rustc +stage1 error.rs -Z treat-err-as-bug | |
| error[E0277]: the trait bound `{integer}: std::ops::Add<()>` is not satisfied | |
| --> error.rs:2:7 | |
| | | |
| 2 | 1 + (); | |
| | ^ no implementation for `{integer} + ()` | |
| | | |
| = help: the trait `std::ops::Add<()>` is not implemented for `{integer}` | |
| error: internal compiler error: unexpected panic | |
| note: the compiler unexpectedly panicked. this is a bug. | |
| note: we would appreciate a bug report: https://github.com/rust-lang/rust/blob/HEAD/CONTRIBUTING.md#bug-reports | |
| note: rustc 1.24.0-dev running on x86_64-unknown-linux-gnu | |
| note: run with `RUST_BACKTRACE=1` for a backtrace | |
| thread 'rustc' panicked at 'encountered error with `-Z treat_err_as_bug', | |
| /home/user/rust/compiler/rustc_errors/src/lib.rs:411:12 | |
| note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose | |
| backtrace. | |
| stack backtrace: | |
| (~~~ IRRELEVANT PART OF BACKTRACE REMOVED BY ME ~~~) | |
| 7: rustc::traits::error_reporting::<impl rustc::infer::InferCtxt<'a, 'tcx>> | |
| ::report_selection_error | |
| at /home/user/rust/compiler/rustc_middle/src/traits/error_reporting.rs:823 | |
| 8: rustc::traits::error_reporting::<impl rustc::infer::InferCtxt<'a, 'tcx>> | |
| ::report_fulfillment_errors | |
| at /home/user/rust/compiler/rustc_middle/src/traits/error_reporting.rs:160 | |
| at /home/user/rust/compiler/rustc_middle/src/traits/error_reporting.rs:112 | |
| 9: rustc_typeck::check::FnCtxt::select_obligations_where_possible | |
| at /home/user/rust/compiler/rustc_typeck/src/check/mod.rs:2192 | |
| (~~~ IRRELEVANT PART OF BACKTRACE REMOVED BY ME ~~~) | |
| 36: rustc_driver::run_compiler | |
| at /home/user/rust/compiler/rustc_driver/src/lib.rs:253 | |
| ``` | |
| Cool, now I have a backtrace for the error! | |
| ### Debugging delayed bugs | |
| The `-Z eagerly-emit-delayed-bugs` option makes it easy to debug delayed bugs. | |
| It turns them into normal errors, i.e. makes them visible. This can be used in | |
| combination with `-Z treat-err-as-bug` to stop at a particular delayed bug and get a backtrace. | |
| ### Getting the error creation location | |
| `-Z track-diagnostics` can help figure out where errors are emitted. | |
| It uses `#[track_caller]` for this and prints its location alongside the error: | |
| ``` | |
| $ RUST_BACKTRACE=1 rustc +stage1 error.rs -Z track-diagnostics | |
| error[E0277]: cannot add `()` to `{integer}` | |
| --> src\error.rs:2:7 | |
| | | |
| 2 | 1 + (); | |
| | ^ no implementation for `{integer} + ()` | |
| -Ztrack-diagnostics: created at compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs:638:39 | |
| | | |
| = help: the trait `Add<()>` is not implemented for `{integer}` | |
| = help: the following other types implement trait `Add<Rhs>`: | |
| <&'a f32 as Add<f32>> | |
| <&'a f64 as Add<f64>> | |
| <&'a i128 as Add<i128>> | |
| <&'a i16 as Add<i16>> | |
| <&'a i32 as Add<i32>> | |
| <&'a i64 as Add<i64>> | |
| <&'a i8 as Add<i8>> | |
| <&'a isize as Add<isize>> | |
| and 48 others | |
| For more information about this error, try `rustc --explain E0277`. | |
| ``` | |
| This is similar but different to `-Z treat-err-as-bug`: | |
| - it will print the locations for all errors emitted | |
| - it does not require a compiler built with debug symbols | |
| - you don't have to read through a big stack trace. | |
| ## Getting logging output | |
| The compiler uses the [`tracing`] crate for logging. | |
| [`tracing`]: https://docs.rs/tracing | |
| For details, see [the chapter on tracing](./tracing.md). | |
| ## Narrowing (bisecting) regressions | |
| The [cargo-bisect-rustc][bisect] tool can be used as a quick and easy way to | |
| find exactly which PR caused a change in `rustc` behavior. | |
| It automatically downloads `rustc` PR artifacts and tests them against a project you provide | |
| until it finds the regression. | |
| You can then look at the PR to get more context on *why* it was changed. | |
| See [this tutorial][bisect-tutorial] on how to use it. | |
| [bisect]: https://github.com/rust-lang/cargo-bisect-rustc | |
| [bisect-tutorial]: https://rust-lang.github.io/cargo-bisect-rustc/tutorial.html | |
| ## Downloading artifacts from Rust's CI | |
| The [rustup-toolchain-install-master][rtim] tool by kennytm can be used to | |
| download the artifacts produced by Rust's CI for a specific SHA1 -- this | |
| basically corresponds to the successful landing of some PR -- and then sets | |
| them up for your local use. | |
| This also works for artifacts produced by `@bors try`. | |
| This is helpful when you want to examine the resulting build of a PR | |
| without doing the build yourself. | |
| [rtim]: https://github.com/kennytm/rustup-toolchain-install-master | |
| ## `#[rustc_*]` TEST attributes | |
| The compiler defines a whole lot of internal (perma-unstable) attributes some of which are useful | |
| for debugging by dumping extra compiler-internal information. | |
| These are prefixed with `rustc_` and | |
| are gated behind the internal feature `rustc_attrs` (enabled via e.g. `#![feature(rustc_attrs)]`). | |
| For a complete and up to date list, see [`builtin_attrs`]. | |
| More specifically, the ones marked `TEST`. | |
| Here are some notable ones: | |
| | Attribute | Description | | |
| |----------------|-------------| | |
| | `rustc_dump_def_parents` | Dumps the chain of `DefId` parents of certain definitions. | | |
| | `rustc_dump_def_path` | Dumps the [`def_path_str`] of an item. | | |
| | `rustc_dump_generics` | Dumps the generics of an item. | | |
| | `rustc_dump_hidden_type_of_opaques` | Dumps the [hidden type of each opaque types][opaq] in the crate. | | |
| | `rustc_dump_inferred_outlives` | Dumps implied bounds of an item. More precisely, the [`inferred_outlives_of`] an item. | | |
| | `rustc_dump_item_bounds` | Dumps the [`item_bounds`] of an item. | | |
| | `rustc_dump_layout` | [See this section](#debugging-type-layouts). | | |
| | `rustc_dump_object_lifetime_defaults` | Dumps the [object lifetime defaults] of an item. | | |
| | `rustc_dump_clauses` | Dumps the [`clauses_of`] an item. | | |
| | `rustc_dump_symbol_name` | Dumps the mangled & demangled [`symbol_name`] of an item. | | |
| | `rustc_dump_variances` | Dumps the [variances] of an item. | | |
| | `rustc_dump_vtable` | Dumps the vtable layout of an impl, or a type alias of a dyn type. | | |
| | `rustc_regions` | Dumps NLL closure region requirements. | | |
| Right below you can find elaborate explainers on a selected few. | |
| [`builtin_attrs`]: https://github.com/rust-lang/rust/blob/HEAD/compiler/rustc_feature/src/builtin_attrs.rs | |
| [`def_path_str`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/context/struct.TyCtxt.html#method.def_path_str | |
| [`inferred_outlives_of`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/context/struct.TyCtxt.html#method.inferred_outlives_of | |
| [`item_bounds`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/context/struct.TyCtxt.html#method.item_bounds | |
| [`clauses_of`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/context/struct.TyCtxt.html#method.clauses_of | |
| [`symbol_name`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/context/struct.TyCtxt.html#method.symbol_name | |
| [object lifetime defaults]: https://doc.rust-lang.org/reference/lifetime-elision.html#default-trait-object-lifetimes | |
| [opaq]: ./opaque-types-impl-trait-inference.md | |
| [variances]: ./variance.md | |
| ### Formatting Graphviz output (.dot files) | |
| [formatting-graphviz-output]: #formatting-graphviz-output | |
| Some compiler options for debugging specific features yield graphviz graphs - | |
| e.g. the `#[rustc_mir(borrowck_graphviz_postflow="suffix.dot")]` attribute | |
| on a function dumps various borrow-checker dataflow graphs in conjunction with | |
| `-Zdump-mir-dataflow`. | |
| These all produce `.dot` files. To view these files, install graphviz (e.g. | |
| `apt-get install graphviz`) and then run the following commands: | |
| ```bash | |
| $ dot -T pdf maybe_init_suffix.dot > maybe_init_suffix.pdf | |
| $ firefox maybe_init_suffix.pdf # Or your favorite pdf viewer | |
| ``` | |
| Graphviz also comes with a preprocessor program, | |
| [`unflatten`](https://graphviz.org/docs/cli/unflatten/), that | |
| sometimes helps making the outputs look less oddly spread out. | |
| It reads a dot file and outputs another dot file, so you can use it in a pipe, | |
| e.g: | |
| ``` | |
| $ unflatten mir_dump/*.foo.-------.nll.0.regioncx.all.dot | dot -Tpdf -o foo-outlives.pdf | |
| ``` | |
| This is particularly useful for complicated region outlives graphs from | |
| [the borrow checker](borrow-check/debugging.md). | |
| [An online Graphviz editor and visualiser is | |
| also available](https://dreampuf.github.io/GraphvizOnline). | |
| ## Narrowing (Bisecting) Regressions | |
| The internal attribute `#[rustc_dump_layout(...)]` can be used to dump the | |
| [`Layout`] of the type it is attached to. | |
| For example: | |
| ```rust | |
| #![feature(rustc_attrs)] | |
| #[rustc_dump_layout(debug)] | |
| type T<'a> = &'a u32; | |
| ``` | |
| Will emit the following: | |
| ```text | |
| error: layout_of(&u32) = Layout { | |
| size: Size(8 bytes), | |
| align: AbiAlign { | |
| abi: Align(8 bytes), | |
| }, | |
| backend_repr: Scalar( | |
| Initialized { | |
| value: Pointer( | |
| AddressSpace( | |
| 0, | |
| ), | |
| ), | |
| valid_range: 1..=18446744073709551615, | |
| }, | |
| ), | |
| fields: Primitive, | |
| largest_niche: Some( | |
| Niche { | |
| offset: Size(0 bytes), | |
| value: Pointer( | |
| AddressSpace( | |
| 0, | |
| ), | |
| ), | |
| valid_range: 1..=18446744073709551615, | |
| }, | |
| ), | |
| uninhabited: false, | |
| variants: Single { | |
| index: 0, | |
| }, | |
| max_repr_align: None, | |
| unadjusted_abi_align: Align(8 bytes), | |
| randomization_seed: 281492156579847, | |
| } | |
| --> src/lib.rs:4:1 | |
| | | |
| 4 | type T<'a> = &'a u32; | |
| | ^^^^^^^^^^^^^^^^^^^^^ | |
| error: aborting due to previous error | |
| ``` | |
| [`Layout`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_public/abi/struct.Layout.html | |
| ## Debugging borrowcheck | |
| Debugging the borrow checker has [its own chapter](borrow-check/debugging.md). | |
| ## Configuring CodeLLDB for debugging `rustc` | |
| If you are using VSCode, and have edited your `bootstrap.toml` to request debugging | |
| level 1 or 2 for the parts of the code you're interested in, then you should be | |
| able to use the [CodeLLDB] extension in VSCode to debug it. | |
| Here is a sample `launch.json` file, being used to run a stage 1 compiler direct | |
| from the directory where it is built (does not have to be "installed"): | |
| ```javascript | |
| // .vscode/launch.json | |
| { | |
| "version": "0.2.0", | |
| "configurations": [ | |
| { | |
| "type": "lldb", | |
| "request": "launch", | |
| "name": "Launch", | |
| "args": [], // array of string command-line arguments to pass to compiler | |
| "program": "${workspaceFolder}/build/host/stage1/bin/rustc", | |
| "windows": { // applicable if using windows | |
| "program": "${workspaceFolder}/build/host/stage1/bin/rustc.exe" | |
| }, | |
| "cwd": "${workspaceFolder}", // current working directory at program start | |
| "stopOnEntry": false, | |
| "sourceLanguages": ["rust"] | |
| } | |
| ] | |
| } | |
| ``` | |
| [CodeLLDB]: https://marketplace.visualstudio.com/items?itemName=vadimcn.vscode-lldb |