Skip to content

Commit e76034c

Browse files
committed
Auto merge of #124500 - VladimirMakaev:lldb-str-formatters, r=Mark-Simulacrum
lldb-formatters: Use StdSliceSyntheticProvider for &str &str has associated summary provider which correctly displays string values in debugger, but while working on #124458 I've noticed that a &str inside an enum displays a blob of memory until a 0 is reached (as a c-string) which makes a very bizarre experience when debugging However there is already StdSliceSyntheticProvider which we use for other slices. This PR enables the same synthetic provider to be used for &str, however the summary provider is still fixed to return the string value I've added a test `debuginfo/strings-and-strs.rs` which prior to this PR would output the following in LLDB: ``` * thread #1, name = 'a', stop reason = breakpoint 1.1 frame #0: 0x0000555555556383 a`strings_and_strs::main::h1d2b5f9227b8767d at strings-and-strs.rs:47:5 44 let plain_str = "Hello"; 45 let str_in_struct = Foo { inner: "Hello" }; 46 let str_in_tuple = ("Hello", "World"); -> 47 zzz(); // #break 48 } 49 50 fn zzz() { (lldb) frame var (alloc::string::String) plain_string = "Hello" { vec = size=5 { [0] = 'H' [1] = 'e' [2] = 'l' [3] = 'l' [4] = 'o' } } (&str) plain_str = "Hello" { data_ptr = 0x0000555555557263 "HelloWorld\U00000001gdb_load_rust_pretty_printers.py" length = 5 } (strings_and_strs::Foo) str_in_struct = { inner = "Hello" { data_ptr = 0x0000555555557263 "HelloWorld\U00000001gdb_load_rust_pretty_printers.py" length = 5 } } ((&str, &str)) str_in_tuple = { 0 = "Hello" { data_ptr = 0x0000555555557263 "HelloWorld\U00000001gdb_load_rust_pretty_printers.py" length = 5 } 1 = "World" { data_ptr = 0x0000555555557268 "World\U00000001gdb_load_rust_pretty_printers.py" length = 5 } } ``` After this PR it would look the following way: ``` * thread #1, name = 'a', stop reason = breakpoint 1.1 frame #0: 0x0000555555556383 a`strings_and_strs::main::h1d2b5f9227b8767d at strings-and-strs.rs:47:5 44 let plain_str = "Hello"; 45 let str_in_struct = Foo { inner: "Hello" }; 46 let str_in_tuple = ("Hello", "World"); -> 47 zzz(); // #break 48 } 49 50 fn zzz() { (lldb) frame var (alloc::string::String) plain_string = "Hello" { vec = size=5 { [0] = 'H' [1] = 'e' [2] = 'l' [3] = 'l' [4] = 'o' } } (&str) plain_str = "Hello" { [0] = 'H' [1] = 'e' [2] = 'l' [3] = 'l' [4] = 'o' } (strings_and_strs::Foo) str_in_struct = { inner = "Hello" { [0] = 'H' [1] = 'e' [2] = 'l' [3] = 'l' [4] = 'o' } } ((&str, &str)) str_in_tuple = { 0 = "Hello" { [0] = 'H' [1] = 'e' [2] = 'l' [3] = 'l' [4] = 'o' } 1 = "World" { [0] = 'W' [1] = 'o' [2] = 'r' [3] = 'l' [4] = 'd' } } ```
2 parents ef15976 + 5b2be36 commit e76034c

File tree

5 files changed

+69
-4
lines changed

5 files changed

+69
-4
lines changed

src/etc/lldb_lookup.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ def synthetic_lookup(valobj, dict):
9292
return StdVecSyntheticProvider(valobj, dict)
9393
if rust_type == RustType.STD_VEC_DEQUE:
9494
return StdVecDequeSyntheticProvider(valobj, dict)
95-
if rust_type == RustType.STD_SLICE:
95+
if rust_type == RustType.STD_SLICE or rust_type == RustType.STD_STR:
9696
return StdSliceSyntheticProvider(valobj, dict)
9797

9898
if rust_type == RustType.STD_HASH_MAP:

src/etc/lldb_providers.py

+3
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,9 @@ def StdStrSummaryProvider(valobj, dict):
159159
# logger = Logger.Logger()
160160
# logger >> "[StdStrSummaryProvider] for " + str(valobj.GetName())
161161

162+
# the code below assumes non-synthetic value, this makes sure the assumption holds
163+
valobj = valobj.GetNonSyntheticValue()
164+
162165
length = valobj.GetChildMemberWithName("length").GetValueAsUnsigned()
163166
if length == 0:
164167
return '""'

tests/debuginfo/empty-string.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
// lldb-check:[...] empty_string = "" { vec = size=0 }
2424

2525
// lldb-command:fr v empty_str
26-
// lldb-check:[...] empty_str = "" { data_ptr = [...] length = 0 }
26+
// lldb-check:[...] empty_str = ""
2727

2828
fn main() {
2929
let empty_string = String::new();

tests/debuginfo/pretty-slices.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,10 @@
2727
// lldb-check:(&mut [i32]) mut_slice = size=4 { [0] = 2 [1] = 3 [2] = 5 [3] = 7 }
2828

2929
// lldb-command:v str_slice
30-
// lldb-check:(&str) str_slice = "string slice" { data_ptr = [...] length = 12 }
30+
// lldb-check:(&str) str_slice = "string slice" { [0] = 's' [1] = 't' [2] = 'r' [3] = 'i' [4] = 'n' [5] = 'g' [6] = ' ' [7] = 's' [8] = 'l' [9] = 'i' [10] = 'c' [11] = 'e' }
3131

3232
// lldb-command:v mut_str_slice
33-
// lldb-check:(&mut str) mut_str_slice = "mutable string slice" { data_ptr = [...] length = 20 }
33+
// lldb-check:(&mut str) mut_str_slice = "mutable string slice" { [0] = 'm' [1] = 'u' [2] = 't' [3] = 'a' [4] = 'b' [5] = 'l' [6] = 'e' [7] = ' ' [8] = 's' [9] = 't' [10] = 'r' [11] = 'i' [12] = 'n' [13] = 'g' [14] = ' ' [15] = 's' [16] = 'l' [17] = 'i' [18] = 'c' [19] = 'e' }
3434

3535
fn b() {}
3636

tests/debuginfo/strings-and-strs.rs

+62
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
// Require a gdb or lldb that can read DW_TAG_variant_part.
2+
//@ min-gdb-version: 8.2
3+
//@ min-lldb-version: 1800
4+
5+
//@ compile-flags:-g
6+
7+
// === GDB TESTS ===================================================================================
8+
// gdb-command:run
9+
10+
// gdb-command:print plain_string
11+
// gdbr-check:$1 = "Hello"
12+
13+
// gdb-command:print plain_str
14+
// gdbr-check:$2 = "Hello"
15+
16+
// gdb-command:print str_in_struct
17+
// gdbr-check:$3 = strings_and_strs::Foo {inner: "Hello"}
18+
19+
// gdb-command:print str_in_tuple
20+
// gdbr-check:$4 = ("Hello", "World")
21+
22+
// gdb-command:print str_in_rc
23+
// gdbr-check:$5 = Rc(strong=1, weak=0) = {value = "Hello", strong = 1, weak = 0}
24+
25+
26+
// === LLDB TESTS ==================================================================================
27+
// lldb-command:run
28+
// lldb-command:v plain_string
29+
// lldbg-check:(alloc::string::String) plain_string = "Hello" { vec = size=5 { [0] = 'H' [1] = 'e' [2] = 'l' [3] = 'l' [4] = 'o' } }
30+
31+
// lldb-command:v plain_str
32+
// lldbg-check:(&str) plain_str = "Hello" { [0] = 'H' [1] = 'e' [2] = 'l' [3] = 'l' [4] = 'o' }
33+
34+
// lldb-command:v str_in_struct
35+
// lldbg-check:((&str, &str)) str_in_tuple = { 0 = "Hello" { [0] = 'H' [1] = 'e' [2] = 'l' [3] = 'l' [4] = 'o' } 1 = "World" { [0] = 'W' [1] = 'o' [2] = 'r' [3] = 'l' [4] = 'd' } }
36+
37+
// lldb-command:v str_in_tuple
38+
// lldbg-check:((&str, &str)) str_in_tuple = { 0 = "Hello" { [0] = 'H' [1] = 'e' [2] = 'l' [3] = 'l' [4] = 'o' } 1 = "World" { [0] = 'W' [1] = 'o' [2] = 'r' [3] = 'l' [4] = 'd' } }
39+
40+
// lldb-command:v str_in_rc
41+
// lldbg-check:(alloc::rc::Rc<&str, alloc::alloc::Global>) str_in_rc = strong=1, weak=0 { value = "Hello" { [0] = 'H' [1] = 'e' [2] = 'l' [3] = 'l' [4] = 'o' } }
42+
43+
44+
#![allow(unused_variables)]
45+
46+
pub struct Foo<'a> {
47+
inner: &'a str,
48+
}
49+
50+
fn main() {
51+
let plain_string = String::from("Hello");
52+
let plain_str = "Hello";
53+
let str_in_struct = Foo { inner: "Hello" };
54+
let str_in_tuple = ("Hello", "World");
55+
56+
let str_in_rc = std::rc::Rc::new("Hello");
57+
zzz(); // #break
58+
}
59+
60+
fn zzz() {
61+
()
62+
}

0 commit comments

Comments
 (0)