Rollup merge of #97028 - ridwanabdillahi:pretty-printer, r=michaelwoerister
Add support for embedding pretty printers via `#[debugger_visualizer]` attribute Initial support for [RFC 3191](https://github.com/rust-lang/rfcs/pull/3191) in PR https://github.com/rust-lang/rust/pull/91779 was scoped to supporting embedding NatVis files using a new attribute. This PR implements the pretty printer support as stated in the RFC mentioned above. This change includes embedding pretty printers in the `.debug_gdb_scripts` just as the pretty printers for rustc are embedded today. Also added additional tests for embedded pretty printers. Additionally cleaned up error checking so all error checking is done up front regardless of the current target. RFC: https://github.com/rust-lang/rfcs/pull/3191
This commit is contained in:
commit
239287f013
27 changed files with 462 additions and 200 deletions
|
|
@ -14,6 +14,7 @@ to embed a debugger visualizer file into the PDB/ELF generated by `rustc`.
|
|||
``` rust,ignore (partial-example)
|
||||
#![feature(debugger_visualizer)]
|
||||
#![debugger_visualizer(natvis_file = "foo.natvis")]
|
||||
#![debugger_visualizer(gdb_script_file = "foo.py")]
|
||||
struct Foo {
|
||||
|
||||
}
|
||||
|
|
@ -22,4 +23,5 @@ struct Foo {
|
|||
## Limitations
|
||||
|
||||
Currently, this feature only supports embedding Natvis files on `-windows-msvc`
|
||||
targets when using the MSVC linker via the `natvis_file` meta item.
|
||||
targets via the `natvis_file` meta item. `-windows-gnu` targets are not currently
|
||||
supported.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
|
||||
<Type Name="dependency_with_embedded_visualizers::Person">
|
||||
<DisplayString>{name} is {age} years old.</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[name]">name</Item>
|
||||
<Item Name="[age]">age</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
</AutoVisualizer>
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
import gdb
|
||||
|
||||
class PersonPrinter:
|
||||
"Print a Person"
|
||||
|
||||
def __init__(self, val):
|
||||
self.val = val
|
||||
self.name = val["name"]
|
||||
self.age = int(val["age"])
|
||||
|
||||
def to_string(self):
|
||||
return "{} is {} years old.".format(self.name, self.age)
|
||||
|
||||
def lookup(val):
|
||||
lookup_tag = val.type.tag
|
||||
if lookup_tag is None:
|
||||
return None
|
||||
if "dependency_with_embedded_visualizers::Person" == lookup_tag:
|
||||
return PersonPrinter(val)
|
||||
|
||||
return None
|
||||
|
||||
gdb.current_objfile().pretty_printers.append(lookup)
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
// compile-flags:-g
|
||||
// ignore-lldb
|
||||
// no-prefer-dynamic
|
||||
|
||||
#![feature(debugger_visualizer)]
|
||||
#![debugger_visualizer(natvis_file = "dependency-with-embedded-visualizers.natvis")]
|
||||
#![debugger_visualizer(gdb_script_file = "dependency-with-embedded-visualizers.py")]
|
||||
#![crate_type = "rlib"]
|
||||
|
||||
pub struct Person {
|
||||
name: String,
|
||||
age: i32,
|
||||
}
|
||||
|
||||
impl Person {
|
||||
pub fn new(name: String, age: i32) -> Person {
|
||||
Person { name: name, age: age }
|
||||
}
|
||||
}
|
||||
|
|
@ -1,18 +1,10 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
|
||||
<Type Name="msvc_embedded_natvis::Point">
|
||||
<Type Name="embedded_visualizer::point::Point">
|
||||
<DisplayString>({x}, {y})</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[x]">x</Item>
|
||||
<Item Name="[y]">y</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
|
||||
<Type Name="msvc_embedded_natvis::Line">
|
||||
<DisplayString>({a}, {b})</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[a]">a</Item>
|
||||
<Item Name="[b]">b</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
</AutoVisualizer>
|
||||
23
src/test/debuginfo/embedded-visualizer-point.py
Normal file
23
src/test/debuginfo/embedded-visualizer-point.py
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
import gdb
|
||||
|
||||
class PointPrinter:
|
||||
"Print a Point"
|
||||
|
||||
def __init__(self, val):
|
||||
self.val = val
|
||||
self.x = int(val["x"])
|
||||
self.y = int(val["y"])
|
||||
|
||||
def to_string(self):
|
||||
return "({}, {})".format(self.x, self.y)
|
||||
|
||||
def lookup(val):
|
||||
lookup_tag = val.type.tag
|
||||
if lookup_tag is None:
|
||||
return None
|
||||
if "embedded_visualizer::point::Point" == lookup_tag:
|
||||
return PointPrinter(val)
|
||||
|
||||
return None
|
||||
|
||||
gdb.current_objfile().pretty_printers.append(lookup)
|
||||
10
src/test/debuginfo/embedded-visualizer.natvis
Normal file
10
src/test/debuginfo/embedded-visualizer.natvis
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
|
||||
<Type Name="embedded_visualizer::Line">
|
||||
<DisplayString>({a}, {b})</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[a]">a</Item>
|
||||
<Item Name="[b]">b</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
</AutoVisualizer>
|
||||
23
src/test/debuginfo/embedded-visualizer.py
Normal file
23
src/test/debuginfo/embedded-visualizer.py
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
import gdb
|
||||
|
||||
class LinePrinter:
|
||||
"Print a Line"
|
||||
|
||||
def __init__(self, val):
|
||||
self.val = val
|
||||
self.a = val["a"]
|
||||
self.b = val["b"]
|
||||
|
||||
def to_string(self):
|
||||
return "({}, {})".format(self.a, self.b)
|
||||
|
||||
def lookup(val):
|
||||
lookup_tag = val.type.tag
|
||||
if lookup_tag is None:
|
||||
return None
|
||||
if "embedded_visualizer::Line" == lookup_tag:
|
||||
return LinePrinter(val)
|
||||
|
||||
return None
|
||||
|
||||
gdb.current_objfile().pretty_printers.append(lookup)
|
||||
112
src/test/debuginfo/embedded-visualizer.rs
Normal file
112
src/test/debuginfo/embedded-visualizer.rs
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
// compile-flags:-g
|
||||
// min-gdb-version: 8.1
|
||||
// ignore-lldb
|
||||
|
||||
// === CDB TESTS ==================================================================================
|
||||
|
||||
// cdb-command: g
|
||||
|
||||
// The .nvlist command in cdb does not always have a deterministic output
|
||||
// for the order that NatVis files are displayed.
|
||||
|
||||
// cdb-command: .nvlist
|
||||
// cdb-check: [...].exe (embedded NatVis "[...]embedded_visualizer-0.natvis")
|
||||
|
||||
// cdb-command: .nvlist
|
||||
// cdb-check: [...].exe (embedded NatVis "[...]embedded_visualizer-1.natvis")
|
||||
|
||||
// cdb-command: .nvlist
|
||||
// cdb-check: [...].exe (embedded NatVis "[...]embedded_visualizer-2.natvis")
|
||||
|
||||
// cdb-command: dx point_a
|
||||
// cdb-check:point_a : (0, 0) [Type: embedded_visualizer::point::Point]
|
||||
// cdb-check: [<Raw View>] [Type: embedded_visualizer::point::Point]
|
||||
// cdb-check: [x] : 0 [Type: int]
|
||||
// cdb-check: [y] : 0 [Type: int]
|
||||
|
||||
// cdb-command: dx point_b
|
||||
// cdb-check:point_b : (5, 8) [Type: embedded_visualizer::point::Point]
|
||||
// cdb-check: [<Raw View>] [Type: embedded_visualizer::point::Point]
|
||||
// cdb-check: [x] : 5 [Type: int]
|
||||
// cdb-check: [y] : 8 [Type: int]
|
||||
|
||||
// cdb-command: dx line
|
||||
// cdb-check:line : ((0, 0), (5, 8)) [Type: embedded_visualizer::Line]
|
||||
// cdb-check: [<Raw View>] [Type: embedded_visualizer::Line]
|
||||
// cdb-check: [a] : (0, 0) [Type: embedded_visualizer::point::Point]
|
||||
// cdb-check: [b] : (5, 8) [Type: embedded_visualizer::point::Point]
|
||||
|
||||
// cdb-command: dx person
|
||||
// cdb-check:person : "Person A" is 10 years old. [Type: dependency_with_embedded_visualizers::Person]
|
||||
// cdb-check: [<Raw View>] [Type: dependency_with_embedded_visualizers::Person]
|
||||
// cdb-check: [name] : "Person A" [Type: alloc::string::String]
|
||||
// cdb-check: [age] : 10 [Type: int]
|
||||
|
||||
// === GDB TESTS ===================================================================================
|
||||
|
||||
// gdb-command: run
|
||||
|
||||
// gdb-command: info auto-load python-scripts
|
||||
// gdb-check:Yes pretty-printer-embedded_visualizer-0
|
||||
// gdb-check:Yes pretty-printer-embedded_visualizer-1
|
||||
// gdb-command: print point_a
|
||||
// gdb-check:$1 = (0, 0)
|
||||
// gdb-command: print point_b
|
||||
// gdb-check:$2 = (5, 8)
|
||||
// gdb-command: print line
|
||||
// gdb-check:$3 = ((0, 0), (5, 8))
|
||||
// gdb-command: print person
|
||||
// gdb-check:$4 = "Person A" is 10 years old.
|
||||
|
||||
#![allow(unused_variables)]
|
||||
#![feature(debugger_visualizer)]
|
||||
#![debugger_visualizer(natvis_file = "embedded-visualizer.natvis")]
|
||||
#![debugger_visualizer(gdb_script_file = "embedded-visualizer.py")]
|
||||
|
||||
// aux-build: dependency-with-embedded-visualizers.rs
|
||||
extern crate dependency_with_embedded_visualizers;
|
||||
|
||||
use dependency_with_embedded_visualizers::Person;
|
||||
|
||||
#[debugger_visualizer(natvis_file = "embedded-visualizer-point.natvis")]
|
||||
#[debugger_visualizer(gdb_script_file = "embedded-visualizer-point.py")]
|
||||
mod point {
|
||||
pub struct Point {
|
||||
x: i32,
|
||||
y: i32,
|
||||
}
|
||||
|
||||
impl Point {
|
||||
pub fn new(x: i32, y: i32) -> Point {
|
||||
Point { x: x, y: y }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
use point::Point;
|
||||
|
||||
pub struct Line {
|
||||
a: Point,
|
||||
b: Point,
|
||||
}
|
||||
|
||||
impl Line {
|
||||
pub fn new(a: Point, b: Point) -> Line {
|
||||
Line { a: a, b: b }
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let point_a = Point::new(0, 0);
|
||||
let point_b = Point::new(5, 8);
|
||||
let line = Line::new(point_a, point_b);
|
||||
|
||||
let name = String::from("Person A");
|
||||
let person = Person::new(name, 10);
|
||||
|
||||
zzz(); // #break
|
||||
}
|
||||
|
||||
fn zzz() {
|
||||
()
|
||||
}
|
||||
|
|
@ -1,64 +0,0 @@
|
|||
// only-cdb
|
||||
// compile-flags:-g
|
||||
|
||||
// === CDB TESTS ==================================================================================
|
||||
|
||||
// cdb-command: g
|
||||
|
||||
// cdb-command: .nvlist
|
||||
// cdb-check: [...].exe (embedded NatVis "[...]msvc_embedded_natvis-0.natvis")
|
||||
|
||||
// cdb-command: dx point_a
|
||||
// cdb-check:point_a : (0, 0) [Type: msvc_embedded_natvis::Point]
|
||||
// cdb-check: [<Raw View>] [Type: msvc_embedded_natvis::Point]
|
||||
// cdb-check: [x] : 0 [Type: int]
|
||||
// cdb-check: [y] : 0 [Type: int]
|
||||
|
||||
// cdb-command: dx point_b
|
||||
// cdb-check:point_b : (5, 8) [Type: msvc_embedded_natvis::Point]
|
||||
// cdb-check: [<Raw View>] [Type: msvc_embedded_natvis::Point]
|
||||
// cdb-check: [x] : 5 [Type: int]
|
||||
// cdb-check: [y] : 8 [Type: int]
|
||||
|
||||
// cdb-command: dx line
|
||||
// cdb-check:line : ((0, 0), (5, 8)) [Type: msvc_embedded_natvis::Line]
|
||||
// cdb-check: [<Raw View>] [Type: msvc_embedded_natvis::Line]
|
||||
// cdb-check: [a] : (0, 0) [Type: msvc_embedded_natvis::Point]
|
||||
// cdb-check: [b] : (5, 8) [Type: msvc_embedded_natvis::Point]
|
||||
|
||||
#![feature(debugger_visualizer)]
|
||||
#![debugger_visualizer(natvis_file = "msvc-embedded-natvis.natvis")]
|
||||
|
||||
pub struct Point {
|
||||
x: i32,
|
||||
y: i32,
|
||||
}
|
||||
|
||||
impl Point {
|
||||
pub fn new(x: i32, y: i32) -> Point {
|
||||
Point { x: x, y: y }
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Line {
|
||||
a: Point,
|
||||
b: Point,
|
||||
}
|
||||
|
||||
impl Line {
|
||||
pub fn new(a: Point, b: Point) -> Line {
|
||||
Line { a: a, b: b }
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let point_a = Point::new(0, 0);
|
||||
let point_b = Point::new(5, 8);
|
||||
let line = Line::new(point_a, point_b);
|
||||
|
||||
zzz(); // #break
|
||||
}
|
||||
|
||||
fn zzz() {
|
||||
()
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
|
||||
</AutoVisualizer>
|
||||
|
|
@ -1,3 +1,3 @@
|
|||
#![debugger_visualizer(natvis_file = "../foo.natvis")] //~ ERROR the `#[debugger_visualizer]` attribute is an experimental feature
|
||||
#![debugger_visualizer(natvis_file = "auxiliary/debugger-visualizer.natvis")] //~ ERROR the `#[debugger_visualizer]` attribute is an experimental feature
|
||||
|
||||
fn main() {}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
error[E0658]: the `#[debugger_visualizer]` attribute is an experimental feature
|
||||
--> $DIR/feature-gate-debugger-visualizer.rs:1:1
|
||||
|
|
||||
LL | #![debugger_visualizer(natvis_file = "../foo.natvis")]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
LL | #![debugger_visualizer(natvis_file = "auxiliary/debugger-visualizer.natvis")]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: see issue #95939 <https://github.com/rust-lang/rust/issues/95939> for more information
|
||||
= help: add `#![feature(debugger_visualizer)]` to the crate attributes to enable
|
||||
|
|
|
|||
|
|
@ -1,4 +1,7 @@
|
|||
// normalize-stderr-test: "foo.random:.*\(" -> "foo.random: $$FILE_NOT_FOUND_MSG ("
|
||||
// normalize-stderr-test: "os error \d+" -> "os error $$FILE_NOT_FOUND_CODE"
|
||||
|
||||
#![feature(debugger_visualizer)]
|
||||
#![debugger_visualizer(random_file = "../foo.random")] //~ ERROR invalid argument
|
||||
|
||||
#![debugger_visualizer(natvis_file = "../foo.random")] //~ ERROR
|
||||
fn main() {}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,18 @@
|
|||
error: invalid argument
|
||||
--> $DIR/invalid-debugger-visualizer-option.rs:2:1
|
||||
--> $DIR/invalid-debugger-visualizer-option.rs:5:24
|
||||
|
|
||||
LL | #![debugger_visualizer(random_file = "../foo.random")]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: expected: `natvis_file = "..."`
|
||||
= note: OR
|
||||
= note: expected: `gdb_script_file = "..."`
|
||||
|
||||
error: aborting due to previous error
|
||||
error: couldn't read $DIR/../foo.random: $FILE_NOT_FOUND_MSG (os error $FILE_NOT_FOUND_CODE)
|
||||
--> $DIR/invalid-debugger-visualizer-option.rs:6:24
|
||||
|
|
||||
LL | #![debugger_visualizer(natvis_file = "../foo.random")]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
#![feature(debugger_visualizer)]
|
||||
|
||||
#[debugger_visualizer(natvis_file = "../foo.natvis")] //~ ERROR attribute should be applied to a module
|
||||
|
||||
fn main() {}
|
||||
|
|
|
|||
|
|
@ -929,6 +929,16 @@ impl<'test> TestCx<'test> {
|
|||
"add-auto-load-safe-path {}\n",
|
||||
rust_pp_module_abs_path.replace(r"\", r"\\")
|
||||
));
|
||||
|
||||
let output_base_dir = self.output_base_dir().to_str().unwrap().to_owned();
|
||||
|
||||
// Add the directory containing the output binary to
|
||||
// include embedded pretty printers to GDB's script
|
||||
// auto loading safe path
|
||||
script_str.push_str(&format!(
|
||||
"add-auto-load-safe-path {}\n",
|
||||
output_base_dir.replace(r"\", r"\\")
|
||||
));
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue