| 185 | } |
| 186 | |
| 187 | fn display_instruction( |
| 188 | &self, |
| 189 | resolved: ResolvedInstructionRef, |
| 190 | diff_config: &DiffObjConfig, |
| 191 | cb: &mut dyn FnMut(InstructionPart) -> Result<()>, |
| 192 | ) -> Result<()> { |
| 193 | if resolved.ins_ref.opcode == OPCODE_DATA { |
| 194 | let (mnemonic, imm) = match resolved.ins_ref.size { |
| 195 | 1 => (".byte", resolved.code[0] as u64), |
| 196 | 2 => (".word", self.endianness.read_u16_bytes(resolved.code.try_into()?) as u64), |
| 197 | 4 => (".dword", self.endianness.read_u32_bytes(resolved.code.try_into()?) as u64), |
| 198 | _ => bail!("Unsupported x86 inline data size {}", resolved.ins_ref.size), |
| 199 | }; |
| 200 | cb(InstructionPart::opcode(mnemonic, OPCODE_DATA))?; |
| 201 | if resolved.relocation.is_some() { |
| 202 | cb(InstructionPart::reloc())?; |
| 203 | } else { |
| 204 | cb(InstructionPart::unsigned(imm))?; |
| 205 | } |
| 206 | return Ok(()); |
| 207 | } |
| 208 | |
| 209 | let mut decoder = self.decoder(resolved.code, resolved.ins_ref.address); |
| 210 | let mut formatter = self.formatter(diff_config); |
| 211 | let mut instruction = Instruction::default(); |
| 212 | decoder.decode_out(&mut instruction); |
| 213 | |
| 214 | // Determine where to insert relocation in instruction output. |
| 215 | // We replace the immediate or displacement with a placeholder value since the formatter |
| 216 | // doesn't provide enough information to know which number is the displacement inside a |
| 217 | // memory operand. |
| 218 | let mut reloc_replace = None; |
| 219 | if let Some(reloc) = resolved.relocation { |
| 220 | const PLACEHOLDER: u64 = 0x7BDE3E7D; // chosen by fair dice roll. guaranteed to be random. |
| 221 | let reloc_offset = reloc.relocation.address - resolved.ins_ref.address; |
| 222 | let reloc_size = self.reloc_size(reloc.relocation.flags).unwrap_or(usize::MAX); |
| 223 | let offsets = decoder.get_constant_offsets(&instruction); |
| 224 | if reloc_offset == offsets.displacement_offset() as u64 |
| 225 | && reloc_size == offsets.displacement_size() |
| 226 | { |
| 227 | instruction.set_memory_displacement64(PLACEHOLDER); |
| 228 | // Formatter always writes the displacement as Int32 |
| 229 | reloc_replace = Some((OpKind::Memory, 4, PLACEHOLDER)); |
| 230 | } else if reloc_offset == offsets.immediate_offset() as u64 |
| 231 | && reloc_size == offsets.immediate_size() |
| 232 | { |
| 233 | let is_branch = matches!( |
| 234 | instruction.op0_kind(), |
| 235 | OpKind::NearBranch16 | OpKind::NearBranch32 | OpKind::NearBranch64 |
| 236 | ); |
| 237 | let op_kind = if is_branch { |
| 238 | instruction.op0_kind() |
| 239 | } else { |
| 240 | match reloc_size { |
| 241 | 2 => OpKind::Immediate16, |
| 242 | 4 => OpKind::Immediate32, |
| 243 | 8 => OpKind::Immediate64, |
| 244 | _ => OpKind::default(), |