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}