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:
parent
30375ccb30
commit
c19f493129
9 changed files with 206 additions and 63 deletions
|
@ -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
|
||||||
};
|
};
|
||||||
|
|
|
@ -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()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -608,6 +608,9 @@ LLVMDIBuilderCreateEnumerator
|
||||||
LLVMDIBuilderCreateEnumerationType
|
LLVMDIBuilderCreateEnumerationType
|
||||||
LLVMDIBuilderCreateUnionType
|
LLVMDIBuilderCreateUnionType
|
||||||
LLVMDIBuilderCreateTemplateTypeParameter
|
LLVMDIBuilderCreateTemplateTypeParameter
|
||||||
|
LLVMDIBuilderCreateOpDeref
|
||||||
|
LLVMDIBuilderCreateOpPlus
|
||||||
|
LLVMDIBuilderCreateComplexVariable
|
||||||
LLVMSetUnnamedAddr
|
LLVMSetUnnamedAddr
|
||||||
LLVMRustAddPass
|
LLVMRustAddPass
|
||||||
LLVMRustAddAnalysisPasses
|
LLVMRustAddAnalysisPasses
|
||||||
|
|
99
src/test/debug-info/by-value-non-immediate-argument.rs
Normal file
99
src/test/debug-info/by-value-non-immediate-argument.rs
Normal 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() {()}
|
|
@ -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() {()}
|
|
|
@ -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
|
||||||
|
|
74
src/test/debug-info/var-captured-in-nested-closure.rs
Normal file
74
src/test/debug-info/var-captured-in-nested-closure.rs
Normal 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() {()}
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Add table
Reference in a new issue