CDVD: Remove exceptions (completely this time)

The actual reads are still missing error checking...
This commit is contained in:
Stenzek 2022-12-28 22:14:43 +10:00 committed by Connor McLaughlin
parent ab4592b8e9
commit 52266d7ac0
14 changed files with 423 additions and 408 deletions

View File

@ -1357,42 +1357,40 @@ std::string_view Achievements::GetELFNameForHash(const std::string& elf_path)
std::optional<std::vector<u8>> Achievements::ReadELFFromCurrentDisc(const std::string& elf_path) std::optional<std::vector<u8>> Achievements::ReadELFFromCurrentDisc(const std::string& elf_path)
{ {
// This CDVD stuff is super nasty and full of exceptions..
std::optional<std::vector<u8>> ret; std::optional<std::vector<u8>> ret;
try
// ELF suffix hack. Taken from CDVD::loadElf
// MLB2k6 has an elf whose suffix is actually ;2
std::string filepath(elf_path);
const std::string::size_type semi_pos = filepath.rfind(';');
if (semi_pos != std::string::npos && std::string_view(filepath).substr(semi_pos) != ";1")
{ {
// ELF suffix hack. Taken from CDVD::loadElf Console.Warning(fmt::format("(Achievements) Non-conforming version suffix ({}) detected and replaced.", elf_path));
// MLB2k6 has an elf whose suffix is actually ;2 filepath.erase(semi_pos);
std::string filepath(elf_path); filepath += ";1";
const std::string::size_type semi_pos = filepath.rfind(';');
if (semi_pos != std::string::npos && std::string_view(filepath).substr(semi_pos) != ";1")
{
Console.Warning("(Achievements) Non-conforming version suffix (%s) detected and replaced.", elf_path.c_str());
filepath.erase(semi_pos);
filepath += ";1";
}
IsoFSCDVD isofs;
IsoFile file(isofs, filepath);
const u32 size = file.getLength();
ret = std::vector<u8>();
ret->resize(size);
if (size > 0)
{
const s32 bytes_read = file.read(ret->data(), static_cast<s32>(size));
if (bytes_read != static_cast<s32>(size))
{
Console.Error("(Achievements) Only read %d of %u bytes of ELF '%s'", bytes_read, size, elf_path.c_str());
ret.reset();
}
}
} }
catch (...)
IsoFSCDVD isofs;
IsoFile file(isofs);
Error error;
if (!file.open(filepath, &error))
{ {
Console.Error("(Achievements) Caught exception while trying to read ELF '%s'.", elf_path.c_str()); Console.Error(fmt::format("(Achievements) Failed to open ELF '{}' on disc: {}", elf_path, error.GetDescription()));
ret.reset(); return ret;
}
const u32 size = file.getLength();
ret = std::vector<u8>();
ret->resize(size);
if (size > 0)
{
const s32 bytes_read = file.read(ret->data(), static_cast<s32>(size));
if (bytes_read != static_cast<s32>(size))
{
Console.Error(fmt::format("(Achievements) Only read {} of {} bytes of ELF '{}'", bytes_read, size, elf_path));
ret.reset();
}
} }
return ret; return ret;

View File

@ -383,140 +383,118 @@ s32 cdvdWriteConfig(const u8* config)
return 0; return 0;
} }
// Sets ElfCRC to the CRC of the game bound to the CDVD source. bool cdvdLoadElf(ElfObject* elfo, std::string elfpath, bool isPSXElf, Error* error)
std::unique_ptr<ElfObject> cdvdLoadElf(std::string filename, bool isPSXElf)
{ {
if (StringUtil::StartsWith(filename, "host:")) if (StringUtil::StartsWith(elfpath, "host:"))
{ {
std::string host_filename(filename.substr(5)); std::string host_filename(elfpath.substr(5));
s64 host_size = FileSystem::GetPathFileSize(host_filename.c_str()); if (!elfo->OpenFile(host_filename, isPSXElf, error))
return std::make_unique<ElfObject>(std::move(host_filename), static_cast<u32>(std::max<s64>(host_size, 0)), isPSXElf); return false;
}
else
{
// Mimic PS2 behavior!
// Much trial-and-error with changing the ISOFS and BOOT2 contents of an image have shown that
// the PS2 BIOS performs the peculiar task of *ignoring* the version info from the parsed BOOT2
// filename *and* the ISOFS, when loading the game's ELF image. What this means is:
//
// 1. a valid PS2 ELF can have any version (ISOFS), and the version need not match the one in SYSTEM.CNF.
// 2. the version info on the file in the BOOT2 parameter of SYSTEM.CNF can be missing, 10 chars long,
// or anything else. Its all ignored.
// 3. Games loading their own files do *not* exhibit this behavior; likely due to using newer IOP modules
// or lower level filesystem APIs (fortunately that doesn't affect us).
//
// FIXME: Properly mimicing this behavior is troublesome since we need to add support for "ignoring"
// version information when doing file searches. I'll add this later. For now, assuming a ;1 should
// be sufficient (no known games have their ELF binary as anything but version ;1)
const std::string::size_type semi_pos = elfpath.rfind(';');
if (semi_pos != std::string::npos && std::string_view(elfpath).substr(semi_pos) != ";1")
{
Console.WriteLn(Color_Blue, "(LoadELF) Non-conforming version suffix (%s) detected and replaced.", elfpath.c_str());
elfpath.erase(semi_pos);
elfpath += ";1";
}
// Fix cdrom:path, the iso reader doesn't like it.
if (StringUtil::StartsWith(elfpath, "cdrom:") && elfpath[6] != '\\' && elfpath[6] != '/')
elfpath.insert(6, 1, '\\');
IsoFSCDVD isofs;
IsoFile file(isofs);
if (!file.open(elfpath, error) || !elfo->OpenIsoFile(elfpath, file, isPSXElf, error))
return false;
} }
// Mimic PS2 behavior! return true;
// Much trial-and-error with changing the ISOFS and BOOT2 contents of an image have shown that
// the PS2 BIOS performs the peculiar task of *ignoring* the version info from the parsed BOOT2
// filename *and* the ISOFS, when loading the game's ELF image. What this means is:
//
// 1. a valid PS2 ELF can have any version (ISOFS), and the version need not match the one in SYSTEM.CNF.
// 2. the version info on the file in the BOOT2 parameter of SYSTEM.CNF can be missing, 10 chars long,
// or anything else. Its all ignored.
// 3. Games loading their own files do *not* exhibit this behavior; likely due to using newer IOP modules
// or lower level filesystem APIs (fortunately that doesn't affect us).
//
// FIXME: Properly mimicing this behavior is troublesome since we need to add support for "ignoring"
// version information when doing file searches. I'll add this later. For now, assuming a ;1 should
// be sufficient (no known games have their ELF binary as anything but version ;1)
const std::string::size_type semi_pos = filename.rfind(';');
if (semi_pos != std::string::npos && std::string_view(filename).substr(semi_pos) != ";1")
{
Console.WriteLn(Color_Blue, "(LoadELF) Non-conforming version suffix (%s) detected and replaced.", filename.c_str());
filename.erase(semi_pos);
filename += ";1";
}
// Fix cdrom:path, the iso reader doesn't like it.
if (StringUtil::StartsWith(filename, "cdrom:") && filename[6] != '\\' && filename[6] != '/')
filename.insert(6, 1, '\\');
IsoFSCDVD isofs;
IsoFile file(isofs, filename);
return std::make_unique<ElfObject>(std::move(filename), file, isPSXElf);
} }
u32 cdvdGetElfCRC(const std::string& path) u32 cdvdGetElfCRC(const std::string& path)
{ {
try ElfObject elfo;
{ if (!elfo.OpenFile(path, false, nullptr))
// Yay for write-after-read here. Isn't our ELF parser great....
const s64 host_size = FileSystem::GetPathFileSize(path.c_str());
if (host_size <= 0)
return 0;
std::unique_ptr<ElfObject> elfptr(std::make_unique<ElfObject>(path, static_cast<u32>(std::max<s64>(host_size, 0)), false));
elfptr->loadHeaders();
return elfptr->getCRC();
}
catch ([[maybe_unused]] Exception::FileNotFound& e)
{
return 0; return 0;
}
return elfo.GetCRC();
} }
// return value:
// 0 - Invalid or unknown disc.
// 1 - PS1 CD
// 2 - PS2 CD
static CDVDDiscType GetPS2ElfName(std::string* name, std::string* version) static CDVDDiscType GetPS2ElfName(std::string* name, std::string* version)
{ {
CDVDDiscType retype = CDVDDiscType::Other; CDVDDiscType retype = CDVDDiscType::Other;
name->clear(); name->clear();
version->clear(); version->clear();
try { Error error;
IsoFSCDVD isofs; IsoFSCDVD isofs;
IsoFile file( isofs, "SYSTEM.CNF;1"); IsoFile file(isofs);
if (!file.open("SYSTEM.CNF;1", &error))
{
Console.Error(fmt::format("(GetElfName) Failed to open SYSTEM.CNF: {}", error.GetDescription()));
return CDVDDiscType::Other;
}
int size = file.getLength(); const int size = file.getLength();
if( size == 0 ) return CDVDDiscType::Other; if (size == 0)
return CDVDDiscType::Other;
while( !file.eof() ) while (!file.eof())
{ {
const std::string line(file.readLine()); const std::string line(file.readLine());
std::string_view key, value; std::string_view key, value;
if (!StringUtil::ParseAssignmentString(line, &key, &value)) if (!StringUtil::ParseAssignmentString(line, &key, &value))
continue; continue;
if( value.empty() && file.getLength() != file.getSeekPos() ) if (value.empty() && file.getLength() != file.getSeekPos())
{ // Some games have a character on the last line of the file, don't print the error in those cases. { // Some games have a character on the last line of the file, don't print the error in those cases.
Console.Warning( "(SYSTEM.CNF) Unusual or malformed entry in SYSTEM.CNF ignored:" ); Console.Warning("(SYSTEM.CNF) Unusual or malformed entry in SYSTEM.CNF ignored:");
Console.Indent().WriteLn(line); Console.Indent().WriteLn(line);
continue; continue;
}
if( key == "BOOT2" )
{
Console.WriteLn( Color_StrongBlue, "(SYSTEM.CNF) Detected PS2 Disc = %.*s",
static_cast<int>(value.size()), value.data());
*name = value;
retype = CDVDDiscType::PS2Disc;
}
else if( key == "BOOT" )
{
Console.WriteLn( Color_StrongBlue, "(SYSTEM.CNF) Detected PSX/PSone Disc = %.*s",
static_cast<int>(value.size()), value.data());
*name = value;
retype = CDVDDiscType::PS1Disc;
}
else if( key == "VMODE" )
{
Console.WriteLn( Color_Blue, "(SYSTEM.CNF) Disc region type = %.*s",
static_cast<int>(value.size()), value.data());
}
else if( key == "VER" )
{
Console.WriteLn( Color_Blue, "(SYSTEM.CNF) Software version = %.*s",
static_cast<int>(value.size()), value.data());
*version = value;
}
} }
if( retype == CDVDDiscType::Other ) if (key == "BOOT2")
{ {
Console.Error("(GetElfName) Disc image is *not* a PlayStation or PS2 game!"); Console.WriteLn(Color_StrongBlue, fmt::format("(SYSTEM.CNF) Detected PS2 Disc = {}", value));
return CDVDDiscType::Other; *name = value;
retype = CDVDDiscType::PS2Disc;
}
else if (key == "BOOT")
{
Console.WriteLn(Color_StrongBlue, fmt::format("(SYSTEM.CNF) Detected PSX/PSone Disc = {}", value));
*name = value;
retype = CDVDDiscType::PS1Disc;
}
else if (key == "VMODE")
{
Console.WriteLn(Color_Blue, fmt::format("(SYSTEM.CNF) Disc region type = {}", value));
}
else if (key == "VER")
{
Console.WriteLn(Color_Blue, fmt::format("(SYSTEM.CNF) Software version = {}", value));
*version = value;
} }
} }
catch( Exception::FileNotFound& )
{ if (retype == CDVDDiscType::Other)
//Console.Warning(ex.FormatDiagnosticMessage()); Console.Error("(GetElfName) Disc image is *not* a PlayStation or PS2 game!");
return CDVDDiscType::Other; // no SYSTEM.CNF, not a PS1/PS2 disc.
}
catch (Exception::BadStream& ex)
{
Console.Error(ex.FormatDiagnosticMessage());
return CDVDDiscType::Other; // ISO error
}
return retype; return retype;
} }
@ -586,21 +564,13 @@ void cdvdGetDiscInfo(std::string* out_serial, std::string* out_elf_path, std::st
if (disc_type == CDVDDiscType::PS2Disc || disc_type == CDVDDiscType::PS1Disc) if (disc_type == CDVDDiscType::PS2Disc || disc_type == CDVDDiscType::PS1Disc)
{ {
try Error error;
{ ElfObject elfo;
const bool isPSXElf = (disc_type == CDVDDiscType::PS1Disc); const bool isPSXElf = (disc_type == CDVDDiscType::PS1Disc);
std::unique_ptr<ElfObject> elfptr(cdvdLoadElf(elfpath, isPSXElf)); if (!cdvdLoadElf(&elfo, elfpath, isPSXElf, &error))
elfptr->loadHeaders(); Console.Error(fmt::format("Failed to load ELF info for {}: {}", elfpath, error.GetDescription()));
crc = elfptr->getCRC(); else
} crc = elfo.GetCRC();
catch ([[maybe_unused]] Exception::FileNotFound& e)
{
Console.Error(fmt::format("Failed to load ELF info for {}", elfpath));
}
catch (Exception::BadStream& ex)
{
Console.Error(ex.FormatDiagnosticMessage());
}
} }
*out_crc = crc; *out_crc = crc;

View File

@ -21,6 +21,7 @@
#include <string> #include <string>
#include <string_view> #include <string_view>
class Error;
class ElfObject; class ElfObject;
#define btoi(b) ((b) / 16 * 10 + (b) % 16) /* BCD to u_char */ #define btoi(b) ((b) / 16 * 10 + (b) % 16) /* BCD to u_char */
@ -189,7 +190,7 @@ extern void cdvdWrite(u8 key, u8 rt);
extern void cdvdGetDiscInfo(std::string* out_serial, std::string* out_elf_path, std::string* out_version, u32* out_crc, extern void cdvdGetDiscInfo(std::string* out_serial, std::string* out_elf_path, std::string* out_version, u32* out_crc,
CDVDDiscType* out_disc_type); CDVDDiscType* out_disc_type);
extern u32 cdvdGetElfCRC(const std::string& path); extern u32 cdvdGetElfCRC(const std::string& path);
extern std::unique_ptr<ElfObject> cdvdLoadElf(std::string filename, bool isPSXElf); extern bool cdvdLoadElf(ElfObject* elfo, std::string filename, bool isPSXElf, Error* error);
extern s32 cdvdCtrlTrayOpen(); extern s32 cdvdCtrlTrayOpen();
extern s32 cdvdCtrlTrayClose(); extern s32 cdvdCtrlTrayClose();

View File

@ -73,14 +73,11 @@ static void CheckNullCDVD()
static int CheckDiskTypeFS(int baseType) static int CheckDiskTypeFS(int baseType)
{ {
IsoFSCDVD isofs; IsoFSCDVD isofs;
try IsoDirectory rootdir(isofs);
if (rootdir.OpenRootDirectory())
{ {
IsoDirectory rootdir(isofs); if (IsoFile file(isofs); file.open(rootdir, "SYSTEM.CNF;1"))
try
{ {
IsoFile file(rootdir, "SYSTEM.CNF;1");
const int size = file.getLength(); const int size = file.getLength();
const std::unique_ptr<char[]> buffer = std::make_unique<char[]>(size + 1); const std::unique_ptr<char[]> buffer = std::make_unique<char[]>(size + 1);
file.read(buffer.get(), size); file.read(buffer.get(), size);
@ -97,40 +94,16 @@ static int CheckDiskTypeFS(int baseType)
return (baseType == CDVD_TYPE_DETCTCD) ? CDVD_TYPE_PS2CD : CDVD_TYPE_PS2DVD; return (baseType == CDVD_TYPE_DETCTCD) ? CDVD_TYPE_PS2CD : CDVD_TYPE_PS2DVD;
} }
catch (Exception::FileNotFound&)
{
}
// PS2 Linux disc 2, doesn't have a System.CNF or a normal ELF // PS2 Linux disc 2, doesn't have a System.CNF or a normal ELF
try if (rootdir.Exists("P2L_0100.02;1"))
{
IsoFile file(rootdir, "P2L_0100.02;1");
return CDVD_TYPE_PS2DVD; return CDVD_TYPE_PS2DVD;
}
catch (Exception::FileNotFound&)
{
}
try if (rootdir.Exists("PSX.EXE;1"))
{
IsoFile file(rootdir, "PSX.EXE;1");
return CDVD_TYPE_PSCD; return CDVD_TYPE_PSCD;
}
catch (Exception::FileNotFound&)
{
}
try if (rootdir.Exists("VIDEO_TS/VIDEO_TS.IFO;1"))
{
IsoFile file(rootdir, "VIDEO_TS/VIDEO_TS.IFO;1");
return CDVD_TYPE_DVDV; return CDVD_TYPE_DVDV;
}
catch (Exception::FileNotFound&)
{
}
}
catch (Exception::FileNotFound&)
{
} }
#ifdef PCSX2_DEVBUILD #ifdef PCSX2_DEVBUILD

View File

@ -16,26 +16,31 @@
#pragma once #pragma once
#include "common/Pcsx2Defs.h" #include "common/Pcsx2Defs.h"
#include <optional>
#include <string_view> #include <string_view>
#include <vector> #include <vector>
class Error;
enum IsoFS_Type enum IsoFS_Type
{ {
FStype_ISO9660 = 1, FStype_ISO9660 = 1,
FStype_Joliet = 2, FStype_Joliet = 2,
}; };
class IsoDirectory class IsoDirectory final
{ {
public: public:
SectorSource& internalReader; SectorSource& internalReader;
std::vector<IsoFileDescriptor> files; std::vector<IsoFileDescriptor> files;
IsoFS_Type m_fstype; IsoFS_Type m_fstype = FStype_ISO9660;
public: public:
IsoDirectory(SectorSource& r); IsoDirectory(SectorSource& r);
IsoDirectory(SectorSource& r, const IsoFileDescriptor& directoryEntry); ~IsoDirectory();
virtual ~IsoDirectory() = default;
bool OpenRootDirectory(Error* error = nullptr);
bool Open(const IsoFileDescriptor& directoryEntry, Error* error = nullptr);
std::string FStype_ToString() const; std::string FStype_ToString() const;
SectorSource& GetReader() const { return internalReader; } SectorSource& GetReader() const { return internalReader; }
@ -46,12 +51,10 @@ public:
u32 GetFileSize(const std::string_view& filePath) const; u32 GetFileSize(const std::string_view& filePath) const;
IsoFileDescriptor FindFile(const std::string_view& filePath) const; std::optional<IsoFileDescriptor> FindFile(const std::string_view& filePath) const;
protected: protected:
const IsoFileDescriptor& GetEntry(const std::string_view& fileName) const; const IsoFileDescriptor& GetEntry(size_t index) const;
const IsoFileDescriptor& GetEntry(int index) const;
void Init(const IsoFileDescriptor& directoryEntry);
int GetIndexOf(const std::string_view& fileName) const; int GetIndexOf(const std::string_view& fileName) const;
}; };

View File

@ -20,7 +20,7 @@
#include "IsoFile.h" #include "IsoFile.h"
#include "common/Assertions.h" #include "common/Assertions.h"
#include "common/Exceptions.h" #include "common/Error.h"
#include "common/FileSystem.h" #include "common/FileSystem.h"
#include "common/Path.h" #include "common/Path.h"
#include "common/StringUtil.h" #include "common/StringUtil.h"
@ -51,6 +51,12 @@ std::string IsoDirectory::FStype_ToString() const
// Used to load the Root directory from an image // Used to load the Root directory from an image
IsoDirectory::IsoDirectory(SectorSource& r) IsoDirectory::IsoDirectory(SectorSource& r)
: internalReader(r) : internalReader(r)
{
}
IsoDirectory::~IsoDirectory() = default;
bool IsoDirectory::OpenRootDirectory(Error* error /* = nullptr */)
{ {
IsoFileDescriptor rootDirEntry; IsoFileDescriptor rootDirEntry;
bool isValid = false; bool isValid = false;
@ -107,22 +113,17 @@ IsoDirectory::IsoDirectory(SectorSource& r)
} }
if (!isValid) if (!isValid)
throw Exception::FileNotFound("IsoFileSystem") // FIXME: Should report the name of the ISO here... {
.SetDiagMsg("IsoFS could not find the root directory on the ISO image."); Error::SetString(error, "IsoFS could not find the root directory on the ISO image.");
return false;
}
DevCon.WriteLn("(IsoFS) Filesystem is %s", FStype_ToString().c_str()); DevCon.WriteLn("(IsoFS) Filesystem is %s", FStype_ToString().c_str());
Init(rootDirEntry); return Open(rootDirEntry);
} }
// Used to load a specific directory from a file descriptor // Used to load a specific directory from a file descriptor
IsoDirectory::IsoDirectory(SectorSource& r, const IsoFileDescriptor& directoryEntry) bool IsoDirectory::Open(const IsoFileDescriptor& directoryEntry, Error* error /* = nullptr */)
: internalReader(r)
{
m_fstype = FStype_ISO9660;
Init(directoryEntry);
}
void IsoDirectory::Init(const IsoFileDescriptor& directoryEntry)
{ {
// parse directory sector // parse directory sector
IsoFile dataStream(internalReader, directoryEntry); IsoFile dataStream(internalReader, directoryEntry);
@ -163,9 +164,10 @@ void IsoDirectory::Init(const IsoFileDescriptor& directoryEntry)
} }
b[0] = 0; b[0] = 0;
return true;
} }
const IsoFileDescriptor& IsoDirectory::GetEntry(int index) const const IsoFileDescriptor& IsoDirectory::GetEntry(size_t index) const
{ {
return files[index]; return files[index];
} }
@ -178,25 +180,19 @@ int IsoDirectory::GetIndexOf(const std::string_view& fileName) const
return i; return i;
} }
throw Exception::FileNotFound(std::string(fileName)); return -1;
} }
const IsoFileDescriptor& IsoDirectory::GetEntry(const std::string_view& fileName) const std::optional<IsoFileDescriptor> IsoDirectory::FindFile(const std::string_view& filePath) const
{
return GetEntry(GetIndexOf(fileName));
}
IsoFileDescriptor IsoDirectory::FindFile(const std::string_view& filePath) const
{ {
if (filePath.empty()) if (filePath.empty())
throw Exception::FileNotFound(); return std::nullopt;
// DOS-style parser should work fine for ISO 9660 path names. Only practical difference // DOS-style parser should work fine for ISO 9660 path names. Only practical difference
// is case sensitivity, and that won't matter for path splitting. // is case sensitivity, and that won't matter for path splitting.
std::vector<std::string_view> parts(Path::SplitWindowsPath(filePath)); std::vector<std::string_view> parts(Path::SplitWindowsPath(filePath));
IsoFileDescriptor info;
const IsoDirectory* dir = this; const IsoDirectory* dir = this;
std::unique_ptr<IsoDirectory> deleteme; IsoDirectory subdir(internalReader);
// walk through path ("." and ".." entries are in the directories themselves, so even if the // walk through path ("." and ".." entries are in the directories themselves, so even if the
// path included . and/or .., it still works) // path included . and/or .., it still works)
@ -206,35 +202,67 @@ IsoFileDescriptor IsoDirectory::FindFile(const std::string_view& filePath) const
for (size_t index = has_device ? 1 : 0; index < (parts.size() - 1); index++) for (size_t index = has_device ? 1 : 0; index < (parts.size() - 1); index++)
{ {
info = dir->GetEntry(parts[index]); const int subdir_index = GetIndexOf(parts[index]);
if (info.IsFile()) if (subdir_index < 0)
throw Exception::FileNotFound(std::string(filePath)); return std::nullopt;
deleteme.reset(new IsoDirectory(internalReader, info)); const IsoFileDescriptor& subdir_entry = GetEntry(static_cast<size_t>(index));
dir = deleteme.get(); if (subdir_entry.IsFile() || !subdir.Open(subdir_entry, nullptr))
return std::nullopt;
dir = &subdir;
} }
info = dir->GetEntry(parts.back()); const int file_index = dir->GetIndexOf(parts.back());
return info; if (file_index < 0)
return std::nullopt;
return GetEntry(static_cast<size_t>(file_index));
}
bool IsoDirectory::Exists(const std::string_view& filePath) const
{
if (filePath.empty())
return false;
const std::optional<IsoFileDescriptor> fd(FindFile(filePath));
return fd.has_value();
} }
bool IsoDirectory::IsFile(const std::string_view& filePath) const bool IsoDirectory::IsFile(const std::string_view& filePath) const
{ {
if (filePath.empty()) if (filePath.empty())
return false; return false;
return (FindFile(filePath).flags & 2) != 2;
const std::optional<IsoFileDescriptor> fd(FindFile(filePath));
if (fd.has_value())
return false;
return ((fd->flags & 2) != 2);
} }
bool IsoDirectory::IsDir(const std::string_view& filePath) const bool IsoDirectory::IsDir(const std::string_view& filePath) const
{ {
if (filePath.empty()) if (filePath.empty())
return false; return false;
return (FindFile(filePath).flags & 2) == 2;
const std::optional<IsoFileDescriptor> fd(FindFile(filePath));
if (fd.has_value())
return false;
return ((fd->flags & 2) == 2);
} }
u32 IsoDirectory::GetFileSize(const std::string_view& filePath) const u32 IsoDirectory::GetFileSize(const std::string_view& filePath) const
{ {
return FindFile(filePath).size; if (filePath.empty())
return 0;
const std::optional<IsoFileDescriptor> fd(FindFile(filePath));
if (fd.has_value())
return 0;
return fd->size;
} }
IsoFileDescriptor::IsoFileDescriptor() IsoFileDescriptor::IsoFileDescriptor()

View File

@ -17,7 +17,7 @@
class IsoFile; class IsoFile;
class IsoDirectory; class IsoDirectory;
struct ISoFileDescriptor; struct IsoFileDescriptor;
#include "SectorSource.h" #include "SectorSource.h"
#include "IsoFileDescriptor.h" #include "IsoFileDescriptor.h"

View File

@ -19,7 +19,7 @@
#include "SectorSource.h" #include "SectorSource.h"
class IsoFSCDVD : public SectorSource class IsoFSCDVD final : public SectorSource
{ {
public: public:
IsoFSCDVD(); IsoFSCDVD();

View File

@ -16,26 +16,19 @@
#include "PrecompiledHeader.h" #include "PrecompiledHeader.h"
#include "common/Assertions.h" #include "common/Assertions.h"
#include "common/Exceptions.h" #include "common/Error.h"
#include "IsoFS.h" #include "IsoFS.h"
#include "IsoFile.h" #include "IsoFile.h"
#include <cstdio> #include <cstdio>
IsoFile::IsoFile(SectorSource& reader, const std::string_view& filename) IsoFile::IsoFile(SectorSource& reader)
: internalReader(reader) : internalReader(reader)
, fileEntry(IsoDirectory(reader).FindFile(filename))
{ {
Init();
} }
IsoFile::IsoFile(const IsoDirectory& dir, const std::string_view& filename) IsoFile::~IsoFile() = default;
: internalReader(dir.GetReader())
, fileEntry(dir.FindFile(filename))
{
Init();
}
IsoFile::IsoFile(SectorSource& reader, const IsoFileDescriptor& fileEntry) IsoFile::IsoFile(SectorSource& reader, const IsoFileDescriptor& fileEntry)
: internalReader(reader) : internalReader(reader)
@ -51,12 +44,35 @@ void IsoFile::Init()
currentSectorNumber = fileEntry.lba; currentSectorNumber = fileEntry.lba;
currentOffset = 0; currentOffset = 0;
sectorOffset = 0; sectorOffset = 0;
maxOffset = std::max<u32>(0, fileEntry.size); maxOffset = fileEntry.size;
if (maxOffset > 0) if (maxOffset > 0)
internalReader.readSector(currentSector, currentSectorNumber); internalReader.readSector(currentSector, currentSectorNumber);
} }
bool IsoFile::open(const IsoDirectory& dir, const std::string_view& filename, Error* error /*= nullptr*/)
{
const std::optional<IsoFileDescriptor> fd(dir.FindFile(filename));
if (!fd.has_value())
{
Error::SetString(error, fmt::format("Failed to find file '{}'", filename));
return false;
}
fileEntry = std::move(fd.value());
Init();
return true;
}
bool IsoFile::open(const std::string_view& filename, Error* error /*= nullptr*/)
{
IsoDirectory dir(internalReader);
if (!dir.OpenRootDirectory(error))
return false;
return open(dir, filename, error);
}
u32 IsoFile::seek(u32 absoffset) u32 IsoFile::seek(u32 absoffset)
{ {
u32 endOffset = absoffset; u32 endOffset = absoffset;
@ -142,7 +158,7 @@ void IsoFile::makeDataAvailable()
u8 IsoFile::readByte() u8 IsoFile::readByte()
{ {
if (currentOffset >= maxOffset) if (currentOffset >= maxOffset)
throw Exception::EndOfStream(); return 0;
makeDataAvailable(); makeDataAvailable();

View File

@ -21,27 +21,31 @@
#include "common/Pcsx2Defs.h" #include "common/Pcsx2Defs.h"
#include <string_view> #include <string_view>
class IsoFile class Error;
class IsoFile final
{ {
public: public:
static const int sectorLength = 2048; static const int sectorLength = 2048;
protected: protected:
SectorSource& internalReader; SectorSource& internalReader;
IsoFileDescriptor fileEntry; IsoFileDescriptor fileEntry = {};
u32 currentOffset; u32 currentOffset = 0;
u32 maxOffset; u32 maxOffset = 0;
int currentSectorNumber; int currentSectorNumber = 0;
int sectorOffset = 0;
u8 currentSector[sectorLength]; u8 currentSector[sectorLength];
int sectorOffset;
public: public:
IsoFile(const IsoDirectory& dir, const std::string_view& filename); IsoFile(SectorSource& reader);
IsoFile(SectorSource& reader, const std::string_view& filename);
IsoFile(SectorSource& reader, const IsoFileDescriptor& fileEntry); IsoFile(SectorSource& reader, const IsoFileDescriptor& fileEntry);
virtual ~IsoFile() = default; ~IsoFile();
bool open(const IsoDirectory& dir, const std::string_view& filename, Error* error = nullptr);
bool open(const std::string_view& filename, Error* error = nullptr);
u32 seek(u32 absoffset); u32 seek(u32 absoffset);
u32 seek(s64 offset, int mode); u32 seek(s64 offset, int mode);

View File

@ -43,50 +43,79 @@ struct PSXEXEHeader
static_assert(sizeof(PSXEXEHeader) == 0x800); static_assert(sizeof(PSXEXEHeader) == 0x800);
#pragma pack(pop) #pragma pack(pop)
// All of ElfObjects functions. ElfObject::ElfObject() = default;
ElfObject::ElfObject(std::string srcfile, IsoFile& isofile, bool isPSXElf_)
: data(isofile.getLength(), "ELF headers") ElfObject::~ElfObject() = default;
, header(*(ELF_HEADER*)data.GetPtr())
, filename(std::move(srcfile)) bool ElfObject::OpenIsoFile(std::string srcfile, IsoFile& isofile, bool isPSXElf_, Error* error)
, isPSXElf(isPSXElf_)
{ {
checkElfSize(data.GetSizeInBytes()); const u32 length = isofile.getLength();
readIso(isofile); if (!CheckElfSize(length, error))
initElfHeaders(); return false;
data.resize(length);
const s32 rsize = isofile.read(data.data(), static_cast<s32>(length));
if (rsize < static_cast<s32>(length))
{
Error::SetString(error, "Failed to read ELF from ISO");
return false;
}
filename = std::move(srcfile);
isPSXElf = isPSXElf_;
InitElfHeaders();
return true;
} }
ElfObject::ElfObject(std::string srcfile, u32 hdrsize, bool isPSXElf_) bool ElfObject::OpenFile(std::string srcfile, bool isPSXElf_, Error* error)
: data(hdrsize, "ELF headers")
, header(*(ELF_HEADER*)data.GetPtr())
, filename(std::move(srcfile))
, isPSXElf(isPSXElf_)
{ {
checkElfSize(data.GetSizeInBytes()); auto fp = FileSystem::OpenManagedCFile(srcfile.c_str(), "rb", error);
readFile(); FILESYSTEM_STAT_DATA sd;
initElfHeaders(); if (!fp || !FileSystem::StatFile(fp.get(), &sd))
{
Error::SetString(error, fmt::format("Failed to read ELF from '{}'", srcfile));
return false;
}
if (!isPSXElf_ && !CheckElfSize(sd.Size, error))
return false;
data.resize(static_cast<size_t>(sd.Size));
if (std::fread(data.data(), data.size(), 1, fp.get()) != 1)
{
Error::SetString(error, fmt::format("Failed to read ELF from '{}'", srcfile));
return false;
}
filename = std::move(srcfile);
isPSXElf = isPSXElf_;
InitElfHeaders();
return true;
} }
void ElfObject::initElfHeaders() void ElfObject::InitElfHeaders()
{ {
if (isPSXElf) if (isPSXElf)
return; return;
DevCon.WriteLn("Initializing Elf: %d bytes", data.GetSizeInBytes()); DevCon.WriteLn("Initializing Elf: %zu bytes", data.size());
const ELF_HEADER& header = GetHeader();
if (header.e_phnum > 0) if (header.e_phnum > 0)
{ {
if ((header.e_phoff + sizeof(ELF_PHR)) <= static_cast<u32>(data.GetSizeInBytes())) if ((header.e_phoff + sizeof(ELF_PHR)) <= data.size())
proghead = reinterpret_cast<ELF_PHR*>(&data[header.e_phoff]); proghead = reinterpret_cast<ELF_PHR*>(&data[header.e_phoff]);
else else
Console.Error("(ELF) Program header offset %u is larger than file size %u", header.e_phoff, data.GetSizeInBytes()); Console.Error("(ELF) Program header offset %u is larger than file size %zu", header.e_phoff, data.size());
} }
if (header.e_shnum > 0) if (header.e_shnum > 0)
{ {
if ((header.e_shoff + sizeof(ELF_SHR)) <= static_cast<u32>(data.GetSizeInBytes())) if ((header.e_shoff + sizeof(ELF_SHR)) <= data.size())
secthead = reinterpret_cast<ELF_SHR*>(&data[header.e_shoff]); secthead = reinterpret_cast<ELF_SHR*>(&data[header.e_shoff]);
else else
Console.Error("(ELF) Section header offset %u is larger than file size %u", header.e_shoff, data.GetSizeInBytes()); Console.Error("(ELF) Section header offset %u is larger than file size %zu", header.e_shoff, data.size());
} }
if ((header.e_shnum > 0) && (header.e_shentsize != sizeof(ELF_SHR))) if ((header.e_shnum > 0) && (header.e_shentsize != sizeof(ELF_SHR)))
@ -147,49 +176,61 @@ void ElfObject::initElfHeaders()
//applyPatches(); //applyPatches();
} }
bool ElfObject::hasValidPSXHeader() bool ElfObject::HasValidPSXHeader() const
{ {
if (data.GetSizeInBytes() < static_cast<s64>(sizeof(PSXEXEHeader))) if (data.size() < sizeof(PSXEXEHeader))
return false; return false;
const PSXEXEHeader* header = reinterpret_cast<const PSXEXEHeader*>(data.GetPtr()); const PSXEXEHeader* header = reinterpret_cast<const PSXEXEHeader*>(data.data());
static constexpr char expected_id[] = {'P', 'S', '-', 'X', ' ', 'E', 'X', 'E'}; static constexpr char expected_id[] = {'P', 'S', '-', 'X', ' ', 'E', 'X', 'E'};
if (std::memcmp(header->id, expected_id, sizeof(expected_id)) != 0) if (std::memcmp(header->id, expected_id, sizeof(expected_id)) != 0)
return false; return false;
if (static_cast<s64>(header->file_size + sizeof(PSXEXEHeader)) > data.GetSizeInBytes()) if ((header->file_size + sizeof(PSXEXEHeader)) > data.size())
{ {
Console.Warning("Incorrect file size in PS-EXE header: %u bytes should not be greater than %u bytes", Console.Warning("Incorrect file size in PS-EXE header: %u bytes should not be greater than %u bytes",
header->file_size, static_cast<unsigned>(data.GetSizeInBytes() - sizeof(PSXEXEHeader))); header->file_size, static_cast<unsigned>(data.size() - sizeof(PSXEXEHeader)));
} }
return true; return true;
} }
bool ElfObject::hasProgramHeaders() { return (proghead != NULL); } bool ElfObject::HasProgramHeaders() const
bool ElfObject::hasSectionHeaders() { return (secthead != NULL); } {
bool ElfObject::hasHeaders() { return (hasProgramHeaders() && hasSectionHeaders()); } return (proghead != nullptr);
}
u32 ElfObject::getEntryPoint() bool ElfObject::HasSectionHeaders() const
{
return (secthead != nullptr);
}
bool ElfObject::HasHeaders() const
{
return (HasProgramHeaders() && HasSectionHeaders());
}
u32 ElfObject::GetEntryPoint() const
{ {
if (isPSXElf) if (isPSXElf)
{ {
if (hasValidPSXHeader()) if (HasValidPSXHeader())
return reinterpret_cast<const PSXEXEHeader*>(data.GetPtr())->initial_pc; return reinterpret_cast<const PSXEXEHeader*>(data.data())->initial_pc;
else else
return 0xFFFFFFFFu; return 0xFFFFFFFFu;
} }
else else
{ {
return header.e_entry; return GetHeader().e_entry;
} }
} }
std::pair<u32,u32> ElfObject::getTextRange() std::pair<u32,u32> ElfObject::GetTextRange() const
{ {
if (!isPSXElf && hasProgramHeaders()) if (!isPSXElf && HasProgramHeaders())
{ {
const ELF_HEADER& header = GetHeader();
for (int i = 0; i < header.e_phnum; i++) for (int i = 0; i < header.e_phnum; i++)
{ {
const u32 start = proghead[i].p_vaddr; const u32 start = proghead[i].p_vaddr;
@ -203,62 +244,36 @@ std::pair<u32,u32> ElfObject::getTextRange()
return std::make_pair(0,0); return std::make_pair(0,0);
} }
void ElfObject::readIso(IsoFile& file) bool ElfObject::CheckElfSize(s64 size, Error* error)
{ {
int rsize = file.read(data.GetPtr(), data.GetSizeInBytes()); if (size > 0xfffffff)
if (rsize < data.GetSizeInBytes()) throw Exception::EndOfStream(filename); Error::SetString(error, "Illegal ELF file size over 2GB!");
else if (size == -1)
Error::SetString(error, "ELF file does not exist!");
else if (size <= static_cast<s64>(sizeof(ELF_HEADER)))
Error::SetString(error, "Unexpected end of ELF file.");
else
return true;
return false;
} }
void ElfObject::readFile() u32 ElfObject::GetCRC() const
{
int rsize = 0;
FILE *f = FileSystem::OpenCFile( filename.c_str(), "rb");
if (f == NULL) throw Exception::FileNotFound(filename);
fseek(f, 0, SEEK_SET);
rsize = fread(data.GetPtr(), 1, data.GetSizeInBytes(), f);
fclose( f );
if (rsize < data.GetSizeInBytes()) throw Exception::EndOfStream(filename);
}
static std::string GetMsg_InvalidELF()
{
return
"Cannot load ELF binary image. The file may be corrupt or incomplete."
"\n\n"
"If loading from an ISO image, this error may be caused by an unsupported ISO image type or a bug in PCSX2 ISO image support.";
}
void ElfObject::checkElfSize(s64 elfsize)
{
const char* diagMsg = NULL;
if (elfsize > 0xfffffff) diagMsg = "Illegal ELF file size over 2GB!";
else if (elfsize == -1) diagMsg = "ELF file does not exist!";
else if (elfsize == 0) diagMsg = "Unexpected end of ELF file.";
if (diagMsg)
throw Exception::BadStream(filename)
.SetDiagMsg(diagMsg)
.SetUserMsg(GetMsg_InvalidELF());
}
u32 ElfObject::getCRC()
{ {
u32 CRC = 0; u32 CRC = 0;
const u32* srcdata = (u32*)data.GetPtr(); const u32* srcdata = reinterpret_cast<const u32*>(data.data());
for(u32 i=data.GetSizeInBytes()/4; i; --i, ++srcdata) for (u32 i = static_cast<u32>(data.size()) / 4; i; --i, ++srcdata)
CRC ^= *srcdata; CRC ^= *srcdata;
return CRC; return CRC;
} }
void ElfObject::loadProgramHeaders() void ElfObject::LoadProgramHeaders()
{ {
if (proghead == NULL) return; if (proghead == NULL) return;
const ELF_HEADER& header = GetHeader();
for( int i = 0 ; i < header.e_phnum ; i++ ) for( int i = 0 ; i < header.e_phnum ; i++ )
{ {
ELF_LOG( "Elf32 Program Header" ); ELF_LOG( "Elf32 Program Header" );
@ -289,11 +304,17 @@ void ElfObject::loadProgramHeaders()
} }
} }
void ElfObject::loadSectionHeaders() void ElfObject::LoadSectionHeaders()
{ {
if (secthead == NULL || header.e_shoff > (u32)data.GetLength()) return; const ELF_HEADER& header = GetHeader();
if (!secthead || header.e_shoff > data.size())
return;
const u8* sections_names = data.GetPtr( secthead[ (header.e_shstrndx == 0xffff ? 0 : header.e_shstrndx) ].sh_offset ); // This function scares me a lot. There's a lot of potential for buffer overreads.
// All the accesses should be wrapped in bounds checked read() calls.
const u32 section_names_offset = secthead[(header.e_shstrndx == 0xffff ? 0 : header.e_shstrndx)].sh_offset;
const u8* sections_names = data.data() + section_names_offset;
int i_st = -1, i_dt = -1; int i_st = -1, i_dt = -1;
@ -343,28 +364,33 @@ void ElfObject::loadSectionHeaders()
if ((i_st >= 0) && (i_dt >= 0)) if ((i_st >= 0) && (i_dt >= 0))
{ {
const char * SymNames; const char* SymNames;
Elf32_Sym * eS; Elf32_Sym* eS;
SymNames = (char*)data.GetPtr(secthead[i_dt].sh_offset); if (secthead[i_dt].sh_offset < data.size() &&
eS = (Elf32_Sym*)data.GetPtr(secthead[i_st].sh_offset); secthead[i_st].sh_offset < data.size())
Console.WriteLn("found %d symbols", secthead[i_st].sh_size / sizeof(Elf32_Sym)); {
SymNames = (char*)(data.data() + secthead[i_dt].sh_offset);
eS = (Elf32_Sym*)(data.data() + secthead[i_st].sh_offset);
Console.WriteLn("found %d symbols", secthead[i_st].sh_size / sizeof(Elf32_Sym));
R5900SymbolMap.Clear(); R5900SymbolMap.Clear();
for(uint i = 1; i < (secthead[i_st].sh_size / sizeof(Elf32_Sym)); i++) { for (uint i = 1; i < (secthead[i_st].sh_size / sizeof(Elf32_Sym)); i++)
if ((eS[i].st_value != 0) && (ELF32_ST_TYPE(eS[i].st_info) == 2))
{ {
R5900SymbolMap.AddLabel(&SymNames[eS[i].st_name],eS[i].st_value); if ((eS[i].st_value != 0) && (ELF32_ST_TYPE(eS[i].st_info) == 2))
{
R5900SymbolMap.AddLabel(&SymNames[eS[i].st_name], eS[i].st_value);
}
} }
} }
} }
} }
void ElfObject::loadHeaders() void ElfObject::LoadHeaders()
{ {
if (isPSXElf) if (isPSXElf)
return; return;
loadProgramHeaders(); LoadProgramHeaders();
loadSectionHeaders(); LoadSectionHeaders();
} }

View File

@ -1,5 +1,5 @@
/* PCSX2 - PS2 Emulator for PCs /* PCSX2 - PS2 Emulator for PCs
* Copyright (C) 2002-2010 PCSX2 Dev Team * Copyright (C) 2002-2023 PCSX2 Dev Team
* *
* PCSX2 is free software: you can redistribute it and/or modify it under the terms * PCSX2 is free software: you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Found- * of the GNU Lesser General Public License as published by the Free Software Found-
@ -15,10 +15,10 @@
#pragma once #pragma once
#include "common/SafeArray.h" #include "common/Error.h"
#include "common/SafeArray.inl"
#include "CDVD/IsoFS/IsoFSCDVD.h" #include "CDVD/IsoFS/IsoFSCDVD.h"
#include "CDVD/IsoFS/IsoFS.h" #include "CDVD/IsoFS/IsoFS.h"
#include <vector>
struct ELF_HEADER { struct ELF_HEADER {
u8 e_ident[16]; //0x7f,"ELF" (ELF file identifier) u8 e_ident[16]; //0x7f,"ELF" (ELF file identifier)
@ -118,39 +118,43 @@ struct Elf32_Rel {
u32 r_info; u32 r_info;
}; };
class ElfObject class ElfObject final
{ {
private: public:
SafeArray<u8> data; ElfObject();
ELF_HEADER& header; ElfObject(const ElfObject&) = delete;
ELF_PHR* proghead = nullptr; ~ElfObject();
ELF_SHR* secthead = nullptr;
std::string filename;
bool isPSXElf;
void initElfHeaders(); __fi const ELF_HEADER& GetHeader() const { return *reinterpret_cast<const ELF_HEADER*>(data.data()); }
bool hasValidPSXHeader(); __fi u32 GetSize() const { return static_cast<u32>(data.size()); }
void readIso(IsoFile& file);
void readFile();
void checkElfSize(s64 elfsize);
public: bool OpenFile(std::string srcfile, bool isPSXElf_, Error* error);
ElfObject(std::string srcfile, IsoFile& isofile, bool isPSXElf_); bool OpenIsoFile(std::string srcfile, IsoFile& isofile, bool isPSXElf_, Error* error);
ElfObject(std::string srcfile, u32 hdrsize, bool isPSXElf_);
bool IsPSXElf() const { return isPSXElf; } void LoadHeaders();
void loadProgramHeaders(); bool HasProgramHeaders() const;
void loadSectionHeaders(); bool HasSectionHeaders() const;
void loadHeaders(); bool HasHeaders() const;
bool hasProgramHeaders(); std::pair<u32, u32> GetTextRange() const;
bool hasSectionHeaders(); u32 GetEntryPoint() const;
bool hasHeaders(); u32 GetCRC() const;
std::pair<u32,u32> getTextRange(); private:
u32 getEntryPoint(); std::vector<u8> data;
u32 getCRC(); ELF_PHR* proghead = nullptr;
ELF_SHR* secthead = nullptr;
std::string filename;
bool isPSXElf;
bool CheckElfSize(s64 size, Error* error);
void InitElfHeaders();
void LoadProgramHeaders();
void LoadSectionHeaders();
bool HasValidPSXHeader() const;
}; };
//------------------- //-------------------

View File

@ -182,16 +182,8 @@ bool GameList::GetIsoSerialAndCRC(const std::string& path, s32* disc_type, std::
bool GameList::GetElfListEntry(const std::string& path, GameList::Entry* entry) bool GameList::GetElfListEntry(const std::string& path, GameList::Entry* entry)
{ {
const s64 file_size = FileSystem::GetPathFileSize(path.c_str()); ElfObject eo;
if (file_size <= 0) if (!eo.OpenFile(path, false, nullptr))
return false;
try
{
ElfObject eo(path, static_cast<uint>(file_size), false);
entry->crc = eo.getCRC();
}
catch (...)
{ {
Console.Error("Failed to parse ELF '%s'", path.c_str()); Console.Error("Failed to parse ELF '%s'", path.c_str());
return false; return false;
@ -201,9 +193,10 @@ bool GameList::GetElfListEntry(const std::string& path, GameList::Entry* entry)
entry->serial.clear(); entry->serial.clear();
entry->title = Path::GetFileTitle(FileSystem::GetDisplayNameFromPath(path)); entry->title = Path::GetFileTitle(FileSystem::GetDisplayNameFromPath(path));
entry->region = Region::Other; entry->region = Region::Other;
entry->total_size = static_cast<u64>(file_size);
entry->type = EntryType::ELF; entry->type = EntryType::ELF;
entry->compatibility_rating = CompatibilityRating::Unknown; entry->compatibility_rating = CompatibilityRating::Unknown;
entry->crc = eo.GetCRC();
entry->total_size = eo.GetSize();
std::string disc_path(VMManager::GetDiscOverrideFromGameSettings(path)); std::string disc_path(VMManager::GetDiscOverrideFromGameSettings(path));
if (!disc_path.empty()) if (!disc_path.empty())

View File

@ -589,7 +589,12 @@ std::string VMManager::GetGameSettingsPath(const std::string_view& game_serial,
std::string VMManager::GetDiscOverrideFromGameSettings(const std::string& elf_path) std::string VMManager::GetDiscOverrideFromGameSettings(const std::string& elf_path)
{ {
std::string iso_path; std::string iso_path;
if (const u32 crc = cdvdGetElfCRC(elf_path); crc != 0) ElfObject elfo;
if (!elfo.OpenFile(elf_path, false, nullptr))
return iso_path;
const u32 crc = elfo.GetCRC();
if (crc != 0)
{ {
INISettingsInterface si(GetGameSettingsPath(std::string_view(), crc)); INISettingsInterface si(GetGameSettingsPath(std::string_view(), crc));
if (si.Load()) if (si.Load())
@ -941,29 +946,23 @@ void VMManager::HandleELFChange(bool verbose_patches_if_changed)
void VMManager::UpdateELFInfo(std::string elf_path) void VMManager::UpdateELFInfo(std::string elf_path)
{ {
try Error error;
ElfObject elfo;
if (!cdvdLoadElf(&elfo, elf_path, false, &error))
{ {
std::unique_ptr<ElfObject> elfptr = cdvdLoadElf(elf_path, false); Console.Error(fmt::format("Failed to read ELF being loaded: {}: {}", elf_path, error.GetDescription()));
elfptr->loadHeaders(); s_elf_path = {};
s_current_crc = elfptr->getCRC(); s_elf_text_range = {};
s_elf_entry_point = elfptr->getEntryPoint(); s_elf_entry_point = 0xFFFFFFFFu;
s_elf_text_range = elfptr->getTextRange(); s_current_crc = 0;
s_elf_path = std::move(elf_path);
return; return;
} }
catch ([[maybe_unused]] Exception::FileNotFound& e)
{
}
catch (Exception::BadStream& ex)
{
Console.Error(ex.FormatDiagnosticMessage());
}
Console.Error(fmt::format("Failed to read ELF being loaded: {}", elf_path)); elfo.LoadHeaders();
s_elf_path = {}; s_current_crc = elfo.GetCRC();
s_elf_text_range = {}; s_elf_entry_point = elfo.GetEntryPoint();
s_elf_entry_point = 0xFFFFFFFFu; s_elf_text_range = elfo.GetTextRange();
s_current_crc = 0; s_elf_path = std::move(elf_path);
} }
void VMManager::ClearELFInfo() void VMManager::ClearELFInfo()