tcx: TyCtxt<'_>, |
codegen_unit_name: &str, |
debug_context: &CrateDebugContext<'ll, '_>, |
) -> &'ll DIDescriptor { |
let mut name_in_debuginfo = match tcx.sess.local_crate_source_file { |
Some(ref path) => path.clone(), |
None => PathBuf::from(&*tcx.crate_name(LOCAL_CRATE).as_str()), |
}; |
|
// The OSX linker has an idiosyncrasy where it will ignore some debuginfo |
// if multiple object files with the same `DW_AT_name` are linked together. |
// As a workaround we generate unique names for each object file. Those do |
// not correspond to an actual source file but that should be harmless. |
if tcx.sess.target.is_like_osx { |
name_in_debuginfo.push("@"); |
name_in_debuginfo.push(codegen_unit_name); |
} |
|
debug!("compile_unit_metadata: {:?}", name_in_debuginfo); |
let rustc_producer = |
format!("rustc version {}", option_env!("CFG_VERSION").expect("CFG_VERSION"),); |
// FIXME(#41252) Remove "clang LLVM" if we can get GDB and LLVM to play nice. |
let producer = format!("clang LLVM ({})", rustc_producer); |
|
let name_in_debuginfo = name_in_debuginfo.to_string_lossy(); |
let flags = "\0"; |
|
let out_dir = &tcx.output_filenames(LOCAL_CRATE).out_directory; |
let split_name = tcx |
.output_filenames(LOCAL_CRATE) |
.split_dwarf_filename(tcx.sess.opts.debugging_opts.split_dwarf, Some(codegen_unit_name)) |
.unwrap_or_default(); |
let out_dir = out_dir.to_str().unwrap(); |
let split_name = split_name.to_str().unwrap(); |
|
// FIXME(#60020): |
// |
// This should actually be |
// |
// let kind = DebugEmissionKind::from_generic(tcx.sess.opts.debuginfo); |
// |
// That is, we should set LLVM's emission kind to `LineTablesOnly` if |
// we are compiling with "limited" debuginfo. However, some of the |
// existing tools relied on slightly more debuginfo being generated than |
// would be the case with `LineTablesOnly`, and we did not want to break |
// these tools in a "drive-by fix", without a good idea or plan about |
// what limited debuginfo should exactly look like. So for now we keep |
// the emission kind as `FullDebug`. |
// |
// See https://github.com/rust-lang/rust/issues/60020 for details. |
let kind = DebugEmissionKind::FullDebug; |
assert!(tcx.sess.opts.debuginfo != DebugInfo::None); |
|
unsafe { |
let file_metadata = llvm::LLVMRustDIBuilderCreateFile( |
debug_context.builder, |
name_in_debuginfo.as_ptr().cast(), |
name_in_debuginfo.len(), |
out_dir.as_ptr().cast(), |
out_dir.len(), |
llvm::ChecksumKind::None, |
ptr::null(), |
0, |
); |
|
let unit_metadata = llvm::LLVMRustDIBuilderCreateCompileUnit( |
debug_context.builder, |
DW_LANG_RUST, |
file_metadata, |
producer.as_ptr().cast(), |
producer.len(), |
tcx.sess.opts.optimize != config::OptLevel::No, |
flags.as_ptr().cast(), |
0, |
split_name.as_ptr().cast(), |
split_name.len(), |
kind, |
0, |
tcx.sess.opts.debugging_opts.split_dwarf_inlining, |
); |
|
if tcx.sess.opts.debugging_opts.profile { |
let cu_desc_metadata = |
llvm::LLVMRustMetadataAsValue(debug_context.llcontext, unit_metadata); |
let default_gcda_path = &tcx.output_filenames(LOCAL_CRATE).with_extension("gcda"); |
let gcda_path = |
tcx.sess.opts.debugging_opts.profile_emit.as_ref().unwrap_or(default_gcda_path); |
|
let gcov_cu_info = [ |
path_to_mdstring( |
debug_context.llcontext, |
&tcx.output_filenames(LOCAL_CRATE).with_extension("gcno"), |
), |
path_to_mdstring(debug_context.llcontext, &gcda_path), |
cu_desc_metadata, |
]; |
let gcov_metadata = llvm::LLVMMDNodeInContext( |
debug_context.llcontext, |
gcov_cu_info.as_ptr(), |
gcov_cu_info.len() as c_uint, |
); |
|
let llvm_gcov_ident = const_cstr!("llvm.gcov"); |
llvm::LLVMAddNamedMetadataOperand( |
debug_context.llmod, |
llvm_gcov_ident.as_ptr(), |
gcov_metadata, |
); |
} |
|
// Insert `llvm.ident` metadata on the wasm32 targets since that will |
// get hooked up to the "producer" sections `processed-by` information. |
if tcx.sess.opts.target_triple.triple().starts_with("wasm32") { |
let name_metadata = llvm::LLVMMDStringInContext( |
debug_context.llcontext, |
rustc_producer.as_ptr().cast(), |
rustc_producer.as_bytes().len() as c_uint, |
); |
llvm::LLVMAddNamedMetadataOperand( |
debug_context.llmod, |
const_cstr!("llvm.ident").as_ptr(), |
llvm::LLVMMDNodeInContext(debug_context.llcontext, &name_metadata, 1), |
); |
} |
|
return unit_metadata; |
}; |
|
fn path_to_mdstring(llcx: &'ll llvm::Context, path: &Path) -> &'ll Value { |
let path_str = path_to_c_string(path); |
unsafe { |
llvm::LLVMMDStringInContext( |
llcx, |
path_str.as_ptr(), |
path_str.as_bytes().len() as c_uint, |
) |
} |
} |
} |