Skip to content

Commit 917f56a

Browse files
committed
krabcake: Successfully send intrinsics::asume data to Valgrind
This patch adds support to send the `bool` in `std::intrinsics::assume` to Valgrind by inserting a Valgrind Client Request using a MirPass.
1 parent f77bfb7 commit 917f56a

File tree

10 files changed

+238
-1
lines changed

10 files changed

+238
-1
lines changed

compiler/rustc_hir/src/lang_items.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,8 @@ pub fn extract(attrs: &[ast::Attribute]) -> Option<(Symbol, Span)> {
147147

148148
language_item_table! {
149149
// Variant name, Name, Getter method name, Target Generic requirements;
150+
KrabcakeRequest, sym::KrabcakeRequest, krabcake_request, Target::Enum, GenericRequirement::None;
151+
InsertKrabcakeRequest, sym::insert_krabcake_request, insert_krabcake_request_fn, Target::Fn, GenericRequirement::None;
150152
Sized, sym::sized, sized_trait, Target::Trait, GenericRequirement::Exact(0);
151153
Unsize, sym::unsize, unsize_trait, Target::Trait, GenericRequirement::Minimum(1);
152154
/// Trait injected by `#[derive(PartialEq)]`, (i.e. "Partial EQ").

compiler/rustc_interface/src/tests.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -754,6 +754,7 @@ fn test_unstable_options_tracking_hash() {
754754
tracked!(inline_mir_hint_threshold, Some(123));
755755
tracked!(inline_mir_threshold, Some(123));
756756
tracked!(instrument_coverage, Some(InstrumentCoverage::All));
757+
tracked!(instrument_krabcake, false);
757758
tracked!(instrument_mcount, true);
758759
tracked!(instrument_xray, Some(InstrumentXRay::default()));
759760
tracked!(link_directives, false);

compiler/rustc_middle/src/mir/patch.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,4 +179,16 @@ impl<'tcx> MirPatch<'tcx> {
179179
};
180180
Self::source_info_for_index(data, loc)
181181
}
182+
183+
pub fn terminator_for_location(
184+
&self,
185+
body: &Body<'tcx>,
186+
loc: Location,
187+
) -> Option<Terminator<'tcx>> {
188+
let data = match loc.block.index().checked_sub(body.basic_blocks.len()) {
189+
Some(new) => &self.new_blocks[new],
190+
None => &body[loc.block],
191+
};
192+
data.terminator.clone()
193+
}
182194
}

compiler/rustc_middle/src/ty/layout.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -680,7 +680,11 @@ where
680680
| ty::GeneratorWitnessMIR(..)
681681
| ty::Foreign(..)
682682
| ty::Dynamic(_, _, ty::Dyn) => {
683-
bug!("TyAndLayout::field({:?}): not applicable", this)
683+
bug!(
684+
"TyAndLayout::field({:?}): not applicable for kind {:?}",
685+
this,
686+
this.ty.kind()
687+
)
684688
}
685689

686690
// Potentially-fat pointers.

compiler/rustc_mir_transform/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ mod simplify_comparison_integral;
9898
mod sroa;
9999
mod uninhabited_enum_branching;
100100
mod unreachable_prop;
101+
mod valgrind_client_request;
101102

102103
use rustc_const_eval::transform::check_consts::{self, ConstCx};
103104
use rustc_const_eval::transform::promote_consts;
@@ -588,6 +589,7 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
588589
&large_enums::EnumSizeOpt { discrepancy: 128 },
589590
// Some cleanup necessary at least for LLVM and potentially other codegen backends.
590591
&add_call_guards::CriticalCallEdges,
592+
&valgrind_client_request::ValgrindClientRequest,
591593
// Dump the end result for testing and debugging purposes.
592594
&dump_mir::Marker("PreCodegen"),
593595
],
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
use crate::MirPass;
2+
3+
use rustc_index::vec::Idx;
4+
use rustc_middle::mir::patch::MirPatch;
5+
use rustc_middle::mir::{
6+
AggregateKind, BasicBlockData, Body, Constant, ConstantKind, Location, NonDivergingIntrinsic,
7+
Operand, Place, Rvalue, StatementKind, TerminatorKind,
8+
};
9+
use rustc_middle::ty::InternalSubsts;
10+
use rustc_middle::ty::TyCtxt;
11+
use rustc_target::abi::VariantIdx;
12+
13+
pub struct ValgrindClientRequest;
14+
15+
impl<'tcx> MirPass<'tcx> for ValgrindClientRequest {
16+
#[instrument(skip(self, tcx, body))]
17+
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
18+
if !tcx.sess.opts.unstable_opts.instrument_krabcake {
19+
info!("Not instrumenting for krabcake");
20+
return;
21+
}
22+
info!("Instrumenting for krabcake now...");
23+
let mut patch = MirPatch::new(body);
24+
25+
for (block_index, block_data) in body.basic_blocks.iter_enumerated() {
26+
for (stmt_index, stmt) in block_data.statements.iter().enumerate() {
27+
match &stmt.kind {
28+
StatementKind::Intrinsic(box NonDivergingIntrinsic::Assume(operand)) => {
29+
let loc = Location { block: block_index, statement_index: stmt_index };
30+
info!("Found assume intrinsic (operand={operand:?}. At {loc:?}");
31+
patch = call_ikr(tcx, patch, body, loc, operand);
32+
}
33+
_ => (),
34+
}
35+
}
36+
}
37+
38+
patch.apply(body);
39+
}
40+
}
41+
42+
fn call_ikr<'tcx>(
43+
tcx: TyCtxt<'tcx>,
44+
mut patch: MirPatch<'tcx>,
45+
body: &Body<'tcx>,
46+
loc: Location,
47+
_operand: &Operand<'tcx>,
48+
) -> MirPatch<'tcx> {
49+
let span = patch.source_info_for_location(body, loc).span;
50+
51+
let op = |flag: bool| {
52+
Operand::Constant(Box::new(Constant {
53+
span,
54+
user_ty: None,
55+
literal: ConstantKind::from_bool(tcx, flag),
56+
}))
57+
};
58+
59+
let (place, rvalue) = {
60+
let krabcake_req_did = tcx.lang_items().krabcake_request().unwrap();
61+
let krabcake_req_substs = InternalSubsts::identity_for_item(tcx, krabcake_req_did);
62+
let krabcake_req_def = tcx.adt_def(krabcake_req_did);
63+
let krabcake_req_ty = tcx.mk_adt(krabcake_req_def, krabcake_req_substs);
64+
let rvalue = Rvalue::Aggregate(
65+
Box::new(AggregateKind::Adt(
66+
krabcake_req_did,
67+
VariantIdx::new(0),
68+
&krabcake_req_substs,
69+
None,
70+
None,
71+
)),
72+
vec![op(true)],
73+
);
74+
let temp = patch.new_temp(krabcake_req_ty, span);
75+
let place = Place::from(temp);
76+
(place, rvalue)
77+
};
78+
79+
patch.add_assign(loc, place, rvalue);
80+
81+
let krabcake_req_operand = Operand::Copy(place);
82+
83+
let orig_terminator = patch.terminator_for_location(body, loc);
84+
let ikr_did = tcx.lang_items().insert_krabcake_request_fn().unwrap();
85+
let ikr_substs = InternalSubsts::identity_for_item(tcx, ikr_did);
86+
let ikr_ty = tcx.mk_fn_def(ikr_did, ikr_substs);
87+
88+
let func = Operand::Constant(Box::new(Constant {
89+
span,
90+
user_ty: None,
91+
literal: ConstantKind::zero_sized(ikr_ty),
92+
}));
93+
let storage = patch.new_temp(tcx.mk_mut_ptr(tcx.types.unit), span);
94+
let storage = Place::from(storage);
95+
let fn_call_terminator_kind = TerminatorKind::Call {
96+
func,
97+
args: vec![krabcake_req_operand],
98+
destination: storage,
99+
target: Some(loc.block + 1),
100+
cleanup: None,
101+
from_hir_call: false,
102+
fn_span: span,
103+
};
104+
105+
patch.patch_terminator(loc.block, fn_call_terminator_kind);
106+
107+
let new_bb =
108+
BasicBlockData { statements: vec![], terminator: orig_terminator, is_cleanup: false };
109+
110+
patch.new_block(new_bb);
111+
patch
112+
}

compiler/rustc_session/src/options.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1473,6 +1473,8 @@ options! {
14731473
`=except-unused-generics`
14741474
`=except-unused-functions`
14751475
`=off` (default)"),
1476+
instrument_krabcake: bool = (false, parse_bool, [TRACKED],
1477+
"insert Valgrind client requests to communicate with Krabcake"),
14761478
instrument_mcount: bool = (false, parse_bool, [TRACKED],
14771479
"insert function instrument code for mcount-based tracing (default: no)"),
14781480
instrument_xray: Option<InstrumentXRay> = (None, parse_instrument_xray, [TRACKED],

compiler/rustc_span/src/symbol.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,7 @@ symbols! {
216216
ItemContext,
217217
Iterator,
218218
IteratorItem,
219+
KrabcakeRequest,
219220
Layout,
220221
Left,
221222
LinkedList,
@@ -824,6 +825,7 @@ symbols! {
824825
inline_const,
825826
inline_const_pat,
826827
inout,
828+
insert_krabcake_request,
827829
instruction_set,
828830
integer_: "integer",
829831
integral,

library/core/src/krabcake.rs

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
use core::arch::asm;
2+
3+
mod vg_c_compatible {
4+
const fn vg_userreq_tool_base(a: u64, b: u64) -> u64 {
5+
((a) & 0xff) << 24 | ((b) & 0xff) << 16
6+
}
7+
8+
/// blah
9+
#[allow(dead_code)] // For currently unused variants
10+
#[derive(Debug, Clone, Copy)]
11+
#[repr(u64)]
12+
pub(super) enum ValgrindClientRequestCode {
13+
/// blah
14+
BorrowMut = vg_userreq_tool_base('K' as u64, 'C' as u64),
15+
/// blah
16+
BorrowShr,
17+
/// blah
18+
AsRaw,
19+
/// blah
20+
AsBorrowMut,
21+
/// blah
22+
AsBorrowShr,
23+
/// blah
24+
RetagFnPrologue,
25+
/// blah
26+
RetagAssign,
27+
/// blah
28+
RetagRaw,
29+
/// blah
30+
IntrinsicsAssume,
31+
/// blah
32+
KrabcakeRecordOverlapError = vg_userreq_tool_base('K' as u64, 'C' as u64) + 256,
33+
}
34+
35+
/// Ultimately, this should map to a [u64; 6], which is what Valgrind expects
36+
#[derive(Debug, Clone, Copy)]
37+
#[repr(C)]
38+
struct ValgrindClientRequest<T>
39+
where
40+
T: Into<u64>,
41+
{
42+
req_code: ValgrindClientRequestCode,
43+
args: [T; 5],
44+
}
45+
}
46+
47+
/// blah
48+
/// #[doc(hidden)]
49+
// There is no issue created for krabcake yet so just using a placeholder
50+
#[unstable(feature = "instrument_krabcake", issue = "1")]
51+
#[cfg_attr(not(bootstrap), lang = "KrabcakeRequest")]
52+
#[derive(Debug, Clone, Copy)]
53+
#[repr(C)]
54+
pub enum KrabcakeRequest {
55+
/// blah
56+
IntrinsicsAssume {
57+
/// blah
58+
flag: bool,
59+
},
60+
}
61+
62+
#[doc(hidden)]
63+
// There is no issue created for krabcake yet so just using a placeholder
64+
#[unstable(feature = "instrument_krabcake", issue = "1")]
65+
#[inline(never)]
66+
#[cfg_attr(not(bootstrap), lang = "insert_krabcake_request")]
67+
pub fn insert_krabcake_request(req: KrabcakeRequest) {
68+
// `res` not used for IntrinsicsAssume request
69+
let mut res = false as u64;
70+
let args: [u64; 6] = match req {
71+
KrabcakeRequest::IntrinsicsAssume { flag } => [
72+
vg_c_compatible::ValgrindClientRequestCode::IntrinsicsAssume as u64,
73+
flag.into(),
74+
0,
75+
0,
76+
0,
77+
0,
78+
],
79+
};
80+
81+
// SAFETY:
82+
// This is a valid safety comment
83+
unsafe {
84+
asm!(
85+
"rol rdi, 3",
86+
"rol rdi, 13",
87+
"rol rdi, 61",
88+
"rol rdi, 51",
89+
"xchg rbx, rbx",
90+
inout("di") res,
91+
in("ax") &args,
92+
);
93+
}
94+
let _ = res;
95+
}

library/core/src/lib.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,11 @@ pub mod task;
376376
#[allow(missing_docs)]
377377
pub mod alloc;
378378

379+
/// blah
380+
// There is no issue created for krabcake yet so just using a placeholder
381+
#[unstable(feature = "instrument_krabcake", issue = "1")]
382+
pub mod krabcake;
383+
379384
// note: does not need to be public
380385
mod bool;
381386
mod tuple;

0 commit comments

Comments
 (0)