diff --git a/src/emulator/ps1/duckstation.rs b/src/emulator/ps1/duckstation.rs
index 2967a4a3..ebd4de7e 100644
--- a/src/emulator/ps1/duckstation.rs
+++ b/src/emulator/ps1/duckstation.rs
@@ -1,4 +1,4 @@
-use crate::{file_format::pe, signature::Signature, Address, Address64, Process};
+use crate::{file_format::pe, signature::Signature, Address, Address64, PointerSize, Process};
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct State {
@@ -7,13 +7,16 @@ pub struct State {
impl State {
pub fn find_ram(&mut self, game: &Process) -> Option
{
- const SIG: Signature<8> = Signature::new("48 89 0D ?? ?? ?? ?? B8");
-
let main_module_range = super::PROCESS_NAMES
.iter()
.filter(|(_, state)| matches!(state, super::State::Duckstation(_)))
.find_map(|(name, _)| game.get_module_range(name).ok())?;
+ // 32bit versions of Duckstation are not supported (nor developed)
+ if pe::MachineType::read(game, main_module_range.0)?.pointer_size()? != PointerSize::Bit64 {
+ return None;
+ }
+
// Recent Duckstation releases include a debug symbol that can be used to easily retrieve the address of the emulated RAM
// Info: https://github.com/stenzek/duckstation/commit/c98e0bd0969abdd82589bfc565aea52119fd0f19
if let Some(debug_symbol) = pe::symbols(game, main_module_range.0).find(|symbol| {
@@ -24,20 +27,19 @@ impl State {
self.addr = debug_symbol.address;
} else {
// For older versions of Duckstation, we fall back to regular sigscanning
- let addr = SIG.scan_process_range(game, main_module_range)? + 3;
- self.addr = addr + 0x4 + game.read::(addr).ok()?;
+ const SIG: Signature<8> = Signature::new("48 89 0D ?? ?? ?? ?? B8");
+ self.addr = SIG
+ .scan_process_range(game, main_module_range)
+ .map(|val| val + 3)
+ .and_then(|addr| Some(addr + 0x4 + game.read::(addr).ok()?))?;
}
- Some(game.read::(self.addr).ok()?.into())
+ Some(game.read::(self.addr).unwrap_or_default().into())
}
pub fn keep_alive(&self, game: &Process, wram_base: &mut Option) -> bool {
- if let Ok(addr) = game.read::(self.addr) {
- *wram_base = Some(addr.into());
- true
- } else {
- false
- }
+ *wram_base = Some(game.read::(self.addr).unwrap_or_default().into());
+ true
}
pub const fn new() -> Self {
diff --git a/src/emulator/ps1/epsxe.rs b/src/emulator/ps1/epsxe.rs
index d7461fc0..bbcc9444 100644
--- a/src/emulator/ps1/epsxe.rs
+++ b/src/emulator/ps1/epsxe.rs
@@ -12,9 +12,10 @@ impl State {
.filter(|(_, state)| matches!(state, super::State::Epsxe(_)))
.find_map(|(name, _)| game.get_module_range(name).ok())?;
- let ptr = SIG.scan_process_range(game, main_module_range)? + 5;
-
- Some(game.read::(ptr).ok()?.into())
+ SIG.scan_process_range(game, main_module_range)
+ .map(|val| val + 5)
+ .and_then(|addr| game.read::(addr).ok())
+ .map(|val| val.into())
}
pub const fn keep_alive(&self) -> bool {
diff --git a/src/emulator/ps1/mednafen.rs b/src/emulator/ps1/mednafen.rs
index 9d351bbe..1b15ae93 100644
--- a/src/emulator/ps1/mednafen.rs
+++ b/src/emulator/ps1/mednafen.rs
@@ -1,4 +1,4 @@
-use crate::{file_format::pe, signature::Signature, Address, Address32, Process};
+use crate::{file_format::pe, signature::Signature, Address, Address32, PointerSize, Process};
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct State;
@@ -14,14 +14,15 @@ impl State {
.find_map(|(name, _)| game.get_module_range(name).ok())?;
let is_64_bit =
- pe::MachineType::read(game, main_module_range.0) == Some(pe::MachineType::X86_64);
+ pe::MachineType::read(game, main_module_range.0)?.pointer_size()? == PointerSize::Bit64;
- let ptr = match is_64_bit {
- true => SIG_64.scan_process_range(game, main_module_range)?,
- false => SIG_32.scan_process_range(game, main_module_range)?,
- } + 0x5;
-
- Some(game.read::(ptr).ok()?.into())
+ match is_64_bit {
+ true => SIG_64.scan_process_range(game, main_module_range),
+ false => SIG_32.scan_process_range(game, main_module_range),
+ }
+ .map(|val| val + 0x5)
+ .and_then(|addr| game.read::(addr).ok())
+ .map(|val| val.into())
}
pub const fn keep_alive(&self) -> bool {
diff --git a/src/emulator/ps1/mod.rs b/src/emulator/ps1/mod.rs
index 3112630c..ae891222 100644
--- a/src/emulator/ps1/mod.rs
+++ b/src/emulator/ps1/mod.rs
@@ -112,7 +112,7 @@ impl Emulator {
State::PsxFin(x) => x.keep_alive(),
State::Duckstation(x) => x.keep_alive(&self.process, &mut ram_base),
State::Retroarch(x) => x.keep_alive(&self.process),
- State::PcsxRedux(x) => x.keep_alive(&self.process),
+ State::PcsxRedux(x) => x.keep_alive(&self.process, &mut ram_base),
State::Xebra(x) => x.keep_alive(),
State::Mednafen(x) => x.keep_alive(),
};
@@ -132,10 +132,14 @@ impl Emulator {
///
/// Valid addresses for the PS1 range from `0x80000000` to `0x817FFFFF`.
pub fn get_address(&self, offset: u32) -> Result {
+ let addr = self
+ .ram_base
+ .get()
+ .filter(|addr| !addr.is_null())
+ .ok_or(Error {})?;
+
match offset {
- (0x80000000..=0x817FFFFF) => {
- Ok(self.ram_base.get().ok_or(Error {})? + offset.sub(0x80000000))
- }
+ (0x80000000..=0x817FFFFF) => Ok(addr + offset.sub(0x80000000)),
_ => Err(Error {}),
}
}
diff --git a/src/emulator/ps1/pcsx_redux.rs b/src/emulator/ps1/pcsx_redux.rs
index b193c0a4..cbd59217 100644
--- a/src/emulator/ps1/pcsx_redux.rs
+++ b/src/emulator/ps1/pcsx_redux.rs
@@ -1,12 +1,9 @@
-use crate::{
- file_format::pe, signature::Signature, Address, Address32, Address64, MemoryRangeFlags, Process,
-};
+use crate::{file_format::pe, signature::Signature, Address, Address64, PointerSize, Process};
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct State {
- is_64_bit: bool,
addr_base: Address,
- addr: Address,
+ offsets: [u64; 3],
}
impl State {
@@ -16,58 +13,43 @@ impl State {
.filter(|(_, state)| matches!(state, super::State::PcsxRedux(_)))
.find_map(|(name, _)| game.get_module_range(name).ok())?;
- self.is_64_bit =
- pe::MachineType::read(game, main_module_range.0) == Some(pe::MachineType::X86_64);
-
- if self.is_64_bit {
- const SIG_BASE: Signature<25> = Signature::new(
- "48 B9 ?? ?? ?? ?? ?? ?? ?? ?? E8 ?? ?? ?? ?? C7 85 ?? ?? ?? ?? 00 00 00 00",
- );
- const SIG_OFFSET: Signature<9> = Signature::new("89 D1 C1 E9 10 48 8B ?? ??");
-
- self.addr_base = SIG_BASE.scan_process_range(game, main_module_range)? + 2;
- self.addr = game.read::(self.addr_base).ok()?.into();
+ if pe::MachineType::read(game, main_module_range.0)?.pointer_size()? != PointerSize::Bit64 {
+ return None;
+ }
- let offset = SIG_OFFSET.scan_process_range(game, main_module_range)? + 8;
- let offset = game.read::(offset).ok()? as u64;
+ const SIG_BASE: Signature<19> =
+ Signature::new("48 8B 05 ?? ?? ?? ?? 48 8B 80 ?? ?? ?? ?? 48 8B 50 ?? E8");
- let addr = game.read::(self.addr + offset).ok()?;
+ let addr = SIG_BASE.scan_process_range(game, main_module_range)? + 3;
- Some(game.read::(addr).ok()?.into())
- } else {
- const SIG: Signature<18> =
- Signature::new("8B 3D 20 ?? ?? ?? 0F B7 D3 8B 04 95 ?? ?? ?? ?? 21 05");
+ self.addr_base = addr + 0x4 + game.read::(addr).ok()?;
- self.addr_base = game
- .memory_ranges()
- .filter(|m| {
- m.flags()
- .unwrap_or_default()
- .contains(MemoryRangeFlags::WRITE)
- })
- .find_map(|m| SIG.scan_process_range(game, m.range().ok()?))?
- + 2;
+ self.offsets = [
+ 0,
+ game.read::(addr + 7).ok()? as u64,
+ game.read::(addr + 14).ok()?.into(),
+ ];
- self.addr = game.read::(self.addr_base).ok()?.into();
- Some(self.addr)
- }
+ Some(
+ game.read_pointer_path::(self.addr_base, PointerSize::Bit64, &self.offsets)
+ .unwrap_or_default()
+ .into(),
+ )
}
- pub fn keep_alive(&self, game: &Process) -> bool {
- if self.is_64_bit {
- game.read::(self.addr_base)
- .is_ok_and(|addr| self.addr == addr.into())
- } else {
- game.read::(self.addr_base)
- .is_ok_and(|addr| self.addr == addr.into())
- }
+ pub fn keep_alive(&self, game: &Process, ram_base: &mut Option) -> bool {
+ *ram_base = Some(
+ game.read_pointer_path::(self.addr_base, PointerSize::Bit64, &self.offsets)
+ .unwrap_or_default()
+ .into(),
+ );
+ true
}
pub const fn new() -> Self {
Self {
- is_64_bit: true,
addr_base: Address::NULL,
- addr: Address::NULL,
+ offsets: [0; 3],
}
}
}
diff --git a/src/emulator/ps1/psxfin.rs b/src/emulator/ps1/psxfin.rs
index 73fc5f02..f6d5d723 100644
--- a/src/emulator/ps1/psxfin.rs
+++ b/src/emulator/ps1/psxfin.rs
@@ -15,26 +15,26 @@ impl State {
.filter(|(_, state)| matches!(state, super::State::PsxFin(_)))
.find_map(|(name, _)| game.get_module_range(name).ok())?;
- let mut ptr: Address32 = if let Some(sig) = SIG.scan_process_range(game, main_module_range)
- {
- game.read(sig + 2).ok()?
- } else if let Some(sig) = SIG_0.scan_process_range(game, main_module_range) {
- game.read(sig + 1).ok()?
- } else if let Some(sig) = SIG_1.scan_process_range(game, main_module_range) {
- game.read(sig + 1).ok()?
- } else if let Some(sig) = SIG_2.scan_process_range(game, main_module_range) {
- game.read(sig + 1).ok()?
- } else {
- return None;
- };
+ let ptr: Address = SIG
+ .scan_process_range(game, main_module_range)
+ .and_then(|addr| {
+ game.read::(addr + 2)
+ .ok()
+ .map(|addr| addr.into())
+ })
+ .or_else(|| SIG_0.scan_process_range(game, main_module_range))
+ .or_else(|| SIG_1.scan_process_range(game, main_module_range))
+ .or_else(|| SIG_2.scan_process_range(game, main_module_range))
+ .and_then(|addr| {
+ game.read::(addr + 1)
+ .ok()
+ .map(|addr| addr.into())
+ })?;
- ptr = game.read::(ptr).ok()?;
-
- if ptr.is_null() {
- None
- } else {
- Some(ptr.into())
- }
+ game.read::(ptr)
+ .ok()
+ .filter(|val| !val.is_null())
+ .map(|addr| addr.into())
}
pub const fn keep_alive(&self) -> bool {
diff --git a/src/emulator/ps1/retroarch.rs b/src/emulator/ps1/retroarch.rs
index 50b7c42b..ccf18ac1 100644
--- a/src/emulator/ps1/retroarch.rs
+++ b/src/emulator/ps1/retroarch.rs
@@ -1,4 +1,6 @@
-use crate::{file_format::pe, signature::Signature, Address, Address32, Address64, Process};
+use crate::{
+ file_format::pe, signature::Signature, Address, Address32, Address64, PointerSize, Process,
+};
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct State {
@@ -20,7 +22,7 @@ impl State {
.find_map(|(name, _)| game.get_module_address(name).ok())?;
let is_64_bit =
- pe::MachineType::read(game, main_module_address) == Some(pe::MachineType::X86_64);
+ pe::MachineType::read(game, main_module_address)?.pointer_size()? == PointerSize::Bit64;
let (core_name, core_address) = SUPPORTED_CORES
.iter()
@@ -28,65 +30,79 @@ impl State {
self.core_base = core_address;
+ let base_scan = pe::symbols(game, core_address)
+ .find(|symbol| {
+ symbol
+ .get_name::<22>(game)
+ .is_ok_and(|name| name.matches(b"retro_get_memory_data"))
+ })?
+ .address;
+
if core_name == SUPPORTED_CORES[0] || core_name == SUPPORTED_CORES[1] {
// Mednafen
if is_64_bit {
- const SIG: Signature<14> =
- Signature::new("48 8B 05 ?? ?? ?? ?? 41 81 E4 FF FF 1F 00");
- let ptr = SIG.scan_process_range(
- game,
- (core_address, game.get_module_size(core_name).ok()?),
- )? + 3;
- let ptr = ptr + 0x4 + game.read::(ptr).ok()?;
- Some(game.read::(ptr).ok()?.into())
+ const SIG: Signature<4> = Signature::new("48 0F 44 05");
+ SIG.scan_process_range(game, (base_scan, 0x100))
+ .map(|addr| addr + 4)
+ .and_then(|addr| {
+ game.read::(addr + 0x4 + game.read::(addr).ok()?)
+ .ok()
+ })
+ .map(|addr| addr.into())
} else {
- const SIG: Signature<11> = Signature::new("A1 ?? ?? ?? ?? 81 E3 FF FF 1F 00");
- let ptr = SIG.scan_process_range(
- game,
- (core_address, game.get_module_size(core_name).ok()?),
- )? + 1;
- let ptr = game.read::(ptr).ok()?;
- Some(game.read::(ptr).ok()?.into())
+ const SIG: Signature<3> = Signature::new("0F 44 05");
+ SIG.scan_process_range(game, (base_scan, 0x100))
+ .map(|addr| addr + 3)
+ .and_then(|addr| {
+ game.read::(game.read::(addr).ok()?)
+ .ok()
+ })
+ .map(|addr| addr.into())
}
} else if core_name == SUPPORTED_CORES[2] {
// Swanstation
if is_64_bit {
- const SIG: Signature<15> =
- Signature::new("48 89 0D ?? ?? ?? ?? 89 35 ?? ?? ?? ?? 89 3D");
- let addr = SIG.scan_process_range(
- game,
- (core_address, game.get_module_size(core_name).ok()?),
- )? + 3;
- let ptr = addr + 0x4 + game.read::(addr).ok()?;
- Some(game.read::(ptr).ok()?.into())
+ const SIG: Signature<8> = Signature::new("48 8B 05 ?? ?? ?? ?? C3");
+ SIG.scan_process_range(game, (base_scan, 0x100))
+ .map(|addr| addr + 3)
+ .and_then(|addr| {
+ game.read::(addr + 0x4 + game.read::(addr).ok()?)
+ .ok()
+ })
+ .map(|addr| addr.into())
} else {
- const SIG: Signature<8> = Signature::new("A1 ?? ?? ?? ?? 23 CB 8B");
- let ptr = SIG.scan_process_range(
- game,
- (core_address, game.get_module_size(core_name).ok()?),
- )? + 1;
- let ptr = game.read::(ptr).ok()?;
- Some(game.read::(ptr).ok()?.into())
+ const SIG: Signature<3> = Signature::new("74 ?? A1");
+ SIG.scan_process_range(game, (base_scan, 0x100))
+ .map(|addr| addr + 3)
+ .and_then(|addr| {
+ game.read::(game.read::(addr).ok()?)
+ .ok()
+ })
+ .map(|addr| addr.into())
}
} else if core_name == SUPPORTED_CORES[3] {
// PCSX ReARMed
if is_64_bit {
- const SIG: Signature<9> = Signature::new("48 8B 35 ?? ?? ?? ?? 81 E2");
- let addr = SIG.scan_process_range(
- game,
- (core_address, game.get_module_size(core_name).ok()?),
- )? + 3;
- let ptr = addr + 0x4 + game.read::(addr).ok()?;
- let ptr = game.read::(ptr).ok()?;
- Some(game.read::(ptr).ok()?.into())
+ const SIG: Signature<10> = Signature::new("48 8B 05 ?? ?? ?? ?? 48 8B 00");
+ SIG.scan_process_range(game, (base_scan, 0x100))
+ .map(|addr| addr + 3)
+ .and_then(|addr| {
+ game.read::(
+ game.read::(addr + 0x4 + game.read::(addr).ok()?)
+ .ok()?,
+ )
+ .ok()
+ })
+ .map(|addr| addr.into())
} else {
- const SIG: Signature<9> = Signature::new("FF FF 1F 00 89 ?? ?? ?? A1");
- let ptr = SIG.scan_process_range(
- game,
- (core_address, game.get_module_size(core_name).ok()?),
- )? + 9;
- let ptr = game.read::(ptr).ok()?;
- Some(game.read::(ptr).ok()?.into())
+ const SIG: Signature<8> = Signature::new("0F 44 05 ?? ?? ?? ?? C3");
+ SIG.scan_process_range(game, (base_scan, 0x100))
+ .map(|addr| addr + 3)
+ .and_then(|addr| {
+ game.read::(game.read::(addr).ok()?)
+ .ok()
+ })
+ .map(|addr| addr.into())
}
} else {
None
diff --git a/src/emulator/ps1/xebra.rs b/src/emulator/ps1/xebra.rs
index 5cbae53d..74ea079d 100644
--- a/src/emulator/ps1/xebra.rs
+++ b/src/emulator/ps1/xebra.rs
@@ -12,11 +12,12 @@ impl State {
.filter(|(_, state)| matches!(state, super::State::Xebra(_)))
.find_map(|(name, _)| game.get_module_range(name).ok())?;
- let ptr = SIG.scan_process_range(game, main_module_range)? + 1;
- let addr = ptr + 0x4 + game.read::(ptr).ok()?;
- let addr = game.read::(addr + 0x16A).ok()?;
- let addr = game.read::(addr).ok()?;
- Some(addr.into())
+ SIG.scan_process_range(game, main_module_range)
+ .map(|addr| addr + 1)
+ .and_then(|addr| Some(addr + 0x4 + game.read::(addr).ok()?))
+ .and_then(|addr| game.read::(addr + 0x16A).ok())
+ .and_then(|addr| game.read::(addr).ok())
+ .map(|addr| addr.into())
}
pub const fn keep_alive(&self) -> bool {