Skip to content

Support pretty printing slices using GDB #85363

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jul 8, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions src/etc/gdb_lookup.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
from rust_types import *


rust_enabled = 'set language rust' in gdb.execute('complete set language ru', to_string=True)
_gdb_version_matched = re.search('([0-9]+)\\.([0-9]+)', gdb.VERSION)
gdb_version = [int(num) for num in _gdb_version_matched.groups()] if _gdb_version_matched else []

Expand Down Expand Up @@ -52,9 +51,10 @@ def lookup(valobj):
return StdStringProvider(valobj)
if rust_type == RustType.STD_OS_STRING:
return StdOsStringProvider(valobj)
if rust_type == RustType.STD_STR and not rust_enabled:
if rust_type == RustType.STD_STR:
return StdStrProvider(valobj)

if rust_type == RustType.STD_SLICE:
return StdSliceProvider(valobj)
if rust_type == RustType.STD_VEC:
return StdVecProvider(valobj)
if rust_type == RustType.STD_VEC_DEQUE:
Expand Down
55 changes: 39 additions & 16 deletions src/etc/gdb_providers.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,39 @@ def to_string(self):
def display_hint():
return "string"

def _enumerate_array_elements(element_ptrs):
for (i, element_ptr) in enumerate(element_ptrs):
key = "[{}]".format(i)
element = element_ptr.dereference()

try:
# rust-lang/rust#64343: passing deref expr to `str` allows
# catching exception on garbage pointer
str(element)
except RuntimeError:
yield key, "inaccessible"

break

yield key, element

class StdSliceProvider:
def __init__(self, valobj):
self.valobj = valobj
self.length = int(valobj["length"])
self.data_ptr = valobj["data_ptr"]

def to_string(self):
return "{}(size={})".format(self.valobj.type, self.length)

def children(self):
return _enumerate_array_elements(
self.data_ptr + index for index in xrange(self.length)
)

@staticmethod
def display_hint():
return "array"

class StdVecProvider:
def __init__(self, valobj):
Expand All @@ -96,19 +129,9 @@ def to_string(self):
return "Vec(size={})".format(self.length)

def children(self):
saw_inaccessible = False
for index in xrange(self.length):
element_ptr = self.data_ptr + index
if saw_inaccessible:
return
try:
# rust-lang/rust#64343: passing deref expr to `str` allows
# catching exception on garbage pointer
str(element_ptr.dereference())
yield "[{}]".format(index), element_ptr.dereference()
except RuntimeError:
saw_inaccessible = True
yield str(index), "inaccessible"
return _enumerate_array_elements(
self.data_ptr + index for index in xrange(self.length)
)

@staticmethod
def display_hint():
Expand All @@ -131,9 +154,9 @@ def to_string(self):
return "VecDeque(size={})".format(self.size)

def children(self):
for index in xrange(0, self.size):
value = (self.data_ptr + ((self.tail + index) % self.cap)).dereference()
yield "[{}]".format(index), value
return _enumerate_array_elements(
(self.data_ptr + ((self.tail + index) % self.cap)) for index in xrange(self.size)
)

@staticmethod
def display_hint():
Expand Down
4 changes: 2 additions & 2 deletions src/etc/lldb_commands
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
type synthetic add -l lldb_lookup.synthetic_lookup -x ".*" --category Rust
type summary add -F lldb_lookup.summary_lookup -e -x -h "^(alloc::([a-z_]+::)+)String$" --category Rust
type summary add -F lldb_lookup.summary_lookup -e -x -h "^&str$" --category Rust
type summary add -F lldb_lookup.summary_lookup -e -x -h "^&\\[.+\\]$" --category Rust
type summary add -F lldb_lookup.summary_lookup -e -x -h "^&(mut )?str$" --category Rust
type summary add -F lldb_lookup.summary_lookup -e -x -h "^&(mut )?\\[.+\\]$" --category Rust
type summary add -F lldb_lookup.summary_lookup -e -x -h "^(std::ffi::([a-z_]+::)+)OsString$" --category Rust
type summary add -F lldb_lookup.summary_lookup -e -x -h "^(alloc::([a-z_]+::)+)Vec<.+>$" --category Rust
type summary add -F lldb_lookup.summary_lookup -e -x -h "^(alloc::([a-z_]+::)+)VecDeque<.+>$" --category Rust
Expand Down
4 changes: 2 additions & 2 deletions src/etc/rust_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ class RustType(object):


STD_STRING_REGEX = re.compile(r"^(alloc::(\w+::)+)String$")
STD_STR_REGEX = re.compile(r"^&str$")
STD_SLICE_REGEX = re.compile(r"^&\[.+\]$")
STD_STR_REGEX = re.compile(r"^&(mut )?str$")
STD_SLICE_REGEX = re.compile(r"^&(mut )?\[.+\]$")
STD_OS_STRING_REGEX = re.compile(r"^(std::ffi::(\w+::)+)OsString$")
STD_VEC_REGEX = re.compile(r"^(alloc::(\w+::)+)Vec<.+>$")
STD_VEC_DEQUE_REGEX = re.compile(r"^(alloc::(\w+::)+)VecDeque<.+>$")
Expand Down
2 changes: 1 addition & 1 deletion src/test/debuginfo/pretty-huge-vec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
// gdb-check:$1 = Vec(size=1000000000) = {[...]...}

// gdb-command: print slice
// gdb-check:$2 = &[u8] {data_ptr: [...], length: 1000000000}
// gdb-check:$2 = &[u8](size=1000000000) = {[...]...}

#![allow(unused_variables)]

Expand Down
46 changes: 46 additions & 0 deletions src/test/debuginfo/pretty-slices.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// ignore-android: FIXME(#10381)
// ignore-windows
// compile-flags:-g

// gdb-command: run

// gdb-command: print slice
// gdbg-check: $1 = struct &[i32](size=3) = {0, 1, 2}
// gdbr-check: $1 = &[i32](size=3) = {0, 1, 2}

// gdb-command: print mut_slice
// gdbg-check: $2 = struct &mut [i32](size=4) = {2, 3, 5, 7}
// gdbr-check: $2 = &mut [i32](size=4) = {2, 3, 5, 7}

// gdb-command: print str_slice
// gdb-check: $3 = "string slice"

// gdb-command: print mut_str_slice
// gdb-check: $4 = "mutable string slice"

// lldb-command: run

// lldb-command: print slice
// lldb-check: (&[i32]) $0 = size=3 { [0] = 0 [1] = 1 [2] = 2 }

// lldb-command: print mut_slice
// lldb-check: (&mut [i32]) $1 = size=4 { [0] = 2 [1] = 3 [2] = 5 [3] = 7 }

// lldb-command: print str_slice
// lldb-check: (&str) $2 = "string slice" { data_ptr = [...] length = 12 }

// lldb-command: print mut_str_slice
// lldb-check: (&mut str) $3 = "mutable string slice" { data_ptr = [...] length = 20 }

fn b() {}

fn main() {
let slice: &[i32] = &[0, 1, 2];
let mut_slice: &mut [i32] = &mut [2, 3, 5, 7];

let str_slice: &str = "string slice";
let mut mut_str_slice_buffer = String::from("mutable string slice");
let mut_str_slice: &mut str = mut_str_slice_buffer.as_mut_str();

b(); // #break
}
4 changes: 2 additions & 2 deletions src/tools/compiletest/src/runtest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1133,8 +1133,8 @@ impl<'test> TestCx<'test> {

let rust_type_regexes = vec![
"^(alloc::([a-z_]+::)+)String$",
"^&str$",
"^&\\[.+\\]$",
"^&(mut )?str$",
"^&(mut )?\\[.+\\]$",
"^(std::ffi::([a-z_]+::)+)OsString$",
"^(alloc::([a-z_]+::)+)Vec<.+>$",
"^(alloc::([a-z_]+::)+)VecDeque<.+>$",
Expand Down