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
// is not emitted by LLVM's GC pass when no functions use GC.
uses_gc: bool,
dbg_cx: Option<debuginfo::DebugContext>,
dbg_cx: Option<debuginfo::CrateDebugContext>,
do_not_commit_warning_issued: bool
}
@ -161,7 +161,7 @@ impl CrateContext {
let crate_map = decl_crate_map(sess, link_meta, llmod);
let dbg_cx = if sess.opts.debuginfo {
Some(debuginfo::DebugContext::new(llmod, name.to_owned()))
Some(debuginfo::CrateDebugContext::new(llmod, name.to_owned()))
} else {
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
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
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.
All private state used by the module is stored within a DebugContext struct, which in turn is
contained in the CrateContext.
All private state used by the module is stored within either the CrateDebugContext struct (owned by
the CrateContext) or the FunctionDebugContext (owned by the FunctionContext).
This file consists of three conceptual sections:
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.
pub struct DebugContext {
pub struct CrateDebugContext {
priv crate_file: ~str,
priv llcontext: ContextRef,
priv builder: DIBuilderRef,
@ -101,13 +100,13 @@ pub struct DebugContext {
priv created_types: HashMap<uint, DIType>,
}
impl DebugContext {
pub fn new(llmod: ModuleRef, crate: ~str) -> DebugContext {
debug!("DebugContext::new");
impl CrateDebugContext {
pub fn new(llmod: ModuleRef, crate: ~str) -> CrateDebugContext {
debug!("CrateDebugContext::new");
let builder = unsafe { llvm::LLVMDIBuilderCreate(llmod) };
// DIBuilder inherits context from the module, so we'd better use the same one
let llcontext = unsafe { llvm::LLVMGetModuleContext(llmod) };
return DebugContext {
return CrateDebugContext {
crate_file: crate,
llcontext: llcontext,
builder: builder,
@ -165,9 +164,9 @@ struct FunctionDebugContextData {
}
enum VariableAccess {
// The value given is a pointer to data
// The value given is a pointer to the data (T*)
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
}
@ -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,
node_id: ast::NodeId,
llptr: ValueRef,
@ -321,7 +320,8 @@ pub fn create_self_argument_metadata(bcx: @mut Block,
_) => {
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;
@ -361,14 +361,10 @@ pub fn create_argument_metadata(bcx: @mut Block,
let fcx = bcx.fcx;
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 file_metadata = file_metadata(cx, filename);
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) {
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) {
match fcx.debug_context {
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,
fn_ast_id: ast::NodeId,
param_substs: Option<@param_substs>,
@ -1663,7 +1670,7 @@ fn bytes_to_bits(bytes: uint) -> c_ulonglong {
}
#[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()
}

View File

@ -608,6 +608,9 @@ LLVMDIBuilderCreateEnumerator
LLVMDIBuilderCreateEnumerationType
LLVMDIBuilderCreateUnionType
LLVMDIBuilderCreateTemplateTypeParameter
LLVMDIBuilderCreateOpDeref
LLVMDIBuilderCreateOpPlus
LLVMDIBuilderCreateComplexVariable
LLVMSetUnnamedAddr
LLVMRustAddPass
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
// 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
// debugger:break zzz
// 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
// 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
// debugger:break zzz
// debugger:run

View File

@ -8,8 +8,6 @@
// option. This file may not be copied, modified, or distributed
// 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
// debugger:break zzz
// debugger:run