fugue_db/
function.rs

1use fugue_ir::Translator;
2use iset::IntervalMap;
3
4use crate::Id;
5use crate::BasicBlock;
6use crate::InterRef;
7use crate::Segment;
8
9use crate::error::Error;
10use crate::schema;
11
12#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
13pub struct Function<'db> {
14    symbol: String,
15    entry: Id<BasicBlock<'db>>,
16    address: u64,
17    segment: Id<Segment>,
18    blocks: Vec<BasicBlock<'db>>,
19    references: Vec<InterRef<'db>>,
20}
21
22impl<'db> Function<'db> {
23    pub fn name(&self) -> &str {
24        &self.symbol
25    }
26
27    pub fn address(&self) -> u64 {
28        self.address
29    }
30
31    pub fn entry(&self) -> Option<&BasicBlock> {
32        self.blocks.get(self.entry.index())
33    }
34
35    pub fn blocks(&self) -> &[BasicBlock] {
36        &self.blocks
37    }
38
39    pub fn segment_id(&self) -> Id<Segment> {
40        self.segment.clone()
41    }
42
43    pub fn references(&self) -> &[InterRef] {
44        &self.references
45    }
46
47    pub(crate) fn from_reader(reader: schema::Function, segments: &'db IntervalMap<u64, Segment>, translators: &'db [Translator]) -> Result<Self, Error> {
48        let address = reader.address();
49        Ok(Self {
50            symbol: reader.symbol().ok_or(Error::DeserialiseField("symbol"))?.to_string(),
51            entry: Id::from(reader.entry()),
52            address,
53            segment: segments
54                .iter(address..address + 1)
55                .find_map(|(_, s)| {
56                    if s.is_code() || s.is_external() {
57                        Some(s.id())
58                    } else {
59                        None
60                    }
61                })
62                .ok_or_else(|| Error::NoFunctionSegment(reader.address()))?,
63            blocks: reader.blocks().ok_or(Error::DeserialiseField("blocks"))?
64                .into_iter()
65                .map(|b| BasicBlock::from_reader(b, segments, translators))
66                .collect::<Result<Vec<_>, _>>()?,
67            references: reader.references().ok_or(Error::DeserialiseField("references"))?
68                .into_iter()
69                .map(InterRef::from_reader)
70                .collect::<Result<Vec<_>, _>>()?,
71        })
72    }
73
74    pub(crate) fn to_builder<'a: 'b, 'b>(
75        &self,
76        builder: &'b mut flatbuffers::FlatBufferBuilder<'a>
77    ) -> Result<flatbuffers::WIPOffset<schema::Function<'a>>, Error> {
78        let symbol = builder.create_string(self.name());
79
80        let bvec = self.blocks
81            .iter()
82            .map(|r| r.to_builder(builder))
83            .collect::<Result<Vec<_>, _>>()?;
84
85        let blocks = builder.create_vector_from_iter(bvec.into_iter());
86
87        let rvec = self.references
88            .iter()
89            .map(|r| r.to_builder(builder))
90            .collect::<Result<Vec<_>, _>>()?;
91
92        let references = builder.create_vector_from_iter(rvec.into_iter());
93
94        let mut fbuilder = schema::FunctionBuilder::new(builder);
95
96        fbuilder.add_symbol(symbol);
97        fbuilder.add_address(self.address());
98        fbuilder.add_entry(self.entry.value());
99        fbuilder.add_blocks(blocks);
100        fbuilder.add_references(references);
101
102        Ok(fbuilder.finish())
103    }
104}
105