blob: 548ea0b1036e0e564e6e96c009c8bda5ff9b0e31 [file] [log] [blame]
Inna Palantff3f07a2019-07-11 16:15:26 -07001// See doc.rs for documentation.
2mod doc;
3
4use rustc_codegen_ssa::debuginfo::VariableAccess::*;
5use rustc_codegen_ssa::debuginfo::VariableKind::*;
6
7use self::utils::{DIB, span_start, create_DIArray, is_node_local_to_unit};
8use self::namespace::mangled_name_of_instance;
9use self::type_names::compute_debuginfo_type_name;
10use self::metadata::{type_metadata, file_metadata, TypeMap};
11use self::source_loc::InternalDebugLocation::{self, UnknownLocation};
12
13use crate::llvm;
14use crate::llvm::debuginfo::{DIFile, DIType, DIScope, DIBuilder, DISubprogram, DIArray, DIFlags,
15 DISPFlags, DILexicalBlock};
16use rustc::hir::CodegenFnAttrFlags;
17use rustc::hir::def_id::{DefId, CrateNum, LOCAL_CRATE};
18use rustc::ty::subst::{SubstsRef, UnpackedKind};
19
20use crate::abi::Abi;
21use crate::common::CodegenCx;
22use crate::builder::Builder;
Inna Palantff3f07a2019-07-11 16:15:26 -070023use crate::value::Value;
Chih-Hung Hsiehda60c852019-12-19 14:56:55 -080024use rustc::ty::{self, ParamEnv, Ty, InstanceDef, Instance};
Inna Palantff3f07a2019-07-11 16:15:26 -070025use rustc::mir;
26use rustc::session::config::{self, DebugInfo};
27use rustc::util::nodemap::{DefIdMap, FxHashMap, FxHashSet};
28use rustc_data_structures::small_c_str::SmallCStr;
29use rustc_data_structures::indexed_vec::IndexVec;
30use rustc_codegen_ssa::debuginfo::{FunctionDebugContext, MirDebugScope, VariableAccess,
Chih-Hung Hsiehfd666f22019-12-19 14:34:18 -080031 VariableKind, FunctionDebugContextData, type_names};
Inna Palantff3f07a2019-07-11 16:15:26 -070032
33use libc::c_uint;
34use std::cell::RefCell;
35use std::ffi::CString;
36
37use syntax_pos::{self, Span, Pos};
38use syntax::ast;
Chih-Hung Hsiehda60c852019-12-19 14:56:55 -080039use syntax::symbol::InternedString;
Inna Palantff3f07a2019-07-11 16:15:26 -070040use rustc::ty::layout::{self, LayoutOf, HasTyCtxt};
41use rustc_codegen_ssa::traits::*;
42
43pub mod gdb;
44mod utils;
45mod namespace;
Inna Palantff3f07a2019-07-11 16:15:26 -070046pub mod metadata;
47mod create_scope_map;
48mod source_loc;
49
50pub use self::create_scope_map::{create_mir_scopes};
51pub use self::metadata::create_global_var_metadata;
52pub use self::metadata::extend_scope_to_file;
53pub use self::source_loc::set_source_location;
54
55#[allow(non_upper_case_globals)]
56const DW_TAG_auto_variable: c_uint = 0x100;
57#[allow(non_upper_case_globals)]
58const DW_TAG_arg_variable: c_uint = 0x101;
59
60/// A context object for maintaining all state needed by the debuginfo module.
61pub struct CrateDebugContext<'a, 'tcx> {
62 llcontext: &'a llvm::Context,
63 llmod: &'a llvm::Module,
64 builder: &'a mut DIBuilder<'a>,
Chih-Hung Hsiehda60c852019-12-19 14:56:55 -080065 created_files: RefCell<FxHashMap<(Option<String>, Option<String>), &'a DIFile>>,
Inna Palantff3f07a2019-07-11 16:15:26 -070066 created_enum_disr_types: RefCell<FxHashMap<(DefId, layout::Primitive), &'a DIType>>,
67
68 type_map: RefCell<TypeMap<'a, 'tcx>>,
69 namespace_map: RefCell<DefIdMap<&'a DIScope>>,
70
71 // This collection is used to assert that composite types (structs, enums,
72 // ...) have their members only set once:
73 composite_types_completed: RefCell<FxHashSet<&'a DIType>>,
74}
75
76impl Drop for CrateDebugContext<'a, 'tcx> {
77 fn drop(&mut self) {
78 unsafe {
79 llvm::LLVMRustDIBuilderDispose(&mut *(self.builder as *mut _));
80 }
81 }
82}
83
84impl<'a, 'tcx> CrateDebugContext<'a, 'tcx> {
85 pub fn new(llmod: &'a llvm::Module) -> Self {
86 debug!("CrateDebugContext::new");
87 let builder = unsafe { llvm::LLVMRustDIBuilderCreate(llmod) };
88 // DIBuilder inherits context from the module, so we'd better use the same one
89 let llcontext = unsafe { llvm::LLVMGetModuleContext(llmod) };
90 CrateDebugContext {
91 llcontext,
92 llmod,
93 builder,
94 created_files: Default::default(),
95 created_enum_disr_types: Default::default(),
96 type_map: Default::default(),
97 namespace_map: RefCell::new(Default::default()),
98 composite_types_completed: Default::default(),
99 }
100 }
101}
102
103/// Creates any deferred debug metadata nodes
104pub fn finalize(cx: &CodegenCx<'_, '_>) {
105 if cx.dbg_cx.is_none() {
106 return;
107 }
108
109 debug!("finalize");
110
111 if gdb::needs_gdb_debug_scripts_section(cx) {
112 // Add a .debug_gdb_scripts section to this compile-unit. This will
113 // cause GDB to try and load the gdb_load_rust_pretty_printers.py file,
114 // which activates the Rust pretty printers for binary this section is
115 // contained in.
116 gdb::get_or_insert_gdb_debug_scripts_section_global(cx);
117 }
118
119 unsafe {
120 llvm::LLVMRustDIBuilderFinalize(DIB(cx));
121 // Debuginfo generation in LLVM by default uses a higher
122 // version of dwarf than macOS currently understands. We can
123 // instruct LLVM to emit an older version of dwarf, however,
124 // for macOS to understand. For more info see #11352
125 // This can be overridden using --llvm-opts -dwarf-version,N.
126 // Android has the same issue (#22398)
127 if cx.sess().target.target.options.is_like_osx ||
128 cx.sess().target.target.options.is_like_android {
129 llvm::LLVMRustAddModuleFlag(cx.llmod,
130 "Dwarf Version\0".as_ptr() as *const _,
131 2)
132 }
133
134 // Indicate that we want CodeView debug information on MSVC
135 if cx.sess().target.target.options.is_like_msvc {
136 llvm::LLVMRustAddModuleFlag(cx.llmod,
137 "CodeView\0".as_ptr() as *const _,
138 1)
139 }
140
141 // Prevent bitcode readers from deleting the debug info.
142 let ptr = "Debug Info Version\0".as_ptr();
143 llvm::LLVMRustAddModuleFlag(cx.llmod, ptr as *const _,
144 llvm::LLVMRustDebugMetadataVersion());
145 };
146}
147
148impl DebugInfoBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> {
149 fn declare_local(
150 &mut self,
151 dbg_context: &FunctionDebugContext<&'ll DISubprogram>,
152 variable_name: ast::Name,
153 variable_type: Ty<'tcx>,
154 scope_metadata: &'ll DIScope,
155 variable_access: VariableAccess<'_, &'ll Value>,
156 variable_kind: VariableKind,
157 span: Span,
158 ) {
159 assert!(!dbg_context.get_ref(span).source_locations_enabled);
160 let cx = self.cx();
161
162 let file = span_start(cx, span).file;
163 let file_metadata = file_metadata(cx,
164 &file.name,
165 dbg_context.get_ref(span).defining_crate);
166
167 let loc = span_start(cx, span);
168 let type_metadata = type_metadata(cx, variable_type, span);
169
170 let (argument_index, dwarf_tag) = match variable_kind {
171 ArgumentVariable(index) => (index as c_uint, DW_TAG_arg_variable),
172 LocalVariable => (0, DW_TAG_auto_variable)
173 };
174 let align = cx.align_of(variable_type);
175
176 let name = SmallCStr::new(&variable_name.as_str());
177 match (variable_access, &[][..]) {
178 (DirectVariable { alloca }, address_operations) |
179 (IndirectVariable {alloca, address_operations}, _) => {
180 let metadata = unsafe {
181 llvm::LLVMRustDIBuilderCreateVariable(
182 DIB(cx),
183 dwarf_tag,
184 scope_metadata,
185 name.as_ptr(),
186 file_metadata,
187 loc.line as c_uint,
188 type_metadata,
189 cx.sess().opts.optimize != config::OptLevel::No,
190 DIFlags::FlagZero,
191 argument_index,
192 align.bytes() as u32,
193 )
194 };
195 source_loc::set_debug_location(self,
196 InternalDebugLocation::new(scope_metadata, loc.line, loc.col.to_usize()));
197 unsafe {
198 let debug_loc = llvm::LLVMGetCurrentDebugLocation(self.llbuilder);
199 let instr = llvm::LLVMRustDIBuilderInsertDeclareAtEnd(
200 DIB(cx),
201 alloca,
202 metadata,
203 address_operations.as_ptr(),
204 address_operations.len() as c_uint,
205 debug_loc,
206 self.llbb());
207
208 llvm::LLVMSetInstDebugLocation(self.llbuilder, instr);
209 }
210 source_loc::set_debug_location(self, UnknownLocation);
211 }
212 }
213 }
214
215 fn set_source_location(
216 &mut self,
217 debug_context: &mut FunctionDebugContext<&'ll DISubprogram>,
218 scope: Option<&'ll DIScope>,
219 span: Span,
220 ) {
221 set_source_location(debug_context, &self, scope, span)
222 }
223 fn insert_reference_to_gdb_debug_scripts_section_global(&mut self) {
224 gdb::insert_reference_to_gdb_debug_scripts_section_global(self)
225 }
226
227 fn set_value_name(&mut self, value: &'ll Value, name: &str) {
228 let cname = SmallCStr::new(name);
229 unsafe {
230 llvm::LLVMSetValueName(value, cname.as_ptr());
231 }
232 }
233}
234
235impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> {
236 fn create_function_debug_context(
237 &self,
238 instance: Instance<'tcx>,
239 sig: ty::FnSig<'tcx>,
240 llfn: &'ll Value,
Chih-Hung Hsiehda60c852019-12-19 14:56:55 -0800241 mir: &mir::Body<'_>,
Inna Palantff3f07a2019-07-11 16:15:26 -0700242 ) -> FunctionDebugContext<&'ll DISubprogram> {
243 if self.sess().opts.debuginfo == DebugInfo::None {
244 return FunctionDebugContext::DebugInfoDisabled;
245 }
246
247 if let InstanceDef::Item(def_id) = instance.def {
248 if self.tcx().codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::NO_DEBUG) {
249 return FunctionDebugContext::FunctionWithoutDebugInfo;
250 }
251 }
252
253 let span = mir.span;
254
255 // This can be the case for functions inlined from another crate
256 if span.is_dummy() {
257 // FIXME(simulacrum): Probably can't happen; remove.
258 return FunctionDebugContext::FunctionWithoutDebugInfo;
259 }
260
261 let def_id = instance.def_id();
262 let containing_scope = get_containing_scope(self, instance);
263 let loc = span_start(self, span);
264 let file_metadata = file_metadata(self, &loc.file.name, def_id.krate);
265
266 let function_type_metadata = unsafe {
267 let fn_signature = get_function_signature(self, sig);
268 llvm::LLVMRustDIBuilderCreateSubroutineType(DIB(self), file_metadata, fn_signature)
269 };
270
271 // Find the enclosing function, in case this is a closure.
272 let def_key = self.tcx().def_key(def_id);
273 let mut name = def_key.disambiguated_data.data.to_string();
274
275 let enclosing_fn_def_id = self.tcx().closure_base_def_id(def_id);
276
277 // Get_template_parameters() will append a `<...>` clause to the function
278 // name if necessary.
279 let generics = self.tcx().generics_of(enclosing_fn_def_id);
280 let substs = instance.substs.truncate_to(self.tcx(), generics);
281 let template_parameters = get_template_parameters(self,
282 &generics,
283 substs,
284 file_metadata,
285 &mut name);
286
287 // Get the linkage_name, which is just the symbol name
288 let linkage_name = mangled_name_of_instance(self, instance);
289
290 let scope_line = span_start(self, span).line;
291
292 let function_name = CString::new(name).unwrap();
293 let linkage_name = SmallCStr::new(&linkage_name.as_str());
294
295 let mut flags = DIFlags::FlagPrototyped;
296
297 if self.layout_of(sig.output()).abi.is_uninhabited() {
298 flags |= DIFlags::FlagNoReturn;
299 }
300
301 let mut spflags = DISPFlags::SPFlagDefinition;
302 if is_node_local_to_unit(self, def_id) {
303 spflags |= DISPFlags::SPFlagLocalToUnit;
304 }
305 if self.sess().opts.optimize != config::OptLevel::No {
306 spflags |= DISPFlags::SPFlagOptimized;
307 }
308 if let Some((id, _)) = self.tcx.entry_fn(LOCAL_CRATE) {
309 if id == def_id {
310 spflags |= DISPFlags::SPFlagMainSubprogram;
311 }
312 }
313
314 let fn_metadata = unsafe {
315 llvm::LLVMRustDIBuilderCreateFunction(
316 DIB(self),
317 containing_scope,
318 function_name.as_ptr(),
319 linkage_name.as_ptr(),
320 file_metadata,
321 loc.line as c_uint,
322 function_type_metadata,
323 scope_line as c_uint,
324 flags,
325 spflags,
326 llfn,
327 template_parameters,
328 None)
329 };
330
331 // Initialize fn debug context (including scope map and namespace map)
332 let fn_debug_context = FunctionDebugContextData {
333 fn_metadata,
334 source_locations_enabled: false,
335 defining_crate: def_id.krate,
336 };
337
338 return FunctionDebugContext::RegularContext(fn_debug_context);
339
340 fn get_function_signature<'ll, 'tcx>(
341 cx: &CodegenCx<'ll, 'tcx>,
342 sig: ty::FnSig<'tcx>,
343 ) -> &'ll DIArray {
344 if cx.sess().opts.debuginfo == DebugInfo::Limited {
345 return create_DIArray(DIB(cx), &[]);
346 }
347
348 let mut signature = Vec::with_capacity(sig.inputs().len() + 1);
349
350 // Return type -- llvm::DIBuilder wants this at index 0
351 signature.push(match sig.output().sty {
352 ty::Tuple(ref tys) if tys.is_empty() => None,
353 _ => Some(type_metadata(cx, sig.output(), syntax_pos::DUMMY_SP))
354 });
355
356 let inputs = if sig.abi == Abi::RustCall {
357 &sig.inputs()[..sig.inputs().len() - 1]
358 } else {
359 sig.inputs()
360 };
361
362 // Arguments types
363 if cx.sess().target.target.options.is_like_msvc {
364 // FIXME(#42800):
365 // There is a bug in MSDIA that leads to a crash when it encounters
366 // a fixed-size array of `u8` or something zero-sized in a
367 // function-type (see #40477).
368 // As a workaround, we replace those fixed-size arrays with a
369 // pointer-type. So a function `fn foo(a: u8, b: [u8; 4])` would
370 // appear as `fn foo(a: u8, b: *const u8)` in debuginfo,
371 // and a function `fn bar(x: [(); 7])` as `fn bar(x: *const ())`.
372 // This transformed type is wrong, but these function types are
373 // already inaccurate due to ABI adjustments (see #42800).
374 signature.extend(inputs.iter().map(|&t| {
375 let t = match t.sty {
376 ty::Array(ct, _)
377 if (ct == cx.tcx.types.u8) || cx.layout_of(ct).is_zst() => {
378 cx.tcx.mk_imm_ptr(ct)
379 }
380 _ => t
381 };
382 Some(type_metadata(cx, t, syntax_pos::DUMMY_SP))
383 }));
384 } else {
385 signature.extend(inputs.iter().map(|t| {
386 Some(type_metadata(cx, t, syntax_pos::DUMMY_SP))
387 }));
388 }
389
390 if sig.abi == Abi::RustCall && !sig.inputs().is_empty() {
391 if let ty::Tuple(args) = sig.inputs()[sig.inputs().len() - 1].sty {
392 signature.extend(
393 args.iter().map(|argument_type| {
Chih-Hung Hsiehfd666f22019-12-19 14:34:18 -0800394 Some(type_metadata(cx, argument_type.expect_ty(), syntax_pos::DUMMY_SP))
Inna Palantff3f07a2019-07-11 16:15:26 -0700395 })
396 );
397 }
398 }
399
400 create_DIArray(DIB(cx), &signature[..])
401 }
402
403 fn get_template_parameters<'ll, 'tcx>(
404 cx: &CodegenCx<'ll, 'tcx>,
405 generics: &ty::Generics,
406 substs: SubstsRef<'tcx>,
407 file_metadata: &'ll DIFile,
408 name_to_append_suffix_to: &mut String,
409 ) -> &'ll DIArray {
410 if substs.types().next().is_none() {
411 return create_DIArray(DIB(cx), &[]);
412 }
413
414 name_to_append_suffix_to.push('<');
415 for (i, actual_type) in substs.types().enumerate() {
416 if i != 0 {
417 name_to_append_suffix_to.push_str(",");
418 }
419
420 let actual_type =
421 cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), actual_type);
422 // Add actual type name to <...> clause of function name
Chih-Hung Hsiehfd666f22019-12-19 14:34:18 -0800423 let actual_type_name = compute_debuginfo_type_name(cx.tcx(),
Inna Palantff3f07a2019-07-11 16:15:26 -0700424 actual_type,
425 true);
426 name_to_append_suffix_to.push_str(&actual_type_name[..]);
427 }
428 name_to_append_suffix_to.push('>');
429
430 // Again, only create type information if full debuginfo is enabled
431 let template_params: Vec<_> = if cx.sess().opts.debuginfo == DebugInfo::Full {
432 let names = get_parameter_names(cx, generics);
433 substs.iter().zip(names).filter_map(|(kind, name)| {
434 if let UnpackedKind::Type(ty) = kind.unpack() {
435 let actual_type =
436 cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), ty);
437 let actual_type_metadata =
438 type_metadata(cx, actual_type, syntax_pos::DUMMY_SP);
439 let name = SmallCStr::new(&name.as_str());
440 Some(unsafe {
441 Some(llvm::LLVMRustDIBuilderCreateTemplateTypeParameter(
442 DIB(cx),
443 None,
444 name.as_ptr(),
445 actual_type_metadata,
446 file_metadata,
447 0,
448 0,
449 ))
450 })
451 } else {
452 None
453 }
454 }).collect()
455 } else {
456 vec![]
457 };
458
459 return create_DIArray(DIB(cx), &template_params[..]);
460 }
461
462 fn get_parameter_names(cx: &CodegenCx<'_, '_>,
463 generics: &ty::Generics)
464 -> Vec<InternedString> {
465 let mut names = generics.parent.map_or(vec![], |def_id| {
466 get_parameter_names(cx, cx.tcx.generics_of(def_id))
467 });
468 names.extend(generics.params.iter().map(|param| param.name));
469 names
470 }
471
472 fn get_containing_scope<'ll, 'tcx>(
473 cx: &CodegenCx<'ll, 'tcx>,
474 instance: Instance<'tcx>,
475 ) -> &'ll DIScope {
476 // First, let's see if this is a method within an inherent impl. Because
477 // if yes, we want to make the result subroutine DIE a child of the
478 // subroutine's self-type.
479 let self_type = cx.tcx.impl_of_method(instance.def_id()).and_then(|impl_def_id| {
480 // If the method does *not* belong to a trait, proceed
481 if cx.tcx.trait_id_of_impl(impl_def_id).is_none() {
482 let impl_self_ty = cx.tcx.subst_and_normalize_erasing_regions(
483 instance.substs,
484 ty::ParamEnv::reveal_all(),
485 &cx.tcx.type_of(impl_def_id),
486 );
487
488 // Only "class" methods are generally understood by LLVM,
489 // so avoid methods on other types (e.g., `<*mut T>::null`).
490 match impl_self_ty.sty {
491 ty::Adt(def, ..) if !def.is_box() => {
492 Some(type_metadata(cx, impl_self_ty, syntax_pos::DUMMY_SP))
493 }
494 _ => None
495 }
496 } else {
497 // For trait method impls we still use the "parallel namespace"
498 // strategy
499 None
500 }
501 });
502
503 self_type.unwrap_or_else(|| {
504 namespace::item_namespace(cx, DefId {
505 krate: instance.def_id().krate,
506 index: cx.tcx
507 .def_key(instance.def_id())
508 .parent
509 .expect("get_containing_scope: missing parent?")
510 })
511 })
512 }
513 }
514
515 fn create_vtable_metadata(
516 &self,
517 ty: Ty<'tcx>,
518 vtable: Self::Value,
519 ) {
520 metadata::create_vtable_metadata(self, ty, vtable)
521 }
522
523 fn create_mir_scopes(
524 &self,
Chih-Hung Hsiehda60c852019-12-19 14:56:55 -0800525 mir: &mir::Body<'_>,
Inna Palantff3f07a2019-07-11 16:15:26 -0700526 debug_context: &mut FunctionDebugContext<&'ll DISubprogram>,
527 ) -> IndexVec<mir::SourceScope, MirDebugScope<&'ll DIScope>> {
528 create_scope_map::create_mir_scopes(self, mir, debug_context)
529 }
530
531 fn extend_scope_to_file(
532 &self,
533 scope_metadata: &'ll DIScope,
534 file: &syntax_pos::SourceFile,
535 defining_crate: CrateNum,
536 ) -> &'ll DILexicalBlock {
537 metadata::extend_scope_to_file(&self, scope_metadata, file, defining_crate)
538 }
539
540 fn debuginfo_finalize(&self) {
541 finalize(self)
542 }
543
Chih-Hung Hsiehfd666f22019-12-19 14:34:18 -0800544 fn debuginfo_upvar_ops_sequence(&self, byte_offset_of_var_in_env: u64) -> [i64; 4] {
Inna Palantff3f07a2019-07-11 16:15:26 -0700545 unsafe {
546 [llvm::LLVMRustDIBuilderCreateOpDeref(),
547 llvm::LLVMRustDIBuilderCreateOpPlusUconst(),
548 byte_offset_of_var_in_env as i64,
549 llvm::LLVMRustDIBuilderCreateOpDeref()]
550 }
551 }
552}