debuginfo: Added test cases for structs, tuples, enums, etc passed by value.

Also updated documentation comments in debuginfo and renamed DebugContext to CrateDebugContext.
This commit is contained in:
Michael Woerister 2013-08-29 11:44:11 +02:00
parent 30375ccb30
commit c19f493129
9 changed files with 206 additions and 63 deletions

View file

@ -111,7 +111,7 @@ pub struct CrateContext {
// decl_gc_metadata knows whether to link to the module metadata, which // decl_gc_metadata knows whether to link to the module metadata, which
// is not emitted by LLVM's GC pass when no functions use GC. // is not emitted by LLVM's GC pass when no functions use GC.
uses_gc: bool, uses_gc: bool,
dbg_cx: Option<debuginfo::DebugContext>, dbg_cx: Option<debuginfo::CrateDebugContext>,
do_not_commit_warning_issued: bool do_not_commit_warning_issued: bool
} }
@ -161,7 +161,7 @@ impl CrateContext {
let crate_map = decl_crate_map(sess, link_meta, llmod); let crate_map = decl_crate_map(sess, link_meta, llmod);
let dbg_cx = if sess.opts.debuginfo { let dbg_cx = if sess.opts.debuginfo {
Some(debuginfo::DebugContext::new(llmod, name.to_owned())) Some(debuginfo::CrateDebugContext::new(llmod, name.to_owned()))
} else { } else {
None None
}; };

View file

@ -27,7 +27,7 @@ where possible. This will hopefully ease the adaption of this module to future L
The public API of the module is a set of functions that will insert the correct metadata into the The public API of the module is a set of functions that will insert the correct metadata into the
LLVM IR when called with the right parameters. The module is thus driven from an outside client with LLVM IR when called with the right parameters. The module is thus driven from an outside client with
functions like `debuginfo::local_var_metadata(bcx: block, local: &ast::local)`. functions like `debuginfo::create_local_var_metadata(bcx: block, local: &ast::local)`.
Internally the module will try to reuse already created metadata by utilizing a cache. The way to Internally the module will try to reuse already created metadata by utilizing a cache. The way to
get a shared metadata node when needed is thus to just call the corresponding function in this get a shared metadata node when needed is thus to just call the corresponding function in this
@ -37,9 +37,8 @@ module:
The function will take care of probing the cache for an existing node for that exact file path. The function will take care of probing the cache for an existing node for that exact file path.
All private state used by the module is stored within a DebugContext struct, which in turn is All private state used by the module is stored within either the CrateDebugContext struct (owned by
contained in the CrateContext. the CrateContext) or the FunctionDebugContext (owned by the FunctionContext).
This file consists of three conceptual sections: This file consists of three conceptual sections:
1. The public interface of the module 1. The public interface of the module
@ -92,7 +91,7 @@ static DW_ATE_unsigned_char: c_uint = 0x08;
//=------------------------------------------------------------------------------------------------- //=-------------------------------------------------------------------------------------------------
/// A context object for maintaining all state needed by the debuginfo module. /// A context object for maintaining all state needed by the debuginfo module.
pub struct DebugContext { pub struct CrateDebugContext {
priv crate_file: ~str, priv crate_file: ~str,
priv llcontext: ContextRef, priv llcontext: ContextRef,
priv builder: DIBuilderRef, priv builder: DIBuilderRef,
@ -101,13 +100,13 @@ pub struct DebugContext {
priv created_types: HashMap<uint, DIType>, priv created_types: HashMap<uint, DIType>,
} }
impl DebugContext { impl CrateDebugContext {
pub fn new(llmod: ModuleRef, crate: ~str) -> DebugContext { pub fn new(llmod: ModuleRef, crate: ~str) -> CrateDebugContext {
debug!("DebugContext::new"); debug!("CrateDebugContext::new");
let builder = unsafe { llvm::LLVMDIBuilderCreate(llmod) }; let builder = unsafe { llvm::LLVMDIBuilderCreate(llmod) };
// DIBuilder inherits context from the module, so we'd better use the same one // DIBuilder inherits context from the module, so we'd better use the same one
let llcontext = unsafe { llvm::LLVMGetModuleContext(llmod) }; let llcontext = unsafe { llvm::LLVMGetModuleContext(llmod) };
return DebugContext { return CrateDebugContext {
crate_file: crate, crate_file: crate,
llcontext: llcontext, llcontext: llcontext,
builder: builder, builder: builder,
@ -165,9 +164,9 @@ struct FunctionDebugContextData {
} }
enum VariableAccess { enum VariableAccess {
// The value given is a pointer to data // The value given is a pointer to the data (T*)
DirectVariable, DirectVariable,
// The value given has to be dereferenced once to get the pointer to data // The value given has to be dereferenced once to get the pointer to data (T**)
IndirectVariable IndirectVariable
} }
@ -224,9 +223,9 @@ pub fn create_local_var_metadata(bcx: @mut Block,
} }
} }
/// Creates debug information for a local variable introduced in the head of a match-statement arm. /// Creates debug information for a variable captured in a closure.
/// ///
// /// Adds the created metadata nodes directly to the crate's IR. /// Adds the created metadata nodes directly to the crate's IR.
pub fn create_captured_var_metadata(bcx: @mut Block, pub fn create_captured_var_metadata(bcx: @mut Block,
node_id: ast::NodeId, node_id: ast::NodeId,
llptr: ValueRef, llptr: ValueRef,
@ -321,7 +320,8 @@ pub fn create_self_argument_metadata(bcx: @mut Block,
_) => { _) => {
explicit_self.span explicit_self.span
} }
_ => bcx.ccx().sess.bug(fmt!("create_self_argument_metadata: unexpected sort of node: %?", fnitem)) _ => bcx.ccx().sess.bug(
fmt!("create_self_argument_metadata: unexpected sort of node: %?", fnitem))
}; };
let scope_metadata = bcx.fcx.debug_context.get_ref(bcx.ccx(), span).fn_metadata; let scope_metadata = bcx.fcx.debug_context.get_ref(bcx.ccx(), span).fn_metadata;
@ -361,14 +361,10 @@ pub fn create_argument_metadata(bcx: @mut Block,
let fcx = bcx.fcx; let fcx = bcx.fcx;
let cx = fcx.ccx; let cx = fcx.ccx;
let pattern = arg.pat;
let filename = span_start(cx, pattern.span).file.name;
let def_map = cx.tcx.def_map; let def_map = cx.tcx.def_map;
let file_metadata = file_metadata(cx, filename);
let scope_metadata = bcx.fcx.debug_context.get_ref(cx, arg.pat.span).fn_metadata; let scope_metadata = bcx.fcx.debug_context.get_ref(cx, arg.pat.span).fn_metadata;
do pat_util::pat_bindings(def_map, pattern) |_, node_id, span, path_ref| { do pat_util::pat_bindings(def_map, arg.pat) |_, node_id, span, path_ref| {
let llptr = match bcx.fcx.llargs.find_copy(&node_id) { let llptr = match bcx.fcx.llargs.find_copy(&node_id) {
Some(v) => v, Some(v) => v,
@ -429,13 +425,24 @@ pub fn set_source_location(fcx: &FunctionContext,
} }
} }
/// Enables emitting source locations for the given functions.
///
/// Since we don't want source locations to be emitted for the function prelude, they are disabled
/// when beginning to translate a new function. This functions switches source location emitting on
/// and must therefore be called before the first real statement/expression of the function is
/// translated.
pub fn start_emitting_source_locations(fcx: &mut FunctionContext) { pub fn start_emitting_source_locations(fcx: &mut FunctionContext) {
match fcx.debug_context { match fcx.debug_context {
FunctionDebugContext(~ref mut data) => data.source_locations_enabled = true, FunctionDebugContext(~ref mut data) => data.source_locations_enabled = true,
_ => { /* safe to ignore */} _ => { /* safe to ignore */ }
} }
} }
/// Creates the function-specific debug context.
///
/// Returns the FunctionDebugContext for the function which holds state needed for debug info
/// creation. The function may also return another variant of the FunctionDebugContext enum which
/// indicates why no debuginfo should be created for the function.
pub fn create_function_debug_context(cx: &mut CrateContext, pub fn create_function_debug_context(cx: &mut CrateContext,
fn_ast_id: ast::NodeId, fn_ast_id: ast::NodeId,
param_substs: Option<@param_substs>, param_substs: Option<@param_substs>,
@ -1663,7 +1670,7 @@ fn bytes_to_bits(bytes: uint) -> c_ulonglong {
} }
#[inline] #[inline]
fn dbg_cx<'a>(cx: &'a mut CrateContext) -> &'a mut DebugContext { fn dbg_cx<'a>(cx: &'a mut CrateContext) -> &'a mut CrateDebugContext {
cx.dbg_cx.get_mut_ref() cx.dbg_cx.get_mut_ref()
} }

View file

@ -608,6 +608,9 @@ LLVMDIBuilderCreateEnumerator
LLVMDIBuilderCreateEnumerationType LLVMDIBuilderCreateEnumerationType
LLVMDIBuilderCreateUnionType LLVMDIBuilderCreateUnionType
LLVMDIBuilderCreateTemplateTypeParameter LLVMDIBuilderCreateTemplateTypeParameter
LLVMDIBuilderCreateOpDeref
LLVMDIBuilderCreateOpPlus
LLVMDIBuilderCreateComplexVariable
LLVMSetUnnamedAddr LLVMSetUnnamedAddr
LLVMRustAddPass LLVMRustAddPass
LLVMRustAddAnalysisPasses LLVMRustAddAnalysisPasses

View file

@ -0,0 +1,99 @@
// Copyright 2013 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.
// compile-flags:-Z extra-debug-info
// debugger:break zzz
// debugger:run
// debugger:finish
// debugger:print s
// check:$1 = {a = 1, b = 2.5}
// debugger:continue
// debugger:finish
// debugger:print x
// check:$2 = {a = 3, b = 4.5}
// debugger:print y
// check:$3 = 5
// debugger:print z
// check:$4 = 6.5
// debugger:continue
// debugger:finish
// debugger:print a
// check:$5 = {7, 8, 9.5, 10.5}
// debugger:continue
// debugger:finish
// debugger:print a
// check:$6 = {11.5, 12.5, 13, 14}
// debugger:continue
// debugger:finish
// debugger:print x
// check:$7 = {{Case1, x = 0, y = 8970181431921507452}, {Case1, 0, 2088533116, 2088533116}}
// debugger:continue
#[deriving(Clone)]
struct Struct {
a: int,
b: float
}
#[deriving(Clone)]
struct StructStruct {
a: Struct,
b: Struct
}
fn fun(s: Struct) {
zzz();
}
fn fun_fun(StructStruct { a: x, b: Struct { a: y, b: z } }: StructStruct) {
zzz();
}
fn tup(a: (int, uint, float, float)) {
zzz();
}
struct Newtype(float, float, int, uint);
fn new_type(a: Newtype) {
zzz();
}
// The first element is to ensure proper alignment, irrespective of the machines word size. Since
// the size of the discriminant value is machine dependent, this has be taken into account when
// datatype layout should be predictable as in this case.
enum Enum {
Case1 { x: i64, y: i64 },
Case2 (i64, i32, i32),
}
fn by_val_enum(x: Enum) {
zzz();
}
fn main() {
fun(Struct { a: 1, b: 2.5 });
fun_fun(StructStruct { a: Struct { a: 3, b: 4.5 }, b: Struct { a: 5, b: 6.5 } });
tup((7, 8, 9.5, 10.5));
new_type(Newtype(11.5, 12.5, 13, 14));
// 0b0111110001111100011111000111110001111100011111000111110001111100 = 8970181431921507452
// 0b01111100011111000111110001111100 = 2088533116
// 0b0111110001111100 = 31868
// 0b01111100 = 124
by_val_enum(Case1 { x: 0, y: 8970181431921507452 });
}
fn zzz() {()}

View file

@ -1,34 +0,0 @@
// Copyright 2013 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.
// compile-flags:-Z extra-debug-info
// debugger:break zzz
// debugger:run
// debugger:finish
// debugger:print s
// check:$1 = {a = 1, b = 2.5}
// debugger:continue
#[deriving(Clone)]
struct Struct {
a: int,
b: float
}
fn fun(s: Struct) {
zzz();
}
fn main() {
fun(Struct { a: 1, b: 2.5 });
}
fn zzz() {()}

View file

@ -8,8 +8,6 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
// compile-flags:-Z extra-debug-info // compile-flags:-Z extra-debug-info
// debugger:break zzz // debugger:break zzz
// debugger:run // debugger:run

View file

@ -0,0 +1,74 @@
// Copyright 2013 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.
// compile-flags:-Z extra-debug-info
// debugger:break zzz
// debugger:run
// debugger:finish
// debugger:print variable
// check:$1 = 1
// debugger:print constant
// check:$2 = 2
// debugger:print a_struct
// check:$3 = {a = -3, b = 4.5, c = 5}
// debugger:print *struct_ref
// check:$4 = {a = -3, b = 4.5, c = 5}
// debugger:print *owned
// check:$5 = 6
// debugger:print managed->val
// check:$6 = 7
// debugger:print closure_local
// check:$7 = 8
// debugger:continue
#[allow(unused_variable)];
struct Struct {
a: int,
b: float,
c: uint
}
fn main() {
let mut variable = 1;
let constant = 2;
let a_struct = Struct {
a: -3,
b: 4.5,
c: 5
};
let struct_ref = &a_struct;
let owned = ~6;
let managed = @7;
let closure = || {
let closure_local = 8;
let nested_closure = || {
zzz();
variable = constant + a_struct.a + struct_ref.a + *owned + *managed + closure_local;
};
// breaking here will yield a wrong value for 'constant'. In particular, GDB will
// read the value of the register that supposedly contains the pointer to 'constant'
// and try derefence it. The register, however, already contains the actual value, and
// not a pointer to it. -mw
// zzz();
nested_closure();
};
closure();
}
fn zzz() {()}

View file

@ -8,8 +8,6 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
// compile-flags:-Z extra-debug-info // compile-flags:-Z extra-debug-info
// debugger:break zzz // debugger:break zzz
// debugger:run // debugger:run

View file

@ -8,8 +8,6 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
// xfail-win32 Broken because of LLVM bug: http://llvm.org/bugs/show_bug.cgi?id=16249
// compile-flags:-Z extra-debug-info // compile-flags:-Z extra-debug-info
// debugger:break zzz // debugger:break zzz
// debugger:run // debugger:run