mirror of
https://github.com/encounter/objdiff.git
synced 2026-07-10 12:18:36 -07:00
Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 66c879a95d | |||
| d53c358d2f | |||
| f24c017545 | |||
| 3b8603ab22 | |||
| 86b7d6b229 | |||
| 3f82781808 | |||
| 926dd06ce9 | |||
| de70b6fca0 | |||
| 79542a4725 | |||
| 0ebd2ae459 | |||
| 08ebea8bd2 | |||
| 46b8890159 | |||
| 8356fe670d |
Generated
+4
-4
@@ -3491,7 +3491,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "objdiff-cli"
|
||||
version = "3.5.1"
|
||||
version = "3.6.1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"argp",
|
||||
@@ -3514,7 +3514,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "objdiff-core"
|
||||
version = "3.5.1"
|
||||
version = "3.6.1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"arm-attr",
|
||||
@@ -3570,7 +3570,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "objdiff-gui"
|
||||
version = "3.5.1"
|
||||
version = "3.6.1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"argp",
|
||||
@@ -3608,7 +3608,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "objdiff-wasm"
|
||||
version = "3.5.1"
|
||||
version = "3.6.1"
|
||||
dependencies = [
|
||||
"log",
|
||||
"objdiff-core",
|
||||
|
||||
+1
-1
@@ -14,7 +14,7 @@ default-members = [
|
||||
resolver = "3"
|
||||
|
||||
[workspace.package]
|
||||
version = "3.5.1"
|
||||
version = "3.6.1"
|
||||
authors = ["Luke Street <luke@street.dev>"]
|
||||
edition = "2024"
|
||||
license = "MIT OR Apache-2.0"
|
||||
|
||||
@@ -77,6 +77,7 @@ ignore = [
|
||||
{ id = "RUSTSEC-2025-0052", reason = "Unmaintained async-std crate is an indirect dependency" },
|
||||
{ id = "RUSTSEC-2025-0119", reason = "Unmaintained number_prefix crate is an indirect dependency" },
|
||||
{ id = "RUSTSEC-2025-0134", reason = "Unmaintained rustls-pemfile crate is an indirect dependency" },
|
||||
{ id = "RUSTSEC-2026-0002", reason = "Unsound advisory in lru indirect dependency" },
|
||||
]
|
||||
# If this is true, then cargo deny will use the git executable to fetch advisory database.
|
||||
# If this is false, then it uses a built-in git library.
|
||||
|
||||
@@ -19,6 +19,7 @@ use crossterm::{
|
||||
},
|
||||
};
|
||||
use objdiff_core::{
|
||||
bindings::diff::DiffResult,
|
||||
build::{
|
||||
BuildConfig, BuildStatus,
|
||||
watcher::{Watcher, create_watcher},
|
||||
@@ -28,7 +29,7 @@ use objdiff_core::{
|
||||
build_globset,
|
||||
path::{check_path_buf, platform_path, platform_path_serde_option},
|
||||
},
|
||||
diff::{DiffObjConfig, MappingConfig, ObjectDiff},
|
||||
diff::{self, DiffObjConfig, DiffSide, MappingConfig, ObjectDiff},
|
||||
jobs::{
|
||||
Job, JobQueue, JobResult,
|
||||
objdiff::{ObjDiffConfig, start_build},
|
||||
@@ -40,7 +41,10 @@ use typed_path::{Utf8PlatformPath, Utf8PlatformPathBuf};
|
||||
|
||||
use crate::{
|
||||
cmd::apply_config_args,
|
||||
util::term::crossterm_panic_handler,
|
||||
util::{
|
||||
output::{OutputFormat, write_output},
|
||||
term::crossterm_panic_handler,
|
||||
},
|
||||
views::{EventControlFlow, EventResult, UiView, function_diff::FunctionDiffUi},
|
||||
};
|
||||
|
||||
@@ -60,6 +64,12 @@ pub struct Args {
|
||||
#[argp(option, short = 'u')]
|
||||
/// Unit name within project
|
||||
unit: Option<String>,
|
||||
#[argp(option, short = 'o', from_str_fn(platform_path))]
|
||||
/// Output file (one-shot mode) ("-" for stdout)
|
||||
output: Option<Utf8PlatformPathBuf>,
|
||||
#[argp(option)]
|
||||
/// Output format (json, json-pretty, proto) (default: json)
|
||||
format: Option<String>,
|
||||
#[argp(positional)]
|
||||
/// Function symbol to diff
|
||||
symbol: Option<String>,
|
||||
@@ -158,7 +168,41 @@ pub fn run(args: Args) -> Result<()> {
|
||||
_ => bail!("Either target and base or project and unit must be specified"),
|
||||
};
|
||||
|
||||
run_interactive(args, target_path, base_path, project_config, unit_options)
|
||||
if let Some(output) = &args.output {
|
||||
run_oneshot(&args, output, target_path.as_deref(), base_path.as_deref(), unit_options)
|
||||
} else {
|
||||
run_interactive(args, target_path, base_path, project_config, unit_options)
|
||||
}
|
||||
}
|
||||
|
||||
fn run_oneshot(
|
||||
args: &Args,
|
||||
output: &Utf8PlatformPath,
|
||||
target_path: Option<&Utf8PlatformPath>,
|
||||
base_path: Option<&Utf8PlatformPath>,
|
||||
unit_options: Option<ProjectOptions>,
|
||||
) -> Result<()> {
|
||||
let output_format = OutputFormat::from_option(args.format.as_deref())?;
|
||||
let (diff_config, mapping_config) = build_config_from_args(args, None, unit_options.as_ref())?;
|
||||
let target = target_path
|
||||
.map(|p| {
|
||||
obj::read::read(p.as_ref(), &diff_config, DiffSide::Target)
|
||||
.with_context(|| format!("Loading {p}"))
|
||||
})
|
||||
.transpose()?;
|
||||
let base = base_path
|
||||
.map(|p| {
|
||||
obj::read::read(p.as_ref(), &diff_config, DiffSide::Base)
|
||||
.with_context(|| format!("Loading {p}"))
|
||||
})
|
||||
.transpose()?;
|
||||
let result =
|
||||
diff::diff_objs(target.as_ref(), base.as_ref(), None, &diff_config, &mapping_config)?;
|
||||
let left = target.as_ref().and_then(|o| result.left.as_ref().map(|d| (o, d)));
|
||||
let right = base.as_ref().and_then(|o| result.right.as_ref().map(|d| (o, d)));
|
||||
let diff_result = DiffResult::new(left, right, &diff_config)?;
|
||||
write_output(&diff_result, Some(output), output_format)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn build_config_from_args(
|
||||
|
||||
@@ -0,0 +1,162 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package objdiff.diff;
|
||||
|
||||
// Top-level diff result containing left and right object diffs
|
||||
message DiffResult {
|
||||
optional DiffObject left = 1;
|
||||
optional DiffObject right = 2;
|
||||
}
|
||||
|
||||
// Diff information for a single object file
|
||||
message DiffObject {
|
||||
repeated DiffSection sections = 1;
|
||||
repeated DiffSymbol symbols = 2;
|
||||
}
|
||||
|
||||
// Diff information for a section
|
||||
message DiffSection {
|
||||
string name = 1;
|
||||
DiffSectionKind kind = 2;
|
||||
uint64 size = 3;
|
||||
uint64 address = 4;
|
||||
optional float match_percent = 5;
|
||||
repeated DiffDataSegment data_diff = 6;
|
||||
repeated DiffDataRelocation reloc_diff = 7;
|
||||
}
|
||||
|
||||
enum DiffSectionKind {
|
||||
SECTION_UNKNOWN = 0;
|
||||
SECTION_CODE = 1;
|
||||
SECTION_DATA = 2;
|
||||
SECTION_BSS = 3;
|
||||
SECTION_COMMON = 4;
|
||||
}
|
||||
|
||||
// Symbol with diff information
|
||||
message DiffSymbol {
|
||||
string name = 1;
|
||||
optional string demangled_name = 2;
|
||||
uint64 address = 3;
|
||||
uint64 size = 4;
|
||||
uint32 flags = 5;
|
||||
// The symbol index in the _other_ object that this symbol was diffed against
|
||||
optional uint32 target_symbol = 6;
|
||||
optional float match_percent = 7;
|
||||
// Instruction diff rows (for code symbols)
|
||||
repeated DiffInstructionRow instructions = 8;
|
||||
// Data diff (for data symbols)
|
||||
repeated DiffDataSegment data_diff = 9;
|
||||
}
|
||||
|
||||
// Symbol visibility flags (bitmask)
|
||||
enum DiffSymbolFlag {
|
||||
SYMBOL_NONE = 0;
|
||||
SYMBOL_GLOBAL = 1;
|
||||
SYMBOL_LOCAL = 2;
|
||||
SYMBOL_WEAK = 4;
|
||||
SYMBOL_COMMON = 8;
|
||||
SYMBOL_HIDDEN = 16;
|
||||
}
|
||||
|
||||
// A single instruction diff row
|
||||
message DiffInstructionRow {
|
||||
DiffKind diff_kind = 1;
|
||||
optional DiffInstruction instruction = 2;
|
||||
repeated DiffInstructionArgDiff arg_diff = 3;
|
||||
}
|
||||
|
||||
// Parsed instruction information
|
||||
message DiffInstruction {
|
||||
uint64 address = 1;
|
||||
uint32 size = 2;
|
||||
// Formatted instruction string
|
||||
string formatted = 3;
|
||||
// Formatted instruction parts
|
||||
repeated DiffInstructionPart parts = 4;
|
||||
// Relocation information (if present)
|
||||
optional DiffRelocation relocation = 5;
|
||||
// Branch destination address
|
||||
optional uint64 branch_dest = 6;
|
||||
// Source line number (if present)
|
||||
optional uint32 line_number = 7;
|
||||
}
|
||||
|
||||
// An instruction part
|
||||
message DiffInstructionPart {
|
||||
oneof part {
|
||||
// Basic text (whitespace, punctuation, etc.)
|
||||
string basic = 1;
|
||||
// Opcode/mnemonic
|
||||
DiffOpcode opcode = 2;
|
||||
// Argument
|
||||
DiffInstructionArg arg = 3;
|
||||
// Separator between arguments (comma)
|
||||
bool separator = 4;
|
||||
}
|
||||
}
|
||||
|
||||
message DiffOpcode {
|
||||
// Mnemonic string
|
||||
string mnemonic = 1;
|
||||
// Base opcode ID
|
||||
uint32 opcode = 2;
|
||||
}
|
||||
|
||||
// An instruction argument
|
||||
message DiffInstructionArg {
|
||||
oneof arg {
|
||||
// Signed immediate value
|
||||
sint64 signed = 1;
|
||||
// Unsigned immediate value
|
||||
uint64 unsigned = 2;
|
||||
// Opaque string value (register names, etc.)
|
||||
string opaque = 3;
|
||||
// Relocation
|
||||
bool reloc = 4;
|
||||
// Branch destination address
|
||||
uint64 branch_dest = 5;
|
||||
}
|
||||
}
|
||||
|
||||
// Relocation information
|
||||
message DiffRelocation {
|
||||
uint32 type = 1;
|
||||
string type_name = 2;
|
||||
uint32 target_symbol = 3;
|
||||
int64 addend = 4;
|
||||
}
|
||||
|
||||
// Argument diff information
|
||||
message DiffInstructionArgDiff {
|
||||
// If set, this argument differs from the other side.
|
||||
// The value is a rotating index for coloring.
|
||||
optional uint32 diff_index = 1;
|
||||
}
|
||||
|
||||
// Diff kind for instructions and data
|
||||
enum DiffKind {
|
||||
DIFF_NONE = 0;
|
||||
DIFF_REPLACE = 1;
|
||||
DIFF_DELETE = 2;
|
||||
DIFF_INSERT = 3;
|
||||
DIFF_OP_MISMATCH = 4;
|
||||
DIFF_ARG_MISMATCH = 5;
|
||||
}
|
||||
|
||||
// Data diff segment
|
||||
message DiffDataSegment {
|
||||
DiffKind kind = 1;
|
||||
bytes data = 2;
|
||||
// Size may be larger than data length for BSS
|
||||
uint64 size = 3;
|
||||
}
|
||||
|
||||
// Data relocation diff
|
||||
message DiffDataRelocation {
|
||||
DiffRelocation relocation = 1;
|
||||
DiffKind kind = 2;
|
||||
// Address range this relocation covers
|
||||
uint64 start = 3;
|
||||
uint64 end = 4;
|
||||
}
|
||||
Binary file not shown.
@@ -174,23 +174,36 @@ impl DataType {
|
||||
strs.push((format!("{bytes:#?}"), None, None));
|
||||
}
|
||||
DataType::String => {
|
||||
if let Some(nul_idx) = bytes.iter().position(|&c| c == b'\0') {
|
||||
let str_bytes = &bytes[..nul_idx];
|
||||
// Special case to display (ASCII) as the label for ASCII-only strings.
|
||||
let (cow, _, had_errors) = encoding_rs::UTF_8.decode(str_bytes);
|
||||
if !had_errors && cow.is_ascii() {
|
||||
let string = format!("{cow}");
|
||||
let copy_string = escape_special_ascii_characters(string.clone());
|
||||
strs.push((string, Some("ASCII".into()), Some(copy_string)));
|
||||
// Special case to display (ASCII) as the label for ASCII-only strings.
|
||||
let mut is_ascii = false;
|
||||
if bytes.is_ascii()
|
||||
&& let Ok(str) = str::from_utf8(bytes)
|
||||
{
|
||||
let trimmed = str.trim_end_matches('\0');
|
||||
if !trimmed.is_empty() {
|
||||
let copy_string = escape_special_ascii_characters(trimmed);
|
||||
strs.push((trimmed.to_string(), Some("ASCII".into()), Some(copy_string)));
|
||||
is_ascii = true;
|
||||
}
|
||||
for (encoding, encoding_name) in SUPPORTED_ENCODINGS {
|
||||
let (cow, _, had_errors) = encoding.decode(str_bytes);
|
||||
// Avoid showing ASCII-only strings more than once if the encoding is ASCII-compatible.
|
||||
if !had_errors && (!encoding.is_ascii_compatible() || !cow.is_ascii()) {
|
||||
let string = format!("{cow}");
|
||||
let copy_string = escape_special_ascii_characters(string.clone());
|
||||
strs.push((string, Some(encoding_name.into()), Some(copy_string)));
|
||||
}
|
||||
}
|
||||
|
||||
for (encoding, encoding_name) in SUPPORTED_ENCODINGS {
|
||||
// Avoid showing ASCII-only strings more than once if the encoding is ASCII-compatible.
|
||||
if is_ascii && encoding.is_ascii_compatible() {
|
||||
continue;
|
||||
}
|
||||
let (cow, _, had_errors) = encoding.decode(bytes);
|
||||
if had_errors {
|
||||
continue;
|
||||
}
|
||||
let trimmed = cow.trim_end_matches('\0');
|
||||
if !trimmed.is_empty() {
|
||||
let copy_string = escape_special_ascii_characters(trimmed);
|
||||
strs.push((
|
||||
trimmed.to_string(),
|
||||
Some(encoding_name.into()),
|
||||
Some(copy_string),
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -508,7 +521,7 @@ pub struct RelocationOverride {
|
||||
|
||||
/// Escape ASCII characters such as \n or \t, but not Unicode characters such as \u{3000}.
|
||||
/// Suitable for copying to clipboard.
|
||||
fn escape_special_ascii_characters(value: String) -> String {
|
||||
fn escape_special_ascii_characters(value: &str) -> String {
|
||||
let mut escaped = String::new();
|
||||
escaped.push('"');
|
||||
for c in value.chars() {
|
||||
|
||||
@@ -342,7 +342,10 @@ impl Arch for ArchPpc {
|
||||
elf::R_PPC_UADDR32 => 4,
|
||||
_ => 1,
|
||||
},
|
||||
_ => 1,
|
||||
RelocationFlags::Coff(r_type) => match r_type {
|
||||
pe::IMAGE_REL_PPC_ADDR32 => 4,
|
||||
_ => 1,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -355,7 +358,9 @@ impl Arch for ArchPpc {
|
||||
}
|
||||
|
||||
fn guess_data_type(&self, resolved: ResolvedInstructionRef, bytes: &[u8]) -> Option<DataType> {
|
||||
if resolved.relocation.is_some_and(|r| r.symbol.name.starts_with("@stringBase")) {
|
||||
if resolved.relocation.is_some_and(|r| {
|
||||
r.symbol.name.starts_with("@stringBase") || r.symbol.name.starts_with("$SG")
|
||||
}) {
|
||||
// Pooled string.
|
||||
return Some(DataType::String);
|
||||
}
|
||||
|
||||
@@ -68,7 +68,12 @@ impl ArchX86 {
|
||||
_ => None,
|
||||
},
|
||||
RelocationFlags::Elf(typ) => match typ {
|
||||
elf::R_386_32 | elf::R_386_PC32 => Some(4),
|
||||
elf::R_386_32
|
||||
| elf::R_386_PC32
|
||||
| elf::R_386_GOT32
|
||||
| elf::R_386_PLT32
|
||||
| elf::R_386_GOTOFF
|
||||
| elf::R_386_GOTPC => Some(4),
|
||||
elf::R_386_16 => Some(2),
|
||||
_ => None,
|
||||
},
|
||||
@@ -272,7 +277,15 @@ impl Arch for ArchX86 {
|
||||
object::RelocationFlags::Coff {
|
||||
typ: pe::IMAGE_REL_I386_DIR32 | pe::IMAGE_REL_I386_REL32,
|
||||
}
|
||||
| object::RelocationFlags::Elf { r_type: elf::R_386_32 | elf::R_386_PC32 } => {
|
||||
| object::RelocationFlags::Elf {
|
||||
r_type:
|
||||
elf::R_386_32
|
||||
| elf::R_386_PC32
|
||||
| elf::R_386_GOT32
|
||||
| elf::R_386_PLT32
|
||||
| elf::R_386_GOTOFF
|
||||
| elf::R_386_GOTPC,
|
||||
} => {
|
||||
let data =
|
||||
section.data()?[address as usize..address as usize + 4].try_into()?;
|
||||
self.endianness.read_i32_bytes(data) as i64
|
||||
@@ -308,7 +321,16 @@ impl Arch for ArchX86 {
|
||||
pe::IMAGE_REL_I386_REL32 => Some("IMAGE_REL_I386_REL32"),
|
||||
_ => None,
|
||||
},
|
||||
_ => None,
|
||||
RelocationFlags::Elf(typ) => match typ {
|
||||
elf::R_386_32 => Some("R_386_32"),
|
||||
elf::R_386_PC32 => Some("R_386_PC32"),
|
||||
elf::R_386_GOT32 => Some("R_386_GOT32"),
|
||||
elf::R_386_PLT32 => Some("R_386_PLT32"),
|
||||
elf::R_386_GOTOFF => Some("R_386_GOTOFF"),
|
||||
elf::R_386_GOTPC => Some("R_386_GOTPC"),
|
||||
elf::R_386_16 => Some("R_386_16"),
|
||||
_ => None,
|
||||
},
|
||||
},
|
||||
Architecture::X86_64 => match flags {
|
||||
RelocationFlags::Coff(typ) => match typ {
|
||||
|
||||
@@ -0,0 +1,350 @@
|
||||
#![allow(clippy::needless_lifetimes)] // Generated serde code
|
||||
|
||||
use alloc::{
|
||||
string::{String, ToString},
|
||||
vec,
|
||||
vec::Vec,
|
||||
};
|
||||
use core::fmt::Write;
|
||||
|
||||
use anyhow::Result;
|
||||
|
||||
use crate::{
|
||||
diff::{self, DiffObjConfig, display::InstructionPart},
|
||||
obj::{self, Object, SymbolFlag},
|
||||
};
|
||||
|
||||
// Protobuf diff types
|
||||
include!(concat!(env!("OUT_DIR"), "/objdiff.diff.rs"));
|
||||
#[cfg(feature = "serde")]
|
||||
include!(concat!(env!("OUT_DIR"), "/objdiff.diff.serde.rs"));
|
||||
|
||||
impl DiffResult {
|
||||
pub fn new(
|
||||
left: Option<(&Object, &diff::ObjectDiff)>,
|
||||
right: Option<(&Object, &diff::ObjectDiff)>,
|
||||
diff_config: &DiffObjConfig,
|
||||
) -> Result<Self> {
|
||||
Ok(Self {
|
||||
left: left.map(|(obj, diff)| DiffObject::new(obj, diff, diff_config)).transpose()?,
|
||||
right: right.map(|(obj, diff)| DiffObject::new(obj, diff, diff_config)).transpose()?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl DiffObject {
|
||||
pub fn new(obj: &Object, diff: &diff::ObjectDiff, diff_config: &DiffObjConfig) -> Result<Self> {
|
||||
let mut sections = Vec::with_capacity(obj.sections.len());
|
||||
for (section_idx, section) in obj.sections.iter().enumerate() {
|
||||
let section_diff = &diff.sections[section_idx];
|
||||
sections.push(DiffSection::new(obj, section, section_diff));
|
||||
}
|
||||
|
||||
let mut symbols = Vec::with_capacity(obj.symbols.len());
|
||||
for (symbol_idx, symbol) in obj.symbols.iter().enumerate() {
|
||||
let symbol_diff = &diff.symbols[symbol_idx];
|
||||
if symbol.size == 0 || symbol.flags.contains(SymbolFlag::Ignored) {
|
||||
continue;
|
||||
}
|
||||
symbols.push(DiffSymbol::new(obj, symbol_idx, symbol, symbol_diff, diff_config)?);
|
||||
}
|
||||
|
||||
Ok(Self { sections, symbols })
|
||||
}
|
||||
}
|
||||
|
||||
impl DiffSection {
|
||||
pub fn new(obj: &Object, section: &obj::Section, section_diff: &diff::SectionDiff) -> Self {
|
||||
Self {
|
||||
name: section.name.clone(),
|
||||
kind: DiffSectionKind::from(section.kind) as i32,
|
||||
size: section.size,
|
||||
address: section.address,
|
||||
match_percent: section_diff.match_percent,
|
||||
data_diff: section_diff.data_diff.iter().map(DiffDataSegment::from).collect(),
|
||||
reloc_diff: section_diff
|
||||
.reloc_diff
|
||||
.iter()
|
||||
.map(|r| DiffDataRelocation::new(obj, r))
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<obj::SectionKind> for DiffSectionKind {
|
||||
fn from(value: obj::SectionKind) -> Self {
|
||||
match value {
|
||||
obj::SectionKind::Unknown => DiffSectionKind::SectionUnknown,
|
||||
obj::SectionKind::Code => DiffSectionKind::SectionCode,
|
||||
obj::SectionKind::Data => DiffSectionKind::SectionData,
|
||||
obj::SectionKind::Bss => DiffSectionKind::SectionBss,
|
||||
obj::SectionKind::Common => DiffSectionKind::SectionCommon,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DiffSymbol {
|
||||
pub fn new(
|
||||
obj: &Object,
|
||||
symbol_idx: usize,
|
||||
symbol: &obj::Symbol,
|
||||
symbol_diff: &diff::SymbolDiff,
|
||||
diff_config: &DiffObjConfig,
|
||||
) -> Result<Self> {
|
||||
// Convert instruction rows
|
||||
let instructions = symbol_diff
|
||||
.instruction_rows
|
||||
.iter()
|
||||
.map(|row| DiffInstructionRow::new(obj, symbol_idx, row, diff_config))
|
||||
.collect::<Result<Vec<_>>>()?;
|
||||
|
||||
// Convert data diff - flatten DataDiffRow segments into a single list
|
||||
let data_diff: Vec<DiffDataSegment> = symbol_diff
|
||||
.data_rows
|
||||
.iter()
|
||||
.flat_map(|row| row.segments.iter().map(DiffDataSegment::from))
|
||||
.collect();
|
||||
|
||||
Ok(Self {
|
||||
// Symbol metadata
|
||||
name: symbol.name.clone(),
|
||||
demangled_name: symbol.demangled_name.clone(),
|
||||
address: symbol.address,
|
||||
size: symbol.size,
|
||||
flags: symbol_flags(&symbol.flags),
|
||||
// Diff information
|
||||
target_symbol: symbol_diff.target_symbol.map(|i| i as u32),
|
||||
match_percent: symbol_diff.match_percent,
|
||||
instructions,
|
||||
data_diff,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn symbol_flags(flags: &obj::SymbolFlagSet) -> u32 {
|
||||
let mut result = 0u32;
|
||||
if flags.contains(SymbolFlag::Global) {
|
||||
result |= DiffSymbolFlag::SymbolGlobal as u32;
|
||||
}
|
||||
if flags.contains(SymbolFlag::Local) {
|
||||
result |= DiffSymbolFlag::SymbolLocal as u32;
|
||||
}
|
||||
if flags.contains(SymbolFlag::Weak) {
|
||||
result |= DiffSymbolFlag::SymbolWeak as u32;
|
||||
}
|
||||
if flags.contains(SymbolFlag::Common) {
|
||||
result |= DiffSymbolFlag::SymbolCommon as u32;
|
||||
}
|
||||
if flags.contains(SymbolFlag::Hidden) {
|
||||
result |= DiffSymbolFlag::SymbolHidden as u32;
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
impl DiffInstructionRow {
|
||||
pub fn new(
|
||||
obj: &Object,
|
||||
symbol_idx: usize,
|
||||
row: &diff::InstructionDiffRow,
|
||||
diff_config: &DiffObjConfig,
|
||||
) -> Result<Self> {
|
||||
let instruction = if let Some(ins_ref) = row.ins_ref {
|
||||
let resolved = obj.resolve_instruction_ref(symbol_idx, ins_ref);
|
||||
resolved.map(|r| DiffInstruction::new(obj, r, diff_config)).transpose()?
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let arg_diff =
|
||||
row.arg_diff.iter().map(|d| DiffInstructionArgDiff { diff_index: d.get() }).collect();
|
||||
|
||||
Ok(Self { diff_kind: DiffKind::from(row.kind) as i32, instruction, arg_diff })
|
||||
}
|
||||
}
|
||||
|
||||
impl DiffInstruction {
|
||||
pub fn new(
|
||||
obj: &Object,
|
||||
resolved: obj::ResolvedInstructionRef,
|
||||
diff_config: &DiffObjConfig,
|
||||
) -> Result<Self> {
|
||||
let mut formatted = String::new();
|
||||
let mut parts = vec![];
|
||||
let separator = diff_config.separator();
|
||||
|
||||
// Use the arch's display_instruction to get formatted parts
|
||||
obj.arch.display_instruction(resolved, diff_config, &mut |part| {
|
||||
write_instruction_part(&mut formatted, &part, separator, resolved.relocation);
|
||||
parts
|
||||
.push(DiffInstructionPart { part: Some(diff_instruction_part::Part::from(&part)) });
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
let relocation = resolved.relocation.map(|r| DiffRelocation::new(obj, r));
|
||||
|
||||
let line_number = resolved
|
||||
.section
|
||||
.line_info
|
||||
.range(..=resolved.ins_ref.address)
|
||||
.last()
|
||||
.map(|(_, &line)| line);
|
||||
|
||||
Ok(Self {
|
||||
address: resolved.ins_ref.address,
|
||||
size: resolved.ins_ref.size as u32,
|
||||
formatted,
|
||||
parts,
|
||||
relocation,
|
||||
branch_dest: resolved.ins_ref.branch_dest,
|
||||
line_number,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn write_instruction_part(
|
||||
out: &mut String,
|
||||
part: &InstructionPart,
|
||||
separator: &str,
|
||||
reloc: Option<obj::ResolvedRelocation>,
|
||||
) {
|
||||
match part {
|
||||
InstructionPart::Basic(s) => out.push_str(s),
|
||||
InstructionPart::Opcode(s, _) => {
|
||||
out.push_str(s);
|
||||
out.push(' ');
|
||||
}
|
||||
InstructionPart::Arg(arg) => match arg {
|
||||
obj::InstructionArg::Value(v) => {
|
||||
let _ = write!(out, "{}", v);
|
||||
}
|
||||
obj::InstructionArg::Reloc => {
|
||||
if let Some(resolved) = reloc {
|
||||
out.push_str(&resolved.symbol.name);
|
||||
if resolved.relocation.addend != 0 {
|
||||
if resolved.relocation.addend < 0 {
|
||||
let _ = write!(out, "-{:#x}", -resolved.relocation.addend);
|
||||
} else {
|
||||
let _ = write!(out, "+{:#x}", resolved.relocation.addend);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
obj::InstructionArg::BranchDest(dest) => {
|
||||
let _ = write!(out, "{:#x}", dest);
|
||||
}
|
||||
},
|
||||
InstructionPart::Separator => out.push_str(separator),
|
||||
}
|
||||
}
|
||||
|
||||
impl diff_instruction_part::Part {
|
||||
fn from(part: &InstructionPart) -> Self {
|
||||
match part {
|
||||
InstructionPart::Basic(s) => diff_instruction_part::Part::Basic(s.to_string()),
|
||||
InstructionPart::Opcode(mnemonic, opcode) => {
|
||||
diff_instruction_part::Part::Opcode(DiffOpcode {
|
||||
mnemonic: mnemonic.to_string(),
|
||||
opcode: *opcode as u32,
|
||||
})
|
||||
}
|
||||
InstructionPart::Arg(arg) => {
|
||||
diff_instruction_part::Part::Arg(DiffInstructionArg::from(arg))
|
||||
}
|
||||
InstructionPart::Separator => diff_instruction_part::Part::Separator(true),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&obj::InstructionArg<'_>> for DiffInstructionArg {
|
||||
fn from(arg: &obj::InstructionArg) -> Self {
|
||||
let arg = match arg {
|
||||
obj::InstructionArg::Value(v) => match v {
|
||||
obj::InstructionArgValue::Signed(v) => diff_instruction_arg::Arg::Signed(*v),
|
||||
obj::InstructionArgValue::Unsigned(v) => diff_instruction_arg::Arg::Unsigned(*v),
|
||||
obj::InstructionArgValue::Opaque(v) => {
|
||||
diff_instruction_arg::Arg::Opaque(v.to_string())
|
||||
}
|
||||
},
|
||||
obj::InstructionArg::Reloc => diff_instruction_arg::Arg::Reloc(true),
|
||||
obj::InstructionArg::BranchDest(dest) => diff_instruction_arg::Arg::BranchDest(*dest),
|
||||
};
|
||||
DiffInstructionArg { arg: Some(arg) }
|
||||
}
|
||||
}
|
||||
|
||||
impl DiffRelocation {
|
||||
pub fn new(obj: &Object, resolved: obj::ResolvedRelocation) -> Self {
|
||||
let type_val = relocation_type(resolved.relocation.flags);
|
||||
let type_name = obj
|
||||
.arch
|
||||
.reloc_name(resolved.relocation.flags)
|
||||
.map(|s| s.to_string())
|
||||
.unwrap_or_default();
|
||||
Self {
|
||||
r#type: type_val,
|
||||
type_name,
|
||||
target_symbol: resolved.relocation.target_symbol as u32,
|
||||
addend: resolved.relocation.addend,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn relocation_type(flags: obj::RelocationFlags) -> u32 {
|
||||
match flags {
|
||||
obj::RelocationFlags::Elf(r_type) => r_type,
|
||||
obj::RelocationFlags::Coff(typ) => typ as u32,
|
||||
}
|
||||
}
|
||||
|
||||
impl From<diff::InstructionDiffKind> for DiffKind {
|
||||
fn from(value: diff::InstructionDiffKind) -> Self {
|
||||
match value {
|
||||
diff::InstructionDiffKind::None => DiffKind::DiffNone,
|
||||
diff::InstructionDiffKind::OpMismatch => DiffKind::DiffOpMismatch,
|
||||
diff::InstructionDiffKind::ArgMismatch => DiffKind::DiffArgMismatch,
|
||||
diff::InstructionDiffKind::Replace => DiffKind::DiffReplace,
|
||||
diff::InstructionDiffKind::Delete => DiffKind::DiffDelete,
|
||||
diff::InstructionDiffKind::Insert => DiffKind::DiffInsert,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<diff::DataDiffKind> for DiffKind {
|
||||
fn from(value: diff::DataDiffKind) -> Self {
|
||||
match value {
|
||||
diff::DataDiffKind::None => DiffKind::DiffNone,
|
||||
diff::DataDiffKind::Replace => DiffKind::DiffReplace,
|
||||
diff::DataDiffKind::Delete => DiffKind::DiffDelete,
|
||||
diff::DataDiffKind::Insert => DiffKind::DiffInsert,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&diff::DataDiff> for DiffDataSegment {
|
||||
fn from(value: &diff::DataDiff) -> Self {
|
||||
Self {
|
||||
kind: DiffKind::from(value.kind) as i32,
|
||||
data: value.data.clone(),
|
||||
size: value.size as u64,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DiffDataRelocation {
|
||||
pub fn new(obj: &Object, value: &diff::DataRelocationDiff) -> Self {
|
||||
let type_val = relocation_type(value.reloc.flags);
|
||||
let type_name =
|
||||
obj.arch.reloc_name(value.reloc.flags).map(|s| s.to_string()).unwrap_or_default();
|
||||
Self {
|
||||
relocation: Some(DiffRelocation {
|
||||
r#type: type_val,
|
||||
type_name,
|
||||
target_symbol: value.reloc.target_symbol as u32,
|
||||
addend: value.reloc.addend,
|
||||
}),
|
||||
kind: DiffKind::from(value.kind) as i32,
|
||||
start: value.range.start,
|
||||
end: value.range.end,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1 +1,3 @@
|
||||
#[cfg(feature = "any-arch")]
|
||||
pub mod diff;
|
||||
pub mod report;
|
||||
|
||||
@@ -35,31 +35,13 @@ pub fn diff_bss_symbol(
|
||||
))
|
||||
}
|
||||
|
||||
pub fn symbol_name_matches(left_name: &str, right_name: &str) -> bool {
|
||||
if let Some((left_prefix, left_suffix)) = left_name.split_once("@class$")
|
||||
&& let Some((right_prefix, right_suffix)) = right_name.split_once("@class$")
|
||||
pub fn symbol_name_matches(left: &Symbol, right: &Symbol) -> bool {
|
||||
if let Some(left_name) = &left.normalized_name
|
||||
&& let Some(right_name) = &right.normalized_name
|
||||
{
|
||||
// Match Metrowerks anonymous class symbol names, ignoring the unique ID.
|
||||
// e.g. __dt__Q29dCamera_c23@class$3665d_camera_cppFv
|
||||
if left_prefix == right_prefix
|
||||
&& let Some(left_idx) = left_suffix.chars().position(|c| !c.is_numeric())
|
||||
&& let Some(right_idx) = right_suffix.chars().position(|c| !c.is_numeric())
|
||||
{
|
||||
// e.g. d_camera_cppFv (after the unique ID)
|
||||
left_suffix[left_idx..] == right_suffix[right_idx..]
|
||||
} else {
|
||||
false
|
||||
}
|
||||
} else if let Some((prefix, suffix)) = left_name.split_once(['$', '.'])
|
||||
&& suffix.chars().all(char::is_numeric)
|
||||
{
|
||||
// Match Metrowerks symbol$1234 against symbol$2345
|
||||
// and GCC symbol.1234 against symbol.2345
|
||||
right_name
|
||||
.split_once(['$', '.'])
|
||||
.is_some_and(|(p, s)| p == prefix && s.chars().all(char::is_numeric))
|
||||
} else {
|
||||
left_name == right_name
|
||||
} else {
|
||||
left.name == right.name
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,7 +55,7 @@ fn reloc_eq(
|
||||
return false;
|
||||
}
|
||||
|
||||
let symbol_name_addend_matches = symbol_name_matches(&left.symbol.name, &right.symbol.name)
|
||||
let symbol_name_addend_matches = symbol_name_matches(left.symbol, right.symbol)
|
||||
&& left.relocation.addend == right.relocation.addend;
|
||||
match (left.symbol.section, right.symbol.section) {
|
||||
(Some(sl), Some(sr)) => {
|
||||
|
||||
@@ -298,9 +298,8 @@ pub fn display_row(
|
||||
}
|
||||
})?;
|
||||
// Fallback for relocation that wasn't displayed
|
||||
if resolved.relocation.is_some() && !displayed_relocation {
|
||||
if !displayed_relocation && let Some(resolved) = resolved.relocation {
|
||||
cb(DiffTextSegment::basic(" <", base_color))?;
|
||||
let resolved = resolved.relocation.unwrap();
|
||||
let diff_index = ins_row.arg_diff.get(arg_idx).copied().unwrap_or_default();
|
||||
let color =
|
||||
diff_index.get().map_or(DiffTextColor::Bright, |i| DiffTextColor::Rotating(i as u8));
|
||||
@@ -813,19 +812,15 @@ pub fn display_sections(
|
||||
}
|
||||
let section_diff = &diff.sections[section_idx];
|
||||
let reverse_fn_order = section.kind == SectionKind::Code && reverse_fn_order;
|
||||
symbols.sort_by(|a, b| {
|
||||
let a = &obj.symbols[a.symbol];
|
||||
let b = &obj.symbols[b.symbol];
|
||||
section_symbol_sort(a, b)
|
||||
.then_with(|| {
|
||||
if reverse_fn_order {
|
||||
b.address.cmp(&a.address)
|
||||
} else {
|
||||
a.address.cmp(&b.address)
|
||||
}
|
||||
})
|
||||
.then_with(|| a.size.cmp(&b.size))
|
||||
});
|
||||
if reverse_fn_order {
|
||||
symbols.sort_by(|a, b| {
|
||||
let a = &obj.symbols[a.symbol];
|
||||
let b = &obj.symbols[b.symbol];
|
||||
section_symbol_sort(a, b)
|
||||
.then_with(|| b.address.cmp(&a.address))
|
||||
.then_with(|| a.size.cmp(&b.size))
|
||||
});
|
||||
}
|
||||
sections.push(SectionDisplay {
|
||||
id: section.id.clone(),
|
||||
name: if section.flags.contains(SectionFlag::Combined) {
|
||||
|
||||
@@ -7,7 +7,6 @@ use alloc::{
|
||||
use core::{num::NonZeroU32, ops::Range};
|
||||
|
||||
use anyhow::Result;
|
||||
use itertools::Itertools;
|
||||
|
||||
use crate::{
|
||||
diff::{
|
||||
@@ -687,18 +686,6 @@ fn symbol_section_kind(obj: &Object, symbol: &Symbol) -> SectionKind {
|
||||
}
|
||||
}
|
||||
|
||||
/// Check if a symbol is a compiler-generated like @1234 or _$E1234.
|
||||
fn is_symbol_compiler_generated(symbol: &Symbol) -> bool {
|
||||
if symbol.name.starts_with('@') && symbol.name[1..].chars().all(char::is_numeric) {
|
||||
// Exclude @stringBase0, @GUARD@, etc.
|
||||
return true;
|
||||
}
|
||||
if symbol.name.starts_with("_$E") && symbol.name[3..].chars().all(char::is_numeric) {
|
||||
return true;
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
fn find_symbol(
|
||||
obj: Option<&Object>,
|
||||
in_obj: &Object,
|
||||
@@ -712,7 +699,7 @@ fn find_symbol(
|
||||
|
||||
// Match compiler-generated symbols against each other (e.g. @251 -> @60)
|
||||
// If they are in the same section and have the same value
|
||||
if is_symbol_compiler_generated(in_symbol)
|
||||
if in_symbol.flags.contains(SymbolFlag::CompilerGenerated)
|
||||
&& matches!(section_kind, SectionKind::Code | SectionKind::Data | SectionKind::Bss)
|
||||
{
|
||||
let mut closest_match_symbol_idx = None;
|
||||
@@ -724,7 +711,7 @@ fn find_symbol(
|
||||
if obj.sections[section_index].name != section_name {
|
||||
continue;
|
||||
}
|
||||
if !is_symbol_compiler_generated(symbol) {
|
||||
if !symbol.flags.contains(SymbolFlag::CompilerGenerated) {
|
||||
continue;
|
||||
}
|
||||
match section_kind {
|
||||
@@ -761,15 +748,11 @@ fn find_symbol(
|
||||
}
|
||||
|
||||
// Try to find a symbol with a matching name
|
||||
if let Some((symbol_idx, _)) = unmatched_symbols(obj, used)
|
||||
.filter(|&(_, symbol)| {
|
||||
symbol_name_matches(&in_symbol.name, &symbol.name)
|
||||
&& symbol_section_kind(obj, symbol) == section_kind
|
||||
&& symbol_section(obj, symbol).is_some_and(|(name, _)| name == section_name)
|
||||
})
|
||||
.sorted_unstable_by_key(|&(_, symbol)| (symbol.section, symbol.address))
|
||||
.next()
|
||||
{
|
||||
if let Some((symbol_idx, _)) = unmatched_symbols(obj, used).find(|&(_, symbol)| {
|
||||
symbol_name_matches(in_symbol, symbol)
|
||||
&& symbol_section_kind(obj, symbol) == section_kind
|
||||
&& symbol_section(obj, symbol).is_some_and(|(name, _)| name == section_name)
|
||||
}) {
|
||||
return Some(symbol_idx);
|
||||
}
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ pub enum SectionKind {
|
||||
|
||||
flags! {
|
||||
#[derive(Hash)]
|
||||
pub enum SymbolFlag: u8 {
|
||||
pub enum SymbolFlag: u16 {
|
||||
Global,
|
||||
Local,
|
||||
Weak,
|
||||
@@ -50,6 +50,8 @@ flags! {
|
||||
SizeInferred,
|
||||
/// Symbol should be ignored by any diffing
|
||||
Ignored,
|
||||
/// Symbol name is compiler-generated; compare by value instead of name
|
||||
CompilerGenerated,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -264,6 +266,7 @@ pub trait FlowAnalysisResult: core::fmt::Debug + Send {
|
||||
pub struct Symbol {
|
||||
pub name: String,
|
||||
pub demangled_name: Option<String>,
|
||||
pub normalized_name: Option<String>,
|
||||
pub address: u64,
|
||||
pub size: u64,
|
||||
pub kind: SymbolKind,
|
||||
@@ -403,6 +406,7 @@ pub struct ResolvedInstructionRef<'obj> {
|
||||
static DUMMY_SYMBOL: Symbol = Symbol {
|
||||
name: String::new(),
|
||||
demangled_name: None,
|
||||
normalized_name: None,
|
||||
address: 0,
|
||||
size: 0,
|
||||
kind: SymbolKind::Unknown,
|
||||
|
||||
+119
-46
@@ -3,6 +3,7 @@ use alloc::{
|
||||
collections::BTreeMap,
|
||||
format,
|
||||
string::{String, ToString},
|
||||
vec,
|
||||
vec::Vec,
|
||||
};
|
||||
use core::{cmp::Ordering, num::NonZeroU64};
|
||||
@@ -35,6 +36,67 @@ fn map_section_kind(section: &object::Section) -> SectionKind {
|
||||
}
|
||||
}
|
||||
|
||||
/// Check if a symbol's name is partially compiler-generated, and if so normalize it for pairing.
|
||||
/// e.g. symbol$1234 and symbol$2345 will both be replaced with symbol$0000 internally.
|
||||
fn get_normalized_symbol_name(name: &str) -> Option<String> {
|
||||
const DUMMY_UNIQUE_ID: &str = "0000";
|
||||
const DUMMY_UNIQUE_MSVC_ID: &str = "00000000";
|
||||
if let Some((prefix, suffix)) = name.split_once("@class$")
|
||||
&& let Some(idx) = suffix.chars().position(|c| !c.is_numeric())
|
||||
&& idx > 0
|
||||
{
|
||||
// Match Metrowerks anonymous class symbol names, ignoring the unique ID.
|
||||
// e.g. __dt__Q29dCamera_c23@class$3665d_camera_cppFv
|
||||
// and: __dt__Q29dCamera_c23@class$1727d_camera_cppFv
|
||||
let suffix = &suffix[idx..];
|
||||
Some(format!("{prefix}@class${DUMMY_UNIQUE_ID}{suffix}"))
|
||||
} else if let Some((prefix, suffix)) = name.split_once('$')
|
||||
&& suffix.chars().all(char::is_numeric)
|
||||
{
|
||||
// Match Metrowerks symbol$1234 against symbol$2345
|
||||
Some(format!("{prefix}${DUMMY_UNIQUE_ID}"))
|
||||
} else if let Some((prefix, suffix)) = name.split_once('.')
|
||||
&& suffix.chars().all(char::is_numeric)
|
||||
{
|
||||
// Match GCC symbol.1234 against symbol.2345
|
||||
Some(format!("{prefix}.{DUMMY_UNIQUE_ID}"))
|
||||
} else if name.starts_with('?') {
|
||||
// Match MSVC anonymous class symbol names, ignoring the unique ID.
|
||||
// e.g. ?CheckContextOr@?A0x24773155@@YA_NPBVDataArray@@@Z
|
||||
// and: ?CheckContextOr@?A0xddf6240c@@YA_NPBVDataArray@@@Z
|
||||
let mut name_str = String::from(name);
|
||||
let anon_indices: Vec<usize> = name_str.match_indices("?A0x").map(|(idx, _)| idx).collect();
|
||||
if !anon_indices.is_empty() {
|
||||
for idx in anon_indices {
|
||||
// the str sequence we're looking for is: ?A0xXXXXXXXX@@
|
||||
if u32::from_str_radix(&name_str[idx + 4..idx + 12], 16).is_ok()
|
||||
&& &name_str[idx + 12..idx + 14] == "@@"
|
||||
{
|
||||
// if the two above checks passed, we're good to replace the hash
|
||||
name_str.replace_range(idx + 4..idx + 12, DUMMY_UNIQUE_MSVC_ID);
|
||||
}
|
||||
}
|
||||
Some(name_str)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Check if a symbol's name is entirely compiler-generated, such as @1234 or _$E1234.
|
||||
/// This enables pairing these symbols up by their value instead of their name.
|
||||
fn is_symbol_name_compiler_generated(name: &str) -> bool {
|
||||
if name.starts_with('@') && name[1..].chars().all(char::is_numeric) {
|
||||
// Exclude @stringBase0, @GUARD@, etc.
|
||||
return true;
|
||||
} else if name.starts_with("_$E") && name[3..].chars().all(char::is_numeric) {
|
||||
return true;
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
fn map_symbol(
|
||||
arch: &dyn Arch,
|
||||
file: &object::File,
|
||||
@@ -97,10 +159,15 @@ fn map_symbol(
|
||||
.and_then(|m| m.virtual_addresses.as_ref())
|
||||
.and_then(|v| v.get(symbol.index().0).cloned());
|
||||
let section = symbol.section_index().and_then(|i| section_indices.get(i.0).copied());
|
||||
let normalized_name = get_normalized_symbol_name(&name);
|
||||
if is_symbol_name_compiler_generated(&name) {
|
||||
flags |= SymbolFlag::CompilerGenerated;
|
||||
}
|
||||
|
||||
Ok(Symbol {
|
||||
name,
|
||||
demangled_name,
|
||||
normalized_name,
|
||||
address,
|
||||
size,
|
||||
kind,
|
||||
@@ -119,13 +186,38 @@ fn map_symbols(
|
||||
split_meta: Option<&SplitMeta>,
|
||||
config: &DiffObjConfig,
|
||||
) -> Result<(Vec<Symbol>, Vec<usize>)> {
|
||||
let symbol_count = obj_file.symbols().count();
|
||||
let mut symbols = Vec::<Symbol>::with_capacity(symbol_count + obj_file.sections().count());
|
||||
let mut symbol_indices = Vec::<usize>::with_capacity(symbol_count + 1);
|
||||
for obj_symbol in obj_file.symbols() {
|
||||
if symbol_indices.len() <= obj_symbol.index().0 {
|
||||
symbol_indices.resize(obj_symbol.index().0 + 1, usize::MAX);
|
||||
}
|
||||
// symbols() is not guaranteed to be sorted by address.
|
||||
// We sort it here to fix pairing bugs with diff algorithms that assume the symbols are ordered.
|
||||
// Sorting everything here once is less expensive than sorting subsets later in expensive loops.
|
||||
let mut max_index = 0;
|
||||
let mut obj_symbols = obj_file
|
||||
.symbols()
|
||||
.filter(|s| s.kind() != object::SymbolKind::File)
|
||||
.inspect(|sym| max_index = max_index.max(sym.index().0))
|
||||
.collect::<Vec<_>>();
|
||||
obj_symbols.sort_by(|a, b| {
|
||||
// Sort symbols by section index, placing absolute symbols last
|
||||
a.section_index()
|
||||
.map_or(usize::MAX, |s| s.0)
|
||||
.cmp(&b.section_index().map_or(usize::MAX, |s| s.0))
|
||||
.then_with(|| {
|
||||
// Sort section symbols first in a section
|
||||
if a.kind() == object::SymbolKind::Section {
|
||||
Ordering::Less
|
||||
} else if b.kind() == object::SymbolKind::Section {
|
||||
Ordering::Greater
|
||||
} else {
|
||||
Ordering::Equal
|
||||
}
|
||||
})
|
||||
// Sort by address within section
|
||||
.then_with(|| a.address().cmp(&b.address()))
|
||||
// If there are multiple symbols with the same address, smaller symbol first
|
||||
.then_with(|| a.size().cmp(&b.size()))
|
||||
});
|
||||
let mut symbols = Vec::<Symbol>::with_capacity(obj_symbols.len() + obj_file.sections().count());
|
||||
let mut symbol_indices = vec![usize::MAX; max_index + 1];
|
||||
for obj_symbol in obj_symbols {
|
||||
let symbol = map_symbol(arch, obj_file, &obj_symbol, section_indices, split_meta, config)?;
|
||||
symbol_indices[obj_symbol.index().0] = symbols.len();
|
||||
symbols.push(symbol);
|
||||
@@ -172,6 +264,7 @@ fn add_section_symbols(sections: &[Section], symbols: &mut Vec<Symbol>) {
|
||||
symbols.push(Symbol {
|
||||
name,
|
||||
demangled_name: None,
|
||||
normalized_name: None,
|
||||
address: 0,
|
||||
size,
|
||||
kind: SymbolKind::Section,
|
||||
@@ -193,40 +286,18 @@ fn is_local_label(symbol: &Symbol) -> bool {
|
||||
}
|
||||
|
||||
fn infer_symbol_sizes(arch: &dyn Arch, symbols: &mut [Symbol], sections: &[Section]) -> Result<()> {
|
||||
// Create a sorted list of symbol indices by section
|
||||
let mut symbols_with_section = Vec::<usize>::with_capacity(symbols.len());
|
||||
for (i, symbol) in symbols.iter().enumerate() {
|
||||
if symbol.section.is_some() {
|
||||
symbols_with_section.push(i);
|
||||
}
|
||||
}
|
||||
symbols_with_section.sort_by(|a, b| {
|
||||
let a = &symbols[*a];
|
||||
let b = &symbols[*b];
|
||||
a.section
|
||||
.unwrap_or(usize::MAX)
|
||||
.cmp(&b.section.unwrap_or(usize::MAX))
|
||||
.then_with(|| {
|
||||
// Sort section symbols first
|
||||
if a.kind == SymbolKind::Section {
|
||||
Ordering::Less
|
||||
} else if b.kind == SymbolKind::Section {
|
||||
Ordering::Greater
|
||||
} else {
|
||||
Ordering::Equal
|
||||
}
|
||||
})
|
||||
.then_with(|| a.address.cmp(&b.address))
|
||||
.then_with(|| a.size.cmp(&b.size))
|
||||
});
|
||||
// Above, we've sorted the symbols by section and then by address.
|
||||
|
||||
// Set symbol sizes based on the next symbol's address
|
||||
let mut iter_idx = 0;
|
||||
let mut last_end = (0, 0);
|
||||
while iter_idx < symbols_with_section.len() {
|
||||
let symbol_idx = symbols_with_section[iter_idx];
|
||||
while iter_idx < symbols.len() {
|
||||
let symbol_idx = iter_idx;
|
||||
let symbol = &symbols[symbol_idx];
|
||||
let section_idx = symbol.section.unwrap();
|
||||
let Some(section_idx) = symbol.section else {
|
||||
// Start of absolute symbols
|
||||
break;
|
||||
};
|
||||
iter_idx += 1;
|
||||
if symbol.size != 0 {
|
||||
if symbol.kind != SymbolKind::Section {
|
||||
@@ -239,10 +310,9 @@ fn infer_symbol_sizes(arch: &dyn Arch, symbols: &mut [Symbol], sections: &[Secti
|
||||
continue;
|
||||
}
|
||||
let next_symbol = loop {
|
||||
if iter_idx >= symbols_with_section.len() {
|
||||
let Some(next_symbol) = symbols.get(iter_idx) else {
|
||||
break None;
|
||||
}
|
||||
let next_symbol = &symbols[symbols_with_section[iter_idx]];
|
||||
};
|
||||
if next_symbol.section != Some(section_idx) {
|
||||
break None;
|
||||
}
|
||||
@@ -298,9 +368,11 @@ fn map_sections(
|
||||
split_meta: Option<&SplitMeta>,
|
||||
) -> Result<(Vec<Section>, Vec<usize>)> {
|
||||
let mut section_names = BTreeMap::<String, usize>::new();
|
||||
let section_count = obj_file.sections().count();
|
||||
let mut max_index = 0;
|
||||
let section_count =
|
||||
obj_file.sections().inspect(|s| max_index = max_index.max(s.index().0)).count();
|
||||
let mut result = Vec::<Section>::with_capacity(section_count);
|
||||
let mut section_indices = Vec::<usize>::with_capacity(section_count + 1);
|
||||
let mut section_indices = vec![usize::MAX; max_index + 1];
|
||||
for section in obj_file.sections() {
|
||||
let name = section.name().context("Failed to process section name")?;
|
||||
let kind = map_section_kind(§ion);
|
||||
@@ -325,9 +397,6 @@ fn map_sections(
|
||||
let id = format!("{name}-{unique_id}");
|
||||
*unique_id += 1;
|
||||
|
||||
if section_indices.len() <= section.index().0 {
|
||||
section_indices.resize(section.index().0 + 1, usize::MAX);
|
||||
}
|
||||
section_indices[section.index().0] = result.len();
|
||||
result.push(Section {
|
||||
id,
|
||||
@@ -826,8 +895,12 @@ fn combine_sections(
|
||||
let mut data_sections = BTreeMap::<String, Vec<usize>>::new();
|
||||
let mut text_sections = BTreeMap::<String, Vec<usize>>::new();
|
||||
for (i, section) in sections.iter().enumerate() {
|
||||
let base_name =
|
||||
if let Some(i) = section.name.rfind('$') { §ion.name[..i] } else { §ion.name };
|
||||
let base_name = section
|
||||
.name
|
||||
.get(1..)
|
||||
.and_then(|s| s.rfind(['$', '.']))
|
||||
.and_then(|i| section.name.get(..i + 1))
|
||||
.unwrap_or(§ion.name);
|
||||
match section.kind {
|
||||
SectionKind::Data | SectionKind::Bss => {
|
||||
data_sections.entry(base_name.to_string()).or_default().push(i);
|
||||
|
||||
@@ -114,6 +114,7 @@ expression: "(sections, symbols)"
|
||||
Symbol {
|
||||
name: ".data",
|
||||
demangled_name: None,
|
||||
normalized_name: None,
|
||||
address: 0,
|
||||
size: 0,
|
||||
kind: Section,
|
||||
@@ -127,6 +128,7 @@ expression: "(sections, symbols)"
|
||||
Symbol {
|
||||
name: "symbol",
|
||||
demangled_name: None,
|
||||
normalized_name: None,
|
||||
address: 4,
|
||||
size: 4,
|
||||
kind: Object,
|
||||
@@ -140,6 +142,7 @@ expression: "(sections, symbols)"
|
||||
Symbol {
|
||||
name: "function",
|
||||
demangled_name: None,
|
||||
normalized_name: None,
|
||||
address: 0,
|
||||
size: 8,
|
||||
kind: Function,
|
||||
@@ -153,6 +156,7 @@ expression: "(sections, symbols)"
|
||||
Symbol {
|
||||
name: ".data",
|
||||
demangled_name: None,
|
||||
normalized_name: None,
|
||||
address: 0,
|
||||
size: 0,
|
||||
kind: Unknown,
|
||||
|
||||
@@ -4,4 +4,4 @@ expression: output
|
||||
---
|
||||
[(Line(90), Dim, 5), (Address(0), Dim, 5), (Spacing(4), Normal, 0), (Opcode("ldr", 32792), Normal, 10), (Argument(Opaque("r12")), Normal, 0), (Basic(", "), Normal, 0), (Basic("["), Normal, 0), (Argument(Opaque("pc")), Normal, 0), (Basic(", "), Normal, 0), (Basic("#"), Normal, 0), (Argument(Signed(0)), Normal, 0), (Basic("]"), Normal, 0), (Basic(" (->"), Normal, 0), (BranchDest(8), Normal, 0), (Basic(")"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Line(90), Dim, 5), (Address(4), Dim, 5), (Spacing(4), Normal, 0), (Opcode("bx", 32777), Normal, 10), (Argument(Opaque("r12")), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Line(90), Dim, 5), (Address(8), Dim, 5), (Spacing(4), Normal, 0), (Opcode(".word", 65534), Normal, 10), (Symbol(Symbol { name: "esEnemyDraw", demangled_name: None, address: 0, size: 0, kind: Unknown, section: None, flags: FlagSet(Global), align: None, virtual_address: None }), Bright, 0), (Eol, Normal, 0)]
|
||||
[(Line(90), Dim, 5), (Address(8), Dim, 5), (Spacing(4), Normal, 0), (Opcode(".word", 65534), Normal, 10), (Symbol(Symbol { name: "esEnemyDraw", demangled_name: None, normalized_name: None, address: 0, size: 0, kind: Unknown, section: None, flags: FlagSet(Global), align: None, virtual_address: None }), Bright, 0), (Eol, Normal, 0)]
|
||||
|
||||
@@ -5,7 +5,7 @@ expression: output
|
||||
[(Address(0), Dim, 5), (Spacing(4), Normal, 0), (Opcode("stmdb", 32883), Normal, 10), (Argument(Opaque("sp")), Normal, 0), (Basic("!"), Normal, 0), (Basic(", "), Normal, 0), (Basic("{"), Normal, 0), (Argument(Opaque("r4")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r5")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r6")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("lr")), Normal, 0), (Basic("}"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(4), Dim, 5), (Spacing(4), Normal, 0), (Opcode("mov", 32811), Normal, 10), (Argument(Opaque("r5")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r0")), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(8), Dim, 5), (Spacing(4), Normal, 0), (Opcode("mov", 32811), Normal, 10), (Argument(Opaque("r4")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r1")), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(12), Dim, 5), (Spacing(4), Normal, 0), (Opcode("bl", 32775), Normal, 10), (Symbol(Symbol { name: "_ZN13LinkStateBase12OnStateLeaveEi", demangled_name: Some("LinkStateBase::OnStateLeave(int)"), address: 0, size: 0, kind: Unknown, section: None, flags: FlagSet(Global | Weak), align: None, virtual_address: None }), Bright, 0), (Addend(-8), Bright, 0), (Eol, Normal, 0)]
|
||||
[(Address(12), Dim, 5), (Spacing(4), Normal, 0), (Opcode("bl", 32775), Normal, 10), (Symbol(Symbol { name: "_ZN13LinkStateBase12OnStateLeaveEi", demangled_name: Some("LinkStateBase::OnStateLeave(int)"), normalized_name: None, address: 0, size: 0, kind: Unknown, section: None, flags: FlagSet(Global | Weak), align: None, virtual_address: None }), Bright, 0), (Addend(-8), Bright, 0), (Eol, Normal, 0)]
|
||||
[(Address(16), Dim, 5), (Spacing(4), Normal, 0), (Opcode("ldr", 32792), Normal, 10), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Basic("["), Normal, 0), (Argument(Opaque("r5")), Normal, 0), (Basic(", "), Normal, 0), (Basic("#"), Normal, 0), (Argument(Signed(20)), Normal, 0), (Basic("]"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(20), Dim, 5), (Spacing(4), Normal, 0), (Opcode("cmp", 32784), Normal, 10), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Basic("#"), Normal, 0), (Argument(Unsigned(10)), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(24), Dim, 5), (Spacing(4), Normal, 0), (Opcode("addls", 32769), Normal, 10), (Argument(Opaque("pc")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("pc")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("lsl")), Normal, 0), (Spacing(1), Normal, 0), (Basic("#"), Normal, 0), (Argument(Unsigned(2)), Normal, 0), (Eol, Normal, 0)]
|
||||
@@ -23,41 +23,41 @@ expression: output
|
||||
[(Address(72), Dim, 5), (Spacing(4), Normal, 0), (Opcode("b", 32772), Normal, 10), (BranchDest(164), Normal, 0), (BranchArrow(41), Rotating(6), 0), (Eol, Normal, 0)]
|
||||
[(Address(76), Dim, 5), (BranchArrow(15), Rotating(4), 0), (Opcode("ldr", 32792), Normal, 10), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Basic("["), Normal, 0), (Argument(Opaque("pc")), Normal, 0), (Basic(", "), Normal, 0), (Basic("#"), Normal, 0), (Argument(Signed(336)), Normal, 0), (Basic("]"), Normal, 0), (Basic(" (->"), Normal, 0), (BranchDest(420), Normal, 0), (Basic(")"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(80), Dim, 5), (Spacing(4), Normal, 0), (Opcode("ldr", 32792), Normal, 10), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Basic("["), Normal, 0), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Basic("#"), Normal, 0), (Argument(Signed(0)), Normal, 0), (Basic("]"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(84), Dim, 5), (Spacing(4), Normal, 0), (Opcode("bl", 32775), Normal, 10), (Symbol(Symbol { name: "_ZN18UnkStruct_027e103c19func_ov000_020cf01cEv", demangled_name: Some("UnkStruct_027e103c::func_ov000_020cf01c()"), address: 0, size: 0, kind: Unknown, section: None, flags: FlagSet(Global | Weak), align: None, virtual_address: None }), Bright, 0), (Addend(-8), Bright, 0), (Eol, Normal, 0)]
|
||||
[(Address(84), Dim, 5), (Spacing(4), Normal, 0), (Opcode("bl", 32775), Normal, 10), (Symbol(Symbol { name: "_ZN18UnkStruct_027e103c19func_ov000_020cf01cEv", demangled_name: Some("UnkStruct_027e103c::func_ov000_020cf01c()"), normalized_name: None, address: 0, size: 0, kind: Unknown, section: None, flags: FlagSet(Global | Weak), align: None, virtual_address: None }), Bright, 0), (Addend(-8), Bright, 0), (Eol, Normal, 0)]
|
||||
[(Address(88), Dim, 5), (Spacing(4), Normal, 0), (Opcode("ldrb", 32793), Normal, 10), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Basic("["), Normal, 0), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Basic("#"), Normal, 0), (Argument(Signed(224)), Normal, 0), (Basic("]"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(92), Dim, 5), (Spacing(4), Normal, 0), (Opcode("cmp", 32784), Normal, 10), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Basic("#"), Normal, 0), (Argument(Unsigned(0)), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(96), Dim, 5), (Spacing(4), Normal, 0), (Opcode("bne", 32772), Normal, 10), (BranchDest(108), Normal, 0), (BranchArrow(27), Rotating(7), 0), (Eol, Normal, 0)]
|
||||
[(Address(100), Dim, 5), (Spacing(4), Normal, 0), (Opcode("bl", 32775), Normal, 10), (BranchDest(424), Normal, 0), (BranchArrow(106), Rotating(8), 0), (Eol, Normal, 0)]
|
||||
[(Address(104), Dim, 5), (Spacing(4), Normal, 0), (Opcode("bl", 32775), Normal, 10), (Symbol(Symbol { name: "_ZN12EquipBombchu19func_ov014_0213ec64Ev", demangled_name: Some("EquipBombchu::func_ov014_0213ec64()"), address: 0, size: 0, kind: Unknown, section: None, flags: FlagSet(Global | Weak), align: None, virtual_address: None }), Bright, 0), (Addend(-8), Bright, 0), (Eol, Normal, 0)]
|
||||
[(Address(104), Dim, 5), (Spacing(4), Normal, 0), (Opcode("bl", 32775), Normal, 10), (Symbol(Symbol { name: "_ZN12EquipBombchu19func_ov014_0213ec64Ev", demangled_name: Some("EquipBombchu::func_ov014_0213ec64()"), normalized_name: None, address: 0, size: 0, kind: Unknown, section: None, flags: FlagSet(Global | Weak), align: None, virtual_address: None }), Bright, 0), (Addend(-8), Bright, 0), (Eol, Normal, 0)]
|
||||
[(Address(108), Dim, 5), (BranchArrow(24), Rotating(7), 0), (Opcode("ldr", 32792), Normal, 10), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Basic("["), Normal, 0), (Argument(Opaque("pc")), Normal, 0), (Basic(", "), Normal, 0), (Basic("#"), Normal, 0), (Argument(Signed(308)), Normal, 0), (Basic("]"), Normal, 0), (Basic(" (->"), Normal, 0), (BranchDest(424), Normal, 0), (Basic(")"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(112), Dim, 5), (Spacing(4), Normal, 0), (Opcode("ldr", 32792), Normal, 10), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Basic("["), Normal, 0), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Basic("#"), Normal, 0), (Argument(Signed(0)), Normal, 0), (Basic("]"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(116), Dim, 5), (Spacing(4), Normal, 0), (Opcode("blx", 32776), Normal, 10), (Symbol(Symbol { name: "_Z19func_ov014_0211fd04Pi", demangled_name: Some("func_ov014_0211fd04(int*)"), address: 0, size: 0, kind: Unknown, section: None, flags: FlagSet(Global | Weak), align: None, virtual_address: None }), Bright, 0), (Addend(-8), Bright, 0), (Eol, Normal, 0)]
|
||||
[(Address(116), Dim, 5), (Spacing(4), Normal, 0), (Opcode("blx", 32776), Normal, 10), (Symbol(Symbol { name: "_Z19func_ov014_0211fd04Pi", demangled_name: Some("func_ov014_0211fd04(int*)"), normalized_name: None, address: 0, size: 0, kind: Unknown, section: None, flags: FlagSet(Global | Weak), align: None, virtual_address: None }), Bright, 0), (Addend(-8), Bright, 0), (Eol, Normal, 0)]
|
||||
[(Address(120), Dim, 5), (Spacing(4), Normal, 0), (Opcode("b", 32772), Normal, 10), (BranchDest(200), Normal, 0), (BranchArrow(50), Rotating(0), 0), (Eol, Normal, 0)]
|
||||
[(Address(124), Dim, 5), (BranchArrow(12), Rotating(2), 0), (Opcode("mov", 32811), Normal, 10), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r5")), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(128), Dim, 5), (Spacing(4), Normal, 0), (Opcode("mov", 32811), Normal, 10), (Argument(Opaque("r1")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r4")), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(132), Dim, 5), (Spacing(4), Normal, 0), (Opcode("bl", 32775), Normal, 10), (Symbol(Symbol { name: "_ZN13LinkStateItem13StopUsingBombEi", demangled_name: Some("LinkStateItem::StopUsingBomb(int)"), address: 0, size: 0, kind: Unknown, section: None, flags: FlagSet(Global | Weak), align: None, virtual_address: None }), Bright, 0), (Addend(-8), Bright, 0), (Eol, Normal, 0)]
|
||||
[(Address(132), Dim, 5), (Spacing(4), Normal, 0), (Opcode("bl", 32775), Normal, 10), (Symbol(Symbol { name: "_ZN13LinkStateItem13StopUsingBombEi", demangled_name: Some("LinkStateItem::StopUsingBomb(int)"), normalized_name: None, address: 0, size: 0, kind: Unknown, section: None, flags: FlagSet(Global | Weak), align: None, virtual_address: None }), Bright, 0), (Addend(-8), Bright, 0), (Eol, Normal, 0)]
|
||||
[(Address(136), Dim, 5), (Spacing(4), Normal, 0), (Opcode("b", 32772), Normal, 10), (BranchDest(200), Normal, 0), (BranchArrow(50), Rotating(0), 0), (Eol, Normal, 0)]
|
||||
[(Address(140), Dim, 5), (BranchArrow(14), Rotating(3), 0), (Opcode("mov", 32811), Normal, 10), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r5")), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(144), Dim, 5), (Spacing(4), Normal, 0), (Opcode("bl", 32775), Normal, 10), (Symbol(Symbol { name: "_ZN13LinkStateItem13StopUsingRopeEv", demangled_name: Some("LinkStateItem::StopUsingRope()"), address: 0, size: 0, kind: Unknown, section: None, flags: FlagSet(Global | Weak), align: None, virtual_address: None }), Bright, 0), (Addend(-8), Bright, 0), (Eol, Normal, 0)]
|
||||
[(Address(144), Dim, 5), (Spacing(4), Normal, 0), (Opcode("bl", 32775), Normal, 10), (Symbol(Symbol { name: "_ZN13LinkStateItem13StopUsingRopeEv", demangled_name: Some("LinkStateItem::StopUsingRope()"), normalized_name: None, address: 0, size: 0, kind: Unknown, section: None, flags: FlagSet(Global | Weak), align: None, virtual_address: None }), Bright, 0), (Addend(-8), Bright, 0), (Eol, Normal, 0)]
|
||||
[(Address(148), Dim, 5), (Spacing(4), Normal, 0), (Opcode("b", 32772), Normal, 10), (BranchDest(200), Normal, 0), (BranchArrow(50), Rotating(0), 0), (Eol, Normal, 0)]
|
||||
[(Address(152), Dim, 5), (BranchArrow(16), Rotating(5), 0), (Opcode("mov", 32811), Normal, 10), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r5")), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(156), Dim, 5), (Spacing(4), Normal, 0), (Opcode("bl", 32775), Normal, 10), (Symbol(Symbol { name: "_ZN13LinkStateItem15StopUsingHammerEv", demangled_name: Some("LinkStateItem::StopUsingHammer()"), address: 0, size: 0, kind: Unknown, section: None, flags: FlagSet(Global | Weak), align: None, virtual_address: None }), Bright, 0), (Addend(-8), Bright, 0), (Eol, Normal, 0)]
|
||||
[(Address(156), Dim, 5), (Spacing(4), Normal, 0), (Opcode("bl", 32775), Normal, 10), (Symbol(Symbol { name: "_ZN13LinkStateItem15StopUsingHammerEv", demangled_name: Some("LinkStateItem::StopUsingHammer()"), normalized_name: None, address: 0, size: 0, kind: Unknown, section: None, flags: FlagSet(Global | Weak), align: None, virtual_address: None }), Bright, 0), (Addend(-8), Bright, 0), (Eol, Normal, 0)]
|
||||
[(Address(160), Dim, 5), (Spacing(4), Normal, 0), (Opcode("b", 32772), Normal, 10), (BranchDest(200), Normal, 0), (BranchArrow(50), Rotating(0), 0), (Eol, Normal, 0)]
|
||||
[(Address(164), Dim, 5), (BranchArrow(17), Rotating(6), 0), (Opcode("ldr", 32792), Normal, 10), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Basic("["), Normal, 0), (Argument(Opaque("pc")), Normal, 0), (Basic(", "), Normal, 0), (Basic("#"), Normal, 0), (Argument(Signed(248)), Normal, 0), (Basic("]"), Normal, 0), (Basic(" (->"), Normal, 0), (BranchDest(420), Normal, 0), (Basic(")"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(168), Dim, 5), (Spacing(4), Normal, 0), (Opcode("mov", 32811), Normal, 10), (Argument(Opaque("r1")), Normal, 0), (Basic(", "), Normal, 0), (Basic("#"), Normal, 0), (Argument(Unsigned(0)), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(172), Dim, 5), (Spacing(4), Normal, 0), (Opcode("ldr", 32792), Normal, 10), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Basic("["), Normal, 0), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Basic("#"), Normal, 0), (Argument(Signed(0)), Normal, 0), (Basic("]"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(176), Dim, 5), (Spacing(4), Normal, 0), (Opcode("mov", 32811), Normal, 10), (Argument(Opaque("r2")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r1")), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(180), Dim, 5), (Spacing(4), Normal, 0), (Opcode("strb", 32885), Normal, 10), (Argument(Opaque("r1")), Normal, 0), (Basic(", "), Normal, 0), (Basic("["), Normal, 0), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Basic("#"), Normal, 0), (Argument(Signed(42)), Normal, 0), (Basic("]"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(184), Dim, 5), (Spacing(4), Normal, 0), (Opcode("bl", 32775), Normal, 10), (Symbol(Symbol { name: "_ZN18UnkStruct_027e103c19func_ov000_020cf9dcEii", demangled_name: Some("UnkStruct_027e103c::func_ov000_020cf9dc(int, int)"), address: 0, size: 0, kind: Unknown, section: None, flags: FlagSet(Global | Weak), align: None, virtual_address: None }), Bright, 0), (Addend(-8), Bright, 0), (Eol, Normal, 0)]
|
||||
[(Address(184), Dim, 5), (Spacing(4), Normal, 0), (Opcode("bl", 32775), Normal, 10), (Symbol(Symbol { name: "_ZN18UnkStruct_027e103c19func_ov000_020cf9dcEii", demangled_name: Some("UnkStruct_027e103c::func_ov000_020cf9dc(int, int)"), normalized_name: None, address: 0, size: 0, kind: Unknown, section: None, flags: FlagSet(Global | Weak), align: None, virtual_address: None }), Bright, 0), (Addend(-8), Bright, 0), (Eol, Normal, 0)]
|
||||
[(Address(188), Dim, 5), (Spacing(4), Normal, 0), (Opcode("b", 32772), Normal, 10), (BranchDest(200), Normal, 0), (BranchArrow(50), Rotating(0), 0), (Eol, Normal, 0)]
|
||||
[(Address(192), Dim, 5), (BranchArrow(11), Rotating(1), 0), (Opcode("mov", 32811), Normal, 10), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r5")), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(196), Dim, 5), (Spacing(4), Normal, 0), (Opcode("bl", 32775), Normal, 10), (Symbol(Symbol { name: "_ZN13LinkStateItem14StopUsingScoopEv", demangled_name: Some("LinkStateItem::StopUsingScoop()"), address: 0, size: 0, kind: Unknown, section: None, flags: FlagSet(Global | Weak), align: None, virtual_address: None }), Bright, 0), (Addend(-8), Bright, 0), (Eol, Normal, 0)]
|
||||
[(Address(196), Dim, 5), (Spacing(4), Normal, 0), (Opcode("bl", 32775), Normal, 10), (Symbol(Symbol { name: "_ZN13LinkStateItem14StopUsingScoopEv", demangled_name: Some("LinkStateItem::StopUsingScoop()"), normalized_name: None, address: 0, size: 0, kind: Unknown, section: None, flags: FlagSet(Global | Weak), align: None, virtual_address: None }), Bright, 0), (Addend(-8), Bright, 0), (Eol, Normal, 0)]
|
||||
[(Address(200), Dim, 5), (BranchArrow(7), Rotating(0), 0), (Opcode("ldr", 32792), Normal, 10), (Argument(Opaque("r1")), Normal, 0), (Basic(", "), Normal, 0), (Basic("["), Normal, 0), (Argument(Opaque("r5")), Normal, 0), (Basic(", "), Normal, 0), (Basic("#"), Normal, 0), (Argument(Signed(20)), Normal, 0), (Basic("]"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(204), Dim, 5), (Spacing(4), Normal, 0), (Opcode("mvn", 32819), Normal, 10), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Basic("#"), Normal, 0), (Argument(Unsigned(0)), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(208), Dim, 5), (Spacing(4), Normal, 0), (Opcode("cmp", 32784), Normal, 10), (Argument(Opaque("r1")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r0")), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(212), Dim, 5), (Spacing(4), Normal, 0), (Opcode("beq", 32772), Normal, 10), (BranchDest(236), Normal, 0), (BranchArrow(59), Rotating(9), 0), (Eol, Normal, 0)]
|
||||
[(Address(216), Dim, 5), (Spacing(4), Normal, 0), (Opcode("mov", 32811), Normal, 10), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r5")), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(220), Dim, 5), (Spacing(4), Normal, 0), (Opcode("bl", 32775), Normal, 10), (Symbol(Symbol { name: "_ZN13LinkStateBase12GetEquipItemEi", demangled_name: Some("LinkStateBase::GetEquipItem(int)"), address: 0, size: 0, kind: Unknown, section: None, flags: FlagSet(Global | Weak), align: None, virtual_address: None }), Bright, 0), (Addend(-8), Bright, 0), (Eol, Normal, 0)]
|
||||
[(Address(220), Dim, 5), (Spacing(4), Normal, 0), (Opcode("bl", 32775), Normal, 10), (Symbol(Symbol { name: "_ZN13LinkStateBase12GetEquipItemEi", demangled_name: Some("LinkStateBase::GetEquipItem(int)"), normalized_name: None, address: 0, size: 0, kind: Unknown, section: None, flags: FlagSet(Global | Weak), align: None, virtual_address: None }), Bright, 0), (Addend(-8), Bright, 0), (Eol, Normal, 0)]
|
||||
[(Address(224), Dim, 5), (Spacing(4), Normal, 0), (Opcode("ldr", 32792), Normal, 10), (Argument(Opaque("r1")), Normal, 0), (Basic(", "), Normal, 0), (Basic("["), Normal, 0), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Basic("#"), Normal, 0), (Argument(Signed(0)), Normal, 0), (Basic("]"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(228), Dim, 5), (Spacing(4), Normal, 0), (Opcode("ldr", 32792), Normal, 10), (Argument(Opaque("r1")), Normal, 0), (Basic(", "), Normal, 0), (Basic("["), Normal, 0), (Argument(Opaque("r1")), Normal, 0), (Basic(", "), Normal, 0), (Basic("#"), Normal, 0), (Argument(Signed(28)), Normal, 0), (Basic("]"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(232), Dim, 5), (Spacing(4), Normal, 0), (Opcode("blx", 32776), Normal, 10), (Argument(Opaque("r1")), Normal, 0), (Eol, Normal, 0)]
|
||||
@@ -77,14 +77,14 @@ expression: output
|
||||
[(Address(288), Dim, 5), (BranchArrow(61), Rotating(10), 0), (Opcode("cmp", 32784), Normal, 10), (Argument(Opaque("r1")), Normal, 0), (Basic(", "), Normal, 0), (Basic("#"), Normal, 0), (Argument(Unsigned(10)), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(292), Dim, 5), (Spacing(4), Normal, 0), (Opcode("bne", 32772), Normal, 10), (BranchDest(308), Normal, 0), (BranchArrow(77), Rotating(12), 0), (Eol, Normal, 0)]
|
||||
[(Address(296), Dim, 5), (BranchArrow(62), Rotating(11), 0), (Opcode("mov", 32811), Normal, 10), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r5")), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(300), Dim, 5), (Spacing(4), Normal, 0), (Opcode("bl", 32775), Normal, 10), (Symbol(Symbol { name: "_ZN13LinkStateBase18EquipItem_vfunc_28Ev", demangled_name: Some("LinkStateBase::EquipItem_vfunc_28()"), address: 0, size: 0, kind: Unknown, section: None, flags: FlagSet(Global | Weak), align: None, virtual_address: None }), Bright, 0), (Addend(-8), Bright, 0), (Eol, Normal, 0)]
|
||||
[(Address(300), Dim, 5), (Spacing(4), Normal, 0), (Opcode("bl", 32775), Normal, 10), (Symbol(Symbol { name: "_ZN13LinkStateBase18EquipItem_vfunc_28Ev", demangled_name: Some("LinkStateBase::EquipItem_vfunc_28()"), normalized_name: None, address: 0, size: 0, kind: Unknown, section: None, flags: FlagSet(Global | Weak), align: None, virtual_address: None }), Bright, 0), (Addend(-8), Bright, 0), (Eol, Normal, 0)]
|
||||
[(Address(304), Dim, 5), (Spacing(4), Normal, 0), (Opcode("b", 32772), Normal, 10), (BranchDest(340), Normal, 0), (BranchArrow(85), Rotating(13), 0), (Eol, Normal, 0)]
|
||||
[(Address(308), Dim, 5), (BranchArrow(64), Rotating(12), 0), (Opcode("mov", 32811), Normal, 10), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r5")), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(312), Dim, 5), (Spacing(4), Normal, 0), (Opcode("bl", 32775), Normal, 10), (Symbol(Symbol { name: "_ZN13LinkStateBase18EquipItem_vfunc_28Ev", demangled_name: Some("LinkStateBase::EquipItem_vfunc_28()"), address: 0, size: 0, kind: Unknown, section: None, flags: FlagSet(Global | Weak), align: None, virtual_address: None }), Bright, 0), (Addend(-8), Bright, 0), (Eol, Normal, 0)]
|
||||
[(Address(312), Dim, 5), (Spacing(4), Normal, 0), (Opcode("bl", 32775), Normal, 10), (Symbol(Symbol { name: "_ZN13LinkStateBase18EquipItem_vfunc_28Ev", demangled_name: Some("LinkStateBase::EquipItem_vfunc_28()"), normalized_name: None, address: 0, size: 0, kind: Unknown, section: None, flags: FlagSet(Global | Weak), align: None, virtual_address: None }), Bright, 0), (Addend(-8), Bright, 0), (Eol, Normal, 0)]
|
||||
[(Address(316), Dim, 5), (Spacing(4), Normal, 0), (Opcode("cmp", 32784), Normal, 10), (Argument(Opaque("r4")), Normal, 0), (Basic(", "), Normal, 0), (Basic("#"), Normal, 0), (Argument(Unsigned(4)), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(320), Dim, 5), (Spacing(4), Normal, 0), (Opcode("cmpne", 32784), Normal, 10), (Argument(Opaque("r4")), Normal, 0), (Basic(", "), Normal, 0), (Basic("#"), Normal, 0), (Argument(Unsigned(2)), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(324), Dim, 5), (Spacing(4), Normal, 0), (Opcode("beq", 32772), Normal, 10), (BranchDest(340), Normal, 0), (BranchArrow(85), Rotating(13), 0), (Eol, Normal, 0)]
|
||||
[(Address(328), Dim, 5), (Spacing(4), Normal, 0), (Opcode("bl", 32775), Normal, 10), (Symbol(Symbol { name: "_ZN13LinkStateItem16GetLinkStateMoveEv", demangled_name: Some("LinkStateItem::GetLinkStateMove()"), address: 488, size: 16, kind: Function, section: Some(0), flags: FlagSet(Global), align: None, virtual_address: None }), Bright, 0), (Addend(-8), Bright, 0), (Eol, Normal, 0)]
|
||||
[(Address(328), Dim, 5), (Spacing(4), Normal, 0), (Opcode("bl", 32775), Normal, 10), (Symbol(Symbol { name: "_ZN13LinkStateItem16GetLinkStateMoveEv", demangled_name: Some("LinkStateItem::GetLinkStateMove()"), normalized_name: None, address: 488, size: 16, kind: Function, section: Some(0), flags: FlagSet(Global), align: None, virtual_address: None }), Bright, 0), (Addend(-8), Bright, 0), (Eol, Normal, 0)]
|
||||
[(Address(332), Dim, 5), (Spacing(4), Normal, 0), (Opcode("mov", 32811), Normal, 10), (Argument(Opaque("r1")), Normal, 0), (Basic(", "), Normal, 0), (Basic("#"), Normal, 0), (Argument(Unsigned(1)), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(336), Dim, 5), (Spacing(4), Normal, 0), (Opcode("strb", 32885), Normal, 10), (Argument(Opaque("r1")), Normal, 0), (Basic(", "), Normal, 0), (Basic("["), Normal, 0), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Basic("#"), Normal, 0), (Argument(Signed(20)), Normal, 0), (Basic("]"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(340), Dim, 5), (BranchArrow(70), Rotating(13), 0), (Opcode("mvn", 32819), Normal, 10), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Basic("#"), Normal, 0), (Argument(Unsigned(0)), Normal, 0), (Eol, Normal, 0)]
|
||||
@@ -94,7 +94,7 @@ expression: output
|
||||
[(Address(356), Dim, 5), (Spacing(4), Normal, 0), (Opcode("cmp", 32784), Normal, 10), (Argument(Opaque("r6")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r4")), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(360), Dim, 5), (Spacing(4), Normal, 0), (Opcode("beq", 32772), Normal, 10), (BranchDest(384), Normal, 0), (BranchArrow(96), Rotating(14), 0), (Eol, Normal, 0)]
|
||||
[(Address(364), Dim, 5), (BranchArrow(95), Rotating(15), 0), (Opcode("mov", 32811), Normal, 10), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r6")), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(368), Dim, 5), (Spacing(4), Normal, 0), (Opcode("bl", 32775), Normal, 10), (Symbol(Symbol { name: "_Z19func_ov000_020b7e6cPi", demangled_name: Some("func_ov000_020b7e6c(int*)"), address: 0, size: 0, kind: Unknown, section: None, flags: FlagSet(Global | Weak), align: None, virtual_address: None }), Bright, 0), (Addend(-8), Bright, 0), (Eol, Normal, 0)]
|
||||
[(Address(368), Dim, 5), (Spacing(4), Normal, 0), (Opcode("bl", 32775), Normal, 10), (Symbol(Symbol { name: "_Z19func_ov000_020b7e6cPi", demangled_name: Some("func_ov000_020b7e6c(int*)"), normalized_name: None, address: 0, size: 0, kind: Unknown, section: None, flags: FlagSet(Global | Weak), align: None, virtual_address: None }), Bright, 0), (Addend(-8), Bright, 0), (Eol, Normal, 0)]
|
||||
[(Address(372), Dim, 5), (Spacing(4), Normal, 0), (Opcode("add", 32769), Normal, 10), (Argument(Opaque("r6")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r6")), Normal, 0), (Basic(", "), Normal, 0), (Basic("#"), Normal, 0), (Argument(Unsigned(4)), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(376), Dim, 5), (Spacing(4), Normal, 0), (Opcode("cmp", 32784), Normal, 10), (Argument(Opaque("r6")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r4")), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(380), Dim, 5), (Spacing(4), Normal, 0), (Opcode("bne", 32772), Normal, 10), (BranchDest(364), Normal, 0), (BranchArrow(91), Rotating(15), 0), (Eol, Normal, 0)]
|
||||
@@ -103,10 +103,10 @@ expression: output
|
||||
[(Address(392), Dim, 5), (Spacing(4), Normal, 0), (Opcode("ldrb", 32793), Normal, 10), (Argument(Opaque("r1")), Normal, 0), (Basic(", "), Normal, 0), (Basic("["), Normal, 0), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Basic("#"), Normal, 0), (Argument(Signed(128)), Normal, 0), (Basic("]"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(396), Dim, 5), (Spacing(4), Normal, 0), (Opcode("cmp", 32784), Normal, 10), (Argument(Opaque("r1")), Normal, 0), (Basic(", "), Normal, 0), (Basic("#"), Normal, 0), (Argument(Unsigned(0)), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(400), Dim, 5), (Spacing(4), Normal, 0), (Opcode("beq", 32772), Normal, 10), (BranchDest(408), Normal, 0), (BranchArrow(102), Rotating(16), 0), (Eol, Normal, 0)]
|
||||
[(Address(404), Dim, 5), (Spacing(4), Normal, 0), (Opcode("bl", 32775), Normal, 10), (Symbol(Symbol { name: "_ZN13PlayerControl13StopFollowingEv", demangled_name: Some("PlayerControl::StopFollowing()"), address: 0, size: 0, kind: Unknown, section: None, flags: FlagSet(Global | Weak), align: None, virtual_address: None }), Bright, 0), (Addend(-8), Bright, 0), (Eol, Normal, 0)]
|
||||
[(Address(404), Dim, 5), (Spacing(4), Normal, 0), (Opcode("bl", 32775), Normal, 10), (Symbol(Symbol { name: "_ZN13PlayerControl13StopFollowingEv", demangled_name: Some("PlayerControl::StopFollowing()"), normalized_name: None, address: 0, size: 0, kind: Unknown, section: None, flags: FlagSet(Global | Weak), align: None, virtual_address: None }), Bright, 0), (Addend(-8), Bright, 0), (Eol, Normal, 0)]
|
||||
[(Address(408), Dim, 5), (BranchArrow(100), Rotating(16), 0), (Opcode("mov", 32811), Normal, 10), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Basic("#"), Normal, 0), (Argument(Unsigned(0)), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(412), Dim, 5), (Spacing(4), Normal, 0), (Opcode("strb", 32885), Normal, 10), (Argument(Opaque("r0")), Normal, 0), (Basic(", "), Normal, 0), (Basic("["), Normal, 0), (Argument(Opaque("r5")), Normal, 0), (Basic(", "), Normal, 0), (Basic("#"), Normal, 0), (Argument(Signed(38)), Normal, 0), (Basic("]"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(416), Dim, 5), (Spacing(4), Normal, 0), (Opcode("ldmia", 32791), Normal, 10), (Argument(Opaque("sp")), Normal, 0), (Basic("!"), Normal, 0), (Basic(", "), Normal, 0), (Basic("{"), Normal, 0), (Argument(Opaque("r4")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r5")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("r6")), Normal, 0), (Basic(", "), Normal, 0), (Argument(Opaque("pc")), Normal, 0), (Basic("}"), Normal, 0), (Eol, Normal, 0)]
|
||||
[(Address(420), Dim, 5), (Spacing(4), Normal, 0), (Opcode(".word", 65534), Normal, 10), (Symbol(Symbol { name: "data_027e103c", demangled_name: None, address: 0, size: 0, kind: Unknown, section: None, flags: FlagSet(Global | Weak), align: None, virtual_address: None }), Bright, 0), (Eol, Normal, 0)]
|
||||
[(Address(424), Dim, 5), (BranchArrow(25), Rotating(8), 0), (Opcode(".word", 65534), Normal, 10), (Symbol(Symbol { name: "data_027e1098", demangled_name: None, address: 0, size: 0, kind: Unknown, section: None, flags: FlagSet(Global | Weak), align: None, virtual_address: None }), Bright, 0), (Eol, Normal, 0)]
|
||||
[(Address(428), Dim, 5), (Spacing(4), Normal, 0), (Opcode(".word", 65534), Normal, 10), (Symbol(Symbol { name: "gPlayerControl", demangled_name: None, address: 0, size: 0, kind: Unknown, section: None, flags: FlagSet(Global | Weak), align: None, virtual_address: None }), Bright, 0), (Eol, Normal, 0)]
|
||||
[(Address(420), Dim, 5), (Spacing(4), Normal, 0), (Opcode(".word", 65534), Normal, 10), (Symbol(Symbol { name: "data_027e103c", demangled_name: None, normalized_name: None, address: 0, size: 0, kind: Unknown, section: None, flags: FlagSet(Global | Weak), align: None, virtual_address: None }), Bright, 0), (Eol, Normal, 0)]
|
||||
[(Address(424), Dim, 5), (BranchArrow(25), Rotating(8), 0), (Opcode(".word", 65534), Normal, 10), (Symbol(Symbol { name: "data_027e1098", demangled_name: None, normalized_name: None, address: 0, size: 0, kind: Unknown, section: None, flags: FlagSet(Global | Weak), align: None, virtual_address: None }), Bright, 0), (Eol, Normal, 0)]
|
||||
[(Address(428), Dim, 5), (Spacing(4), Normal, 0), (Opcode(".word", 65534), Normal, 10), (Symbol(Symbol { name: "gPlayerControl", demangled_name: None, normalized_name: None, address: 0, size: 0, kind: Unknown, section: None, flags: FlagSet(Global | Weak), align: None, virtual_address: None }), Bright, 0), (Eol, Normal, 0)]
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user