fugue_db/
basic_block.rs

1use fugue_ir::disassembly::{ContextDatabase, IRBuilderArena};
2use fugue_ir::PCode;
3use fugue_ir::Translator;
4use fugue_ir::il::Instruction;
5use iset::IntervalMap;
6
7use crate::ArchitectureDef;
8use crate::Id;
9use crate::IntraRef;
10use crate::Segment;
11
12use crate::error::Error;
13use crate::schema;
14
15use educe::Educe;
16
17#[derive(Educe)]
18#[educe(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
19pub struct BasicBlock<'db> {
20    address: u64,
21    length: usize,
22    architecture_id: Id<ArchitectureDef>,
23    predecessors: Vec<IntraRef<'db>>,
24    successors: Vec<IntraRef<'db>>,
25    segment: &'db Segment,
26    #[educe(
27        Debug(ignore),
28        PartialEq(ignore),
29        PartialOrd(ignore),
30        Ord(ignore),
31        Hash(ignore)
32    )]
33    translator: &'db Translator,
34}
35
36impl<'db> BasicBlock<'db> {
37    #[doc(hidden)]
38    pub fn architecture(&self) -> usize {
39        self.architecture_id.index()
40    }
41
42    pub fn address(&self) -> u64 {
43        self.address
44    }
45
46    pub fn len(&self) -> usize {
47        self.length
48    }
49
50    pub fn segment(&self) -> &'db Segment {
51        self.segment
52    }
53
54    pub fn successors(&self) -> &[IntraRef] {
55        &self.successors
56    }
57
58    pub fn predecessors(&self) -> &[IntraRef] {
59        &self.predecessors
60    }
61
62    pub fn bytes(&self) -> &'db [u8] {
63        let offset = (self.address() - self.segment.address()) as usize;
64        &self.segment.bytes()[offset..offset + self.len()]
65    }
66
67    pub fn translate_with<F, O>(&self, context: &mut ContextDatabase, mut f: F) -> Result<Vec<O>, Error>
68    where F: FnMut(&'db Translator, &mut ContextDatabase, u64, &[u8]) -> Result<(O, usize), Error> {
69        let mut offset = 0;
70        let mut outputs = Vec::with_capacity(16);
71
72        let block_addr = self.address();
73        let bytes = self.bytes();
74
75        while offset < self.bytes().len() {
76            let address = block_addr + offset as u64;
77            let (output, length) = f(self.translator, context, address, &bytes[offset..])?;
78
79            offset += length;
80            outputs.push(output);
81        }
82
83        Ok(outputs)
84    }
85
86    pub fn disassemble_with<'z>(&self, context: &mut ContextDatabase, arena: &'z IRBuilderArena) -> Result<Vec<Instruction<'z>>, Error> {
87        self.translate_with(context, |translator, context, address, bytes| {
88            let insn = translator.disassemble(context, arena, translator.address(address), bytes)
89                .map_err(|source| Error::Lifting { address, source })?;
90            let length = insn.length();
91            Ok((insn, length))
92        })
93    }
94
95    pub fn disassemble<'z>(&self, arena: &'z IRBuilderArena) -> Result<Vec<Instruction<'z>>, Error> {
96        let mut context = self.translator.context_database();
97        self.disassemble_with(&mut context, arena)
98    }
99
100
101    pub fn lift_with<'z>(&self, context: &mut ContextDatabase) -> Result<Vec<PCode>, Error> {
102        self.translate_with(context, |translator, context, address, bytes| {
103            let pcode = translator.lift_pcode(context, translator.address(address), bytes)
104                .map_err(|source| Error::Lifting { address, source })?;
105            let length = pcode.length();
106            Ok((pcode, length))
107        })
108    }
109
110    pub fn lift(&self) -> Result<Vec<PCode>, Error> {
111        let mut context = self.translator.context_database();
112        self.lift_with(&mut context)
113    }
114
115    pub(crate) fn from_reader(
116        reader: schema::BasicBlock,
117        segments: &'db IntervalMap<u64, Segment>,
118        translators: &'db [Translator],
119    ) -> Result<Self, Error> {
120        let architecture_id = Id::<ArchitectureDef>::from(reader.architecture());
121        let arch_index = architecture_id.index();
122        let address = reader.address();
123        Ok(Self {
124            address,
125            length: reader.size_() as usize,
126            architecture_id,
127            segment: segments
128                .iter(address..address + reader.size_() as u64)
129                .find_map(|(_, s)| {
130                    if s.is_code() || s.is_external() {
131                        Some(s)
132                    } else {
133                        None
134                    }
135                })
136                .ok_or_else(|| Error::NoBlockSegment(reader.address()))?,
137            predecessors: reader
138                .predecessors()
139                .ok_or(Error::DeserialiseField("predecessors"))?
140                .into_iter()
141                .map(IntraRef::from_reader)
142                .collect::<Result<Vec<_>, _>>()?,
143            successors: reader
144                .successors()
145                .ok_or(Error::DeserialiseField("successors"))?
146                .into_iter()
147                .map(IntraRef::from_reader)
148                .collect::<Result<Vec<_>, _>>()?,
149            translator: &translators[arch_index],
150        })
151    }
152
153    pub(crate) fn to_builder<'a: 'b, 'b>(
154        &self,
155        builder: &'b mut flatbuffers::FlatBufferBuilder<'a>,
156    ) -> Result<flatbuffers::WIPOffset<schema::BasicBlock<'a>>, Error> {
157        let pvec = self.predecessors
158            .iter()
159            .map(|r| r.to_builder(builder))
160            .collect::<Result<Vec<_>, _>>()?;
161
162        let predecessors = builder.create_vector_from_iter(pvec.into_iter());
163
164        let svec = self.successors
165            .iter()
166            .map(|r| r.to_builder(builder))
167            .collect::<Result<Vec<_>, _>>()?;
168
169        let successors = builder.create_vector_from_iter(svec.into_iter());
170
171        let mut bbuilder = schema::BasicBlockBuilder::new(builder);
172
173        bbuilder.add_address(self.address());
174        bbuilder.add_size_(self.len() as u32);
175        bbuilder.add_architecture(self.architecture_id.index() as u32);
176        bbuilder.add_predecessors(predecessors);
177        bbuilder.add_successors(successors);
178
179        Ok(bbuilder.finish())
180    }
181}