use crate::{ diff::{ ObjDataDiff, ObjDataDiffKind, ObjDiff, ObjInsArgDiff, ObjInsBranchFrom, ObjInsBranchTo, ObjInsDiff, ObjInsDiffKind, ObjSectionDiff, ObjSymbolDiff, }, obj::{ ObjInfo, ObjIns, ObjInsArg, ObjInsArgValue, ObjReloc, ObjSectionKind, ObjSymbol, ObjSymbolFlagSet, ObjSymbolFlags, }, }; // Protobuf diff types include!(concat!(env!("OUT_DIR"), "/objdiff.diff.rs")); include!(concat!(env!("OUT_DIR"), "/objdiff.diff.serde.rs")); impl DiffResult { pub fn new(left: Option<(&ObjInfo, &ObjDiff)>, right: Option<(&ObjInfo, &ObjDiff)>) -> Self { Self { left: left.map(|(obj, diff)| ObjectDiff::new(obj, diff)), right: right.map(|(obj, diff)| ObjectDiff::new(obj, diff)), } } } impl ObjectDiff { pub fn new(obj: &ObjInfo, diff: &ObjDiff) -> Self { Self { sections: diff .sections .iter() .enumerate() .map(|(i, d)| SectionDiff::new(obj, i, d)) .collect(), } } } impl SectionDiff { pub fn new(obj: &ObjInfo, section_index: usize, section_diff: &ObjSectionDiff) -> Self { let section = &obj.sections[section_index]; let functions = section_diff.symbols.iter().map(|d| FunctionDiff::new(obj, d)).collect(); let data = section_diff.data_diff.iter().map(|d| DataDiff::new(obj, d)).collect(); Self { name: section.name.to_string(), kind: SectionKind::from(section.kind) as i32, size: section.size, address: section.address, functions, data, match_percent: section_diff.match_percent, } } } impl From for SectionKind { fn from(value: ObjSectionKind) -> Self { match value { ObjSectionKind::Code => SectionKind::SectionText, ObjSectionKind::Data => SectionKind::SectionData, ObjSectionKind::Bss => SectionKind::SectionBss, // TODO common } } } impl FunctionDiff { pub fn new(object: &ObjInfo, symbol_diff: &ObjSymbolDiff) -> Self { let (_section, symbol) = object.section_symbol(symbol_diff.symbol_ref); // let diff_symbol = symbol_diff.diff_symbol.map(|symbol_ref| { // let (_section, symbol) = object.section_symbol(symbol_ref); // Symbol::from(symbol) // }); let instructions = symbol_diff .instructions .iter() .map(|ins_diff| InstructionDiff::new(object, ins_diff)) .collect(); Self { symbol: Some(Symbol::new(symbol)), // diff_symbol, instructions, match_percent: symbol_diff.match_percent, } } } impl DataDiff { pub fn new(_object: &ObjInfo, data_diff: &ObjDataDiff) -> Self { Self { kind: DiffKind::from(data_diff.kind) as i32, data: data_diff.data.clone(), size: data_diff.len as u64, } } } impl Symbol { pub fn new(value: &ObjSymbol) -> Self { Self { name: value.name.to_string(), demangled_name: value.demangled_name.clone(), address: value.address, size: value.size, flags: symbol_flags(value.flags), } } } fn symbol_flags(value: ObjSymbolFlagSet) -> u32 { let mut flags = 0u32; if value.0.contains(ObjSymbolFlags::Global) { flags |= SymbolFlag::SymbolNone as u32; } if value.0.contains(ObjSymbolFlags::Local) { flags |= SymbolFlag::SymbolLocal as u32; } if value.0.contains(ObjSymbolFlags::Weak) { flags |= SymbolFlag::SymbolWeak as u32; } if value.0.contains(ObjSymbolFlags::Common) { flags |= SymbolFlag::SymbolCommon as u32; } if value.0.contains(ObjSymbolFlags::Hidden) { flags |= SymbolFlag::SymbolHidden as u32; } flags } impl Instruction { pub fn new(object: &ObjInfo, instruction: &ObjIns) -> Self { Self { address: instruction.address, size: instruction.size as u32, opcode: instruction.op as u32, mnemonic: instruction.mnemonic.clone(), formatted: instruction.formatted.clone(), arguments: instruction.args.iter().map(Argument::new).collect(), relocation: instruction.reloc.as_ref().map(|reloc| Relocation::new(object, reloc)), branch_dest: instruction.branch_dest, line_number: instruction.line, original: instruction.orig.clone(), } } } impl Argument { pub fn new(value: &ObjInsArg) -> Self { Self { value: Some(match value { ObjInsArg::PlainText(s) => argument::Value::PlainText(s.to_string()), ObjInsArg::Arg(v) => argument::Value::Argument(ArgumentValue::new(v)), ObjInsArg::Reloc => argument::Value::Relocation(ArgumentRelocation {}), ObjInsArg::BranchDest(dest) => argument::Value::BranchDest(*dest), }), } } } impl ArgumentValue { pub fn new(value: &ObjInsArgValue) -> Self { Self { value: Some(match value { ObjInsArgValue::Signed(v) => argument_value::Value::Signed(*v), ObjInsArgValue::Unsigned(v) => argument_value::Value::Unsigned(*v), ObjInsArgValue::Opaque(v) => argument_value::Value::Opaque(v.to_string()), }), } } } impl Relocation { pub fn new(object: &ObjInfo, reloc: &ObjReloc) -> Self { Self { r#type: match reloc.flags { object::RelocationFlags::Elf { r_type } => r_type, object::RelocationFlags::MachO { r_type, .. } => r_type as u32, object::RelocationFlags::Coff { typ } => typ as u32, object::RelocationFlags::Xcoff { r_rtype, .. } => r_rtype as u32, _ => unreachable!(), }, type_name: object.arch.display_reloc(reloc.flags).into_owned(), target: Some(RelocationTarget { symbol: Some(Symbol::new(&reloc.target)), addend: reloc.addend, }), } } } impl InstructionDiff { pub fn new(object: &ObjInfo, instruction_diff: &ObjInsDiff) -> Self { Self { instruction: instruction_diff.ins.as_ref().map(|ins| Instruction::new(object, ins)), diff_kind: DiffKind::from(instruction_diff.kind) as i32, branch_from: instruction_diff.branch_from.as_ref().map(InstructionBranchFrom::new), branch_to: instruction_diff.branch_to.as_ref().map(InstructionBranchTo::new), arg_diff: instruction_diff.arg_diff.iter().map(ArgumentDiff::new).collect(), } } } impl ArgumentDiff { pub fn new(value: &Option) -> Self { Self { diff_index: value.as_ref().map(|v| v.idx as u32) } } } impl From for DiffKind { fn from(value: ObjInsDiffKind) -> Self { match value { ObjInsDiffKind::None => DiffKind::DiffNone, ObjInsDiffKind::OpMismatch => DiffKind::DiffOpMismatch, ObjInsDiffKind::ArgMismatch => DiffKind::DiffArgMismatch, ObjInsDiffKind::Replace => DiffKind::DiffReplace, ObjInsDiffKind::Delete => DiffKind::DiffDelete, ObjInsDiffKind::Insert => DiffKind::DiffInsert, } } } impl From for DiffKind { fn from(value: ObjDataDiffKind) -> Self { match value { ObjDataDiffKind::None => DiffKind::DiffNone, ObjDataDiffKind::Replace => DiffKind::DiffReplace, ObjDataDiffKind::Delete => DiffKind::DiffDelete, ObjDataDiffKind::Insert => DiffKind::DiffInsert, } } } impl InstructionBranchFrom { pub fn new(value: &ObjInsBranchFrom) -> Self { Self { instruction_index: value.ins_idx.iter().map(|&x| x as u32).collect(), branch_index: value.branch_idx as u32, } } } impl InstructionBranchTo { pub fn new(value: &ObjInsBranchTo) -> Self { Self { instruction_index: value.ins_idx as u32, branch_index: value.branch_idx as u32 } } }