mirror of https://github.com/encounter/objdiff.git
Update ppc750cl, add Itanium demangler & cleanup
This commit is contained in:
parent
e7991cb28d
commit
30d14870ef
|
@ -29,9 +29,17 @@ jobs:
|
||||||
uses: dtolnay/rust-toolchain@stable
|
uses: dtolnay/rust-toolchain@stable
|
||||||
with:
|
with:
|
||||||
components: clippy
|
components: clippy
|
||||||
|
- name: Setup sccache
|
||||||
|
uses: mozilla-actions/sccache-action@v0.0.4
|
||||||
- name: Cargo check
|
- name: Cargo check
|
||||||
|
env:
|
||||||
|
RUSTC_WRAPPER: sccache
|
||||||
|
SCCACHE_GHA_ENABLED: "true"
|
||||||
run: cargo check
|
run: cargo check
|
||||||
- name: Cargo clippy
|
- name: Cargo clippy
|
||||||
|
env:
|
||||||
|
RUSTC_WRAPPER: sccache
|
||||||
|
SCCACHE_GHA_ENABLED: "true"
|
||||||
run: cargo clippy
|
run: cargo clippy
|
||||||
|
|
||||||
fmt:
|
fmt:
|
||||||
|
@ -84,7 +92,12 @@ jobs:
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
- name: Setup Rust toolchain
|
- name: Setup Rust toolchain
|
||||||
uses: dtolnay/rust-toolchain@stable
|
uses: dtolnay/rust-toolchain@stable
|
||||||
|
- name: Setup sccache
|
||||||
|
uses: mozilla-actions/sccache-action@v0.0.4
|
||||||
- name: Cargo test
|
- name: Cargo test
|
||||||
|
env:
|
||||||
|
RUSTC_WRAPPER: sccache
|
||||||
|
SCCACHE_GHA_ENABLED: "true"
|
||||||
run: cargo test --release
|
run: cargo test --release
|
||||||
|
|
||||||
build:
|
build:
|
||||||
|
@ -117,18 +130,18 @@ jobs:
|
||||||
run: |
|
run: |
|
||||||
sudo apt-get update
|
sudo apt-get update
|
||||||
sudo apt-get -y install ${{ matrix.packages }}
|
sudo apt-get -y install ${{ matrix.packages }}
|
||||||
- name: Run sccache-cache
|
|
||||||
uses: mozilla-actions/sccache-action@v0.0.4
|
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
- name: Setup Rust toolchain
|
- name: Setup Rust toolchain
|
||||||
uses: dtolnay/rust-toolchain@stable
|
uses: dtolnay/rust-toolchain@stable
|
||||||
with:
|
with:
|
||||||
targets: ${{ matrix.target }}
|
targets: ${{ matrix.target }}
|
||||||
|
- name: Setup sccache
|
||||||
|
uses: mozilla-actions/sccache-action@v0.0.4
|
||||||
- name: Cargo build
|
- name: Cargo build
|
||||||
env:
|
env:
|
||||||
|
RUSTC_WRAPPER: sccache
|
||||||
SCCACHE_GHA_ENABLED: "true"
|
SCCACHE_GHA_ENABLED: "true"
|
||||||
RUSTC_WRAPPER: "sccache"
|
|
||||||
run: >
|
run: >
|
||||||
cargo build --profile ${{ env.BUILD_PROFILE }} --target ${{ matrix.target }}
|
cargo build --profile ${{ env.BUILD_PROFILE }} --target ${{ matrix.target }}
|
||||||
--bin objdiff-cli --bin objdiff --features ${{ matrix.features }}
|
--bin objdiff-cli --bin objdiff --features ${{ matrix.features }}
|
||||||
|
|
|
@ -1054,6 +1054,15 @@ dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cpp_demangle"
|
||||||
|
version = "0.4.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7e8227005286ec39567949b33df9896bcadfa6051bccca2488129f108ca23119"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cpufeatures"
|
name = "cpufeatures"
|
||||||
version = "0.2.12"
|
version = "0.2.12"
|
||||||
|
@ -3013,7 +3022,6 @@ dependencies = [
|
||||||
"argp",
|
"argp",
|
||||||
"crossterm",
|
"crossterm",
|
||||||
"enable-ansi-support",
|
"enable-ansi-support",
|
||||||
"log",
|
|
||||||
"objdiff-core",
|
"objdiff-core",
|
||||||
"ratatui",
|
"ratatui",
|
||||||
"rayon",
|
"rayon",
|
||||||
|
@ -3022,7 +3030,6 @@ dependencies = [
|
||||||
"supports-color",
|
"supports-color",
|
||||||
"time",
|
"time",
|
||||||
"tracing",
|
"tracing",
|
||||||
"tracing-attributes",
|
|
||||||
"tracing-subscriber",
|
"tracing-subscriber",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -3032,6 +3039,7 @@ version = "1.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"byteorder",
|
"byteorder",
|
||||||
|
"cpp_demangle",
|
||||||
"cwdemangle",
|
"cwdemangle",
|
||||||
"filetime",
|
"filetime",
|
||||||
"flagset",
|
"flagset",
|
||||||
|
@ -3081,15 +3089,11 @@ dependencies = [
|
||||||
"rfd",
|
"rfd",
|
||||||
"ron",
|
"ron",
|
||||||
"self_update",
|
"self_update",
|
||||||
"semver",
|
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"serde_yaml",
|
|
||||||
"shell-escape",
|
"shell-escape",
|
||||||
"tempfile",
|
"tempfile",
|
||||||
"thiserror",
|
|
||||||
"time",
|
"time",
|
||||||
"toml 0.8.11",
|
|
||||||
"tracing-subscriber",
|
"tracing-subscriber",
|
||||||
"tracing-wasm",
|
"tracing-wasm",
|
||||||
"vergen",
|
"vergen",
|
||||||
|
@ -3363,12 +3367,8 @@ checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ppc750cl"
|
name = "ppc750cl"
|
||||||
version = "0.2.0"
|
version = "0.3.0"
|
||||||
source = "git+https://github.com/encounter/ppc750cl?rev=4a2bbbc6f84dcb76255ab6f3595a8d4a0ce96618#4a2bbbc6f84dcb76255ab6f3595a8d4a0ce96618"
|
source = "git+https://github.com/encounter/ppc750cl?rev=d31bf75009e4efc102fc2b3b33fb7cd041859942#d31bf75009e4efc102fc2b3b33fb7cd041859942"
|
||||||
dependencies = [
|
|
||||||
"num-traits",
|
|
||||||
"serde",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ppv-lite86"
|
name = "ppv-lite86"
|
||||||
|
@ -3970,15 +3970,6 @@ dependencies = [
|
||||||
"syn 2.0.52",
|
"syn 2.0.52",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "serde_spanned"
|
|
||||||
version = "0.6.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1"
|
|
||||||
dependencies = [
|
|
||||||
"serde",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_urlencoded"
|
name = "serde_urlencoded"
|
||||||
version = "0.7.1"
|
version = "0.7.1"
|
||||||
|
@ -4466,26 +4457,11 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "toml"
|
|
||||||
version = "0.8.11"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "af06656561d28735e9c1cd63dfd57132c8155426aa6af24f36a00a351f88c48e"
|
|
||||||
dependencies = [
|
|
||||||
"serde",
|
|
||||||
"serde_spanned",
|
|
||||||
"toml_datetime",
|
|
||||||
"toml_edit 0.22.7",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "toml_datetime"
|
name = "toml_datetime"
|
||||||
version = "0.6.5"
|
version = "0.6.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1"
|
checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1"
|
||||||
dependencies = [
|
|
||||||
"serde",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "toml_edit"
|
name = "toml_edit"
|
||||||
|
@ -4495,7 +4471,7 @@ checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"indexmap",
|
"indexmap",
|
||||||
"toml_datetime",
|
"toml_datetime",
|
||||||
"winnow 0.5.40",
|
"winnow",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -4506,20 +4482,7 @@ checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"indexmap",
|
"indexmap",
|
||||||
"toml_datetime",
|
"toml_datetime",
|
||||||
"winnow 0.5.40",
|
"winnow",
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "toml_edit"
|
|
||||||
version = "0.22.7"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "18769cd1cec395d70860ceb4d932812a0b4d06b1a4bb336745a4d21b9496e992"
|
|
||||||
dependencies = [
|
|
||||||
"indexmap",
|
|
||||||
"serde",
|
|
||||||
"serde_spanned",
|
|
||||||
"toml_datetime",
|
|
||||||
"winnow 0.6.2",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -5460,15 +5423,6 @@ dependencies = [
|
||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "winnow"
|
|
||||||
version = "0.6.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "7a4191c47f15cc3ec71fcb4913cb83d58def65dd3787610213c649283b5ce178"
|
|
||||||
dependencies = [
|
|
||||||
"memchr",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winreg"
|
name = "winreg"
|
||||||
version = "0.50.0"
|
version = "0.50.0"
|
||||||
|
@ -5485,7 +5439,7 @@ version = "0.1.12"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b68db261ef59e9e52806f688020631e987592bd83619edccda9c47d42cde4f6c"
|
checksum = "b68db261ef59e9e52806f688020631e987592bd83619edccda9c47d42cde4f6c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"toml 0.5.11",
|
"toml",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
|
@ -18,7 +18,6 @@ anyhow = "1.0.81"
|
||||||
argp = "0.3.0"
|
argp = "0.3.0"
|
||||||
crossterm = "0.27.0"
|
crossterm = "0.27.0"
|
||||||
enable-ansi-support = "0.2.1"
|
enable-ansi-support = "0.2.1"
|
||||||
log = "0.4.21"
|
|
||||||
objdiff-core = { path = "../objdiff-core", features = ["all"] }
|
objdiff-core = { path = "../objdiff-core", features = ["all"] }
|
||||||
ratatui = "0.26.1"
|
ratatui = "0.26.1"
|
||||||
rayon = "1.9.0"
|
rayon = "1.9.0"
|
||||||
|
@ -27,5 +26,4 @@ serde_json = "1.0.114"
|
||||||
supports-color = "3.0.0"
|
supports-color = "3.0.0"
|
||||||
time = { version = "0.3.34", features = ["formatting", "local-offset"] }
|
time = { version = "0.3.34", features = ["formatting", "local-offset"] }
|
||||||
tracing = "0.1.40"
|
tracing = "0.1.40"
|
||||||
tracing-attributes = "0.1.27"
|
|
||||||
tracing-subscriber = { version = "0.3.18", features = ["env-filter"] }
|
tracing-subscriber = { version = "0.3.18", features = ["env-filter"] }
|
||||||
|
|
|
@ -14,6 +14,7 @@ use objdiff_core::{
|
||||||
obj::{ObjSectionKind, ObjSymbolFlags},
|
obj::{ObjSectionKind, ObjSymbolFlags},
|
||||||
};
|
};
|
||||||
use rayon::iter::{IntoParallelRefMutIterator, ParallelIterator};
|
use rayon::iter::{IntoParallelRefMutIterator, ParallelIterator};
|
||||||
|
use tracing::{info, warn};
|
||||||
|
|
||||||
#[derive(FromArgs, PartialEq, Debug)]
|
#[derive(FromArgs, PartialEq, Debug)]
|
||||||
/// Commands for processing NVIDIA Shield TV alf files.
|
/// Commands for processing NVIDIA Shield TV alf files.
|
||||||
|
@ -114,13 +115,13 @@ pub fn run(args: Args) -> Result<()> {
|
||||||
|
|
||||||
fn generate(args: GenerateArgs) -> Result<()> {
|
fn generate(args: GenerateArgs) -> Result<()> {
|
||||||
let project_dir = args.project.as_deref().unwrap_or_else(|| Path::new("."));
|
let project_dir = args.project.as_deref().unwrap_or_else(|| Path::new("."));
|
||||||
log::info!("Loading project {}", project_dir.display());
|
info!("Loading project {}", project_dir.display());
|
||||||
|
|
||||||
let config = objdiff_core::config::try_project_config(project_dir);
|
let config = objdiff_core::config::try_project_config(project_dir);
|
||||||
let Some((Ok(mut project), _)) = config else {
|
let Some((Ok(mut project), _)) = config else {
|
||||||
bail!("No project configuration found");
|
bail!("No project configuration found");
|
||||||
};
|
};
|
||||||
log::info!(
|
info!(
|
||||||
"Generating report for {} units (using {} threads)",
|
"Generating report for {} units (using {} threads)",
|
||||||
project.objects.len(),
|
project.objects.len(),
|
||||||
if args.deduplicate { 1 } else { rayon::current_num_threads() }
|
if args.deduplicate { 1 } else { rayon::current_num_threads() }
|
||||||
|
@ -181,9 +182,9 @@ fn generate(args: GenerateArgs) -> Result<()> {
|
||||||
report.matched_functions as f32 / report.total_functions as f32 * 100.0
|
report.matched_functions as f32 / report.total_functions as f32 * 100.0
|
||||||
};
|
};
|
||||||
let duration = start.elapsed();
|
let duration = start.elapsed();
|
||||||
log::info!("Report generated in {}.{:03}s", duration.as_secs(), duration.subsec_millis());
|
info!("Report generated in {}.{:03}s", duration.as_secs(), duration.subsec_millis());
|
||||||
if let Some(output) = &args.output {
|
if let Some(output) = &args.output {
|
||||||
log::info!("Writing to {}", output.display());
|
info!("Writing to {}", output.display());
|
||||||
let mut output = BufWriter::new(
|
let mut output = BufWriter::new(
|
||||||
File::create(output)
|
File::create(output)
|
||||||
.with_context(|| format!("Failed to create file {}", output.display()))?,
|
.with_context(|| format!("Failed to create file {}", output.display()))?,
|
||||||
|
@ -206,11 +207,11 @@ fn report_object(
|
||||||
object.resolve_paths(project_dir, target_dir, base_dir);
|
object.resolve_paths(project_dir, target_dir, base_dir);
|
||||||
match (&object.target_path, &object.base_path) {
|
match (&object.target_path, &object.base_path) {
|
||||||
(None, Some(_)) if object.complete != Some(true) => {
|
(None, Some(_)) if object.complete != Some(true) => {
|
||||||
log::warn!("Skipping object without target: {}", object.name());
|
warn!("Skipping object without target: {}", object.name());
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
(None, None) => {
|
(None, None) => {
|
||||||
log::warn!("Skipping object without target or base: {}", object.name());
|
warn!("Skipping object without target or base: {}", object.name());
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
|
@ -452,7 +453,7 @@ fn changes(args: ChangesArgs) -> Result<()> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(output) = &args.output {
|
if let Some(output) = &args.output {
|
||||||
log::info!("Writing to {}", output.display());
|
info!("Writing to {}", output.display());
|
||||||
let mut output = BufWriter::new(
|
let mut output = BufWriter::new(
|
||||||
File::create(output)
|
File::create(output)
|
||||||
.with_context(|| format!("Failed to create file {}", output.display()))?,
|
.with_context(|| format!("Failed to create file {}", output.display()))?,
|
||||||
|
|
|
@ -18,7 +18,7 @@ config = ["globset", "semver", "serde_json", "serde_yaml"]
|
||||||
dwarf = ["gimli"]
|
dwarf = ["gimli"]
|
||||||
mips = ["any-arch", "rabbitizer"]
|
mips = ["any-arch", "rabbitizer"]
|
||||||
ppc = ["any-arch", "cwdemangle", "ppc750cl"]
|
ppc = ["any-arch", "cwdemangle", "ppc750cl"]
|
||||||
x86 = ["any-arch", "iced-x86", "msvc-demangler"]
|
x86 = ["any-arch", "cpp_demangle", "iced-x86", "msvc-demangler"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0.81"
|
anyhow = "1.0.81"
|
||||||
|
@ -43,15 +43,12 @@ gimli = { version = "0.28.1", default-features = false, features = ["read-all"],
|
||||||
|
|
||||||
# ppc
|
# ppc
|
||||||
cwdemangle = { version = "1.0.0", optional = true }
|
cwdemangle = { version = "1.0.0", optional = true }
|
||||||
ppc750cl = { git = "https://github.com/encounter/ppc750cl", rev = "4a2bbbc6f84dcb76255ab6f3595a8d4a0ce96618", optional = true }
|
ppc750cl = { git = "https://github.com/encounter/ppc750cl", rev = "d31bf75009e4efc102fc2b3b33fb7cd041859942", optional = true }
|
||||||
|
|
||||||
# mips
|
# mips
|
||||||
rabbitizer = { version = "1.9.2", optional = true }
|
rabbitizer = { version = "1.9.2", optional = true }
|
||||||
|
|
||||||
# x86
|
# x86
|
||||||
|
cpp_demangle = { version = "0.4.3", optional = true }
|
||||||
|
iced-x86 = { version = "1.21.0", default-features = false, features = ["std", "decoder", "intel", "gas", "masm", "nasm", "exhaustive_enums"], optional = true }
|
||||||
msvc-demangler = { version = "0.10.0", optional = true }
|
msvc-demangler = { version = "0.10.0", optional = true }
|
||||||
[dependencies.iced-x86]
|
|
||||||
version = "1.21.0"
|
|
||||||
default-features = false
|
|
||||||
features = ["std", "decoder", "intel", "gas", "masm", "nasm", "exhaustive_enums"]
|
|
||||||
optional = true
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use std::{borrow::Cow, collections::BTreeMap};
|
use std::borrow::Cow;
|
||||||
|
|
||||||
use anyhow::{bail, Result};
|
use anyhow::{bail, Result};
|
||||||
use object::{elf, Endian, Endianness, File, Object, Relocation, RelocationFlags};
|
use object::{elf, Endian, Endianness, File, Object, Relocation, RelocationFlags};
|
||||||
|
@ -7,7 +7,7 @@ use rabbitizer::{config, Abi, InstrCategory, Instruction, OperandType};
|
||||||
use crate::{
|
use crate::{
|
||||||
arch::{ObjArch, ProcessCodeResult},
|
arch::{ObjArch, ProcessCodeResult},
|
||||||
diff::DiffObjConfig,
|
diff::DiffObjConfig,
|
||||||
obj::{ObjIns, ObjInsArg, ObjInsArgValue, ObjReloc, ObjSection},
|
obj::{ObjInfo, ObjIns, ObjInsArg, ObjInsArgValue, ObjReloc, ObjSection, SymbolRef},
|
||||||
};
|
};
|
||||||
|
|
||||||
fn configure_rabbitizer() {
|
fn configure_rabbitizer() {
|
||||||
|
@ -21,27 +21,31 @@ pub struct ObjArchMips {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ObjArchMips {
|
impl ObjArchMips {
|
||||||
pub fn new(object: &File) -> Result<Self> { Ok(Self { endianness: object.endianness() }) }
|
pub fn new(object: &File) -> Result<Self> {
|
||||||
|
configure_rabbitizer();
|
||||||
|
Ok(Self { endianness: object.endianness() })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ObjArch for ObjArchMips {
|
impl ObjArch for ObjArchMips {
|
||||||
fn process_code(
|
fn process_code(
|
||||||
&self,
|
&self,
|
||||||
|
obj: &ObjInfo,
|
||||||
|
symbol_ref: SymbolRef,
|
||||||
config: &DiffObjConfig,
|
config: &DiffObjConfig,
|
||||||
data: &[u8],
|
|
||||||
start_address: u64,
|
|
||||||
relocs: &[ObjReloc],
|
|
||||||
line_info: &Option<BTreeMap<u64, u64>>,
|
|
||||||
) -> Result<ProcessCodeResult> {
|
) -> Result<ProcessCodeResult> {
|
||||||
configure_rabbitizer();
|
let (section, symbol) = obj.section_symbol(symbol_ref);
|
||||||
|
let code = §ion.data
|
||||||
|
[symbol.section_address as usize..(symbol.section_address + symbol.size) as usize];
|
||||||
|
|
||||||
let end_address = start_address + data.len() as u64;
|
let start_address = symbol.address;
|
||||||
let ins_count = data.len() / 4;
|
let end_address = symbol.address + symbol.size;
|
||||||
|
let ins_count = code.len() / 4;
|
||||||
let mut ops = Vec::<u16>::with_capacity(ins_count);
|
let mut ops = Vec::<u16>::with_capacity(ins_count);
|
||||||
let mut insts = Vec::<ObjIns>::with_capacity(ins_count);
|
let mut insts = Vec::<ObjIns>::with_capacity(ins_count);
|
||||||
let mut cur_addr = start_address as u32;
|
let mut cur_addr = start_address as u32;
|
||||||
for chunk in data.chunks_exact(4) {
|
for chunk in code.chunks_exact(4) {
|
||||||
let reloc = relocs.iter().find(|r| (r.address as u32 & !3) == cur_addr);
|
let reloc = section.relocations.iter().find(|r| (r.address as u32 & !3) == cur_addr);
|
||||||
let code = self.endianness.read_u32_bytes(chunk.try_into()?);
|
let code = self.endianness.read_u32_bytes(chunk.try_into()?);
|
||||||
let instruction = Instruction::new(code, cur_addr, InstrCategory::CPU);
|
let instruction = Instruction::new(code, cur_addr, InstrCategory::CPU);
|
||||||
|
|
||||||
|
@ -61,11 +65,7 @@ impl ObjArch for ObjArchMips {
|
||||||
let mut args = Vec::with_capacity(operands.len() + 1);
|
let mut args = Vec::with_capacity(operands.len() + 1);
|
||||||
for (idx, op) in operands.iter().enumerate() {
|
for (idx, op) in operands.iter().enumerate() {
|
||||||
if idx > 0 {
|
if idx > 0 {
|
||||||
if config.space_between_args {
|
args.push(ObjInsArg::PlainText(config.separator().into()));
|
||||||
args.push(ObjInsArg::PlainText(", ".to_string()));
|
|
||||||
} else {
|
|
||||||
args.push(ObjInsArg::PlainText(",".to_string()));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
match op {
|
match op {
|
||||||
|
@ -85,7 +85,7 @@ impl ObjArch for ObjArchMips {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
args.push(ObjInsArg::Arg(ObjInsArgValue::Opaque(
|
args.push(ObjInsArg::Arg(ObjInsArgValue::Opaque(
|
||||||
op.disassemble(&instruction, None),
|
op.disassemble(&instruction, None).into(),
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -94,23 +94,24 @@ impl ObjArch for ObjArchMips {
|
||||||
push_reloc(&mut args, reloc)?;
|
push_reloc(&mut args, reloc)?;
|
||||||
} else {
|
} else {
|
||||||
args.push(ObjInsArg::Arg(ObjInsArgValue::Opaque(
|
args.push(ObjInsArg::Arg(ObjInsArgValue::Opaque(
|
||||||
OperandType::cpu_immediate.disassemble(&instruction, None),
|
OperandType::cpu_immediate.disassemble(&instruction, None).into(),
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
args.push(ObjInsArg::PlainText("(".to_string()));
|
args.push(ObjInsArg::PlainText("(".into()));
|
||||||
args.push(ObjInsArg::Arg(ObjInsArgValue::Opaque(
|
args.push(ObjInsArg::Arg(ObjInsArgValue::Opaque(
|
||||||
OperandType::cpu_rs.disassemble(&instruction, None),
|
OperandType::cpu_rs.disassemble(&instruction, None).into(),
|
||||||
)));
|
)));
|
||||||
args.push(ObjInsArg::PlainText(")".to_string()));
|
args.push(ObjInsArg::PlainText(")".into()));
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
args.push(ObjInsArg::Arg(ObjInsArgValue::Opaque(
|
args.push(ObjInsArg::Arg(ObjInsArgValue::Opaque(
|
||||||
op.disassemble(&instruction, None),
|
op.disassemble(&instruction, None).into(),
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let line = line_info
|
let line = obj
|
||||||
|
.line_info
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.and_then(|map| map.range(..=cur_addr as u64).last().map(|(_, &b)| b));
|
.and_then(|map| map.range(..=cur_addr as u64).last().map(|(_, &b)| b));
|
||||||
insts.push(ObjIns {
|
insts.push(ObjIns {
|
||||||
|
@ -161,9 +162,9 @@ impl ObjArch for ObjArchMips {
|
||||||
elf::R_MIPS_GPREL16 => Cow::Borrowed("R_MIPS_GPREL16"),
|
elf::R_MIPS_GPREL16 => Cow::Borrowed("R_MIPS_GPREL16"),
|
||||||
elf::R_MIPS_32 => Cow::Borrowed("R_MIPS_32"),
|
elf::R_MIPS_32 => Cow::Borrowed("R_MIPS_32"),
|
||||||
elf::R_MIPS_26 => Cow::Borrowed("R_MIPS_26"),
|
elf::R_MIPS_26 => Cow::Borrowed("R_MIPS_26"),
|
||||||
_ => Cow::Owned(format!("<Elf {r_type:?}>")),
|
_ => Cow::Owned(format!("<{flags:?}>")),
|
||||||
},
|
},
|
||||||
flags => Cow::Owned(format!("<{flags:?}>")),
|
_ => Cow::Owned(format!("<{flags:?}>")),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -172,29 +173,29 @@ fn push_reloc(args: &mut Vec<ObjInsArg>, reloc: &ObjReloc) -> Result<()> {
|
||||||
match reloc.flags {
|
match reloc.flags {
|
||||||
RelocationFlags::Elf { r_type } => match r_type {
|
RelocationFlags::Elf { r_type } => match r_type {
|
||||||
elf::R_MIPS_HI16 => {
|
elf::R_MIPS_HI16 => {
|
||||||
args.push(ObjInsArg::PlainText("%hi(".to_string()));
|
args.push(ObjInsArg::PlainText("%hi(".into()));
|
||||||
args.push(ObjInsArg::Reloc);
|
args.push(ObjInsArg::Reloc);
|
||||||
args.push(ObjInsArg::PlainText(")".to_string()));
|
args.push(ObjInsArg::PlainText(")".into()));
|
||||||
}
|
}
|
||||||
elf::R_MIPS_LO16 => {
|
elf::R_MIPS_LO16 => {
|
||||||
args.push(ObjInsArg::PlainText("%lo(".to_string()));
|
args.push(ObjInsArg::PlainText("%lo(".into()));
|
||||||
args.push(ObjInsArg::Reloc);
|
args.push(ObjInsArg::Reloc);
|
||||||
args.push(ObjInsArg::PlainText(")".to_string()));
|
args.push(ObjInsArg::PlainText(")".into()));
|
||||||
}
|
}
|
||||||
elf::R_MIPS_GOT16 => {
|
elf::R_MIPS_GOT16 => {
|
||||||
args.push(ObjInsArg::PlainText("%got(".to_string()));
|
args.push(ObjInsArg::PlainText("%got(".into()));
|
||||||
args.push(ObjInsArg::Reloc);
|
args.push(ObjInsArg::Reloc);
|
||||||
args.push(ObjInsArg::PlainText(")".to_string()));
|
args.push(ObjInsArg::PlainText(")".into()));
|
||||||
}
|
}
|
||||||
elf::R_MIPS_CALL16 => {
|
elf::R_MIPS_CALL16 => {
|
||||||
args.push(ObjInsArg::PlainText("%call16(".to_string()));
|
args.push(ObjInsArg::PlainText("%call16(".into()));
|
||||||
args.push(ObjInsArg::Reloc);
|
args.push(ObjInsArg::Reloc);
|
||||||
args.push(ObjInsArg::PlainText(")".to_string()));
|
args.push(ObjInsArg::PlainText(")".into()));
|
||||||
}
|
}
|
||||||
elf::R_MIPS_GPREL16 => {
|
elf::R_MIPS_GPREL16 => {
|
||||||
args.push(ObjInsArg::PlainText("%gp_rel(".to_string()));
|
args.push(ObjInsArg::PlainText("%gp_rel(".into()));
|
||||||
args.push(ObjInsArg::Reloc);
|
args.push(ObjInsArg::Reloc);
|
||||||
args.push(ObjInsArg::PlainText(")".to_string()));
|
args.push(ObjInsArg::PlainText(")".into()));
|
||||||
}
|
}
|
||||||
elf::R_MIPS_32 | elf::R_MIPS_26 => {
|
elf::R_MIPS_32 | elf::R_MIPS_26 => {
|
||||||
args.push(ObjInsArg::Reloc);
|
args.push(ObjInsArg::Reloc);
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
use std::{borrow::Cow, collections::BTreeMap};
|
use std::borrow::Cow;
|
||||||
|
|
||||||
use anyhow::{bail, Result};
|
use anyhow::{bail, Result};
|
||||||
use object::{Architecture, Object, Relocation, RelocationFlags};
|
use object::{Architecture, Object, Relocation, RelocationFlags};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
diff::DiffObjConfig,
|
diff::DiffObjConfig,
|
||||||
obj::{ObjIns, ObjReloc, ObjSection},
|
obj::{ObjInfo, ObjIns, ObjSection, SymbolRef},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(feature = "mips")]
|
#[cfg(feature = "mips")]
|
||||||
|
@ -18,11 +18,9 @@ mod x86;
|
||||||
pub trait ObjArch: Send + Sync {
|
pub trait ObjArch: Send + Sync {
|
||||||
fn process_code(
|
fn process_code(
|
||||||
&self,
|
&self,
|
||||||
|
obj: &ObjInfo,
|
||||||
|
symbol_ref: SymbolRef,
|
||||||
config: &DiffObjConfig,
|
config: &DiffObjConfig,
|
||||||
data: &[u8],
|
|
||||||
address: u64,
|
|
||||||
relocs: &[ObjReloc],
|
|
||||||
line_info: &Option<BTreeMap<u64, u64>>,
|
|
||||||
) -> Result<ProcessCodeResult>;
|
) -> Result<ProcessCodeResult>;
|
||||||
|
|
||||||
fn implcit_addend(&self, section: &ObjSection, address: u64, reloc: &Relocation)
|
fn implcit_addend(&self, section: &ObjSection, address: u64, reloc: &Relocation)
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
use std::{borrow::Cow, collections::BTreeMap};
|
use std::borrow::Cow;
|
||||||
|
|
||||||
use anyhow::{bail, Result};
|
use anyhow::{bail, Result};
|
||||||
use object::{elf, File, Relocation, RelocationFlags};
|
use object::{elf, File, Relocation, RelocationFlags};
|
||||||
use ppc750cl::{disasm_iter, Argument, SimplifiedIns, GPR};
|
use ppc750cl::{Argument, GPR};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
arch::{ObjArch, ProcessCodeResult},
|
arch::{ObjArch, ProcessCodeResult},
|
||||||
diff::DiffObjConfig,
|
diff::DiffObjConfig,
|
||||||
obj::{ObjIns, ObjInsArg, ObjInsArgValue, ObjReloc, ObjSection},
|
obj::{ObjInfo, ObjIns, ObjInsArg, ObjInsArgValue, ObjReloc, ObjSection, SymbolRef},
|
||||||
};
|
};
|
||||||
|
|
||||||
// Relative relocation, can be Simm, Offset or BranchDest
|
// Relative relocation, can be Simm, Offset or BranchDest
|
||||||
|
@ -31,30 +31,37 @@ impl ObjArchPpc {
|
||||||
impl ObjArch for ObjArchPpc {
|
impl ObjArch for ObjArchPpc {
|
||||||
fn process_code(
|
fn process_code(
|
||||||
&self,
|
&self,
|
||||||
|
obj: &ObjInfo,
|
||||||
|
symbol_ref: SymbolRef,
|
||||||
config: &DiffObjConfig,
|
config: &DiffObjConfig,
|
||||||
data: &[u8],
|
|
||||||
address: u64,
|
|
||||||
relocs: &[ObjReloc],
|
|
||||||
line_info: &Option<BTreeMap<u64, u64>>,
|
|
||||||
) -> Result<ProcessCodeResult> {
|
) -> Result<ProcessCodeResult> {
|
||||||
let ins_count = data.len() / 4;
|
let (section, symbol) = obj.section_symbol(symbol_ref);
|
||||||
|
let code = §ion.data
|
||||||
|
[symbol.section_address as usize..(symbol.section_address + symbol.size) as usize];
|
||||||
|
|
||||||
|
let ins_count = code.len() / 4;
|
||||||
let mut ops = Vec::<u16>::with_capacity(ins_count);
|
let mut ops = Vec::<u16>::with_capacity(ins_count);
|
||||||
let mut insts = Vec::<ObjIns>::with_capacity(ins_count);
|
let mut insts = Vec::<ObjIns>::with_capacity(ins_count);
|
||||||
for mut ins in disasm_iter(data, address as u32) {
|
let mut cur_addr = symbol.address as u32;
|
||||||
let reloc = relocs.iter().find(|r| (r.address as u32 & !3) == ins.addr);
|
for chunk in code.chunks_exact(4) {
|
||||||
|
let mut code = u32::from_be_bytes(chunk.try_into()?);
|
||||||
|
let reloc = section.relocations.iter().find(|r| (r.address as u32 & !3) == cur_addr);
|
||||||
if let Some(reloc) = reloc {
|
if let Some(reloc) = reloc {
|
||||||
// Zero out relocations
|
// Zero out relocations
|
||||||
ins.code = match reloc.flags {
|
code = match reloc.flags {
|
||||||
RelocationFlags::Elf { r_type: elf::R_PPC_EMB_SDA21 } => ins.code & !0x1FFFFF,
|
RelocationFlags::Elf { r_type: elf::R_PPC_EMB_SDA21 } => code & !0x1FFFFF,
|
||||||
RelocationFlags::Elf { r_type: elf::R_PPC_REL24 } => ins.code & !0x3FFFFFC,
|
RelocationFlags::Elf { r_type: elf::R_PPC_REL24 } => code & !0x3FFFFFC,
|
||||||
RelocationFlags::Elf { r_type: elf::R_PPC_REL14 } => ins.code & !0xFFFC,
|
RelocationFlags::Elf { r_type: elf::R_PPC_REL14 } => code & !0xFFFC,
|
||||||
RelocationFlags::Elf {
|
RelocationFlags::Elf {
|
||||||
r_type: elf::R_PPC_ADDR16_HI | elf::R_PPC_ADDR16_HA | elf::R_PPC_ADDR16_LO,
|
r_type: elf::R_PPC_ADDR16_HI | elf::R_PPC_ADDR16_HA | elf::R_PPC_ADDR16_LO,
|
||||||
} => ins.code & !0xFFFF,
|
} => code & !0xFFFF,
|
||||||
_ => ins.code,
|
_ => code,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
let simplified = ins.clone().simplified();
|
|
||||||
|
let ins = ppc750cl::Ins::new(code);
|
||||||
|
let orig = ins.basic().to_string();
|
||||||
|
let simplified = ins.simplified();
|
||||||
|
|
||||||
let mut reloc_arg = None;
|
let mut reloc_arg = None;
|
||||||
if let Some(reloc) = reloc {
|
if let Some(reloc) = reloc {
|
||||||
|
@ -77,13 +84,9 @@ impl ObjArch for ObjArchPpc {
|
||||||
let mut args = vec![];
|
let mut args = vec![];
|
||||||
let mut branch_dest = None;
|
let mut branch_dest = None;
|
||||||
let mut writing_offset = false;
|
let mut writing_offset = false;
|
||||||
for (idx, arg) in simplified.args.iter().enumerate() {
|
for (idx, arg) in simplified.args_iter().enumerate() {
|
||||||
if idx > 0 && !writing_offset {
|
if idx > 0 && !writing_offset {
|
||||||
if config.space_between_args {
|
args.push(ObjInsArg::PlainText(config.separator().into()));
|
||||||
args.push(ObjInsArg::PlainText(", ".to_string()));
|
|
||||||
} else {
|
|
||||||
args.push(ObjInsArg::PlainText(",".to_string()));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if reloc_arg == Some(idx) {
|
if reloc_arg == Some(idx) {
|
||||||
|
@ -108,41 +111,45 @@ impl ObjArch for ObjArchPpc {
|
||||||
args.push(ObjInsArg::Arg(ObjInsArgValue::Signed(offset.0 as i64)));
|
args.push(ObjInsArg::Arg(ObjInsArgValue::Signed(offset.0 as i64)));
|
||||||
}
|
}
|
||||||
Argument::BranchDest(dest) => {
|
Argument::BranchDest(dest) => {
|
||||||
let dest = ins.addr.wrapping_add_signed(dest.0) as u64;
|
let dest = cur_addr.wrapping_add_signed(dest.0) as u64;
|
||||||
args.push(ObjInsArg::BranchDest(dest));
|
args.push(ObjInsArg::BranchDest(dest));
|
||||||
branch_dest = Some(dest);
|
branch_dest = Some(dest);
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
args.push(ObjInsArg::Arg(ObjInsArgValue::Opaque(arg.to_string())));
|
args.push(ObjInsArg::Arg(ObjInsArgValue::Opaque(
|
||||||
|
arg.to_string().into(),
|
||||||
|
)));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if writing_offset {
|
if writing_offset {
|
||||||
args.push(ObjInsArg::PlainText(")".to_string()));
|
args.push(ObjInsArg::PlainText(")".into()));
|
||||||
writing_offset = false;
|
writing_offset = false;
|
||||||
}
|
}
|
||||||
if is_offset_arg(arg) {
|
if is_offset_arg(arg) {
|
||||||
args.push(ObjInsArg::PlainText("(".to_string()));
|
args.push(ObjInsArg::PlainText("(".into()));
|
||||||
writing_offset = true;
|
writing_offset = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ops.push(simplified.ins.op as u16);
|
ops.push(ins.op as u16);
|
||||||
let line = line_info
|
let line = obj
|
||||||
|
.line_info
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.and_then(|map| map.range(..=simplified.ins.addr as u64).last().map(|(_, &b)| b));
|
.and_then(|map| map.range(..=cur_addr as u64).last().map(|(_, &b)| b));
|
||||||
insts.push(ObjIns {
|
insts.push(ObjIns {
|
||||||
address: simplified.ins.addr as u64,
|
address: cur_addr as u64,
|
||||||
size: 4,
|
size: 4,
|
||||||
mnemonic: format!("{}{}", simplified.mnemonic, simplified.suffix),
|
mnemonic: simplified.mnemonic.to_string(),
|
||||||
args,
|
args,
|
||||||
reloc: reloc.cloned(),
|
reloc: reloc.cloned(),
|
||||||
op: ins.op as u16,
|
op: ins.op as u16,
|
||||||
branch_dest,
|
branch_dest,
|
||||||
line,
|
line,
|
||||||
orig: Some(format!("{}", SimplifiedIns::basic_form(ins))),
|
orig: Some(orig),
|
||||||
});
|
});
|
||||||
|
cur_addr += 4;
|
||||||
}
|
}
|
||||||
Ok(ProcessCodeResult { ops, insts })
|
Ok(ProcessCodeResult { ops, insts })
|
||||||
}
|
}
|
||||||
|
@ -157,7 +164,7 @@ impl ObjArch for ObjArchPpc {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn demangle(&self, name: &str) -> Option<String> {
|
fn demangle(&self, name: &str) -> Option<String> {
|
||||||
cwdemangle::demangle(name, &Default::default())
|
cwdemangle::demangle(name, &cwdemangle::DemangleOptions::default())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn display_reloc(&self, flags: RelocationFlags) -> Cow<'static, str> {
|
fn display_reloc(&self, flags: RelocationFlags) -> Cow<'static, str> {
|
||||||
|
@ -171,9 +178,9 @@ impl ObjArch for ObjArchPpc {
|
||||||
elf::R_PPC_UADDR32 => Cow::Borrowed("R_PPC_UADDR32"),
|
elf::R_PPC_UADDR32 => Cow::Borrowed("R_PPC_UADDR32"),
|
||||||
elf::R_PPC_REL24 => Cow::Borrowed("R_PPC_REL24"),
|
elf::R_PPC_REL24 => Cow::Borrowed("R_PPC_REL24"),
|
||||||
elf::R_PPC_REL14 => Cow::Borrowed("R_PPC_REL14"),
|
elf::R_PPC_REL14 => Cow::Borrowed("R_PPC_REL14"),
|
||||||
_ => Cow::Owned(format!("<Elf {r_type:?}>")),
|
_ => Cow::Owned(format!("<{flags:?}>")),
|
||||||
},
|
},
|
||||||
flags => Cow::Owned(format!("<{flags:?}>")),
|
_ => Cow::Owned(format!("<{flags:?}>")),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -183,19 +190,19 @@ fn push_reloc(args: &mut Vec<ObjInsArg>, reloc: &ObjReloc) -> Result<()> {
|
||||||
RelocationFlags::Elf { r_type } => match r_type {
|
RelocationFlags::Elf { r_type } => match r_type {
|
||||||
elf::R_PPC_ADDR16_LO => {
|
elf::R_PPC_ADDR16_LO => {
|
||||||
args.push(ObjInsArg::Reloc);
|
args.push(ObjInsArg::Reloc);
|
||||||
args.push(ObjInsArg::PlainText("@l".to_string()));
|
args.push(ObjInsArg::PlainText("@l".into()));
|
||||||
}
|
}
|
||||||
elf::R_PPC_ADDR16_HI => {
|
elf::R_PPC_ADDR16_HI => {
|
||||||
args.push(ObjInsArg::Reloc);
|
args.push(ObjInsArg::Reloc);
|
||||||
args.push(ObjInsArg::PlainText("@h".to_string()));
|
args.push(ObjInsArg::PlainText("@h".into()));
|
||||||
}
|
}
|
||||||
elf::R_PPC_ADDR16_HA => {
|
elf::R_PPC_ADDR16_HA => {
|
||||||
args.push(ObjInsArg::Reloc);
|
args.push(ObjInsArg::Reloc);
|
||||||
args.push(ObjInsArg::PlainText("@ha".to_string()));
|
args.push(ObjInsArg::PlainText("@ha".into()));
|
||||||
}
|
}
|
||||||
elf::R_PPC_EMB_SDA21 => {
|
elf::R_PPC_EMB_SDA21 => {
|
||||||
args.push(ObjInsArg::Reloc);
|
args.push(ObjInsArg::Reloc);
|
||||||
args.push(ObjInsArg::PlainText("@sda21".to_string()));
|
args.push(ObjInsArg::PlainText("@sda21".into()));
|
||||||
}
|
}
|
||||||
elf::R_PPC_ADDR32 | elf::R_PPC_UADDR32 | elf::R_PPC_REL24 | elf::R_PPC_REL14 => {
|
elf::R_PPC_ADDR32 | elf::R_PPC_UADDR32 | elf::R_PPC_REL24 | elf::R_PPC_REL14 => {
|
||||||
args.push(ObjInsArg::Reloc);
|
args.push(ObjInsArg::Reloc);
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use std::{borrow::Cow, collections::BTreeMap};
|
use std::borrow::Cow;
|
||||||
|
|
||||||
use anyhow::{anyhow, bail, ensure, Result};
|
use anyhow::{anyhow, bail, ensure, Result};
|
||||||
use iced_x86::{
|
use iced_x86::{
|
||||||
|
@ -11,7 +11,7 @@ use object::{pe, Endian, Endianness, File, Object, Relocation, RelocationFlags};
|
||||||
use crate::{
|
use crate::{
|
||||||
arch::{ObjArch, ProcessCodeResult},
|
arch::{ObjArch, ProcessCodeResult},
|
||||||
diff::{DiffObjConfig, X86Formatter},
|
diff::{DiffObjConfig, X86Formatter},
|
||||||
obj::{ObjIns, ObjInsArg, ObjInsArgValue, ObjReloc, ObjSection},
|
obj::{ObjInfo, ObjIns, ObjInsArg, ObjInsArgValue, ObjSection, SymbolRef},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct ObjArchX86 {
|
pub struct ObjArchX86 {
|
||||||
|
@ -28,14 +28,16 @@ impl ObjArchX86 {
|
||||||
impl ObjArch for ObjArchX86 {
|
impl ObjArch for ObjArchX86 {
|
||||||
fn process_code(
|
fn process_code(
|
||||||
&self,
|
&self,
|
||||||
|
obj: &ObjInfo,
|
||||||
|
symbol_ref: SymbolRef,
|
||||||
config: &DiffObjConfig,
|
config: &DiffObjConfig,
|
||||||
data: &[u8],
|
|
||||||
start_address: u64,
|
|
||||||
relocs: &[ObjReloc],
|
|
||||||
line_info: &Option<BTreeMap<u64, u64>>,
|
|
||||||
) -> Result<ProcessCodeResult> {
|
) -> Result<ProcessCodeResult> {
|
||||||
|
let (section, symbol) = obj.section_symbol(symbol_ref);
|
||||||
|
let code = §ion.data
|
||||||
|
[symbol.section_address as usize..(symbol.section_address + symbol.size) as usize];
|
||||||
|
|
||||||
let mut result = ProcessCodeResult { ops: Vec::new(), insts: Vec::new() };
|
let mut result = ProcessCodeResult { ops: Vec::new(), insts: Vec::new() };
|
||||||
let mut decoder = Decoder::with_ip(self.bits, data, start_address, DecoderOptions::NONE);
|
let mut decoder = Decoder::with_ip(self.bits, code, symbol.address, DecoderOptions::NONE);
|
||||||
let mut formatter: Box<dyn Formatter> = match config.x86_formatter {
|
let mut formatter: Box<dyn Formatter> = match config.x86_formatter {
|
||||||
X86Formatter::Intel => Box::new(IntelFormatter::new()),
|
X86Formatter::Intel => Box::new(IntelFormatter::new()),
|
||||||
X86Formatter::Gas => Box::new(GasFormatter::new()),
|
X86Formatter::Gas => Box::new(GasFormatter::new()),
|
||||||
|
@ -66,7 +68,8 @@ impl ObjArch for ObjArchX86 {
|
||||||
|
|
||||||
let address = instruction.ip();
|
let address = instruction.ip();
|
||||||
let op = instruction.mnemonic() as u16;
|
let op = instruction.mnemonic() as u16;
|
||||||
let reloc = relocs
|
let reloc = section
|
||||||
|
.relocations
|
||||||
.iter()
|
.iter()
|
||||||
.find(|r| r.address >= address && r.address < address + instruction.len() as u64);
|
.find(|r| r.address >= address && r.address < address + instruction.len() as u64);
|
||||||
output.ins = ObjIns {
|
output.ins = ObjIns {
|
||||||
|
@ -77,7 +80,7 @@ impl ObjArch for ObjArchX86 {
|
||||||
args: vec![],
|
args: vec![],
|
||||||
reloc: reloc.cloned(),
|
reloc: reloc.cloned(),
|
||||||
branch_dest: None,
|
branch_dest: None,
|
||||||
line: line_info.as_ref().and_then(|m| m.get(&address).cloned()),
|
line: obj.line_info.as_ref().and_then(|m| m.get(&address).cloned()),
|
||||||
orig: None,
|
orig: None,
|
||||||
};
|
};
|
||||||
// Run the formatter, which will populate output.ins
|
// Run the formatter, which will populate output.ins
|
||||||
|
@ -141,7 +144,9 @@ impl ObjArch for ObjArchX86 {
|
||||||
if name.starts_with('?') {
|
if name.starts_with('?') {
|
||||||
msvc_demangler::demangle(name, msvc_demangler::DemangleFlags::llvm()).ok()
|
msvc_demangler::demangle(name, msvc_demangler::DemangleFlags::llvm()).ok()
|
||||||
} else {
|
} else {
|
||||||
None
|
cpp_demangle::Symbol::new(name)
|
||||||
|
.ok()
|
||||||
|
.and_then(|s| s.demangle(&cpp_demangle::DemangleOptions::default()).ok())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -150,9 +155,9 @@ impl ObjArch for ObjArchX86 {
|
||||||
RelocationFlags::Coff { typ } => match typ {
|
RelocationFlags::Coff { typ } => match typ {
|
||||||
pe::IMAGE_REL_I386_DIR32 => Cow::Borrowed("IMAGE_REL_I386_DIR32"),
|
pe::IMAGE_REL_I386_DIR32 => Cow::Borrowed("IMAGE_REL_I386_DIR32"),
|
||||||
pe::IMAGE_REL_I386_REL32 => Cow::Borrowed("IMAGE_REL_I386_REL32"),
|
pe::IMAGE_REL_I386_REL32 => Cow::Borrowed("IMAGE_REL_I386_REL32"),
|
||||||
_ => Cow::Owned(format!("<Coff {typ:?}>")),
|
_ => Cow::Owned(format!("<{flags:?}>")),
|
||||||
},
|
},
|
||||||
flags => Cow::Owned(format!("<{flags:?}>")),
|
_ => Cow::Owned(format!("<{flags:?}>")),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -214,10 +219,10 @@ impl FormatterOutput for InstructionFormatterOutput {
|
||||||
self.ins_operands.push(None);
|
self.ins_operands.push(None);
|
||||||
match kind {
|
match kind {
|
||||||
FormatterTextKind::Text | FormatterTextKind::Punctuation => {
|
FormatterTextKind::Text | FormatterTextKind::Punctuation => {
|
||||||
self.ins.args.push(ObjInsArg::PlainText(text.to_string()));
|
self.ins.args.push(ObjInsArg::PlainText(text.to_string().into()));
|
||||||
}
|
}
|
||||||
FormatterTextKind::Keyword | FormatterTextKind::Operator => {
|
FormatterTextKind::Keyword | FormatterTextKind::Operator => {
|
||||||
self.ins.args.push(ObjInsArg::Arg(ObjInsArgValue::Opaque(text.to_string())));
|
self.ins.args.push(ObjInsArg::Arg(ObjInsArgValue::Opaque(text.to_string().into())));
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
if self.error.is_none() {
|
if self.error.is_none() {
|
||||||
|
@ -230,7 +235,7 @@ impl FormatterOutput for InstructionFormatterOutput {
|
||||||
fn write_prefix(&mut self, _instruction: &Instruction, text: &str, _prefix: PrefixKind) {
|
fn write_prefix(&mut self, _instruction: &Instruction, text: &str, _prefix: PrefixKind) {
|
||||||
self.formatted.push_str(text);
|
self.formatted.push_str(text);
|
||||||
self.ins_operands.push(None);
|
self.ins_operands.push(None);
|
||||||
self.ins.args.push(ObjInsArg::Arg(ObjInsArgValue::Opaque(text.to_string())));
|
self.ins.args.push(ObjInsArg::Arg(ObjInsArgValue::Opaque(text.to_string().into())));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_mnemonic(&mut self, _instruction: &Instruction, text: &str) {
|
fn write_mnemonic(&mut self, _instruction: &Instruction, text: &str) {
|
||||||
|
@ -318,7 +323,7 @@ impl FormatterOutput for InstructionFormatterOutput {
|
||||||
) {
|
) {
|
||||||
self.formatted.push_str(text);
|
self.formatted.push_str(text);
|
||||||
self.ins_operands.push(instruction_operand);
|
self.ins_operands.push(instruction_operand);
|
||||||
self.ins.args.push(ObjInsArg::PlainText(text.to_string()));
|
self.ins.args.push(ObjInsArg::PlainText(text.to_string().into()));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_register(
|
fn write_register(
|
||||||
|
@ -331,6 +336,6 @@ impl FormatterOutput for InstructionFormatterOutput {
|
||||||
) {
|
) {
|
||||||
self.formatted.push_str(text);
|
self.formatted.push_str(text);
|
||||||
self.ins_operands.push(instruction_operand);
|
self.ins_operands.push(instruction_operand);
|
||||||
self.ins.args.push(ObjInsArg::Arg(ObjInsArgValue::Opaque(text.to_string())));
|
self.ins.args.push(ObjInsArg::Arg(ObjInsArgValue::Opaque(text.to_string().into())));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ use std::{
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
};
|
};
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::{anyhow, Context, Result};
|
||||||
use filetime::FileTime;
|
use filetime::FileTime;
|
||||||
use globset::{Glob, GlobSet, GlobSetBuilder};
|
use globset::{Glob, GlobSet, GlobSetBuilder};
|
||||||
|
|
||||||
|
@ -96,7 +96,7 @@ pub struct ScratchConfig {
|
||||||
pub build_ctx: bool,
|
pub build_ctx: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const CONFIG_FILENAMES: [&str; 3] = ["objdiff.yml", "objdiff.yaml", "objdiff.json"];
|
pub const CONFIG_FILENAMES: [&str; 3] = ["objdiff.json", "objdiff.yml", "objdiff.yaml"];
|
||||||
|
|
||||||
pub const DEFAULT_WATCH_PATTERNS: &[&str] = &[
|
pub const DEFAULT_WATCH_PATTERNS: &[&str] = &[
|
||||||
"*.c", "*.cp", "*.cpp", "*.cxx", "*.h", "*.hp", "*.hpp", "*.hxx", "*.s", "*.S", "*.asm",
|
"*.c", "*.cp", "*.cpp", "*.cxx", "*.h", "*.hp", "*.hpp", "*.hxx", "*.s", "*.S", "*.asm",
|
||||||
|
@ -121,16 +121,33 @@ pub fn try_project_config(dir: &Path) -> Option<(Result<ProjectConfig>, ProjectC
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let ts = FileTime::from_last_modification_time(&metadata);
|
let ts = FileTime::from_last_modification_time(&metadata);
|
||||||
let config = match filename.contains("json") {
|
let mut result = match filename.contains("json") {
|
||||||
true => read_json_config(&mut file),
|
true => read_json_config(&mut file),
|
||||||
false => read_yml_config(&mut file),
|
false => read_yml_config(&mut file),
|
||||||
};
|
};
|
||||||
return Some((config, ProjectConfigInfo { path: config_path, timestamp: ts }));
|
if let Ok(config) = &result {
|
||||||
|
// Validate min_version if present
|
||||||
|
if let Err(e) = validate_min_version(config) {
|
||||||
|
result = Err(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Some((result, ProjectConfigInfo { path: config_path, timestamp: ts }));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn validate_min_version(config: &ProjectConfig) -> Result<()> {
|
||||||
|
let Some(min_version) = &config.min_version else { return Ok(()) };
|
||||||
|
let version = semver::Version::parse(env!("CARGO_PKG_VERSION"))
|
||||||
|
.context("Failed to parse package version")?;
|
||||||
|
match semver::VersionReq::parse(&format!(">={min_version}")) {
|
||||||
|
Ok(version_req) if version_req.matches(&version) => Ok(()),
|
||||||
|
Ok(_) => Err(anyhow!("Project requires objdiff version {min_version} or higher")),
|
||||||
|
Err(e) => Err(anyhow::Error::new(e).context("Failed to parse min_version")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn read_yml_config<R: Read>(reader: &mut R) -> Result<ProjectConfig> {
|
fn read_yml_config<R: Read>(reader: &mut R) -> Result<ProjectConfig> {
|
||||||
Ok(serde_yaml::from_reader(reader)?)
|
Ok(serde_yaml::from_reader(reader)?)
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,16 +21,7 @@ pub fn no_diff_code(
|
||||||
symbol_ref: SymbolRef,
|
symbol_ref: SymbolRef,
|
||||||
config: &DiffObjConfig,
|
config: &DiffObjConfig,
|
||||||
) -> Result<ObjSymbolDiff> {
|
) -> Result<ObjSymbolDiff> {
|
||||||
let (section, symbol) = obj.section_symbol(symbol_ref);
|
let out = obj.arch.process_code(obj, symbol_ref, config)?;
|
||||||
let code = §ion.data
|
|
||||||
[symbol.section_address as usize..(symbol.section_address + symbol.size) as usize];
|
|
||||||
let out = obj.arch.process_code(
|
|
||||||
config,
|
|
||||||
code,
|
|
||||||
symbol.address,
|
|
||||||
§ion.relocations,
|
|
||||||
&obj.line_info,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
let mut diff = Vec::<ObjInsDiff>::new();
|
let mut diff = Vec::<ObjInsDiff>::new();
|
||||||
for i in out.insts {
|
for i in out.insts {
|
||||||
|
@ -47,26 +38,8 @@ pub fn diff_code(
|
||||||
right_symbol_ref: SymbolRef,
|
right_symbol_ref: SymbolRef,
|
||||||
config: &DiffObjConfig,
|
config: &DiffObjConfig,
|
||||||
) -> Result<(ObjSymbolDiff, ObjSymbolDiff)> {
|
) -> Result<(ObjSymbolDiff, ObjSymbolDiff)> {
|
||||||
let (left_section, left_symbol) = left_obj.section_symbol(left_symbol_ref);
|
let left_out = left_obj.arch.process_code(left_obj, left_symbol_ref, config)?;
|
||||||
let (right_section, right_symbol) = right_obj.section_symbol(right_symbol_ref);
|
let right_out = left_obj.arch.process_code(right_obj, right_symbol_ref, config)?;
|
||||||
let left_code = &left_section.data[left_symbol.section_address as usize
|
|
||||||
..(left_symbol.section_address + left_symbol.size) as usize];
|
|
||||||
let right_code = &right_section.data[right_symbol.section_address as usize
|
|
||||||
..(right_symbol.section_address + right_symbol.size) as usize];
|
|
||||||
let left_out = left_obj.arch.process_code(
|
|
||||||
config,
|
|
||||||
left_code,
|
|
||||||
left_symbol.address,
|
|
||||||
&left_section.relocations,
|
|
||||||
&left_obj.line_info,
|
|
||||||
)?;
|
|
||||||
let right_out = left_obj.arch.process_code(
|
|
||||||
config,
|
|
||||||
right_code,
|
|
||||||
right_symbol.address,
|
|
||||||
&right_section.relocations,
|
|
||||||
&right_obj.line_info,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
let mut left_diff = Vec::<ObjInsDiff>::new();
|
let mut left_diff = Vec::<ObjInsDiff>::new();
|
||||||
let mut right_diff = Vec::<ObjInsDiff>::new();
|
let mut right_diff = Vec::<ObjInsDiff>::new();
|
||||||
|
@ -312,7 +285,7 @@ fn compare_ins(
|
||||||
state.diff_count += 1;
|
state.diff_count += 1;
|
||||||
}
|
}
|
||||||
let a_str = match a {
|
let a_str = match a {
|
||||||
ObjInsArg::PlainText(arg) => arg.clone(),
|
ObjInsArg::PlainText(arg) => arg.to_string(),
|
||||||
ObjInsArg::Arg(arg) => arg.to_string(),
|
ObjInsArg::Arg(arg) => arg.to_string(),
|
||||||
ObjInsArg::Reloc => String::new(),
|
ObjInsArg::Reloc => String::new(),
|
||||||
ObjInsArg::BranchDest(arg) => format!("{arg}"),
|
ObjInsArg::BranchDest(arg) => format!("{arg}"),
|
||||||
|
@ -326,7 +299,7 @@ fn compare_ins(
|
||||||
ObjInsArgDiff { idx }
|
ObjInsArgDiff { idx }
|
||||||
};
|
};
|
||||||
let b_str = match b {
|
let b_str = match b {
|
||||||
ObjInsArg::PlainText(arg) => arg.clone(),
|
ObjInsArg::PlainText(arg) => arg.to_string(),
|
||||||
ObjInsArg::Arg(arg) => arg.to_string(),
|
ObjInsArg::Arg(arg) => arg.to_string(),
|
||||||
ObjInsArg::Reloc => String::new(),
|
ObjInsArg::Reloc => String::new(),
|
||||||
ObjInsArg::BranchDest(arg) => format!("{arg}"),
|
ObjInsArg::BranchDest(arg) => format!("{arg}"),
|
||||||
|
|
|
@ -31,6 +31,16 @@ pub struct DiffObjConfig {
|
||||||
pub x86_formatter: X86Formatter,
|
pub x86_formatter: X86Formatter,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl DiffObjConfig {
|
||||||
|
pub fn separator(&self) -> &'static str {
|
||||||
|
if self.space_between_args {
|
||||||
|
", "
|
||||||
|
} else {
|
||||||
|
","
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct ObjSectionDiff {
|
pub struct ObjSectionDiff {
|
||||||
pub symbols: Vec<ObjSymbolDiff>,
|
pub symbols: Vec<ObjSymbolDiff>,
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
pub mod read;
|
pub mod read;
|
||||||
pub mod split_meta;
|
pub mod split_meta;
|
||||||
|
|
||||||
use std::{collections::BTreeMap, fmt, path::PathBuf};
|
use std::{borrow::Cow, collections::BTreeMap, fmt, path::PathBuf};
|
||||||
|
|
||||||
use filetime::FileTime;
|
use filetime::FileTime;
|
||||||
use flagset::{flags, FlagSet};
|
use flagset::{flags, FlagSet};
|
||||||
|
@ -35,7 +35,7 @@ pub struct ObjSection {
|
||||||
pub address: u64,
|
pub address: u64,
|
||||||
pub size: u64,
|
pub size: u64,
|
||||||
pub data: Vec<u8>,
|
pub data: Vec<u8>,
|
||||||
pub index: usize,
|
pub orig_index: usize,
|
||||||
pub symbols: Vec<ObjSymbol>,
|
pub symbols: Vec<ObjSymbol>,
|
||||||
pub relocations: Vec<ObjReloc>,
|
pub relocations: Vec<ObjReloc>,
|
||||||
pub virtual_address: Option<u64>,
|
pub virtual_address: Option<u64>,
|
||||||
|
@ -45,7 +45,7 @@ pub struct ObjSection {
|
||||||
pub enum ObjInsArgValue {
|
pub enum ObjInsArgValue {
|
||||||
Signed(i64),
|
Signed(i64),
|
||||||
Unsigned(u64),
|
Unsigned(u64),
|
||||||
Opaque(String),
|
Opaque(Cow<'static, str>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ObjInsArgValue {
|
impl ObjInsArgValue {
|
||||||
|
@ -73,7 +73,7 @@ impl fmt::Display for ObjInsArgValue {
|
||||||
|
|
||||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||||
pub enum ObjInsArg {
|
pub enum ObjInsArg {
|
||||||
PlainText(String),
|
PlainText(Cow<'static, str>),
|
||||||
Arg(ObjInsArgValue),
|
Arg(ObjInsArgValue),
|
||||||
Reloc,
|
Reloc,
|
||||||
BranchDest(u64),
|
BranchDest(u64),
|
||||||
|
|
|
@ -107,7 +107,7 @@ fn filter_sections(obj_file: &File<'_>, split_meta: Option<&SplitMeta>) -> Resul
|
||||||
address: section.address(),
|
address: section.address(),
|
||||||
size: section.size(),
|
size: section.size(),
|
||||||
data: data.to_vec(),
|
data: data.to_vec(),
|
||||||
index: section.index().0,
|
orig_index: section.index().0,
|
||||||
symbols: Vec::new(),
|
symbols: Vec::new(),
|
||||||
relocations: Vec::new(),
|
relocations: Vec::new(),
|
||||||
virtual_address,
|
virtual_address,
|
||||||
|
@ -129,7 +129,7 @@ fn symbols_by_section(
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if let Some(index) = symbol.section().index() {
|
if let Some(index) = symbol.section().index() {
|
||||||
if index.0 == section.index {
|
if index.0 == section.orig_index {
|
||||||
if symbol.is_local() && section.kind == ObjSectionKind::Code {
|
if symbol.is_local() && section.kind == ObjSectionKind::Code {
|
||||||
// TODO strip local syms in diff?
|
// TODO strip local syms in diff?
|
||||||
let name = symbol.name().context("Failed to process symbol name")?;
|
let name = symbol.name().context("Failed to process symbol name")?;
|
||||||
|
@ -218,7 +218,7 @@ fn relocations_by_section(
|
||||||
section: &ObjSection,
|
section: &ObjSection,
|
||||||
split_meta: Option<&SplitMeta>,
|
split_meta: Option<&SplitMeta>,
|
||||||
) -> Result<Vec<ObjReloc>> {
|
) -> Result<Vec<ObjReloc>> {
|
||||||
let obj_section = obj_file.section_by_index(SectionIndex(section.index))?;
|
let obj_section = obj_file.section_by_index(SectionIndex(section.orig_index))?;
|
||||||
let mut relocations = Vec::<ObjReloc>::new();
|
let mut relocations = Vec::<ObjReloc>::new();
|
||||||
for (address, reloc) in obj_section.relocations() {
|
for (address, reloc) in obj_section.relocations() {
|
||||||
let symbol = match reloc.target() {
|
let symbol = match reloc.target() {
|
||||||
|
|
|
@ -43,15 +43,11 @@ png = "0.17.13"
|
||||||
pollster = "0.3.0"
|
pollster = "0.3.0"
|
||||||
rfd = { version = "0.14.0" } #, default-features = false, features = ['xdg-portal']
|
rfd = { version = "0.14.0" } #, default-features = false, features = ['xdg-portal']
|
||||||
ron = "0.8.1"
|
ron = "0.8.1"
|
||||||
semver = "1.0.22"
|
|
||||||
serde = { version = "1", features = ["derive"] }
|
serde = { version = "1", features = ["derive"] }
|
||||||
serde_json = "1.0.114"
|
serde_json = "1.0.114"
|
||||||
serde_yaml = "0.9.32"
|
|
||||||
shell-escape = "0.1.5"
|
shell-escape = "0.1.5"
|
||||||
tempfile = "3.10.1"
|
tempfile = "3.10.1"
|
||||||
thiserror = "1.0.58"
|
|
||||||
time = { version = "0.3.34", features = ["formatting", "local-offset"] }
|
time = { version = "0.3.34", features = ["formatting", "local-offset"] }
|
||||||
toml = "0.8.11"
|
|
||||||
|
|
||||||
# For Linux static binaries, use rustls
|
# For Linux static binaries, use rustls
|
||||||
[target.'cfg(target_os = "linux")'.dependencies]
|
[target.'cfg(target_os = "linux")'.dependencies]
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use std::path::{Component, Path};
|
use std::path::{Component, Path};
|
||||||
|
|
||||||
use anyhow::{ensure, Result};
|
use anyhow::Result;
|
||||||
use globset::Glob;
|
use globset::Glob;
|
||||||
use objdiff_core::config::{try_project_config, ProjectObject, DEFAULT_WATCH_PATTERNS};
|
use objdiff_core::config::{try_project_config, ProjectObject, DEFAULT_WATCH_PATTERNS};
|
||||||
|
|
||||||
|
@ -70,15 +70,6 @@ pub fn load_project_config(config: &mut AppConfig) -> Result<()> {
|
||||||
};
|
};
|
||||||
if let Some((result, info)) = try_project_config(project_dir) {
|
if let Some((result, info)) = try_project_config(project_dir) {
|
||||||
let project_config = result?;
|
let project_config = result?;
|
||||||
if let Some(min_version) = &project_config.min_version {
|
|
||||||
let version_str = env!("CARGO_PKG_VERSION");
|
|
||||||
let version = semver::Version::parse(version_str).unwrap();
|
|
||||||
let version_req = semver::VersionReq::parse(&format!(">={min_version}"))?;
|
|
||||||
ensure!(
|
|
||||||
version_req.matches(&version),
|
|
||||||
"Project requires objdiff version {min_version} or higher"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
config.custom_make = project_config.custom_make;
|
config.custom_make = project_config.custom_make;
|
||||||
config.target_obj_dir = project_config.target_dir.map(|p| project_dir.join(p));
|
config.target_obj_dir = project_config.target_dir.map(|p| project_dir.join(p));
|
||||||
config.base_obj_dir = project_config.base_dir.map(|p| project_dir.join(p));
|
config.base_obj_dir = project_config.base_dir.map(|p| project_dir.join(p));
|
||||||
|
|
|
@ -287,7 +287,7 @@ fn symbol_list_ui(
|
||||||
|
|
||||||
for (section, section_diff) in obj.0.sections.iter().zip(&obj.1.sections) {
|
for (section, section_diff) in obj.0.sections.iter().zip(&obj.1.sections) {
|
||||||
CollapsingHeader::new(format!("{} ({:x})", section.name, section.size))
|
CollapsingHeader::new(format!("{} ({:x})", section.name, section.size))
|
||||||
.id_source(Id::new(section.name.clone()).with(section.index))
|
.id_source(Id::new(section.name.clone()).with(section.orig_index))
|
||||||
.default_open(true)
|
.default_open(true)
|
||||||
.show(ui, |ui| {
|
.show(ui, |ui| {
|
||||||
if section.kind == ObjSectionKind::Code && state.reverse_fn_order {
|
if section.kind == ObjSectionKind::Code && state.reverse_fn_order {
|
||||||
|
|
Loading…
Reference in New Issue