Auto merge of #102963 - ilammy:xray-basic, r=estebank
Add `-Z instrument-xray` flag Implement MCP https://github.com/rust-lang/compiler-team/issues/561, adding `-Z instrument-xray` flag which enables XRay instrumentation in LLVM.
This commit is contained in:
commit
a12d31d5a6
35 changed files with 312 additions and 9 deletions
|
@ -118,7 +118,8 @@ pub fn frame_pointer_type_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> Option<&'ll Attr
|
||||||
|
|
||||||
/// Tell LLVM what instrument function to insert.
|
/// Tell LLVM what instrument function to insert.
|
||||||
#[inline]
|
#[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 {
|
if cx.sess().opts.unstable_opts.instrument_mcount {
|
||||||
// Similar to `clang -pg` behavior. Handled by the
|
// Similar to `clang -pg` behavior. Handled by the
|
||||||
// `post-inline-ee-instrument` LLVM pass.
|
// `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.
|
// See test/CodeGen/mcount.c in clang.
|
||||||
let mcount_name = cx.sess().target.mcount.as_ref();
|
let mcount_name = cx.sess().target.mcount.as_ref();
|
||||||
|
|
||||||
Some(llvm::CreateAttrStringValue(
|
attrs.push(llvm::CreateAttrStringValue(
|
||||||
cx.llcx,
|
cx.llcx,
|
||||||
"instrument-function-entry-inlined",
|
"instrument-function-entry-inlined",
|
||||||
&mcount_name,
|
&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> {
|
fn nojumptables_attr<'ll>(cx: &CodegenCx<'ll, '_>) -> Option<&'ll Attribute> {
|
||||||
|
|
|
@ -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_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_sanitizer_not_supported = {$us} sanitizer is not supported for this target
|
||||||
|
|
||||||
session_sanitizers_not_supported = {$us} sanitizers are not supported for this target
|
session_sanitizers_not_supported = {$us} sanitizers are not supported for this target
|
||||||
|
|
|
@ -5,6 +5,7 @@ use rustc_data_structures::fx::FxHashSet;
|
||||||
use rustc_errors::{emitter::HumanReadableErrorType, registry, ColorConfig};
|
use rustc_errors::{emitter::HumanReadableErrorType, registry, ColorConfig};
|
||||||
use rustc_session::config::rustc_optgroups;
|
use rustc_session::config::rustc_optgroups;
|
||||||
use rustc_session::config::Input;
|
use rustc_session::config::Input;
|
||||||
|
use rustc_session::config::InstrumentXRay;
|
||||||
use rustc_session::config::TraitSolver;
|
use rustc_session::config::TraitSolver;
|
||||||
use rustc_session::config::{build_configuration, build_session_options, to_crate_config};
|
use rustc_session::config::{build_configuration, build_session_options, to_crate_config};
|
||||||
use rustc_session::config::{
|
use rustc_session::config::{
|
||||||
|
@ -755,6 +756,7 @@ fn test_unstable_options_tracking_hash() {
|
||||||
tracked!(inline_mir_threshold, Some(123));
|
tracked!(inline_mir_threshold, Some(123));
|
||||||
tracked!(instrument_coverage, Some(InstrumentCoverage::All));
|
tracked!(instrument_coverage, Some(InstrumentCoverage::All));
|
||||||
tracked!(instrument_mcount, true);
|
tracked!(instrument_mcount, true);
|
||||||
|
tracked!(instrument_xray, Some(InstrumentXRay::default()));
|
||||||
tracked!(link_only, true);
|
tracked!(link_only, true);
|
||||||
tracked!(llvm_plugins, vec![String::from("plugin_name")]);
|
tracked!(llvm_plugins, vec![String::from("plugin_name")]);
|
||||||
tracked!(location_detail, LocationDetail { file: true, line: false, column: false });
|
tracked!(location_detail, LocationDetail { file: true, line: false, column: false });
|
||||||
|
|
|
@ -174,6 +174,25 @@ pub enum InstrumentCoverage {
|
||||||
Off,
|
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<usize>,
|
||||||
|
/// `-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)]
|
#[derive(Clone, PartialEq, Hash, Debug)]
|
||||||
pub enum LinkerPluginLto {
|
pub enum LinkerPluginLto {
|
||||||
LinkerPlugin(PathBuf),
|
LinkerPlugin(PathBuf),
|
||||||
|
@ -2805,9 +2824,9 @@ impl PpMode {
|
||||||
pub(crate) mod dep_tracking {
|
pub(crate) mod dep_tracking {
|
||||||
use super::{
|
use super::{
|
||||||
BranchProtection, CFGuard, CFProtection, CrateType, DebugInfo, ErrorOutputType,
|
BranchProtection, CFGuard, CFProtection, CrateType, DebugInfo, ErrorOutputType,
|
||||||
InstrumentCoverage, LdImpl, LinkerPluginLto, LocationDetail, LtoCli, OomStrategy, OptLevel,
|
InstrumentCoverage, InstrumentXRay, LdImpl, LinkerPluginLto, LocationDetail, LtoCli,
|
||||||
OutputType, OutputTypes, Passes, SourceFileHashAlgorithm, SplitDwarfKind,
|
OomStrategy, OptLevel, OutputType, OutputTypes, Passes, SourceFileHashAlgorithm,
|
||||||
SwitchWithOptPath, SymbolManglingVersion, TraitSolver, TrimmedDefPaths,
|
SplitDwarfKind, SwitchWithOptPath, SymbolManglingVersion, TraitSolver, TrimmedDefPaths,
|
||||||
};
|
};
|
||||||
use crate::lint;
|
use crate::lint;
|
||||||
use crate::options::WasiExecModel;
|
use crate::options::WasiExecModel;
|
||||||
|
@ -2876,6 +2895,7 @@ pub(crate) mod dep_tracking {
|
||||||
CodeModel,
|
CodeModel,
|
||||||
TlsModel,
|
TlsModel,
|
||||||
InstrumentCoverage,
|
InstrumentCoverage,
|
||||||
|
InstrumentXRay,
|
||||||
CrateType,
|
CrateType,
|
||||||
MergeFunctions,
|
MergeFunctions,
|
||||||
PanicStrategy,
|
PanicStrategy,
|
||||||
|
|
|
@ -71,6 +71,12 @@ pub struct ProfileSampleUseFileDoesNotExist<'a> {
|
||||||
#[diag(session_target_requires_unwind_tables)]
|
#[diag(session_target_requires_unwind_tables)]
|
||||||
pub struct TargetRequiresUnwindTables;
|
pub struct TargetRequiresUnwindTables;
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
#[diag(session_instrumentation_not_supported)]
|
||||||
|
pub struct InstrumentationNotSupported {
|
||||||
|
pub us: String,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic)]
|
#[derive(Diagnostic)]
|
||||||
#[diag(session_sanitizer_not_supported)]
|
#[diag(session_sanitizer_not_supported)]
|
||||||
pub struct SanitizerNotSupported {
|
pub struct SanitizerNotSupported {
|
||||||
|
|
|
@ -380,6 +380,7 @@ mod desc {
|
||||||
pub const parse_dump_mono_stats: &str = "`markdown` (default) or `json`";
|
pub const parse_dump_mono_stats: &str = "`markdown` (default) or `json`";
|
||||||
pub const parse_instrument_coverage: &str =
|
pub const parse_instrument_coverage: &str =
|
||||||
"`all` (default), `except-unused-generics`, `except-unused-functions`, or `off`";
|
"`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_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_treat_err_as_bug: &str = "either no value or a number bigger than 0";
|
||||||
pub const parse_trait_solver: &str =
|
pub const parse_trait_solver: &str =
|
||||||
|
@ -869,6 +870,68 @@ mod parse {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn parse_instrument_xray(
|
||||||
|
slot: &mut Option<InstrumentXRay>,
|
||||||
|
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<NonZeroUsize>, v: Option<&str>) -> bool {
|
pub(crate) fn parse_treat_err_as_bug(slot: &mut Option<NonZeroUsize>, v: Option<&str>) -> bool {
|
||||||
match v {
|
match v {
|
||||||
Some(s) => {
|
Some(s) => {
|
||||||
|
@ -1397,6 +1460,16 @@ options! {
|
||||||
`=off` (default)"),
|
`=off` (default)"),
|
||||||
instrument_mcount: bool = (false, parse_bool, [TRACKED],
|
instrument_mcount: bool = (false, parse_bool, [TRACKED],
|
||||||
"insert function instrument code for mcount-based tracing (default: no)"),
|
"insert function instrument code for mcount-based tracing (default: no)"),
|
||||||
|
instrument_xray: Option<InstrumentXRay> = (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: bool = (false, parse_bool, [UNTRACKED],
|
||||||
"keep hygiene data after analysis (default: no)"),
|
"keep hygiene data after analysis (default: no)"),
|
||||||
layout_seed: Option<u64> = (None, parse_opt_number, [TRACKED],
|
layout_seed: Option<u64> = (None, parse_opt_number, [TRACKED],
|
||||||
|
|
|
@ -1589,6 +1589,10 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
|
||||||
{
|
{
|
||||||
sess.emit_err(errors::SplitDebugInfoUnstablePlatform { debuginfo: sess.split_debuginfo() });
|
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.
|
/// Holds data on the current incremental compilation session, if there is one.
|
||||||
|
|
|
@ -19,6 +19,7 @@ pub fn target() -> Target {
|
||||||
| SanitizerSet::MEMTAG
|
| SanitizerSet::MEMTAG
|
||||||
| SanitizerSet::SHADOWCALLSTACK
|
| SanitizerSet::SHADOWCALLSTACK
|
||||||
| SanitizerSet::ADDRESS,
|
| SanitizerSet::ADDRESS,
|
||||||
|
supports_xray: true,
|
||||||
..super::android_base::opts()
|
..super::android_base::opts()
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@ pub fn target() -> Target {
|
||||||
| SanitizerSet::MEMTAG
|
| SanitizerSet::MEMTAG
|
||||||
| SanitizerSet::THREAD
|
| SanitizerSet::THREAD
|
||||||
| SanitizerSet::HWADDRESS,
|
| SanitizerSet::HWADDRESS,
|
||||||
|
supports_xray: true,
|
||||||
..super::linux_gnu_base::opts()
|
..super::linux_gnu_base::opts()
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ use crate::spec::{Target, TargetOptions};
|
||||||
pub fn target() -> Target {
|
pub fn target() -> Target {
|
||||||
let mut base = super::linux_musl_base::opts();
|
let mut base = super::linux_musl_base::opts();
|
||||||
base.max_atomic_width = Some(128);
|
base.max_atomic_width = Some(128);
|
||||||
|
base.supports_xray = true;
|
||||||
|
|
||||||
Target {
|
Target {
|
||||||
llvm_target: "aarch64-unknown-linux-musl".into(),
|
llvm_target: "aarch64-unknown-linux-musl".into(),
|
||||||
|
|
|
@ -1718,6 +1718,9 @@ pub struct TargetOptions {
|
||||||
/// The ABI of entry function.
|
/// The ABI of entry function.
|
||||||
/// Default value is `Conv::C`, i.e. C call convention
|
/// Default value is `Conv::C`, i.e. C call convention
|
||||||
pub entry_abi: Conv,
|
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
|
/// Add arguments for the given flavor and also for its "twin" flavors
|
||||||
|
@ -1937,6 +1940,7 @@ impl Default for TargetOptions {
|
||||||
supports_stack_protector: true,
|
supports_stack_protector: true,
|
||||||
entry_name: "main".into(),
|
entry_name: "main".into(),
|
||||||
entry_abi: Conv::C,
|
entry_abi: Conv::C,
|
||||||
|
supports_xray: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2592,6 +2596,7 @@ impl Target {
|
||||||
key!(supports_stack_protector, bool);
|
key!(supports_stack_protector, bool);
|
||||||
key!(entry_name);
|
key!(entry_name);
|
||||||
key!(entry_abi, Conv)?;
|
key!(entry_abi, Conv)?;
|
||||||
|
key!(supports_xray, bool);
|
||||||
|
|
||||||
if base.is_builtin {
|
if base.is_builtin {
|
||||||
// This can cause unfortunate ICEs later down the line.
|
// 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!(supports_stack_protector);
|
||||||
target_option_val!(entry_name);
|
target_option_val!(entry_name);
|
||||||
target_option_val!(entry_abi);
|
target_option_val!(entry_abi);
|
||||||
|
target_option_val!(supports_xray);
|
||||||
|
|
||||||
if let Some(abi) = self.default_adjusted_cabi {
|
if let Some(abi) = self.default_adjusted_cabi {
|
||||||
d.insert("default-adjusted-cabi".into(), Abi::name(abi).to_json());
|
d.insert("default-adjusted-cabi".into(), Abi::name(abi).to_json());
|
||||||
|
|
|
@ -8,6 +8,7 @@ pub fn target() -> Target {
|
||||||
base.max_atomic_width = Some(64);
|
base.max_atomic_width = Some(64);
|
||||||
base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]);
|
base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]);
|
||||||
base.stack_probes = StackProbeType::X86;
|
base.stack_probes = StackProbeType::X86;
|
||||||
|
base.supports_xray = true;
|
||||||
|
|
||||||
Target {
|
Target {
|
||||||
llvm_target: "x86_64-linux-android".into(),
|
llvm_target: "x86_64-linux-android".into(),
|
||||||
|
|
|
@ -8,6 +8,7 @@ pub fn target() -> Target {
|
||||||
base.stack_probes = StackProbeType::X86;
|
base.stack_probes = StackProbeType::X86;
|
||||||
base.supported_sanitizers =
|
base.supported_sanitizers =
|
||||||
SanitizerSet::ADDRESS | SanitizerSet::CFI | SanitizerSet::MEMORY | SanitizerSet::THREAD;
|
SanitizerSet::ADDRESS | SanitizerSet::CFI | SanitizerSet::MEMORY | SanitizerSet::THREAD;
|
||||||
|
base.supports_xray = true;
|
||||||
|
|
||||||
Target {
|
Target {
|
||||||
llvm_target: "x86_64-unknown-freebsd".into(),
|
llvm_target: "x86_64-unknown-freebsd".into(),
|
||||||
|
|
|
@ -12,6 +12,7 @@ pub fn target() -> Target {
|
||||||
| SanitizerSet::LEAK
|
| SanitizerSet::LEAK
|
||||||
| SanitizerSet::MEMORY
|
| SanitizerSet::MEMORY
|
||||||
| SanitizerSet::THREAD;
|
| SanitizerSet::THREAD;
|
||||||
|
base.supports_xray = true;
|
||||||
|
|
||||||
Target {
|
Target {
|
||||||
llvm_target: "x86_64-unknown-linux-gnu".into(),
|
llvm_target: "x86_64-unknown-linux-gnu".into(),
|
||||||
|
|
|
@ -12,6 +12,7 @@ pub fn target() -> Target {
|
||||||
| SanitizerSet::LEAK
|
| SanitizerSet::LEAK
|
||||||
| SanitizerSet::MEMORY
|
| SanitizerSet::MEMORY
|
||||||
| SanitizerSet::THREAD;
|
| SanitizerSet::THREAD;
|
||||||
|
base.supports_xray = true;
|
||||||
|
|
||||||
Target {
|
Target {
|
||||||
llvm_target: "x86_64-unknown-linux-musl".into(),
|
llvm_target: "x86_64-unknown-linux-musl".into(),
|
||||||
|
|
|
@ -11,6 +11,7 @@ pub fn target() -> Target {
|
||||||
| SanitizerSet::LEAK
|
| SanitizerSet::LEAK
|
||||||
| SanitizerSet::MEMORY
|
| SanitizerSet::MEMORY
|
||||||
| SanitizerSet::THREAD;
|
| SanitizerSet::THREAD;
|
||||||
|
base.supports_xray = true;
|
||||||
|
|
||||||
Target {
|
Target {
|
||||||
llvm_target: "x86_64-unknown-netbsd".into(),
|
llvm_target: "x86_64-unknown-netbsd".into(),
|
||||||
|
|
|
@ -6,6 +6,7 @@ pub fn target() -> Target {
|
||||||
base.max_atomic_width = Some(64);
|
base.max_atomic_width = Some(64);
|
||||||
base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]);
|
base.add_pre_link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-m64"]);
|
||||||
base.stack_probes = StackProbeType::X86;
|
base.stack_probes = StackProbeType::X86;
|
||||||
|
base.supports_xray = true;
|
||||||
|
|
||||||
Target {
|
Target {
|
||||||
llvm_target: "x86_64-unknown-openbsd".into(),
|
llvm_target: "x86_64-unknown-openbsd".into(),
|
||||||
|
|
39
src/doc/unstable-book/src/compiler-flags/instrument-xray.md
Normal file
39
src/doc/unstable-book/src/compiler-flags/instrument-xray.md
Normal file
|
@ -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).
|
|
@ -941,6 +941,7 @@ pub fn make_test_description<R: Read>(
|
||||||
let has_hwasan = util::HWASAN_SUPPORTED_TARGETS.contains(&&*config.target);
|
let has_hwasan = util::HWASAN_SUPPORTED_TARGETS.contains(&&*config.target);
|
||||||
let has_memtag = util::MEMTAG_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_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
|
// 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.
|
// whether `rust-lld` is present in the compiler under test.
|
||||||
|
@ -1019,6 +1020,7 @@ pub fn make_test_description<R: Read>(
|
||||||
&& config.parse_name_directive(ln, "needs-sanitizer-shadow-call-stack")
|
&& config.parse_name_directive(ln, "needs-sanitizer-shadow-call-stack")
|
||||||
);
|
);
|
||||||
reason!(!config.can_unwind() && config.parse_name_directive(ln, "needs-unwind"));
|
reason!(!config.can_unwind() && config.parse_name_directive(ln, "needs-unwind"));
|
||||||
|
reason!(!has_xray && config.parse_name_directive(ln, "needs-xray"));
|
||||||
reason!(
|
reason!(
|
||||||
config.target == "wasm32-unknown-unknown"
|
config.target == "wasm32-unknown-unknown"
|
||||||
&& config.parse_name_directive(ln, directives::CHECK_RUN_RESULTS)
|
&& config.parse_name_directive(ln, directives::CHECK_RUN_RESULTS)
|
||||||
|
|
|
@ -78,6 +78,19 @@ pub const MEMTAG_SUPPORTED_TARGETS: &[&str] =
|
||||||
|
|
||||||
pub const SHADOWCALLSTACK_SUPPORTED_TARGETS: &[&str] = &["aarch64-linux-android"];
|
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 {
|
pub fn make_new_path(path: &str) -> String {
|
||||||
assert!(cfg!(windows));
|
assert!(cfg!(windows));
|
||||||
// Windows just uses PATH as the library search path, so we have to
|
// Windows just uses PATH as the library search path, so we have to
|
||||||
|
|
|
@ -9,7 +9,7 @@ use std::path::Path;
|
||||||
|
|
||||||
const ENTRY_LIMIT: usize = 1000;
|
const ENTRY_LIMIT: usize = 1000;
|
||||||
// FIXME: The following limits should be reduced eventually.
|
// 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;
|
const ISSUES_ENTRY_LIMIT: usize = 2001;
|
||||||
|
|
||||||
fn check_entries(path: &Path, bad: &mut bool) {
|
fn check_entries(path: &Path, bad: &mut bool) {
|
||||||
|
|
9
tests/codegen/instrument-xray/basic.rs
Normal file
9
tests/codegen/instrument-xray/basic.rs
Normal file
|
@ -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() {}
|
12
tests/codegen/instrument-xray/options-combine.rs
Normal file
12
tests/codegen/instrument-xray/options-combine.rs
Normal file
|
@ -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() {}
|
11
tests/codegen/instrument-xray/options-override.rs
Normal file
11
tests/codegen/instrument-xray/options-override.rs
Normal file
|
@ -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() {}
|
|
@ -70,6 +70,15 @@
|
||||||
`=except-unused-functions`
|
`=except-unused-functions`
|
||||||
`=off` (default)
|
`=off` (default)
|
||||||
-Z instrument-mcount=val -- insert function instrument code for mcount-based tracing (default: no)
|
-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 keep-hygiene-data=val -- keep hygiene data after analysis (default: no)
|
||||||
-Z layout-seed=val -- seed layout randomization
|
-Z layout-seed=val -- seed layout randomization
|
||||||
-Z link-native-libraries=val -- link native libraries in the linker invocation (default: yes)
|
-Z link-native-libraries=val -- link native libraries in the linker invocation (default: yes)
|
||||||
|
|
7
tests/ui/instrument-xray/flags-always-never-1.rs
Normal file
7
tests/ui/instrument-xray/flags-always-never-1.rs
Normal file
|
@ -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() {}
|
2
tests/ui/instrument-xray/flags-always-never-1.stderr
Normal file
2
tests/ui/instrument-xray/flags-always-never-1.stderr
Normal file
|
@ -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
|
||||||
|
|
9
tests/ui/instrument-xray/flags-always-never-2.rs
Normal file
9
tests/ui/instrument-xray/flags-always-never-2.rs
Normal file
|
@ -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() {}
|
9
tests/ui/instrument-xray/flags-basic.rs
Normal file
9
tests/ui/instrument-xray/flags-basic.rs
Normal file
|
@ -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() {}
|
7
tests/ui/instrument-xray/flags-dupe-always.rs
Normal file
7
tests/ui/instrument-xray/flags-dupe-always.rs
Normal file
|
@ -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() {}
|
2
tests/ui/instrument-xray/flags-dupe-always.stderr
Normal file
2
tests/ui/instrument-xray/flags-dupe-always.stderr
Normal file
|
@ -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
|
||||||
|
|
7
tests/ui/instrument-xray/flags-dupe-ignore-loops.rs
Normal file
7
tests/ui/instrument-xray/flags-dupe-ignore-loops.rs
Normal file
|
@ -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() {}
|
2
tests/ui/instrument-xray/flags-dupe-ignore-loops.stderr
Normal file
2
tests/ui/instrument-xray/flags-dupe-ignore-loops.stderr
Normal file
|
@ -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
|
||||||
|
|
9
tests/ui/instrument-xray/target-not-supported.rs
Normal file
9
tests/ui/instrument-xray/target-not-supported.rs
Normal file
|
@ -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]
|
4
tests/ui/instrument-xray/target-not-supported.stderr
Normal file
4
tests/ui/instrument-xray/target-not-supported.stderr
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
error: XRay instrumentation is not supported for this target
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue