Skip to content

Commit

Permalink
Fix debug line number info for macro expansions.
Browse files Browse the repository at this point in the history
Macro expansions result in code tagged with completely different debug locations than the surrounding expressions.  This wrecks havoc on debugger's ability the step over source lines.
This change fixes the problem by tagging expanded code as "inlined" at the macro expansion site, which allows the debugger to sort it out.
Note that only the outermost expansion is currently handled, stepping into a macro will still result in stepping craziness.
  • Loading branch information
vadimcn committed Aug 4, 2016
1 parent a0b4e67 commit 659f420
Show file tree
Hide file tree
Showing 10 changed files with 286 additions and 62 deletions.
2 changes: 1 addition & 1 deletion src/librustc/middle/region.rs
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ impl CodeExtent {
// (This is the special case aluded to in the
// doc-comment for this method)
let stmt_span = blk.stmts[r.first_statement_index as usize].span;
Some(Span { lo: stmt_span.hi, ..blk.span })
Some(Span { lo: stmt_span.hi, hi: blk.span.hi, expn_id: stmt_span.expn_id })
}
}
}
Expand Down
7 changes: 7 additions & 0 deletions src/librustc_llvm/ffi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -637,6 +637,8 @@ extern {
pub fn LLVMAddNamedMetadataOperand(M: ModuleRef,
Str: *const c_char,
Val: ValueRef);
pub fn LLVMRustMetadataAsValue(context: ContextRef, metadata: MetadataRef) -> ValueRef;
pub fn LLVMRustValueAsMetadata(value: ValueRef) -> MetadataRef;

/* Operations on scalar constants */
pub fn LLVMConstInt(IntTy: TypeRef, N: c_ulonglong, SignExtend: Bool)
Expand Down Expand Up @@ -1796,6 +1798,11 @@ extern {
Col: c_uint)
-> DILexicalBlock;

pub fn LLVMRustDIBuilderCreateLexicalBlockFile(Builder: DIBuilderRef,
Scope: DIScope,
File: DIFile)
-> DILexicalBlock;

pub fn LLVMRustDIBuilderCreateStaticVariable(Builder: DIBuilderRef,
Context: DIScope,
Name: *const c_char,
Expand Down
46 changes: 38 additions & 8 deletions src/librustc_trans/debuginfo/create_scope_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ use rustc_data_structures::bitvec::BitVector;
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
use rustc::hir::{self, PatKind};

use syntax_pos::BytePos;

// This procedure builds the *scope map* for a given function, which maps any
// given ast::NodeId in the function's AST to the correct DIScope metadata instance.
//
Expand Down Expand Up @@ -68,11 +70,29 @@ pub fn create_scope_map(cx: &CrateContext,
return scope_map;
}

#[derive(Clone, Copy, Debug)]
pub struct MirDebugScope {
pub scope_metadata: DIScope,
pub start_pos: BytePos,
pub end_pos: BytePos,
}

impl MirDebugScope {
pub fn is_valid(&self) -> bool {
!self.scope_metadata.is_null()
}
}

/// Produce DIScope DIEs for each MIR Scope which has variables defined in it.
/// If debuginfo is disabled, the returned vector is empty.
pub fn create_mir_scopes(fcx: &FunctionContext) -> IndexVec<VisibilityScope, DIScope> {
pub fn create_mir_scopes(fcx: &FunctionContext) -> IndexVec<VisibilityScope, MirDebugScope> {
let mir = fcx.mir.clone().expect("create_mir_scopes: missing MIR for fn");
let mut scopes = IndexVec::from_elem(ptr::null_mut(), &mir.visibility_scopes);
let null_scope = MirDebugScope {
scope_metadata: ptr::null_mut(),
start_pos: BytePos(0),
end_pos: BytePos(0)
};
let mut scopes = IndexVec::from_elem(null_scope, &mir.visibility_scopes);

let fn_metadata = match fcx.debug_context {
FunctionDebugContext::RegularContext(box ref data) => data.fn_metadata,
Expand Down Expand Up @@ -102,8 +122,8 @@ fn make_mir_scope(ccx: &CrateContext,
has_variables: &BitVector,
fn_metadata: DISubprogram,
scope: VisibilityScope,
scopes: &mut IndexVec<VisibilityScope, DIScope>) {
if !scopes[scope].is_null() {
scopes: &mut IndexVec<VisibilityScope, MirDebugScope>) {
if scopes[scope].is_valid() {
return;
}

Expand All @@ -113,7 +133,12 @@ fn make_mir_scope(ccx: &CrateContext,
scopes[parent]
} else {
// The root is the function itself.
scopes[scope] = fn_metadata;
let loc = span_start(ccx, mir.span);
scopes[scope] = MirDebugScope {
scope_metadata: fn_metadata,
start_pos: loc.file.start_pos,
end_pos: loc.file.end_pos,
};
return;
};

Expand All @@ -124,22 +149,27 @@ fn make_mir_scope(ccx: &CrateContext,
// However, we don't skip creating a nested scope if
// our parent is the root, because we might want to
// put arguments in the root and not have shadowing.
if parent_scope != fn_metadata {
if parent_scope.scope_metadata != fn_metadata {
scopes[scope] = parent_scope;
return;
}
}

let loc = span_start(ccx, scope_data.span);
scopes[scope] = unsafe {
let file_metadata = file_metadata(ccx, &loc.file.name, &loc.file.abs_path);
let scope_metadata = unsafe {
llvm::LLVMRustDIBuilderCreateLexicalBlock(
DIB(ccx),
parent_scope,
parent_scope.scope_metadata,
file_metadata,
loc.line as c_uint,
loc.col.to_usize() as c_uint)
};
scopes[scope] = MirDebugScope {
scope_metadata: scope_metadata,
start_pos: loc.file.start_pos,
end_pos: loc.file.end_pos,
};
}

// local helper functions for walking the AST.
Expand Down
16 changes: 15 additions & 1 deletion src/librustc_trans/debuginfo/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use context::SharedCrateContext;
use session::Session;

use llvm::{self, ValueRef};
use llvm::debuginfo::{DIType, DIFile, DIScope, DIDescriptor, DICompositeType};
use llvm::debuginfo::{DIType, DIFile, DIScope, DIDescriptor, DICompositeType, DILexicalBlock};

use rustc::hir::def_id::DefId;
use rustc::hir::pat_util;
Expand Down Expand Up @@ -2104,3 +2104,17 @@ pub fn create_argument_metadata(bcx: Block, arg: &hir::Arg) {
span);
})
}

// Creates an "extension" of an existing DIScope into another file.
pub fn extend_scope_to_file(ccx: &CrateContext,
scope_metadata: DIScope,
file: &syntax_pos::FileMap)
-> DILexicalBlock {
let file_metadata = file_metadata(ccx, &file.name, &file.abs_path);
unsafe {
llvm::LLVMRustDIBuilderCreateLexicalBlockFile(
DIB(ccx),
scope_metadata,
file_metadata)
}
}
9 changes: 5 additions & 4 deletions src/librustc_trans/debuginfo/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ use std::cell::{Cell, RefCell};
use std::ffi::CString;
use std::ptr;

use syntax_pos::{self, Span, Pos};
use syntax_pos::{self, Span};
use syntax::ast;
use syntax::attr::IntType;

Expand All @@ -55,7 +55,7 @@ pub mod metadata;
mod create_scope_map;
mod source_loc;

pub use self::create_scope_map::create_mir_scopes;
pub use self::create_scope_map::{create_mir_scopes, MirDebugScope};
pub use self::source_loc::start_emitting_source_locations;
pub use self::source_loc::get_cleanup_debug_loc_for_ast_node;
pub use self::source_loc::with_source_location_override;
Expand All @@ -64,6 +64,7 @@ pub use self::metadata::create_argument_metadata;
pub use self::metadata::create_captured_var_metadata;
pub use self::metadata::create_global_var_metadata;
pub use self::metadata::create_local_var_metadata;
pub use self::metadata::extend_scope_to_file;

#[allow(non_upper_case_globals)]
const DW_TAG_auto_variable: c_uint = 0x100;
Expand Down Expand Up @@ -509,7 +510,7 @@ pub fn declare_local<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
argument_index)
};
source_loc::set_debug_location(cx, None,
InternalDebugLocation::new(scope_metadata, loc.line, loc.col.to_usize()));
InternalDebugLocation::KnownLocation(scope_metadata, span.lo, None));
unsafe {
let debug_loc = llvm::LLVMGetCurrentDebugLocation(cx.raw_builder());
let instr = llvm::LLVMRustDIBuilderInsertDeclareAtEnd(
Expand Down Expand Up @@ -542,7 +543,7 @@ pub fn declare_local<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum DebugLoc {
At(ast::NodeId, Span),
ScopeAt(DIScope, Span),
ScopeAt(DIScope, Span, Option<(DIScope, Span)>),
None
}

Expand Down
74 changes: 40 additions & 34 deletions src/librustc_trans/debuginfo/source_loc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

use self::InternalDebugLocation::*;

use super::utils::{debug_context, span_start};
use super::utils::debug_context;
use super::metadata::{scope_metadata,UNKNOWN_COLUMN_NUMBER};
use super::{FunctionDebugContext, DebugLoc};

Expand All @@ -21,7 +21,7 @@ use common::{NodeIdAndSpan, CrateContext, FunctionContext};

use libc::c_uint;
use std::ptr;
use syntax_pos::{self, Span, Pos};
use syntax_pos::{self, Span, BytePos};
use syntax::ast;

pub fn get_cleanup_debug_loc_for_ast_node<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
Expand Down Expand Up @@ -108,21 +108,20 @@ pub fn set_source_location(fcx: &FunctionContext,
}

let dbg_loc = if function_debug_context.source_locations_enabled.get() {
let (scope, span) = match debug_loc {
match debug_loc {
DebugLoc::At(node_id, span) => {
(scope_metadata(fcx, node_id, span), span)
let scope = scope_metadata(fcx, node_id, span);
KnownLocation(scope, span.lo, None)
}
DebugLoc::ScopeAt(scope, span) => (scope, span),
DebugLoc::None => {
set_debug_location(fcx.ccx, builder, UnknownLocation);
return;
DebugLoc::ScopeAt(scope, span, inlined_at) => {
let inlined_at_loc = match inlined_at {
Some((scope, span)) => Some((scope, span.lo)),
None => None
};
KnownLocation(scope, span.lo, inlined_at_loc)
}
};

debug!("set_source_location: {}",
fcx.ccx.sess().codemap().span_to_string(span));
let loc = span_start(fcx.ccx, span);
InternalDebugLocation::new(scope, loc.line, loc.col.to_usize())
DebugLoc::None => UnknownLocation
}
} else {
UnknownLocation
};
Expand Down Expand Up @@ -173,23 +172,12 @@ pub fn start_emitting_source_locations(fcx: &FunctionContext) {
}
}


#[derive(Copy, Clone, PartialEq)]
pub enum InternalDebugLocation {
KnownLocation { scope: DIScope, line: usize, col: usize },
KnownLocation(DIScope, BytePos, Option<(DIScope, BytePos)>),
UnknownLocation
}

impl InternalDebugLocation {
pub fn new(scope: DIScope, line: usize, col: usize) -> InternalDebugLocation {
KnownLocation {
scope: scope,
line: line,
col: col,
}
}
}

pub fn set_debug_location(cx: &CrateContext,
builder: Option<llvm::BuilderRef>,
debug_location: InternalDebugLocation) {
Expand All @@ -199,19 +187,37 @@ pub fn set_debug_location(cx: &CrateContext,
}
}

let cm = cx.sess().codemap();
let metadata_node = match debug_location {
KnownLocation { scope, line, .. } => {
// Always set the column to zero like Clang and GCC
let col = UNKNOWN_COLUMN_NUMBER;
debug!("setting debug location to {} {}", line, col);

KnownLocation(scope, pos, inlined_at) => {

let inlined_at_loc = match inlined_at {
Some((scope, pos)) => {
let loc = cm.lookup_char_pos(pos);
unsafe {
llvm::LLVMRustValueAsMetadata(
llvm::LLVMRustDIBuilderCreateDebugLocation(
debug_context(cx).llcontext,
loc.line as c_uint,
UNKNOWN_COLUMN_NUMBER as c_uint,
scope,
ptr::null_mut())
)
}
},
None => ptr::null_mut()
};

let loc = cm.lookup_char_pos(pos);
debug!("setting debug location to line {}", loc.line);
// Set the column to zero like Clang and GCC
unsafe {
llvm::LLVMRustDIBuilderCreateDebugLocation(
debug_context(cx).llcontext,
line as c_uint,
col as c_uint,
loc.line as c_uint,
UNKNOWN_COLUMN_NUMBER as c_uint,
scope,
ptr::null_mut())
inlined_at_loc)
}
}
UnknownLocation => {
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_trans/intrinsic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
let name = tcx.item_name(def_id).as_str();

let span = match call_debug_location {
DebugLoc::At(_, span) | DebugLoc::ScopeAt(_, span) => span,
DebugLoc::At(_, span) | DebugLoc::ScopeAt(_, span, _) => span,
DebugLoc::None => {
span_bug!(fcx.span.unwrap_or(DUMMY_SP),
"intrinsic `{}` called with missing span", name);
Expand Down
Loading

0 comments on commit 659f420

Please sign in to comment.