llvm_mapper/record/
comdat.rs1use std::convert::TryInto;
4
5use llvm_support::StrtabRef;
6use num_enum::{TryFromPrimitive, TryFromPrimitiveError};
7use thiserror::Error;
8
9use crate::block::strtab::StrtabError;
10use crate::map::{MapError, PartialCtxMappable, PartialMapCtx};
11use crate::unroll::UnrolledRecord;
12
13#[non_exhaustive]
15#[derive(Debug, Error)]
16pub enum ComdatError {
17 #[error("unsupported COMDAT record format (v1)")]
19 V1Unsupported,
20
21 #[error("COMDAT record doesn't have enough fields ({0} < 3)")]
23 TooShort(usize),
24
25 #[error("error while accessing COMDAT name: {0}")]
27 Name(#[from] StrtabError),
28
29 #[error("unknown or invalid COMDAT selection kind: {0}")]
31 SelectionKind(#[from] TryFromPrimitiveError<SelectionKind>),
32
33 #[error("mapping error in comdat list")]
35 Map(#[from] MapError),
36}
37
38#[non_exhaustive]
42#[derive(Debug, TryFromPrimitive)]
43#[repr(u64)]
44pub enum SelectionKind {
45 Any,
47 ExactMatch,
49 Largest,
51 NoDeduplicate,
53 SameSize,
55}
56
57#[non_exhaustive]
59#[derive(Debug)]
60pub struct Comdat {
61 pub selection_kind: SelectionKind,
63 pub name: String,
65}
66
67impl PartialCtxMappable<UnrolledRecord> for Comdat {
68 type Error = ComdatError;
69
70 fn try_map(record: &UnrolledRecord, ctx: &mut PartialMapCtx) -> Result<Self, Self::Error> {
71 if !ctx.use_strtab().map_err(MapError::Context)? {
72 return Err(ComdatError::V1Unsupported);
73 }
74
75 if record.fields().len() != 3 {
77 return Err(ComdatError::TooShort(record.fields().len()));
78 }
79
80 let name = {
82 let sref: StrtabRef = (record.fields()[0], record.fields()[1]).into();
83 ctx.strtab.try_get(&sref)?.into()
84 };
85 let selection_kind: SelectionKind = record.fields()[2].try_into()?;
86
87 Ok(Self {
88 selection_kind,
89 name: name,
90 })
91 }
92}