Skip to content

Commit

Permalink
partial symbol finder
Browse files Browse the repository at this point in the history
  • Loading branch information
AngheloAlf committed Nov 30, 2024
1 parent 6e02946 commit f05e2f9
Show file tree
Hide file tree
Showing 14 changed files with 881 additions and 98 deletions.
392 changes: 375 additions & 17 deletions src/spimdisasm/src/analysis/instruction_analysis_result.rs

Large diffs are not rendered by default.

11 changes: 11 additions & 0 deletions src/spimdisasm/src/analysis/lo_pairing_info.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/* SPDX-FileCopyrightText: © 2024 Decompollaborate */
/* SPDX-License-Identifier: MIT */

use crate::rom_address::RomAddress;

pub struct LoPairingInfo {
pub(crate) instr_rom: RomAddress,
pub(crate) value: i64, // TODO: This is fishy
pub(crate) is_gp_rel: bool,
pub(crate) is_gp_got: bool,
}
2 changes: 2 additions & 0 deletions src/spimdisasm/src/analysis/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@

mod instruction_analysis_result;
mod instruction_analyzer;
mod lo_pairing_info;
mod register_tracker;
mod tracked_register_state;

pub use instruction_analysis_result::InstructionAnalysisResult;
pub(crate) use instruction_analyzer::InstructionAnalyzer;
pub(crate) use lo_pairing_info::LoPairingInfo;
pub(crate) use register_tracker::RegisterTracker;
pub(crate) use tracked_register_state::TrackedRegisterState;
175 changes: 172 additions & 3 deletions src/spimdisasm/src/analysis/register_tracker.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
/* SPDX-FileCopyrightText: © 2024 Decompollaborate */
/* SPDX-License-Identifier: MIT */

use rabbitizer::{registers::Gpr, traits::Register, Instruction};
use rabbitizer::{opcodes::Opcode, registers::Gpr, traits::Register, Instruction};

use super::TrackedRegisterState;
use crate::rom_address::RomAddress;

use super::{LoPairingInfo, TrackedRegisterState};

#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct RegisterTracker {
Expand Down Expand Up @@ -42,7 +44,174 @@ impl RegisterTracker {
}
}

pub(crate) fn process_branch(&mut self, _instr: &Instruction) {
pub(crate) fn process_branch(&mut self, instr: &Instruction, instr_rom: RomAddress) {
assert!(instr.get_branch_offset_generic().is_some());

if let Some(reg) = instr.field_rs() {
if instr.opcode().reads_rs() {
self.registers[reg.as_index()].set_branching(instr_rom);
}
}
if let Some(reg) = instr.field_rt() {
if instr.opcode().reads_rt() {
self.registers[reg.as_index()].set_branching(instr_rom);
}
}
if let Some(reg) = instr.field_rd() {
if instr.opcode().reads_rd() {
self.registers[reg.as_index()].set_branching(instr_rom);
}
}
}

pub(crate) fn process_hi(
&mut self,
instr: &Instruction,
instr_rom: RomAddress,
prev_instr: Option<&Instruction>,
) {
assert!(instr.opcode().can_be_hi());

let reg = instr
.get_destination_gpr()
.expect("lui should have dst register");
let state = &mut self.registers[reg.as_index()];

state.clear();
state.set_hi(
instr
.get_processed_immediate()
.expect("lui should have an immediate field") as u32,
instr_rom,
prev_instr,
);
}

pub(crate) fn process_gp_load(&mut self, instr: &Instruction, instr_rom: RomAddress) {
assert!(instr.opcode().can_be_lo());

let reg = instr
.get_destination_gpr()
.expect("should have dst register");
let state = &mut self.registers[reg.as_index()];

state.clear();
state.set_gp_load(
instr
.get_processed_immediate()
.expect("should have immediate field") as u32,
instr_rom,
);
}

pub(crate) fn process_lo(&mut self, instr: &Instruction, value: u32, instr_rom: RomAddress) {
if let Some(dst_reg) = instr.get_destination_gpr() {
let state = &mut self.registers[dst_reg.as_index()];
state.set_lo(value, instr_rom);
if instr.opcode().does_dereference() {
state.set_deref(instr_rom);
}
if Some(dst_reg) == instr.field_rs() {
state.clear_hi();
state.clear_gp();
}
state.clear_branch();
}
}

pub(crate) fn overwrite_registers(&mut self, instr: &Instruction, instr_rom: RomAddress) {
if self.move_register(instr) {
return;
}

match instr.opcode() {
Opcode::core_mtc1 | Opcode::core_dmtc1 | Opcode::core_ctc1 => {
// IDO usually use a reg as a temp when loading a constant value
// into the float coprocessor, after that IDO never re-uses the value
// in that reg for anything else
self.clear_reg(instr.field_rt().expect("This should not panic"), instr_rom);
}
_ => {
if let Some(reg) = instr.get_destination_gpr() {
if instr.opcode().can_be_hi() {
self.registers[reg.as_index()].clear_lo();
} else {
self.clear_reg(reg, instr_rom);
}
}
}
}
}

pub(crate) fn preprocess_lo_and_get_info(
&mut self,
instr: &Instruction,
instr_rom: RomAddress,
) -> Option<LoPairingInfo> {
if let Some(reg) = instr.field_rs() {
let state = &self.registers[reg.as_index()];

if let Some(hi_info) = state.hi_info() {
if !hi_info.set_on_branch_likely {
return Some(LoPairingInfo {
instr_rom: hi_info.instr_rom,
value: state.value() as i64,
is_gp_rel: false,
is_gp_got: false,
});
}
} else if reg.is_global_pointer(instr.abi()) {
return Some(LoPairingInfo {
instr_rom: RomAddress::new(0),
value: state.value() as i64,
is_gp_rel: true,
is_gp_got: false,
});
} else if let Some(gp_info) = state.gp_info() {
return Some(LoPairingInfo {
instr_rom: gp_info,
value: state.value() as i64,
is_gp_rel: false,
is_gp_got: true,
});
}

if let Some(rt) = instr.field_rt() {
if instr.opcode().does_dereference() {
if state.lo_info().is_some() && state.dereferenced().is_none() {
// Simulate a dereference
self.registers[rt.as_index()].dereference_from(*state, instr_rom);
self.registers[rt.as_index()].clear_branch();
}
}
}
}

None
}

pub(crate) fn has_lo_but_not_hi(&self, instr: &Instruction) -> bool {
instr.field_rs().is_some_and(|reg| {
let state = self.registers[reg.as_index()];
state.lo_info().is_some() && state.hi_info().is_none()
})
}
}

impl RegisterTracker {
fn move_register(&mut self, _instr: &Instruction) -> bool {
// TODO
false
}

fn clear_reg(&mut self, reg: Gpr, instr_rom: RomAddress) {
let state = &mut self.registers[reg.as_index()];

state.clear_hi();
if !state.was_set_in_current_instr(instr_rom) {
state.clear_gp();
state.clear_lo();
}
state.clear_branch();
}
}
121 changes: 118 additions & 3 deletions src/spimdisasm/src/analysis/tracked_register_state.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,130 @@
/* SPDX-FileCopyrightText: © 2024 Decompollaborate */
/* SPDX-License-Identifier: MIT */

use rabbitizer::Instruction;

use crate::rom_address::RomAddress;

#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub(crate) struct HiInfo {
pub(crate) instr_rom: RomAddress,

// If the previous instructions is a branch likely, then nulify
// the effects of this instruction for future analysis
pub(crate) set_on_branch_likely: bool,
}

#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct TrackedRegisterState {}
pub struct TrackedRegisterState {
// Maybe wrap in Option?
value: u32,

// TODO: maybe wrap in an enum?
hi_info: Option<HiInfo>,
gp_info: Option<RomAddress>,
lo_info: Option<RomAddress>,
dereferenced: Option<RomAddress>,
branch_info: Option<RomAddress>,
}

impl TrackedRegisterState {
pub(crate) fn new() -> Self {
Self {}
Self {
value: 0,
hi_info: None,
gp_info: None,
lo_info: None,
dereferenced: None,
branch_info: None,
}
}

pub(crate) fn value(&self) -> u32 {
self.value
}
pub(crate) fn hi_info(&self) -> Option<HiInfo> {
self.hi_info
}
pub(crate) fn gp_info(&self) -> Option<RomAddress> {
self.gp_info
}
pub(crate) fn lo_info(&self) -> Option<RomAddress> {
self.lo_info
}
pub(crate) fn dereferenced(&self) -> Option<RomAddress> {
self.dereferenced
}
}

impl TrackedRegisterState {
pub fn clear(&mut self) {
self.value = 0;

self.clear_hi();
self.clear_gp();
self.clear_lo();
self.clear_branch();
}

pub fn clear_hi(&mut self) {
self.hi_info = None;
}
pub fn clear_gp(&mut self) {
self.gp_info = None;
}
pub fn clear_lo(&mut self) {
self.lo_info = None;
self.dereferenced = None;
}
pub fn clear_branch(&mut self) {
self.branch_info = None;
}
}

impl TrackedRegisterState {
pub fn clear(&mut self) {}
pub fn set_hi(&mut self, value: u32, instr_rom: RomAddress, prev_instr: Option<&Instruction>) {
assert!(self.gp_info.is_none());
self.value = value << 16;

self.hi_info = Some(HiInfo {
instr_rom,
set_on_branch_likely: prev_instr
.is_some_and(|x| x.opcode().is_branch_likely() || x.is_unconditional_branch()),
});
self.dereferenced = None;
}

pub fn set_gp_load(&mut self, value: u32, instr_rom: RomAddress) {
assert!(self.hi_info.is_none());
self.value = value;

self.gp_info = Some(instr_rom);
}

pub fn set_lo(&mut self, value: u32, instr_rom: RomAddress) {
self.value = value;

self.lo_info = Some(instr_rom);
self.dereferenced = None;
}

pub fn set_branching(&mut self, instr_rom: RomAddress) {
self.branch_info = Some(instr_rom);
}

pub fn set_deref(&mut self, instr_rom: RomAddress) {
self.dereferenced = Some(instr_rom);
}

pub fn dereference_from(&mut self, other: Self, instr_rom: RomAddress) {
*self = other;
self.set_deref(instr_rom);
}
}

impl TrackedRegisterState {
pub fn was_set_in_current_instr(&self, _instr_rom: RomAddress) -> bool {
// TODO
false
}
}
19 changes: 1 addition & 18 deletions src/spimdisasm/src/context/context_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -208,24 +208,7 @@ pub struct ContextBuilderOverlay {
}

impl ContextBuilderOverlay {
/*
pub fn add_overlay(&mut self, category: OverlayCategoryName,
rom_range: AddressRange<RomAddress>,
vram_range: AddressRange<Vram>,) -> SegmentModifier {
let segment = self.overlay_segments
.entry(
category.clone()
)
.or_insert_with(
|| OverlayCategory::new(category, rom_range, vram_range)
);
SegmentModifier {
segment
}
}
*/
#[must_use]
pub fn add_overlay_category(&mut self, category: OverlayCategoryName) -> OverlaysBuilder {
OverlaysBuilder {
name: category.clone(),
Expand Down
Loading

0 comments on commit f05e2f9

Please sign in to comment.