mirror of
https://github.com/encounter/objdiff.git
synced 2026-07-10 12:18:36 -07:00
Compare commits
37 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a015971c20 | |||
| e67d5998b3 | |||
| 91bc23edfc | |||
| c9c3b32376 | |||
| 0dc123b064 | |||
| 1e62d4664c | |||
| 1205e8ceb4 | |||
| c917cad5f0 | |||
| dd653329f5 | |||
| f5d3d5f10a | |||
| c327ed3ea8 | |||
| 85fb18a21a | |||
| 00ad0d8094 | |||
| 8fac63c42c | |||
| 0fb7f3901c | |||
| 3385f58341 | |||
| 60b227f45e | |||
| 127ae5ae44 | |||
| 5f48e69775 | |||
| 8756eee07b | |||
| bd3ed0d5ad | |||
| e638d0b17a | |||
| f58616b6dd | |||
| e9762e24c2 | |||
| dab79d96a1 | |||
| a57e5db983 | |||
| d0afd3b83e | |||
| a367af612b | |||
| 22052ea10b | |||
| f7c3501eae | |||
| 07ef93f16a | |||
| 8e8ab6bef8 | |||
| e865f3d598 | |||
| 2b13e9886a | |||
| 1750af736a | |||
| 731b604c24 | |||
| 2d643eb071 |
+4
-5
@@ -1,5 +1,4 @@
|
||||
[target.x86_64-pc-windows-msvc]
|
||||
linker = "rust-lld"
|
||||
|
||||
[target.aarch64-pc-windows-msvc]
|
||||
linker = "rust-lld"
|
||||
# statically link the C runtime so the executable does not depend on
|
||||
# that shared/dynamic library.
|
||||
[target.'cfg(all(target_env = "msvc", target_os = "windows"))']
|
||||
rustflags = ["-C", "target-feature=+crt-static"]
|
||||
|
||||
Generated
+804
-671
File diff suppressed because it is too large
Load Diff
+2
-2
@@ -14,9 +14,9 @@ strip = "debuginfo"
|
||||
codegen-units = 1
|
||||
|
||||
[workspace.package]
|
||||
version = "3.0.0-beta.7"
|
||||
version = "3.0.0-beta.13"
|
||||
authors = ["Luke Street <luke@street.dev>"]
|
||||
edition = "2024"
|
||||
license = "MIT OR Apache-2.0"
|
||||
repository = "https://github.com/encounter/objdiff"
|
||||
rust-version = "1.85"
|
||||
rust-version = "1.88"
|
||||
|
||||
@@ -19,9 +19,9 @@ Supports:
|
||||
- ARM (GBA, DS, 3DS)
|
||||
- ARM64 (Switch)
|
||||
- MIPS (N64, PS1, PS2, PSP)
|
||||
- PowerPC (GameCube, Wii)
|
||||
- PowerPC (GameCube, Wii, PS3, Xbox 360)
|
||||
- SuperH (Saturn, Dreamcast)
|
||||
- x86 (COFF only)
|
||||
- x86, x86_64 (PC)
|
||||
|
||||
See [Usage](#usage) for more information.
|
||||
|
||||
|
||||
@@ -175,6 +175,10 @@
|
||||
"type": "boolean",
|
||||
"description": "If true, objdiff will run the build command with the context file as an argument to generate it.",
|
||||
"default": false
|
||||
},
|
||||
"preset_id": {
|
||||
"type": "number",
|
||||
"description": "The decomp.me preset ID to use for the scratch.\nCompiler and flags in the config will take precedence over the preset, but the preset is useful for organizational purposes."
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
|
||||
@@ -15,11 +15,11 @@ publish = false
|
||||
[dependencies]
|
||||
anyhow = "1.0"
|
||||
argp = "0.4"
|
||||
crossterm = "0.28"
|
||||
crossterm = "0.29"
|
||||
enable-ansi-support = "0.2"
|
||||
memmap2 = "0.9"
|
||||
objdiff-core = { path = "../objdiff-core", features = ["all"] }
|
||||
prost = "0.13"
|
||||
prost = "0.14"
|
||||
ratatui = "0.29"
|
||||
rayon = "1.10"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
|
||||
@@ -203,14 +203,10 @@ fn run_oneshot(
|
||||
let output_format = OutputFormat::from_option(args.format.as_deref())?;
|
||||
let (diff_config, mapping_config) = build_config_from_args(args)?;
|
||||
let target = target_path
|
||||
.map(|p| {
|
||||
obj::read::read(p.as_ref(), &diff_config).with_context(|| format!("Loading {}", p))
|
||||
})
|
||||
.map(|p| obj::read::read(p.as_ref(), &diff_config).with_context(|| format!("Loading {p}")))
|
||||
.transpose()?;
|
||||
let base = base_path
|
||||
.map(|p| {
|
||||
obj::read::read(p.as_ref(), &diff_config).with_context(|| format!("Loading {}", p))
|
||||
})
|
||||
.map(|p| obj::read::read(p.as_ref(), &diff_config).with_context(|| format!("Loading {p}")))
|
||||
.transpose()?;
|
||||
let result =
|
||||
diff::diff_objs(target.as_ref(), base.as_ref(), None, &diff_config, &mapping_config)?;
|
||||
@@ -399,7 +395,7 @@ fn run_interactive(
|
||||
stdout(),
|
||||
EnterAlternateScreen,
|
||||
EnableMouseCapture,
|
||||
SetTitle(format!("{} - objdiff", symbol_name)),
|
||||
SetTitle(format!("{symbol_name} - objdiff")),
|
||||
)?;
|
||||
let backend = CrosstermBackend::new(stdout());
|
||||
let mut terminal = Terminal::new(backend)?;
|
||||
|
||||
@@ -177,16 +177,14 @@ fn report_object(
|
||||
.target_path
|
||||
.as_ref()
|
||||
.map(|p| {
|
||||
obj::read::read(p.as_ref(), diff_config)
|
||||
.with_context(|| format!("Failed to open {}", p))
|
||||
obj::read::read(p.as_ref(), diff_config).with_context(|| format!("Failed to open {p}"))
|
||||
})
|
||||
.transpose()?;
|
||||
let base = object
|
||||
.base_path
|
||||
.as_ref()
|
||||
.map(|p| {
|
||||
obj::read::read(p.as_ref(), diff_config)
|
||||
.with_context(|| format!("Failed to open {}", p))
|
||||
obj::read::read(p.as_ref(), diff_config).with_context(|| format!("Failed to open {p}"))
|
||||
})
|
||||
.transpose()?;
|
||||
let result =
|
||||
@@ -245,16 +243,17 @@ fn report_object(
|
||||
for (symbol, symbol_diff) in obj.symbols.iter().zip(&obj_diff.symbols) {
|
||||
if symbol.section != Some(section_idx)
|
||||
|| symbol.size == 0
|
||||
|| symbol.flags.contains(SymbolFlag::Hidden | SymbolFlag::Ignored)
|
||||
|| symbol.flags.contains(SymbolFlag::Hidden)
|
||||
|| symbol.flags.contains(SymbolFlag::Ignored)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if let Some(existing_functions) = &mut existing_functions {
|
||||
if symbol.flags.contains(SymbolFlag::Global | SymbolFlag::Weak)
|
||||
&& !existing_functions.insert(symbol.name.clone())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if let Some(existing_functions) = &mut existing_functions
|
||||
&& (symbol.flags.contains(SymbolFlag::Global)
|
||||
|| symbol.flags.contains(SymbolFlag::Weak))
|
||||
&& !existing_functions.insert(symbol.name.clone())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
let match_percent = symbol_diff.match_percent.unwrap_or_else(|| {
|
||||
// Support cases where we don't have a target object,
|
||||
@@ -431,8 +430,8 @@ fn read_report(path: &Utf8PlatformPath) -> Result<Report> {
|
||||
std::io::stdin().read_to_end(&mut data)?;
|
||||
return Report::parse(&data).with_context(|| "Failed to load report from stdin");
|
||||
}
|
||||
let file = File::open(path).with_context(|| format!("Failed to open {}", path))?;
|
||||
let file = File::open(path).with_context(|| format!("Failed to open {path}"))?;
|
||||
let mmap =
|
||||
unsafe { memmap2::Mmap::map(&file) }.with_context(|| format!("Failed to map {}", path))?;
|
||||
Report::parse(mmap.as_ref()).with_context(|| format!("Failed to load report {}", path))
|
||||
unsafe { memmap2::Mmap::map(&file) }.with_context(|| format!("Failed to map {path}"))?;
|
||||
Report::parse(mmap.as_ref()).with_context(|| format!("Failed to load report {path}"))
|
||||
}
|
||||
|
||||
@@ -87,7 +87,7 @@ impl UiView for FunctionDiffUi {
|
||||
.and_then(|(_, _, d)| d.match_percent)
|
||||
{
|
||||
line_r.spans.push(Span::styled(
|
||||
format!("{:.2}% ", percent),
|
||||
format!("{percent:.2}% "),
|
||||
Style::new().fg(match_percent_color(percent)),
|
||||
));
|
||||
}
|
||||
@@ -97,7 +97,7 @@ impl UiView for FunctionDiffUi {
|
||||
.and_then(|t| t.format(&state.time_format).ok())
|
||||
.unwrap_or_else(|| "N/A".to_string());
|
||||
line_r.spans.push(Span::styled(
|
||||
format!("Last reload: {}", reload_time),
|
||||
format!("Last reload: {reload_time}"),
|
||||
Style::new().fg(Color::White),
|
||||
));
|
||||
line_r.spans.push(Span::styled(
|
||||
@@ -170,32 +170,31 @@ impl UiView for FunctionDiffUi {
|
||||
|
||||
let mut prev_text = None;
|
||||
let mut prev_margin_text = None;
|
||||
if self.three_way {
|
||||
if let Some((obj, symbol_idx, symbol_diff)) =
|
||||
if self.three_way
|
||||
&& let Some((obj, symbol_idx, symbol_diff)) =
|
||||
get_symbol(state.prev_obj.as_ref(), self.prev_sym)
|
||||
{
|
||||
let mut text = Text::default();
|
||||
let rect = content_chunks[4].inner(Margin::new(0, 1));
|
||||
self.print_sym(
|
||||
&mut text,
|
||||
obj,
|
||||
symbol_idx,
|
||||
symbol_diff,
|
||||
&state.diff_obj_config,
|
||||
rect,
|
||||
&self.right_highlight,
|
||||
result,
|
||||
true,
|
||||
);
|
||||
max_width = max_width.max(text.width());
|
||||
prev_text = Some(text);
|
||||
{
|
||||
let mut text = Text::default();
|
||||
let rect = content_chunks[4].inner(Margin::new(0, 1));
|
||||
self.print_sym(
|
||||
&mut text,
|
||||
obj,
|
||||
symbol_idx,
|
||||
symbol_diff,
|
||||
&state.diff_obj_config,
|
||||
rect,
|
||||
&self.right_highlight,
|
||||
result,
|
||||
true,
|
||||
);
|
||||
max_width = max_width.max(text.width());
|
||||
prev_text = Some(text);
|
||||
|
||||
// Render margin
|
||||
let mut text = Text::default();
|
||||
let rect = content_chunks[3].inner(Margin::new(1, 1));
|
||||
self.print_margin(&mut text, symbol_diff, rect);
|
||||
prev_margin_text = Some(text);
|
||||
}
|
||||
// Render margin
|
||||
let mut text = Text::default();
|
||||
let rect = content_chunks[3].inner(Margin::new(1, 1));
|
||||
self.print_margin(&mut text, symbol_diff, rect);
|
||||
prev_margin_text = Some(text);
|
||||
}
|
||||
|
||||
let max_scroll_x =
|
||||
@@ -450,11 +449,11 @@ impl UiView for FunctionDiffUi {
|
||||
|
||||
fn reload(&mut self, state: &AppState) -> Result<()> {
|
||||
let left_sym =
|
||||
state.left_obj.as_ref().and_then(|(o, _)| find_function(o, &self.symbol_name));
|
||||
state.left_obj.as_ref().and_then(|(o, _)| o.symbol_by_name(&self.symbol_name));
|
||||
let right_sym =
|
||||
state.right_obj.as_ref().and_then(|(o, _)| find_function(o, &self.symbol_name));
|
||||
state.right_obj.as_ref().and_then(|(o, _)| o.symbol_by_name(&self.symbol_name));
|
||||
let prev_sym =
|
||||
state.prev_obj.as_ref().and_then(|(o, _)| find_function(o, &self.symbol_name));
|
||||
state.prev_obj.as_ref().and_then(|(o, _)| o.symbol_by_name(&self.symbol_name));
|
||||
self.num_rows = match (
|
||||
get_symbol(state.left_obj.as_ref(), left_sym),
|
||||
get_symbol(state.right_obj.as_ref(), right_sym),
|
||||
@@ -538,7 +537,7 @@ impl FunctionDiffUi {
|
||||
let label_text = match segment.text {
|
||||
DiffText::Basic(text) => text.to_string(),
|
||||
DiffText::Line(num) => format!("{num} "),
|
||||
DiffText::Address(addr) => format!("{:x}:", addr),
|
||||
DiffText::Address(addr) => format!("{addr:x}:"),
|
||||
DiffText::Opcode(mnemonic, _op) => format!("{mnemonic} "),
|
||||
DiffText::Argument(arg) => arg.to_string(),
|
||||
DiffText::BranchDest(addr) => format!("{addr:x}"),
|
||||
@@ -546,7 +545,7 @@ impl FunctionDiffUi {
|
||||
sym.demangled_name.as_ref().unwrap_or(&sym.name).clone()
|
||||
}
|
||||
DiffText::Addend(addend) => match addend.cmp(&0i64) {
|
||||
Ordering::Greater => format!("+{:#x}", addend),
|
||||
Ordering::Greater => format!("+{addend:#x}"),
|
||||
Ordering::Less => format!("-{:#x}", -addend),
|
||||
_ => String::new(),
|
||||
},
|
||||
@@ -561,15 +560,18 @@ impl FunctionDiffUi {
|
||||
let len = label_text.len();
|
||||
let highlighted =
|
||||
highlight_kind != HighlightKind::None && *highlight == highlight_kind;
|
||||
if let Some((cx, cy)) = result.click_xy {
|
||||
if cx >= sx && cx < sx + len as u16 && cy == sy {
|
||||
new_highlight = Some(highlight_kind);
|
||||
}
|
||||
if let Some((cx, cy)) = result.click_xy
|
||||
&& cx >= sx
|
||||
&& cx < sx + len as u16
|
||||
&& cy == sy
|
||||
{
|
||||
new_highlight = Some(highlight_kind);
|
||||
}
|
||||
let mut style = Style::new().fg(match segment.color {
|
||||
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,
|
||||
@@ -650,12 +652,3 @@ fn get_symbol(
|
||||
let sym = sym?;
|
||||
Some((obj, sym, &diff.symbols[sym]))
|
||||
}
|
||||
|
||||
fn find_function(obj: &Object, name: &str) -> Option<usize> {
|
||||
for (symbol_idx, symbol) in obj.symbols.iter().enumerate() {
|
||||
if symbol.name == name {
|
||||
return Some(symbol_idx);
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
+23
-17
@@ -41,6 +41,7 @@ any-arch = [
|
||||
"dep:regex",
|
||||
"dep:similar",
|
||||
"dep:syn",
|
||||
"dep:encoding_rs"
|
||||
]
|
||||
bindings = [
|
||||
"dep:prost",
|
||||
@@ -61,7 +62,10 @@ config = [
|
||||
"dep:semver",
|
||||
"dep:typed-path",
|
||||
]
|
||||
dwarf = ["dep:gimli"]
|
||||
dwarf = [
|
||||
"dep:gimli",
|
||||
"dep:typed-arena",
|
||||
]
|
||||
serde = [
|
||||
"dep:pbjson",
|
||||
"dep:pbjson-build",
|
||||
@@ -77,6 +81,7 @@ std = [
|
||||
"prost?/std",
|
||||
"serde?/std",
|
||||
"similar?/std",
|
||||
"typed-arena?/std",
|
||||
"typed-path?/std",
|
||||
"dep:filetime",
|
||||
"dep:memmap2",
|
||||
@@ -91,7 +96,7 @@ ppc = [
|
||||
"any-arch",
|
||||
"dep:cwdemangle",
|
||||
"dep:cwextab",
|
||||
"dep:ppc750cl",
|
||||
"dep:powerpc",
|
||||
"dep:rlwinmdec",
|
||||
]
|
||||
x86 = [
|
||||
@@ -122,14 +127,14 @@ features = ["all"]
|
||||
[dependencies]
|
||||
anyhow = { version = "1.0", default-features = false }
|
||||
filetime = { version = "0.2", optional = true }
|
||||
flagset = { version = "0.4", default-features = false, optional = true, git = "https://github.com/enarx/flagset.git", rev = "a1fe9369b3741e43fec45da1998e83b9d78966a2" }
|
||||
flagset = { version = "0.4", default-features = false, optional = true }
|
||||
itertools = { version = "0.14", default-features = false, features = ["use_alloc"] }
|
||||
log = { version = "0.4", default-features = false, optional = true }
|
||||
memmap2 = { version = "0.9", optional = true }
|
||||
num-traits = { version = "0.2", default-features = false, optional = true }
|
||||
object = { git = "https://github.com/gimli-rs/object", rev = "a74579249e21ab8fcd3a86be588de336f18297cb", default-features = false, features = ["read_core", "elf", "pe"] }
|
||||
pbjson = { version = "0.7", default-features = false, optional = true }
|
||||
prost = { version = "0.13", default-features = false, features = ["prost-derive"], optional = true }
|
||||
object = { git = "https://github.com/gimli-rs/object", rev = "16ff70aa6fbd97d6bb7b92375929f4d72414c32b", default-features = false, features = ["read_core", "elf", "coff"] }
|
||||
pbjson = { version = "0.8", default-features = false, optional = true }
|
||||
prost = { version = "0.14", default-features = false, features = ["derive"], optional = true }
|
||||
regex = { version = "1.11", default-features = false, features = [], optional = true }
|
||||
serde = { version = "1.0", default-features = false, features = ["derive"], optional = true }
|
||||
similar = { version = "2.7", default-features = false, features = ["hashbrown"], optional = true, git = "https://github.com/encounter/similar.git", branch = "no_std" }
|
||||
@@ -141,16 +146,17 @@ semver = { version = "1.0", default-features = false, optional = true }
|
||||
serde_json = { version = "1.0", default-features = false, features = ["alloc"], optional = true }
|
||||
|
||||
# dwarf
|
||||
gimli = { version = "0.31", default-features = false, features = ["read"], optional = true }
|
||||
gimli = { version = "0.32", default-features = false, features = ["read"], optional = true }
|
||||
typed-arena = { version = "2.0", default-features = false, optional = true }
|
||||
|
||||
# ppc
|
||||
cwdemangle = { version = "1.0", optional = true }
|
||||
cwextab = { version = "1.0", optional = true }
|
||||
ppc750cl = { version = "0.3", optional = true }
|
||||
cwextab = { version = "1.1", optional = true }
|
||||
powerpc = { version = "0.4", optional = true }
|
||||
rlwinmdec = { version = "1.1", optional = true }
|
||||
|
||||
# mips
|
||||
rabbitizer = { version = "2.0.0-alpha.1", default-features = false, features = ["all_extensions"], optional = true }
|
||||
rabbitizer = { version = "2.0.0-alpha.4", default-features = false, features = ["all_extensions"], optional = true }
|
||||
|
||||
# x86
|
||||
cpp_demangle = { version = "0.4", default-features = false, features = ["alloc"], optional = true }
|
||||
@@ -158,7 +164,7 @@ iced-x86 = { version = "1.21", default-features = false, features = ["decoder",
|
||||
msvc-demangler = { version = "0.11", optional = true }
|
||||
|
||||
# arm
|
||||
unarm = { version = "1.8", optional = true }
|
||||
unarm = { version = "1.9", optional = true }
|
||||
arm-attr = { version = "0.2", optional = true }
|
||||
|
||||
# arm64
|
||||
@@ -166,15 +172,15 @@ yaxpeax-arch = { version = "0.3", default-features = false, optional = true }
|
||||
yaxpeax-arm = { version = "0.3", default-features = false, optional = true }
|
||||
|
||||
# build
|
||||
notify = { version = "8.0.0", optional = true }
|
||||
notify = { version = "8.1.0", optional = true }
|
||||
notify-debouncer-full = { version = "0.5.0", optional = true }
|
||||
shell-escape = { version = "0.1", optional = true }
|
||||
tempfile = { version = "3.19", optional = true }
|
||||
tempfile = { version = "3.20", 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]
|
||||
@@ -188,10 +194,10 @@ self_update = { version = "0.42", optional = true }
|
||||
|
||||
[build-dependencies]
|
||||
heck = { version = "0.5", optional = true }
|
||||
pbjson-build = { version = "0.7", optional = true }
|
||||
pbjson-build = { version = "0.8", optional = true }
|
||||
prettyplease = { version = "0.2", optional = true }
|
||||
proc-macro2 = { version = "1.0", optional = true }
|
||||
prost-build = { version = "0.13", optional = true }
|
||||
prost-build = { version = "0.14", optional = true }
|
||||
quote = { version = "1.0", optional = true }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = { version = "1.0" }
|
||||
|
||||
@@ -11,6 +11,6 @@ objdiff-core contains the core functionality of [objdiff](https://github.com/enc
|
||||
- **`arm64`**: Enables the ARM64 backend powered by [yaxpeax-arm](https://github.com/iximeow/yaxpeax-arm).
|
||||
- **`arm`**: Enables the ARM backend powered by [unarm](https://github.com/AetiasHax/unarm).
|
||||
- **`mips`**: Enables the MIPS backend powered by [rabbitizer](https://github.com/Decompollaborate/rabbitizer).
|
||||
- **`ppc`**: Enables the PowerPC backend powered by [ppc750cl](https://github.com/encounter/ppc750cl).
|
||||
- **`ppc`**: Enables the PowerPC backend powered by [powerpc](https://github.com/encounter/powerpc-rs).
|
||||
- **`superh`**: Enables the SuperH backend powered by an included disassembler.
|
||||
- **`x86`**: Enables the x86 backend powered by [iced-x86](https://crates.io/crates/iced-x86).
|
||||
|
||||
@@ -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"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -60,10 +60,10 @@ pub struct ConfigGroup {
|
||||
}
|
||||
|
||||
fn build_doc(name: &str, description: Option<&str>) -> TokenStream {
|
||||
let mut doc = format!(" {}", name);
|
||||
let mut doc = format!(" {name}");
|
||||
let mut out = quote! { #[doc = #doc] };
|
||||
if let Some(description) = description {
|
||||
doc = format!(" {}", description);
|
||||
doc = format!(" {description}");
|
||||
out.extend(quote! { #[doc = ""] });
|
||||
out.extend(quote! { #[doc = #doc] });
|
||||
}
|
||||
@@ -443,9 +443,9 @@ pub fn generate_diff_config() {
|
||||
}
|
||||
impl core::fmt::Display for ConfigPropertyValue {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
match self {
|
||||
ConfigPropertyValue::Boolean(value) => write!(f, "{}", value),
|
||||
ConfigPropertyValue::Choice(value) => write!(f, "{}", value),
|
||||
match *self {
|
||||
ConfigPropertyValue::Boolean(value) => write!(f, "{value}"),
|
||||
ConfigPropertyValue::Choice(value) => f.write_str(value),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ use object::{Endian as _, Object as _, ObjectSection as _, ObjectSymbol as _, el
|
||||
use unarm::{args, arm, thumb};
|
||||
|
||||
use crate::{
|
||||
arch::Arch,
|
||||
arch::{Arch, RelocationOverride, RelocationOverrideTarget},
|
||||
diff::{ArmArchVersion, ArmR9Usage, DiffObjConfig, display::InstructionPart},
|
||||
obj::{
|
||||
InstructionRef, Relocation, RelocationFlags, ResolvedInstructionRef, ResolvedRelocation,
|
||||
@@ -225,7 +225,7 @@ impl Arch for ArchArm {
|
||||
|
||||
let mut address = start_addr;
|
||||
while address < end_addr {
|
||||
while let Some(next) = next_mapping.take_if(|x| address >= x.address) {
|
||||
while let Some(next) = next_mapping.filter(|x| address >= x.address) {
|
||||
// Change mapping
|
||||
mode = next.mapping;
|
||||
next_mapping = mappings_iter.next();
|
||||
@@ -356,47 +356,57 @@ impl Arch for ArchArm {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn implcit_addend(
|
||||
fn relocation_override(
|
||||
&self,
|
||||
_file: &object::File<'_>,
|
||||
section: &object::Section,
|
||||
address: u64,
|
||||
_relocation: &object::Relocation,
|
||||
flags: RelocationFlags,
|
||||
) -> Result<i64> {
|
||||
let section_data = section.data()?;
|
||||
let address = address as usize;
|
||||
Ok(match flags {
|
||||
// ARM calls
|
||||
RelocationFlags::Elf(elf::R_ARM_PC24)
|
||||
| RelocationFlags::Elf(elf::R_ARM_XPC25)
|
||||
| RelocationFlags::Elf(elf::R_ARM_CALL) => {
|
||||
let data = section_data[address..address + 4].try_into()?;
|
||||
let addend = self.endianness.read_i32_bytes(data);
|
||||
let imm24 = addend & 0xffffff;
|
||||
(imm24 << 2) << 8 >> 8
|
||||
relocation: &object::Relocation,
|
||||
) -> Result<Option<RelocationOverride>> {
|
||||
match relocation.flags() {
|
||||
// Handle ELF implicit relocations
|
||||
object::RelocationFlags::Elf { r_type } => {
|
||||
if relocation.has_implicit_addend() {
|
||||
let section_data = section.data()?;
|
||||
let address = address as usize;
|
||||
let addend = match r_type {
|
||||
// ARM calls
|
||||
elf::R_ARM_PC24 | elf::R_ARM_XPC25 | elf::R_ARM_CALL => {
|
||||
let data = section_data[address..address + 4].try_into()?;
|
||||
let addend = self.endianness.read_i32_bytes(data);
|
||||
let imm24 = addend & 0xffffff;
|
||||
(imm24 << 2) << 8 >> 8
|
||||
}
|
||||
|
||||
// Thumb calls
|
||||
elf::R_ARM_THM_PC22 | elf::R_ARM_THM_XPC22 => {
|
||||
let data = section_data[address..address + 2].try_into()?;
|
||||
let high = self.endianness.read_i16_bytes(data) as i32;
|
||||
let data = section_data[address + 2..address + 4].try_into()?;
|
||||
let low = self.endianness.read_i16_bytes(data) as i32;
|
||||
|
||||
let imm22 = ((high & 0x7ff) << 11) | (low & 0x7ff);
|
||||
(imm22 << 1) << 9 >> 9
|
||||
}
|
||||
|
||||
// Data
|
||||
elf::R_ARM_ABS32 => {
|
||||
let data = section_data[address..address + 4].try_into()?;
|
||||
self.endianness.read_i32_bytes(data)
|
||||
}
|
||||
|
||||
flags => bail!("Unsupported ARM implicit relocation {flags:?}"),
|
||||
};
|
||||
Ok(Some(RelocationOverride {
|
||||
target: RelocationOverrideTarget::Keep,
|
||||
addend: addend as i64,
|
||||
}))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
// Thumb calls
|
||||
RelocationFlags::Elf(elf::R_ARM_THM_PC22)
|
||||
| RelocationFlags::Elf(elf::R_ARM_THM_XPC22) => {
|
||||
let data = section_data[address..address + 2].try_into()?;
|
||||
let high = self.endianness.read_i16_bytes(data) as i32;
|
||||
let data = section_data[address + 2..address + 4].try_into()?;
|
||||
let low = self.endianness.read_i16_bytes(data) as i32;
|
||||
|
||||
let imm22 = ((high & 0x7ff) << 11) | (low & 0x7ff);
|
||||
(imm22 << 1) << 9 >> 9
|
||||
}
|
||||
|
||||
// Data
|
||||
RelocationFlags::Elf(elf::R_ARM_ABS32) => {
|
||||
let data = section_data[address..address + 4].try_into()?;
|
||||
self.endianness.read_i32_bytes(data)
|
||||
}
|
||||
|
||||
flags => bail!("Unsupported ARM implicit relocation {flags:?}"),
|
||||
} as i64)
|
||||
_ => Ok(None),
|
||||
}
|
||||
}
|
||||
|
||||
fn demangle(&self, name: &str) -> Option<String> {
|
||||
@@ -575,7 +585,7 @@ fn push_args(
|
||||
arg_cb(InstructionPart::basic("}"))?;
|
||||
}
|
||||
args::Argument::CoprocNum(value) => {
|
||||
arg_cb(InstructionPart::opaque(format!("p{}", value)))?;
|
||||
arg_cb(InstructionPart::opaque(format!("p{value}")))?;
|
||||
}
|
||||
args::Argument::ShiftImm(shift) => {
|
||||
arg_cb(InstructionPart::opaque(shift.op.to_string()))?;
|
||||
|
||||
+284
-279
File diff suppressed because it is too large
Load Diff
+106
-55
@@ -7,18 +7,15 @@ use alloc::{
|
||||
use anyhow::{Result, bail};
|
||||
use object::{Endian as _, Object as _, ObjectSection as _, ObjectSymbol as _, elf};
|
||||
use rabbitizer::{
|
||||
IsaExtension, IsaVersion, Vram,
|
||||
abi::Abi,
|
||||
operands::{IU16, ValuedOperand},
|
||||
registers_meta::Register,
|
||||
IsaExtension, IsaVersion, Vram, abi::Abi, operands::ValuedOperand, registers_meta::Register,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
arch::Arch,
|
||||
arch::{Arch, RelocationOverride, RelocationOverrideTarget},
|
||||
diff::{DiffObjConfig, MipsAbi, MipsInstrCategory, display::InstructionPart},
|
||||
obj::{
|
||||
InstructionArg, InstructionArgValue, InstructionRef, Relocation, RelocationFlags,
|
||||
ResolvedInstructionRef, ResolvedRelocation, SymbolFlag, SymbolFlagSet,
|
||||
ResolvedInstructionRef, ResolvedRelocation, Section, Symbol, SymbolFlag, SymbolFlagSet,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -143,6 +140,14 @@ impl ArchMips {
|
||||
})
|
||||
}
|
||||
|
||||
fn default_instruction_flags(&self) -> rabbitizer::InstructionFlags {
|
||||
match self.isa_extension {
|
||||
Some(extension) => rabbitizer::InstructionFlags::new_extension(extension),
|
||||
None => rabbitizer::InstructionFlags::new(IsaVersion::MIPS_III),
|
||||
}
|
||||
.with_abi(self.abi)
|
||||
}
|
||||
|
||||
fn instruction_flags(&self, diff_config: &DiffObjConfig) -> rabbitizer::InstructionFlags {
|
||||
let isa_extension = match diff_config.mips_instr_category {
|
||||
MipsInstrCategory::Auto => self.isa_extension,
|
||||
@@ -154,7 +159,7 @@ impl ArchMips {
|
||||
};
|
||||
match isa_extension {
|
||||
Some(extension) => rabbitizer::InstructionFlags::new_extension(extension),
|
||||
None => rabbitizer::InstructionFlags::new_isa(IsaVersion::MIPS_III, None),
|
||||
None => rabbitizer::InstructionFlags::new(IsaVersion::MIPS_III),
|
||||
}
|
||||
.with_abi(match diff_config.mips_abi {
|
||||
MipsAbi::Auto => self.abi,
|
||||
@@ -225,53 +230,66 @@ impl Arch for ArchMips {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn implcit_addend(
|
||||
fn relocation_override(
|
||||
&self,
|
||||
file: &object::File<'_>,
|
||||
section: &object::Section,
|
||||
address: u64,
|
||||
reloc: &object::Relocation,
|
||||
flags: RelocationFlags,
|
||||
) -> Result<i64> {
|
||||
// Check for paired R_MIPS_HI16 and R_MIPS_LO16 relocations.
|
||||
if let RelocationFlags::Elf(elf::R_MIPS_HI16 | elf::R_MIPS_LO16) = flags {
|
||||
if let Some(addend) = self
|
||||
.paired_relocations
|
||||
.get(section.index().0)
|
||||
.and_then(|m| m.get(&address).copied())
|
||||
{
|
||||
return Ok(addend);
|
||||
}
|
||||
}
|
||||
relocation: &object::Relocation,
|
||||
) -> Result<Option<RelocationOverride>> {
|
||||
match relocation.flags() {
|
||||
// Handle ELF implicit relocations
|
||||
object::RelocationFlags::Elf { r_type } => {
|
||||
if relocation.has_implicit_addend() {
|
||||
// Check for paired R_MIPS_HI16 and R_MIPS_LO16 relocations.
|
||||
if let elf::R_MIPS_HI16 | elf::R_MIPS_LO16 = r_type
|
||||
&& let Some(addend) = self
|
||||
.paired_relocations
|
||||
.get(section.index().0)
|
||||
.and_then(|m| m.get(&address).copied())
|
||||
{
|
||||
return Ok(Some(RelocationOverride {
|
||||
target: RelocationOverrideTarget::Keep,
|
||||
addend,
|
||||
}));
|
||||
}
|
||||
|
||||
let data = section.data()?;
|
||||
let code = data[address as usize..address as usize + 4].try_into()?;
|
||||
let addend = self.endianness.read_u32_bytes(code);
|
||||
Ok(match flags {
|
||||
RelocationFlags::Elf(elf::R_MIPS_32) => addend as i64,
|
||||
RelocationFlags::Elf(elf::R_MIPS_26) => ((addend & 0x03FFFFFF) << 2) as i64,
|
||||
RelocationFlags::Elf(elf::R_MIPS_HI16) => ((addend & 0x0000FFFF) << 16) as i32 as i64,
|
||||
RelocationFlags::Elf(elf::R_MIPS_LO16 | elf::R_MIPS_GOT16 | elf::R_MIPS_CALL16) => {
|
||||
(addend & 0x0000FFFF) as i16 as i64
|
||||
}
|
||||
RelocationFlags::Elf(elf::R_MIPS_GPREL16 | elf::R_MIPS_LITERAL) => {
|
||||
let object::RelocationTarget::Symbol(idx) = reloc.target() else {
|
||||
bail!("Unsupported R_MIPS_GPREL16 relocation against a non-symbol");
|
||||
};
|
||||
let sym = file.symbol_by_index(idx)?;
|
||||
let data = section.data()?;
|
||||
let code = self
|
||||
.endianness
|
||||
.read_u32_bytes(data[address as usize..address as usize + 4].try_into()?);
|
||||
let addend = match r_type {
|
||||
elf::R_MIPS_32 => code as i64,
|
||||
elf::R_MIPS_26 => ((code & 0x03FFFFFF) << 2) as i64,
|
||||
elf::R_MIPS_HI16 => ((code & 0x0000FFFF) << 16) as i32 as i64,
|
||||
elf::R_MIPS_LO16 | elf::R_MIPS_GOT16 | elf::R_MIPS_CALL16 => {
|
||||
(code & 0x0000FFFF) as i16 as i64
|
||||
}
|
||||
elf::R_MIPS_GPREL16 | elf::R_MIPS_LITERAL => {
|
||||
let object::RelocationTarget::Symbol(idx) = relocation.target() else {
|
||||
bail!("Unsupported R_MIPS_GPREL16 relocation against a non-symbol");
|
||||
};
|
||||
let sym = file.symbol_by_index(idx)?;
|
||||
|
||||
// if the symbol we are relocating against is in a local section we need to add
|
||||
// the ri_gp_value from .reginfo to the addend.
|
||||
if sym.section().index().is_some() {
|
||||
((addend & 0x0000FFFF) as i16 as i64) + self.ri_gp_value as i64
|
||||
// if the symbol we are relocating against is in a local section we need to add
|
||||
// the ri_gp_value from .reginfo to the addend.
|
||||
if sym.section().index().is_some() {
|
||||
((code & 0x0000FFFF) as i16 as i64) + self.ri_gp_value as i64
|
||||
} else {
|
||||
(code & 0x0000FFFF) as i16 as i64
|
||||
}
|
||||
}
|
||||
elf::R_MIPS_PC16 => 0, // PC-relative relocation
|
||||
R_MIPS15_S3 => ((code & 0x001FFFC0) >> 3) as i64,
|
||||
flags => bail!("Unsupported MIPS implicit relocation {flags:?}"),
|
||||
};
|
||||
Ok(Some(RelocationOverride { target: RelocationOverrideTarget::Keep, addend }))
|
||||
} else {
|
||||
(addend & 0x0000FFFF) as i16 as i64
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
RelocationFlags::Elf(elf::R_MIPS_PC16) => 0, // PC-relative relocation
|
||||
RelocationFlags::Elf(R_MIPS15_S3) => ((addend & 0x001FFFC0) >> 3) as i64,
|
||||
flags => bail!("Unsupported MIPS implicit relocation {flags:?}"),
|
||||
})
|
||||
_ => Ok(None),
|
||||
}
|
||||
}
|
||||
|
||||
fn demangle(&self, name: &str) -> Option<String> {
|
||||
@@ -320,6 +338,36 @@ impl Arch for ArchMips {
|
||||
}
|
||||
flags
|
||||
}
|
||||
|
||||
fn infer_function_size(
|
||||
&self,
|
||||
symbol: &Symbol,
|
||||
section: &Section,
|
||||
next_address: u64,
|
||||
) -> Result<u64> {
|
||||
// Trim any trailing 4-byte zeroes from the end (nops)
|
||||
let mut new_address = next_address;
|
||||
while new_address >= symbol.address + 4
|
||||
&& let Some(data) = section.data_range(new_address - 4, 4)
|
||||
&& data == [0u8; 4]
|
||||
{
|
||||
new_address -= 4;
|
||||
}
|
||||
// Check if the last instruction has a delay slot, if so, include the delay slot nop
|
||||
if new_address + 4 <= next_address
|
||||
&& new_address >= symbol.address + 4
|
||||
&& let Some(data) = section.data_range(new_address - 4, 4)
|
||||
&& let instruction = rabbitizer::Instruction::new(
|
||||
self.endianness.read_u32_bytes(data.try_into().unwrap()),
|
||||
Vram::new((new_address - 4) as u32),
|
||||
self.default_instruction_flags(),
|
||||
)
|
||||
&& instruction.opcode().has_delay_slot()
|
||||
{
|
||||
new_address += 4;
|
||||
}
|
||||
Ok(new_address.saturating_sub(symbol.address))
|
||||
}
|
||||
}
|
||||
|
||||
fn push_args(
|
||||
@@ -335,14 +383,18 @@ fn push_args(
|
||||
}
|
||||
|
||||
match op {
|
||||
ValuedOperand::core_immediate(imm) => {
|
||||
ValuedOperand::core_imm_i16(imm) => {
|
||||
if let Some(resolved) = relocation {
|
||||
push_reloc(resolved.relocation, &mut arg_cb)?;
|
||||
} else {
|
||||
arg_cb(match imm {
|
||||
IU16::Integer(s) => InstructionPart::signed(s),
|
||||
IU16::Unsigned(u) => InstructionPart::unsigned(u),
|
||||
})?;
|
||||
arg_cb(InstructionPart::signed(imm))?;
|
||||
}
|
||||
}
|
||||
ValuedOperand::core_imm_u16(imm) => {
|
||||
if let Some(resolved) = relocation {
|
||||
push_reloc(resolved.relocation, &mut arg_cb)?;
|
||||
} else {
|
||||
arg_cb(InstructionPart::unsigned(imm))?;
|
||||
}
|
||||
}
|
||||
ValuedOperand::core_label(..) | ValuedOperand::core_branch_target_label(..) => {
|
||||
@@ -359,14 +411,13 @@ fn push_args(
|
||||
))?;
|
||||
}
|
||||
}
|
||||
ValuedOperand::core_immediate_base(imm, base) => {
|
||||
ValuedOperand::core_imm_rs(imm, base) => {
|
||||
if let Some(resolved) = relocation {
|
||||
push_reloc(resolved.relocation, &mut arg_cb)?;
|
||||
} else {
|
||||
arg_cb(InstructionPart::Arg(InstructionArg::Value(match imm {
|
||||
IU16::Integer(s) => InstructionArgValue::Signed(s as i64),
|
||||
IU16::Unsigned(u) => InstructionArgValue::Unsigned(u as u64),
|
||||
})))?;
|
||||
arg_cb(InstructionPart::Arg(InstructionArg::Value(
|
||||
InstructionArgValue::Signed(imm as i64),
|
||||
)))?;
|
||||
}
|
||||
arg_cb(InstructionPart::basic("("))?;
|
||||
arg_cb(InstructionPart::opaque(base.either_name(
|
||||
|
||||
@@ -1,5 +1,14 @@
|
||||
use alloc::{borrow::Cow, boxed::Box, format, string::String, vec::Vec};
|
||||
use core::{ffi::CStr, fmt, fmt::Debug};
|
||||
use alloc::{
|
||||
borrow::Cow,
|
||||
boxed::Box,
|
||||
format,
|
||||
string::{String, ToString},
|
||||
vec::Vec,
|
||||
};
|
||||
use core::{
|
||||
ffi::CStr,
|
||||
fmt::{self, Debug},
|
||||
};
|
||||
|
||||
use anyhow::{Result, bail};
|
||||
use encoding_rs::SHIFT_JIS;
|
||||
@@ -11,8 +20,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 +41,7 @@ pub mod superh;
|
||||
pub mod x86;
|
||||
|
||||
/// Represents the type of data associated with an instruction
|
||||
#[derive(PartialEq)]
|
||||
pub enum DataType {
|
||||
Int8,
|
||||
Int16,
|
||||
@@ -44,16 +55,16 @@ pub enum DataType {
|
||||
|
||||
impl fmt::Display for DataType {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
DataType::Int8 => write!(f, "Int8"),
|
||||
DataType::Int16 => write!(f, "Int16"),
|
||||
DataType::Int32 => write!(f, "Int32"),
|
||||
DataType::Int64 => write!(f, "Int64"),
|
||||
DataType::Float => write!(f, "Float"),
|
||||
DataType::Double => write!(f, "Double"),
|
||||
DataType::Bytes => write!(f, "Bytes"),
|
||||
DataType::String => write!(f, "String"),
|
||||
}
|
||||
f.write_str(match self {
|
||||
DataType::Int8 => "Int8",
|
||||
DataType::Int16 => "Int16",
|
||||
DataType::Int32 => "Int32",
|
||||
DataType::Int64 => "Int64",
|
||||
DataType::Float => "Float",
|
||||
DataType::Double => "Double",
|
||||
DataType::Bytes => "Bytes",
|
||||
DataType::String => "String",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,8 +72,8 @@ impl DataType {
|
||||
pub fn display_labels(&self, endian: object::Endianness, bytes: &[u8]) -> Vec<String> {
|
||||
let mut strs = Vec::new();
|
||||
for (literal, label_override) in self.display_literals(endian, bytes) {
|
||||
let label = label_override.unwrap_or_else(|| format!("{}", self));
|
||||
strs.push(format!("{}: {}", label, literal))
|
||||
let label = label_override.unwrap_or_else(|| self.to_string());
|
||||
strs.push(format!("{label}: {literal}"))
|
||||
}
|
||||
strs
|
||||
}
|
||||
@@ -95,7 +106,7 @@ impl DataType {
|
||||
match self {
|
||||
DataType::Int8 => {
|
||||
let i = i8::from_ne_bytes(bytes.try_into().unwrap());
|
||||
strs.push((format!("{:#x}", i), None));
|
||||
strs.push((format!("{i:#x}"), None));
|
||||
|
||||
if i < 0 {
|
||||
strs.push((format!("{:#x}", ReallySigned(i)), None));
|
||||
@@ -103,7 +114,7 @@ impl DataType {
|
||||
}
|
||||
DataType::Int16 => {
|
||||
let i = endian.read_i16_bytes(bytes.try_into().unwrap());
|
||||
strs.push((format!("{:#x}", i), None));
|
||||
strs.push((format!("{i:#x}"), None));
|
||||
|
||||
if i < 0 {
|
||||
strs.push((format!("{:#x}", ReallySigned(i)), None));
|
||||
@@ -111,7 +122,7 @@ impl DataType {
|
||||
}
|
||||
DataType::Int32 => {
|
||||
let i = endian.read_i32_bytes(bytes.try_into().unwrap());
|
||||
strs.push((format!("{:#x}", i), None));
|
||||
strs.push((format!("{i:#x}"), None));
|
||||
|
||||
if i < 0 {
|
||||
strs.push((format!("{:#x}", ReallySigned(i)), None));
|
||||
@@ -119,7 +130,7 @@ impl DataType {
|
||||
}
|
||||
DataType::Int64 => {
|
||||
let i = endian.read_i64_bytes(bytes.try_into().unwrap());
|
||||
strs.push((format!("{:#x}", i), None));
|
||||
strs.push((format!("{i:#x}"), None));
|
||||
|
||||
if i < 0 {
|
||||
strs.push((format!("{:#x}", ReallySigned(i)), None));
|
||||
@@ -146,16 +157,16 @@ impl DataType {
|
||||
));
|
||||
}
|
||||
DataType::Bytes => {
|
||||
strs.push((format!("{:#?}", bytes), None));
|
||||
strs.push((format!("{bytes:#?}"), None));
|
||||
}
|
||||
DataType::String => {
|
||||
if let Ok(cstr) = CStr::from_bytes_until_nul(bytes) {
|
||||
strs.push((format!("{:?}", cstr), None));
|
||||
strs.push((format!("{cstr:?}"), None));
|
||||
}
|
||||
if let Some(nul_idx) = bytes.iter().position(|&c| c == b'\0') {
|
||||
let (cow, _, had_errors) = SHIFT_JIS.decode(&bytes[..nul_idx]);
|
||||
if !had_errors {
|
||||
let str = format!("{:?}", cow);
|
||||
let str = format!("{cow:?}");
|
||||
// Only add the Shift JIS string if it's different from the ASCII string.
|
||||
if !strs.iter().any(|x| x.0 == str) {
|
||||
strs.push((str, Some("Shift JIS".into())));
|
||||
@@ -204,10 +215,10 @@ impl dyn Arch {
|
||||
|
||||
// Remove any branch destinations that are outside the function range
|
||||
for ins in result.iter_mut() {
|
||||
if let Some(branch_dest) = ins.branch_dest {
|
||||
if branch_dest < function_start || branch_dest >= function_end {
|
||||
ins.branch_dest = None;
|
||||
}
|
||||
if let Some(branch_dest) = ins.branch_dest
|
||||
&& (branch_dest < function_start || branch_dest >= function_end)
|
||||
{
|
||||
ins.branch_dest = None;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -335,14 +346,26 @@ pub trait Arch: Send + Sync + Debug {
|
||||
Vec::new()
|
||||
}
|
||||
|
||||
fn implcit_addend(
|
||||
// Perform detailed data flow analysis
|
||||
fn data_flow_analysis(
|
||||
&self,
|
||||
file: &object::File<'_>,
|
||||
section: &object::Section,
|
||||
address: u64,
|
||||
relocation: &object::Relocation,
|
||||
flags: RelocationFlags,
|
||||
) -> Result<i64>;
|
||||
_obj: &Object,
|
||||
_symbol: &Symbol,
|
||||
_code: &[u8],
|
||||
_relocations: &[Relocation],
|
||||
) -> Option<Box<dyn FlowAnalysisResult>> {
|
||||
None
|
||||
}
|
||||
|
||||
fn relocation_override(
|
||||
&self,
|
||||
_file: &object::File<'_>,
|
||||
_section: &object::Section,
|
||||
_address: u64,
|
||||
_relocation: &object::Relocation,
|
||||
) -> Result<Option<RelocationOverride>> {
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
fn demangle(&self, _name: &str) -> Option<String> { None }
|
||||
|
||||
@@ -383,13 +406,24 @@ pub trait Arch: Send + Sync + Debug {
|
||||
) -> Vec<ContextItem> {
|
||||
Vec::new()
|
||||
}
|
||||
|
||||
fn infer_function_size(
|
||||
&self,
|
||||
symbol: &Symbol,
|
||||
_section: &Section,
|
||||
next_address: u64,
|
||||
) -> Result<u64> {
|
||||
Ok(next_address.saturating_sub(symbol.address))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_arch(object: &object::File) -> Result<Box<dyn Arch>> {
|
||||
use object::Object as _;
|
||||
Ok(match object.architecture() {
|
||||
#[cfg(feature = "ppc")]
|
||||
object::Architecture::PowerPc => Box::new(ppc::ArchPpc::new(object)?),
|
||||
object::Architecture::PowerPc | object::Architecture::PowerPc64 => {
|
||||
Box::new(ppc::ArchPpc::new(object)?)
|
||||
}
|
||||
#[cfg(feature = "mips")]
|
||||
object::Architecture::Mips => Box::new(mips::ArchMips::new(object)?),
|
||||
#[cfg(feature = "x86")]
|
||||
@@ -434,16 +468,19 @@ impl Arch for ArchDummy {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn implcit_addend(
|
||||
&self,
|
||||
_file: &object::File<'_>,
|
||||
_section: &object::Section,
|
||||
_address: u64,
|
||||
_relocation: &object::Relocation,
|
||||
_flags: RelocationFlags,
|
||||
) -> Result<i64> {
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
fn data_reloc_size(&self, _flags: RelocationFlags) -> usize { 0 }
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum RelocationOverrideTarget {
|
||||
Keep,
|
||||
Skip,
|
||||
Symbol(object::SymbolIndex),
|
||||
Section(object::SectionIndex),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct RelocationOverride {
|
||||
pub target: RelocationOverrideTarget,
|
||||
pub addend: i64,
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -197,7 +197,7 @@ fn match_ni_f(
|
||||
}
|
||||
_ => {
|
||||
parts.push(InstructionPart::basic(".word 0x"));
|
||||
parts.push(InstructionPart::basic(format!("{:04X}", op)));
|
||||
parts.push(InstructionPart::basic(format!("{op:04X}")));
|
||||
parts.push(InstructionPart::basic(" /* unknown instruction */"));
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user