llvm_mapper/record/
function.rs1use std::convert::TryFrom;
4
5use llvm_support::{
6 AlignError, CallingConvention, DllStorageClass, Linkage, MaybeAlign, Type, UnnamedAddr,
7 Visibility,
8};
9use num_enum::TryFromPrimitiveError;
10use thiserror::Error;
11
12use crate::block::attributes::AttributeEntry;
13use crate::map::{CtxMappable, MapCtx};
14use crate::record::StrtabError;
15use crate::unroll::UnrolledRecord;
16
17#[derive(Debug, Error)]
19pub enum FunctionError {
20 #[error("function record too short: {0} < 10 fields")]
22 TooShort(usize),
23
24 #[error("unsupported function record format (v1)")]
26 V1Unsupported,
27
28 #[error("error while accessing string table")]
30 Strtab(#[from] StrtabError),
31
32 #[error("unknown calling convention")]
34 CallingConvention(#[from] TryFromPrimitiveError<CallingConvention>),
35
36 #[error("invalid type table index: {0}")]
38 Type(u64),
39
40 #[error("invalid attribute entry ID: {0}")]
42 Attribute(u64),
43
44 #[error("invalid alignment")]
46 Alignment(#[from] AlignError),
47
48 #[error("invalid section table index: {0}")]
50 Section(usize),
51
52 #[error("invalid visibility")]
54 Visibility(#[from] TryFromPrimitiveError<Visibility>),
55
56 #[error("invalid GC table index: {0}")]
58 Gc(usize),
59
60 #[error("invalid storage class")]
62 DllStorageClass(#[from] TryFromPrimitiveError<DllStorageClass>),
63}
64
65#[non_exhaustive]
67#[derive(Debug)]
68pub struct Function<'ctx> {
69 pub name: &'ctx str,
71
72 pub ty: &'ctx Type,
74
75 pub calling_convention: CallingConvention,
77
78 pub is_declaration: bool,
80
81 pub linkage: Linkage,
83
84 pub attributes: Option<&'ctx AttributeEntry>,
86
87 pub alignment: MaybeAlign,
89
90 pub section: Option<&'ctx str>,
92
93 pub visibility: Visibility,
95
96 pub gc_name: Option<&'ctx str>,
98
99 pub unnamed_addr: UnnamedAddr,
101
102 pub storage_class: DllStorageClass,
104}
105
106impl<'ctx> CtxMappable<'ctx, UnrolledRecord> for Function<'ctx> {
107 type Error = FunctionError;
108
109 fn try_map(record: &UnrolledRecord, ctx: &'ctx MapCtx) -> Result<Self, Self::Error> {
110 let fields = record.fields();
111
112 if !ctx.use_strtab() {
113 return Err(FunctionError::V1Unsupported);
114 }
115
116 if fields.len() < 10 {
120 return Err(FunctionError::TooShort(fields.len()));
121 }
122
123 let name = ctx.strtab.read_name(record)?;
124 let ty = ctx
125 .type_table
126 .get(fields[2])
127 .ok_or(FunctionError::Type(fields[2]))?;
128 let calling_convention = CallingConvention::try_from(fields[3])?;
129 let is_declaration = fields[4] != 0;
130 let linkage = Linkage::from(fields[5]);
131
132 let attributes = {
133 let paramattr = fields[6];
134 if paramattr == 0 {
137 None
138 } else {
139 Some(
143 ctx.attributes
144 .get(paramattr - 1)
145 .ok_or(FunctionError::Attribute(paramattr))?,
146 )
147 }
148 };
149
150 let alignment = MaybeAlign::try_from(fields[7] as u8)?;
153
154 let section = match fields[8] as usize {
155 0 => None,
156 idx => Some(
157 ctx.section_table
158 .get(idx - 1)
159 .map(AsRef::as_ref)
160 .ok_or(FunctionError::Section(idx - 1))?,
161 ),
162 };
163
164 let visibility = Visibility::try_from(fields[9])?;
165
166 let gc_name = fields
169 .get(10)
170 .and_then(|idx| match *idx as usize {
171 0 => None,
172 idx => Some(
173 ctx.gc_table
174 .get(idx - 1)
175 .map(AsRef::as_ref)
176 .ok_or(FunctionError::Gc(idx - 1)),
177 ),
178 })
179 .transpose()?;
180
181 let unnamed_addr = fields
182 .get(11)
183 .copied()
184 .map(UnnamedAddr::from)
185 .unwrap_or(UnnamedAddr::None);
186
187 let storage_class = fields.get(13).map_or_else(
190 || Ok(DllStorageClass::Default),
191 |v| DllStorageClass::try_from(*v),
192 )?;
193
194 Ok(Self {
200 name,
201 ty,
202 calling_convention,
203 is_declaration,
204 linkage,
205 attributes,
206 alignment,
207 section,
208 visibility,
209 gc_name,
210 unnamed_addr,
211 storage_class,
212 })
213 }
214}