yaxpeax_core/arch/display/
function.rs1use yaxpeax_arch::Arch;
2use yaxpeax_arch::AddressBase;
3use yaxpeax_arch::AddressDisplay;
4use yaxpeax_arch::LengthedInstruction;
5use arch::DecodeFrom;
6use arch::InstructionSpan;
7use arch::display::BaseDisplay;
8use analyses::static_single_assignment::DataDisplay;
9use analyses::static_single_assignment::SSAValues;
10use analyses::static_single_assignment::SSA;
11use analyses::control_flow::ControlFlowGraph;
12use memory::MemoryRepr;
13use memory::MemoryRange;
14use data::Direction;
15use display::location::{NoHighlights, HighlightList, LocationHighlighter};
16use arch::FunctionQuery;
17use arch::SymbolQuery;
18use arch::FunctionRepr;
19use yaxpeax_arch::ColorSettings;
20
21use std::fmt;
22use std::fmt::Write;
23use std::marker::PhantomData;
24
25pub struct FunctionView<
34 'a, 'c, 'd, 'e,
35 F: FunctionRepr,
36 Context: FunctionQuery<A::Address>,
37 A: Arch + BaseDisplay<F, Context> + SSAValues,
38 M: MemoryRepr<A> + MemoryRange<A>
39> {
40 pub _function_type: PhantomData<F>,
41 pub data: &'a M,
42 pub ctx: Context,
43 pub fn_graph: &'c ControlFlowGraph<A::Address>,
44 pub ssa: Option<&'d SSA<A>>,
45 pub colors: Option<&'e ColorSettings>,
46 pub highlight_instrs: Vec<A::Address>,
47 pub highlight_locs: Vec<(A::Address, A::Location, Direction)>,
48}
49
50pub trait FunctionDisplay<A: Arch + SSAValues> {
51 fn entrypoint(&self) -> A::Address;
52 fn remove_highlight_instr(&mut self, addr: A::Address);
53 fn add_highlight_instr(&mut self, addr: A::Address);
54 fn add_highlight_loc(&mut self, loc: (A::Address, A::Location, Direction));
55 fn reset_highlight_instrs(&mut self);
56 fn reset_highlight_locs(&mut self);
57 fn view_between(&self, start: Option<A::Address>, end: Option<A::Address>) -> Vec<(A::Address, Vec<String>)>;
58}
59
60pub trait FunctionInstructionDisplay<A: Arch + SSAValues, Context: SymbolQuery<A::Address> + FunctionQuery<A::Address>> {
61 fn display_instruction_in_function<W: fmt::Write, Highlighter: LocationHighlighter<A::Location>>(
62 dest: &mut W,
63 instr: &A::Instruction,
64 address: A::Address,
65 context: &Context,
66 ssa: Option<&SSA<A>>,
67 colors: Option<&ColorSettings>,
68 highlight: &Highlighter
69 ) -> fmt::Result;
70}
71
72
73impl <
74 'a, 'c, 'd, 'e,
75 A,
76 F: FunctionRepr,
77 Context: FunctionQuery<A::Address> + SymbolQuery<A::Address>,
78 M: MemoryRepr<A> + MemoryRange<A>
79> FunctionDisplay<A> for FunctionView<'a, 'c, 'd, 'e, F, Context, A, M> where
80 A: Arch +
81 SSAValues +
82 FunctionInstructionDisplay<A, Context> +
83 DecodeFrom<M> +
84 BaseDisplay<F, Context>,
85{
86 fn entrypoint(&self) -> A::Address {
87 self.fn_graph.entrypoint
88 }
89 fn remove_highlight_instr(&mut self, addr: A::Address) {
90 for i in 0..self.highlight_instrs.len() {
91 if self.highlight_instrs[i] == addr {
92 self.highlight_instrs.swap_remove(i);
93 return;
94 }
95 }
96 }
97 fn add_highlight_instr(&mut self, addr: A::Address) {
98 self.highlight_instrs.push(addr);
99 }
100 fn add_highlight_loc(&mut self, loc: (A::Address, A::Location, Direction)) {
101 self.highlight_locs.push(loc);
102 }
103 fn reset_highlight_instrs(&mut self) {
104 self.highlight_instrs.clear();
105 }
106 fn reset_highlight_locs(&mut self) {
107 self.highlight_locs.clear();
108 }
109
110 fn view_between(&self, start: Option<A::Address>, end: Option<A::Address>) -> Vec<(A::Address, Vec<String>)> {
111 let mut text: Vec<(A::Address, Vec<String>)> = Vec::new();
112 let mut blocks: Vec<A::Address> = self.fn_graph.blocks.keys().cloned().collect();
113 blocks.sort();
114
115 for blockaddr in blocks.iter() {
116 let block = self.fn_graph.get_block(*blockaddr);
117
118 use num_traits::Zero;
122 if block.start == A::Address::zero() { continue; }
123
124 let mut iter = A::instructions_spanning(self.data, block.start, block.end);
125
126 if let Some(ssa) = self.ssa {
127 let start_ok = if let Some(start) = start {
128 block.start >= start
129 } else { true };
130
131 let end_ok = if let Some(end) = end {
132 block.start <= end
133 } else { true };
134
135 if start_ok && end_ok {
136 if self.fn_graph.sources(block.start).len() == 0 {
137 continue;
138 }
139 let mut strings: Vec<String> = Vec::new();
140
141 for source in self.fn_graph.sources(block.start) {
143 if let Some(modifications) = ssa.control_dependent_values
144 .get(&source)
145 .and_then(|dests| dests.get(&block.start)) {
146
147 for ((_loc, dir), value) in modifications.iter() {
148 match dir {
149 Direction::Read => {
150 strings.push(format!("read: {}", value.borrow().display(false, None)));
151 strings.push(format!(" via edge {} -> {}", source.show(), block.start.show()));
152 }
153 Direction::Write => {
154 strings.push(format!("write: {}", value.borrow().display(false, None)));
155 strings.push(format!(" via edge {} -> {}", source.show(), block.start.show()));
156 }
157 }
158 }
159 }
160 }
161
162 if let Some(phis) = ssa.phi.get(&block.start) {
163 let frame = format!("{}: : | |", block.start.show());
165 let mut hiddens: Vec<A::Location> = Vec::new();
166 for (_, phi_op) in phis.iter() {
167 let out = phi_op.out.borrow();
168 if !out.used {
169 hiddens.push(out.location.clone());
170 continue;
171 }
172 let mut phi_line = format!("{} {} <- phi(", frame, phi_op.out.borrow().display(false, None));
173 let mut in_iter = phi_op.ins.iter();
174 if let Some(phi_in) = in_iter.next() {
175 write!(phi_line, "{}", phi_in.borrow().display(false, None)).unwrap();
176 }
177 while let Some(phi_in) = in_iter.next() {
178 write!(phi_line, ", {}", phi_in.borrow().display(false, None)).unwrap();
179 }
180 phi_line.push(')');
181 strings.push(phi_line);
182 }
183 if hiddens.len() > 0 {
184 let mut hidden_locs_line = format!("{} hidden dead phis for {:?}", frame, hiddens[0]);
185 for loc in &hiddens[1..] {
186 write!(hidden_locs_line, ", {:?}", loc).unwrap();
187 }
188 strings.push(hidden_locs_line);
189 }
190 }
191 text.push((block.start, strings));
192 }
193 }
194
195 let span_end = iter.end;
196 while let Some((address, instr)) = iter.next() {
197 if let Some(start) = start {
198 if address < start {
199 continue;
200 }
201 }
202
203 if let Some(end) = end {
204 if address > end {
205 continue;
206 }
207 }
208
209 let mut instr_string = String::new();
210 A::render_frame(
211 &mut instr_string,
212 address,
213 instr,
214 &mut self.data.range(address..(address.wrapping_offset(instr.len()))).unwrap(),
215 Some(&self.ctx),
216 ).unwrap();
217 write!(instr_string, " ").unwrap();
219 if self.highlight_instrs.contains(&address) {
220 write!(instr_string, "{}", termion::style::Invert).unwrap();
221 }
222 let highlights: Vec<(A::Location, Direction)> = self.highlight_locs.iter().filter_map(|(highlight_addr, loc, dir)| {
223 Some((loc.clone(), *dir)).filter(|_| highlight_addr == &address)
224 }).collect();
225 if highlights.len() == 0 {
226 A::display_instruction_in_function(
227 &mut instr_string,
228 &instr,
229 address,
230 &self.ctx, self.ssa, self.colors,
231 &NoHighlights
232 ).unwrap();
233 } else {
234 A::display_instruction_in_function(
235 &mut instr_string,
236 &instr,
237 address,
238 &self.ctx, self.ssa, self.colors,
239 &HighlightList {
240 operands_bits: 0,
241 location_highlights: highlights
242 }
243 ).unwrap();
244 }
245 if self.highlight_instrs.contains(&address) {
246 write!(instr_string, "{}", termion::style::NoInvert).unwrap();
247 }
248 if address.wrapping_offset(instr.len()) > span_end {
249 write!(instr_string ,"\n┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄").unwrap();
250 }
251
252 match text.last().map(|(addr, _)| *addr) {
254 Some(last_addr) if last_addr == address => { },
255 _ => {
256 text.push((address, Vec::new()));
257 }
258 }
259 text.last_mut().expect("actually unreachable").1.extend(
260 instr_string.split("\n").map(|s| s.to_string())
261 );
262 }
263 }
264 text
265 }
266}
267