Skip to content

Commit

Permalink
auto merge of #10966 : michaelwoerister/rust/prelude2, r=cmr
Browse files Browse the repository at this point in the history
This PR improves the stepping experience in GDB. It contains some fine tuning of line information and makes *rustc* produce nearly the same IR/DWARF as Clang. The focus of the changes is function prologue handling which has caused some problems in the past (#9641).

It seems that GDB does not properly handle function prologues when the function uses segmented stacks, i.e. it does not recognize that the `__morestack` check is part of the prologue. When setting a breakpoint like `break foo` it will set the break point before the arguments of `foo()` have been loaded and still contain bogus values. For function with the #[no_split_stack] attribute this problem has never occurred for me so I'm pretty sure that segmented stacks are the cause of the problem. @jdm mentioned that segmented stack won't be completely abandoned after all. I'd be grateful if you could tell me about what the future might bring in this regard (@brson, @cmr).

Anyway, this PR should alleviate this problem at least in the case when setting breakpoints using line numbers and also make it less confusing when setting them via function names because then GDB will break *before* the first statement where one could conceivably argue that arguments need not be initialized yet.

Also, a koala: 🐨

Cheers,
Michael
  • Loading branch information
bors committed Dec 16, 2013
2 parents 7b42497 + 9384de7 commit 4e77c11
Show file tree
Hide file tree
Showing 8 changed files with 584 additions and 27 deletions.
6 changes: 5 additions & 1 deletion src/librustc/middle/trans/_match.rs
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,7 @@ use util::common::indenter;
use util::ppaux::{Repr, vec_map_to_str};

use std::hashmap::HashMap;
use std::ptr;
use std::vec;
use syntax::ast;
use syntax::ast::Ident;
Expand Down Expand Up @@ -2046,7 +2047,10 @@ pub fn store_arg(mut bcx: @mut Block,
// Debug information (the llvm.dbg.declare intrinsic to be precise) always expects to get an
// alloca, which only is the case on the general path, so lets disable the optimized path when
// debug info is enabled.
let fast_path = !bcx.ccx().sess.opts.extra_debuginfo && simple_identifier(pat).is_some();
let arg_is_alloca = unsafe { llvm::LLVMIsAAllocaInst(llval) != ptr::null() };

let fast_path = (arg_is_alloca || !bcx.ccx().sess.opts.extra_debuginfo)
&& simple_identifier(pat).is_some();

if fast_path {
// Optimized path for `x: T` case. This just adopts
Expand Down
25 changes: 22 additions & 3 deletions src/librustc/middle/trans/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -875,8 +875,11 @@ pub fn trans_external_path(ccx: &mut CrateContext, did: ast::DefId, t: ty::t) ->
}
}
pub fn invoke(bcx: @mut Block, llfn: ValueRef, llargs: ~[ValueRef],
attributes: &[(uint, lib::llvm::Attribute)])
pub fn invoke(bcx: @mut Block,
llfn: ValueRef,
llargs: ~[ValueRef],
attributes: &[(uint, lib::llvm::Attribute)],
call_info: Option<NodeInfo>)
-> (ValueRef, @mut Block) {
let _icx = push_ctxt("invoke_");
if bcx.unreachable {
Expand All @@ -899,11 +902,18 @@ pub fn invoke(bcx: @mut Block, llfn: ValueRef, llargs: ~[ValueRef],
}
}
let normal_bcx = sub_block(bcx, "normal return");
let landing_pad = get_landing_pad(bcx);

match call_info {
Some(info) => debuginfo::set_source_location(bcx.fcx, info.id, info.span),
None => debuginfo::clear_source_location(bcx.fcx)
};

let llresult = Invoke(bcx,
llfn,
llargs,
normal_bcx.llbb,
get_landing_pad(bcx),
landing_pad,
attributes);
return (llresult, normal_bcx);
} else {
Expand All @@ -913,6 +923,12 @@ pub fn invoke(bcx: @mut Block, llfn: ValueRef, llargs: ~[ValueRef],
debug!("arg: {}", llarg);
}
}

match call_info {
Some(info) => debuginfo::set_source_location(bcx.fcx, info.id, info.span),
None => debuginfo::clear_source_location(bcx.fcx)
};

let llresult = Call(bcx, llfn, llargs, attributes);
return (llresult, bcx);
}
Expand Down Expand Up @@ -1551,6 +1567,7 @@ pub fn alloca_maybe_zeroed(cx: @mut Block, ty: Type, name: &str, zero: bool) ->
return llvm::LLVMGetUndef(ty.ptr_to().to_ref());
}
}
debuginfo::clear_source_location(cx.fcx);
let p = Alloca(cx, ty, name);
if zero {
let b = cx.fcx.ccx.builder();
Expand All @@ -1567,6 +1584,7 @@ pub fn arrayalloca(cx: @mut Block, ty: Type, v: ValueRef) -> ValueRef {
return llvm::LLVMGetUndef(ty.to_ref());
}
}
debuginfo::clear_source_location(cx.fcx);
return ArrayAlloca(cx, ty, v);
}

Expand Down Expand Up @@ -1810,6 +1828,7 @@ pub fn finish_fn(fcx: @mut FunctionContext, last_bcx: @mut Block) {
None => last_bcx
};
build_return_block(fcx, ret_cx);
debuginfo::clear_source_location(fcx);
fcx.cleanup();
}

Expand Down
2 changes: 1 addition & 1 deletion src/librustc/middle/trans/callee.rs
Original file line number Diff line number Diff line change
Expand Up @@ -697,7 +697,7 @@ pub fn trans_call_inner(in_cx: @mut Block,
}

// Invoke the actual rust fn and update bcx/llresult.
let (llret, b) = base::invoke(bcx, llfn, llargs, attrs);
let (llret, b) = base::invoke(bcx, llfn, llargs, attrs, call_info);
bcx = b;
llresult = llret;

Expand Down
80 changes: 61 additions & 19 deletions src/librustc/middle/trans/debuginfo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,43 @@ continuation, storing all state needed to continue traversal at the type members
been registered with the cache. (This implementation approach might be a tad over-engineered and
may change in the future)
## Source Locations and Line Information
In addition to data type descriptions the debugging information must also allow to map machine code
locations back to source code locations in order to be useful. This functionality is also handled in
this module. The following functions allow to control source mappings:
+ set_source_location()
+ clear_source_location()
+ start_emitting_source_locations()
`set_source_location()` allows to set the current source location. All IR instructions created after
a call to this function will be linked to the given source location, until another location is
specified with `set_source_location()` or the source location is cleared with
`clear_source_location()`. In the later case, subsequent IR instruction will not be linked to any
source location. As you can see, this is a stateful API (mimicking the one in LLVM), so be careful
with source locations set by previous calls. It's probably best to not rely on any specific state
being present at a given point in code.
One topic that deserves some extra attention is *function prologues*. At the beginning of a
function's machine code there are typically a few instructions for loading argument values into
allocas and checking if there's enough stack space for the function to execute. This *prologue* is
not visible in the source code and LLVM puts a special PROLOGUE END marker into the line table at
the first non-prologue instruction of the function. In order to find out where the prologue ends,
LLVM looks for the first instruction in the function body that is linked to a source location. So,
when generating prologue instructions we have to make sure that we don't emit source location
information until the 'real' function body begins. For this reason, source location emission is
disabled by default for any new function being translated and is only activated after a call to the
third function from the list above, `start_emitting_source_locations()`. This function should be
called right before regularly starting to translate the top-level block of the given function.
There is one exception to the above rule: `llvm.dbg.declare` instruction must be linked to the
source location of the variable being declared. For function parameters these `llvm.dbg.declare`
instructions typically occur in the middle of the prologue, however, they are ignored by LLVM's
prologue detection. The `create_argument_metadata()` and related functions take care of linking the
`llvm.dbg.declare` instructions to the correct source locations even while source location emission
is still disabled, so there is no need to do anything special with source location handling here.
*/


Expand Down Expand Up @@ -651,7 +688,16 @@ pub fn create_function_debug_context(cx: &mut CrateContext,
(function_name.clone(), file_metadata)
};

let scope_line = get_scope_line(cx, top_level_block, loc.line);
// Clang sets this parameter to the opening brace of the function's block, so let's do this too.
let scope_line = span_start(cx, top_level_block.span).line;

// The is_local_to_unit flag indicates whether a function is local to the current compilation
// unit (i.e. if it is *static* in the C-sense). The *reachable* set should provide a good
// approximation of this, as it contains everything that might leak out of the current crate
// (by being externally visible or by being inlined into something externally visible). It might
// better to use the `exported_items` set from `driver::CrateAnalysis` in the future, but (atm)
// this set is not available in the translation pass.
let is_local_to_unit = !cx.reachable.contains(&fn_ast_id);

let fn_metadata = function_name.with_c_str(|function_name| {
linkage_name.with_c_str(|linkage_name| {
Expand All @@ -664,7 +710,7 @@ pub fn create_function_debug_context(cx: &mut CrateContext,
file_metadata,
loc.line as c_uint,
function_type_metadata,
false,
is_local_to_unit,
true,
scope_line as c_uint,
FlagPrototyped as c_uint,
Expand All @@ -687,6 +733,9 @@ pub fn create_function_debug_context(cx: &mut CrateContext,
let arg_pats = fn_decl.inputs.map(|arg_ref| arg_ref.pat);
populate_scope_map(cx, arg_pats, top_level_block, fn_metadata, &mut fn_debug_context.scope_map);

// Clear the debug location so we don't assign them in the function prelude
set_debug_location(cx, UnknownLocation);

return FunctionDebugContext(fn_debug_context);

fn get_function_signature(cx: &mut CrateContext,
Expand Down Expand Up @@ -837,21 +886,6 @@ pub fn create_function_debug_context(cx: &mut CrateContext,

return create_DIArray(DIB(cx), template_params);
}

fn get_scope_line(cx: &CrateContext,
top_level_block: &ast::Block,
default: uint)
-> uint {
match *top_level_block {
ast::Block { stmts: ref statements, .. } if statements.len() > 0 => {
span_start(cx, statements[0].span).line
}
ast::Block { expr: Some(@ref expr), .. } => {
span_start(cx, expr.span).line
}
_ => default
}
}
}

//=-------------------------------------------------------------------------------------------------
Expand Down Expand Up @@ -2128,7 +2162,8 @@ fn set_debug_location(cx: &mut CrateContext, debug_location: DebugLocation) {
let metadata_node;

match debug_location {
KnownLocation { scope, line, col } => {
KnownLocation { scope, line, .. } => {
let col = 0; // Always set the column to zero like Clang and GCC
debug!("setting debug location to {} {}", line, col);
let elements = [C_i32(line as i32), C_i32(col as i32), scope, ptr::null()];
unsafe {
Expand Down Expand Up @@ -2244,7 +2279,14 @@ fn populate_scope_map(cx: &mut CrateContext,
})
}

walk_block(cx, fn_entry_block, &mut scope_stack, scope_map);
// Clang creates a separate scope for function bodies, so let's do this too
with_new_scope(cx,
fn_entry_block.span,
&mut scope_stack,
scope_map,
|cx, scope_stack, scope_map| {
walk_block(cx, fn_entry_block, scope_stack, scope_map);
});

// local helper functions for walking the AST.
fn with_new_scope(cx: &mut CrateContext,
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/middle/trans/glue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -429,7 +429,7 @@ pub fn trans_struct_drop(bcx: @mut Block, t: ty::t, v0: ValueRef, dtor_did: ast:
add_clean(bcx, llfld_a, fld.mt.ty);
}

let (_, bcx) = invoke(bcx, dtor_addr, args, []);
let (_, bcx) = invoke(bcx, dtor_addr, args, [], None);
bcx
})
}
Expand Down
3 changes: 1 addition & 2 deletions src/test/debug-info/basic-types-metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,7 @@
// debugger:whatis f64
// check:type = f64
// debugger:info functions _yyy
// check:[...]
// check:![...]_yyy()();
// check:[...]![...]_yyy()();
// debugger:detach
// debugger:quit

Expand Down
Loading

0 comments on commit 4e77c11

Please sign in to comment.