diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs index 54ac7a46cf2f3..7a4ec494c8e7f 100644 --- a/compiler/rustc_codegen_llvm/src/attributes.rs +++ b/compiler/rustc_codegen_llvm/src/attributes.rs @@ -118,7 +118,8 @@ pub fn frame_pointer_type_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> Option<&'ll Attr /// Tell LLVM what instrument function to insert. #[inline] -fn instrument_function_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> Option<&'ll Attribute> { +fn instrument_function_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> SmallVec<[&'ll Attribute; 4]> { + let mut attrs = SmallVec::new(); if cx.sess().opts.unstable_opts.instrument_mcount { // Similar to `clang -pg` behavior. Handled by the // `post-inline-ee-instrument` LLVM pass. @@ -127,14 +128,41 @@ fn instrument_function_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> Option<&'ll Attribu // See test/CodeGen/mcount.c in clang. let mcount_name = cx.sess().target.mcount.as_ref(); - Some(llvm::CreateAttrStringValue( + attrs.push(llvm::CreateAttrStringValue( cx.llcx, "instrument-function-entry-inlined", &mcount_name, - )) - } else { - None + )); + } + if let Some(options) = &cx.sess().opts.unstable_opts.instrument_xray { + // XRay instrumentation is similar to __cyg_profile_func_{enter,exit}. + // Function prologue and epilogue are instrumented with NOP sleds, + // a runtime library later replaces them with detours into tracing code. + if options.always { + attrs.push(llvm::CreateAttrStringValue(cx.llcx, "function-instrument", "xray-always")); + } + if options.never { + attrs.push(llvm::CreateAttrStringValue(cx.llcx, "function-instrument", "xray-never")); + } + if options.ignore_loops { + attrs.push(llvm::CreateAttrString(cx.llcx, "xray-ignore-loops")); + } + // LLVM will not choose the default for us, but rather requires specific + // threshold in absence of "xray-always". Use the same default as Clang. + let threshold = options.instruction_threshold.unwrap_or(200); + attrs.push(llvm::CreateAttrStringValue( + cx.llcx, + "xray-instruction-threshold", + &threshold.to_string(), + )); + if options.skip_entry { + attrs.push(llvm::CreateAttrString(cx.llcx, "xray-skip-entry")); + } + if options.skip_exit { + attrs.push(llvm::CreateAttrString(cx.llcx, "xray-skip-exit")); + } } + attrs } fn nojumptables_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> Option<&'ll Attribute> { diff --git a/compiler/rustc_error_messages/locales/en-US/session.ftl b/compiler/rustc_error_messages/locales/en-US/session.ftl index 5984c201af0d0..fe553edab4276 100644 --- a/compiler/rustc_error_messages/locales/en-US/session.ftl +++ b/compiler/rustc_error_messages/locales/en-US/session.ftl @@ -25,6 +25,8 @@ session_profile_sample_use_file_does_not_exist = file `{$path}` passed to `-C pr session_target_requires_unwind_tables = target requires unwind tables, they cannot be disabled with `-C force-unwind-tables=no` +session_instrumentation_not_supported = {$us} instrumentation is not supported for this target + session_sanitizer_not_supported = {$us} sanitizer is not supported for this target session_sanitizers_not_supported = {$us} sanitizers are not supported for this target diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 5165ee424e31b..0d3499ca9a048 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -5,6 +5,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc_errors::{emitter::HumanReadableErrorType, registry, ColorConfig}; use rustc_session::config::rustc_optgroups; use rustc_session::config::Input; +use rustc_session::config::InstrumentXRay; use rustc_session::config::TraitSolver; use rustc_session::config::{build_configuration, build_session_options, to_crate_config}; use rustc_session::config::{ @@ -755,6 +756,7 @@ fn test_unstable_options_tracking_hash() { tracked!(inline_mir_threshold, Some(123)); tracked!(instrument_coverage, Some(InstrumentCoverage::All)); tracked!(instrument_mcount, true); + tracked!(instrument_xray, Some(InstrumentXRay::default())); tracked!(link_only, true); tracked!(llvm_plugins, vec![String::from("plugin_name")]); tracked!(location_detail, LocationDetail { file: true, line: false, column: false }); diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 973d860118ef1..7d2fdf94baa36 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -174,6 +174,25 @@ pub enum InstrumentCoverage { Off, } +/// Settings for `-Z instrument-xray` flag. +#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)] +pub struct InstrumentXRay { + /// `-Z instrument-xray=always`, force instrumentation + pub always: bool, + /// `-Z instrument-xray=never`, disable instrumentation + pub never: bool, + /// `-Z instrument-xray=ignore-loops`, ignore presence of loops, + /// instrument functions based only on instruction count + pub ignore_loops: bool, + /// `-Z instrument-xray=instruction-threshold=N`, explicitly set instruction threshold + /// for instrumentation, or `None` to use compiler's default + pub instruction_threshold: Option, + /// `-Z instrument-xray=skip-entry`, do not instrument function entry + pub skip_entry: bool, + /// `-Z instrument-xray=skip-exit`, do not instrument function exit + pub skip_exit: bool, +} + #[derive(Clone, PartialEq, Hash, Debug)] pub enum LinkerPluginLto { LinkerPlugin(PathBuf), @@ -2805,9 +2824,9 @@ impl PpMode { pub(crate) mod dep_tracking { use super::{ BranchProtection, CFGuard, CFProtection, CrateType, DebugInfo, ErrorOutputType, - InstrumentCoverage, LdImpl, LinkerPluginLto, LocationDetail, LtoCli, OomStrategy, OptLevel, - OutputType, OutputTypes, Passes, SourceFileHashAlgorithm, SplitDwarfKind, - SwitchWithOptPath, SymbolManglingVersion, TraitSolver, TrimmedDefPaths, + InstrumentCoverage, InstrumentXRay, LdImpl, LinkerPluginLto, LocationDetail, LtoCli, + OomStrategy, OptLevel, OutputType, OutputTypes, Passes, SourceFileHashAlgorithm, + SplitDwarfKind, SwitchWithOptPath, SymbolManglingVersion, TraitSolver, TrimmedDefPaths, }; use crate::lint; use crate::options::WasiExecModel; @@ -2876,6 +2895,7 @@ pub(crate) mod dep_tracking { CodeModel, TlsModel, InstrumentCoverage, + InstrumentXRay, CrateType, MergeFunctions, PanicStrategy, diff --git a/compiler/rustc_session/src/errors.rs b/compiler/rustc_session/src/errors.rs index 8e8fba5e236f5..c851145440b86 100644 --- a/compiler/rustc_session/src/errors.rs +++ b/compiler/rustc_session/src/errors.rs @@ -71,6 +71,12 @@ pub struct ProfileSampleUseFileDoesNotExist<'a> { #[diag(session_target_requires_unwind_tables)] pub struct TargetRequiresUnwindTables; +#[derive(Diagnostic)] +#[diag(session_instrumentation_not_supported)] +pub struct InstrumentationNotSupported { + pub us: String, +} + #[derive(Diagnostic)] #[diag(session_sanitizer_not_supported)] pub struct SanitizerNotSupported { diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 61cb81aec3de0..b9723d35e5891 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -380,6 +380,7 @@ mod desc { pub const parse_dump_mono_stats: &str = "`markdown` (default) or `json`"; pub const parse_instrument_coverage: &str = "`all` (default), `except-unused-generics`, `except-unused-functions`, or `off`"; + pub const parse_instrument_xray: &str = "either a boolean (`yes`, `no`, `on`, `off`, etc), or a comma separated list of settings: `always` or `never` (mutually exclusive), `ignore-loops`, `instruction-threshold=N`, `skip-entry`, `skip-exit`"; pub const parse_unpretty: &str = "`string` or `string=string`"; pub const parse_treat_err_as_bug: &str = "either no value or a number bigger than 0"; pub const parse_trait_solver: &str = @@ -869,6 +870,68 @@ mod parse { true } + pub(crate) fn parse_instrument_xray( + slot: &mut Option, + v: Option<&str>, + ) -> bool { + if v.is_some() { + let mut bool_arg = None; + if parse_opt_bool(&mut bool_arg, v) { + *slot = if bool_arg.unwrap() { Some(InstrumentXRay::default()) } else { None }; + return true; + } + } + + let mut options = slot.get_or_insert_default(); + let mut seen_always = false; + let mut seen_never = false; + let mut seen_ignore_loops = false; + let mut seen_instruction_threshold = false; + let mut seen_skip_entry = false; + let mut seen_skip_exit = false; + for option in v.into_iter().map(|v| v.split(',')).flatten() { + match option { + "always" if !seen_always && !seen_never => { + options.always = true; + options.never = false; + seen_always = true; + } + "never" if !seen_never && !seen_always => { + options.never = true; + options.always = false; + seen_never = true; + } + "ignore-loops" if !seen_ignore_loops => { + options.ignore_loops = true; + seen_ignore_loops = true; + } + option + if option.starts_with("instruction-threshold") + && !seen_instruction_threshold => + { + let Some(("instruction-threshold", n)) = option.split_once('=') else { + return false; + }; + match n.parse() { + Ok(n) => options.instruction_threshold = Some(n), + Err(_) => return false, + } + seen_instruction_threshold = true; + } + "skip-entry" if !seen_skip_entry => { + options.skip_entry = true; + seen_skip_entry = true; + } + "skip-exit" if !seen_skip_exit => { + options.skip_exit = true; + seen_skip_exit = true; + } + _ => return false, + } + } + true + } + pub(crate) fn parse_treat_err_as_bug(slot: &mut Option, v: Option<&str>) -> bool { match v { Some(s) => { @@ -1397,6 +1460,16 @@ options! { `=off` (default)"), instrument_mcount: bool = (false, parse_bool, [TRACKED], "insert function instrument code for mcount-based tracing (default: no)"), + instrument_xray: Option = (None, parse_instrument_xray, [TRACKED], + "insert function instrument code for XRay-based tracing (default: no) + Optional extra settings: + `=always` + `=never` + `=ignore-loops` + `=instruction-threshold=N` + `=skip-entry` + `=skip-exit` + Multiple options can be combined with commas."), keep_hygiene_data: bool = (false, parse_bool, [UNTRACKED], "keep hygiene data after analysis (default: no)"), layout_seed: Option = (None, parse_opt_number, [TRACKED], diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 8a0176f639174..fe6ac80fde6eb 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -1589,6 +1589,10 @@ fn validate_commandline_args_with_session_available(sess: &Session) { { sess.emit_err(errors::SplitDebugInfoUnstablePlatform { debuginfo: sess.split_debuginfo() }); } + + if sess.opts.unstable_opts.instrument_xray.is_some() && !sess.target.options.supports_xray { + sess.emit_err(errors::InstrumentationNotSupported { us: "XRay".to_string() }); + } } /// Holds data on the current incremental compilation session, if there is one. diff --git a/compiler/rustc_target/src/spec/aarch64_linux_android.rs b/compiler/rustc_target/src/spec/aarch64_linux_android.rs index c85f7f62a4239..daa946ccd519c 100644 --- a/compiler/rustc_target/src/spec/aarch64_linux_android.rs +++ b/compiler/rustc_target/src/spec/aarch64_linux_android.rs @@ -19,6 +19,7 @@ pub fn target() -> Target { | SanitizerSet::MEMTAG | SanitizerSet::SHADOWCALLSTACK | SanitizerSet::ADDRESS, + supports_xray: true, ..super::android_base::opts() }, } diff --git a/compiler/rustc_target/src/spec/aarch64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/aarch64_unknown_linux_gnu.rs index 3006044d54a6e..36d54f1d7cc5c 100644 --- a/compiler/rustc_target/src/spec/aarch64_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/aarch64_unknown_linux_gnu.rs @@ -17,6 +17,7 @@ pub fn target() -> Target { | SanitizerSet::MEMTAG | SanitizerSet::THREAD | SanitizerSet::HWADDRESS, + supports_xray: true, ..super::linux_gnu_base::opts() }, } diff --git a/compiler/rustc_target/src/spec/aarch64_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/aarch64_unknown_linux_musl.rs index 002d0dac2a668..9c299fed6be16 100644 --- a/compiler/rustc_target/src/spec/aarch64_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/aarch64_unknown_linux_musl.rs @@ -3,6 +3,7 @@ use crate::spec::{Target, TargetOptions}; pub fn target() -> Target { let mut base = super::linux_musl_base::opts(); base.max_atomic_width = Some(128); + base.supports_xray = true; Target { llvm_target: "aarch64-unknown-linux-musl".into(), diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index a094c2c545269..bc1920e34249a 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -1718,6 +1718,9 @@ pub struct TargetOptions { /// The ABI of entry function. /// Default value is `Conv::C`, i.e. C call convention pub entry_abi: Conv, + + /// Whether the target supports XRay instrumentation. + pub supports_xray: bool, } /// Add arguments for the given flavor and also for its "twin" flavors @@ -1937,6 +1940,7 @@ impl Default for TargetOptions { supports_stack_protector: true, entry_name: "main".into(), entry_abi: Conv::C, + supports_xray: false, } } } @@ -2592,6 +2596,7 @@ impl Target { key!(supports_stack_protector, bool); key!(entry_name); key!(entry_abi, Conv)?; + key!(supports_xray, bool); if base.is_builtin { // This can cause unfortunate ICEs later down the line. @@ -2845,6 +2850,7 @@ impl ToJson for Target { target_option_val!(supports_stack_protector); target_option_val!(entry_name); target_option_val!(entry_abi); + target_option_val!(supports_xray); if let Some(abi) = self.default_adjusted_cabi { d.insert("default-adjusted-cabi".into(), Abi::name(abi).to_json()); diff --git a/compiler/rustc_target/src/spec/x86_64_linux_android.rs b/compiler/rustc_target/src/spec/x86_64_linux_android.rs index 9c9137848550f..a3bdb5f5465b0 100644 --- a/compiler/rustc_target/src/spec/x86_64_linux_android.rs +++ b/compiler/rustc_target/src/spec/x86_64_linux_android.rs @@ -8,6 +8,7 @@ pub fn target() -> Target { base.max_atomic_width = Some(64); base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]); base.stack_probes = StackProbeType::X86; + base.supports_xray = true; Target { llvm_target: "x86_64-linux-android".into(), diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_freebsd.rs b/compiler/rustc_target/src/spec/x86_64_unknown_freebsd.rs index 98988ab359542..b41e5842aad13 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_freebsd.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_freebsd.rs @@ -8,6 +8,7 @@ pub fn target() -> Target { base.stack_probes = StackProbeType::X86; base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::CFI | SanitizerSet::MEMORY | SanitizerSet::THREAD; + base.supports_xray = true; Target { llvm_target: "x86_64-unknown-freebsd".into(), diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnu.rs index a91ab365b668a..9af1049b87026 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnu.rs @@ -12,6 +12,7 @@ pub fn target() -> Target { | SanitizerSet::LEAK | SanitizerSet::MEMORY | SanitizerSet::THREAD; + base.supports_xray = true; Target { llvm_target: "x86_64-unknown-linux-gnu".into(), diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/x86_64_unknown_linux_musl.rs index 9087dc3df6007..bf4cf7d7becad 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_linux_musl.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_linux_musl.rs @@ -12,6 +12,7 @@ pub fn target() -> Target { | SanitizerSet::LEAK | SanitizerSet::MEMORY | SanitizerSet::THREAD; + base.supports_xray = true; Target { llvm_target: "x86_64-unknown-linux-musl".into(), diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_netbsd.rs b/compiler/rustc_target/src/spec/x86_64_unknown_netbsd.rs index 64ae425d8c0b7..74c434935ba88 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_netbsd.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_netbsd.rs @@ -11,6 +11,7 @@ pub fn target() -> Target { | SanitizerSet::LEAK | SanitizerSet::MEMORY | SanitizerSet::THREAD; + base.supports_xray = true; Target { llvm_target: "x86_64-unknown-netbsd".into(), diff --git a/compiler/rustc_target/src/spec/x86_64_unknown_openbsd.rs b/compiler/rustc_target/src/spec/x86_64_unknown_openbsd.rs index 66b8e20226f19..8e4d42a0acaf3 100644 --- a/compiler/rustc_target/src/spec/x86_64_unknown_openbsd.rs +++ b/compiler/rustc_target/src/spec/x86_64_unknown_openbsd.rs @@ -6,6 +6,7 @@ pub fn target() -> Target { base.max_atomic_width = Some(64); base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]); base.stack_probes = StackProbeType::X86; + base.supports_xray = true; Target { llvm_target: "x86_64-unknown-openbsd".into(), diff --git a/src/doc/unstable-book/src/compiler-flags/instrument-xray.md b/src/doc/unstable-book/src/compiler-flags/instrument-xray.md new file mode 100644 index 0000000000000..7fb33cd68b4a3 --- /dev/null +++ b/src/doc/unstable-book/src/compiler-flags/instrument-xray.md @@ -0,0 +1,39 @@ +# `instrument-xray` + +The tracking issue for this feature is: [#102921](https://github.com/rust-lang/rust/issues/102921). + +------------------------ + +Enable generation of NOP sleds for XRay function tracing instrumentation. +For more information on XRay, +read [LLVM documentation](https://llvm.org/docs/XRay.html), +and/or the [XRay whitepaper](http://research.google.com/pubs/pub45287.html). + +Set the `-Z instrument-xray` compiler flag in order to enable XRay instrumentation. + + - `-Z instrument-xray` – use the default settings + - `-Z instrument-xray=skip-exit` – configure a custom setting + - `-Z instrument-xray=ignore-loops,instruction-threshold=300` – + multiple settings separated by commas + +Supported options: + + - `always` – force instrumentation of all functions + - `never` – do no instrument any functions + - `ignore-loops` – ignore presence of loops, + instrument functions based only on instruction count + - `instruction-threshold=10` – set a different instruction threshold for instrumentation + - `skip-entry` – do no instrument function entry + - `skip-exit` – do no instrument function exit + +The default settings are: + + - instrument both entry & exit from functions + - instrument functions with at least 200 instructions, + or containing a non-trivial loop + +Note that `-Z instrument-xray` only enables generation of NOP sleds +which on their own don't do anything useful. +In order to actually trace the functions, +you will need to link a separate runtime library of your choice, +such as Clang's [XRay Runtime Library](https://www.llvm.org/docs/XRay.html#xray-runtime-library). diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index 45fd87bea9bb5..e11ebca6ea9af 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -941,6 +941,7 @@ pub fn make_test_description( let has_hwasan = util::HWASAN_SUPPORTED_TARGETS.contains(&&*config.target); let has_memtag = util::MEMTAG_SUPPORTED_TARGETS.contains(&&*config.target); let has_shadow_call_stack = util::SHADOWCALLSTACK_SUPPORTED_TARGETS.contains(&&*config.target); + let has_xray = util::XRAY_SUPPORTED_TARGETS.contains(&&*config.target); // For tests using the `needs-rust-lld` directive (e.g. for `-Zgcc-ld=lld`), we need to find // whether `rust-lld` is present in the compiler under test. @@ -1019,6 +1020,7 @@ pub fn make_test_description( && config.parse_name_directive(ln, "needs-sanitizer-shadow-call-stack") ); reason!(!config.can_unwind() && config.parse_name_directive(ln, "needs-unwind")); + reason!(!has_xray && config.parse_name_directive(ln, "needs-xray")); reason!( config.target == "wasm32-unknown-unknown" && config.parse_name_directive(ln, directives::CHECK_RUN_RESULTS) diff --git a/src/tools/compiletest/src/util.rs b/src/tools/compiletest/src/util.rs index ff7e8df987816..67f49bb6397c2 100644 --- a/src/tools/compiletest/src/util.rs +++ b/src/tools/compiletest/src/util.rs @@ -78,6 +78,19 @@ pub const MEMTAG_SUPPORTED_TARGETS: &[&str] = pub const SHADOWCALLSTACK_SUPPORTED_TARGETS: &[&str] = &["aarch64-linux-android"]; +pub const XRAY_SUPPORTED_TARGETS: &[&str] = &[ + "aarch64-linux-android", + "aarch64-unknown-linux-gnu", + "aarch64-unknown-linux-musl", + "x86_64-linux-android", + "x86_64-unknown-freebsd", + "x86_64-unknown-linux-gnu", + "x86_64-unknown-linux-musl", + "x86_64-unknown-netbsd", + "x86_64-unknown-none-linuxkernel", + "x86_64-unknown-openbsd", +]; + pub fn make_new_path(path: &str) -> String { assert!(cfg!(windows)); // Windows just uses PATH as the library search path, so we have to diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs index 83551a1d820ab..ef3abb9514f24 100644 --- a/src/tools/tidy/src/ui_tests.rs +++ b/src/tools/tidy/src/ui_tests.rs @@ -9,7 +9,7 @@ use std::path::Path; const ENTRY_LIMIT: usize = 1000; // FIXME: The following limits should be reduced eventually. -const ROOT_ENTRY_LIMIT: usize = 939; +const ROOT_ENTRY_LIMIT: usize = 940; const ISSUES_ENTRY_LIMIT: usize = 2001; fn check_entries(path: &Path, bad: &mut bool) { diff --git a/tests/codegen/instrument-xray/basic.rs b/tests/codegen/instrument-xray/basic.rs new file mode 100644 index 0000000000000..d3e49d5317442 --- /dev/null +++ b/tests/codegen/instrument-xray/basic.rs @@ -0,0 +1,9 @@ +// Checks that `-Z instrument-xray` produces expected instrumentation. +// +// needs-xray +// compile-flags: -Z instrument-xray=always + +#![crate_type = "lib"] + +// CHECK: attributes #{{.*}} "function-instrument"="xray-always" +pub fn function() {} diff --git a/tests/codegen/instrument-xray/options-combine.rs b/tests/codegen/instrument-xray/options-combine.rs new file mode 100644 index 0000000000000..f7e500b65f62d --- /dev/null +++ b/tests/codegen/instrument-xray/options-combine.rs @@ -0,0 +1,12 @@ +// Checks that `-Z instrument-xray` options can be specified multiple times. +// +// needs-xray +// compile-flags: -Z instrument-xray=skip-exit +// compile-flags: -Z instrument-xray=instruction-threshold=123 +// compile-flags: -Z instrument-xray=instruction-threshold=456 + +#![crate_type = "lib"] + +// CHECK: attributes #{{.*}} "xray-instruction-threshold"="456" "xray-skip-exit" +// CHECK-NOT: attributes #{{.*}} "xray-instruction-threshold"="123" +pub fn function() {} diff --git a/tests/codegen/instrument-xray/options-override.rs b/tests/codegen/instrument-xray/options-override.rs new file mode 100644 index 0000000000000..00f81837902dd --- /dev/null +++ b/tests/codegen/instrument-xray/options-override.rs @@ -0,0 +1,11 @@ +// Checks that the last `-Z instrument-xray` option wins. +// +// needs-xray +// compile-flags: -Z instrument-xray=always +// compile-flags: -Z instrument-xray=never + +#![crate_type = "lib"] + +// CHECK: attributes #{{.*}} "function-instrument"="xray-never" +// CHECK-NOT: attributes #{{.*}} "function-instrument"="xray-always" +pub fn function() {} diff --git a/tests/rustdoc-ui/z-help.stdout b/tests/rustdoc-ui/z-help.stdout index 706db892cb30d..6c1684201a202 100644 --- a/tests/rustdoc-ui/z-help.stdout +++ b/tests/rustdoc-ui/z-help.stdout @@ -70,6 +70,15 @@ `=except-unused-functions` `=off` (default) -Z instrument-mcount=val -- insert function instrument code for mcount-based tracing (default: no) + -Z instrument-xray=val -- insert function instrument code for XRay-based tracing (default: no) + Optional extra settings: + `=always` + `=never` + `=ignore-loops` + `=instruction-threshold=N` + `=skip-entry` + `=skip-exit` + Multiple options can be combined with commas. -Z keep-hygiene-data=val -- keep hygiene data after analysis (default: no) -Z layout-seed=val -- seed layout randomization -Z link-native-libraries=val -- link native libraries in the linker invocation (default: yes) diff --git a/tests/ui/instrument-xray/flags-always-never-1.rs b/tests/ui/instrument-xray/flags-always-never-1.rs new file mode 100644 index 0000000000000..4dd43439eb7c2 --- /dev/null +++ b/tests/ui/instrument-xray/flags-always-never-1.rs @@ -0,0 +1,7 @@ +// Checks that `-Z instrument-xray` does not allow `always` and `never` simultaneously. +// +// needs-xray +// compile-flags: -Z instrument-xray=always,never +// error-pattern: incorrect value `always,never` for unstable option `instrument-xray` + +fn main() {} diff --git a/tests/ui/instrument-xray/flags-always-never-1.stderr b/tests/ui/instrument-xray/flags-always-never-1.stderr new file mode 100644 index 0000000000000..e211c6f602546 --- /dev/null +++ b/tests/ui/instrument-xray/flags-always-never-1.stderr @@ -0,0 +1,2 @@ +error: incorrect value `always,never` for unstable option `instrument-xray` - either a boolean (`yes`, `no`, `on`, `off`, etc), or a comma separated list of settings: `always` or `never` (mutually exclusive), `ignore-loops`, `instruction-threshold=N`, `skip-entry`, `skip-exit` was expected + diff --git a/tests/ui/instrument-xray/flags-always-never-2.rs b/tests/ui/instrument-xray/flags-always-never-2.rs new file mode 100644 index 0000000000000..7310aa0a0d288 --- /dev/null +++ b/tests/ui/instrument-xray/flags-always-never-2.rs @@ -0,0 +1,9 @@ +// Checks that `-Z instrument-xray` allows `always` and `never` sequentially. +// (The last specified setting wins, like `-Z instrument-xray=no` as well.) +// +// needs-xray +// compile-flags: -Z instrument-xray=always +// compile-flags: -Z instrument-xray=never +// check-pass + +fn main() {} diff --git a/tests/ui/instrument-xray/flags-basic.rs b/tests/ui/instrument-xray/flags-basic.rs new file mode 100644 index 0000000000000..b97f0dd8a072c --- /dev/null +++ b/tests/ui/instrument-xray/flags-basic.rs @@ -0,0 +1,9 @@ +// Verifies basic `-Z instrument-xray` flags. +// +// needs-xray +// compile-flags: -Z instrument-xray +// compile-flags: -Z instrument-xray=skip-exit +// compile-flags: -Z instrument-xray=ignore-loops,instruction-threshold=300 +// check-pass + +fn main() {} diff --git a/tests/ui/instrument-xray/flags-dupe-always.rs b/tests/ui/instrument-xray/flags-dupe-always.rs new file mode 100644 index 0000000000000..407f3e2aa5da8 --- /dev/null +++ b/tests/ui/instrument-xray/flags-dupe-always.rs @@ -0,0 +1,7 @@ +// Checks that `-Z instrument-xray` does not allow duplicates. +// +// needs-xray +// compile-flags: -Z instrument-xray=always,always +// error-pattern: incorrect value `always,always` for unstable option `instrument-xray` + +fn main() {} diff --git a/tests/ui/instrument-xray/flags-dupe-always.stderr b/tests/ui/instrument-xray/flags-dupe-always.stderr new file mode 100644 index 0000000000000..d1ac113fa4384 --- /dev/null +++ b/tests/ui/instrument-xray/flags-dupe-always.stderr @@ -0,0 +1,2 @@ +error: incorrect value `always,always` for unstable option `instrument-xray` - either a boolean (`yes`, `no`, `on`, `off`, etc), or a comma separated list of settings: `always` or `never` (mutually exclusive), `ignore-loops`, `instruction-threshold=N`, `skip-entry`, `skip-exit` was expected + diff --git a/tests/ui/instrument-xray/flags-dupe-ignore-loops.rs b/tests/ui/instrument-xray/flags-dupe-ignore-loops.rs new file mode 100644 index 0000000000000..75b210a6547ec --- /dev/null +++ b/tests/ui/instrument-xray/flags-dupe-ignore-loops.rs @@ -0,0 +1,7 @@ +// Checks that `-Z instrument-xray` does not allow duplicates. +// +// needs-xray +// compile-flags: -Z instrument-xray=ignore-loops,ignore-loops +// error-pattern: incorrect value `ignore-loops,ignore-loops` for unstable option `instrument-xray` + +fn main() {} diff --git a/tests/ui/instrument-xray/flags-dupe-ignore-loops.stderr b/tests/ui/instrument-xray/flags-dupe-ignore-loops.stderr new file mode 100644 index 0000000000000..52f6b33075bc1 --- /dev/null +++ b/tests/ui/instrument-xray/flags-dupe-ignore-loops.stderr @@ -0,0 +1,2 @@ +error: incorrect value `ignore-loops,ignore-loops` for unstable option `instrument-xray` - either a boolean (`yes`, `no`, `on`, `off`, etc), or a comma separated list of settings: `always` or `never` (mutually exclusive), `ignore-loops`, `instruction-threshold=N`, `skip-entry`, `skip-exit` was expected + diff --git a/tests/ui/instrument-xray/target-not-supported.rs b/tests/ui/instrument-xray/target-not-supported.rs new file mode 100644 index 0000000000000..e6bdd23e8fc3a --- /dev/null +++ b/tests/ui/instrument-xray/target-not-supported.rs @@ -0,0 +1,9 @@ +// Verifies that `-Z instrument-xray` cannot be used with unsupported targets, +// +// needs-llvm-components: x86 +// compile-flags: -Z instrument-xray --target x86_64-apple-darwin +// error-pattern: error: XRay instrumentation is not supported for this target + +#![feature(no_core)] +#![no_core] +#![no_main] diff --git a/tests/ui/instrument-xray/target-not-supported.stderr b/tests/ui/instrument-xray/target-not-supported.stderr new file mode 100644 index 0000000000000..6e3b0c8a380b8 --- /dev/null +++ b/tests/ui/instrument-xray/target-not-supported.stderr @@ -0,0 +1,4 @@ +error: XRay instrumentation is not supported for this target + +error: aborting due to previous error +