rustc_sanitizers/cfi/typeid/itanium_cxx_abi/
mod.rs1use rustc_abi::CanonAbi;
8use rustc_data_structures::fx::FxHashMap;
9use rustc_middle::bug;
10use rustc_middle::ty::{self, Instance, Ty, TyCtxt, TypeFoldable, TypeVisitableExt};
11use rustc_target::callconv::{FnAbi, PassMode};
12use tracing::instrument;
13
14mod encode;
15mod transform;
16use crate::cfi::typeid::TypeIdOptions;
17use crate::cfi::typeid::itanium_cxx_abi::encode::{DictKey, EncodeTyOptions, encode_ty};
18use crate::cfi::typeid::itanium_cxx_abi::transform::{
19 TransformTy, TransformTyOptions, transform_instance,
20};
21
22#[instrument(level = "trace", skip(tcx))]
25pub fn typeid_for_fnabi<'tcx>(
26 tcx: TyCtxt<'tcx>,
27 fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
28 options: TypeIdOptions,
29) -> String {
30 let mut typeid = String::from("_Z");
33
34 typeid.push_str("TS");
38
39 typeid.push('F');
41
42 let mut dict: FxHashMap<DictKey<'tcx>, usize> = FxHashMap::default();
45
46 let mut encode_ty_options = EncodeTyOptions::from_bits(options.bits())
47 .unwrap_or_else(|| bug!("typeid_for_fnabi: invalid option(s) `{:?}`", options.bits()));
48 match fn_abi.conv {
49 CanonAbi::C => {
50 encode_ty_options.insert(EncodeTyOptions::GENERALIZE_REPR_C);
51 }
52 _ => {
53 encode_ty_options.remove(EncodeTyOptions::GENERALIZE_REPR_C);
54 }
55 }
56
57 let transform_ty_options = TransformTyOptions::from_bits(options.bits())
59 .unwrap_or_else(|| bug!("typeid_for_fnabi: invalid option(s) `{:?}`", options.bits()));
60 let mut type_folder = TransformTy::new(tcx, transform_ty_options);
61 let ty = fn_abi.ret.layout.ty.fold_with(&mut type_folder);
62 typeid.push_str(&encode_ty(tcx, ty, &mut dict, encode_ty_options));
63
64 if !fn_abi.c_variadic {
70 let mut pushed_arg = false;
71 for arg in fn_abi.args.iter().filter(|arg| arg.mode != PassMode::Ignore) {
72 pushed_arg = true;
73 let ty = arg.layout.ty.fold_with(&mut type_folder);
74 typeid.push_str(&encode_ty(tcx, ty, &mut dict, encode_ty_options));
75 }
76 if !pushed_arg {
77 typeid.push('v');
80 }
81 } else {
82 for n in 0..fn_abi.fixed_count as usize {
83 if fn_abi.args[n].mode == PassMode::Ignore {
84 continue;
85 }
86 let ty = fn_abi.args[n].layout.ty.fold_with(&mut type_folder);
87 typeid.push_str(&encode_ty(tcx, ty, &mut dict, encode_ty_options));
88 }
89
90 typeid.push('z');
91 }
92
93 typeid.push('E');
95
96 if options.contains(EncodeTyOptions::NORMALIZE_INTEGERS) {
98 typeid.push_str(".normalized");
99 }
100
101 if options.contains(EncodeTyOptions::GENERALIZE_POINTERS) {
102 typeid.push_str(".generalized");
103 }
104
105 typeid
106}
107
108#[instrument(level = "trace", skip(tcx))]
111pub fn typeid_for_instance<'tcx>(
112 tcx: TyCtxt<'tcx>,
113 instance: Instance<'tcx>,
114 options: TypeIdOptions,
115) -> String {
116 assert!(!instance.has_non_region_param(), "{instance:#?} must be fully monomorphic");
117 let transform_ty_options = TransformTyOptions::from_bits(options.bits())
118 .unwrap_or_else(|| bug!("typeid_for_instance: invalid option(s) `{:?}`", options.bits()));
119 let instance = transform_instance(tcx, instance, transform_ty_options);
120 let fn_abi = tcx
121 .fn_abi_of_instance(
122 ty::TypingEnv::fully_monomorphized().as_query_input((instance, ty::List::empty())),
123 )
124 .unwrap_or_else(|error| {
125 bug!("typeid_for_instance: couldn't get fn_abi of instance {instance:?}: {error:?}")
126 });
127 typeid_for_fnabi(tcx, fn_abi, options)
128}