mirror of
https://github.com/encounter/objdiff.git
synced 2026-07-10 12:18:36 -07:00
Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| bd3ed0d5ad | |||
| e638d0b17a | |||
| f58616b6dd | |||
| e9762e24c2 | |||
| dab79d96a1 | |||
| a57e5db983 | |||
| d0afd3b83e | |||
| a367af612b | |||
| 22052ea10b |
Generated
+4
-4
@@ -3373,7 +3373,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "objdiff-cli"
|
||||
version = "3.0.0-beta.8"
|
||||
version = "3.0.0-beta.10"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"argp",
|
||||
@@ -3396,7 +3396,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "objdiff-core"
|
||||
version = "3.0.0-beta.8"
|
||||
version = "3.0.0-beta.10"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"arm-attr",
|
||||
@@ -3450,7 +3450,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "objdiff-gui"
|
||||
version = "3.0.0-beta.8"
|
||||
version = "3.0.0-beta.10"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"cfg-if",
|
||||
@@ -3486,7 +3486,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "objdiff-wasm"
|
||||
version = "3.0.0-beta.8"
|
||||
version = "3.0.0-beta.10"
|
||||
dependencies = [
|
||||
"log",
|
||||
"objdiff-core",
|
||||
|
||||
+1
-1
@@ -14,7 +14,7 @@ strip = "debuginfo"
|
||||
codegen-units = 1
|
||||
|
||||
[workspace.package]
|
||||
version = "3.0.0-beta.8"
|
||||
version = "3.0.0-beta.10"
|
||||
authors = ["Luke Street <luke@street.dev>"]
|
||||
edition = "2024"
|
||||
license = "MIT OR Apache-2.0"
|
||||
|
||||
@@ -21,7 +21,7 @@ Supports:
|
||||
- MIPS (N64, PS1, PS2, PSP)
|
||||
- PowerPC (GameCube, Wii)
|
||||
- SuperH (Saturn, Dreamcast)
|
||||
- x86 (COFF only)
|
||||
- x86, x86_64 (PC)
|
||||
|
||||
See [Usage](#usage) for more information.
|
||||
|
||||
|
||||
@@ -570,6 +570,7 @@ impl FunctionDiffUi {
|
||||
DiffTextColor::Normal => Color::Gray,
|
||||
DiffTextColor::Dim => Color::DarkGray,
|
||||
DiffTextColor::Bright => Color::White,
|
||||
DiffTextColor::DataFlow => Color::LightCyan,
|
||||
DiffTextColor::Replace => Color::Cyan,
|
||||
DiffTextColor::Delete => Color::Red,
|
||||
DiffTextColor::Insert => Color::Green,
|
||||
|
||||
@@ -41,6 +41,7 @@ any-arch = [
|
||||
"dep:regex",
|
||||
"dep:similar",
|
||||
"dep:syn",
|
||||
"dep:encoding_rs"
|
||||
]
|
||||
bindings = [
|
||||
"dep:prost",
|
||||
@@ -171,10 +172,10 @@ notify-debouncer-full = { version = "0.5.0", optional = true }
|
||||
shell-escape = { version = "0.1", optional = true }
|
||||
tempfile = { version = "3.19", optional = true }
|
||||
time = { version = "0.3", optional = true }
|
||||
encoding_rs = "0.8.35"
|
||||
encoding_rs = { version = "0.8.35", optional = true }
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
winapi = { version = "0.3", optional = true }
|
||||
winapi = { version = "0.3", optional = true, features = ["winbase"] }
|
||||
|
||||
# For Linux static binaries, use rustls
|
||||
[target.'cfg(target_os = "linux")'.dependencies]
|
||||
|
||||
@@ -25,6 +25,20 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "analyzeDataFlow",
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"name": "(Experimental) Perform data flow analysis",
|
||||
"description": "Use data flow analysis to display known information about register contents where possible"
|
||||
},
|
||||
{
|
||||
"id": "showDataFlow",
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"name": "Show data flow",
|
||||
"description": "Show data flow analysis results in place of register name where present"
|
||||
},
|
||||
{
|
||||
"id": "spaceBetweenArgs",
|
||||
"type": "boolean",
|
||||
@@ -264,7 +278,8 @@
|
||||
"id": "ppc",
|
||||
"name": "PowerPC",
|
||||
"properties": [
|
||||
"ppc.calculatePoolRelocations"
|
||||
"ppc.calculatePoolRelocations",
|
||||
"analyzeDataFlow"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
use alloc::{borrow::Cow, boxed::Box, format, string::String, vec::Vec};
|
||||
use core::{ffi::CStr, fmt, fmt::Debug};
|
||||
use core::{
|
||||
ffi::CStr,
|
||||
fmt::{self, Debug},
|
||||
};
|
||||
|
||||
use anyhow::{Result, bail};
|
||||
use encoding_rs::SHIFT_JIS;
|
||||
@@ -11,8 +14,9 @@ use crate::{
|
||||
display::{ContextItem, HoverItem, InstructionPart},
|
||||
},
|
||||
obj::{
|
||||
InstructionArg, InstructionRef, Object, ParsedInstruction, Relocation, RelocationFlags,
|
||||
ResolvedInstructionRef, ResolvedSymbol, Section, Symbol, SymbolFlagSet, SymbolKind,
|
||||
FlowAnalysisResult, InstructionArg, InstructionRef, Object, ParsedInstruction, Relocation,
|
||||
RelocationFlags, ResolvedInstructionRef, ResolvedSymbol, Section, Symbol, SymbolFlagSet,
|
||||
SymbolKind,
|
||||
},
|
||||
util::ReallySigned,
|
||||
};
|
||||
@@ -31,6 +35,7 @@ pub mod superh;
|
||||
pub mod x86;
|
||||
|
||||
/// Represents the type of data associated with an instruction
|
||||
#[derive(PartialEq)]
|
||||
pub enum DataType {
|
||||
Int8,
|
||||
Int16,
|
||||
@@ -335,6 +340,17 @@ pub trait Arch: Send + Sync + Debug {
|
||||
Vec::new()
|
||||
}
|
||||
|
||||
// Perform detailed data flow analysis
|
||||
fn data_flow_analysis(
|
||||
&self,
|
||||
_obj: &Object,
|
||||
_symbol: &Symbol,
|
||||
_code: &[u8],
|
||||
_relocations: &[Relocation],
|
||||
) -> Option<Box<dyn FlowAnalysisResult>> {
|
||||
None
|
||||
}
|
||||
|
||||
fn implcit_addend(
|
||||
&self,
|
||||
file: &object::File<'_>,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,5 @@
|
||||
use alloc::{
|
||||
boxed::Box,
|
||||
collections::{BTreeMap, BTreeSet},
|
||||
string::{String, ToString},
|
||||
vec,
|
||||
@@ -18,11 +19,13 @@ use crate::{
|
||||
display::{ContextItem, HoverItem, HoverItemColor, InstructionPart, SymbolNavigationKind},
|
||||
},
|
||||
obj::{
|
||||
InstructionRef, Object, Relocation, RelocationFlags, ResolvedInstructionRef,
|
||||
ResolvedRelocation, Symbol, SymbolFlag, SymbolFlagSet,
|
||||
FlowAnalysisResult, InstructionRef, Object, Relocation, RelocationFlags,
|
||||
ResolvedInstructionRef, ResolvedRelocation, Symbol, SymbolFlag, SymbolFlagSet,
|
||||
},
|
||||
};
|
||||
|
||||
mod flow_analysis;
|
||||
|
||||
// Relative relocation, can be Simm, Offset or BranchDest
|
||||
fn is_relative_arg(arg: &ppc750cl::Argument) -> bool {
|
||||
matches!(
|
||||
@@ -157,6 +160,7 @@ impl Arch for ArchPpc {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Could be replaced by data_flow_analysis once that feature stabilizes
|
||||
fn generate_pooled_relocations(
|
||||
&self,
|
||||
address: u64,
|
||||
@@ -167,6 +171,16 @@ impl Arch for ArchPpc {
|
||||
generate_fake_pool_relocations_for_function(address, code, relocations, symbols)
|
||||
}
|
||||
|
||||
fn data_flow_analysis(
|
||||
&self,
|
||||
obj: &Object,
|
||||
symbol: &Symbol,
|
||||
code: &[u8],
|
||||
relocations: &[Relocation],
|
||||
) -> Option<Box<dyn FlowAnalysisResult>> {
|
||||
Some(flow_analysis::ppc_data_flow_analysis(obj, symbol, code, relocations))
|
||||
}
|
||||
|
||||
fn implcit_addend(
|
||||
&self,
|
||||
_file: &object::File<'_>,
|
||||
@@ -225,7 +239,7 @@ impl Arch for ArchPpc {
|
||||
return Some(DataType::String);
|
||||
}
|
||||
let opcode = ppc750cl::Opcode::from(resolved.ins_ref.opcode as u8);
|
||||
if let Some(ty) = guess_data_type_from_load_store_inst_op(opcode) {
|
||||
if let Some(ty) = flow_analysis::guess_data_type_from_load_store_inst_op(opcode) {
|
||||
// Numeric type.
|
||||
return Some(ty);
|
||||
}
|
||||
@@ -501,25 +515,6 @@ fn make_symbol_ref(symbol: &object::Symbol) -> Result<ExtabSymbolRef> {
|
||||
Ok(ExtabSymbolRef { original_index: symbol.index().0 - 1, name, demangled_name })
|
||||
}
|
||||
|
||||
fn guess_data_type_from_load_store_inst_op(inst_op: ppc750cl::Opcode) -> Option<DataType> {
|
||||
use ppc750cl::Opcode;
|
||||
match inst_op {
|
||||
Opcode::Lbz | Opcode::Lbzu | Opcode::Lbzux | Opcode::Lbzx => Some(DataType::Int8),
|
||||
Opcode::Lhz | Opcode::Lhzu | Opcode::Lhzux | Opcode::Lhzx => Some(DataType::Int16),
|
||||
Opcode::Lha | Opcode::Lhau | Opcode::Lhaux | Opcode::Lhax => Some(DataType::Int16),
|
||||
Opcode::Lwz | Opcode::Lwzu | Opcode::Lwzux | Opcode::Lwzx => Some(DataType::Int32),
|
||||
Opcode::Lfs | Opcode::Lfsu | Opcode::Lfsux | Opcode::Lfsx => Some(DataType::Float),
|
||||
Opcode::Lfd | Opcode::Lfdu | Opcode::Lfdux | Opcode::Lfdx => Some(DataType::Double),
|
||||
|
||||
Opcode::Stb | Opcode::Stbu | Opcode::Stbux | Opcode::Stbx => Some(DataType::Int8),
|
||||
Opcode::Sth | Opcode::Sthu | Opcode::Sthux | Opcode::Sthx => Some(DataType::Int16),
|
||||
Opcode::Stw | Opcode::Stwu | Opcode::Stwux | Opcode::Stwx => Some(DataType::Int32),
|
||||
Opcode::Stfs | Opcode::Stfsu | Opcode::Stfsux | Opcode::Stfsx => Some(DataType::Float),
|
||||
Opcode::Stfd | Opcode::Stfdu | Opcode::Stfdux | Opcode::Stfdx => Some(DataType::Double),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct PoolReference {
|
||||
addr_src_gpr: ppc750cl::GPR,
|
||||
@@ -536,7 +531,7 @@ fn get_pool_reference_for_inst(
|
||||
) -> Option<PoolReference> {
|
||||
use ppc750cl::{Argument, Opcode};
|
||||
let args = &simplified.args;
|
||||
if guess_data_type_from_load_store_inst_op(opcode).is_some() {
|
||||
if flow_analysis::guess_data_type_from_load_store_inst_op(opcode).is_some() {
|
||||
match (args[1], args[2]) {
|
||||
(Argument::Offset(offset), Argument::GPR(addr_src_gpr)) => {
|
||||
// e.g. lwz. Immediate offset.
|
||||
@@ -668,7 +663,7 @@ fn make_fake_pool_reloc(
|
||||
// and returns a Vec of "fake pool relocations" that simulate what a relocation for that instruction
|
||||
// would look like if data hadn't been pooled.
|
||||
// This method tries to follow the function's proper control flow. It keeps track of a queue of
|
||||
// states it hasn't traversed yet, where each state holds an instruction address and a HashMap of
|
||||
// states it hasn't traversed yet, where each state holds an instruction address and a map of
|
||||
// which registers hold which pool relocations at that point.
|
||||
// When a conditional or unconditional branch is encountered, the destination of the branch is added
|
||||
// to the queue. Conditional branches will traverse both the path where the branch is taken and the
|
||||
@@ -6,7 +6,7 @@ use iced_x86::{
|
||||
Decoder, DecoderOptions, DecoratorKind, FormatterOutput, FormatterTextKind, GasFormatter,
|
||||
Instruction, IntelFormatter, MasmFormatter, NasmFormatter, NumberKind, OpKind, Register,
|
||||
};
|
||||
use object::{Endian as _, Object as _, ObjectSection as _, pe};
|
||||
use object::{Endian as _, Object as _, ObjectSection as _, elf, pe};
|
||||
|
||||
use crate::{
|
||||
arch::Arch,
|
||||
@@ -67,7 +67,11 @@ impl ArchX86 {
|
||||
pe::IMAGE_REL_I386_DIR32 | pe::IMAGE_REL_I386_REL32 => Some(4),
|
||||
_ => None,
|
||||
},
|
||||
_ => None,
|
||||
RelocationFlags::Elf(typ) => match typ {
|
||||
elf::R_386_32 | elf::R_386_PC32 => Some(4),
|
||||
elf::R_386_16 => Some(2),
|
||||
_ => None,
|
||||
},
|
||||
},
|
||||
Architecture::X86_64 => match flags {
|
||||
RelocationFlags::Coff(typ) => match typ {
|
||||
@@ -75,7 +79,11 @@ impl ArchX86 {
|
||||
pe::IMAGE_REL_AMD64_ADDR64 => Some(8),
|
||||
_ => None,
|
||||
},
|
||||
_ => None,
|
||||
RelocationFlags::Elf(typ) => match typ {
|
||||
elf::R_X86_64_PC32 => Some(4),
|
||||
elf::R_X86_64_64 => Some(8),
|
||||
_ => None,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -227,7 +235,8 @@ impl Arch for ArchX86 {
|
||||
) -> Result<i64> {
|
||||
match self.arch {
|
||||
Architecture::X86 => match flags {
|
||||
RelocationFlags::Coff(pe::IMAGE_REL_I386_DIR32 | pe::IMAGE_REL_I386_REL32) => {
|
||||
RelocationFlags::Coff(pe::IMAGE_REL_I386_DIR32 | pe::IMAGE_REL_I386_REL32)
|
||||
| RelocationFlags::Elf(elf::R_386_32 | elf::R_386_PC32) => {
|
||||
let data =
|
||||
section.data()?[address as usize..address as usize + 4].try_into()?;
|
||||
Ok(self.endianness.read_i32_bytes(data) as i64)
|
||||
@@ -235,12 +244,14 @@ impl Arch for ArchX86 {
|
||||
flags => bail!("Unsupported x86 implicit relocation {flags:?}"),
|
||||
},
|
||||
Architecture::X86_64 => match flags {
|
||||
RelocationFlags::Coff(pe::IMAGE_REL_AMD64_ADDR32NB | pe::IMAGE_REL_AMD64_REL32) => {
|
||||
RelocationFlags::Coff(pe::IMAGE_REL_AMD64_ADDR32NB | pe::IMAGE_REL_AMD64_REL32)
|
||||
| RelocationFlags::Elf(elf::R_X86_64_32 | elf::R_X86_64_PC32) => {
|
||||
let data =
|
||||
section.data()?[address as usize..address as usize + 4].try_into()?;
|
||||
Ok(self.endianness.read_i32_bytes(data) as i64)
|
||||
}
|
||||
RelocationFlags::Coff(pe::IMAGE_REL_AMD64_ADDR64) => {
|
||||
RelocationFlags::Coff(pe::IMAGE_REL_AMD64_ADDR64)
|
||||
| RelocationFlags::Elf(elf::R_X86_64_64) => {
|
||||
let data =
|
||||
section.data()?[address as usize..address as usize + 8].try_into()?;
|
||||
Ok(self.endianness.read_i64_bytes(data))
|
||||
|
||||
@@ -325,12 +325,11 @@ fn reloc_eq(
|
||||
|| display_ins_data_literals(left_obj, left_ins)
|
||||
== display_ins_data_literals(right_obj, right_ins))
|
||||
}
|
||||
(Some(_), None) => false,
|
||||
(None, Some(_)) => {
|
||||
// Match if possibly stripped weak symbol
|
||||
symbol_name_addend_matches && right_reloc.symbol.flags.contains(SymbolFlag::Weak)
|
||||
}
|
||||
(None, None) => symbol_name_addend_matches,
|
||||
(Some(_), None) | (None, None) => symbol_name_addend_matches,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -53,12 +53,11 @@ fn reloc_eq(
|
||||
section_name_eq(left_obj, right_obj, sl, sr)
|
||||
&& (symbol_name_addend_matches || address_eq(left, right))
|
||||
}
|
||||
(Some(_), None) => false,
|
||||
(None, Some(_)) => {
|
||||
// Match if possibly stripped weak symbol
|
||||
symbol_name_addend_matches && right.symbol.flags.contains(SymbolFlag::Weak)
|
||||
}
|
||||
(None, None) => symbol_name_addend_matches,
|
||||
(Some(_), None) | (None, None) => symbol_name_addend_matches,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,8 +14,9 @@ use regex::Regex;
|
||||
use crate::{
|
||||
diff::{DiffObjConfig, InstructionDiffKind, InstructionDiffRow, ObjectDiff, SymbolDiff},
|
||||
obj::{
|
||||
InstructionArg, InstructionArgValue, Object, ParsedInstruction, ResolvedInstructionRef,
|
||||
ResolvedRelocation, SectionFlag, SectionKind, Symbol, SymbolFlag, SymbolKind,
|
||||
FlowAnalysisValue, InstructionArg, InstructionArgValue, Object, ParsedInstruction,
|
||||
ResolvedInstructionRef, ResolvedRelocation, SectionFlag, SectionKind, Symbol, SymbolFlag,
|
||||
SymbolKind,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -47,11 +48,12 @@ pub enum DiffText<'a> {
|
||||
pub enum DiffTextColor {
|
||||
#[default]
|
||||
Normal, // Grey
|
||||
Dim, // Dark grey
|
||||
Bright, // White
|
||||
Replace, // Blue
|
||||
Delete, // Red
|
||||
Insert, // Green
|
||||
Dim, // Dark grey
|
||||
Bright, // White
|
||||
DataFlow, // Light blue
|
||||
Replace, // Blue
|
||||
Delete, // Red
|
||||
Insert, // Green
|
||||
Rotating(u8),
|
||||
}
|
||||
|
||||
@@ -186,6 +188,11 @@ pub fn display_row(
|
||||
}
|
||||
let mut arg_idx = 0;
|
||||
let mut displayed_relocation = false;
|
||||
let analysis_result = if diff_config.show_data_flow {
|
||||
obj.flow_analysis_results.get(&resolved.symbol.address)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
obj.arch.display_instruction(resolved, diff_config, &mut |part| match part {
|
||||
InstructionPart::Basic(text) => {
|
||||
if text.chars().all(|c| c == ' ') {
|
||||
@@ -208,15 +215,30 @@ pub fn display_row(
|
||||
if arg == InstructionArg::Reloc {
|
||||
displayed_relocation = true;
|
||||
}
|
||||
match (arg, resolved.ins_ref.branch_dest) {
|
||||
(InstructionArg::Value(value), _) => cb(DiffTextSegment {
|
||||
text: DiffText::Argument(value),
|
||||
color: diff_index
|
||||
let data_flow_value =
|
||||
analysis_result.and_then(|result|
|
||||
result.as_ref().get_argument_value_at_address(
|
||||
ins_ref.address, (arg_idx - 1) as u8));
|
||||
match (arg, data_flow_value, resolved.ins_ref.branch_dest) {
|
||||
// If we have a flow analysis result, always use that over anything else.
|
||||
(InstructionArg::Value(_) | InstructionArg::Reloc, Some(FlowAnalysisValue::Text(text)), _) => {
|
||||
cb(DiffTextSegment {
|
||||
text: DiffText::Argument(InstructionArgValue::Opaque(Cow::Borrowed(text))),
|
||||
color: DiffTextColor::DataFlow,
|
||||
pad_to: 0,
|
||||
})
|
||||
},
|
||||
(InstructionArg::Value(value), None, _) => {
|
||||
let color = diff_index
|
||||
.get()
|
||||
.map_or(base_color, |i| DiffTextColor::Rotating(i as u8)),
|
||||
pad_to: 0,
|
||||
}),
|
||||
(InstructionArg::Reloc, None) => {
|
||||
.map_or(base_color, |i| DiffTextColor::Rotating(i as u8));
|
||||
cb(DiffTextSegment {
|
||||
text: DiffText::Argument(value),
|
||||
color,
|
||||
pad_to: 0,
|
||||
})
|
||||
},
|
||||
(InstructionArg::Reloc, _, None) => {
|
||||
let resolved = resolved.relocation.unwrap();
|
||||
let color = diff_index
|
||||
.get()
|
||||
@@ -235,9 +257,9 @@ pub fn display_row(
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
(InstructionArg::BranchDest(dest), _) |
|
||||
(InstructionArg::BranchDest(dest), _, _) |
|
||||
// If the relocation was resolved to a branch destination, emit that instead.
|
||||
(InstructionArg::Reloc, Some(dest)) => {
|
||||
(InstructionArg::Reloc, _, Some(dest)) => {
|
||||
if let Some(addr) = dest.checked_sub(resolved.symbol.address) {
|
||||
cb(DiffTextSegment {
|
||||
text: DiffText::BranchDest(addr),
|
||||
|
||||
@@ -233,6 +233,19 @@ pub enum SymbolKind {
|
||||
Section,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum FlowAnalysisValue {
|
||||
Text(String),
|
||||
}
|
||||
|
||||
pub trait FlowAnalysisResult: core::fmt::Debug + Send {
|
||||
fn get_argument_value_at_address(
|
||||
&self,
|
||||
address: u64,
|
||||
argument: u8,
|
||||
) -> Option<&FlowAnalysisValue>;
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Hash, Default)]
|
||||
pub struct Symbol {
|
||||
pub name: String,
|
||||
@@ -260,6 +273,7 @@ pub struct Object {
|
||||
pub path: Option<std::path::PathBuf>,
|
||||
#[cfg(feature = "std")]
|
||||
pub timestamp: Option<filetime::FileTime>,
|
||||
pub flow_analysis_results: BTreeMap<u64, Box<dyn FlowAnalysisResult>>,
|
||||
}
|
||||
|
||||
impl Default for Object {
|
||||
@@ -274,6 +288,7 @@ impl Default for Object {
|
||||
path: None,
|
||||
#[cfg(feature = "std")]
|
||||
timestamp: None,
|
||||
flow_analysis_results: BTreeMap::<u64, Box<dyn FlowAnalysisResult>>::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -312,6 +327,8 @@ impl Object {
|
||||
pub fn symbol_by_name(&self, name: &str) -> Option<usize> {
|
||||
self.symbols.iter().position(|symbol| symbol.section.is_some() && symbol.name == name)
|
||||
}
|
||||
|
||||
pub fn has_flow_analysis_result(&self) -> bool { !self.flow_analysis_results.is_empty() }
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
|
||||
|
||||
@@ -432,17 +432,18 @@ fn map_relocations(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn calculate_pooled_relocations(
|
||||
arch: &dyn Arch,
|
||||
sections: &mut [Section],
|
||||
symbols: &[Symbol],
|
||||
) -> Result<()> {
|
||||
for (section_index, section) in sections.iter_mut().enumerate() {
|
||||
fn perform_data_flow_analysis(obj: &mut Object, config: &DiffObjConfig) -> Result<()> {
|
||||
// If neither of these settings are on, no flow analysis to perform
|
||||
if !config.analyze_data_flow && !config.ppc_calculate_pool_relocations {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let mut generated_relocations = Vec::<(usize, Vec<Relocation>)>::new();
|
||||
for (section_index, section) in obj.sections.iter().enumerate() {
|
||||
if section.kind != SectionKind::Code {
|
||||
continue;
|
||||
}
|
||||
let mut fake_pool_relocs = Vec::new();
|
||||
for symbol in symbols {
|
||||
for symbol in obj.symbols.iter() {
|
||||
if symbol.section != Some(section_index) {
|
||||
continue;
|
||||
}
|
||||
@@ -457,14 +458,32 @@ fn calculate_pooled_relocations(
|
||||
symbol.address + symbol.size
|
||||
)
|
||||
})?;
|
||||
fake_pool_relocs.append(&mut arch.generate_pooled_relocations(
|
||||
symbol.address,
|
||||
code,
|
||||
§ion.relocations,
|
||||
symbols,
|
||||
));
|
||||
|
||||
// Optional pooled relocation computation
|
||||
// Long view: This could be replaced by the full data flow analysis
|
||||
// once that feature has stabilized.
|
||||
if config.ppc_calculate_pool_relocations {
|
||||
let relocations = obj.arch.generate_pooled_relocations(
|
||||
symbol.address,
|
||||
code,
|
||||
§ion.relocations,
|
||||
&obj.symbols,
|
||||
);
|
||||
generated_relocations.push((section_index, relocations));
|
||||
}
|
||||
|
||||
// Optional full data flow analysis
|
||||
if config.analyze_data_flow {
|
||||
obj.arch.data_flow_analysis(obj, symbol, code, §ion.relocations).and_then(
|
||||
|flow_result| obj.flow_analysis_results.insert(symbol.address, flow_result),
|
||||
);
|
||||
}
|
||||
}
|
||||
section.relocations.append(&mut fake_pool_relocs);
|
||||
}
|
||||
for (section_index, mut relocations) in generated_relocations {
|
||||
obj.sections[section_index].relocations.append(&mut relocations);
|
||||
}
|
||||
for section in obj.sections.iter_mut() {
|
||||
section.relocations.sort_by_key(|r| r.address);
|
||||
}
|
||||
Ok(())
|
||||
@@ -865,15 +884,12 @@ pub fn parse(data: &[u8], config: &DiffObjConfig) -> Result<Object> {
|
||||
let (mut symbols, symbol_indices) =
|
||||
map_symbols(arch.as_ref(), &obj_file, §ions, §ion_indices, split_meta.as_ref())?;
|
||||
map_relocations(arch.as_ref(), &obj_file, &mut sections, §ion_indices, &symbol_indices)?;
|
||||
if config.ppc_calculate_pool_relocations {
|
||||
calculate_pooled_relocations(arch.as_ref(), &mut sections, &symbols)?;
|
||||
}
|
||||
parse_line_info(&obj_file, &mut sections, §ion_indices, data)?;
|
||||
if config.combine_data_sections || config.combine_text_sections {
|
||||
combine_sections(&mut sections, &mut symbols, config)?;
|
||||
}
|
||||
arch.post_init(§ions, &symbols);
|
||||
Ok(Object {
|
||||
let mut obj = Object {
|
||||
arch,
|
||||
endianness: obj_file.endianness(),
|
||||
symbols,
|
||||
@@ -883,7 +899,14 @@ pub fn parse(data: &[u8], config: &DiffObjConfig) -> Result<Object> {
|
||||
path: None,
|
||||
#[cfg(feature = "std")]
|
||||
timestamp: None,
|
||||
})
|
||||
flow_analysis_results: Default::default(),
|
||||
};
|
||||
|
||||
// Need to construct the obj first so that we have a convinient package to
|
||||
// pass to flow analysis. Then the flow analysis will mutate obj adding
|
||||
// additional data to it.
|
||||
perform_data_flow_analysis(&mut obj, config)?;
|
||||
Ok(obj)
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
|
||||
@@ -59,3 +59,33 @@ pub fn align_u64_to(len: u64, align: u64) -> u64 { len + ((align - (len % align)
|
||||
pub fn align_data_slice_to(data: &mut Vec<u8>, align: u64) {
|
||||
data.resize(align_u64_to(data.len() as u64, align) as usize, 0);
|
||||
}
|
||||
|
||||
// Float where we specifically care about comparing the raw bits rather than
|
||||
// caring about IEEE semantics.
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct RawFloat(pub f32);
|
||||
impl PartialEq for RawFloat {
|
||||
fn eq(&self, other: &Self) -> bool { self.0.to_bits() == other.0.to_bits() }
|
||||
}
|
||||
impl Eq for RawFloat {}
|
||||
impl Ord for RawFloat {
|
||||
fn cmp(&self, other: &Self) -> core::cmp::Ordering { self.0.to_bits().cmp(&other.0.to_bits()) }
|
||||
}
|
||||
impl PartialOrd for RawFloat {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> { Some(self.cmp(other)) }
|
||||
}
|
||||
|
||||
// Double where we specifically care about comparing the raw bits rather than
|
||||
// caring about IEEE semantics.
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub struct RawDouble(pub f64);
|
||||
impl PartialEq for RawDouble {
|
||||
fn eq(&self, other: &Self) -> bool { self.0.to_bits() == other.0.to_bits() }
|
||||
}
|
||||
impl Eq for RawDouble {}
|
||||
impl Ord for RawDouble {
|
||||
fn cmp(&self, other: &Self) -> core::cmp::Ordering { self.0.to_bits().cmp(&other.0.to_bits()) }
|
||||
}
|
||||
impl PartialOrd for RawDouble {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> { Some(self.cmp(other)) }
|
||||
}
|
||||
|
||||
@@ -1954,4 +1954,5 @@ Object {
|
||||
split_meta: None,
|
||||
path: None,
|
||||
timestamp: None,
|
||||
flow_analysis_results: {},
|
||||
}
|
||||
|
||||
@@ -3826,4 +3826,5 @@ Object {
|
||||
split_meta: None,
|
||||
path: None,
|
||||
timestamp: None,
|
||||
flow_analysis_results: {},
|
||||
}
|
||||
|
||||
@@ -1490,4 +1490,5 @@ Object {
|
||||
split_meta: None,
|
||||
path: None,
|
||||
timestamp: None,
|
||||
flow_analysis_results: {},
|
||||
}
|
||||
|
||||
@@ -548,4 +548,5 @@ Object {
|
||||
split_meta: None,
|
||||
path: None,
|
||||
timestamp: None,
|
||||
flow_analysis_results: {},
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user