diff --git a/src/etc/lldb_rust_formatters.py b/src/etc/lldb_rust_formatters.py index 42c83b6a42e..20f9b1ce66c 100644 --- a/src/etc/lldb_rust_formatters.py +++ b/src/etc/lldb_rust_formatters.py @@ -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. @@ -100,6 +81,16 @@ def print_struct_val_starting_from(field_start_index, val, internal_dict): 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 + "" + return this + print_val(field_val, internal_dict) body = separator.join([render_child(idx) for idx in range(field_start_index, num_children)]) @@ -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 #=-------------------------------------------------------------------------------------------------- @@ -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)]) diff --git a/src/test/debuginfo/issue22656.rs b/src/test/debuginfo/issue22656.rs new file mode 100644 index 00000000000..af518797d19 --- /dev/null +++ b/src/test/debuginfo/issue22656.rs @@ -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 or the MIT license +// , 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() { () }