Skip to content

debuginfo: Make LLDB pretty printer correctly handle zero-sized fields. #23307

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 1 commit into from
Mar 13, 2015
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
98 changes: 77 additions & 21 deletions src/etc/lldb_rust_formatters.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,31 +40,12 @@ def print_struct_val(val, internal_dict):

if is_vec_slice(val):
return print_vec_slice_val(val, internal_dict)
elif is_std_vec(val):
return print_std_vec_val(val, internal_dict)
else:
return print_struct_val_starting_from(0, val, internal_dict)


def print_vec_slice_val(val, internal_dict):
length = val.GetChildAtIndex(1).GetValueAsUnsigned()

data_ptr_val = val.GetChildAtIndex(0)
data_ptr_type = data_ptr_val.GetType()
assert data_ptr_type.IsPointerType()

element_type = data_ptr_type.GetPointeeType()
element_type_size = element_type.GetByteSize()

start_address = data_ptr_val.GetValueAsUnsigned()

def render_element(i):
address = start_address + i * element_type_size
element_val = val.CreateValueFromAddress(val.GetName() +
("[%s]" % i), address, element_type)
return print_val(element_val, internal_dict)

return "&[%s]" % (', '.join([render_element(i) for i in range(length)]))


def print_struct_val_starting_from(field_start_index, val, internal_dict):
'''
Prints a struct, tuple, or tuple struct value with Rust syntax.
Expand Down Expand Up @@ -100,6 +81,16 @@ def render_child(child_index):
this += field_name + ": "

field_val = val.GetChildAtIndex(child_index)

if not field_val.IsValid():
field = t.GetFieldAtIndex(child_index)
# LLDB is not good at handling zero-sized values, so we have to help
# it a little
if field.GetType().GetByteSize() == 0:
return this + extract_type_name(field.GetType().GetName())
else:
return this + "<invalid value>"

return this + print_val(field_val, internal_dict)

body = separator.join([render_child(idx) for idx in range(field_start_index, num_children)])
Expand Down Expand Up @@ -195,6 +186,30 @@ def print_fixed_size_vec_val(val, internal_dict):
return output


def print_vec_slice_val(val, internal_dict):
length = val.GetChildAtIndex(1).GetValueAsUnsigned()

data_ptr_val = val.GetChildAtIndex(0)
data_ptr_type = data_ptr_val.GetType()

return "&[%s]" % print_array_of_values(val.GetName(),
data_ptr_val,
length,
internal_dict)


def print_std_vec_val(val, internal_dict):
length = val.GetChildAtIndex(1).GetValueAsUnsigned()

# Vec<> -> Unique<> -> NonZero<> -> *T
data_ptr_val = val.GetChildAtIndex(0).GetChildAtIndex(0).GetChildAtIndex(0)
data_ptr_type = data_ptr_val.GetType()

return "vec![%s]" % print_array_of_values(val.GetName(),
data_ptr_val,
length,
internal_dict)

#=--------------------------------------------------------------------------------------------------
# Helper Functions
#=--------------------------------------------------------------------------------------------------
Expand Down Expand Up @@ -243,3 +258,44 @@ def is_vec_slice(val):

type_name = extract_type_name(ty.GetName()).replace("&'static", "&").replace(" ", "")
return type_name.startswith("&[") and type_name.endswith("]")

def is_std_vec(val):
ty = val.GetType()
if ty.GetTypeClass() != lldb.eTypeClassStruct:
return False

if ty.GetNumberOfFields() != 3:
return False

if ty.GetFieldAtIndex(0).GetName() != "ptr":
return False

if ty.GetFieldAtIndex(1).GetName() != "len":
return False

if ty.GetFieldAtIndex(2).GetName() != "cap":
return False

return ty.GetName().startswith("collections::vec::Vec<")


def print_array_of_values(array_name, data_ptr_val, length, internal_dict):
'''Prints a contigous memory range, interpreting it as values of the
pointee-type of data_ptr_val.'''

data_ptr_type = data_ptr_val.GetType()
assert data_ptr_type.IsPointerType()

element_type = data_ptr_type.GetPointeeType()
element_type_size = element_type.GetByteSize()

start_address = data_ptr_val.GetValueAsUnsigned()

def render_element(i):
address = start_address + i * element_type_size
element_val = data_ptr_val.CreateValueFromAddress(array_name + ("[%s]" % i),
address,
element_type)
return print_val(element_val, internal_dict)

return ', '.join([render_element(i) for i in range(length)])
57 changes: 57 additions & 0 deletions src/test/debuginfo/issue22656.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// 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.


// This test makes sure that the LLDB pretty printer does not throw an exception
// when trying to handle a Vec<> or anything else that contains zero-sized
// fields.

// min-lldb-version: 310
// ignore-gdb
// ignore-tidy-linelength

// compile-flags:-g

// === LLDB TESTS ==================================================================================
// lldb-command:run

// lldb-command:print v
// lldb-check:[...]$0 = vec![1, 2, 3]
// lldb-command:print zs
// lldb-check:[...]$1 = StructWithZeroSizedField { x: ZeroSizedStruct, y: 123, z: ZeroSizedStruct, w: 456 }
// lldb-command:continue

#![allow(unused_variables)]
#![allow(dead_code)]
#![omit_gdb_pretty_printer_section]

struct ZeroSizedStruct;

struct StructWithZeroSizedField {
x: ZeroSizedStruct,
y: u32,
z: ZeroSizedStruct,
w: u64
}

fn main() {
let v = vec![1,2,3];

let zs = StructWithZeroSizedField {
x: ZeroSizedStruct,
y: 123,
z: ZeroSizedStruct,
w: 456
};

zzz(); // #break
}

fn zzz() { () }