Skip to content

Commit

Permalink
debuginfo: Add GDB pretty printers for slices, Vec<>, and String.
Browse files Browse the repository at this point in the history
  • Loading branch information
michaelwoerister committed Mar 12, 2015
1 parent b2f09c1 commit 90fc28d
Show file tree
Hide file tree
Showing 2 changed files with 148 additions and 1 deletion.
89 changes: 88 additions & 1 deletion src/etc/gdb_rust_pretty_printing.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,18 @@ def rust_pretty_printer_lookup_function(val):
if type_code == gdb.TYPE_CODE_STRUCT:
struct_kind = classify_struct(val.type)

if struct_kind == STRUCT_KIND_SLICE:
return RustSlicePrinter(val)

if struct_kind == STRUCT_KIND_STR_SLICE:
return RustStringSlicePrinter(val)

if struct_kind == STRUCT_KIND_STD_VEC:
return RustStdVecPrinter(val)

if struct_kind == STRUCT_KIND_STD_STRING:
return RustStdStringPrinter(val)

if struct_kind == STRUCT_KIND_TUPLE:
return RustTuplePrinter(val)

Expand Down Expand Up @@ -172,6 +181,28 @@ def children(self):
def display_hint(self):
return "array"

class RustSlicePrinter:
def __init__(self, val):
self.val = val

def display_hint(self):
return "array"

def to_string(self):
length = int(self.val["length"])
return self.val.type.tag + ("(len: %i)" % length)

def children(self):
cs = []
length = int(self.val["length"])
data_ptr = self.val["data_ptr"]
assert data_ptr.type.code == gdb.TYPE_CODE_PTR
pointee_type = data_ptr.type.target()

for index in range(0, length):
cs.append((str(index), (data_ptr + index).dereference()))

return cs

class RustStringSlicePrinter:
def __init__(self, val):
Expand All @@ -181,6 +212,35 @@ def to_string(self):
slice_byte_len = self.val["length"]
return '"%s"' % self.val["data_ptr"].string(encoding="utf-8", length=slice_byte_len)

class RustStdVecPrinter:
def __init__(self, val):
self.val = val

def display_hint(self):
return "array"

def to_string(self):
length = int(self.val["len"])
cap = int(self.val["cap"])
return self.val.type.tag + ("(len: %i, cap: %i)" % (length, cap))

def children(self):
cs = []
(length, data_ptr) = extract_length_and_data_ptr_from_std_vec(self.val)
pointee_type = data_ptr.type.target()

for index in range(0, length):
cs.append((str(index), (data_ptr + index).dereference()))
return cs

class RustStdStringPrinter:
def __init__(self, val):
self.val = val

def to_string(self):
(length, data_ptr) = extract_length_and_data_ptr_from_std_vec(self.val["vec"])
return '"%s"' % data_ptr.string(encoding="utf-8", length=length)


class RustCStyleEnumPrinter:
def __init__(self, val):
Expand All @@ -204,19 +264,38 @@ def to_string(self):
STRUCT_KIND_TUPLE_VARIANT = 3
STRUCT_KIND_STRUCT_VARIANT = 4
STRUCT_KIND_CSTYLE_VARIANT = 5
STRUCT_KIND_STR_SLICE = 6
STRUCT_KIND_SLICE = 6
STRUCT_KIND_STR_SLICE = 7
STRUCT_KIND_STD_VEC = 8
STRUCT_KIND_STD_STRING = 9


def classify_struct(type):
# print("\nclassify_struct: tag=%s\n" % type.tag)
if type.tag == "&str":
return STRUCT_KIND_STR_SLICE

if type.tag.startswith("&[") and type.tag.endswith("]"):
return STRUCT_KIND_SLICE

fields = list(type.fields())
field_count = len(fields)

if field_count == 0:
return STRUCT_KIND_REGULAR_STRUCT

if (field_count == 3 and
fields[0].name == "ptr" and
fields[1].name == "len" and
fields[2].name == "cap" and
type.tag.startswith("Vec<")):
return STRUCT_KIND_STD_VEC

if (field_count == 1 and
fields[0].name == "vec" and
type.tag == "String"):
return STRUCT_KIND_STD_STRING

if fields[0].name == "RUST$ENUM$DISR":
if field_count == 1:
return STRUCT_KIND_CSTYLE_VARIANT
Expand Down Expand Up @@ -254,3 +333,11 @@ def get_field_at_index(val, index):
return field
i += 1
return None

def extract_length_and_data_ptr_from_std_vec(vec_val):
length = int(vec_val["len"])
vec_ptr_val = vec_val["ptr"]
unique_ptr_val = vec_ptr_val[first_field(vec_ptr_val)]
data_ptr = unique_ptr_val[first_field(unique_ptr_val)]
assert data_ptr.type.code == gdb.TYPE_CODE_PTR
return (length, data_ptr)
60 changes: 60 additions & 0 deletions src/test/debuginfo/gdb-pretty-std.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// Copyright 2013-2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// ignore-windows failing on win32 bot
// ignore-freebsd: gdb package too new
// ignore-tidy-linelength
// ignore-lldb
// ignore-android: FIXME(#10381)
// compile-flags:-g
// min-gdb-version 7.7

// gdb-command: run

// gdb-command: print slice
// gdb-check:$1 = &[i32](len: 4) = {0, 1, 2, 3}

// gdb-command: print vec
// gdb-check:$2 = Vec<u64>(len: 4, cap: [...]) = {4, 5, 6, 7}

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

// gdb-command: print string
// gdb-check:$4 = "IAMA string!"

// gdb-command: print some
// gdb-check:$5 = Some = {8}

// gdb-command: print none
// gdb-check:$6 = None

fn main() {

// &[]
let slice: &[i32] = &[0, 1, 2, 3];

// Vec
let vec = vec![4u64, 5, 6, 7];

// &str
let str_slice = "IAMA string slice!";

// String
let string = "IAMA string!".to_string();

// Option
let some = Some(8i16);
let none: Option<i64> = None;

zzz(); // #break
}

fn zzz() { () }

0 comments on commit 90fc28d

Please sign in to comment.