llvm_mapper/
map.rs

1//! Traits for mapping bitstream types to models.
2
3use thiserror::Error;
4
5use crate::block::Strtab;
6use crate::block::{AttributeGroups, Attributes, TypeTable};
7use crate::record::{Comdat, DataLayout, RecordStringError};
8use crate::unroll::ConsistencyError;
9
10/// Generic errors that can occur when mapping.
11#[derive(Debug, Error)]
12pub enum MapError {
13    /// We couldn't map a block, for any number of reasons.
14    #[error("error while mapping block: {0}")]
15    BadBlockMap(String),
16
17    /// We encountered an inconsistent block or record state.
18    #[error("inconsistent block or record state")]
19    Inconsistent(#[from] ConsistencyError),
20
21    /// We encountered an unsupported feature or layout.
22    #[error("unsupported: {0}")]
23    Unsupported(String),
24
25    /// We encountered an invalid state or combination of states.
26    ///
27    /// This variant should be used extremely sparingly.
28    #[error("invalid: {0}")]
29    Invalid(String),
30
31    /// We couldn't extract a string from a record.
32    #[error("error while extracting string: {0}")]
33    RecordString(#[from] RecordStringError),
34
35    /// We don't have the appropriate context for a mapping operation.
36    #[error("missing context for mapping")]
37    Context(#[from] MapCtxError),
38}
39
40/// Errors that can occur when accessing a [`MapCtx`](MapCtx).
41#[derive(Debug, Error)]
42pub enum MapCtxError {
43    /// The version field is needed, but unavailable.
44    #[error("mapping context requires a version for disambiguation, but none is available")]
45    NoVersion,
46
47    /// The type table is needed, but unavailable.
48    #[error("mapping context requires types, but none are available")]
49    NoTypeTable,
50}
51
52/// A mushy container for various bits of state that are necessary for
53/// correct block and record mapping in the context of a particular IR module.
54///
55/// This is the "partial" counterpart to the [`MapCtx`](MapCtx) structure,
56/// which is produced from this structure with a call to [`reify`](PartialMapCtx::reify).
57#[non_exhaustive]
58#[derive(Debug, Default)]
59pub(crate) struct PartialMapCtx {
60    pub(crate) version: Option<u64>,
61    pub(crate) datalayout: DataLayout,
62    pub(crate) section_table: Vec<String>,
63    pub(crate) gc_table: Vec<String>,
64    pub(crate) strtab: Strtab,
65    pub(crate) attribute_groups: AttributeGroups,
66    pub(crate) attributes: Attributes,
67    pub(crate) type_table: Option<TypeTable>,
68    pub(crate) comdats: Vec<Comdat>,
69}
70
71impl PartialMapCtx {
72    pub(crate) fn reify(&self) -> Result<MapCtx, MapCtxError> {
73        log::debug!("reifying {self:?}");
74        Ok(MapCtx {
75            version: self.version.ok_or(MapCtxError::NoVersion)?,
76            datalayout: &self.datalayout,
77            section_table: &self.section_table,
78            gc_table: &self.gc_table,
79            strtab: &self.strtab,
80            attribute_groups: &self.attribute_groups,
81            attributes: &self.attributes,
82            type_table: self.type_table.as_ref().ok_or(MapCtxError::NoTypeTable)?,
83            comdats: &self.comdats,
84        })
85    }
86
87    /// A helper function for whether or not to use an associated string table for string lookups.
88    ///
89    /// This corresponds to `MODULE_CODE_VERSION`s of 2 and higher.
90    pub fn use_strtab(&self) -> Result<bool, MapCtxError> {
91        self.version.map(|v| v >= 2).ok_or(MapCtxError::NoVersion)
92    }
93
94    /// Returns the attribute groups stored in this context, or an error if not available.
95    pub fn attribute_groups(&self) -> &AttributeGroups {
96        &self.attribute_groups
97    }
98}
99
100/// A handle for various bits of state that are necessary for correct block
101/// and record mapping in the context of a particular IR module.
102///
103/// Block and record mapping operations are expected to update the supplied context,
104/// as appropriate.
105#[non_exhaustive]
106#[derive(Debug)]
107pub struct MapCtx<'ctx> {
108    /// The `MODULE_CODE_VERSION` for the IR module being mapped.
109    pub version: u64,
110
111    /// The datalayout specification.
112    pub datalayout: &'ctx DataLayout,
113
114    /// The section table.
115    pub section_table: &'ctx [String],
116
117    /// The GC table.
118    pub gc_table: &'ctx [String],
119
120    /// The string table.
121    pub strtab: &'ctx Strtab,
122
123    /// Any attribute groups.
124    pub attribute_groups: &'ctx AttributeGroups,
125
126    /// Any raw attributes.
127    pub attributes: &'ctx Attributes,
128
129    /// The type table.
130    pub type_table: &'ctx TypeTable,
131
132    /// The COMDAT list.
133    pub comdats: &'ctx [Comdat],
134    // TODO(ww): Maybe symtab and identification in here?
135}
136
137impl MapCtx<'_> {
138    /// A helper function for whether or not to use an associated string table for string lookups.
139    ///
140    /// This corresponds to `MODULE_CODE_VERSION`s of 2 and higher.
141    pub fn use_strtab(&self) -> bool {
142        self.version >= 2
143    }
144
145    /// A helper function for determining how operands are encoded.
146    ///
147    /// This corresponds to `MODULE_CODE_VERSION`s of 1 and higher.
148    pub fn use_relative_ids(&self) -> bool {
149        self.version >= 1
150    }
151}
152
153/// A trait for mapping some raw `T` into a model type.
154///
155/// This trait allows an implementer to modify the given [`PartialMapCtx`](PartialMapCtx),
156/// filling it in with state before it's reified into a "real" [`MapCtx`](MapCtx).
157///
158/// This two-stage process is designed to limit the number of invalid
159/// states that a `MapCtx` can be in, and to enable better lifetimes
160/// later in the IR module mapping process.
161pub(crate) trait PartialCtxMappable<T>: Sized {
162    type Error;
163
164    /// Attempt to map `T` into `Self` using the given [`PartialMapCtx`](PartialMapCtx).
165    fn try_map(raw: &T, ctx: &mut PartialMapCtx) -> Result<Self, Self::Error>;
166}
167
168/// A trait for mapping some raw `T` into a model type.
169///
170/// Implementing this trait is *almost* always preferable over
171/// [`PartialCtxMappable`](PartialCtxMappable) -- the former should really only
172/// be used when a mapping implementation **absolutely** must modify its
173/// [`MapCtx`](MapCtx), which should only happen early in IR module parsing.
174pub(crate) trait CtxMappable<'ctx, T>: Sized {
175    type Error;
176
177    /// Attempt to map `T` into `Self` using the given [`MapCtx`](MapCtx).
178    fn try_map(raw: &T, ctx: &'ctx MapCtx) -> Result<Self, Self::Error>;
179}