Skip to content

Commit 4e77c11

Browse files
committed
auto merge of #10966 : michaelwoerister/rust/prelude2, r=cmr
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
2 parents 7b42497 + 9384de7 commit 4e77c11

File tree

8 files changed

+584
-27
lines changed

8 files changed

+584
-27
lines changed

src/librustc/middle/trans/_match.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,7 @@ use util::common::indenter;
220220
use util::ppaux::{Repr, vec_map_to_str};
221221

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

20512055
if fast_path {
20522056
// Optimized path for `x: T` case. This just adopts

src/librustc/middle/trans/base.rs

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -875,8 +875,11 @@ pub fn trans_external_path(ccx: &mut CrateContext, did: ast::DefId, t: ty::t) ->
875875
}
876876
}
877877
878-
pub fn invoke(bcx: @mut Block, llfn: ValueRef, llargs: ~[ValueRef],
879-
attributes: &[(uint, lib::llvm::Attribute)])
878+
pub fn invoke(bcx: @mut Block,
879+
llfn: ValueRef,
880+
llargs: ~[ValueRef],
881+
attributes: &[(uint, lib::llvm::Attribute)],
882+
call_info: Option<NodeInfo>)
880883
-> (ValueRef, @mut Block) {
881884
let _icx = push_ctxt("invoke_");
882885
if bcx.unreachable {
@@ -899,11 +902,18 @@ pub fn invoke(bcx: @mut Block, llfn: ValueRef, llargs: ~[ValueRef],
899902
}
900903
}
901904
let normal_bcx = sub_block(bcx, "normal return");
905+
let landing_pad = get_landing_pad(bcx);
906+
907+
match call_info {
908+
Some(info) => debuginfo::set_source_location(bcx.fcx, info.id, info.span),
909+
None => debuginfo::clear_source_location(bcx.fcx)
910+
};
911+
902912
let llresult = Invoke(bcx,
903913
llfn,
904914
llargs,
905915
normal_bcx.llbb,
906-
get_landing_pad(bcx),
916+
landing_pad,
907917
attributes);
908918
return (llresult, normal_bcx);
909919
} else {
@@ -913,6 +923,12 @@ pub fn invoke(bcx: @mut Block, llfn: ValueRef, llargs: ~[ValueRef],
913923
debug!("arg: {}", llarg);
914924
}
915925
}
926+
927+
match call_info {
928+
Some(info) => debuginfo::set_source_location(bcx.fcx, info.id, info.span),
929+
None => debuginfo::clear_source_location(bcx.fcx)
930+
};
931+
916932
let llresult = Call(bcx, llfn, llargs, attributes);
917933
return (llresult, bcx);
918934
}
@@ -1551,6 +1567,7 @@ pub fn alloca_maybe_zeroed(cx: @mut Block, ty: Type, name: &str, zero: bool) ->
15511567
return llvm::LLVMGetUndef(ty.ptr_to().to_ref());
15521568
}
15531569
}
1570+
debuginfo::clear_source_location(cx.fcx);
15541571
let p = Alloca(cx, ty, name);
15551572
if zero {
15561573
let b = cx.fcx.ccx.builder();
@@ -1567,6 +1584,7 @@ pub fn arrayalloca(cx: @mut Block, ty: Type, v: ValueRef) -> ValueRef {
15671584
return llvm::LLVMGetUndef(ty.to_ref());
15681585
}
15691586
}
1587+
debuginfo::clear_source_location(cx.fcx);
15701588
return ArrayAlloca(cx, ty, v);
15711589
}
15721590

@@ -1810,6 +1828,7 @@ pub fn finish_fn(fcx: @mut FunctionContext, last_bcx: @mut Block) {
18101828
None => last_bcx
18111829
};
18121830
build_return_block(fcx, ret_cx);
1831+
debuginfo::clear_source_location(fcx);
18131832
fcx.cleanup();
18141833
}
18151834

src/librustc/middle/trans/callee.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -697,7 +697,7 @@ pub fn trans_call_inner(in_cx: @mut Block,
697697
}
698698

699699
// Invoke the actual rust fn and update bcx/llresult.
700-
let (llret, b) = base::invoke(bcx, llfn, llargs, attrs);
700+
let (llret, b) = base::invoke(bcx, llfn, llargs, attrs, call_info);
701701
bcx = b;
702702
llresult = llret;
703703

src/librustc/middle/trans/debuginfo.rs

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

90127

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

654-
let scope_line = get_scope_line(cx, top_level_block, loc.line);
691+
// Clang sets this parameter to the opening brace of the function's block, so let's do this too.
692+
let scope_line = span_start(cx, top_level_block.span).line;
693+
694+
// The is_local_to_unit flag indicates whether a function is local to the current compilation
695+
// unit (i.e. if it is *static* in the C-sense). The *reachable* set should provide a good
696+
// approximation of this, as it contains everything that might leak out of the current crate
697+
// (by being externally visible or by being inlined into something externally visible). It might
698+
// better to use the `exported_items` set from `driver::CrateAnalysis` in the future, but (atm)
699+
// this set is not available in the translation pass.
700+
let is_local_to_unit = !cx.reachable.contains(&fn_ast_id);
655701

656702
let fn_metadata = function_name.with_c_str(|function_name| {
657703
linkage_name.with_c_str(|linkage_name| {
@@ -664,7 +710,7 @@ pub fn create_function_debug_context(cx: &mut CrateContext,
664710
file_metadata,
665711
loc.line as c_uint,
666712
function_type_metadata,
667-
false,
713+
is_local_to_unit,
668714
true,
669715
scope_line as c_uint,
670716
FlagPrototyped as c_uint,
@@ -687,6 +733,9 @@ pub fn create_function_debug_context(cx: &mut CrateContext,
687733
let arg_pats = fn_decl.inputs.map(|arg_ref| arg_ref.pat);
688734
populate_scope_map(cx, arg_pats, top_level_block, fn_metadata, &mut fn_debug_context.scope_map);
689735

736+
// Clear the debug location so we don't assign them in the function prelude
737+
set_debug_location(cx, UnknownLocation);
738+
690739
return FunctionDebugContext(fn_debug_context);
691740

692741
fn get_function_signature(cx: &mut CrateContext,
@@ -837,21 +886,6 @@ pub fn create_function_debug_context(cx: &mut CrateContext,
837886

838887
return create_DIArray(DIB(cx), template_params);
839888
}
840-
841-
fn get_scope_line(cx: &CrateContext,
842-
top_level_block: &ast::Block,
843-
default: uint)
844-
-> uint {
845-
match *top_level_block {
846-
ast::Block { stmts: ref statements, .. } if statements.len() > 0 => {
847-
span_start(cx, statements[0].span).line
848-
}
849-
ast::Block { expr: Some(@ref expr), .. } => {
850-
span_start(cx, expr.span).line
851-
}
852-
_ => default
853-
}
854-
}
855889
}
856890

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

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

2247-
walk_block(cx, fn_entry_block, &mut scope_stack, scope_map);
2282+
// Clang creates a separate scope for function bodies, so let's do this too
2283+
with_new_scope(cx,
2284+
fn_entry_block.span,
2285+
&mut scope_stack,
2286+
scope_map,
2287+
|cx, scope_stack, scope_map| {
2288+
walk_block(cx, fn_entry_block, scope_stack, scope_map);
2289+
});
22482290

22492291
// local helper functions for walking the AST.
22502292
fn with_new_scope(cx: &mut CrateContext,

src/librustc/middle/trans/glue.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -429,7 +429,7 @@ pub fn trans_struct_drop(bcx: @mut Block, t: ty::t, v0: ValueRef, dtor_did: ast:
429429
add_clean(bcx, llfld_a, fld.mt.ty);
430430
}
431431

432-
let (_, bcx) = invoke(bcx, dtor_addr, args, []);
432+
let (_, bcx) = invoke(bcx, dtor_addr, args, [], None);
433433
bcx
434434
})
435435
}

src/test/debug-info/basic-types-metadata.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,7 @@
4545
// debugger:whatis f64
4646
// check:type = f64
4747
// debugger:info functions _yyy
48-
// check:[...]
49-
// check:![...]_yyy()();
48+
// check:[...]![...]_yyy()();
5049
// debugger:detach
5150
// debugger:quit
5251

0 commit comments

Comments
 (0)