GE Debugger: Simple framework to load dumps.

This tries to execute them within the context of the emulator as much as
possible, so we don't have weird bugs.  Going with a file type so we can
easily load the dump by opening the file directly.
This commit is contained in:
Unknown W. Brackets 2017-06-03 12:47:38 -07:00
parent 37a894a558
commit 36069d1446
18 changed files with 363 additions and 48 deletions

View File

@ -1348,6 +1348,8 @@ add_library(${CoreLibName} ${CoreLinkType}
Core/ELF/ParamSFO.cpp
Core/ELF/ParamSFO.h
Core/FileSystems/tlzrc.cpp
Core/FileSystems/BlobFileSystem.cpp
Core/FileSystems/BlobFileSystem.h
Core/FileSystems/BlockDevices.cpp
Core/FileSystems/BlockDevices.h
Core/FileSystems/DirectoryFileSystem.cpp

View File

@ -21,7 +21,8 @@
<PropertyGroup Label="Globals">
<ProjectGuid>{533F1D30-D04D-47CC-AD71-20F658907E36}</ProjectGuid>
<RootNamespace>Core</RootNamespace>
<WindowsTargetPlatformVersion></WindowsTargetPlatformVersion>
<WindowsTargetPlatformVersion>
</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
@ -183,6 +184,7 @@
<ClCompile Include="..\ext\udis86\syn.c" />
<ClCompile Include="..\ext\udis86\udis86.c" />
<ClCompile Include="AVIDump.cpp" />
<ClCompile Include="FileSystems\BlobFileSystem.cpp" />
<ClCompile Include="HLE\KUBridge.cpp" />
<ClCompile Include="MIPS\IR\IRAsm.cpp" />
<ClCompile Include="MIPS\IR\IRCompALU.cpp" />
@ -524,6 +526,7 @@
<ClInclude Include="..\ext\udis86\udint.h" />
<ClInclude Include="..\ext\udis86\udis86.h" />
<ClInclude Include="AVIDump.h" />
<ClInclude Include="FileSystems\BlobFileSystem.h" />
<ClInclude Include="HLE\KUBridge.h" />
<ClInclude Include="MIPS\IR\IRFrontend.h" />
<ClInclude Include="MIPS\IR\IRInst.h" />

View File

@ -680,6 +680,9 @@
<ClCompile Include="HLE\KUBridge.cpp">
<Filter>HLE\Libraries</Filter>
</ClCompile>
<ClCompile Include="FileSystems\BlobFileSystem.cpp">
<Filter>FileSystems</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="ELF\ElfReader.h">
@ -1250,10 +1253,13 @@
<ClInclude Include="HLE\KUBridge.h">
<Filter>HLE\Libraries</Filter>
</ClInclude>
<ClInclude Include="FileSystems\BlobFileSystem.h">
<Filter>FileSystems</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="CMakeLists.txt" />
<None Include="..\LICENSE.TXT" />
<None Include="..\android\jni\Android.mk" />
</ItemGroup>
</Project>
</Project>

View File

@ -0,0 +1,137 @@
// Copyright (c) 2017- PPSSPP Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0 or later versions.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#include "Core/FileSystems/BlobFileSystem.h"
BlobFileSystem::BlobFileSystem(IHandleAllocator *hAlloc, FileLoader *fileLoader, std::string alias)
: alloc_(hAlloc), fileLoader_(fileLoader), alias_(alias) {
}
BlobFileSystem::~BlobFileSystem() {
// TODO: Who deletes fileLoader?
}
void BlobFileSystem::DoState(PointerWrap &p) {
// Not used in real emulation.
}
std::vector<PSPFileInfo> BlobFileSystem::GetDirListing(std::string path) {
std::vector<PSPFileInfo> listing;
listing.push_back(GetFileInfo(alias_));
return listing;
}
u32 BlobFileSystem::OpenFile(std::string filename, FileAccess access, const char *devicename) {
u32 newHandle = alloc_->GetNewHandle();
entries_[newHandle] = 0;
return newHandle;
}
void BlobFileSystem::CloseFile(u32 handle) {
alloc_->FreeHandle(handle);
entries_.erase(handle);
}
size_t BlobFileSystem::ReadFile(u32 handle, u8 *pointer, s64 size) {
auto entry = entries_.find(handle);
if (entry != entries_.end()) {
size_t readSize = fileLoader_->ReadAt(entry->second, size, pointer);
entry->second += readSize;
return readSize;
}
return 0;
}
size_t BlobFileSystem::ReadFile(u32 handle, u8 *pointer, s64 size, int &usec) {
usec = 0;
return ReadFile(handle, pointer, size);
}
size_t BlobFileSystem::WriteFile(u32 handle, const u8 *pointer, s64 size) {
return 0;
}
size_t BlobFileSystem::WriteFile(u32 handle, const u8 *pointer, s64 size, int &usec) {
return 0;
}
size_t BlobFileSystem::SeekFile(u32 handle, s32 position, FileMove type) {
auto entry = entries_.find(handle);
if (entry != entries_.end()) {
switch (type) {
case FILEMOVE_BEGIN:
entry->second = position;
break;
case FILEMOVE_CURRENT:
entry->second += position;
break;
case FILEMOVE_END:
entry->second = fileLoader_->FileSize() + position;
break;
}
return (size_t)entry->second;
}
return 0;
}
PSPFileInfo BlobFileSystem::GetFileInfo(std::string filename) {
PSPFileInfo info{};
info.name = alias_;
info.size = fileLoader_->FileSize();
info.access = 0666;
info.exists = true;
info.type = FILETYPE_NORMAL;
return info;
}
bool BlobFileSystem::OwnsHandle(u32 handle) {
auto entry = entries_.find(handle);
return entry != entries_.end();
}
int BlobFileSystem::Ioctl(u32 handle, u32 cmd, u32 indataPtr, u32 inlen, u32 outdataPtr, u32 outlen, int &usec) {
return -1;
}
int BlobFileSystem::DevType(u32 handle) {
return -1;
}
bool BlobFileSystem::MkDir(const std::string &dirname) {
return false;
}
bool BlobFileSystem::RmDir(const std::string &dirname) {
return false;
}
int BlobFileSystem::RenameFile(const std::string &from, const std::string &to) {
return -1;
}
bool BlobFileSystem::RemoveFile(const std::string &filename) {
return false;
}
bool BlobFileSystem::GetHostPath(const std::string &inpath, std::string &outpath) {
outpath = fileLoader_->Path();
return true;
}
u64 BlobFileSystem::FreeSpace(const std::string &path) {
return 0;
}

View File

@ -0,0 +1,61 @@
// Copyright (c) 2017- PPSSPP Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0 or later versions.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#pragma once
// This is used for opening a debug file as a blob, and mounting it.
#include <map>
#include <string>
#include "Core/Loaders.h"
#include "Core/FileSystems/FileSystem.h"
class BlobFileSystem : public IFileSystem {
public:
BlobFileSystem(IHandleAllocator *hAlloc, FileLoader *fileLoader, std::string alias);
~BlobFileSystem();
void DoState(PointerWrap &p) override;
std::vector<PSPFileInfo> GetDirListing(std::string path) override;
u32 OpenFile(std::string filename, FileAccess access, const char *devicename = nullptr) override;
void CloseFile(u32 handle) override;
size_t ReadFile(u32 handle, u8 *pointer, s64 size) override;
size_t ReadFile(u32 handle, u8 *pointer, s64 size, int &usec) override;
size_t WriteFile(u32 handle, const u8 *pointer, s64 size) override;
size_t WriteFile(u32 handle, const u8 *pointer, s64 size, int &usec) override;
size_t SeekFile(u32 handle, s32 position, FileMove type) override;
PSPFileInfo GetFileInfo(std::string filename) override;
bool OwnsHandle(u32 handle) override;
int Ioctl(u32 handle, u32 cmd, u32 indataPtr, u32 inlen, u32 outdataPtr, u32 outlen, int &usec) override;
int DevType(u32 handle) override;
int Flags() override { return 0; }
bool MkDir(const std::string &dirname) override;
bool RmDir(const std::string &dirname) override;
int RenameFile(const std::string &from, const std::string &to) override;
bool RemoveFile(const std::string &filename) override;
bool GetHostPath(const std::string &inpath, std::string &outpath) override;
u64 FreeSpace(const std::string &path) override;
private:
// File positions.
std::map<u32, s64> entries_;
IHandleAllocator *alloc_;
FileLoader *fileLoader_;
std::string alias_;
};

View File

@ -92,6 +92,7 @@ const HLEFunction FakeSysCalls[] = {
{NID_EXTENDRETURN, __KernelReturnFromExtendStack, "__KernelReturnFromExtendStack"},
{NID_MODULERETURN, __KernelReturnFromModuleFunc, "__KernelReturnFromModuleFunc"},
{NID_IDLE, __KernelIdle, "_sceKernelIdle"},
{NID_GPUREPLAY, __KernelGPUReplay, "__KernelGPUReplay"},
};
const HLEFunction UtilsForUser[] =

View File

@ -23,5 +23,6 @@
#define NID_EXTENDRETURN 0xbad0b0c9
#define NID_MODULERETURN 0xbad0d318
#define NID_IDLE 0x1d7e1d7e
#define NID_GPUREPLAY 0x9e45bd95
void RegisterAllModules();

View File

@ -24,6 +24,7 @@
#include "Common/FileUtil.h"
#include "Common/StringUtils.h"
#include "Core/Config.h"
#include "Core/Core.h"
#include "Core/HLE/HLE.h"
#include "Core/HLE/FunctionWrappers.h"
#include "Core/HLE/HLETables.h"
@ -57,6 +58,7 @@
#include "Core/HLE/KernelWaitHelpers.h"
#include "Core/ELF/ParamSFO.h"
#include "GPU/Debugger/Record.h"
#include "GPU/GPU.h"
#include "GPU/GPUInterface.h"
#include "GPU/GPUState.h"
@ -1513,8 +1515,36 @@ u32 __KernelGetModuleGP(SceUID uid)
}
}
bool __KernelLoadExec(const char *filename, u32 paramPtr, std::string *error_string)
{
void __KernelLoadReset() {
// Wipe kernel here, loadexec should reset the entire system
if (__KernelIsRunning()) {
u32 error;
while (!loadedModules.empty()) {
SceUID moduleID = *loadedModules.begin();
Module *module = kernelObjects.Get<Module>(moduleID, error);
if (module) {
module->Cleanup();
} else {
// An invalid module. We need to remove it or we'll loop forever.
WARN_LOG(LOADER, "Invalid module still marked as loaded on loadexec");
loadedModules.erase(moduleID);
}
}
Replacement_Shutdown();
__KernelShutdown();
// HLE needs to be reset here
HLEShutdown();
Replacement_Init();
HLEInit();
gpu->Reinitialize();
}
__KernelModuleInit();
__KernelInit();
}
bool __KernelLoadExec(const char *filename, u32 paramPtr, std::string *error_string) {
SceKernelLoadExecParam param;
if (paramPtr)
@ -1536,33 +1566,7 @@ bool __KernelLoadExec(const char *filename, u32 paramPtr, std::string *error_str
Memory::Memcpy(param_key, keyAddr, (u32)keylen);
}
// Wipe kernel here, loadexec should reset the entire system
if (__KernelIsRunning())
{
u32 error;
while (!loadedModules.empty()) {
SceUID moduleID = *loadedModules.begin();
Module *module = kernelObjects.Get<Module>(moduleID, error);
if (module) {
module->Cleanup();
} else {
// An invalid module. We need to remove it or we'll loop forever.
WARN_LOG(LOADER, "Invalid module still marked as loaded on loadexec");
loadedModules.erase(moduleID);
}
}
Replacement_Shutdown();
__KernelShutdown();
//HLE needs to be reset here
HLEShutdown();
Replacement_Init();
HLEInit();
gpu->Reinitialize();
}
__KernelModuleInit();
__KernelInit();
__KernelLoadReset();
PSPFileInfo info = pspFileSystem.GetFileInfo(filename);
if (!info.exists) {
@ -1635,6 +1639,33 @@ bool __KernelLoadExec(const char *filename, u32 paramPtr, std::string *error_str
return true;
}
bool __KernelLoadGEDump(std::string *error_string) {
__KernelLoadReset();
mipsr4k.pc = PSP_GetUserMemoryBase();
const static u32_le runDumpCode[] = {
MIPS_MAKE_LUI(MIPS_REG_RA, mipsr4k.pc >> 16),
MIPS_MAKE_JR_RA(),
MIPS_MAKE_SYSCALL("FakeSysCalls", "__KernelGPUReplay"),
MIPS_MAKE_BREAK(0),
};
for (size_t i = 0; i < ARRAY_SIZE(runDumpCode); ++i) {
Memory::WriteUnchecked_U32(runDumpCode[i], mipsr4k.pc + (int)i * sizeof(u32_le));
}
__KernelStartIdleThreads(0);
return true;
}
void __KernelGPUReplay() {
if (!GPURecord::RunMountedReplay()) {
Core_Stop();
}
hleEatCycles(msToCycles(1001.0f / 60.0f));
}
int sceKernelLoadExec(const char *filename, u32 paramPtr)
{
std::string exec_filename = filename;

View File

@ -39,7 +39,9 @@ void __KernelModuleDoState(PointerWrap &p);
void __KernelModuleShutdown();
u32 __KernelGetModuleGP(SceUID module);
bool __KernelLoadGEDump(std::string *error_string);
bool __KernelLoadExec(const char *filename, u32 paramPtr, std::string *error_string);
void __KernelGPUReplay();
void __KernelReturnFromModuleFunc();
u32 hleKernelStopUnloadSelfModuleWithOrWithoutStatus(u32 exitCode, u32 argSize, u32 argp, u32 statusAddr, u32 optionAddr, bool WithStatus);

View File

@ -69,31 +69,30 @@ IdentifiedFileType Identify_File(FileLoader *fileLoader) {
}
std::string extension = fileLoader->Extension();
if (!strcasecmp(extension.c_str(), ".iso"))
{
if (!strcasecmp(extension.c_str(), ".iso")) {
// may be a psx iso, they have 2352 byte sectors. You never know what some people try to open
if ((fileLoader->FileSize() % 2352) == 0)
{
if ((fileLoader->FileSize() % 2352) == 0) {
unsigned char sync[12];
fileLoader->ReadAt(0, 12, sync);
// each sector in a mode2 image starts with these 12 bytes
if (memcmp(sync,"\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00",12) == 0)
{
if (memcmp(sync,"\x00\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x00", 12) == 0) {
return IdentifiedFileType::ISO_MODE2;
}
// maybe it also just happened to have that size,
}
return IdentifiedFileType::PSP_ISO;
}
else if (!strcasecmp(extension.c_str(),".cso"))
{
} else if (!strcasecmp(extension.c_str(), ".cso")) {
return IdentifiedFileType::PSP_ISO;
}
else if (!strcasecmp(extension.c_str(),".ppst"))
{
} else if (!strcasecmp(extension.c_str(), ".ppst")) {
return IdentifiedFileType::PPSSPP_SAVESTATE;
} else if (!strcasecmp(extension.c_str(), ".ppdmp")) {
char data[8]{};
fileLoader->ReadAt(0, 8, data);
if (memcmp(data, "PPSSPPGE", 8) == 0) {
return IdentifiedFileType::PPSSPP_GE_DUMP;
}
}
// First, check if it's a directory with an EBOOT.PBP in it.
@ -337,6 +336,9 @@ bool LoadFile(FileLoader **fileLoaderPtr, std::string *error_string) {
*error_string = "This is save data, not a game."; // Actually, we could make it load it...
break;
case IdentifiedFileType::PPSSPP_GE_DUMP:
return Load_PSP_GE_Dump(fileLoader, error_string);
case IdentifiedFileType::UNKNOWN_BIN:
case IdentifiedFileType::UNKNOWN_ELF:
case IdentifiedFileType::UNKNOWN:

View File

@ -49,6 +49,8 @@ enum class IdentifiedFileType {
PSP_SAVEDATA_DIRECTORY,
PPSSPP_SAVESTATE,
PPSSPP_GE_DUMP,
UNKNOWN,
};

View File

@ -27,11 +27,12 @@
#include "Core/ELF/ElfReader.h"
#include "Core/ELF/ParamSFO.h"
#include "FileSystems/BlockDevices.h"
#include "FileSystems/DirectoryFileSystem.h"
#include "FileSystems/ISOFileSystem.h"
#include "FileSystems/MetaFileSystem.h"
#include "FileSystems/VirtualDiscFileSystem.h"
#include "Core/FileSystems/BlockDevices.h"
#include "Core/FileSystems/BlobFileSystem.h"
#include "Core/FileSystems/DirectoryFileSystem.h"
#include "Core/FileSystems/ISOFileSystem.h"
#include "Core/FileSystems/MetaFileSystem.h"
#include "Core/FileSystems/VirtualDiscFileSystem.h"
#include "Core/Loaders.h"
#include "Core/MemMap.h"
@ -355,3 +356,11 @@ bool Load_PSP_ELF_PBP(FileLoader *fileLoader, std::string *error_string) {
return __KernelLoadExec(finalName.c_str(), 0, error_string);
}
bool Load_PSP_GE_Dump(FileLoader *fileLoader, std::string *error_string) {
BlobFileSystem *umd = new BlobFileSystem(&pspFileSystem, fileLoader, "data.ppdmp");
pspFileSystem.Mount("disc0:", umd);
__KernelLoadGEDump(error_string);
return true;
}

View File

@ -23,5 +23,6 @@ class FileLoader;
bool Load_PSP_ISO(FileLoader *fileLoader, std::string *error_string);
bool Load_PSP_ELF_PBP(FileLoader *fileLoader, std::string *error_string);
bool Load_PSP_GE_Dump(FileLoader *fileLoader, std::string *error_string);
void InitMemoryForGameISO(FileLoader *fileLoader);
void InitMemoryForGamePBP(FileLoader *fileLoader);

View File

@ -21,7 +21,10 @@
#include "base/stringutil.h"
#include "Common/Common.h"
#include "Common/FileUtil.h"
#include "Common/Log.h"
#include "Core/Core.h"
#include "Core/ELF/ParamSFO.h"
#include "Core/FileSystems/MetaFileSystem.h"
#include "Core/MemMap.h"
#include "Core/System.h"
#include "GPU/GPUState.h"
@ -412,4 +415,47 @@ void NotifyFrame() {
}
}
bool RunMountedReplay() {
_assert_msg_(SYSTEM, !active && !nextFrame, "Cannot run replay while recording.");
u32 fp = pspFileSystem.OpenFile("disc0:/data.ppdmp", FILEACCESS_READ);
u8 header[8]{};
int version = 0;
pspFileSystem.ReadFile(fp, header, sizeof(header));
pspFileSystem.ReadFile(fp, (u8 *)&version, sizeof(version));
if (memcmp(header, HEADER, sizeof(HEADER)) != 0 || version != VERSION) {
ERROR_LOG(SYSTEM, "Invalid GE dump or unsupported version");
return false;
}
int sz = 0;
pspFileSystem.ReadFile(fp, (u8 *)&sz, sizeof(sz));
int bufsz = 0;
pspFileSystem.ReadFile(fp, (u8 *)&bufsz, sizeof(bufsz));
commands.resize(sz);
for (int i = 0; i < sz; ++i) {
size_t read = 0;
read += pspFileSystem.ReadFile(fp, (u8 *)&commands[i].type, sizeof(commands[i].type));
read += pspFileSystem.ReadFile(fp, (u8 *)&commands[i].sz, sizeof(commands[i].sz));
read += pspFileSystem.ReadFile(fp, (u8 *)&commands[i].ptr, sizeof(commands[i].ptr));
if (read != sizeof(commands[i].type) + sizeof(commands[i].sz) + sizeof(commands[i].ptr)) {
ERROR_LOG(SYSTEM, "Truncated GE dump");
return false;
}
}
pushbuf.resize(bufsz);
if (pspFileSystem.ReadFile(fp, pushbuf.data(), bufsz) != bufsz) {
ERROR_LOG(SYSTEM, "Truncated GE dump");
return false;
}
pspFileSystem.CloseFile(fp);
// TODO: Execute commands.
return true;
}
};

View File

@ -29,4 +29,6 @@ void NotifyMemset(u32 dest, int v, u32 sz);
void NotifyUpload(u32 dest, u32 sz);
void NotifyFrame();
bool RunMountedReplay();
};

View File

@ -330,6 +330,7 @@
<ClInclude Include="..\..\Core\FileLoaders\LocalFileLoader.h" />
<ClInclude Include="..\..\Core\FileLoaders\RamCachingFileLoader.h" />
<ClInclude Include="..\..\Core\FileLoaders\RetryingFileLoader.h" />
<ClInclude Include="..\..\Core\FileSystems\BlobFileSystem.h" />
<ClInclude Include="..\..\Core\FileSystems\BlockDevices.h" />
<ClInclude Include="..\..\Core\FileSystems\DirectoryFileSystem.h" />
<ClInclude Include="..\..\Core\FileSystems\FileSystem.h" />
@ -521,6 +522,7 @@
<ClCompile Include="..\..\Core\FileLoaders\LocalFileLoader.cpp" />
<ClCompile Include="..\..\Core\FileLoaders\RamCachingFileLoader.cpp" />
<ClCompile Include="..\..\Core\FileLoaders\RetryingFileLoader.cpp" />
<ClCompile Include="..\..\Core\FileSystems\BlobFileSystem.cpp" />
<ClCompile Include="..\..\Core\FileSystems\BlockDevices.cpp" />
<ClCompile Include="..\..\Core\FileSystems\DirectoryFileSystem.cpp" />
<ClCompile Include="..\..\Core\FileSystems\FileSystem.cpp" />

View File

@ -166,6 +166,9 @@
<ClCompile Include="..\..\Core\MIPS\x86\RegCacheFPU.cpp">
<Filter>MIPS\x86</Filter>
</ClCompile>
<ClCompile Include="..\..\Core\FileSystems\BlobFileSystem.cpp">
<Filter>FileSystems</Filter>
</ClCompile>
<ClCompile Include="..\..\Core\FileSystems\BlockDevices.cpp">
<Filter>FileSystems</Filter>
</ClCompile>
@ -674,6 +677,9 @@
<ClInclude Include="..\..\Core\MIPS\x86\RegCacheFPU.h">
<Filter>MIPS\x86</Filter>
</ClInclude>
<ClInclude Include="..\..\Core\FileSystems\BlobFileSystem.h">
<Filter>FileSystems</Filter>
</ClInclude>
<ClInclude Include="..\..\Core\FileSystems\BlockDevices.h">
<Filter>FileSystems</Filter>
</ClInclude>

View File

@ -364,6 +364,7 @@ EXEC_AND_LIB_FILES := \
$(SRC)/Core/HLE/sceGameUpdate.cpp \
$(SRC)/Core/HLE/sceNp.cpp \
$(SRC)/Core/HLE/scePauth.cpp \
$(SRC)/Core/FileSystems/BlobFileSystem.cpp \
$(SRC)/Core/FileSystems/BlockDevices.cpp \
$(SRC)/Core/FileSystems/ISOFileSystem.cpp \
$(SRC)/Core/FileSystems/FileSystem.cpp \