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