mirror of
https://github.com/encounter/decomp-toolkit.git
synced 2025-12-12 22:56:28 +00:00
Semi-working REL analysis & splitting
This commit is contained in:
@@ -24,13 +24,13 @@ pub struct SectionAddress {
|
||||
|
||||
impl Debug for SectionAddress {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}:{:#010X}", self.section as isize, self.address)
|
||||
write!(f, "{}:{:#X}", self.section as isize, self.address)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for SectionAddress {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}:{:#010X}", self.section as isize, self.address)
|
||||
write!(f, "{}:{:#X}", self.section as isize, self.address)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,9 +131,19 @@ impl AnalyzerState {
|
||||
section.address,
|
||||
section.address + section.size
|
||||
);
|
||||
let address_str = if obj.module_id == 0 {
|
||||
format!("{:08X}", addr.address)
|
||||
} else {
|
||||
format!(
|
||||
"{}_{}_{:X}",
|
||||
obj.module_id,
|
||||
section.name.trim_start_matches('.'),
|
||||
addr.address
|
||||
)
|
||||
};
|
||||
obj.add_symbol(
|
||||
ObjSymbol {
|
||||
name: format!("jumptable_{:08X}", addr.address),
|
||||
name: format!("jumptable_{}", address_str),
|
||||
demangled_name: None,
|
||||
address: addr.address as u64,
|
||||
section: Some(addr.section),
|
||||
|
||||
@@ -5,7 +5,7 @@ use crate::{
|
||||
util::split::is_linker_generated_label,
|
||||
};
|
||||
|
||||
pub fn detect_object_boundaries(obj: &mut ObjInfo) -> Result<()> {
|
||||
pub fn detect_objects(obj: &mut ObjInfo) -> Result<()> {
|
||||
for (section_index, section) in
|
||||
obj.sections.iter_mut().filter(|(_, s)| s.kind != ObjSectionKind::Code)
|
||||
{
|
||||
|
||||
@@ -151,8 +151,9 @@ impl AnalysisPass for FindRelCtorsDtors {
|
||||
let possible_sections = obj
|
||||
.sections
|
||||
.iter()
|
||||
.filter(|&(_, section)| {
|
||||
.filter(|&(index, section)| {
|
||||
if section.section_known
|
||||
|| state.known_sections.contains_key(&index)
|
||||
|| !matches!(section.kind, ObjSectionKind::Data | ObjSectionKind::ReadOnlyData)
|
||||
|| section.size < 4
|
||||
{
|
||||
@@ -283,3 +284,40 @@ impl AnalysisPass for FindRelCtorsDtors {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct FindRelRodataData {}
|
||||
|
||||
impl AnalysisPass for FindRelRodataData {
|
||||
fn execute(state: &mut AnalyzerState, obj: &ObjInfo) -> Result<()> {
|
||||
ensure!(obj.kind == ObjKind::Relocatable);
|
||||
|
||||
match (obj.sections.by_name(".rodata")?, obj.sections.by_name(".data")?) {
|
||||
(None, None) => {}
|
||||
_ => return Ok(()),
|
||||
}
|
||||
|
||||
let possible_sections = obj
|
||||
.sections
|
||||
.iter()
|
||||
.filter(|&(index, section)| {
|
||||
!section.section_known
|
||||
&& !state.known_sections.contains_key(&index)
|
||||
&& matches!(section.kind, ObjSectionKind::Data | ObjSectionKind::ReadOnlyData)
|
||||
})
|
||||
.collect_vec();
|
||||
|
||||
if possible_sections.len() != 2 {
|
||||
log::warn!("Failed to find .rodata and .data");
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
log::debug!("Found .rodata and .data: {:?}", possible_sections);
|
||||
let rodata_section_index = possible_sections[0].0;
|
||||
state.known_sections.insert(rodata_section_index, ".rodata".to_string());
|
||||
|
||||
let data_section_index = possible_sections[1].0;
|
||||
state.known_sections.insert(data_section_index, ".data".to_string());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -309,8 +309,8 @@ impl FunctionSlices {
|
||||
}
|
||||
}
|
||||
}
|
||||
BranchTarget::JumpTable { .. } => {
|
||||
bail!("Conditional jump table unsupported @ {:#010X}", ins_addr);
|
||||
BranchTarget::JumpTable { address, size } => {
|
||||
bail!("Conditional jump table unsupported @ {:#010X} -> {:#010X} size {:#X?}", ins_addr, address, size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,8 @@ use std::{
|
||||
|
||||
use anyhow::{bail, Result};
|
||||
use ppc750cl::Opcode;
|
||||
use tracing::{debug_span, info_span};
|
||||
use tracing_attributes::instrument;
|
||||
|
||||
use crate::{
|
||||
analysis::{
|
||||
@@ -88,8 +90,8 @@ impl Tracker {
|
||||
}
|
||||
}
|
||||
|
||||
#[instrument(name = "tracker", skip(self, obj))]
|
||||
pub fn process(&mut self, obj: &ObjInfo) -> Result<()> {
|
||||
log::debug!("Processing code sections");
|
||||
self.process_code(obj)?;
|
||||
for (section_index, section) in obj
|
||||
.sections
|
||||
@@ -151,6 +153,7 @@ impl Tracker {
|
||||
) -> Result<ExecCbResult<()>> {
|
||||
let ExecCbData { executor, vm, result, ins_addr, section: _, ins, block_start: _ } = data;
|
||||
let is_function_addr = |addr: SectionAddress| addr >= function_start && addr < function_end;
|
||||
let _span = debug_span!("ins", addr = %ins_addr, op = ?ins.op).entered();
|
||||
|
||||
match result {
|
||||
StepResult::Continue => {
|
||||
@@ -310,8 +313,20 @@ impl Tracker {
|
||||
executor.push(addr, branch.vm, true);
|
||||
}
|
||||
}
|
||||
BranchTarget::JumpTable { .. } => {
|
||||
bail!("Conditional jump table unsupported @ {:#010X}", ins_addr)
|
||||
BranchTarget::JumpTable { address, size } => {
|
||||
let (entries, _) = uniq_jump_table_entries(
|
||||
obj,
|
||||
address,
|
||||
size,
|
||||
ins_addr,
|
||||
function_start,
|
||||
Some(function_end),
|
||||
)?;
|
||||
for target in entries {
|
||||
if is_function_addr(target) {
|
||||
executor.push(target, branch.vm.clone_all(), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -326,6 +341,9 @@ impl Tracker {
|
||||
};
|
||||
let function_start = SectionAddress::new(section_index, symbol.address as u32);
|
||||
let function_end = function_start + symbol.size as u32;
|
||||
let _span =
|
||||
info_span!("fn", name = %symbol.name, start = %function_start, end = %function_end)
|
||||
.entered();
|
||||
|
||||
// The compiler can sometimes create impossible-to-reach branches,
|
||||
// but we still want to track them.
|
||||
@@ -461,6 +479,7 @@ impl Tracker {
|
||||
.or_else(|| check_symbol(self.sda_base, "_SDA_BASE_"))
|
||||
}
|
||||
|
||||
#[instrument(name = "apply", skip(self, obj))]
|
||||
pub fn apply(&self, obj: &mut ObjInfo, replace: bool) -> Result<()> {
|
||||
fn apply_section_name(section: &mut ObjSection, name: &str) {
|
||||
let module_id = if let Some((_, b)) = section.name.split_once(':') {
|
||||
|
||||
@@ -126,8 +126,11 @@ pub fn section_address_for(
|
||||
let (section_index, _) = obj.sections.at_address(target_addr).ok()?;
|
||||
return Some(SectionAddress::new(section_index, target_addr));
|
||||
}
|
||||
// TODO: relative jumps within relocatable objects?
|
||||
None
|
||||
if obj.sections[ins_addr.section].contains(target_addr) {
|
||||
Some(SectionAddress::new(ins_addr.section, target_addr))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl VM {
|
||||
@@ -180,11 +183,11 @@ impl VM {
|
||||
pub fn clone_all(&self) -> Box<Self> { Box::new(self.clone()) }
|
||||
|
||||
pub fn step(&mut self, obj: &ObjInfo, ins_addr: SectionAddress, ins: &Ins) -> StepResult {
|
||||
let relocation_target = relocation_target_for(obj, ins_addr, None).ok().flatten();
|
||||
if let Some(_target) = relocation_target {
|
||||
let _defs = ins.defs();
|
||||
// TODO
|
||||
}
|
||||
// let relocation_target = relocation_target_for(obj, ins_addr, None).ok().flatten();
|
||||
// if let Some(_target) = relocation_target {
|
||||
// let _defs = ins.defs();
|
||||
// // TODO
|
||||
// }
|
||||
|
||||
match ins.op {
|
||||
Opcode::Illegal => {
|
||||
|
||||
Reference in New Issue
Block a user