mirror of
https://github.com/encounter/objdiff.git
synced 2026-03-30 11:32:16 -07:00
Restore objdiff-cli oneshot mode (JSON output) (#323)
This commit is contained in:
@@ -19,6 +19,7 @@ use crossterm::{
|
||||
},
|
||||
};
|
||||
use objdiff_core::{
|
||||
bindings::diff::DiffResult,
|
||||
build::{
|
||||
BuildConfig, BuildStatus,
|
||||
watcher::{Watcher, create_watcher},
|
||||
@@ -28,7 +29,7 @@ use objdiff_core::{
|
||||
build_globset,
|
||||
path::{check_path_buf, platform_path, platform_path_serde_option},
|
||||
},
|
||||
diff::{DiffObjConfig, MappingConfig, ObjectDiff},
|
||||
diff::{self, DiffObjConfig, DiffSide, MappingConfig, ObjectDiff},
|
||||
jobs::{
|
||||
Job, JobQueue, JobResult,
|
||||
objdiff::{ObjDiffConfig, start_build},
|
||||
@@ -40,7 +41,10 @@ use typed_path::{Utf8PlatformPath, Utf8PlatformPathBuf};
|
||||
|
||||
use crate::{
|
||||
cmd::apply_config_args,
|
||||
util::term::crossterm_panic_handler,
|
||||
util::{
|
||||
output::{OutputFormat, write_output},
|
||||
term::crossterm_panic_handler,
|
||||
},
|
||||
views::{EventControlFlow, EventResult, UiView, function_diff::FunctionDiffUi},
|
||||
};
|
||||
|
||||
@@ -60,6 +64,12 @@ pub struct Args {
|
||||
#[argp(option, short = 'u')]
|
||||
/// Unit name within project
|
||||
unit: Option<String>,
|
||||
#[argp(option, short = 'o', from_str_fn(platform_path))]
|
||||
/// Output file (one-shot mode) ("-" for stdout)
|
||||
output: Option<Utf8PlatformPathBuf>,
|
||||
#[argp(option)]
|
||||
/// Output format (json, json-pretty, proto) (default: json)
|
||||
format: Option<String>,
|
||||
#[argp(positional)]
|
||||
/// Function symbol to diff
|
||||
symbol: Option<String>,
|
||||
@@ -158,7 +168,41 @@ pub fn run(args: Args) -> Result<()> {
|
||||
_ => bail!("Either target and base or project and unit must be specified"),
|
||||
};
|
||||
|
||||
run_interactive(args, target_path, base_path, project_config, unit_options)
|
||||
if let Some(output) = &args.output {
|
||||
run_oneshot(&args, output, target_path.as_deref(), base_path.as_deref(), unit_options)
|
||||
} else {
|
||||
run_interactive(args, target_path, base_path, project_config, unit_options)
|
||||
}
|
||||
}
|
||||
|
||||
fn run_oneshot(
|
||||
args: &Args,
|
||||
output: &Utf8PlatformPath,
|
||||
target_path: Option<&Utf8PlatformPath>,
|
||||
base_path: Option<&Utf8PlatformPath>,
|
||||
unit_options: Option<ProjectOptions>,
|
||||
) -> Result<()> {
|
||||
let output_format = OutputFormat::from_option(args.format.as_deref())?;
|
||||
let (diff_config, mapping_config) = build_config_from_args(args, None, unit_options.as_ref())?;
|
||||
let target = target_path
|
||||
.map(|p| {
|
||||
obj::read::read(p.as_ref(), &diff_config, DiffSide::Target)
|
||||
.with_context(|| format!("Loading {p}"))
|
||||
})
|
||||
.transpose()?;
|
||||
let base = base_path
|
||||
.map(|p| {
|
||||
obj::read::read(p.as_ref(), &diff_config, DiffSide::Base)
|
||||
.with_context(|| format!("Loading {p}"))
|
||||
})
|
||||
.transpose()?;
|
||||
let result =
|
||||
diff::diff_objs(target.as_ref(), base.as_ref(), None, &diff_config, &mapping_config)?;
|
||||
let left = target.as_ref().and_then(|o| result.left.as_ref().map(|d| (o, d)));
|
||||
let right = base.as_ref().and_then(|o| result.right.as_ref().map(|d| (o, d)));
|
||||
let diff_result = DiffResult::new(left, right, &diff_config)?;
|
||||
write_output(&diff_result, Some(output), output_format)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn build_config_from_args(
|
||||
|
||||
@@ -0,0 +1,162 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package objdiff.diff;
|
||||
|
||||
// Top-level diff result containing left and right object diffs
|
||||
message DiffResult {
|
||||
optional DiffObject left = 1;
|
||||
optional DiffObject right = 2;
|
||||
}
|
||||
|
||||
// Diff information for a single object file
|
||||
message DiffObject {
|
||||
repeated DiffSection sections = 1;
|
||||
repeated DiffSymbol symbols = 2;
|
||||
}
|
||||
|
||||
// Diff information for a section
|
||||
message DiffSection {
|
||||
string name = 1;
|
||||
DiffSectionKind kind = 2;
|
||||
uint64 size = 3;
|
||||
uint64 address = 4;
|
||||
optional float match_percent = 5;
|
||||
repeated DiffDataSegment data_diff = 6;
|
||||
repeated DiffDataRelocation reloc_diff = 7;
|
||||
}
|
||||
|
||||
enum DiffSectionKind {
|
||||
SECTION_UNKNOWN = 0;
|
||||
SECTION_CODE = 1;
|
||||
SECTION_DATA = 2;
|
||||
SECTION_BSS = 3;
|
||||
SECTION_COMMON = 4;
|
||||
}
|
||||
|
||||
// Symbol with diff information
|
||||
message DiffSymbol {
|
||||
string name = 1;
|
||||
optional string demangled_name = 2;
|
||||
uint64 address = 3;
|
||||
uint64 size = 4;
|
||||
uint32 flags = 5;
|
||||
// The symbol index in the _other_ object that this symbol was diffed against
|
||||
optional uint32 target_symbol = 6;
|
||||
optional float match_percent = 7;
|
||||
// Instruction diff rows (for code symbols)
|
||||
repeated DiffInstructionRow instructions = 8;
|
||||
// Data diff (for data symbols)
|
||||
repeated DiffDataSegment data_diff = 9;
|
||||
}
|
||||
|
||||
// Symbol visibility flags (bitmask)
|
||||
enum DiffSymbolFlag {
|
||||
SYMBOL_NONE = 0;
|
||||
SYMBOL_GLOBAL = 1;
|
||||
SYMBOL_LOCAL = 2;
|
||||
SYMBOL_WEAK = 4;
|
||||
SYMBOL_COMMON = 8;
|
||||
SYMBOL_HIDDEN = 16;
|
||||
}
|
||||
|
||||
// A single instruction diff row
|
||||
message DiffInstructionRow {
|
||||
DiffKind diff_kind = 1;
|
||||
optional DiffInstruction instruction = 2;
|
||||
repeated DiffInstructionArgDiff arg_diff = 3;
|
||||
}
|
||||
|
||||
// Parsed instruction information
|
||||
message DiffInstruction {
|
||||
uint64 address = 1;
|
||||
uint32 size = 2;
|
||||
// Formatted instruction string
|
||||
string formatted = 3;
|
||||
// Formatted instruction parts
|
||||
repeated DiffInstructionPart parts = 4;
|
||||
// Relocation information (if present)
|
||||
optional DiffRelocation relocation = 5;
|
||||
// Branch destination address
|
||||
optional uint64 branch_dest = 6;
|
||||
// Source line number (if present)
|
||||
optional uint32 line_number = 7;
|
||||
}
|
||||
|
||||
// An instruction part
|
||||
message DiffInstructionPart {
|
||||
oneof part {
|
||||
// Basic text (whitespace, punctuation, etc.)
|
||||
string basic = 1;
|
||||
// Opcode/mnemonic
|
||||
DiffOpcode opcode = 2;
|
||||
// Argument
|
||||
DiffInstructionArg arg = 3;
|
||||
// Separator between arguments (comma)
|
||||
bool separator = 4;
|
||||
}
|
||||
}
|
||||
|
||||
message DiffOpcode {
|
||||
// Mnemonic string
|
||||
string mnemonic = 1;
|
||||
// Base opcode ID
|
||||
uint32 opcode = 2;
|
||||
}
|
||||
|
||||
// An instruction argument
|
||||
message DiffInstructionArg {
|
||||
oneof arg {
|
||||
// Signed immediate value
|
||||
sint64 signed = 1;
|
||||
// Unsigned immediate value
|
||||
uint64 unsigned = 2;
|
||||
// Opaque string value (register names, etc.)
|
||||
string opaque = 3;
|
||||
// Relocation
|
||||
bool reloc = 4;
|
||||
// Branch destination address
|
||||
uint64 branch_dest = 5;
|
||||
}
|
||||
}
|
||||
|
||||
// Relocation information
|
||||
message DiffRelocation {
|
||||
uint32 type = 1;
|
||||
string type_name = 2;
|
||||
uint32 target_symbol = 3;
|
||||
int64 addend = 4;
|
||||
}
|
||||
|
||||
// Argument diff information
|
||||
message DiffInstructionArgDiff {
|
||||
// If set, this argument differs from the other side.
|
||||
// The value is a rotating index for coloring.
|
||||
optional uint32 diff_index = 1;
|
||||
}
|
||||
|
||||
// Diff kind for instructions and data
|
||||
enum DiffKind {
|
||||
DIFF_NONE = 0;
|
||||
DIFF_REPLACE = 1;
|
||||
DIFF_DELETE = 2;
|
||||
DIFF_INSERT = 3;
|
||||
DIFF_OP_MISMATCH = 4;
|
||||
DIFF_ARG_MISMATCH = 5;
|
||||
}
|
||||
|
||||
// Data diff segment
|
||||
message DiffDataSegment {
|
||||
DiffKind kind = 1;
|
||||
bytes data = 2;
|
||||
// Size may be larger than data length for BSS
|
||||
uint64 size = 3;
|
||||
}
|
||||
|
||||
// Data relocation diff
|
||||
message DiffDataRelocation {
|
||||
DiffRelocation relocation = 1;
|
||||
DiffKind kind = 2;
|
||||
// Address range this relocation covers
|
||||
uint64 start = 3;
|
||||
uint64 end = 4;
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,350 @@
|
||||
#![allow(clippy::needless_lifetimes)] // Generated serde code
|
||||
|
||||
use alloc::{
|
||||
string::{String, ToString},
|
||||
vec,
|
||||
vec::Vec,
|
||||
};
|
||||
use core::fmt::Write;
|
||||
|
||||
use anyhow::Result;
|
||||
|
||||
use crate::{
|
||||
diff::{self, DiffObjConfig, display::InstructionPart},
|
||||
obj::{self, Object, SymbolFlag},
|
||||
};
|
||||
|
||||
// Protobuf diff types
|
||||
include!(concat!(env!("OUT_DIR"), "/objdiff.diff.rs"));
|
||||
#[cfg(feature = "serde")]
|
||||
include!(concat!(env!("OUT_DIR"), "/objdiff.diff.serde.rs"));
|
||||
|
||||
impl DiffResult {
|
||||
pub fn new(
|
||||
left: Option<(&Object, &diff::ObjectDiff)>,
|
||||
right: Option<(&Object, &diff::ObjectDiff)>,
|
||||
diff_config: &DiffObjConfig,
|
||||
) -> Result<Self> {
|
||||
Ok(Self {
|
||||
left: left.map(|(obj, diff)| DiffObject::new(obj, diff, diff_config)).transpose()?,
|
||||
right: right.map(|(obj, diff)| DiffObject::new(obj, diff, diff_config)).transpose()?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl DiffObject {
|
||||
pub fn new(obj: &Object, diff: &diff::ObjectDiff, diff_config: &DiffObjConfig) -> Result<Self> {
|
||||
let mut sections = Vec::with_capacity(obj.sections.len());
|
||||
for (section_idx, section) in obj.sections.iter().enumerate() {
|
||||
let section_diff = &diff.sections[section_idx];
|
||||
sections.push(DiffSection::new(obj, section, section_diff));
|
||||
}
|
||||
|
||||
let mut symbols = Vec::with_capacity(obj.symbols.len());
|
||||
for (symbol_idx, symbol) in obj.symbols.iter().enumerate() {
|
||||
let symbol_diff = &diff.symbols[symbol_idx];
|
||||
if symbol.size == 0 || symbol.flags.contains(SymbolFlag::Ignored) {
|
||||
continue;
|
||||
}
|
||||
symbols.push(DiffSymbol::new(obj, symbol_idx, symbol, symbol_diff, diff_config)?);
|
||||
}
|
||||
|
||||
Ok(Self { sections, symbols })
|
||||
}
|
||||
}
|
||||
|
||||
impl DiffSection {
|
||||
pub fn new(obj: &Object, section: &obj::Section, section_diff: &diff::SectionDiff) -> Self {
|
||||
Self {
|
||||
name: section.name.clone(),
|
||||
kind: DiffSectionKind::from(section.kind) as i32,
|
||||
size: section.size,
|
||||
address: section.address,
|
||||
match_percent: section_diff.match_percent,
|
||||
data_diff: section_diff.data_diff.iter().map(DiffDataSegment::from).collect(),
|
||||
reloc_diff: section_diff
|
||||
.reloc_diff
|
||||
.iter()
|
||||
.map(|r| DiffDataRelocation::new(obj, r))
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<obj::SectionKind> for DiffSectionKind {
|
||||
fn from(value: obj::SectionKind) -> Self {
|
||||
match value {
|
||||
obj::SectionKind::Unknown => DiffSectionKind::SectionUnknown,
|
||||
obj::SectionKind::Code => DiffSectionKind::SectionCode,
|
||||
obj::SectionKind::Data => DiffSectionKind::SectionData,
|
||||
obj::SectionKind::Bss => DiffSectionKind::SectionBss,
|
||||
obj::SectionKind::Common => DiffSectionKind::SectionCommon,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DiffSymbol {
|
||||
pub fn new(
|
||||
obj: &Object,
|
||||
symbol_idx: usize,
|
||||
symbol: &obj::Symbol,
|
||||
symbol_diff: &diff::SymbolDiff,
|
||||
diff_config: &DiffObjConfig,
|
||||
) -> Result<Self> {
|
||||
// Convert instruction rows
|
||||
let instructions = symbol_diff
|
||||
.instruction_rows
|
||||
.iter()
|
||||
.map(|row| DiffInstructionRow::new(obj, symbol_idx, row, diff_config))
|
||||
.collect::<Result<Vec<_>>>()?;
|
||||
|
||||
// Convert data diff - flatten DataDiffRow segments into a single list
|
||||
let data_diff: Vec<DiffDataSegment> = symbol_diff
|
||||
.data_rows
|
||||
.iter()
|
||||
.flat_map(|row| row.segments.iter().map(DiffDataSegment::from))
|
||||
.collect();
|
||||
|
||||
Ok(Self {
|
||||
// Symbol metadata
|
||||
name: symbol.name.clone(),
|
||||
demangled_name: symbol.demangled_name.clone(),
|
||||
address: symbol.address,
|
||||
size: symbol.size,
|
||||
flags: symbol_flags(&symbol.flags),
|
||||
// Diff information
|
||||
target_symbol: symbol_diff.target_symbol.map(|i| i as u32),
|
||||
match_percent: symbol_diff.match_percent,
|
||||
instructions,
|
||||
data_diff,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn symbol_flags(flags: &obj::SymbolFlagSet) -> u32 {
|
||||
let mut result = 0u32;
|
||||
if flags.contains(SymbolFlag::Global) {
|
||||
result |= DiffSymbolFlag::SymbolGlobal as u32;
|
||||
}
|
||||
if flags.contains(SymbolFlag::Local) {
|
||||
result |= DiffSymbolFlag::SymbolLocal as u32;
|
||||
}
|
||||
if flags.contains(SymbolFlag::Weak) {
|
||||
result |= DiffSymbolFlag::SymbolWeak as u32;
|
||||
}
|
||||
if flags.contains(SymbolFlag::Common) {
|
||||
result |= DiffSymbolFlag::SymbolCommon as u32;
|
||||
}
|
||||
if flags.contains(SymbolFlag::Hidden) {
|
||||
result |= DiffSymbolFlag::SymbolHidden as u32;
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
impl DiffInstructionRow {
|
||||
pub fn new(
|
||||
obj: &Object,
|
||||
symbol_idx: usize,
|
||||
row: &diff::InstructionDiffRow,
|
||||
diff_config: &DiffObjConfig,
|
||||
) -> Result<Self> {
|
||||
let instruction = if let Some(ins_ref) = row.ins_ref {
|
||||
let resolved = obj.resolve_instruction_ref(symbol_idx, ins_ref);
|
||||
resolved.map(|r| DiffInstruction::new(obj, r, diff_config)).transpose()?
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let arg_diff =
|
||||
row.arg_diff.iter().map(|d| DiffInstructionArgDiff { diff_index: d.get() }).collect();
|
||||
|
||||
Ok(Self { diff_kind: DiffKind::from(row.kind) as i32, instruction, arg_diff })
|
||||
}
|
||||
}
|
||||
|
||||
impl DiffInstruction {
|
||||
pub fn new(
|
||||
obj: &Object,
|
||||
resolved: obj::ResolvedInstructionRef,
|
||||
diff_config: &DiffObjConfig,
|
||||
) -> Result<Self> {
|
||||
let mut formatted = String::new();
|
||||
let mut parts = vec![];
|
||||
let separator = diff_config.separator();
|
||||
|
||||
// Use the arch's display_instruction to get formatted parts
|
||||
obj.arch.display_instruction(resolved, diff_config, &mut |part| {
|
||||
write_instruction_part(&mut formatted, &part, separator, resolved.relocation);
|
||||
parts
|
||||
.push(DiffInstructionPart { part: Some(diff_instruction_part::Part::from(&part)) });
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
let relocation = resolved.relocation.map(|r| DiffRelocation::new(obj, r));
|
||||
|
||||
let line_number = resolved
|
||||
.section
|
||||
.line_info
|
||||
.range(..=resolved.ins_ref.address)
|
||||
.last()
|
||||
.map(|(_, &line)| line);
|
||||
|
||||
Ok(Self {
|
||||
address: resolved.ins_ref.address,
|
||||
size: resolved.ins_ref.size as u32,
|
||||
formatted,
|
||||
parts,
|
||||
relocation,
|
||||
branch_dest: resolved.ins_ref.branch_dest,
|
||||
line_number,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn write_instruction_part(
|
||||
out: &mut String,
|
||||
part: &InstructionPart,
|
||||
separator: &str,
|
||||
reloc: Option<obj::ResolvedRelocation>,
|
||||
) {
|
||||
match part {
|
||||
InstructionPart::Basic(s) => out.push_str(s),
|
||||
InstructionPart::Opcode(s, _) => {
|
||||
out.push_str(s);
|
||||
out.push(' ');
|
||||
}
|
||||
InstructionPart::Arg(arg) => match arg {
|
||||
obj::InstructionArg::Value(v) => {
|
||||
let _ = write!(out, "{}", v);
|
||||
}
|
||||
obj::InstructionArg::Reloc => {
|
||||
if let Some(resolved) = reloc {
|
||||
out.push_str(&resolved.symbol.name);
|
||||
if resolved.relocation.addend != 0 {
|
||||
if resolved.relocation.addend < 0 {
|
||||
let _ = write!(out, "-{:#x}", -resolved.relocation.addend);
|
||||
} else {
|
||||
let _ = write!(out, "+{:#x}", resolved.relocation.addend);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
obj::InstructionArg::BranchDest(dest) => {
|
||||
let _ = write!(out, "{:#x}", dest);
|
||||
}
|
||||
},
|
||||
InstructionPart::Separator => out.push_str(separator),
|
||||
}
|
||||
}
|
||||
|
||||
impl diff_instruction_part::Part {
|
||||
fn from(part: &InstructionPart) -> Self {
|
||||
match part {
|
||||
InstructionPart::Basic(s) => diff_instruction_part::Part::Basic(s.to_string()),
|
||||
InstructionPart::Opcode(mnemonic, opcode) => {
|
||||
diff_instruction_part::Part::Opcode(DiffOpcode {
|
||||
mnemonic: mnemonic.to_string(),
|
||||
opcode: *opcode as u32,
|
||||
})
|
||||
}
|
||||
InstructionPart::Arg(arg) => {
|
||||
diff_instruction_part::Part::Arg(DiffInstructionArg::from(arg))
|
||||
}
|
||||
InstructionPart::Separator => diff_instruction_part::Part::Separator(true),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&obj::InstructionArg<'_>> for DiffInstructionArg {
|
||||
fn from(arg: &obj::InstructionArg) -> Self {
|
||||
let arg = match arg {
|
||||
obj::InstructionArg::Value(v) => match v {
|
||||
obj::InstructionArgValue::Signed(v) => diff_instruction_arg::Arg::Signed(*v),
|
||||
obj::InstructionArgValue::Unsigned(v) => diff_instruction_arg::Arg::Unsigned(*v),
|
||||
obj::InstructionArgValue::Opaque(v) => {
|
||||
diff_instruction_arg::Arg::Opaque(v.to_string())
|
||||
}
|
||||
},
|
||||
obj::InstructionArg::Reloc => diff_instruction_arg::Arg::Reloc(true),
|
||||
obj::InstructionArg::BranchDest(dest) => diff_instruction_arg::Arg::BranchDest(*dest),
|
||||
};
|
||||
DiffInstructionArg { arg: Some(arg) }
|
||||
}
|
||||
}
|
||||
|
||||
impl DiffRelocation {
|
||||
pub fn new(obj: &Object, resolved: obj::ResolvedRelocation) -> Self {
|
||||
let type_val = relocation_type(resolved.relocation.flags);
|
||||
let type_name = obj
|
||||
.arch
|
||||
.reloc_name(resolved.relocation.flags)
|
||||
.map(|s| s.to_string())
|
||||
.unwrap_or_default();
|
||||
Self {
|
||||
r#type: type_val,
|
||||
type_name,
|
||||
target_symbol: resolved.relocation.target_symbol as u32,
|
||||
addend: resolved.relocation.addend,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn relocation_type(flags: obj::RelocationFlags) -> u32 {
|
||||
match flags {
|
||||
obj::RelocationFlags::Elf(r_type) => r_type,
|
||||
obj::RelocationFlags::Coff(typ) => typ as u32,
|
||||
}
|
||||
}
|
||||
|
||||
impl From<diff::InstructionDiffKind> for DiffKind {
|
||||
fn from(value: diff::InstructionDiffKind) -> Self {
|
||||
match value {
|
||||
diff::InstructionDiffKind::None => DiffKind::DiffNone,
|
||||
diff::InstructionDiffKind::OpMismatch => DiffKind::DiffOpMismatch,
|
||||
diff::InstructionDiffKind::ArgMismatch => DiffKind::DiffArgMismatch,
|
||||
diff::InstructionDiffKind::Replace => DiffKind::DiffReplace,
|
||||
diff::InstructionDiffKind::Delete => DiffKind::DiffDelete,
|
||||
diff::InstructionDiffKind::Insert => DiffKind::DiffInsert,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<diff::DataDiffKind> for DiffKind {
|
||||
fn from(value: diff::DataDiffKind) -> Self {
|
||||
match value {
|
||||
diff::DataDiffKind::None => DiffKind::DiffNone,
|
||||
diff::DataDiffKind::Replace => DiffKind::DiffReplace,
|
||||
diff::DataDiffKind::Delete => DiffKind::DiffDelete,
|
||||
diff::DataDiffKind::Insert => DiffKind::DiffInsert,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&diff::DataDiff> for DiffDataSegment {
|
||||
fn from(value: &diff::DataDiff) -> Self {
|
||||
Self {
|
||||
kind: DiffKind::from(value.kind) as i32,
|
||||
data: value.data.clone(),
|
||||
size: value.size as u64,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DiffDataRelocation {
|
||||
pub fn new(obj: &Object, value: &diff::DataRelocationDiff) -> Self {
|
||||
let type_val = relocation_type(value.reloc.flags);
|
||||
let type_name =
|
||||
obj.arch.reloc_name(value.reloc.flags).map(|s| s.to_string()).unwrap_or_default();
|
||||
Self {
|
||||
relocation: Some(DiffRelocation {
|
||||
r#type: type_val,
|
||||
type_name,
|
||||
target_symbol: value.reloc.target_symbol as u32,
|
||||
addend: value.reloc.addend,
|
||||
}),
|
||||
kind: DiffKind::from(value.kind) as i32,
|
||||
start: value.range.start,
|
||||
end: value.range.end,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1 +1,3 @@
|
||||
#[cfg(feature = "any-arch")]
|
||||
pub mod diff;
|
||||
pub mod report;
|
||||
|
||||
Reference in New Issue
Block a user