From a68b8947f8d0762f77362a4fc8c144b38e8751fb Mon Sep 17 00:00:00 2001 From: LegionMammal978 Date: Fri, 14 Jan 2022 16:23:48 -0500 Subject: [PATCH] Fix stack overflow in llvm::Verifier::visitMDNode() This code is a proof-of-concept more than anything else. It is not ready to be merged in its current state. Any version of this fix must somehow measure the depth of the metadata nodes (or a rough upper bound), and it must somehow send that depth to the LLVM codegen entry point. There is likely a tradeoff to be made between performance and readability here. --- compiler/rustc_codegen_llvm/src/back/write.rs | 15 +++- .../src/debuginfo/create_scope_map.rs | 24 ++--- .../src/debuginfo/metadata.rs | 79 ++++++++++------ .../src/debuginfo/metadata/enums/cpp_like.rs | 8 +- .../src/debuginfo/metadata/enums/mod.rs | 20 +++-- .../src/debuginfo/metadata/enums/native.rs | 63 +++++++------ .../src/debuginfo/metadata/type_map.rs | 8 +- .../rustc_codegen_llvm/src/debuginfo/mod.rs | 90 +++++++++++++++---- .../src/debuginfo/namespace.rs | 1 + .../rustc_codegen_llvm/src/debuginfo/utils.rs | 7 +- compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 3 + compiler/rustc_data_structures/src/stack.rs | 5 ++ 12 files changed, 219 insertions(+), 104 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index 99e30531c226f..dc7c5dcbc7e67 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -19,6 +19,7 @@ use rustc_codegen_ssa::traits::*; use rustc_codegen_ssa::{CompiledModule, ModuleCodegen}; use rustc_data_structures::profiling::SelfProfilerRef; use rustc_data_structures::small_c_str::SmallCStr; +use rustc_data_structures::stack::ensure_recursive_stack; use rustc_errors::{FatalError, Handler, Level}; use rustc_fs_util::{link_or_copy, path_to_c_string}; use rustc_middle::bug; @@ -757,6 +758,13 @@ pub(crate) unsafe fn codegen( create_msvc_imps(cgcx, llcx, llmod); } + let stack_size = crate::debuginfo::LLMOD_DEPTHS + .lock() + .unwrap() + .get(&(llmod as *const _ as usize)) + .unwrap_or(&0) + * 256; + // A codegen-specific pass manager is used to generate object // files for an LLVM module. // @@ -769,6 +777,7 @@ pub(crate) unsafe fn codegen( tm: &'ll llvm::TargetMachine, llmod: &'ll llvm::Module, no_builtins: bool, + stack_size: usize, f: F, ) -> R where @@ -777,7 +786,7 @@ pub(crate) unsafe fn codegen( let cpm = llvm::LLVMCreatePassManager(); llvm::LLVMAddAnalysisPasses(tm, cpm); llvm::LLVMRustAddLibraryInfo(cpm, llmod, no_builtins); - f(cpm) + ensure_recursive_stack(stack_size, || f(cpm)) } // Two things to note: @@ -881,7 +890,7 @@ pub(crate) unsafe fn codegen( } else { llmod }; - with_codegen(tm, llmod, config.no_builtins, |cpm| { + with_codegen(tm, llmod, config.no_builtins, stack_size, |cpm| { write_output_file( diag_handler, tm, @@ -916,7 +925,7 @@ pub(crate) unsafe fn codegen( (_, SplitDwarfKind::Split) => Some(dwo_out.as_path()), }; - with_codegen(tm, llmod, config.no_builtins, |cpm| { + with_codegen(tm, llmod, config.no_builtins, stack_size, |cpm| { write_output_file( diag_handler, tm, diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs b/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs index 76caa3ceaafae..ef002e857aa40 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs @@ -1,5 +1,5 @@ use super::metadata::file_metadata; -use super::utils::DIB; +use super::utils::{self, DIB}; use rustc_codegen_ssa::mir::debuginfo::{DebugScope, FunctionDebugContext}; use rustc_codegen_ssa::traits::*; @@ -97,15 +97,19 @@ fn make_mir_scope<'ll, 'tcx>( let callee_fn_abi = cx.fn_abi_of_instance(callee, ty::List::empty()); cx.dbg_scope_fn(callee, callee_fn_abi, None) } - None => unsafe { - llvm::LLVMRustDIBuilderCreateLexicalBlock( - DIB(cx), - parent_scope.dbg_scope.unwrap(), - file_metadata, - loc.line, - loc.col, - ) - }, + None => { + let dbg_scope = unsafe { + llvm::LLVMRustDIBuilderCreateLexicalBlock( + DIB(cx), + parent_scope.dbg_scope.unwrap(), + file_metadata, + loc.line, + loc.col, + ) + }; + utils::debug_context(cx).add_di_node(dbg_scope); + dbg_scope + } }; let inlined_at = scope_data.inlined.map(|(_, callsite_span)| { diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index 502aae33b8c99..50be7bb103084 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -136,10 +136,10 @@ fn build_fixed_size_array_di_node<'ll, 'tcx>( let upper_bound = len.eval_usize(cx.tcx, ty::ParamEnv::reveal_all()) as c_longlong; - let subrange = - unsafe { Some(llvm::LLVMRustDIBuilderGetOrCreateSubrange(DIB(cx), 0, upper_bound)) }; + let subrange = unsafe { llvm::LLVMRustDIBuilderGetOrCreateSubrange(DIB(cx), 0, upper_bound) }; + debug_context(cx).add_di_node(subrange); - let subscripts = create_DIArray(DIB(cx), &[subrange]); + let subscripts = create_DIArray(cx, &[Some(subrange)]); let di_node = unsafe { llvm::LLVMRustDIBuilderCreateArrayType( DIB(cx), @@ -149,6 +149,7 @@ fn build_fixed_size_array_di_node<'ll, 'tcx>( subscripts, ) }; + debug_context(cx).add_di_node(di_node); DINodeCreationResult::new(di_node, false) } @@ -204,6 +205,7 @@ fn build_pointer_or_reference_di_node<'ll, 'tcx>( ptr_type_debuginfo_name.len(), ) }; + debug_context(cx).add_di_node(di_node); DINodeCreationResult { di_node, already_stored_in_typemap: false } } @@ -255,6 +257,7 @@ fn build_pointer_or_reference_di_node<'ll, 'tcx>( 0, ) }; + debug_context(cx).add_di_node(data_ptr_type_di_node); smallvec![ build_field_di_node( @@ -332,9 +335,10 @@ fn build_subroutine_type_di_node<'ll, 'tcx>( let fn_di_node = unsafe { llvm::LLVMRustDIBuilderCreateSubroutineType( DIB(cx), - create_DIArray(DIB(cx), &signature_di_nodes[..]), + create_DIArray(cx, &signature_di_nodes[..]), ) }; + debug_context(cx).add_nested_di_node(fn_di_node, &[3]); // This is actually a function pointer, so wrap it in pointer DI. let name = compute_debuginfo_type_name(cx.tcx, fn_ty, false); @@ -349,6 +353,7 @@ fn build_subroutine_type_di_node<'ll, 'tcx>( name.len(), ) }; + debug_context(cx).add_di_node(di_node); DINodeCreationResult::new(di_node, false) } @@ -498,7 +503,7 @@ pub fn type_di_node<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'ll D // FIXME(mw): Cache this via a regular UniqueTypeId instead of an extra field in the debug context. fn recursion_marker_type_di_node<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>) -> &'ll DIType { *debug_context(cx).recursion_marker_type.get_or_init(move || { - unsafe { + let di_node = unsafe { // The choice of type here is pretty arbitrary - // anything reading the debuginfo for a recursive // type is going to see *something* weird - the only @@ -517,7 +522,9 @@ fn recursion_marker_type_di_node<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>) -> &'ll D cx.tcx.data_layout.pointer_size.bits(), DW_ATE_unsigned, ) - } + }; + debug_context(cx).add_di_node(di_node); + di_node }) } @@ -595,6 +602,7 @@ fn file_metadata_raw<'ll>( hash_value.len(), ) }; + debug_context(cx).add_di_node(file_metadata); v.insert(file_metadata); file_metadata @@ -680,6 +688,7 @@ fn build_basic_type_di_node<'ll, 'tcx>( encoding, ) }; + debug_context(cx).add_di_node(ty_di_node); if !cpp_like_debuginfo { return DINodeCreationResult::new(ty_di_node, false); @@ -703,6 +712,7 @@ fn build_basic_type_di_node<'ll, 'tcx>( None, ) }; + debug_context(cx).add_di_node(typedef_di_node); DINodeCreationResult::new(typedef_di_node, false) } @@ -740,18 +750,17 @@ fn build_param_type_di_node<'ll, 'tcx>( ) -> DINodeCreationResult<'ll> { debug!("build_param_type_di_node: {:?}", t); let name = format!("{:?}", t); - DINodeCreationResult { - di_node: unsafe { - llvm::LLVMRustDIBuilderCreateBasicType( - DIB(cx), - name.as_ptr().cast(), - name.len(), - Size::ZERO.bits(), - DW_ATE_unsigned, - ) - }, - already_stored_in_typemap: false, - } + let di_node = unsafe { + llvm::LLVMRustDIBuilderCreateBasicType( + DIB(cx), + name.as_ptr().cast(), + name.len(), + Size::ZERO.bits(), + DW_ATE_unsigned, + ) + }; + debug_context(cx).add_di_node(di_node); + DINodeCreationResult { di_node, already_stored_in_typemap: false } } pub fn build_compile_unit_di_node<'ll, 'tcx>( @@ -838,6 +847,7 @@ pub fn build_compile_unit_di_node<'ll, 'tcx>( ptr::null(), 0, ); + debug_context.add_di_node(compile_unit_file); let unit_metadata = llvm::LLVMRustDIBuilderCreateCompileUnit( debug_context.builder, @@ -857,6 +867,7 @@ pub fn build_compile_unit_di_node<'ll, 'tcx>( 0, tcx.sess.opts.debugging_opts.split_dwarf_inlining, ); + debug_context.add_di_node(unit_metadata); if tcx.sess.opts.debugging_opts.profile { let cu_desc_metadata = @@ -924,7 +935,7 @@ fn build_field_di_node<'ll, 'tcx>( flags: DIFlags, type_di_node: &'ll DIType, ) -> &'ll DIType { - unsafe { + let di_node = unsafe { llvm::LLVMRustDIBuilderCreateMemberType( DIB(cx), owner, @@ -938,7 +949,9 @@ fn build_field_di_node<'ll, 'tcx>( flags, type_di_node, ) - } + }; + debug_context(cx).add_di_node(di_node); + di_node } /// Creates the debuginfo node for a Rust struct type. Maybe be a regular struct or a tuple-struct. @@ -1257,7 +1270,7 @@ fn build_generic_type_param_di_nodes<'ll, 'tcx>( cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), ty); let actual_type_di_node = type_di_node(cx, actual_type); let name = name.as_str(); - Some(unsafe { + let template_param = unsafe { llvm::LLVMRustDIBuilderCreateTemplateTypeParameter( DIB(cx), None, @@ -1265,7 +1278,9 @@ fn build_generic_type_param_di_nodes<'ll, 'tcx>( name.len(), actual_type_di_node, ) - }) + }; + debug_context(cx).add_di_node(template_param); + Some(template_param) } else { None } @@ -1326,7 +1341,7 @@ pub fn build_global_var_di_node<'ll>(cx: &CodegenCx<'ll, '_>, def_id: DefId, glo let global_align = cx.align_of(variable_type); - unsafe { + let di_node = unsafe { llvm::LLVMRustDIBuilderCreateStaticVariable( DIB(cx), Some(var_scope), @@ -1341,8 +1356,9 @@ pub fn build_global_var_di_node<'ll>(cx: &CodegenCx<'ll, '_>, def_id: DefId, glo global, None, global_align.bytes() as u32, - ); - } + ) + }; + debug_context(cx).add_nested_di_node(di_node, &[0, 1]); } /// Generates LLVM debuginfo for a vtable. @@ -1467,7 +1483,7 @@ pub fn create_vtable_di_node<'ll, 'tcx>( let vtable_type_di_node = build_vtable_type_di_node(cx, ty, poly_trait_ref); let linkage_name = ""; - unsafe { + let di_node = unsafe { llvm::LLVMRustDIBuilderCreateStaticVariable( DIB(cx), NO_SCOPE_METADATA, @@ -1482,8 +1498,9 @@ pub fn create_vtable_di_node<'ll, 'tcx>( vtable, None, 0, - ); - } + ) + }; + debug_context(cx).add_nested_di_node(di_node, &[0, 1]); } /// Creates an "extension" of an existing `DIScope` into another file. @@ -1493,7 +1510,11 @@ pub fn extend_scope_to_file<'ll>( file: &SourceFile, ) -> &'ll DILexicalBlock { let file_metadata = file_metadata(cx, file); - unsafe { llvm::LLVMRustDIBuilderCreateLexicalBlockFile(DIB(cx), scope_metadata, file_metadata) } + let di_node = unsafe { + llvm::LLVMRustDIBuilderCreateLexicalBlockFile(DIB(cx), scope_metadata, file_metadata) + }; + debug_context(cx).add_di_node(di_node); + di_node } pub fn tuple_field_name(field_index: usize) -> Cow<'static, str> { diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs index d6e2c8ccdf44a..9d803bb148f53 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs @@ -27,7 +27,7 @@ use crate::{ unknown_file_metadata, DINodeCreationResult, SmallVec, NO_GENERICS, NO_SCOPE_METADATA, UNKNOWN_LINE_NUMBER, }, - utils::DIB, + utils::{debug_context, DIB}, }, llvm::{ self, @@ -441,7 +441,7 @@ fn build_union_fields_for_direct_tag_enum_or_generator<'ll, 'tcx>( // We use LLVMRustDIBuilderCreateMemberType() member type directly because // the build_field_di_node() function does not support specifying a source location, // which is something that we don't do anywhere else. - unsafe { + let member_type_di_node = unsafe { llvm::LLVMRustDIBuilderCreateMemberType( DIB(cx), enum_type_di_node, @@ -458,7 +458,9 @@ fn build_union_fields_for_direct_tag_enum_or_generator<'ll, 'tcx>( DIFlags::FlagZero, variant_member_info.variant_struct_type_di_node, ) - } + }; + debug_context(cx).add_di_node(member_type_di_node); + member_type_di_node })); debug_assert_eq!( diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs index 73e01d0453b25..7d56a9a0a890c 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs @@ -26,7 +26,7 @@ use crate::{ type_map::{self, Stub}, unknown_file_metadata, UNKNOWN_LINE_NUMBER, }, - utils::{create_DIArray, get_namespace_for_item, DIB}, + utils::{create_DIArray, debug_context, get_namespace_for_item, DIB}, }, llvm::{ self, @@ -163,22 +163,24 @@ fn build_enumeration_type_di_node<'ll, 'tcx>( let enumerator_di_nodes: SmallVec> = variants .map(|(discr, variant_name)| { - unsafe { - Some(llvm::LLVMRustDIBuilderCreateEnumerator( + let enumerator_di_node = unsafe { + llvm::LLVMRustDIBuilderCreateEnumerator( DIB(cx), variant_name.as_ptr().cast(), variant_name.len(), // FIXME: what if enumeration has i128 discriminant? discr.val as i64, is_unsigned, - )) - } + ) + }; + debug_context(cx).add_di_node(enumerator_di_node); + Some(enumerator_di_node) }) .collect(); let (size, align) = cx.size_and_align_of(base_type); - unsafe { + let di_node = unsafe { llvm::LLVMRustDIBuilderCreateEnumerationType( DIB(cx), containing_scope, @@ -188,11 +190,13 @@ fn build_enumeration_type_di_node<'ll, 'tcx>( UNKNOWN_LINE_NUMBER, size.bits(), align.bits() as u32, - create_DIArray(DIB(cx), &enumerator_di_nodes[..]), + create_DIArray(cx, &enumerator_di_nodes[..]), type_di_node(cx, base_type), true, ) - } + }; + debug_context(cx).add_di_node(di_node); + di_node } /// Build the debuginfo node for the struct type describing a single variant of an enum. diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs index f1935e0ec31af..bbbd5695268f8 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs @@ -11,7 +11,7 @@ use crate::{ unknown_file_metadata, DINodeCreationResult, SmallVec, NO_GENERICS, UNKNOWN_LINE_NUMBER, }, - utils::{create_DIArray, get_namespace_for_item, DIB}, + utils::{create_DIArray, debug_context, get_namespace_for_item, DIB}, }, llvm::{ self, @@ -243,28 +243,29 @@ fn build_enum_variant_part_di_node<'ll, 'tcx>( let variant_part_unique_type_id = UniqueTypeId::for_enum_variant_part(cx.tcx, enum_type_and_layout.ty); - let stub = StubInfo::new( - cx, - variant_part_unique_type_id, - |cx, variant_part_unique_type_id_str| unsafe { - let variant_part_name = ""; - llvm::LLVMRustDIBuilderCreateVariantPart( - DIB(cx), - enum_type_di_node, - variant_part_name.as_ptr().cast(), - variant_part_name.len(), - unknown_file_metadata(cx), - UNKNOWN_LINE_NUMBER, - enum_type_and_layout.size.bits(), - enum_type_and_layout.align.abi.bits() as u32, - DIFlags::FlagZero, - tag_member_di_node, - create_DIArray(DIB(cx), &[]), - variant_part_unique_type_id_str.as_ptr().cast(), - variant_part_unique_type_id_str.len(), - ) - }, - ); + let stub = + StubInfo::new(cx, variant_part_unique_type_id, |cx, variant_part_unique_type_id_str| { + let variant_part_di_node = unsafe { + let variant_part_name = ""; + llvm::LLVMRustDIBuilderCreateVariantPart( + DIB(cx), + enum_type_di_node, + variant_part_name.as_ptr().cast(), + variant_part_name.len(), + unknown_file_metadata(cx), + UNKNOWN_LINE_NUMBER, + enum_type_and_layout.size.bits(), + enum_type_and_layout.align.abi.bits() as u32, + DIFlags::FlagZero, + tag_member_di_node, + create_DIArray(cx, &[]), + variant_part_unique_type_id_str.as_ptr().cast(), + variant_part_unique_type_id_str.len(), + ) + }; + debug_context(cx).add_di_node(variant_part_di_node); + variant_part_di_node + }); type_map::build_type_with_children( cx, @@ -330,8 +331,8 @@ fn build_discr_member_di_node<'ll, 'tcx>( let tag_base_type = tag_base_type(cx, enum_or_generator_type_and_layout); let (size, align) = cx.size_and_align_of(tag_base_type); - unsafe { - Some(llvm::LLVMRustDIBuilderCreateMemberType( + let di_node = unsafe { + llvm::LLVMRustDIBuilderCreateMemberType( DIB(cx), containing_scope, tag_name.as_ptr().cast(), @@ -343,8 +344,10 @@ fn build_discr_member_di_node<'ll, 'tcx>( enum_or_generator_type_and_layout.fields.offset(tag_field).bits(), DIFlags::FlagArtificial, type_di_node(cx, tag_base_type), - )) - } + ) + }; + debug_context(cx).add_di_node(di_node); + Some(di_node) } } } @@ -402,7 +405,7 @@ fn build_enum_variant_member_di_node<'ll, 'tcx>( .source_info .unwrap_or_else(|| (unknown_file_metadata(cx), UNKNOWN_LINE_NUMBER)); - unsafe { + let di_node = unsafe { llvm::LLVMRustDIBuilderCreateVariantMemberType( DIB(cx), variant_part_di_node, @@ -417,7 +420,9 @@ fn build_enum_variant_member_di_node<'ll, 'tcx>( DIFlags::FlagZero, variant_member_info.variant_struct_type_di_node, ) - } + }; + debug_context(cx).add_di_node(di_node); + di_node } /// Information needed for building a `DW_TAG_variant`: diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs index 87fbb737ea8a9..3df11a9dc95c2 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs @@ -175,7 +175,7 @@ pub(super) fn stub<'ll, 'tcx>( containing_scope: Option<&'ll DIScope>, flags: DIFlags, ) -> StubInfo<'ll, 'tcx> { - let empty_array = create_DIArray(DIB(cx), &[]); + let empty_array = create_DIArray(cx, &[]); let unique_type_id_str = unique_type_id.generate_unique_id_string(cx.tcx); let metadata = match kind { @@ -222,6 +222,7 @@ pub(super) fn stub<'ll, 'tcx>( ) }, }; + debug_context(cx).add_di_node(metadata); StubInfo { metadata, unique_type_id } } @@ -251,8 +252,8 @@ pub(super) fn build_type_with_children<'ll, 'tcx>( if !(members.is_empty() && generics.is_empty()) { unsafe { - let members_array = create_DIArray(DIB(cx), &members[..]); - let generics_array = create_DIArray(DIB(cx), &generics[..]); + let members_array = create_DIArray(cx, &members[..]); + let generics_array = create_DIArray(cx, &generics[..]); llvm::LLVMRustDICompositeTypeReplaceArrays( DIB(cx), stub_info.metadata, @@ -260,6 +261,7 @@ pub(super) fn build_type_with_children<'ll, 'tcx>( Some(generics_array), ); } + debug_context(cx).add_di_node(stub_info.metadata); } DINodeCreationResult { di_node: stub_info.metadata, already_stored_in_typemap: true } diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs index 4e6d3f88e6719..9e67a38a79d77 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs @@ -5,7 +5,7 @@ use rustc_codegen_ssa::mir::debuginfo::VariableKind::*; use self::metadata::{file_metadata, type_di_node}; use self::metadata::{UNKNOWN_COLUMN_NUMBER, UNKNOWN_LINE_NUMBER}; use self::namespace::mangled_name_of_instance; -use self::utils::{create_DIArray, is_node_local_to_unit, DIB}; +use self::utils::{create_DIArray, debug_context, is_node_local_to_unit, DIB}; use crate::abi::FnAbi; use crate::builder::Builder; @@ -38,7 +38,8 @@ use libc::c_uint; use smallvec::SmallVec; use std::cell::RefCell; use std::iter; -use std::lazy::OnceCell; +use std::lazy::{OnceCell, SyncLazy}; +use std::sync::Mutex; use tracing::debug; mod create_scope_map; @@ -56,6 +57,8 @@ const DW_TAG_auto_variable: c_uint = 0x100; #[allow(non_upper_case_globals)] const DW_TAG_arg_variable: c_uint = 0x101; +pub static LLMOD_DEPTHS: SyncLazy>> = SyncLazy::new(Default::default); + /// A context object for maintaining all state needed by the debuginfo module. pub struct CodegenUnitDebugContext<'ll, 'tcx> { llcontext: &'ll llvm::Context, @@ -66,6 +69,7 @@ pub struct CodegenUnitDebugContext<'ll, 'tcx> { type_map: metadata::TypeMap<'ll, 'tcx>, namespace_map: RefCell>, recursion_marker_type: OnceCell<&'ll DIType>, + depth_map: RefCell>, } impl Drop for CodegenUnitDebugContext<'_, '_> { @@ -90,6 +94,7 @@ impl<'ll, 'tcx> CodegenUnitDebugContext<'ll, 'tcx> { type_map: Default::default(), namespace_map: RefCell::new(Default::default()), recursion_marker_type: OnceCell::new(), + depth_map: Default::default(), } } @@ -132,6 +137,47 @@ impl<'ll, 'tcx> CodegenUnitDebugContext<'ll, 'tcx> { ); } } + + pub fn add_di_node(&self, di_node: &'ll llvm::Metadata) { + self.add_nested_di_node(di_node, &[]) + } + + pub fn add_nested_di_node(&self, di_node: &'ll llvm::Metadata, indices: &[usize]) { + let di_node_as_llval = unsafe { llvm::LLVMRustMetadataAsValue(self.llcontext, di_node) }; + let num_operands = unsafe { llvm::LLVMGetMDNodeNumOperands(di_node_as_llval) as usize }; + let mut operands = Vec::with_capacity(num_operands); + unsafe { + llvm::LLVMGetMDNodeOperands(di_node_as_llval, operands.as_mut_ptr()); + operands.set_len(num_operands); + } + for &index in indices { + if let Some(operand) = operands[index] { + let operand = unsafe { + assert!(llvm::LLVMIsAMDNode(operand).is_some()); + llvm::LLVMValueAsMetadata(operand) + }; + self.add_di_node(operand); + } + } + let mut depth_map = self.depth_map.borrow_mut(); + let node_depth = operands + .into_iter() + .flatten() + .filter_map(|operand| unsafe { llvm::LLVMIsAMDNode(operand) }) + .map(|operand| { + let operand = unsafe { llvm::LLVMValueAsMetadata(operand) }; + depth_map[&operand] + 1 + }) + .max() + .unwrap_or(1); + depth_map.insert(di_node, node_depth); + LLMOD_DEPTHS + .lock() + .unwrap() + .entry(self.llmod as *const _ as usize) + .and_modify(|depth| *depth = (*depth).max(node_depth)) + .or_insert(node_depth); + } } /// Creates any deferred debug metadata nodes @@ -326,6 +372,7 @@ impl<'ll, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { let fn_signature = get_function_signature(self, fn_abi); llvm::LLVMRustDIBuilderCreateSubroutineType(DIB(self), fn_signature) }; + debug_context(self).add_nested_di_node(function_type_metadata, &[3]); let mut name = String::new(); type_names::push_item_name(tcx, def_id, false, &mut name); @@ -373,8 +420,8 @@ impl<'ll, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { } } - unsafe { - return llvm::LLVMRustDIBuilderCreateFunction( + let function_metadata = unsafe { + llvm::LLVMRustDIBuilderCreateFunction( DIB(self), containing_scope, name.as_ptr().cast(), @@ -390,15 +437,17 @@ impl<'ll, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { maybe_definition_llfn, template_parameters, None, - ); - } + ) + }; + debug_context(self).add_nested_di_node(function_metadata, &[7]); + return function_metadata; fn get_function_signature<'ll, 'tcx>( cx: &CodegenCx<'ll, 'tcx>, fn_abi: &FnAbi<'tcx, Ty<'tcx>>, ) -> &'ll DIArray { if cx.sess().opts.debuginfo == DebugInfo::Limited { - return create_DIArray(DIB(cx), &[]); + return create_DIArray(cx, &[]); } let mut signature = Vec::with_capacity(fn_abi.args.len() + 1); @@ -439,7 +488,7 @@ impl<'ll, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { .extend(fn_abi.args.iter().map(|arg| Some(type_di_node(cx, arg.layout.ty)))); } - create_DIArray(DIB(cx), &signature[..]) + create_DIArray(cx, &signature[..]) } fn get_template_parameters<'ll, 'tcx>( @@ -448,7 +497,7 @@ impl<'ll, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { substs: SubstsRef<'tcx>, ) -> &'ll DIArray { if substs.types().next().is_none() { - return create_DIArray(DIB(cx), &[]); + return create_DIArray(cx, &[]); } // Again, only create type information if full debuginfo is enabled @@ -461,15 +510,17 @@ impl<'ll, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), ty); let actual_type_metadata = type_di_node(cx, actual_type); let name = name.as_str(); - Some(unsafe { - Some(llvm::LLVMRustDIBuilderCreateTemplateTypeParameter( + let template_param = unsafe { + llvm::LLVMRustDIBuilderCreateTemplateTypeParameter( DIB(cx), None, name.as_ptr().cast(), name.len(), actual_type_metadata, - )) - }) + ) + }; + debug_context(cx).add_di_node(template_param); + Some(Some(template_param)) } else { None } @@ -479,7 +530,7 @@ impl<'ll, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { vec![] }; - create_DIArray(DIB(cx), &template_params) + create_DIArray(cx, &template_params) } fn get_parameter_names(cx: &CodegenCx<'_, '_>, generics: &ty::Generics) -> Vec { @@ -552,7 +603,10 @@ impl<'ll, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { ) -> &'ll DILocation { let DebugLoc { line, col, .. } = self.lookup_debug_loc(span.lo()); - unsafe { llvm::LLVMRustDIBuilderCreateDebugLocation(line, col, scope, inlined_at) } + let dbg_loc = + unsafe { llvm::LLVMRustDIBuilderCreateDebugLocation(line, col, scope, inlined_at) }; + debug_context(self).add_di_node(dbg_loc); + dbg_loc } fn create_vtable_debuginfo( @@ -598,7 +652,7 @@ impl<'ll, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { let align = self.align_of(variable_type); let name = variable_name.as_str(); - unsafe { + let dbg_var = unsafe { llvm::LLVMRustDIBuilderCreateVariable( DIB(self), dwarf_tag, @@ -613,6 +667,8 @@ impl<'ll, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { argument_index, align.bytes() as u32, ) - } + }; + debug_context(self).add_di_node(dbg_var); + dbg_var } } diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/namespace.rs b/compiler/rustc_codegen_llvm/src/debuginfo/namespace.rs index d5ea48c311b94..d2c7e4f1dec91 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/namespace.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/namespace.rs @@ -42,6 +42,7 @@ pub fn item_namespace<'ll>(cx: &CodegenCx<'ll, '_>, def_id: DefId) -> &'ll DISco false, // ExportSymbols (only relevant for C++ anonymous namespaces) ) }; + debug_context(cx).add_di_node(scope); debug_context(cx).namespace_map.borrow_mut().insert(def_id, scope); scope diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs b/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs index fe9851cfa5612..645d8e4b594b5 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs @@ -26,10 +26,13 @@ pub fn is_node_local_to_unit(cx: &CodegenCx<'_, '_>, def_id: DefId) -> bool { #[allow(non_snake_case)] pub fn create_DIArray<'ll>( - builder: &DIBuilder<'ll>, + cx: &CodegenCx<'ll, '_>, arr: &[Option<&'ll DIDescriptor>], ) -> &'ll DIArray { - unsafe { llvm::LLVMRustDIBuilderGetOrCreateArray(builder, arr.as_ptr(), arr.len() as u32) } + let di_array = + unsafe { llvm::LLVMRustDIBuilderGetOrCreateArray(DIB(cx), arr.as_ptr(), arr.len() as u32) }; + debug_context(cx).add_di_node(di_array); + di_array } #[inline] diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 13baaddccd4df..648ba07fd014f 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -1075,6 +1075,7 @@ extern "C" { pub fn LLVMGetUndef(Ty: &Type) -> &Value; // Operations on metadata + pub fn LLVMIsAMDNode(Val: &Value) -> Option<&Value>; pub fn LLVMMDStringInContext(C: &Context, Str: *const c_char, SLen: c_uint) -> &Value; pub fn LLVMMDNodeInContext<'a>( C: &'a Context, @@ -1082,6 +1083,8 @@ extern "C" { Count: c_uint, ) -> &'a Value; pub fn LLVMAddNamedMetadataOperand<'a>(M: &'a Module, Name: *const c_char, Val: &'a Value); + pub fn LLVMGetMDNodeNumOperands(V: &Value) -> c_uint; + pub fn LLVMGetMDNodeOperands<'a>(V: &'a Value, Dest: *mut Option<&'a Value>); // Operations on scalar constants pub fn LLVMConstInt(IntTy: &Type, N: c_ulonglong, SignExtend: Bool) -> &Value; diff --git a/compiler/rustc_data_structures/src/stack.rs b/compiler/rustc_data_structures/src/stack.rs index 3bdd67512321b..6a7661a925370 100644 --- a/compiler/rustc_data_structures/src/stack.rs +++ b/compiler/rustc_data_structures/src/stack.rs @@ -16,3 +16,8 @@ const STACK_PER_RECURSION: usize = 1 * 1024 * 1024; // 1MB pub fn ensure_sufficient_stack(f: impl FnOnce() -> R) -> R { stacker::maybe_grow(RED_ZONE, STACK_PER_RECURSION, f) } + +pub fn ensure_recursive_stack(stack_size: usize, f: impl FnOnce() -> R) -> R { + let full_size = stack_size + RED_ZONE; + stacker::maybe_grow(full_size, full_size, f) +}