| 157 | } |
| 158 | |
| 159 | pub fn display_row( |
| 160 | obj: &Object, |
| 161 | symbol_index: usize, |
| 162 | ins_row: &InstructionDiffRow, |
| 163 | diff_config: &DiffObjConfig, |
| 164 | mut cb: impl FnMut(DiffTextSegment) -> Result<()>, |
| 165 | ) -> Result<()> { |
| 166 | let Some(ins_ref) = ins_row.ins_ref else { |
| 167 | cb(EOL_SEGMENT)?; |
| 168 | return Ok(()); |
| 169 | }; |
| 170 | let Some(resolved) = obj.resolve_instruction_ref(symbol_index, ins_ref) else { |
| 171 | cb(DiffTextSegment::basic("<invalid>", DiffTextColor::Delete))?; |
| 172 | cb(EOL_SEGMENT)?; |
| 173 | return Ok(()); |
| 174 | }; |
| 175 | let base_color = match ins_row.kind { |
| 176 | InstructionDiffKind::Replace => DiffTextColor::Replace, |
| 177 | InstructionDiffKind::Delete => DiffTextColor::Delete, |
| 178 | InstructionDiffKind::Insert => DiffTextColor::Insert, |
| 179 | _ => DiffTextColor::Normal, |
| 180 | }; |
| 181 | if let Some(line) = resolved.section.line_info.range(..=ins_ref.address).last().map(|(_, &b)| b) |
| 182 | { |
| 183 | cb(DiffTextSegment { text: DiffText::Line(line), color: DiffTextColor::Dim, pad_to: 5 })?; |
| 184 | } |
| 185 | cb(DiffTextSegment { |
| 186 | text: DiffText::Address(ins_ref.address.saturating_sub(resolved.symbol.address)), |
| 187 | color: DiffTextColor::Dim, |
| 188 | pad_to: 5, |
| 189 | })?; |
| 190 | if let Some(branch) = &ins_row.branch_from { |
| 191 | // Pick the first branch source if there are multiple. |
| 192 | let ins_idx = branch.ins_idx[0]; |
| 193 | cb(DiffTextSegment { |
| 194 | text: DiffText::BranchArrow(ins_idx), |
| 195 | color: DiffTextColor::Rotating(branch.branch_idx as u8), |
| 196 | pad_to: 0, |
| 197 | })?; |
| 198 | } else { |
| 199 | cb(DiffTextSegment::spacing(4))?; |
| 200 | } |
| 201 | let mut arg_idx = 0; |
| 202 | let mut displayed_relocation = false; |
| 203 | let analysis_result = if diff_config.show_data_flow { |
| 204 | obj.get_flow_analysis_result(resolved.symbol) |
| 205 | } else { |
| 206 | None |
| 207 | }; |
| 208 | obj.arch.display_instruction(resolved, diff_config, &mut |part| match part { |
| 209 | InstructionPart::Basic(text) => { |
| 210 | if text.chars().all(|c| c == ' ') { |
| 211 | cb(DiffTextSegment::spacing(text.len() as u8)) |
| 212 | } else { |
| 213 | cb(DiffTextSegment::basic(&text, base_color)) |
| 214 | } |
| 215 | } |
| 216 | InstructionPart::Opcode(mnemonic, opcode) => cb(DiffTextSegment { |