mirror of
https://github.com/obhq/obliteration.git
synced 2024-06-12 17:47:18 -04:00
Implements sys_dynlib_get_info (#672)
This commit is contained in:
parent
f6023d48e5
commit
b741095180
|
@ -279,7 +279,7 @@ impl FileInfo {
|
|||
let id = LE::read_u16(&data[6..]);
|
||||
|
||||
// Lookup name.
|
||||
let name = match self.read_str(name.try_into().unwrap()) {
|
||||
let name = match self.read_str(name as usize) {
|
||||
Ok(v) => v.to_owned(),
|
||||
Err(e) => return Err(ReadModuleError::InvalidNameOffset(name, e)),
|
||||
};
|
||||
|
@ -301,6 +301,15 @@ impl FileInfo {
|
|||
Ok(LibraryInfo::new(id, name, LibraryFlags::empty()))
|
||||
}
|
||||
|
||||
pub fn read_fingerprint(&self, offset: usize) -> [u8; 20] {
|
||||
let offset = offset + self.dynoff;
|
||||
|
||||
let mut fingerprint = [0u8; 20];
|
||||
fingerprint.copy_from_slice(&self.data[offset..(offset + 20)]);
|
||||
|
||||
fingerprint
|
||||
}
|
||||
|
||||
pub fn read_str(&self, offset: usize) -> Result<&str, StringTableError> {
|
||||
// Get raw string.
|
||||
let tab = &self.data[self.strtab..(self.strtab + self.strsz)];
|
||||
|
@ -316,7 +325,9 @@ impl FileInfo {
|
|||
};
|
||||
|
||||
// Get Rust string.
|
||||
std::str::from_utf8(raw).map_err(|_| StringTableError::NotUtf8)
|
||||
let string = std::str::from_utf8(raw)?;
|
||||
|
||||
Ok(string)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -419,3 +430,9 @@ pub enum StringTableError {
|
|||
#[error("the offset is not a UTF-8 string")]
|
||||
NotUtf8,
|
||||
}
|
||||
|
||||
impl From<std::str::Utf8Error> for StringTableError {
|
||||
fn from(_: std::str::Utf8Error) -> Self {
|
||||
Self::NotUtf8
|
||||
}
|
||||
}
|
||||
|
|
|
@ -336,6 +336,10 @@ impl<I: Read + Seek> Elf<I> {
|
|||
self.programs.as_slice()
|
||||
}
|
||||
|
||||
pub fn relro(&self) -> Option<usize> {
|
||||
self.relro
|
||||
}
|
||||
|
||||
pub fn dynamic(&self) -> Option<usize> {
|
||||
self.dynamic
|
||||
}
|
||||
|
|
|
@ -90,3 +90,13 @@ pub enum ProcType {
|
|||
MiniApp,
|
||||
System, // TODO: Verify this.
|
||||
}
|
||||
|
||||
impl Into<u32> for ProcType {
|
||||
fn into(self) -> u32 {
|
||||
match self {
|
||||
ProcType::BigApp => 0,
|
||||
ProcType::MiniApp => 1,
|
||||
ProcType::System => 2,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,18 +43,10 @@ impl TryInto<DmemContainer> for i32 {
|
|||
}
|
||||
}
|
||||
|
||||
impl TryInto<DmemContainer> for usize {
|
||||
type Error = SysErr;
|
||||
|
||||
fn try_into(self) -> Result<DmemContainer, Self::Error> {
|
||||
(self as i32).try_into()
|
||||
}
|
||||
}
|
||||
|
||||
impl DeviceDriver for Dmem {
|
||||
fn ioctl(
|
||||
&self,
|
||||
dev: &Arc<CharacterDevice>,
|
||||
_: &Arc<CharacterDevice>,
|
||||
cmd: IoCmd,
|
||||
td: Option<&VThread>,
|
||||
) -> Result<(), Box<dyn Errno>> {
|
||||
|
@ -76,7 +68,8 @@ impl DeviceDriver for Dmem {
|
|||
}
|
||||
|
||||
match cmd {
|
||||
IoCmd::DMEM10(size) => *size = self.total_size,
|
||||
// TODO: properly implement this
|
||||
IoCmd::DMEMTOTAL(size) => *size = self.total_size,
|
||||
IoCmd::DMEMGETPRT(_prt) => todo!(),
|
||||
IoCmd::DMEMGETAVAIL(_avail) => todo!(),
|
||||
IoCmd::DMEMALLOC(_alloc) => todo!(),
|
||||
|
|
|
@ -6,6 +6,12 @@ use std::sync::Arc;
|
|||
#[derive(Debug)]
|
||||
pub struct BlockPool {}
|
||||
|
||||
impl BlockPool {
|
||||
pub fn new() -> Arc<Self> {
|
||||
Arc::new(Self {})
|
||||
}
|
||||
}
|
||||
|
||||
impl FileBackend for BlockPool {
|
||||
#[allow(unused_variables)] // TODO: remove when implementing
|
||||
fn ioctl(
|
||||
|
|
|
@ -1,14 +1,15 @@
|
|||
use thiserror::Error;
|
||||
|
||||
use crate::dev::{Dmem, DmemContainer};
|
||||
use crate::errno::EINVAL;
|
||||
use crate::fs::{make_dev, CharacterDevice, DriverFlags, Fs, MakeDevError, MakeDevFlags, Mode};
|
||||
use crate::fs::{
|
||||
make_dev, CharacterDevice, DriverFlags, Fs, MakeDevError, MakeDevFlags, Mode, VFile, VFileType,
|
||||
};
|
||||
use crate::info;
|
||||
use crate::process::{VProc, VThread};
|
||||
use crate::process::VThread;
|
||||
use crate::syscalls::{SysErr, SysIn, SysOut, Syscalls};
|
||||
use crate::ucred::{Gid, Privilege, Uid};
|
||||
use crate::ucred::{Gid, Uid};
|
||||
use std::ops::Index;
|
||||
use std::sync::Arc;
|
||||
use thiserror::Error;
|
||||
|
||||
pub use self::blockpool::*;
|
||||
|
||||
|
@ -112,24 +113,31 @@ impl DmemManager {
|
|||
fn sys_dmem_container(self: &Arc<Self>, td: &VThread, i: &SysIn) -> Result<SysOut, SysErr> {
|
||||
let dmem_id: i32 = i.args[0].try_into().unwrap();
|
||||
|
||||
let mut dmem_container = td.proc().dmem_container_mut();
|
||||
let old_dmem_container = *dmem_container;
|
||||
let dmem_container = td.proc().dmem_container_mut();
|
||||
let current_container = *dmem_container;
|
||||
|
||||
if dmem_id != -1 {
|
||||
todo!()
|
||||
}
|
||||
|
||||
Ok(old_dmem_container.into())
|
||||
Ok(current_container.into())
|
||||
}
|
||||
|
||||
fn sys_blockpool_open(self: &Arc<Self>, _td: &VThread, i: &SysIn) -> Result<SysOut, SysErr> {
|
||||
fn sys_blockpool_open(self: &Arc<Self>, td: &VThread, i: &SysIn) -> Result<SysOut, SysErr> {
|
||||
let flags: u32 = i.args[0].try_into().unwrap();
|
||||
|
||||
if flags & 0xffafffff != 0 {
|
||||
return Err(SysErr::Raw(EINVAL));
|
||||
}
|
||||
|
||||
todo!("sys_blockpool_open on new FS")
|
||||
let bp = BlockPool::new();
|
||||
|
||||
let fd = td
|
||||
.proc()
|
||||
.files()
|
||||
.alloc(Arc::new(VFile::new(VFileType::Blockpool(bp))));
|
||||
|
||||
Ok(fd.into())
|
||||
}
|
||||
|
||||
fn sys_blockpool_map(self: &Arc<Self>, _: &VThread, i: &SysIn) -> Result<SysOut, SysErr> {
|
||||
|
@ -158,10 +166,6 @@ impl DmemManager {
|
|||
fn sys_blockpool_move(self: &Arc<Self>, _: &VThread, _i: &SysIn) -> Result<SysOut, SysErr> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn get_dmem_device<'a>(self: &'a Arc<Self>, dmem: DmemContainer) -> &'a DmemDevice {
|
||||
self.index(dmem)
|
||||
}
|
||||
}
|
||||
|
||||
impl Index<DmemContainer> for DmemManager {
|
||||
|
|
|
@ -24,7 +24,7 @@ pub struct VFile {
|
|||
}
|
||||
|
||||
impl VFile {
|
||||
pub(super) fn new(ty: VFileType) -> Self {
|
||||
pub fn new(ty: VFileType) -> Self {
|
||||
let gg = GutexGroup::new();
|
||||
|
||||
Self {
|
||||
|
|
|
@ -112,7 +112,7 @@ commands! {
|
|||
DIPSWCHECK2(&mut i32) = 0x40048806,
|
||||
|
||||
/// Get total size?
|
||||
DMEM10(&mut usize) = 0x4008800a,
|
||||
DMEMTOTAL(&mut usize) = 0x4008800a,
|
||||
/// Get PRT aperture
|
||||
DMEMGETPRT(&mut PrtAperture) = 0xC018800C,
|
||||
/// Get available memory size
|
||||
|
|
|
@ -443,7 +443,7 @@ impl Fs {
|
|||
// Our IoCmd contains both the command and the argument (if there is one).
|
||||
let cmd = IoCmd::try_from_raw_parts(i.args[1].into(), i.args[2].into())?;
|
||||
|
||||
info!("Executing ioctl({cmd:?}) on file descriptor {fd}.");
|
||||
info!("Executing ioctl {cmd:?} on file descriptor {fd}.");
|
||||
|
||||
self.ioctl(fd, cmd, td)?;
|
||||
|
||||
|
|
|
@ -434,7 +434,7 @@ fn run() -> Result<(), KernelError> {
|
|||
.load(path, flags, false, true, &main)
|
||||
.map_err(|e| KernelError::FailedToLoadLibkernel(e.into()))?;
|
||||
|
||||
libkernel.flags_mut().remove(ModuleFlags::UNK2);
|
||||
libkernel.flags_mut().remove(ModuleFlags::IS_NEW);
|
||||
libkernel.print(info!());
|
||||
|
||||
ld.set_kernel(libkernel);
|
||||
|
@ -448,7 +448,7 @@ fn run() -> Result<(), KernelError> {
|
|||
.load(path, flags, false, true, &main)
|
||||
.map_err(|e| KernelError::FailedToLoadLibSceLibcInternal(e.into()))?;
|
||||
|
||||
libc.flags_mut().remove(ModuleFlags::UNK2);
|
||||
libc.flags_mut().remove(ModuleFlags::IS_NEW);
|
||||
libc.print(info!());
|
||||
|
||||
drop(libc);
|
||||
|
|
|
@ -783,7 +783,7 @@ impl VProc {
|
|||
|
||||
ProcTypeInfo {
|
||||
len: size_of::<ProcTypeInfo>(),
|
||||
ty: self.budget_ptype as u32,
|
||||
ty: self.budget_ptype.into(),
|
||||
flags,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -132,7 +132,7 @@ impl RegMgr {
|
|||
// Lookup the entry.
|
||||
let key = RegKey::new(key);
|
||||
let entry = self.lookup(key).ok_or(RegError::NotFound(key))?;
|
||||
let web = if cred.is_webcore_process() || cred.is_diskplayerui_process() {
|
||||
let web = if cred.is_libkernel_web() || cred.is_webprocess_webapp_or_webmas() {
|
||||
1
|
||||
} else {
|
||||
0
|
||||
|
|
|
@ -20,6 +20,7 @@ pub struct Memory {
|
|||
base: usize,
|
||||
text: usize,
|
||||
data: usize,
|
||||
relro: Option<usize>,
|
||||
obcode: usize,
|
||||
obcode_sealed: Gutex<usize>,
|
||||
obdata: usize,
|
||||
|
@ -61,10 +62,8 @@ impl Memory {
|
|||
}
|
||||
}
|
||||
ProgramType::PT_SCE_RELRO => {
|
||||
if relro.is_some() {
|
||||
if relro.replace(segments.len()).is_some() {
|
||||
return Err(MapError::MultipleRelroProgram);
|
||||
} else {
|
||||
relro = Some(segments.len());
|
||||
}
|
||||
}
|
||||
_ => continue,
|
||||
|
@ -132,7 +131,7 @@ impl Memory {
|
|||
len += segment.len;
|
||||
segments.push(segment);
|
||||
|
||||
// Create workspace for our data. We cannot mix this the code because the executable-space
|
||||
// Create workspace for our data. We cannot mix this with the code because the executable-space
|
||||
// protection on some system don't allow execution on writable page.
|
||||
let obdata = segments.len();
|
||||
let segment = MemorySegment {
|
||||
|
@ -180,6 +179,7 @@ impl Memory {
|
|||
base,
|
||||
text,
|
||||
data,
|
||||
relro,
|
||||
obcode,
|
||||
obcode_sealed: gg.spawn(0),
|
||||
obdata,
|
||||
|
@ -212,6 +212,10 @@ impl Memory {
|
|||
&self.segments[self.data]
|
||||
}
|
||||
|
||||
pub fn relro_segment(&self) -> Option<&MemorySegment> {
|
||||
self.relro.as_ref().map(|i| &self.segments[*i])
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
/// Some part of the returned slice may not readable.
|
||||
pub unsafe fn as_bytes(&self) -> &[u8] {
|
||||
|
|
|
@ -129,7 +129,7 @@ impl RuntimeLinker {
|
|||
)
|
||||
.map_err(ExecError::MapFailed)?;
|
||||
|
||||
*app.flags_mut() |= ModuleFlags::MAIN_PROG;
|
||||
*app.flags_mut() |= ModuleFlags::MAINPROG;
|
||||
|
||||
self.ee
|
||||
.setup_module(&mut app)
|
||||
|
@ -270,7 +270,7 @@ impl RuntimeLinker {
|
|||
// TODO: Check the call to sceSblAuthMgrIsLoadable in the self_load_shared_object on the PS4
|
||||
// to see how it is return the value.
|
||||
if name != "libc.sprx" && name != "libSceFios2.sprx" {
|
||||
*md.flags_mut() |= ModuleFlags::UNK1;
|
||||
*md.flags_mut() |= ModuleFlags::IS_SYSTEM;
|
||||
}
|
||||
|
||||
if let Err(e) = self.ee.setup_module(&mut md) {
|
||||
|
@ -335,7 +335,7 @@ impl RuntimeLinker {
|
|||
// Resolve.
|
||||
let dags = md.dag_static();
|
||||
|
||||
let sym = if md.flags().intersects(ModuleFlags::MAIN_PROG) {
|
||||
let sym = if md.flags().intersects(ModuleFlags::MAINPROG) {
|
||||
todo!("do_dlsym on MAIN_PROG");
|
||||
} else {
|
||||
resolver.resolve_from_list(
|
||||
|
@ -451,8 +451,95 @@ impl RuntimeLinker {
|
|||
Ok(SysOut::ZERO)
|
||||
}
|
||||
|
||||
fn sys_dynlib_get_info(self: &Arc<Self>, _td: &VThread, _i: &SysIn) -> Result<SysOut, SysErr> {
|
||||
todo!()
|
||||
fn sys_dynlib_get_info(self: &Arc<Self>, td: &VThread, i: &SysIn) -> Result<SysOut, SysErr> {
|
||||
let handle: u32 = i.args[0].try_into().unwrap();
|
||||
let info = {
|
||||
let info_out: *mut DynlibInfo = i.args[1].into();
|
||||
|
||||
unsafe { &mut *info_out }
|
||||
};
|
||||
|
||||
info!("Getting info for module id = {}.", handle);
|
||||
|
||||
let bin = td.proc().bin();
|
||||
|
||||
let bin = match bin.as_ref() {
|
||||
Some(bin) if bin.app().file_info().is_some() => bin,
|
||||
_ => return Err(SysErr::Raw(EPERM)),
|
||||
};
|
||||
|
||||
if info.size != size_of::<DynlibInfo>() {
|
||||
return Err(SysErr::Raw(EINVAL));
|
||||
}
|
||||
|
||||
*info = self.dynlib_get_info(handle, bin, true)?;
|
||||
|
||||
Ok(SysOut::ZERO)
|
||||
}
|
||||
|
||||
fn dynlib_get_info(
|
||||
&self,
|
||||
handle: u32,
|
||||
bin: &Binaries,
|
||||
no_system: bool,
|
||||
) -> Result<DynlibInfo, SysErr> {
|
||||
let mut info: DynlibInfo = unsafe { zeroed() };
|
||||
|
||||
let mut modules = bin.list();
|
||||
|
||||
let md = modules
|
||||
.find(|m| m.id() == handle)
|
||||
.ok_or(SysErr::Raw(ESRCH))?;
|
||||
|
||||
if no_system && md.flags().intersects(ModuleFlags::IS_SYSTEM) {
|
||||
return Err(SysErr::Raw(EPERM));
|
||||
}
|
||||
|
||||
let name = md.path().file_name().unwrap();
|
||||
|
||||
let mem = md.memory();
|
||||
let addr = mem.addr();
|
||||
|
||||
info.name[..name.len()].copy_from_slice(name.as_bytes());
|
||||
info.name[0xff] = 0;
|
||||
info.segment_count = 2;
|
||||
|
||||
info.text_segment.addr = mem.base();
|
||||
info.text_segment.size = mem.text_segment().len().try_into().unwrap();
|
||||
info.text_segment.prot = 5;
|
||||
|
||||
info.data_segment.addr = addr + mem.data_segment().start();
|
||||
info.data_segment.size = mem.data_segment().len().try_into().unwrap();
|
||||
info.data_segment.prot = 3;
|
||||
|
||||
if let Some(seg) = mem.relro_segment() {
|
||||
info.relro_segment.addr = addr + seg.start();
|
||||
info.relro_segment.size = seg.len().try_into().unwrap();
|
||||
info.relro_segment.prot = 1;
|
||||
|
||||
info.segment_count += 1;
|
||||
};
|
||||
|
||||
info.fingerprint = md.fingerprint();
|
||||
|
||||
let mut e = info!();
|
||||
|
||||
writeln!(
|
||||
e,
|
||||
"Retrieved info for module {} (ID = {}).",
|
||||
md.path(),
|
||||
handle
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
writeln!(e, "mapbase : {:#x}", info.text_segment.addr).unwrap();
|
||||
writeln!(e, "textsize: {:#x}", info.text_segment.size).unwrap();
|
||||
writeln!(e, "database: {:#x}", info.data_segment.addr).unwrap();
|
||||
writeln!(e, "datasize: {:#x}", info.data_segment.size).unwrap();
|
||||
|
||||
print(e);
|
||||
|
||||
Ok(info)
|
||||
}
|
||||
|
||||
fn sys_dynlib_load_prx(self: &Arc<Self>, td: &VThread, i: &SysIn) -> Result<SysOut, SysErr> {
|
||||
|
@ -703,7 +790,7 @@ impl RuntimeLinker {
|
|||
|
||||
self.relocate_rela(md, mem.as_mut(), &mut relocated, resolver)?;
|
||||
|
||||
if !md.flags().contains(ModuleFlags::UNK4) {
|
||||
if !md.flags().contains(ModuleFlags::JMPSLOTS_DONE) {
|
||||
self.relocate_plt(md, mem.as_mut(), &mut relocated, resolver)?;
|
||||
}
|
||||
|
||||
|
@ -892,6 +979,8 @@ impl RuntimeLinker {
|
|||
let flags: u32 = i.args[1].try_into().unwrap();
|
||||
let info: *mut DynlibInfoEx = i.args[2].into();
|
||||
|
||||
info!("Getting info_ex for module id = {}.", handle);
|
||||
|
||||
// Check if application is dynamic linking.
|
||||
let bin = td.proc().bin();
|
||||
let bin = bin.as_ref().ok_or(SysErr::Raw(EPERM))?;
|
||||
|
@ -901,9 +990,8 @@ impl RuntimeLinker {
|
|||
}
|
||||
|
||||
// Check buffer size.
|
||||
let size: usize = unsafe { (*info).size.try_into().unwrap() };
|
||||
|
||||
if size != size_of::<DynlibInfoEx>() {
|
||||
if unsafe { (*info).size } != size_of::<DynlibInfoEx>() {
|
||||
return Err(SysErr::Raw(EINVAL));
|
||||
}
|
||||
|
||||
|
@ -920,17 +1008,20 @@ impl RuntimeLinker {
|
|||
|
||||
*info = unsafe { zeroed() };
|
||||
info.handle = md.id();
|
||||
info.mapbase = addr + mem.base();
|
||||
info.textsize = mem.text_segment().len().try_into().unwrap();
|
||||
info.unk3 = 5;
|
||||
info.database = addr + mem.data_segment().start();
|
||||
info.datasize = mem.data_segment().len().try_into().unwrap();
|
||||
info.unk4 = 3;
|
||||
info.unk6 = 2;
|
||||
|
||||
info.text_segment.addr = addr + mem.base();
|
||||
info.text_segment.size = mem.text_segment().len().try_into().unwrap();
|
||||
info.text_segment.prot = 5;
|
||||
|
||||
info.data_segment.addr = addr + mem.data_segment().start();
|
||||
info.data_segment.size = mem.data_segment().len().try_into().unwrap();
|
||||
info.data_segment.prot = 3;
|
||||
|
||||
info.segment_count = 2;
|
||||
info.refcount = *md.ref_count();
|
||||
|
||||
// Copy module name.
|
||||
if flags & 2 == 0 || !md.flags().contains(ModuleFlags::UNK1) {
|
||||
if flags & 2 == 0 || !md.flags().contains(ModuleFlags::IS_SYSTEM) {
|
||||
let name = md.path().file_name().unwrap();
|
||||
|
||||
info.name[..name.len()].copy_from_slice(name.as_bytes());
|
||||
|
@ -941,13 +1032,13 @@ impl RuntimeLinker {
|
|||
// Let's keep the same behavior as the PS4 for now.
|
||||
info.tlsindex = if flags & 1 != 0 {
|
||||
let flags = md.flags();
|
||||
let mut upper = if flags.contains(ModuleFlags::UNK1) {
|
||||
let mut upper = if flags.contains(ModuleFlags::IS_SYSTEM) {
|
||||
1
|
||||
} else {
|
||||
0
|
||||
};
|
||||
|
||||
if flags.contains(ModuleFlags::MAIN_PROG) {
|
||||
if flags.contains(ModuleFlags::MAINPROG) {
|
||||
upper += 2;
|
||||
}
|
||||
|
||||
|
@ -968,7 +1059,7 @@ impl RuntimeLinker {
|
|||
info.tlsoffset = (*md.tls_offset()).try_into().unwrap();
|
||||
|
||||
// Initialization and finalization functions.
|
||||
if !md.flags().contains(ModuleFlags::UNK5) {
|
||||
if !md.flags().contains(ModuleFlags::NOT_GET_PROC) {
|
||||
info.init = md.init().map(|v| addr + v).unwrap_or(0);
|
||||
info.fini = md.fini().map(|v| addr + v).unwrap_or(0);
|
||||
}
|
||||
|
@ -987,15 +1078,16 @@ impl RuntimeLinker {
|
|||
|
||||
writeln!(
|
||||
e,
|
||||
"Retrieved info for module {} (ID = {}).",
|
||||
"Retrieved info_ex for module {} (ID = {}).",
|
||||
md.path(),
|
||||
handle
|
||||
)
|
||||
.unwrap();
|
||||
writeln!(e, "mapbase : {:#x}", info.mapbase).unwrap();
|
||||
writeln!(e, "textsize : {:#x}", info.textsize).unwrap();
|
||||
writeln!(e, "database : {:#x}", info.database).unwrap();
|
||||
writeln!(e, "datasize : {:#x}", info.datasize).unwrap();
|
||||
|
||||
writeln!(e, "mapbase : {:#x}", info.text_segment.addr).unwrap();
|
||||
writeln!(e, "textsize : {:#x}", info.text_segment.size).unwrap();
|
||||
writeln!(e, "database : {:#x}", info.data_segment.addr).unwrap();
|
||||
writeln!(e, "datasize : {:#x}", info.data_segment.size).unwrap();
|
||||
writeln!(e, "tlsindex : {}", info.tlsindex).unwrap();
|
||||
writeln!(e, "tlsinit : {:#x}", info.tlsinit).unwrap();
|
||||
writeln!(e, "tlsoffset : {:#x}", info.tlsoffset).unwrap();
|
||||
|
@ -1043,9 +1135,33 @@ impl RuntimeLinker {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[repr(C)]
|
||||
struct SegmentInfo {
|
||||
addr: usize,
|
||||
size: u32,
|
||||
prot: u32,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[repr(C)]
|
||||
struct DynlibInfo {
|
||||
size: usize,
|
||||
name: [u8; 256],
|
||||
text_segment: SegmentInfo,
|
||||
data_segment: SegmentInfo,
|
||||
relro_segment: SegmentInfo,
|
||||
unk_segment: SegmentInfo,
|
||||
segment_count: u32,
|
||||
fingerprint: [u8; 0x14],
|
||||
}
|
||||
|
||||
const _: () = assert!(size_of::<DynlibInfo>() == 0x160);
|
||||
|
||||
#[derive(Debug)]
|
||||
#[repr(C)]
|
||||
struct DynlibInfoEx {
|
||||
size: u64,
|
||||
size: usize,
|
||||
name: [u8; 256],
|
||||
handle: u32,
|
||||
tlsindex: u32,
|
||||
|
@ -1062,17 +1178,16 @@ struct DynlibInfoEx {
|
|||
eh_frame: usize,
|
||||
eh_frame_hdr_size: u32,
|
||||
eh_frame_size: u32,
|
||||
mapbase: usize,
|
||||
textsize: u32,
|
||||
unk3: u32, // Always 5.
|
||||
database: usize,
|
||||
datasize: u32,
|
||||
unk4: u32, // Always 3.
|
||||
unk5: [u8; 0x20], // Always zeroes.
|
||||
unk6: u32, // Always 2.
|
||||
text_segment: SegmentInfo,
|
||||
data_segment: SegmentInfo,
|
||||
relro_segment: SegmentInfo,
|
||||
unk_segment: SegmentInfo,
|
||||
segment_count: u32, // Always 2.
|
||||
refcount: u32,
|
||||
}
|
||||
|
||||
const _: () = assert!(size_of::<DynlibInfoEx>() == 0x1a8);
|
||||
|
||||
/// Contains how TLS was allocated so far.
|
||||
#[derive(Debug)]
|
||||
pub struct TlsAlloc {
|
||||
|
|
|
@ -39,6 +39,7 @@ pub struct Module {
|
|||
needed: Vec<NeededModule>,
|
||||
modules: Vec<ModuleInfo>,
|
||||
libraries: Vec<LibraryInfo>,
|
||||
fingerprint: [u8; 20],
|
||||
memory: Memory,
|
||||
relocated: Gutex<Vec<Option<Relocated>>>,
|
||||
file_info: Option<FileInfo>,
|
||||
|
@ -173,13 +174,14 @@ impl Module {
|
|||
proc_param,
|
||||
mod_param,
|
||||
sdk_ver,
|
||||
flags: gg.spawn(ModuleFlags::UNK2),
|
||||
flags: gg.spawn(ModuleFlags::IS_NEW),
|
||||
names,
|
||||
dag_static: gg.spawn(Vec::new()),
|
||||
dag_dynamic: gg.spawn(Vec::new()),
|
||||
needed: Vec::new(),
|
||||
modules: Vec::new(),
|
||||
libraries: Vec::new(),
|
||||
fingerprint: [0; 20],
|
||||
memory,
|
||||
relocated: gg.spawn(Vec::new()),
|
||||
file_info: None,
|
||||
|
@ -284,6 +286,10 @@ impl Module {
|
|||
self.libraries.as_ref()
|
||||
}
|
||||
|
||||
pub fn fingerprint(&self) -> [u8; 20] {
|
||||
self.fingerprint
|
||||
}
|
||||
|
||||
pub fn memory(&self) -> &Memory {
|
||||
&self.memory
|
||||
}
|
||||
|
@ -550,6 +556,8 @@ impl Module {
|
|||
/// See `digest_dynamic` on the PS4 for a reference.
|
||||
fn digest_dynamic(&mut self, base: usize, info: &FileInfo) -> Result<(), MapError> {
|
||||
// TODO: Implement the remaining tags.
|
||||
let mut fingerprint_offset = None;
|
||||
|
||||
for (i, (tag, value)) in info.dynamic().enumerate() {
|
||||
match tag {
|
||||
DynamicTag::DT_NULL => break,
|
||||
|
@ -579,6 +587,9 @@ impl Module {
|
|||
DynamicTag::DT_SONAME => self.digest_soname(info, i, value)?,
|
||||
DynamicTag::DT_TEXTREL => *self.flags.get_mut() |= ModuleFlags::TEXT_REL,
|
||||
DynamicTag::DT_FLAGS => self.digest_flags(value)?,
|
||||
DynamicTag::DT_SCE_FINGERPRINT => {
|
||||
fingerprint_offset = Some(u64::from_le_bytes(value) as usize)
|
||||
}
|
||||
DynamicTag::DT_SCE_MODULE_INFO | DynamicTag::DT_SCE_NEEDED_MODULE => {
|
||||
self.digest_module_info(info, i, value)?;
|
||||
}
|
||||
|
@ -589,6 +600,8 @@ impl Module {
|
|||
}
|
||||
}
|
||||
|
||||
self.digest_fingerprint(info, fingerprint_offset.unwrap_or(0));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -645,6 +658,12 @@ impl Module {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn digest_fingerprint(&mut self, info: &FileInfo, offset: usize) {
|
||||
let fingerprint = info.read_fingerprint(offset);
|
||||
|
||||
self.fingerprint = fingerprint;
|
||||
}
|
||||
|
||||
fn digest_module_info(
|
||||
&mut self,
|
||||
info: &FileInfo,
|
||||
|
@ -739,18 +758,17 @@ bitflags! {
|
|||
/// Flags for [`Module`].
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub struct ModuleFlags: u16 {
|
||||
const MAIN_PROG = 0x0001;
|
||||
const MAINPROG = 0x0001;
|
||||
const TEXT_REL = 0x0002;
|
||||
const JMPSLOTS_DONE = 0x0004; // TODO: This seems incorrect.
|
||||
const TLS_DONE = 0x0008;
|
||||
const INIT_SCANNED = 0x0010;
|
||||
const ON_FINI_LIST = 0x0020;
|
||||
const DAG_INITED = 0x0040;
|
||||
const UNK1 = 0x0100; // TODO: Rename this.
|
||||
const UNK2 = 0x0200; // TODO: Rename this.
|
||||
const UNK3 = 0x0400; // TODO: Rename this.
|
||||
const UNK4 = 0x0800; // TODO: It seems like this is actually JMPSLOTS_DONE.
|
||||
const UNK5 = 0x1000; // TODO: Rename this.
|
||||
const IS_SYSTEM = 0x0100;
|
||||
const IS_NEW = 0x0200;
|
||||
const LIBC_FIOS = 0x0400;
|
||||
const JMPSLOTS_DONE = 0x0800;
|
||||
const NOT_GET_PROC = 0x1000;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -72,7 +72,7 @@ impl AuthPaid {
|
|||
/// A wrapper type for `caps` field of [`AuthInfo`].
|
||||
#[repr(transparent)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct AuthCaps([u64; 4]);
|
||||
pub struct AuthCaps(pub(super) [u64; 4]);
|
||||
|
||||
impl AuthCaps {
|
||||
pub fn new(raw: [u64; 4]) -> Self {
|
||||
|
@ -87,14 +87,6 @@ impl AuthCaps {
|
|||
(self.0[0] & 0x2000000000000000) != 0
|
||||
}
|
||||
|
||||
pub fn is_jit_compiler_process(&self) -> bool {
|
||||
todo!()
|
||||
}
|
||||
|
||||
pub fn is_jit_application_process(&self) -> bool {
|
||||
todo!()
|
||||
}
|
||||
|
||||
pub fn has_use_video_service_capability(&self) -> bool {
|
||||
self.0[0] >> 0x39 & 1 != 0
|
||||
}
|
||||
|
@ -126,11 +118,20 @@ impl AuthAttrs {
|
|||
}
|
||||
|
||||
pub fn has_sce_program_attribute(&self) -> bool {
|
||||
todo!()
|
||||
(self.0[0] & 0x80000000) != 0
|
||||
}
|
||||
|
||||
pub fn is_debuggable_process(&self) -> bool {
|
||||
todo!()
|
||||
if self.0[0] & 0x1000000 == 0 {
|
||||
if self.0[0] & 0x2000000 != 0 {
|
||||
true
|
||||
} else {
|
||||
// TODO: properly implement this branch.
|
||||
false
|
||||
}
|
||||
} else {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_unk1(&self) -> bool {
|
||||
|
|
|
@ -57,13 +57,13 @@ impl Ucred {
|
|||
self.groups[1..].binary_search(&gid).is_ok()
|
||||
}
|
||||
|
||||
pub fn is_unknown1(&self) -> bool {
|
||||
pub fn is_libkernel_web(&self) -> bool {
|
||||
// TODO: Refactor this for readability.
|
||||
let id = self.auth.paid.get().wrapping_add(0xc7ffffffeffffffc);
|
||||
(id < 0xf) && ((0x6001 >> (id & 0x3f) & 1) != 0)
|
||||
let val = self.auth.paid.get().wrapping_add(0xc7ffffffeffffffc);
|
||||
(val < 0xf) && ((0x6001 >> (val & 0x3f) & 1) != 0)
|
||||
}
|
||||
|
||||
pub fn is_unknown2(&self) -> bool {
|
||||
pub fn is_webprocess_webapp_or_webmas(&self) -> bool {
|
||||
matches!(
|
||||
self.auth.paid.get(),
|
||||
0x380000001000000f | 0x3800000010000013
|
||||
|
@ -77,12 +77,36 @@ impl Ucred {
|
|||
|
||||
/// See `sceSblACMgrIsJitCompilerProcess` on the PS4 for a reference.
|
||||
pub fn is_jit_compiler_process(&self) -> bool {
|
||||
self.auth.caps.is_jit_compiler_process()
|
||||
let val = self.auth.caps.0[1];
|
||||
|
||||
if val >> 0x3e & 1 == 0 {
|
||||
if val >> 0x38 & 1 != 0 && !todo!() {
|
||||
true
|
||||
} else if (self.auth.paid.get() >> 56) == 0x31 && !todo!() {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
} else {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
/// See `sceSblACMgrIsJitCompilerProcess` on the PS4 for a reference.
|
||||
/// See `sceSblACMgrIsJitApplicationProcess` on the PS4 for a reference.
|
||||
pub fn is_jit_application_process(&self) -> bool {
|
||||
self.auth.caps.is_jit_application_process()
|
||||
let val = self.auth.caps.0[1];
|
||||
|
||||
if val >> 0x3d & 1 == 0 {
|
||||
if val >> 0x38 & 1 != 0 && !todo!() {
|
||||
true
|
||||
} else if (self.auth.paid.get() >> 56) == 0x31 && !todo!() {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
} else {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
/// See `sceSblACMgrIsVideoplayerProcess` on the PS4 for a reference.
|
||||
|
@ -97,14 +121,17 @@ impl Ucred {
|
|||
|
||||
/// See `sceSblACMgrIsWebcoreProcess` on the PS4 for a reference.
|
||||
pub fn is_webcore_process(&self) -> bool {
|
||||
todo!()
|
||||
let val = self.auth.paid.get().wrapping_add(0xc7ffffffeffffffd);
|
||||
|
||||
(val < 0x11) && (0x1d003 >> (val & 0x3f) & 1 != 0)
|
||||
}
|
||||
|
||||
/// See `sceSblACMgrHasSceProgramAttribute` on the PS4 for a reference.
|
||||
pub fn has_sce_program_attribute(&self) -> bool {
|
||||
self.auth.attrs.has_sce_program_attribute()
|
||||
}
|
||||
|
||||
/// See `sceSblACMgrHasSceProgramAttribute` on the PS4 for a reference.
|
||||
/// See `sceSblACMgrIsDebuggableProcess` on the PS4 for a reference.
|
||||
pub fn is_debuggable_process(&self) -> bool {
|
||||
self.auth.attrs.is_debuggable_process()
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@ privileges! {
|
|||
/// See https://github.com/freebsd/freebsd-src/blob/release/9.1.0/sys/sys/priv.h for standard
|
||||
/// FreeBSD privileges.
|
||||
#[repr(i32)]
|
||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||
#[derive(PartialEq, Eq)]
|
||||
pub enum Privilege {
|
||||
/// Exceed system open files limit.
|
||||
#[allow(unused)]
|
||||
|
@ -57,6 +57,7 @@ privileges! {
|
|||
/// Currently unknown.
|
||||
SCE683 = 683,
|
||||
/// Currently unknown.
|
||||
#[allow(unused)]
|
||||
SCE685 = 685,
|
||||
/// Currently unknown.
|
||||
SCE686 = 686,
|
||||
|
|
|
@ -295,11 +295,11 @@ impl Vm {
|
|||
}
|
||||
|
||||
/// See `vm_map_set_name` on the PS4 for a reference.
|
||||
pub fn mname<N: AsRef<str>>(
|
||||
pub fn mname(
|
||||
&self,
|
||||
addr: *mut u8,
|
||||
len: usize,
|
||||
name: N,
|
||||
name: impl AsRef<str>,
|
||||
) -> Result<(), MemoryUpdateError> {
|
||||
let name = name.as_ref();
|
||||
let sname = CString::new(name);
|
||||
|
@ -310,7 +310,7 @@ impl Vm {
|
|||
|i| i.name != name,
|
||||
|i| {
|
||||
if let Ok(name) = &sname {
|
||||
i.storage.set_name(i.addr, i.len, name).ok();
|
||||
let _ = i.storage.set_name(i.addr, i.len, name);
|
||||
}
|
||||
|
||||
i.name = name.to_owned();
|
||||
|
@ -510,7 +510,7 @@ impl Vm {
|
|||
|
||||
// Set storage name if supported.
|
||||
if let Ok(name) = CString::new(name.as_str()) {
|
||||
storage.set_name(addr, len, &name).ok();
|
||||
let _ = storage.set_name(addr, len, &name);
|
||||
}
|
||||
|
||||
Ok(Alloc {
|
||||
|
|
Loading…
Reference in a new issue