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