Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[experimental] shorten backtraces using debuginfo #134831

Draft
wants to merge 18 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3525,6 +3525,7 @@ dependencies = [
"bitflags",
"cc",
"either",
"gimli 0.31.1",
"itertools",
"libc",
"object 0.36.7",
Expand Down
12 changes: 11 additions & 1 deletion compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use gimli::write::{
};
use gimli::{AArch64, Encoding, Format, LineEncoding, Register, RiscV, RunTimeEndian, X86_64};
use indexmap::IndexSet;
use rustc_codegen_ssa::debuginfo::type_names;
use rustc_codegen_ssa::debuginfo::{DW_AT_short_backtrace, DW_short_backtrace_value, type_names};
use rustc_hir::def::DefKind;
use rustc_hir::def_id::DefIdMap;
use rustc_session::Session;
Expand Down Expand Up @@ -239,6 +239,16 @@ impl DebugContext {
entry.set(gimli::DW_AT_decl_file, AttributeValue::FileIndex(Some(file_id)));
entry.set(gimli::DW_AT_decl_line, AttributeValue::Udata(line));

if let Some(skip) = tcx.codegen_fn_attrs(instance.def_id()).skip_short_backtrace {
tracing::info!(
"debuginfo {:?}: skip_short_backtrace={:?}",
tcx.item_name(instance.def_id()),
skip
);
let attr = AttributeValue::Data1(DW_short_backtrace_value(skip));
entry.set(gimli::DwAt(DW_AT_short_backtrace), attr);
}

if !fn_abi.ret.is_ignore() {
let return_dw_ty = self.debug_type(tcx, type_dbg, fn_abi.ret.layout.ty);
let entry = self.dwarf.unit.get_mut(entry_id);
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_codegen_cranelift/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ extern crate rustc_metadata;
extern crate rustc_session;
extern crate rustc_span;
extern crate rustc_target;
extern crate tracing;

// This prevents duplicating functions and statics that are already part of the host rustc process.
#[allow(unused_extern_crates)]
Expand Down
15 changes: 14 additions & 1 deletion compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ use crate::common::{AsCCharPtr, CodegenCx};
use crate::llvm;
use crate::llvm::debuginfo::{
DIArray, DIBuilder, DIFile, DIFlags, DILexicalBlock, DILocation, DISPFlags, DIScope, DIType,
DIVariable,
DIVariable, ShortBacktraceKind,
};
use crate::value::Value;

Expand Down Expand Up @@ -375,6 +375,17 @@ impl<'ll, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
}
}

// If appropriate, mark the function as skippable in backtraces.
let skip = self.tcx.codegen_fn_attrs(instance.def_id()).skip_short_backtrace;
if let Some(s) = skip {
tracing::info!(
"generate short backtrace {s:?} for {}",
tcx.opt_item_name(instance.def_id())
.map_or_else(|| tcx.def_path_str(instance.def_id()), |s| s.to_string())
);
}
let skip = ShortBacktraceKind::from_generic(skip);

// When we're adding a method to a type DIE, we only want a DW_AT_declaration there, because
// LLVM LTO can't unify type definitions when a child DIE is a full subprogram definition.
// When we use this `decl` below, the subprogram definition gets created at the CU level
Expand All @@ -392,6 +403,7 @@ impl<'ll, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
function_type_metadata,
flags,
spflags & !DISPFlags::SPFlagDefinition,
skip,
template_parameters,
)
});
Expand All @@ -410,6 +422,7 @@ impl<'ll, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> {
scope_line,
flags,
spflags,
skip,
maybe_definition_llfn,
template_parameters,
decl,
Expand Down
25 changes: 25 additions & 0 deletions compiler/rustc_codegen_llvm/src/llvm/ffi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use std::fmt::Debug;
use std::marker::PhantomData;
use std::ptr;

use debuginfo::ShortBacktraceKind;
use libc::{c_char, c_int, c_uint, c_ulonglong, c_void, size_t};
use rustc_macros::TryFromU32;
use rustc_target::spec::SymbolVisibility;
Expand Down Expand Up @@ -707,6 +708,7 @@ pub type InlineAsmDiagHandlerTy = unsafe extern "C" fn(&SMDiagnostic, *const c_v

pub mod debuginfo {
use bitflags::bitflags;
use rustc_middle::middle::codegen_fn_attrs::SkipShortBacktrace;

use super::{InvariantOpaque, Metadata};

Expand Down Expand Up @@ -775,6 +777,27 @@ pub mod debuginfo {
}
}

/// LLVMRustShortBacktrace
#[derive(Copy, Clone, Debug)]
#[repr(C)]
pub enum ShortBacktraceKind {
SkipFrame,
StartShortBacktrace,
EndShortBacktrace,
None,
}

impl ShortBacktraceKind {
pub fn from_generic(opt: Option<SkipShortBacktrace>) -> Self {
match opt {
None => ShortBacktraceKind::None,
Some(SkipShortBacktrace::ThisFrameOnly) => ShortBacktraceKind::SkipFrame,
Some(SkipShortBacktrace::Start) => ShortBacktraceKind::StartShortBacktrace,
Some(SkipShortBacktrace::End) => ShortBacktraceKind::EndShortBacktrace,
}
}
}

/// LLVMRustDebugEmissionKind
#[derive(Copy, Clone)]
#[repr(C)]
Expand Down Expand Up @@ -1891,6 +1914,7 @@ unsafe extern "C" {
ScopeLine: c_uint,
Flags: DIFlags,
SPFlags: DISPFlags,
ShortBacktrace: ShortBacktraceKind,
MaybeFn: Option<&'a Value>,
TParam: &'a DIArray,
Decl: Option<&'a DIDescriptor>,
Expand All @@ -1908,6 +1932,7 @@ unsafe extern "C" {
Ty: &'a DIType,
Flags: DIFlags,
SPFlags: DISPFlags,
ShortBacktrace: ShortBacktraceKind,
TParam: &'a DIArray,
) -> &'a DISubprogram;

Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_codegen_ssa/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ bitflags = "2.4.1"
# `cc` in `rustc_llvm` if you update the `cc` here.
cc = "=1.2.5"
either = "1.5.0"
gimli = "0.31.1"
itertools = "0.12"
pathdiff = "0.2.0"
regex = "1.4"
Expand Down
16 changes: 15 additions & 1 deletion compiler/rustc_codegen_ssa/src/codegen_attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId};
use rustc_hir::weak_lang_items::WEAK_LANG_ITEMS;
use rustc_hir::{self as hir, HirId, LangItem, lang_items};
use rustc_middle::middle::codegen_fn_attrs::{
CodegenFnAttrFlags, CodegenFnAttrs, PatchableFunctionEntry,
CodegenFnAttrFlags, CodegenFnAttrs, PatchableFunctionEntry, SkipShortBacktrace,
};
use rustc_middle::mir::mono::Linkage;
use rustc_middle::query::Providers;
Expand Down Expand Up @@ -581,6 +581,19 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
}
});

codegen_fn_attrs.skip_short_backtrace = SkipShortBacktrace::lookup(tcx, did);
match codegen_fn_attrs.skip_short_backtrace {
Some(SkipShortBacktrace::Start | SkipShortBacktrace::End) => {
if !matches!(codegen_fn_attrs.inline, InlineAttr::Never | InlineAttr::None) {
struct_span_code_err!(tcx.dcx(), tcx.get_attr(did, sym::inline).unwrap().span(), E0535, "invalid argument")
.with_note("`#[rustc_{start,end}_short_backtrace]` functions must always be `#[inline(never)]`")
.emit();
}
codegen_fn_attrs.inline = InlineAttr::Never;
}
Some(SkipShortBacktrace::ThisFrameOnly) | None => {}
}

// #73631: closures inherit `#[target_feature]` annotations
//
// If this closure is marked `#[inline(always)]`, simply skip adding `#[target_feature]`.
Expand Down Expand Up @@ -643,6 +656,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
// Additionally weak lang items have predetermined symbol names.
if WEAK_LANG_ITEMS.iter().any(|&l| tcx.lang_items().get(l) == Some(did.to_def_id())) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL;
codegen_fn_attrs.skip_short_backtrace = Some(SkipShortBacktrace::ThisFrameOnly);
}
if let Some((name, _)) = lang_items::extract(attrs)
&& let Some(lang_item) = LangItem::from_name(name)
Expand Down
19 changes: 19 additions & 0 deletions compiler/rustc_codegen_ssa/src/debuginfo/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,25 @@ use rustc_middle::ty::{self, Ty, TyCtxt};
// FIXME(eddyb) find a place for this (or a way to replace it).
pub mod type_names;

#[allow(non_upper_case_globals)]
mod short_backtraces {
use rustc_middle::middle::codegen_fn_attrs::SkipShortBacktrace;

// This is effectively public API. Don't change it.
pub const DW_AT_short_backtrace: u16 = 0x3c00;
pub const DW_FORM_short_backtrace: u16 = gimli::constants::DW_FORM_data1.0;

#[allow(non_snake_case)]
pub fn DW_short_backtrace_value(fn_attr: SkipShortBacktrace) -> u8 {
match fn_attr {
SkipShortBacktrace::ThisFrameOnly => 0,
SkipShortBacktrace::Start => 1,
SkipShortBacktrace::End => 2,
}
}
}
pub use short_backtraces::*;

/// Returns true if we want to generate a DW_TAG_enumeration_type description for
/// this instead of a DW_TAG_struct_type with DW_TAG_variant_part.
///
Expand Down
12 changes: 12 additions & 0 deletions compiler/rustc_feature/src/builtin_attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -684,6 +684,18 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
rustc_allocator_zeroed, Normal, template!(Word), WarnFollowing,
EncodeCrossCrate::No, IMPL_DETAIL
),
rustc_attr!(
rustc_skip_short_backtrace, Normal, template!(Word), WarnFollowing,
EncodeCrossCrate::No, IMPL_DETAIL,
),
rustc_attr!(
rustc_start_short_backtrace, Normal, template!(Word), WarnFollowing,
EncodeCrossCrate::No, IMPL_DETAIL,
),
rustc_attr!(
rustc_end_short_backtrace, Normal, template!(Word), WarnFollowing,
EncodeCrossCrate::No, IMPL_DETAIL,
),
gated!(
default_lib_allocator, Normal, template!(Word), WarnFollowing,
EncodeCrossCrate::No, allocator_internals, experimental!(default_lib_allocator),
Expand Down
45 changes: 43 additions & 2 deletions compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -822,6 +822,33 @@ static DISubprogram::DISPFlags fromRust(LLVMRustDISPFlags SPFlags) {
return Result;
}

#ifdef LLVM_RUSTLLVM
// These values **must** match debuginfo::ShortBacktrace! They also *happen*
// to match LLVM, but that isn't required as we do giant sets of
// matching below. The value shouldn't be directly passed to LLVM.
enum class LLVMRustShortBacktrace {
SkipFrame,
StartShortBacktrace,
EndShortBacktrace,
None,
};

static std::optional<ShortBacktraceAttr> shortBacktraceFromRust(LLVMRustShortBacktrace backtrace) {
switch (backtrace) {
case LLVMRustShortBacktrace::SkipFrame:
return ShortBacktraceAttr::SkipFrame;
case LLVMRustShortBacktrace::StartShortBacktrace:
return ShortBacktraceAttr::StartShortBacktrace;
case LLVMRustShortBacktrace::EndShortBacktrace:
return ShortBacktraceAttr::EndShortBacktrace;
case LLVMRustShortBacktrace::None:
return std::nullopt;
default:
report_fatal_error("bad ShortBacktraceAttr.");
}
}
#endif

enum class LLVMRustDebugEmissionKind {
NoDebug,
FullDebug,
Expand Down Expand Up @@ -1016,6 +1043,9 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateFunction(
size_t NameLen, const char *LinkageName, size_t LinkageNameLen,
LLVMMetadataRef File, unsigned LineNo, LLVMMetadataRef Ty,
unsigned ScopeLine, LLVMRustDIFlags Flags, LLVMRustDISPFlags SPFlags,
#ifdef LLVM_RUSTLLVM
LLVMRustShortBacktrace shortBacktrace,
#endif
LLVMValueRef MaybeFn, LLVMMetadataRef TParam, LLVMMetadataRef Decl) {
DITemplateParameterArray TParams =
DITemplateParameterArray(unwrap<MDTuple>(TParam));
Expand All @@ -1025,6 +1055,9 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateFunction(
unwrapDI<DIScope>(Scope), StringRef(Name, NameLen),
StringRef(LinkageName, LinkageNameLen), unwrapDI<DIFile>(File), LineNo,
unwrapDI<DISubroutineType>(Ty), ScopeLine, llvmFlags, llvmSPFlags,
#ifdef LLVM_RUSTLLVM
shortBacktraceFromRust(shortBacktrace),
#endif
TParams, unwrapDIPtr<DISubprogram>(Decl));
if (MaybeFn)
unwrap<Function>(MaybeFn)->setSubprogram(Sub);
Expand All @@ -1035,7 +1068,11 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateMethod(
LLVMRustDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name,
size_t NameLen, const char *LinkageName, size_t LinkageNameLen,
LLVMMetadataRef File, unsigned LineNo, LLVMMetadataRef Ty,
LLVMRustDIFlags Flags, LLVMRustDISPFlags SPFlags, LLVMMetadataRef TParam) {
LLVMRustDIFlags Flags, LLVMRustDISPFlags SPFlags,
#ifdef LLVM_RUSTLLVM
LLVMRustShortBacktrace shortBacktrace,
#endif
LLVMMetadataRef TParam) {
DITemplateParameterArray TParams =
DITemplateParameterArray(unwrap<MDTuple>(TParam));
DISubprogram::DISPFlags llvmSPFlags = fromRust(SPFlags);
Expand All @@ -1045,7 +1082,11 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateMethod(
StringRef(LinkageName, LinkageNameLen), unwrapDI<DIFile>(File), LineNo,
unwrapDI<DISubroutineType>(Ty), 0, 0,
nullptr, // VTable params aren't used
llvmFlags, llvmSPFlags, TParams);
llvmFlags, llvmSPFlags,
#ifdef LLVM_RUSTLLVM
shortBacktraceFromRust(shortBacktrace),
#endif
TParams);
return wrap(Sub);
}

Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_middle/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,9 @@ middle_limit_invalid =
`limit` must be a non-negative integer
.label = {$error_str}

middle_multiple_short_backtrace_attrs = multiple `#[rustc_*_short_backtrace]` attributes were used on the same item
.note = "attribute used here"

middle_opaque_hidden_type_mismatch =
concrete type differs from previous defining opaque type use
.label = expected `{$self_ty}`, got `{$other_ty}`
Expand Down
Loading