From 39a0be6dc8210e0f127638ac5cc6820b8ce534df Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Sat, 6 May 2023 10:25:55 -0700 Subject: [PATCH] Updates and copy-edits for debugger_visualizer. --- src/attributes.md | 2 +- src/attributes/debugger.md | 113 +++++++++++++------------------------ 2 files changed, 41 insertions(+), 74 deletions(-) diff --git a/src/attributes.md b/src/attributes.md index 28d49fff1..92ce1cd09 100644 --- a/src/attributes.md +++ b/src/attributes.md @@ -272,7 +272,7 @@ The following is an index of all built-in attributes. - [`non_exhaustive`] — Indicate that a type will have more fields/variants added in future. - Debugger - - [`debugger_visualizer`] — Embeds a file that specifies debugger output for a type + - [`debugger_visualizer`] — Embeds a file that specifies debugger output for a type. [Doc comments]: comments.md#doc-comments [ECMA-334]: https://www.ecma-international.org/publications/standards/Ecma-334.htm diff --git a/src/attributes/debugger.md b/src/attributes/debugger.md index 208f6bd82..6ea80221e 100644 --- a/src/attributes/debugger.md +++ b/src/attributes/debugger.md @@ -1,55 +1,36 @@ # Debugger attributes -The following [attributes] are used for enhancing the debugging experience when using third-party debuggers like GDB or LLDB. +The following [attributes] are used for enhancing the debugging experience when using third-party debuggers like GDB or WinDbg. ## The `debugger_visualizer` attribute -The `debugger_visualizer` attribute can be used to embed a debugger visualizer file into the debug information generated by `rustc`. -This enables an improved debugger experience for types outside of Rust's standard library. +The *`debugger_visualizer` attribute* can be used to embed a debugger visualizer file into the debug information. +This enables an improved debugger experience for displaying values in the debugger. +It uses the [_MetaListNameValueStr_] syntax to specify its inputs, and must be specified as a crate attribute. ### Using `debugger_visualizer` with Natvis Natvis is an XML-based framework for Microsoft debuggers (such as Visual Studio and WinDbg) that uses declarative rules to customize the display of types. -A Natvis file is embedded using the `natvis-file` meta item. For detailed information on the Natvis format, refer to Microsoft's [Natvis documentation]. -
-Currently, this attribute only supports embedding Natvis files on `-windows-msvc` targets. -
+This attribute only supports embedding Natvis files on `-windows-msvc` targets. -Consider a crate with this directory structure: - -```text -/Cargo.toml -/Rectangle.natvis - +-- src - +-- main.rs -``` - -Where `main.rs` contains: +The path to the Natvis file is specified with the `natvis_file` key, which is a path relative to the crate source file: + ```rust ignore -#![debugger_visualizer(natvis_file = "../Rectangle.natvis")] -mod fancy_rect { - pub struct FancyRect { - pub x: f32, - pub y: f32, - pub dx: f32, - pub dy: f32, - } - - impl FancyRect { - pub fn new(x: f32, y: f32, dx: f32, dy: f32) -> Self { - FancyRect { x, y, dx, dy } - } - } -} +#![debugger_visualizer(natvis_file = "Rectangle.natvis")] -use fancy_rect::FancyRect; +struct FancyRect { + x: f32, + y: f32, + dx: f32, + dy: f32, +} fn main() { - let fancy_rect = FancyRect::new(10.0, 10.0, 5.0, 5.0); - () + let fancy_rect = FancyRect { x: 10.0, y: 10.0, dx: 5.0, dy: 5.0 }; + println!("set breakpoint here"); } ``` @@ -58,7 +39,7 @@ and `Rectangle.natvis` contains: ```xml - + ({x},{y}) + ({dx}, {dy}) @@ -82,55 +63,38 @@ When viewed under WinDbg, the `fancy_rect` variable would be shown as follows: ```text > Variables: - > fancy_rect: (10, 10) + (5, 5) - > LowerLeft: (10, 10) - > UpperLeft: (10, 15) - > UpperRight: (15, 15) - > LowerRight: (15, 10) + > fancy_rect: (10.0, 10.0) + (5.0, 5.0) + > LowerLeft: (10.0, 10.0) + > UpperLeft: (10.0, 15.0) + > UpperRight: (15.0, 15.0) + > LowerRight: (15.0, 10.0) ``` ### Using `debugger_visualizer` with GDB GDB supports the use of a structured Python script, called a *pretty printer*, that describes how a type should be visualized in the debugger view. -These scripts are embedded using the `gdb_script_file` meta item. -For detailed information on pretty printers, refer to GDB's [pretty print documentation]. +For detailed information on pretty printers, refer to GDB's [pretty printing documentation]. Embedded pretty printers are not automatically loaded when debugging a binary under GDB. There are two ways to enable auto-loading embedded pretty printers: -1. Launch GDB with extra arguments to explicitly add a directory or binary to the auto-load safe path: `gdb -iex "set auto-load safe-path path/to/binary" path/to/binary` (For more information, see GDB's [auto-loading documentation]) +1. Launch GDB with extra arguments to explicitly add a directory or binary to the auto-load safe path: `gdb -iex "add-auto-load-safe-path safe-path path/to/binary" path/to/binary` + For more information, see GDB's [auto-loading documentation]. 1. Create a file named `gdbinit` under `$HOME/.config/gdb` (you may need to create the directory if it doesn't already exist). Add the following line to that file: `add-auto-load-safe-path path/to/binary`. -Consider a crate called `PersonPrinter` with this directory structure: - -```text -/Cargo.toml -/printer.py - +-- src - +-- main.rs -``` - -Where `main.rs` contains: +These scripts are embedded using the `gdb_script_file` key, which is a path relative to the crate source file. + ```rust ignore -#![debugger_visualizer(gdb_script_file = "../printer.py")] -mod person { - pub struct Person { - pub name: String, - pub age: i32, - } - - impl Person { - pub fn new(name: String, age: i32) -> Self { - Person { name, age } - } - } -} +#![debugger_visualizer(gdb_script_file = "printer.py")] -use person::Person; +struct Person { + name: String, + age: i32, +} fn main() { - let bob = Person::new(String::from("Bob"), 10); - () + let bob = Person { name: String::from("Bob"), age: 10 }; + println!("set breakpoint here"); } ``` @@ -154,7 +118,7 @@ def lookup(val): lookup_tag = val.type.tag if lookup_tag is None: return None - if "PersonPrinter::person::Person" == lookup_tag: + if "foo::Person" == lookup_tag: return PersonPrinter(val) return None @@ -162,13 +126,16 @@ def lookup(val): gdb.current_objfile().pretty_printers.append(lookup) ``` -When the crate's debug executable is passed into GDB, `print bob` will display: +When the crate's debug executable is passed into GDB[^rust-gdb], `print bob` will display: ```text "Bob" is 10 years old. ``` +[^rust-gdb]: Note: This assumes you are using the `rust-gdb` script which configures pretty-printers for standard library types like `String`. + [auto-loading documentation]: https://sourceware.org/gdb/onlinedocs/gdb/Auto_002dloading-safe-path.html [attributes]: ../attributes.md [Natvis documentation]: https://docs.microsoft.com/en-us/visualstudio/debugger/create-custom-views-of-native-objects -[pretty print documentation]: https://sourceware.org/gdb/onlinedocs/gdb/Pretty-Printing.html +[pretty printing documentation]: https://sourceware.org/gdb/onlinedocs/gdb/Pretty-Printing.html +[_MetaListNameValueStr_]: ../attributes.md#meta-item-attribute-syntax