about summary refs log tree commit diff
diff options
context:
space:
mode:
authorTom Tromey <tom@tromey.com>2017-05-27 13:46:42 -0600
committerTom Tromey <tom@tromey.com>2017-11-15 01:48:14 -0700
commitae4cc6069626206b493caf6b1158d3d5d601bbc7 (patch)
treec3c653d637dd0b24ec1f2395d64b252c2b6eefcd
parenta5122281416e2c627c0610096ea3064a01bc2bb0 (diff)
downloadrust-ae4cc6069626206b493caf6b1158d3d5d601bbc7.tar.gz
rust-ae4cc6069626206b493caf6b1158d3d5d601bbc7.zip
Emit debug info for trait object pointer
Emit better debugging information for a trait object pointer.  In
particular, now:

* The fields are explicitly represented in the DWARF;
* DWARF for the vtable itself is emitted; and
* The DWARF for the vtable's type has a DW_AT_containing_type which
  points to the concrete type for which the vtable was emitted.  This is
  a small DWARF extension, that allows debuggers to determine the real
  type of the object to which a trait object points.

I'll submit the gdb patch to take advantage of this new debuginfo once
this lands.

The vtable type is not currently complete -- it doesn't include members
for the pointers it contains.  This information was not needed for this
feature.

This addresses part 1 of #1563.
-rw-r--r--src/librustc_trans/debuginfo/metadata.rs92
-rw-r--r--src/librustc_trans/debuginfo/mod.rs1
-rw-r--r--src/librustc_trans/meth.rs3
m---------src/llvm0
-rw-r--r--src/test/codegen/vtabletype.rs33
5 files changed, 128 insertions, 1 deletions
diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs
index 4f07af9071d..a68390eab7f 100644
--- a/src/librustc_trans/debuginfo/metadata.rs
+++ b/src/librustc_trans/debuginfo/metadata.rs
@@ -18,6 +18,7 @@ use super::utils::{debug_context, DIB, span_start, bytes_to_bits, size_and_align
 use super::namespace::mangled_name_of_item;
 use super::type_names::compute_debuginfo_type_name;
 use super::{CrateDebugContext};
+use abi;
 use context::SharedCrateContext;
 
 use llvm::{self, ValueRef};
@@ -438,11 +439,38 @@ fn trait_pointer_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
     let trait_llvm_type = type_of::type_of(cx, trait_object_type);
     let file_metadata = unknown_file_metadata(cx);
 
+
+    let ptr_type = cx.tcx().mk_ptr(ty::TypeAndMut {
+        ty: cx.tcx().types.u8,
+        mutbl: hir::MutImmutable
+    });
+    let ptr_type_metadata = type_metadata(cx, ptr_type, syntax_pos::DUMMY_SP);
+    let llvm_type = type_of::type_of(cx, ptr_type);
+
+    assert_eq!(abi::FAT_PTR_ADDR, 0);
+    assert_eq!(abi::FAT_PTR_EXTRA, 1);
+    let member_descriptions = [
+        MemberDescription {
+            name: "pointer".to_string(),
+            llvm_type: llvm_type,
+            type_metadata: ptr_type_metadata,
+            offset: ComputedMemberOffset,
+            flags: DIFlags::FlagArtificial,
+        },
+        MemberDescription {
+            name: "vtable".to_string(),
+            llvm_type: llvm_type,
+            type_metadata: ptr_type_metadata,
+            offset: ComputedMemberOffset,
+            flags: DIFlags::FlagArtificial,
+        },
+    ];
+
     composite_type_metadata(cx,
                             trait_llvm_type,
                             &trait_type_name[..],
                             unique_type_id,
-                            &[],
+                            &member_descriptions,
                             containing_scope,
                             file_metadata,
                             syntax_pos::DUMMY_SP)
@@ -1858,3 +1886,65 @@ pub fn extend_scope_to_file(ccx: &CrateContext,
             file_metadata)
     }
 }
+
+/// Creates debug information for the given vtable, which is for the
+/// given type.
+///
+/// Adds the created metadata nodes directly to the crate's IR.
+pub fn create_vtable_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
+                                        ty: ty::Ty<'tcx>,
+                                        vtable: ValueRef) {
+    if cx.dbg_cx().is_none() {
+        return;
+    }
+
+    let type_metadata = type_metadata(cx, ty, syntax_pos::DUMMY_SP);
+    let llvm_vtable_type = Type::vtable_ptr(cx).element_type();
+    let (struct_size, struct_align) = size_and_align_of(cx, llvm_vtable_type);
+
+    unsafe {
+        // LLVMRustDIBuilderCreateStructType() wants an empty array. A null
+        // pointer will lead to hard to trace and debug LLVM assertions
+        // later on in llvm/lib/IR/Value.cpp.
+        let empty_array = create_DIArray(DIB(cx), &[]);
+
+        let name = CString::new("vtable").unwrap();
+
+        // Create a new one each time.  We don't want metadata caching
+        // here, because each vtable will refer to a unique containing
+        // type.
+        let vtable_type = llvm::LLVMRustDIBuilderCreateStructType(
+            DIB(cx),
+            NO_SCOPE_METADATA,
+            name.as_ptr(),
+            unknown_file_metadata(cx),
+            UNKNOWN_LINE_NUMBER,
+            bytes_to_bits(struct_size),
+            bytes_to_bits(struct_align),
+            DIFlags::FlagArtificial,
+            ptr::null_mut(),
+            empty_array,
+            0,
+            type_metadata,
+            name.as_ptr()
+        );
+
+        llvm::LLVMRustDIBuilderCreateStaticVariable(DIB(cx),
+                                                    NO_SCOPE_METADATA,
+                                                    name.as_ptr(),
+                                                    // LLVM 3.9
+                                                    // doesn't accept
+                                                    // null here, so
+                                                    // pass the name
+                                                    // as the linkage
+                                                    // name.
+                                                    name.as_ptr(),
+                                                    unknown_file_metadata(cx),
+                                                    UNKNOWN_LINE_NUMBER,
+                                                    vtable_type,
+                                                    true,
+                                                    vtable,
+                                                    ptr::null_mut(),
+                                                    0);
+    }
+}
diff --git a/src/librustc_trans/debuginfo/mod.rs b/src/librustc_trans/debuginfo/mod.rs
index 1a284292016..15b299674ee 100644
--- a/src/librustc_trans/debuginfo/mod.rs
+++ b/src/librustc_trans/debuginfo/mod.rs
@@ -56,6 +56,7 @@ mod source_loc;
 pub use self::create_scope_map::{create_mir_scopes, MirDebugScope};
 pub use self::source_loc::start_emitting_source_locations;
 pub use self::metadata::create_global_var_metadata;
+pub use self::metadata::create_vtable_metadata;
 pub use self::metadata::extend_scope_to_file;
 pub use self::source_loc::set_source_location;
 
diff --git a/src/librustc_trans/meth.rs b/src/librustc_trans/meth.rs
index 3253a0339a8..e7c5a36838c 100644
--- a/src/librustc_trans/meth.rs
+++ b/src/librustc_trans/meth.rs
@@ -18,6 +18,7 @@ use monomorphize;
 use type_::Type;
 use value::Value;
 use rustc::ty::{self, Ty};
+use debuginfo;
 
 #[derive(Copy, Clone, Debug)]
 pub struct VirtualIndex(usize);
@@ -99,6 +100,8 @@ pub fn get_vtable<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     let align = machine::llalign_of_pref(ccx, val_ty(vtable_const));
     let vtable = consts::addr_of(ccx, vtable_const, align, "vtable");
 
+    debuginfo::create_vtable_metadata(ccx, ty, vtable);
+
     ccx.vtables().borrow_mut().insert((ty, trait_ref), vtable);
     vtable
 }
diff --git a/src/llvm b/src/llvm
-Subproject b48f77c5ed570001957408f4adeec88ae010c4d
+Subproject 51f104bf1cc6c3a588a11c90a3b4a4a18ee080a
diff --git a/src/test/codegen/vtabletype.rs b/src/test/codegen/vtabletype.rs
new file mode 100644
index 00000000000..b6466467548
--- /dev/null
+++ b/src/test/codegen/vtabletype.rs
@@ -0,0 +1,33 @@
+// Copyright 2017 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 depends on a patch that was committed to upstream LLVM
+// after 5.0, then backported to the Rust LLVM fork.
+
+// ignore-tidy-linelength
+// ignore-windows
+// ignore-macos
+// min-system-llvm-version 5.1
+
+// compile-flags: -g -C no-prepopulate-passes
+
+// CHECK-LABEL: @main
+// CHECK: {{.*}}DICompositeType{{.*}}name: "vtable",{{.*}}vtableHolder:{{.*}}
+
+pub trait T {
+}
+
+impl T for f64 {
+}
+
+pub fn main() {
+    let d = 23.0f64;
+    let td = &d as &T;
+}