Partial commit: Loader

This commit is contained in:
Nekotekina 2016-02-02 00:47:09 +03:00
parent 250ce63527
commit 2553e45d76
13 changed files with 450 additions and 1885 deletions

348
rpcs3/Loader/ELF.h Normal file
View File

@ -0,0 +1,348 @@
#pragma once
#include "../../Utilities/File.h"
enum class elf_os : u8
{
none = 0,
lv2 = 0x66,
};
enum class elf_type : u16
{
none = 0,
rel = 1,
exec = 2,
dyn = 3,
core = 4,
prx = 0xffa4,
psv1 = 0xfe00, // ET_SCE_EXEC
psv2 = 0xfe04, // ET_SCE_RELEXEC (vitasdk)
};
enum class elf_machine : u16
{
ppc64 = 0x15,
spu = 0x17,
arm = 0x28,
mips = 0x08,
};
template<template<typename T> class en_t, typename sz_t>
struct elf_ehdr
{
nse_t<u32> e_magic;
u8 e_class;
u8 e_data;
u8 e_curver;
elf_os e_os_abi;
u8 e_abi_ver;
u8 e_pad[7];
en_t<elf_type> e_type;
en_t<elf_machine> e_machine;
en_t<u32> e_version;
en_t<sz_t> e_entry;
en_t<sz_t> e_phoff;
en_t<sz_t> e_shoff;
en_t<u32> e_flags;
en_t<u16> e_ehsize;
en_t<u16> e_phentsize;
en_t<u16> e_phnum;
en_t<u16> e_shentsize;
en_t<u16> e_shnum;
en_t<u16> e_shstrndx;
};
template<template<typename T> class en_t, typename sz_t>
struct elf_phdr
{
static_assert(!sizeof(sz_t), "Invalid elf size type (must be u32 or u64)");
};
template<template<typename T> class en_t>
struct elf_phdr<en_t, u64>
{
en_t<u32> p_type;
en_t<u32> p_flags;
en_t<u64> p_offset;
en_t<u64> p_vaddr;
en_t<u64> p_paddr;
en_t<u64> p_filesz;
en_t<u64> p_memsz;
en_t<u64> p_align;
};
template<template<typename T> class en_t>
struct elf_phdr<en_t, u32>
{
en_t<u32> p_type;
en_t<u32> p_offset;
en_t<u32> p_vaddr;
en_t<u32> p_paddr;
en_t<u32> p_filesz;
en_t<u32> p_memsz;
en_t<u32> p_flags;
en_t<u32> p_align;
};
template<template<typename T> class en_t, typename sz_t>
struct elf_prog final : elf_phdr<en_t, sz_t>
{
std::vector<char> bin;
using base = elf_phdr<en_t, sz_t>;
elf_prog() = default;
elf_prog(u32 type, u32 flags, sz_t vaddr, sz_t memsz, sz_t align, std::vector<char>&& bin)
: bin(std::move(bin))
{
base::p_type = type;
base::p_flags = flags;
base::p_vaddr = vaddr;
base::p_memsz = memsz;
base::p_align = align;
base::p_filesz = static_cast<sz_t>(bin.size());
base::p_paddr = 0;
base::p_offset = -1;
}
};
template<template<typename T> class en_t, typename sz_t>
struct elf_shdr
{
en_t<u32> sh_name;
en_t<u32> sh_type;
en_t<sz_t> sh_flags;
en_t<sz_t> sh_addr;
en_t<sz_t> sh_offset;
en_t<sz_t> sh_size;
en_t<u32> sh_link;
en_t<u32> sh_info;
en_t<sz_t> sh_addralign;
en_t<sz_t> sh_entsize;
};
// Default elf_loader::load() return type, specialized to change.
template<typename T>
struct elf_load_result
{
using type = void;
};
// ELF loader errors
enum class elf_error
{
ok = 0,
stream,
stream_header,
stream_phdrs,
stream_shdrs,
stream_data,
header_magic,
header_version,
header_class,
header_machine,
header_endianness,
header_type,
header_os,
};
// ELF loader error information
template<>
struct bijective<elf_error, const char*>
{
static constexpr std::pair<elf_error, const char*> map[]
{
{ elf_error::ok, "" },
{ elf_error::stream, "Invalid stream" },
{ elf_error::stream_header, "Failed to read ELF header" },
{ elf_error::stream_phdrs, "Failed to read ELF program headers" },
{ elf_error::stream_shdrs, "Failed to read ELF section headers" },
{ elf_error::stream_data, "Failed to read ELF program data" },
{ elf_error::header_magic, "Not an ELF" },
{ elf_error::header_version, "Invalid or unsupported ELF format" },
{ elf_error::header_class, "Invalid ELF class" },
{ elf_error::header_machine, "Invalid ELF machine" },
{ elf_error::header_endianness, "Invalid ELF data (endianness)" },
{ elf_error::header_type, "Invalid ELF type" },
{ elf_error::header_os, "Invalid ELF OS ABI" },
};
};
// ELF loader with specified parameters.
// en_t: endianness (specify le_t or be_t)
// sz_t: size (specify u32 for ELF32, u64 for ELF64)
template<template<typename T> class en_t, typename sz_t, elf_machine Machine, elf_os OS, elf_type Type>
class elf_loader
{
elf_error m_error{};
elf_error error(elf_error e)
{
return m_error = e;
}
public:
using ehdr_t = elf_ehdr<en_t, sz_t>;
using phdr_t = elf_phdr<en_t, sz_t>;
using shdr_t = elf_shdr<en_t, sz_t>;
using prog_t = elf_prog<en_t, sz_t>;
ehdr_t header{};
std::vector<prog_t> progs;
std::vector<shdr_t> shdrs;
public:
elf_loader() = default;
elf_loader(const fs::file& stream, u64 offset = 0)
{
open(stream, offset);
}
elf_error open(const fs::file& stream, u64 offset = 0)
{
// Check stream
if (!stream)
return error(elf_error::stream);
// Read ELF header
stream.seek(offset);
if (!stream.read(header))
return error(elf_error::stream_header);
// Check magic
if (header.e_magic != "\177ELF"_u32)
return error(elf_error::header_magic);
// Check class
if (header.e_class != (std::is_same<sz_t, u32>::value ? 1 : 2))
return error(elf_error::header_class);
// Check endianness
if (header.e_data != (std::is_same<en_t<u32>, le_t<u32>>::value ? 1 : 2))
return error(elf_error::header_endianness);
// Check machine
if (header.e_machine != Machine)
return error(elf_error::header_machine);
// Check OS only if specified (hack)
if (OS != elf_os::none && header.e_os_abi != OS)
return error(elf_error::header_os);
// Check type only if specified (hack)
if (Type != elf_type::none && header.e_type != Type)
return error(elf_error::header_type);
// Check version and other params
if (header.e_curver != 1 || header.e_version != 1 || header.e_ehsize != sizeof(ehdr_t))
return error(elf_error::header_version);
if (header.e_phnum && header.e_phentsize != sizeof(phdr_t))
return error(elf_error::header_version);
if (header.e_shnum && header.e_shentsize != sizeof(shdr_t))
return error(elf_error::header_version);
// Load program headers
std::vector<phdr_t> _phdrs(header.e_phnum);
stream.seek(offset + header.e_phoff);
if (!stream.read(_phdrs))
return error(elf_error::stream_phdrs);
shdrs.resize(header.e_shnum);
stream.seek(offset + header.e_shoff);
if (!stream.read(shdrs))
return error(elf_error::stream_shdrs);
progs.clear();
progs.reserve(_phdrs.size());
for (const auto& hdr : _phdrs)
{
progs.emplace_back();
static_cast<phdr_t&>(progs.back()) = hdr;
progs.back().bin.resize(hdr.p_filesz);
stream.seek(offset + hdr.p_offset);
if (!stream.read(progs.back().bin))
return error(elf_error::stream_data);
}
shdrs.shrink_to_fit();
progs.shrink_to_fit();
return m_error = elf_error::ok;
}
void save(const fs::file& stream) const
{
// Write header
ehdr_t header{};
header.e_magic = "\177ELF"_u32;
header.e_class = std::is_same<sz_t, u32>::value ? 1 : 2;
header.e_data = std::is_same<en_t<u32>, le_t<u32>>::value ? 1 : 2;
header.e_curver = 1;
header.e_os_abi = OS != elf_os::none ? OS : this->header.e_os_abi;
header.e_abi_ver = this->header.e_abi_ver;
header.e_type = Type != elf_type::none ? Type : this->header.e_type;
header.e_machine = Machine;
header.e_version = 1;
header.e_entry = this->header.e_entry;
header.e_phoff = SIZE_32(ehdr_t);
header.e_shoff = SIZE_32(ehdr_t) + SIZE_32(phdr_t) * ::size32(progs);
header.e_flags = this->header.e_flags;
header.e_ehsize = SIZE_32(ehdr_t);
header.e_phentsize = SIZE_32(phdr_t);
header.e_phnum = ::size32(progs);
header.e_shentsize = SIZE_32(shdr_t);
header.e_shnum = ::size32(shdrs);
header.e_shstrndx = this->header.e_shstrndx;
stream.write(header);
sz_t off = header.e_shoff + SIZE_32(shdr_t) * ::size32(shdrs);
for (phdr_t phdr : progs)
{
phdr.p_offset = std::exchange(off, off + phdr.p_filesz);
stream.write(phdr);
}
for (shdr_t shdr : shdrs)
{
// TODO?
stream.write(shdr);
}
// Write data
for (const auto& prog : progs)
{
stream.write(prog.bin);
}
}
// Return error code
operator elf_error() const
{
return m_error;
}
// Format-specific loader function (must be specialized)
typename elf_load_result<elf_loader>::type load() const;
};
using ppu_exec_loader = elf_loader<be_t, u64, elf_machine::ppc64, elf_os::none, elf_type::exec>;
using ppu_prx_loader = elf_loader<be_t, u64, elf_machine::ppc64, elf_os::lv2, elf_type::prx>;
using spu_exec_loader = elf_loader<be_t, u32, elf_machine::spu, elf_os::none, elf_type::exec>;
using arm_exec_loader = elf_loader<le_t, u32, elf_machine::arm, elf_os::none, elf_type::none>;
template<> struct elf_load_result<ppu_prx_loader> { using type = std::shared_ptr<struct lv2_prx_t>; };

View File

@ -1,453 +0,0 @@
#include "stdafx.h"
#include "ELF32.h"
#include "Emu/FS/vfsStream.h"
#include "Emu/Memory/Memory.h"
#include "Emu/Cell/SPUThread.h"
#include "Emu/ARMv7/ARMv7Thread.h"
#include "Emu/ARMv7/ARMv7Decoder.h"
#include "Emu/ARMv7/PSVFuncList.h"
#include "Emu/System.h"
#include "Emu/state.h"
extern void armv7_init_tls();
namespace loader
{
namespace handlers
{
handler::error_code elf32::init(vfsStream& stream)
{
m_ehdr = {};
m_phdrs.clear();
m_shdrs.clear();
error_code res = handler::init(stream);
if (res != ok)
{
return res;
}
m_stream->Read(&m_ehdr, sizeof(ehdr));
if (!m_ehdr.check())
{
return bad_file;
}
if (m_ehdr.data_le.e_phnum && (m_ehdr.is_le() ? m_ehdr.data_le.e_phentsize != sizeof(phdr) : m_ehdr.data_be.e_phentsize != sizeof(phdr)))
{
return broken_file;
}
if (m_ehdr.data_le.e_shnum && (m_ehdr.is_le() ? m_ehdr.data_le.e_shentsize != sizeof(shdr) : m_ehdr.data_be.e_shentsize != sizeof(shdr)))
{
return broken_file;
}
LOG_WARNING(LOADER, "m_ehdr.e_type = 0x%x", m_ehdr.is_le() ? m_ehdr.data_le.e_type : m_ehdr.data_be.e_type.value());
if (m_ehdr.data_le.e_phnum)
{
m_phdrs.resize(m_ehdr.is_le() ? m_ehdr.data_le.e_phnum : m_ehdr.data_be.e_phnum.value());
m_stream->Seek(handler::get_stream_offset() + (m_ehdr.is_le() ? m_ehdr.data_le.e_phoff : m_ehdr.data_be.e_phoff.value()));
size_t size = (m_ehdr.is_le() ? m_ehdr.data_le.e_phnum : m_ehdr.data_be.e_phnum.value()) * sizeof(phdr);
if (m_stream->Read(m_phdrs.data(), size) != size)
return broken_file;
}
if (m_ehdr.data_le.e_shnum)
{
m_shdrs.resize(m_ehdr.is_le() ? m_ehdr.data_le.e_shnum : m_ehdr.data_be.e_shnum.value());
m_stream->Seek(handler::get_stream_offset() + (m_ehdr.is_le() ? m_ehdr.data_le.e_shoff : m_ehdr.data_be.e_shoff.value()));
size_t size = (m_ehdr.is_le() ? m_ehdr.data_le.e_shnum : m_ehdr.data_be.e_shnum.value()) * sizeof(shdr);
if (m_stream->Read(m_shdrs.data(), size) != size)
return broken_file;
}
return ok;
}
handler::error_code elf32::load()
{
Elf_Machine machine;
switch (machine = (Elf_Machine)(u16)(m_ehdr.is_le() ? m_ehdr.data_le.e_machine : m_ehdr.data_be.e_machine.value()))
{
case MACHINE_MIPS: vm::psp::init(); break;
case MACHINE_ARM: vm::psv::init(); break;
case MACHINE_SPU: vm::ps3::init(); break;
default:
return bad_version;
}
error_code res = load_data(0);
if (res != ok)
return res;
switch (machine)
{
case MACHINE_MIPS: break;
case MACHINE_ARM:
{
struct psv_libc_param_t
{
u32 size; // 0x0000001c
u32 unk1; // 0x00000000
vm::lptr<u32> sceLibcHeapSize;
vm::lptr<u32> sceLibcHeapSizeDefault;
vm::lptr<u32> sceLibcHeapExtendedAlloc;
vm::lptr<u32> sceLibcHeapDelayedAlloc;
u32 unk2;
u32 unk3;
vm::lptr<u32> __sce_libcmallocreplace;
vm::lptr<u32> __sce_libcnewreplace;
};
struct psv_process_param_t
{
u32 size; // 0x00000030
u32 unk1; // 'PSP2'
u32 unk2; // 0x00000005
u32 unk3;
vm::lcptr<char> sceUserMainThreadName;
vm::lptr<s32> sceUserMainThreadPriority;
vm::lptr<u32> sceUserMainThreadStackSize;
vm::lptr<u32> sceUserMainThreadAttribute;
vm::lcptr<char> sceProcessName;
vm::lptr<u32> sce_process_preload_disabled;
vm::lptr<u32> sceUserMainThreadCpuAffinityMask;
vm::lptr<psv_libc_param_t> __sce_libcparam;
};
initialize_psv_modules();
auto armv7_thr_stop_data = vm::ptr<u32>::make(vm::alloc(3 * 4, vm::main));
armv7_thr_stop_data[0] = 0xf870; // HACK instruction (Thumb)
armv7_thr_stop_data[1] = SFI_HLE_RETURN;
Emu.SetCPUThreadStop(armv7_thr_stop_data.addr());
u32 entry = 0; // actual entry point (ELFs entry point is ignored)
u32 fnid_addr = 0;
u32 code_start = 0;
u32 code_end = 0;
u32 vnid_addr = 0;
std::unordered_map<u32, u32> vnid_list;
vm::ptr<psv_process_param_t> proc_param = vm::null;
for (auto& shdr : m_shdrs)
{
// get secton name
//auto name = vm::cptr<char>::make(sname_base + shdr.data_le.sh_name);
m_stream->Seek(handler::get_stream_offset() + m_shdrs[m_ehdr.data_le.e_shstrndx].data_le.sh_offset + shdr.data_le.sh_name);
std::string name;
char c;
while (m_stream->SRead(c) && c)
{
name.push_back(c);
}
if (!strcmp(name.c_str(), ".text"))
{
LOG_NOTICE(LOADER, ".text analysis...");
code_start = shdr.data_le.sh_addr;
code_end = shdr.data_le.sh_size + code_start;
}
else if (!strcmp(name.c_str(), ".sceExport.rodata"))
{
LOG_NOTICE(LOADER, ".sceExport.rodata analysis...");
auto enid = vm::cptr<u32>::make(shdr.data_le.sh_addr);
auto edata = vm::cptr<u32>::make(enid.addr() + shdr.data_le.sh_size / 2);
for (u32 j = 0; j < shdr.data_le.sh_size / 8; j++)
{
switch (const u32 nid = enid[j])
{
case 0x935cd196: // set entry point
{
entry = edata[j];
break;
}
case 0x6c2224ba: // __sce_moduleinfo
{
// currently nothing, but it should theoretically be the root of analysis instead of section name comparison
break;
}
case 0x70fba1e7: // __sce_process_param
{
proc_param.set(edata[j]);
break;
}
default:
{
LOG_ERROR(LOADER, "Unknown export 0x%08x (addr=0x%08x)", nid, edata[j]);
}
}
}
}
else if (!strcmp(name.c_str(), ".sceFNID.rodata"))
{
LOG_NOTICE(LOADER, ".sceFNID.rodata analysis...");
fnid_addr = shdr.data_le.sh_addr;
}
else if (!strcmp(name.c_str(), ".sceFStub.rodata"))
{
LOG_NOTICE(LOADER, ".sceFStub.rodata analysis...");
if (!fnid_addr)
{
LOG_ERROR(LOADER, ".sceFNID.rodata address not found, unable to process imports");
continue;
}
auto fnid = vm::cptr<u32>::make(fnid_addr);
auto fstub = vm::cptr<u32>::make(shdr.data_le.sh_addr);
for (u32 j = 0; j < shdr.data_le.sh_size / 4; j++)
{
const u32 nid = fnid[j];
const u32 addr = fstub[j];
u32 index;
if (auto func = get_psv_func_by_nid(nid, &index))
{
if (func->module)
{
LOG_NOTICE(LOADER, "Imported function '%s' in module '%s' (nid=0x%08x, addr=0x%x)", func->name, func->module->name, nid, addr);
}
else
{
LOG_NOTICE(LOADER, "Imported function '%s' (nid=0x%08x, addr=0x%x)", func->name, nid, addr);
}
}
else
{
LOG_ERROR(LOADER, "Unknown function 0x%08x (addr=0x%x)", nid, addr);
// TODO: set correct name if possible
index = add_psv_func(psv_func(nid, 0, nullptr, "UNKNOWN", nullptr));
}
vm::psv::write32(addr, 0xe0700090 | (index & 0xfff0) << 4 | (index & 0xf)); // HACK instruction (ARM)
code_end = std::min<u32>(addr, code_end);
}
}
else if (!strcmp(name.c_str(), ".sceVNID.rodata"))
{
LOG_NOTICE(LOADER, ".sceVNID.rodata analysis...");
vnid_addr = shdr.data_le.sh_addr;
}
else if (!strcmp(name.c_str(), ".sceVStub.rodata"))
{
LOG_NOTICE(LOADER, ".sceVStub.rodata analysis...");
if (!vnid_addr)
{
if (shdr.data_le.sh_size)
{
LOG_ERROR(LOADER, ".sceVNID.rodata address not found, unable to process imports");
}
continue;
}
auto vnid = vm::cptr<u32>::make(vnid_addr);
auto vstub = vm::cptr<u32>::make(shdr.data_le.sh_addr);
for (u32 j = 0; j < shdr.data_le.sh_size / 4; j++)
{
const u32 nid = vnid[j];
const u32 addr = vstub[j];
LOG_ERROR(LOADER, "Unknown object 0x%08x (ref_addr=0x%x)", nid, addr);
// TODO: find imported object (vtable, typeinfo or something), assign it to vnid_list[addr]
}
}
else if (!strcmp(name.c_str(), ".tbss"))
{
LOG_NOTICE(LOADER, ".tbss analysis...");
const u32 img_addr = shdr.data_le.sh_addr; // start address of TLS initialization image
const u32 img_size = (&shdr)[1].data_le.sh_addr - img_addr; // calculate its size as the difference between sections
const u32 tls_size = shdr.data_le.sh_size; // full size of TLS
LOG_WARNING(LOADER, "TLS: img_addr=0x%08x, img_size=0x%x, tls_size=0x%x", img_addr, img_size, tls_size);
Emu.SetTLSData(img_addr, img_size, tls_size);
}
else if (!strcmp(name.c_str(), ".sceRefs.rodata"))
{
LOG_NOTICE(LOADER, ".sceRefs.rodata analysis...");
u32 data = 0;
for (auto code = vm::cptr<u32>::make(shdr.data_le.sh_addr); code.addr() < shdr.data_le.sh_addr + shdr.data_le.sh_size; code++)
{
switch (*code)
{
case 0x000000ff: // save address for future use
{
data = *++code;
break;
}
case 0x0000002f: // movw r*,# instruction is replaced
{
if (!data) // probably, imported object
{
auto found = vnid_list.find(code.addr());
if (found != vnid_list.end())
{
data = found->second;
}
}
if (!data)
{
LOG_ERROR(LOADER, ".sceRefs: movw writing failed (ref_addr=0x%x, addr=0x%x)", code, code[1]);
}
else
{
LOG_NOTICE(LOADER, ".sceRefs: movw written at 0x%x (ref_addr=0x%x, data=0x%x)", code[1], code, data);
}
const u32 addr = *++code;
vm::psv::write16(addr + 0, vm::psv::read16(addr + 0) | (data & 0x800) >> 1 | (data & 0xf000) >> 12);
vm::psv::write16(addr + 2, vm::psv::read16(addr + 2) | (data & 0x700) << 4 | (data & 0xff));
break;
}
case 0x00000030: // movt r*,# instruction is replaced
{
if (!data)
{
LOG_ERROR(LOADER, ".sceRefs: movt writing failed (ref_addr=0x%x, addr=0x%x)", code, code[1]);
}
else
{
LOG_NOTICE(LOADER, ".sceRefs: movt written at 0x%x (ref_addr=0x%x, data=0x%x)", code[1], code, data);
}
const u32 addr = *++code;
vm::psv::write16(addr + 0, vm::psv::read16(addr + 0) | (data & 0x8000000) >> 17 | (data & 0xf0000000) >> 28);
vm::psv::write16(addr + 2, vm::psv::read16(addr + 2) | (data & 0x7000000) >> 12 | (data & 0xff0000) >> 16);
break;
}
case 0x00000000:
{
data = 0;
LOG_TRACE(LOADER, ".sceRefs: zero code found");
break;
}
default:
{
LOG_ERROR(LOADER, "Unknown code in .sceRefs section (0x%08x)", *code);
}
}
}
}
}
LOG_NOTICE(LOADER, "__sce_process_param(addr=0x%x) analysis...", proc_param);
if (proc_param->size != 0x30 || proc_param->unk1 != *(u32*)"PSP2" || proc_param->unk2 != 5)
{
LOG_ERROR(LOADER, "__sce_process_param: unexpected data found (size=0x%x, 0x%x, 0x%x, 0x%x)", proc_param->size, proc_param->unk1, proc_param->unk2, proc_param->unk3);
}
LOG_NOTICE(LOADER, "*** &sceUserMainThreadName = 0x%x", proc_param->sceUserMainThreadName);
LOG_NOTICE(LOADER, "*** &sceUserMainThreadPriority = 0x%x", proc_param->sceUserMainThreadPriority);
LOG_NOTICE(LOADER, "*** &sceUserMainThreadStackSize = 0x%x", proc_param->sceUserMainThreadStackSize);
LOG_NOTICE(LOADER, "*** &sceUserMainThreadAttribute = 0x%x", proc_param->sceUserMainThreadAttribute);
LOG_NOTICE(LOADER, "*** &sceProcessName = 0x%x", proc_param->sceProcessName);
LOG_NOTICE(LOADER, "*** &sce_process_preload_disabled = 0x%x", proc_param->sce_process_preload_disabled);
LOG_NOTICE(LOADER, "*** &sceUserMainThreadCpuAffinityMask = 0x%x", proc_param->sceUserMainThreadCpuAffinityMask);
auto libc_param = proc_param->__sce_libcparam;
LOG_NOTICE(LOADER, "__sce_libcparam(addr=0x%x) analysis...", libc_param);
if (libc_param->size != 0x1c || libc_param->unk1)
{
LOG_ERROR(LOADER, "__sce_libcparam: unexpected data found (size=0x%x, 0x%x, 0x%x)", libc_param->size, libc_param->unk1, libc_param->unk2);
}
LOG_NOTICE(LOADER, "*** &sceLibcHeapSize = 0x%x", libc_param->sceLibcHeapSize);
LOG_NOTICE(LOADER, "*** &sceLibcHeapSizeDefault = 0x%x", libc_param->sceLibcHeapSizeDefault);
LOG_NOTICE(LOADER, "*** &sceLibcHeapExtendedAlloc = 0x%x", libc_param->sceLibcHeapExtendedAlloc);
LOG_NOTICE(LOADER, "*** &sceLibcHeapDelayedAlloc = 0x%x", libc_param->sceLibcHeapDelayedAlloc);
armv7_init_tls();
armv7_decoder_initialize(code_start, code_end);
const std::string& thread_name = proc_param->sceUserMainThreadName ? proc_param->sceUserMainThreadName.get_ptr() : "main_thread";
const u32 stack_size = proc_param->sceUserMainThreadStackSize ? proc_param->sceUserMainThreadStackSize->value() : 256 * 1024;
const u32 priority = proc_param->sceUserMainThreadPriority ? proc_param->sceUserMainThreadPriority->value() : 160;
armv7_thread(entry, thread_name, stack_size, priority).args({ Emu.GetPath(), "-emu" }).run();
break;
}
case MACHINE_SPU: spu_thread(m_ehdr.is_le() ? m_ehdr.data_le.e_entry : m_ehdr.data_be.e_entry.value(), "main_thread").args({ Emu.GetPath()/*, "-emu"*/ }).run(); break;
}
return ok;
}
handler::error_code elf32::load_data(u32 offset, bool skip_writeable)
{
Elf_Machine machine = (Elf_Machine)(u16)(m_ehdr.is_le() ? m_ehdr.data_le.e_machine : m_ehdr.data_be.e_machine.value());
for (auto &phdr : m_phdrs)
{
u32 memsz = m_ehdr.is_le() ? phdr.data_le.p_memsz : phdr.data_be.p_memsz.value();
u32 filesz = m_ehdr.is_le() ? phdr.data_le.p_filesz : phdr.data_be.p_filesz.value();
u32 vaddr = offset + (m_ehdr.is_le() ? phdr.data_le.p_vaddr : phdr.data_be.p_vaddr.value());
u32 offset = m_ehdr.is_le() ? phdr.data_le.p_offset : phdr.data_be.p_offset.value();
switch (m_ehdr.is_le() ? phdr.data_le.p_type : phdr.data_be.p_type.value())
{
case 0x00000001: //LOAD
if (phdr.data_le.p_memsz)
{
if (machine == MACHINE_ARM && !vm::falloc(vaddr, memsz, vm::main))
{
LOG_ERROR(LOADER, "%s(): AllocFixed(0x%llx, 0x%x) failed", __FUNCTION__, vaddr, memsz);
return loading_error;
}
if (skip_writeable == true && (phdr.data_be.p_flags & 2/*PF_W*/) != 0)
{
continue;
}
if (filesz)
{
m_stream->Seek(handler::get_stream_offset() + offset);
m_stream->Read(vm::base(vaddr), filesz);
}
}
break;
}
}
return ok;
}
}
}

View File

@ -1,139 +0,0 @@
#pragma once
#include "Loader.h"
struct vfsStream;
namespace loader
{
namespace handlers
{
class elf32 : public handler
{
public:
struct ehdr
{
u32 e_magic;
u8 e_class;
u8 e_data;
u8 e_curver;
u8 e_os_abi;
union
{
struct
{
u64 e_abi_ver;
u16 e_type;
u16 e_machine;
u32 e_version;
u32 e_entry;
u32 e_phoff;
u32 e_shoff;
u32 e_flags;
u16 e_ehsize;
u16 e_phentsize;
u16 e_phnum;
u16 e_shentsize;
u16 e_shnum;
u16 e_shstrndx;
} data_le;
struct
{
be_t<u64> e_abi_ver;
be_t<u16> e_type;
be_t<u16> e_machine;
be_t<u32> e_version;
be_t<u32> e_entry;
be_t<u32> e_phoff;
be_t<u32> e_shoff;
be_t<u32> e_flags;
be_t<u16> e_ehsize;
be_t<u16> e_phentsize;
be_t<u16> e_phnum;
be_t<u16> e_shentsize;
be_t<u16> e_shnum;
be_t<u16> e_shstrndx;
} data_be;
};
bool is_le() const { return e_data == 1; }
bool check() const { return e_magic == 0x464C457F; }
};
struct shdr
{
union
{
struct
{
u32 sh_name;
u32 sh_type;
u32 sh_flags;
u32 sh_addr;
u32 sh_offset;
u32 sh_size;
u32 sh_link;
u32 sh_info;
u32 sh_addralign;
u32 sh_entsize;
} data_le;
struct
{
be_t<u32> sh_name;
be_t<u32> sh_type;
be_t<u32> sh_flags;
be_t<u32> sh_addr;
be_t<u32> sh_offset;
be_t<u32> sh_size;
be_t<u32> sh_link;
be_t<u32> sh_info;
be_t<u32> sh_addralign;
be_t<u32> sh_entsize;
} data_be;
};
};
struct phdr
{
union
{
struct
{
u32 p_type;
u32 p_offset;
u32 p_vaddr;
u32 p_paddr;
u32 p_filesz;
u32 p_memsz;
u32 p_flags;
u32 p_align;
} data_le;
struct
{
be_t<u32> p_type;
be_t<u32> p_offset;
be_t<u32> p_vaddr;
be_t<u32> p_paddr;
be_t<u32> p_filesz;
be_t<u32> p_memsz;
be_t<u32> p_flags;
be_t<u32> p_align;
} data_be;
};
};
ehdr m_ehdr;
std::vector<phdr> m_phdrs;
std::vector<shdr> m_shdrs;
error_code init(vfsStream& stream) override;
error_code load() override;
error_code load_data(u32 offset, bool skip_writeable = false);
virtual ~elf32() = default;
};
}
}

View File

@ -1,737 +0,0 @@
#include "stdafx.h"
#include "Emu/FS/vfsStream.h"
#include "Emu/FS/vfsFile.h"
#include "Emu/FS/vfsDir.h"
#include "Emu/Memory/Memory.h"
#include "Emu/IdManager.h"
#include "Emu/System.h"
#include "Emu/state.h"
#include "Emu/SysCalls/SysCalls.h"
#include "Emu/SysCalls/Modules.h"
#include "Emu/SysCalls/ModuleManager.h"
#include "Emu/SysCalls/lv2/sys_prx.h"
#include "Emu/Cell/PPUInstrTable.h"
#include "ELF64.h"
using namespace PPU_instr;
namespace loader
{
namespace handlers
{
handler::error_code elf64::init(vfsStream& stream)
{
m_ehdr = {};
m_sprx_module_info = {};
m_sprx_function_info = {};
m_phdrs.clear();
m_shdrs.clear();
m_sprx_segments_info.clear();
m_sprx_import_info.clear();
m_sprx_export_info.clear();
error_code res = handler::init(stream);
if (res != ok)
{
return res;
}
m_stream->Read(&m_ehdr, sizeof(ehdr));
if (!m_ehdr.check())
{
return bad_file;
}
if (m_ehdr.e_phnum && m_ehdr.e_phentsize != sizeof(phdr))
{
return broken_file;
}
if (m_ehdr.e_shnum && m_ehdr.e_shentsize != sizeof(shdr))
{
return broken_file;
}
if (m_ehdr.e_machine != MACHINE_PPC64 && m_ehdr.e_machine != MACHINE_SPU)
{
LOG_ERROR(LOADER, "Unknown elf64 machine type: 0x%x", m_ehdr.e_machine);
return bad_version;
}
if (m_ehdr.e_phnum)
{
m_phdrs.resize(m_ehdr.e_phnum);
m_stream->Seek(handler::get_stream_offset() + m_ehdr.e_phoff);
if (m_stream->Read(m_phdrs.data(), m_ehdr.e_phnum * sizeof(phdr)) != m_ehdr.e_phnum * sizeof(phdr))
return broken_file;
}
if (m_ehdr.e_shnum)
{
m_shdrs.resize(m_ehdr.e_shnum);
m_stream->Seek(handler::get_stream_offset() + m_ehdr.e_shoff);
if (m_stream->Read(m_shdrs.data(), m_ehdr.e_shnum * sizeof(shdr)) != m_ehdr.e_shnum * sizeof(shdr))
return broken_file;
}
if (is_sprx())
{
m_stream->Seek(handler::get_stream_offset() + m_phdrs[0].p_paddr.addr());
m_stream->Read(&m_sprx_module_info, sizeof(sprx_module_info));
//m_stream->Seek(handler::get_stream_offset() + m_phdrs[1].p_vaddr.addr());
//m_stream->Read(&m_sprx_function_info, sizeof(sprx_function_info));
}
return ok;
}
handler::error_code elf64::load_sprx(sprx_info& info)
{
for (auto &phdr : m_phdrs)
{
switch ((u32)phdr.p_type)
{
case 0x1: //load
{
if (phdr.p_memsz)
{
sprx_segment_info segment;
segment.size = phdr.p_memsz;
segment.size_file = phdr.p_filesz;
segment.begin.set(vm::alloc(segment.size, vm::main));
if (!segment.begin)
{
LOG_ERROR(LOADER, "%s() sprx: vm::alloc(0x%x) failed", __FUNCTION__, segment.size);
return loading_error;
}
segment.initial_addr = phdr.p_vaddr;
LOG_WARNING(LOADER, "segment addr=0x%x, initial addr = 0x%x", segment.begin.addr(), segment.initial_addr.addr());
if (phdr.p_filesz)
{
m_stream->Seek(handler::get_stream_offset() + phdr.p_offset);
m_stream->Read(segment.begin.get_ptr(), phdr.p_filesz);
}
if (phdr.p_paddr)
{
sys_prx_module_info_t module_info;
m_stream->Seek(handler::get_stream_offset() + phdr.p_paddr.addr());
m_stream->Read(&module_info, sizeof(module_info));
info.name = std::string(module_info.name, 28);
info.rtoc = module_info.toc + segment.begin.addr();
LOG_WARNING(LOADER, "%s (rtoc=0x%x):", info.name, info.rtoc);
sys_prx_library_info_t lib;
for (u32 e = module_info.exports_start.addr();
e < module_info.exports_end.addr();
e += lib.size ? lib.size : sizeof(sys_prx_library_info_t))
{
m_stream->Seek(handler::get_stream_offset() + phdr.p_offset + e);
m_stream->Read(&lib, sizeof(lib));
std::string modulename;
if (lib.name_addr)
{
char name[27];
m_stream->Seek(handler::get_stream_offset() + phdr.p_offset + lib.name_addr);
m_stream->Read(name, sizeof(name));
modulename = name;
LOG_WARNING(LOADER, "**** Exported: %s", name);
}
auto &module = info.modules[modulename];
LOG_WARNING(LOADER, "**** 0x%x - 0x%x - 0x%x", (u32)lib.unk4, (u32)lib.unk5, (u32)lib.unk6);
for (u16 i = 0, end = lib.num_func; i < end; ++i)
{
be_t<u32> fnid, fstub;
m_stream->Seek(handler::get_stream_offset() + phdr.p_offset + lib.fnid_addr + i * sizeof(fnid));
m_stream->Read(&fnid, sizeof(fnid));
m_stream->Seek(handler::get_stream_offset() + phdr.p_offset + lib.fstub_addr + i * sizeof(fstub));
m_stream->Read(&fstub, sizeof(fstub));
module.exports[fnid] = fstub;
//LOG_NOTICE(LOADER, "Exported function '%s' in '%s' module (LLE)", get_ps3_function_name(fnid), module_name);
LOG_WARNING(LOADER, "**** %s: [%s] -> 0x%x", modulename, get_ps3_function_name(fnid), (u32)fstub);
}
}
for (u32 i = module_info.imports_start;
i < module_info.imports_end;
i += lib.size ? lib.size : sizeof(sys_prx_library_info_t))
{
m_stream->Seek(handler::get_stream_offset() + phdr.p_offset + i);
m_stream->Read(&lib, sizeof(lib));
std::string modulename;
if (lib.name_addr)
{
char name[27];
m_stream->Seek(handler::get_stream_offset() + phdr.p_offset + lib.name_addr);
m_stream->Read(name, sizeof(name));
modulename = name;
LOG_WARNING(LOADER, "**** Imported: %s", name);
}
auto &module = info.modules[modulename];
LOG_WARNING(LOADER, "**** 0x%x - 0x%x - 0x%x", (u32)lib.unk4, (u32)lib.unk5, (u32)lib.unk6);
for (u16 i = 0, end = lib.num_func; i < end; ++i)
{
be_t<u32> fnid, fstub;
m_stream->Seek(handler::get_stream_offset() + phdr.p_offset + lib.fnid_addr + i * sizeof(fnid));
m_stream->Read(&fnid, sizeof(fnid));
m_stream->Seek(handler::get_stream_offset() + phdr.p_offset + lib.fstub_addr + i * sizeof(fstub));
m_stream->Read(&fstub, sizeof(fstub));
module.imports[fnid] = fstub;
LOG_WARNING(LOADER, "**** %s: [%s] -> 0x%x", modulename, get_ps3_function_name(fnid), (u32)fstub);
}
}
}
info.segments.push_back(segment);
}
break;
}
case 0x700000a4: //relocation
{
m_stream->Seek(handler::get_stream_offset() + phdr.p_offset);
for (uint i = 0; i < phdr.p_filesz; i += sizeof(sys_prx_relocation_info_t))
{
sys_prx_relocation_info_t rel;
m_stream->Read(&rel, sizeof(rel));
u32 ADDR = info.segments[rel.index_addr].begin.addr() + rel.offset;
switch ((u32)rel.type)
{
case 1:
LOG_NOTICE(LOADER, "**** RELOCATION(1): 0x%x <- 0x%x", ADDR, (u32)(info.segments[rel.index_value].begin.addr() + rel.ptr.addr()));
*vm::ptr<u32>::make(ADDR) = info.segments[rel.index_value].begin.addr() + rel.ptr.addr();
break;
case 4:
LOG_NOTICE(LOADER, "**** RELOCATION(4): 0x%x <- 0x%x", ADDR, (u16)(rel.ptr.addr()));
*vm::ptr<u16>::make(ADDR) = (u16)(u64)rel.ptr.addr();
break;
case 5:
LOG_NOTICE(LOADER, "**** RELOCATION(5): 0x%x <- 0x%x", ADDR, (u16)(info.segments[rel.index_value].begin.addr() >> 16));
*vm::ptr<u16>::make(ADDR) = info.segments[rel.index_value].begin.addr() >> 16;
break;
case 6:
LOG_WARNING(LOADER, "**** RELOCATION(6): 0x%x <- 0x%x", ADDR, (u16)(info.segments[1].begin.addr() >> 16));
*vm::ptr<u16>::make(ADDR) = info.segments[1].begin.addr() >> 16;
break;
default:
LOG_ERROR(LOADER, "unknown prx relocation type (0x%x)", (u32)rel.type);
return bad_relocation_type;
}
}
break;
}
}
}
for (auto &m : info.modules)
{
for (auto &e : m.second.exports)
{
u32 stub = e.second;
for (auto &s : info.segments)
{
if (stub >= s.initial_addr.addr() && stub < s.initial_addr.addr() + s.size_file)
{
stub += s.begin.addr() - s.initial_addr.addr();
break;
}
}
assert(e.second != stub);
e.second = stub;
}
for (auto &i : m.second.imports)
{
u32 stub = i.second;
for (auto &s : info.segments)
{
if (stub >= s.initial_addr.addr() && stub < s.initial_addr.addr() + s.size_file)
{
stub += s.begin.addr() - s.initial_addr.addr();
break;
}
}
assert(i.second != stub);
i.second = stub;
}
}
return ok;
}
handler::error_code elf64::load()
{
if (is_sprx())
{
sprx_info info;
return load_sprx(info);
}
//store elf to memory
vm::ps3::init();
Emu.GetModuleManager().Init();
error_code res = alloc_memory(0);
if (res != ok)
{
return res;
}
std::vector<u32> start_funcs;
std::vector<u32> stop_funcs;
std::vector<u32> exit_funcs;
//load modules
vfsDir lle_dir("/dev_flash/sys/external");
for (const auto module : lle_dir)
{
if (module->flags & DirEntry_TypeDir)
{
continue;
}
if (rpcs3::state.config.core.load_liblv2.value())
{
if (module->name != "liblv2.sprx")
{
continue;
}
}
elf64 sprx_handler;
vfsFile fsprx(lle_dir.GetPath() + "/" + module->name);
if (fsprx.IsOpened())
{
sprx_handler.init(fsprx);
if (sprx_handler.is_sprx())
{
if (!rpcs3::state.config.core.load_liblv2.value())
{
if (rpcs3::config.lle.get_entry_value<bool>(sprx_handler.sprx_get_module_name(), false) == false)
{
continue;
}
}
LOG_WARNING(LOADER, "Loading LLE library '%s'", sprx_handler.sprx_get_module_name().c_str());
sprx_info info;
sprx_handler.load_sprx(info);
for (auto &m : info.modules)
{
if (m.first == "")
{
for (auto &e : m.second.exports)
{
auto code = vm::cptr<u32>::make(vm::check_addr(e.second, 8) ? vm::read32(e.second).value() : 0);
bool is_empty = !code || (code[0] == 0x38600000 && code[1] == BLR());
if (!code)
{
LOG_ERROR(LOADER, "bad OPD of special function 0x%08x in '%s' library (0x%x)", e.first, info.name.c_str(), code);
}
switch (e.first)
{
case 0xbc9a0086:
{
if (!is_empty)
{
LOG_ERROR(LOADER, "start func found in '%s' library (0x%x)", info.name.c_str(), code);
start_funcs.push_back(e.second);
}
break;
}
case 0xab779874:
{
if (!is_empty)
{
LOG_ERROR(LOADER, "stop func found in '%s' library (0x%x)", info.name.c_str(), code);
stop_funcs.push_back(e.second);
}
break;
}
case 0x3ab9a95e:
{
if (!is_empty)
{
LOG_ERROR(LOADER, "exit func found in '%s' library (0x%x)", info.name.c_str(), code);
exit_funcs.push_back(e.second);
}
break;
}
default: LOG_ERROR(LOADER, "unknown special func 0x%08x in '%s' library (0x%x)", e.first, info.name.c_str(), code); break;
}
}
continue;
}
Module<>* module = Emu.GetModuleManager().GetModuleByName(m.first.c_str());
if (!module)
{
LOG_ERROR(LOADER, "Unknown module '%s' in '%s' library", m.first.c_str(), info.name.c_str());
}
for (auto& f : m.second.exports)
{
const u32 nid = f.first;
const u32 addr = f.second;
u32 index;
auto func = get_ppu_func_by_nid(nid, &index);
if (!func)
{
index = add_ppu_func(ModuleFunc(nid, 0, module, nullptr, nullptr, vm::ptr<void()>::make(addr)));
}
else
{
func->lle_func.set(addr);
if (func->flags & MFF_FORCED_HLE)
{
u32 i_addr = 0;
if (!vm::check_addr(addr, 8) || !vm::check_addr(i_addr = vm::read32(addr), 4))
{
LOG_ERROR(LOADER, "Failed to inject code for exported function '%s' (opd=0x%x, 0x%x)", get_ps3_function_name(nid), addr, i_addr);
}
else
{
vm::write32(i_addr, HACK(index | EIF_PERFORM_BLR));
}
}
}
}
for (auto& f : m.second.imports)
{
const u32 nid = f.first;
const u32 addr = f.second;
u32 index;
auto func = get_ppu_func_by_nid(nid, &index);
if (!func)
{
LOG_ERROR(LOADER, "Unknown function '%s' (0x%x)", get_ps3_function_name(nid), addr);
index = add_ppu_func(ModuleFunc(nid, 0, module, nullptr, nullptr));
}
else
{
LOG_NOTICE(LOADER, "Imported function '%s' (0x%x)", get_ps3_function_name(nid), addr);
}
if (!patch_ppu_import(addr, index))
{
LOG_ERROR(LOADER, "Failed to inject code for function '%s' (0x%x)", get_ps3_function_name(nid), addr);
}
}
}
}
}
}
res = load_data(0);
if (res != ok)
return res;
//initialize process
auto rsx_callback_data = vm::ptr<u32>::make(vm::alloc(4 * 4, vm::main));
*rsx_callback_data++ = (rsx_callback_data + 1).addr();
Emu.SetRSXCallback(rsx_callback_data.addr());
rsx_callback_data[0] = ADDI(r11, 0, 0x3ff);
rsx_callback_data[1] = SC(0);
rsx_callback_data[2] = BLR();
auto ppu_thr_stop_data = vm::ptr<u32>::make(vm::alloc(2 * 4, vm::main));
ppu_thr_stop_data[0] = SC(3);
ppu_thr_stop_data[1] = BLR();
Emu.SetCPUThreadStop(ppu_thr_stop_data.addr());
Emu.GetModuleManager().Alloc();
static const int branch_size = 8 * 4;
auto make_branch = [](vm::ptr<u32>& ptr, u32 addr)
{
u32 stub = vm::read32(addr);
u32 rtoc = vm::read32(addr + 4);
*ptr++ = LI_(r0, 0);
*ptr++ = ORI(r0, r0, stub & 0xffff);
*ptr++ = ORIS(r0, r0, stub >> 16);
*ptr++ = LI_(r2, 0);
*ptr++ = ORI(r2, r2, rtoc & 0xffff);
*ptr++ = ORIS(r2, r2, rtoc >> 16);
*ptr++ = MTCTR(r0);
*ptr++ = BCTRL();
};
auto entry = vm::ptr<u32>::make(vm::alloc(56 + branch_size * (start_funcs.size() + 1), vm::main));
const auto OPD = entry;
// make initial OPD
*entry++ = OPD.addr() + 8;
*entry++ = 0xdeadbeef;
// save initialization args
*entry++ = MR(r14, r3);
*entry++ = MR(r15, r4);
*entry++ = MR(r16, r5);
*entry++ = MR(r17, r6);
*entry++ = MR(r18, r11);
*entry++ = MR(r19, r12);
for (auto &f : start_funcs)
{
make_branch(entry, f);
}
// restore initialization args
*entry++ = MR(r3, r14);
*entry++ = MR(r4, r15);
*entry++ = MR(r5, r16);
*entry++ = MR(r6, r17);
*entry++ = MR(r11, r18);
*entry++ = MR(r12, r19);
// branch to initialization
make_branch(entry, m_ehdr.e_entry);
const auto decoder_cache = fxm::make<ppu_decoder_cache_t>();
for (u32 page = 0; page < 0x20000000; page += 4096)
{
// TODO: scan only executable areas
if (vm::check_addr(page, 4096))
{
decoder_cache->initialize(page, 4096);
}
}
ppu_thread main_thread(OPD.addr(), "main_thread");
main_thread.args({ Emu.GetPath()/*, "-emu"*/ }).run();
main_thread.gpr(11, OPD.addr()).gpr(12, Emu.GetMallocPageSize());
return ok;
}
handler::error_code elf64::alloc_memory(u64 offset)
{
for (auto &phdr : m_phdrs)
{
switch (phdr.p_type.value())
{
case 0x00000001: //LOAD
{
if (phdr.p_memsz)
{
if (!vm::falloc(phdr.p_vaddr.addr(), phdr.p_memsz, vm::main))
{
LOG_ERROR(LOADER, "%s(): AllocFixed(0x%llx, 0x%llx) failed", __FUNCTION__, phdr.p_vaddr.addr(), phdr.p_memsz);
return loading_error;
}
}
break;
}
}
}
return ok;
}
handler::error_code elf64::load_data(u64 offset)
{
for (auto &phdr : m_phdrs)
{
switch (phdr.p_type.value())
{
case 0x00000001: //LOAD
{
if (phdr.p_memsz)
{
if (phdr.p_filesz)
{
m_stream->Seek(handler::get_stream_offset() + phdr.p_offset);
m_stream->Read(phdr.p_vaddr.get_ptr(), phdr.p_filesz);
if (rpcs3::state.config.core.hook_st_func.value())
{
hook_ppu_funcs(vm::static_ptr_cast<u32>(phdr.p_vaddr), phdr.p_filesz / 4);
}
}
}
break;
}
case 0x00000007: //TLS
{
Emu.SetTLSData(phdr.p_vaddr.addr(), phdr.p_filesz, phdr.p_memsz);
break;
}
case 0x60000001: //LOOS+1
{
if (phdr.p_filesz)
{
struct process_param_t
{
be_t<u32> size;
be_t<u32> magic;
be_t<u32> version;
be_t<u32> sdk_version;
be_t<s32> primary_prio;
be_t<u32> primary_stacksize;
be_t<u32> malloc_pagesize;
be_t<u32> ppc_seg;
//be_t<u32> crash_dump_param_addr;
};
const auto& info = *(process_param_t*)phdr.p_vaddr.get_ptr();
if (info.size < sizeof(process_param_t))
{
LOG_WARNING(LOADER, "Bad process_param size! [0x%x : 0x%x]", info.size, SIZE_32(process_param_t));
}
if (info.magic != 0x13bcc5f6)
{
LOG_ERROR(LOADER, "Bad process_param magic! [0x%x]", info.magic);
}
else
{
LOG_NOTICE(LOADER, "*** sdk version: 0x%x", info.sdk_version);
LOG_NOTICE(LOADER, "*** primary prio: %d", info.primary_prio);
LOG_NOTICE(LOADER, "*** primary stacksize: 0x%x", info.primary_stacksize);
LOG_NOTICE(LOADER, "*** malloc pagesize: 0x%x", info.malloc_pagesize);
LOG_NOTICE(LOADER, "*** ppc seg: 0x%x", info.ppc_seg);
//LOG_NOTICE(LOADER, "*** crash dump param addr: 0x%x", info.crash_dump_param_addr);
Emu.SetParams(info.sdk_version, info.malloc_pagesize, std::max<u32>(info.primary_stacksize, 0x4000), info.primary_prio);
}
}
break;
}
case 0x60000002: //LOOS+2
{
if (phdr.p_filesz)
{
const sys_proc_prx_param& proc_prx_param = *(sys_proc_prx_param*)phdr.p_vaddr.get_ptr();
if (proc_prx_param.magic != 0x1b434cec)
{
LOG_ERROR(LOADER, "Bad magic! (0x%x)", proc_prx_param.magic);
break;
}
for (auto stub = proc_prx_param.libstubstart; stub < proc_prx_param.libstubend; ++stub)
{
const std::string module_name = stub->s_modulename.get_ptr();
Module<>* module = Emu.GetModuleManager().GetModuleByName(module_name.c_str());
if (!module)
{
LOG_ERROR(LOADER, "Unknown module '%s'", module_name.c_str());
}
for (u32 i = 0; i < stub->s_imports; ++i)
{
const u32 nid = stub->s_nid[i];
const u32 addr = stub->s_text[i];
u32 index;
auto func = get_ppu_func_by_nid(nid, &index);
if (!func)
{
LOG_ERROR(LOADER, "Unknown function '%s' in '%s' module (0x%x)", get_ps3_function_name(nid), module_name, addr);
index = add_ppu_func(ModuleFunc(nid, 0, module, nullptr, nullptr));
}
else
{
const bool is_lle = func->lle_func && !(func->flags & MFF_FORCED_HLE);
LOG_NOTICE(LOADER, "Imported %sfunction '%s' in '%s' module (0x%x)", is_lle ? "LLE " : "", get_ps3_function_name(nid), module_name, addr);
}
if (!patch_ppu_import(addr, index))
{
LOG_ERROR(LOADER, "Failed to inject code at address 0x%x", addr);
}
}
}
}
break;
}
default:
{
LOG_ERROR(LOADER, "Unknown phdr type (0x%08x)", phdr.p_type);
}
}
}
return ok;
}
}
}

View File

@ -1,164 +0,0 @@
#pragma once
#include "Loader.h"
struct vfsStream;
namespace loader
{
namespace handlers
{
class elf64 : public handler
{
public:
struct ehdr
{
be_t<u32> e_magic;
u8 e_class;
u8 e_data;
u8 e_curver;
u8 e_os_abi;
be_t<u64> e_abi_ver;
be_t<u16> e_type;
be_t<u16> e_machine;
be_t<u32> e_version;
be_t<u64> e_entry;
be_t<u64> e_phoff;
be_t<u64> e_shoff;
be_t<u32> e_flags;
be_t<u16> e_ehsize;
be_t<u16> e_phentsize;
be_t<u16> e_phnum;
be_t<u16> e_shentsize;
be_t<u16> e_shnum;
be_t<u16> e_shstrndx;
bool check() const { return e_magic == 0x7F454C46; }
} m_ehdr;
struct phdr
{
be_t<u32> p_type;
be_t<u32> p_flags;
be_t<u64> p_offset;
_ptr_base<void, be_t<u64>> p_vaddr;
_ptr_base<void, be_t<u64>> p_paddr;
be_t<u64> p_filesz;
be_t<u64> p_memsz;
be_t<u64> p_align;
};
struct shdr
{
be_t<u32> sh_name;
be_t<u32> sh_type;
be_t<u64> sh_flags;
_ptr_base<void, be_t<u64>> sh_addr;
be_t<u64> sh_offset;
be_t<u64> sh_size;
be_t<u32> sh_link;
be_t<u32> sh_info;
be_t<u64> sh_addralign;
be_t<u64> sh_entsize;
};
struct sprx_module_info
{
be_t<u16> attr;
u8 version[2];
char name[28];
be_t<u32> toc_addr;
be_t<u32> export_start;
be_t<u32> export_end;
be_t<u32> import_start;
be_t<u32> import_end;
} m_sprx_module_info;
struct sprx_export_info
{
u8 size;
u8 padding;
be_t<u16> version;
be_t<u16> attr;
be_t<u16> func_count;
be_t<u16> vars_count;
be_t<u16> tls_vars_count;
be_t<u16> hash_info;
be_t<u16> tls_hash_info;
u8 reserved[2];
be_t<u32> lib_name_offset;
be_t<u32> nid_offset;
be_t<u32> stub_offset;
};
struct sprx_import_info
{
u8 size;
u8 unused;
be_t<u16> version;
be_t<u16> attr;
be_t<u16> func_count;
be_t<u16> vars_count;
be_t<u16> tls_vars_count;
u8 reserved[4];
be_t<u32> lib_name_offset;
be_t<u32> nid_offset;
be_t<u32> stub_offset;
//...
};
struct sprx_function_info
{
be_t<u32> name_table_offset;
be_t<u32> entry_table_offset;
be_t<u32> padding;
} m_sprx_function_info;
struct sprx_lib_info
{
std::string name;
};
struct sprx_segment_info
{
_ptr_base<void> begin;
u32 size;
u32 size_file;
_ptr_base<void> initial_addr;
std::vector<sprx_module_info> modules;
};
struct sprx_info
{
std::string name;
u32 rtoc;
struct module_info
{
std::unordered_map<u32, u32> exports;
std::unordered_map<u32, u32> imports;
};
std::unordered_map<std::string, module_info> modules;
std::vector<sprx_segment_info> segments;
};
std::vector<phdr> m_phdrs;
std::vector<shdr> m_shdrs;
std::vector<sprx_segment_info> m_sprx_segments_info;
std::vector<sprx_import_info> m_sprx_import_info;
std::vector<sprx_export_info> m_sprx_export_info;
public:
virtual ~elf64() = default;
error_code init(vfsStream& stream) override;
error_code load() override;
error_code alloc_memory(u64 offset);
error_code load_data(u64 offset);
error_code load_sprx(sprx_info& info);
bool is_sprx() const { return m_ehdr.e_type == 0xffa4; }
std::string sprx_get_module_name() const { return m_sprx_module_info.name; }
};
}
}

View File

@ -1,130 +0,0 @@
#include "stdafx.h"
#include "Loader.h"
#include "PSF.h"
#include "Emu/FS/vfsLocalFile.h"
namespace loader
{
bool loader::load(vfsStream& stream)
{
for (auto i : m_handlers)
{
i->set_status(i->init(stream));
if (i->get_status() == handler::ok)
{
i->set_status(i->load());
if (i->get_status() == handler::ok)
{
return true;
}
LOG_NOTICE(LOADER, "loader::load() failed: %s", i->get_error_code().c_str());
}
else
{
LOG_NOTICE(LOADER, "loader::init() failed: %s", i->get_error_code().c_str());
stream.Seek(i->get_stream_offset());
}
}
return false;
}
handler::error_code handler::init(vfsStream& stream)
{
m_stream_offset = stream.Tell();
m_stream = &stream;
return ok;
}
};
static const u64 g_spu_offset = 0x10000;
const std::string Ehdr_DataToString(const u8 data)
{
if(data > 1) return fmt::format("%d's complement, big endian", data);
if(data < 1) return "Data is not found";
return fmt::format("%d's complement, little endian", data);
}
const std::string Ehdr_TypeToString(const u16 type)
{
switch(type)
{
case 0: return "NULL";
case 2: return "EXEC (Executable file)";
};
return fmt::format("Unknown (%d)", type);
}
const std::string Ehdr_OS_ABIToString(const u8 os_abi)
{
switch(os_abi)
{
case 0x0 : return "UNIX System V";
case 0x66: return "Cell OS LV-2";
};
return fmt::format("Unknown (0x%x)", os_abi);
}
const std::string Ehdr_MachineToString(const u16 machine)
{
switch(machine)
{
case MACHINE_MIPS: return "MIPS";
case MACHINE_PPC64: return "PowerPC64";
case MACHINE_SPU: return "SPU";
case MACHINE_ARM: return "ARM";
};
return fmt::format("Unknown (0x%x)", machine);
}
const std::string Phdr_FlagsToString(u32 flags)
{
enum {ppu_R = 0x1, ppu_W = 0x2, ppu_E = 0x4};
enum {spu_E = 0x1, spu_W = 0x2, spu_R = 0x4};
enum {rsx_R = 0x1, rsx_W = 0x2, rsx_E = 0x4};
#define FLAGS_TO_STRING(f) \
std::string(f & f##_R ? "R" : "-") + \
std::string(f & f##_W ? "W" : "-") + \
std::string(f & f##_E ? "E" : "-")
const u8 ppu = flags & 0xf;
const u8 spu = (flags >> 0x14) & 0xf;
const u8 rsx = (flags >> 0x18) & 0xf;
std::string ret;
ret += fmt::format("[0x%x] ", flags);
flags &= ~ppu;
flags &= ~spu << 0x14;
flags &= ~rsx << 0x18;
if(flags != 0) return fmt::format("Unknown %s PPU[0x%x] SPU[0x%x] RSX[0x%x]", ret.c_str(), ppu, spu, rsx);
ret += "PPU[" + FLAGS_TO_STRING(ppu) + "] ";
ret += "SPU[" + FLAGS_TO_STRING(spu) + "] ";
ret += "RSX[" + FLAGS_TO_STRING(rsx) + "]";
return ret;
}
const std::string Phdr_TypeToString(const u32 type)
{
switch(type)
{
case 0x00000001: return "LOAD";
case 0x00000004: return "NOTE";
case 0x00000007: return "TLS";
case 0x60000001: return "LOOS+1";
case 0x60000002: return "LOOS+2";
};
return fmt::format("Unknown (0x%x)", type);
}

View File

@ -1,131 +0,0 @@
#pragma once
#include "Emu/Memory/vm.h"
struct vfsFileBase;
struct vfsStream;
#ifdef _DEBUG
//#define LOADER_DEBUG
#endif
enum Elf_Machine
{
MACHINE_Unknown,
MACHINE_MIPS = 0x08,
MACHINE_PPC64 = 0x15,
MACHINE_SPU = 0x17,
MACHINE_ARM = 0x28
};
enum ShdrType
{
SHT_NULL,
SHT_PROGBITS,
SHT_SYMTAB,
SHT_STRTAB,
SHT_RELA,
SHT_HASH,
SHT_DYNAMIC,
SHT_NOTE,
SHT_NOBITS,
SHT_REL,
SHT_SHLIB,
SHT_DYNSYM
};
enum ShdrFlag
{
SHF_WRITE = 0x1,
SHF_ALLOC = 0x2,
SHF_EXECINSTR = 0x4,
SHF_MASKPROC = 0xf0000000
};
const std::string Ehdr_DataToString(const u8 data);
const std::string Ehdr_TypeToString(const u16 type);
const std::string Ehdr_OS_ABIToString(const u8 os_abi);
const std::string Ehdr_MachineToString(const u16 machine);
const std::string Phdr_FlagsToString(u32 flags);
const std::string Phdr_TypeToString(const u32 type);
namespace loader
{
class handler
{
u64 m_stream_offset;
protected:
vfsStream* m_stream;
public:
enum error_code
{
bad_version = -1,
bad_file = -2,
broken_file = -3,
loading_error = -4,
bad_relocation_type = -5,
ok = 0
};
virtual ~handler() = default;
virtual error_code init(vfsStream& stream);
virtual error_code load() = 0;
u64 get_stream_offset() const
{
return m_stream_offset;
}
void set_status(const error_code& code)
{
m_status = code;
}
error_code get_status() const
{
return m_status;
}
const std::string get_error_code() const
{
switch (m_status)
{
case bad_version: return "Bad version";
case bad_file: return "Bad file";
case broken_file: return "Broken file";
case loading_error: return "Loading error";
case bad_relocation_type: return "Bad relocation type";
case ok: return "Ok";
default: return "Unknown error code";
}
}
protected:
error_code m_status;
};
class loader
{
std::vector<handler*> m_handlers;
public:
~loader()
{
for (auto &h : m_handlers)
{
delete h;
}
}
void register_handler(handler* handler)
{
m_handlers.push_back(handler);
}
bool load(vfsStream& stream);
};
using namespace vm;
}

View File

@ -3,7 +3,7 @@
namespace psf
{
_log::channel log("PSF");
_log::channel log("PSF", _log::level::notice);
struct header_t
{
@ -25,26 +25,26 @@ namespace psf
const std::string& entry::as_string() const
{
CHECK_ASSERTION(m_type == format::string || m_type == format::array);
Expects(m_type == format::string || m_type == format::array);
return m_value_string;
}
u32 entry::as_integer() const
{
CHECK_ASSERTION(m_type == format::integer);
Expects(m_type == format::integer);
return m_value_integer;
}
entry& entry::operator =(const std::string& value)
{
CHECK_ASSERTION(m_type == format::string || m_type == format::array);
Expects(m_type == format::string || m_type == format::array);
m_value_string = value;
return *this;
}
entry& entry::operator =(u32 value)
{
CHECK_ASSERTION(m_type == format::integer);
Expects(m_type == format::integer);
m_value_integer = value;
return *this;
}
@ -61,10 +61,10 @@ namespace psf
return SIZE_32(u32);
}
throw EXCEPTION("Invalid format (0x%x)", m_type);
throw fmt::exception("Invalid format (0x%x)" HERE, m_type);
}
registry load(const std::vector<char>& data)
registry load_object(const std::vector<char>& data)
{
registry result;
@ -75,18 +75,18 @@ namespace psf
}
// Check size
CHECK_ASSERTION(data.size() >= sizeof(header_t));
CHECK_ASSERTION((std::uintptr_t)data.data() % 8 == 0);
Expects(data.size() >= sizeof(header_t));
Expects((std::uintptr_t)data.data() % 8 == 0);
// Get header
const header_t& header = reinterpret_cast<const header_t&>(data[0]);
// Check magic and version
CHECK_ASSERTION(header.magic == *(u32*)"\0PSF");
CHECK_ASSERTION(header.version == 0x101);
CHECK_ASSERTION(sizeof(header_t) + header.entries_num * sizeof(def_table_t) <= header.off_key_table);
CHECK_ASSERTION(header.off_key_table <= header.off_data_table);
CHECK_ASSERTION(header.off_data_table <= data.size());
Expects(header.magic == "\0PSF"_u32);
Expects(header.version == 0x101);
Expects(sizeof(header_t) + header.entries_num * sizeof(def_table_t) <= header.off_key_table);
Expects(header.off_key_table <= header.off_data_table);
Expects(header.off_data_table <= data.size());
// Get indices (alignment should be fine)
const def_table_t* indices = reinterpret_cast<const def_table_t*>(data.data() + sizeof(header_t));
@ -94,7 +94,7 @@ namespace psf
// Load entries
for (u32 i = 0; i < header.entries_num; ++i)
{
CHECK_ASSERTION(indices[i].key_off < header.off_data_table - header.off_key_table);
Expects(indices[i].key_off < header.off_data_table - header.off_key_table);
// Get key name range
const auto name_ptr = data.begin() + header.off_key_table + indices[i].key_off;
@ -103,10 +103,10 @@ namespace psf
// Get name (must be unique)
std::string key(name_ptr, name_end);
CHECK_ASSERTION(result.count(key) == 0);
CHECK_ASSERTION(indices[i].param_len <= indices[i].param_max);
CHECK_ASSERTION(indices[i].data_off < data.size() - header.off_data_table);
CHECK_ASSERTION(indices[i].param_max < data.size() - indices[i].data_off);
Expects(result.count(key) == 0);
Expects(indices[i].param_len <= indices[i].param_max);
Expects(indices[i].data_off < data.size() - header.off_data_table);
Expects(indices[i].param_max < data.size() - indices[i].data_off);
// Get data pointer
const auto value_ptr = data.begin() + header.off_data_table + indices[i].data_off;
@ -147,7 +147,7 @@ namespace psf
return result;
}
std::vector<char> save(const registry& psf)
std::vector<char> save_object(const registry& psf)
{
std::vector<def_table_t> indices; indices.reserve(psf.size());
@ -175,7 +175,7 @@ namespace psf
// Generate header
header_t header;
header.magic = *(u32*)"\0PSF";
header.magic = "\0PSF"_u32;
header.version = 0x101;
header.off_key_table = gsl::narrow<u32>(sizeof(header_t) + sizeof(def_table_t) * psf.size());
header.off_data_table = gsl::narrow<u32>(header.off_key_table + key_offset);

View File

@ -1,5 +1,7 @@
#pragma once
#include <map>
namespace psf
{
enum class format : u16
@ -23,8 +25,8 @@ namespace psf
, m_max_size(max_size)
, m_value_string(value)
{
CHECK_ASSERTION(type == format::string || type == format::array);
CHECK_ASSERTION(max_size);
Expects(type == format::string || type == format::array);
Expects(max_size);
}
// Construct integer entry, assign the value
@ -49,11 +51,24 @@ namespace psf
// Define PSF registry as a sorted map of entries:
using registry = std::map<std::string, entry>;
// Load PSF registry from binary data
registry load(const std::vector<char>&);
// Load PSF registry from SFO binary data
registry load_object(const std::vector<char>&);
// Convert PSF registry to binary format
std::vector<char> save(const registry&);
// Load PSF registry from SFO file, if opened
inline registry load_object(const fs::file& f)
{
if (f)
{
return load_object(f.to_vector<char>());
}
else
{
return registry{};
}
}
// Convert PSF registry to SFO binary format
std::vector<char> save_object(const registry&);
// Get string value or default value
std::string get_string(const registry& psf, const std::string& key, const std::string& def = {});

View File

@ -1,52 +1,41 @@
#include "stdafx.h"
#include "Utilities/rXml.h"
#include "Emu/FS/VFS.h"
#include "Emu/FS/vfsFileBase.h"
#include "Emu/System.h"
#include "TROPUSR.h"
TROPUSRLoader::TROPUSRLoader()
{
m_file = NULL;
memset(&m_header, 0, sizeof(m_header));
}
TROPUSRLoader::~TROPUSRLoader()
{
Close();
}
bool TROPUSRLoader::Load(const std::string& filepath, const std::string& configpath)
{
if (m_file)
{
Close();
}
const std::string& path = vfs::get(filepath);
if (!Emu.GetVFS().ExistsFile(filepath))
if (!fs::is_file(path))
{
Generate(filepath, configpath);
}
m_file = Emu.GetVFS().OpenFile(filepath, fom::read);
LoadHeader();
LoadTableHeaders();
LoadTables();
if (!m_file.open(path, fs::read))
{
return false;
}
Close();
if (!LoadHeader() || !LoadTableHeaders() || !LoadTables())
{
return false;
}
m_file.release();
return true;
}
bool TROPUSRLoader::LoadHeader()
{
if (!m_file->IsOpened())
if (!m_file)
{
return false;
}
m_file->Seek(0);
m_file.seek(0);
if (m_file->Read(&m_header, sizeof(TROPUSRHeader)) != sizeof(TROPUSRHeader))
if (!m_file.read(m_header))
{
return false;
}
@ -56,18 +45,18 @@ bool TROPUSRLoader::LoadHeader()
bool TROPUSRLoader::LoadTableHeaders()
{
if (!m_file->IsOpened())
if (!m_file)
{
return false;
}
m_file->Seek(0x30);
m_file.seek(0x30);
m_tableHeaders.clear();
m_tableHeaders.resize(m_header.tables_count);
for (TROPUSRTableHeader& tableHeader : m_tableHeaders)
{
if (m_file->Read(&tableHeader, sizeof(TROPUSRTableHeader)) != sizeof(TROPUSRTableHeader))
if (!m_file.read(tableHeader))
return false;
}
@ -76,14 +65,14 @@ bool TROPUSRLoader::LoadTableHeaders()
bool TROPUSRLoader::LoadTables()
{
if (!m_file->IsOpened())
if (!m_file)
{
return false;
}
for (const TROPUSRTableHeader& tableHeader : m_tableHeaders)
{
m_file->Seek(tableHeader.offset);
m_file.seek(tableHeader.offset);
if (tableHeader.type == 4)
{
@ -92,7 +81,7 @@ bool TROPUSRLoader::LoadTables()
for (auto& entry : m_table4)
{
if (m_file->Read(&entry, sizeof(TROPUSREntry4)) != sizeof(TROPUSREntry4))
if (!m_file.read(entry))
return false;
}
}
@ -104,7 +93,7 @@ bool TROPUSRLoader::LoadTables()
for (auto& entry : m_table6)
{
if (m_file->Read(&entry, sizeof(TROPUSREntry6)) != sizeof(TROPUSREntry6))
if (!m_file.read(entry))
return false;
}
}
@ -118,39 +107,39 @@ bool TROPUSRLoader::LoadTables()
// TODO: TROPUSRLoader::Save deletes the TROPUSR and creates it again. This is probably very slow.
bool TROPUSRLoader::Save(const std::string& filepath)
{
if (m_file)
if (!m_file.open(vfs::get(filepath), fs::rewrite))
{
Close();
return false;
}
m_file = Emu.GetVFS().OpenFile(filepath, fom::rewrite);
m_file->Write(&m_header, sizeof(TROPUSRHeader));
m_file.write(m_header);
for (const TROPUSRTableHeader& tableHeader : m_tableHeaders)
{
m_file->Write(&tableHeader, sizeof(TROPUSRTableHeader));
m_file.write(tableHeader);
}
for (const auto& entry : m_table4)
{
m_file->Write(&entry, sizeof(TROPUSREntry4));
m_file.write(entry);
}
for (const auto& entry : m_table6)
{
m_file->Write(&entry, sizeof(TROPUSREntry6));
m_file.write(entry);
}
m_file->Close();
m_file.release();
return true;
}
bool TROPUSRLoader::Generate(const std::string& filepath, const std::string& configpath)
{
std::string path;
const std::string& path = vfs::get(configpath);
// TODO: rXmlDocument can open only real file
ASSERT(!fs::get_virtual_device(path));
rXmlDocument doc;
Emu.GetVFS().GetDevice(configpath.c_str(), path);
doc.Load(path);
m_table4.clear();
@ -238,13 +227,3 @@ bool TROPUSRLoader::UnlockTrophy(u32 id, u64 timestamp1, u64 timestamp2)
return true;
}
void TROPUSRLoader::Close()
{
if (m_file)
{
m_file->Close();
delete m_file;
m_file = nullptr;
}
}

View File

@ -1,7 +1,5 @@
#pragma once
struct vfsStream;
struct TROPUSRHeader
{
be_t<u32> magic; // 81 8F 54 AD
@ -56,8 +54,8 @@ struct TROPUSREntry6
class TROPUSRLoader
{
vfsStream* m_file;
TROPUSRHeader m_header;
fs::file m_file;
TROPUSRHeader m_header{};
std::vector<TROPUSRTableHeader> m_tableHeaders;
std::vector<TROPUSREntry4> m_table4;
@ -69,12 +67,8 @@ class TROPUSRLoader
virtual bool LoadTables();
public:
TROPUSRLoader();
~TROPUSRLoader();
virtual bool Load(const std::string& filepath, const std::string& configpath);
virtual bool Save(const std::string& filepath);
virtual void Close();
virtual u32 GetTrophiesCount();

View File

@ -1,42 +1,34 @@
#include "stdafx.h"
#include "Emu/System.h"
#include "Emu/FS/VFS.h"
#include "Emu/FS/vfsFile.h"
#include "TRP.h"
TRPLoader::TRPLoader(vfsStream& f) : trp_f(f)
TRPLoader::TRPLoader(const fs::file& f)
: trp_f(f)
{
}
TRPLoader::~TRPLoader()
bool TRPLoader::Install(const std::string& dest, bool show)
{
Close();
}
bool TRPLoader::Install(std::string dest, bool show)
{
if (!trp_f.IsOpened())
if (!trp_f)
{
return false;
}
if (!dest.empty() && dest.back() != '/')
const std::string& local_path = vfs::get(dest);
if (!fs::create_dir(local_path) && errno != EEXIST)
{
dest += '/';
return false;
}
if (!Emu.GetVFS().ExistsDir(dest))
{
Emu.GetVFS().CreateDir(dest);
}
std::vector<char> buffer; buffer.reserve(65536);
for (const TRPEntry& entry : m_entries)
{
char* buffer = new char [(u32)entry.size];
trp_f.Seek(entry.offset);
trp_f.Read(buffer, entry.size);
vfsFile(dest + entry.name, fom::rewrite).Write(buffer, entry.size);
delete[] buffer;
trp_f.seek(entry.offset);
buffer.resize(entry.size);
if (!trp_f.read(buffer)) continue; // ???
fs::file(local_path + '/' + entry.name, fs::rewrite).write(buffer);
}
return true;
@ -44,14 +36,14 @@ bool TRPLoader::Install(std::string dest, bool show)
bool TRPLoader::LoadHeader(bool show)
{
if (!trp_f.IsOpened())
if (!trp_f)
{
return false;
}
trp_f.Seek(0);
trp_f.seek(0);
if (trp_f.Read(&m_header, sizeof(TRPHeader)) != sizeof(TRPHeader))
if (!trp_f.read(m_header))
{
return false;
}
@ -71,7 +63,7 @@ bool TRPLoader::LoadHeader(bool show)
for (u32 i = 0; i < m_header.trp_files_count; i++)
{
if (trp_f.Read(&m_entries[i], sizeof(TRPEntry)) != sizeof(TRPEntry))
if (!trp_f.read(m_entries[i]))
{
return false;
}
@ -123,8 +115,3 @@ void TRPLoader::RenameEntry(const char *oldname, const char *newname)
}
}
}
void TRPLoader::Close()
{
trp_f.Close();
}

View File

@ -1,7 +1,5 @@
#pragma once
struct vfsStream;
struct TRPHeader
{
be_t<u32> trp_magic;
@ -23,21 +21,19 @@ struct TRPEntry
char padding[12];
};
class TRPLoader
class TRPLoader final
{
vfsStream& trp_f;
const fs::file& trp_f;
TRPHeader m_header;
std::vector<TRPEntry> m_entries;
public:
TRPLoader(vfsStream& f);
~TRPLoader();
virtual bool Install(std::string dest, bool show = false);
virtual bool LoadHeader(bool show = false);
TRPLoader(const fs::file& f);
virtual bool ContainsEntry(const char *filename);
virtual void RemoveEntry(const char *filename);
virtual void RenameEntry(const char *oldname, const char *newname);
bool Install(const std::string& dest, bool show = false);
bool LoadHeader(bool show = false);
virtual void Close();
bool ContainsEntry(const char *filename);
void RemoveEntry(const char *filename);
void RenameEntry(const char *oldname, const char *newname);
};