Postmortem debug target now loads/scans the trace and inits the filesystem.

This commit is contained in:
Ben Vanik
2014-08-15 10:19:59 -07:00
parent 4768f2fc0b
commit 3de39aaf10
27 changed files with 541 additions and 255 deletions

View File

@@ -9,8 +9,7 @@
#include <xenia/debug_agent.h>
#include <codecvt>
#include <poly/string.h>
#include <gflags/gflags.h>
DEFINE_string(trace_file, "", "Trace to the given file.");
@@ -45,8 +44,7 @@ int DebugAgent::Initialize() {
}
int DebugAgent::SetupTracing(const std::string& trace_file, uint64_t capacity) {
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> cvt;
auto file_path = cvt.from_bytes(trace_file);
auto file_path = poly::to_wstring(trace_file);
file_ = CreateFile(file_path.c_str(), GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_TEMPORARY,

View File

@@ -9,6 +9,7 @@
#include <xenia/emulator.h>
#include <poly/poly.h>
#include <xdb/protocol.h>
#include <xenia/apu/apu.h>
#include <xenia/cpu/cpu.h>
@@ -149,7 +150,7 @@ void Emulator::set_main_window(Window* window) {
});
}
X_STATUS Emulator::LaunchXexFile(const xechar_t* path) {
X_STATUS Emulator::LaunchXexFile(const std::wstring& path) {
// We create a virtual filesystem pointing to its directory and symlink
// that to the game filesystem.
// e.g., /my/files/foo.xex will get a local fs at:
@@ -157,111 +158,60 @@ X_STATUS Emulator::LaunchXexFile(const xechar_t* path) {
// and then get that symlinked to game:\, so
// -> game:\foo.xex
auto ev = xdb::protocol::ProcessStartEvent::Append(memory()->trace_base());
if (ev) {
ev->type = xdb::protocol::EventType::PROCESS_START;
int result_code =
file_system_->InitializeFromPath(FileSystemType::XEX_FILE, path);
if (result_code) {
return X_STATUS_INVALID_PARAMETER;
}
int result_code = 0;
// Get just the filename (foo.xex).
const xechar_t* file_name = xestrrchr(path, poly::path_separator);
if (file_name) {
// Skip slash.
file_name++;
} else {
std::wstring file_name;
auto last_slash = path.find_last_of(poly::path_separator);
if (last_slash == std::string::npos) {
// No slash found, whole thing is a file.
file_name = path;
} else {
// Skip slash.
file_name = path.substr(last_slash + 1);
}
// Get the parent path of the file.
xechar_t parent_path[poly::max_path];
XEIGNORE(xestrcpy(parent_path, XECOUNT(parent_path), path));
parent_path[file_name - path] = 0;
// Register the local directory in the virtual filesystem.
result_code = file_system_->RegisterHostPathDevice(
"\\Device\\Harddisk1\\Partition0", parent_path);
if (result_code) {
XELOGE("Unable to mount local directory");
return result_code;
}
// Create symlinks to the device.
file_system_->CreateSymbolicLink(
"game:", "\\Device\\Harddisk1\\Partition0");
file_system_->CreateSymbolicLink(
"d:", "\\Device\\Harddisk1\\Partition0");
// Get the file name of the module to load from the filesystem.
char fs_path[poly::max_path];
XEIGNORE(xestrcpya(fs_path, XECOUNT(fs_path), "game:\\"));
char* fs_path_ptr = fs_path + xestrlena(fs_path);
*fs_path_ptr = 0;
#if XE_WCHAR
XEIGNORE(xestrnarrow(fs_path_ptr, XECOUNT(fs_path), file_name));
#else
XEIGNORE(xestrcpya(fs_path_ptr, XECOUNT(fs_path), file_name));
#endif
// Launch the game.
return xboxkrnl_->LaunchModule(fs_path);
std::string fs_path = "game:\\" + poly::to_string(file_name);
return CompleteLaunch(path, fs_path);
}
X_STATUS Emulator::LaunchDiscImage(const xechar_t* path) {
int result_code = 0;
X_STATUS Emulator::LaunchDiscImage(const std::wstring& path) {
int result_code =
file_system_->InitializeFromPath(FileSystemType::DISC_IMAGE, path);
if (result_code) {
return X_STATUS_INVALID_PARAMETER;
}
// Launch the game.
return CompleteLaunch(path, "game:\\default.xex");
}
X_STATUS Emulator::LaunchSTFSTitle(const std::wstring& path) {
int result_code =
file_system_->InitializeFromPath(FileSystemType::STFS_TITLE, path);
if (result_code) {
return X_STATUS_INVALID_PARAMETER;
}
// Launch the game.
return CompleteLaunch(path, "game:\\default.xex");
}
X_STATUS Emulator::CompleteLaunch(const std::wstring& path,
const std::string& module_path) {
auto ev = xdb::protocol::ProcessStartEvent::Append(memory()->trace_base());
if (ev) {
ev->type = xdb::protocol::EventType::PROCESS_START;
ev->membase = reinterpret_cast<uint64_t>(memory()->membase());
auto path_length = poly::to_string(path)
.copy(ev->launch_path, sizeof(ev->launch_path) - 1);
ev->launch_path[path_length] = 0;
}
// Register the disc image in the virtual filesystem.
result_code = file_system_->RegisterDiscImageDevice(
"\\Device\\Cdrom0", path);
if (result_code) {
XELOGE("Unable to mount disc image");
return result_code;
}
// Create symlinks to the device.
file_system_->CreateSymbolicLink(
"game:",
"\\Device\\Cdrom0");
file_system_->CreateSymbolicLink(
"d:",
"\\Device\\Cdrom0");
// Launch the game.
return xboxkrnl_->LaunchModule("game:\\default.xex");
}
X_STATUS Emulator::LaunchSTFSTitle(const xechar_t* path) {
int result_code = 0;
auto ev = xdb::protocol::ProcessStartEvent::Append(memory()->trace_base());
if (ev) {
ev->type = xdb::protocol::EventType::PROCESS_START;
}
// TODO(benvanik): figure out paths.
// Register the disc image in the virtual filesystem.
result_code = file_system_->RegisterSTFSContainerDevice(
"\\Device\\Cdrom0", path);
if (result_code) {
XELOGE("Unable to mount STFS container");
return result_code;
}
// Create symlinks to the device.
file_system_->CreateSymbolicLink(
"game:",
"\\Device\\Cdrom0");
file_system_->CreateSymbolicLink(
"d:",
"\\Device\\Cdrom0");
// Launch the game.
return xboxkrnl_->LaunchModule("game:\\default.xex");
return xboxkrnl_->LaunchModule(module_path.c_str());
}

View File

@@ -10,6 +10,8 @@
#ifndef XENIA_EMULATOR_H_
#define XENIA_EMULATOR_H_
#include <string>
#include <xenia/common.h>
#include <xenia/core.h>
#include <xenia/debug_agent.h>
@@ -32,7 +34,7 @@ XEDECLARECLASS2(xe, ui, Window);
namespace xe {
class Emulator {
public:
public:
Emulator(const xechar_t* command_line);
~Emulator();
@@ -59,11 +61,14 @@ public:
X_STATUS Setup();
// TODO(benvanik): raw binary.
X_STATUS LaunchXexFile(const xechar_t* path);
X_STATUS LaunchDiscImage(const xechar_t* path);
X_STATUS LaunchSTFSTitle(const xechar_t* path);
X_STATUS LaunchXexFile(const std::wstring& path);
X_STATUS LaunchDiscImage(const std::wstring& path);
X_STATUS LaunchSTFSTitle(const std::wstring& path);
private:
X_STATUS CompleteLaunch(const std::wstring& path,
const std::string& module_path);
private:
xechar_t command_line_[poly::max_path];
ui::Window* main_window_;

View File

@@ -9,20 +9,12 @@
#include <xenia/kernel/fs/device.h>
using namespace xe;
using namespace xe::kernel;
using namespace xe::kernel::fs;
Device::Device(const std::string& path) : path_(path) {}
Device::Device(const char* path) {
path_ = xestrdupa(path);
}
Device::~Device() {}
Device::~Device() {
xe_free(path_);
}
const char* Device::path() {
return path_;
}
const char* Device::path() const { return path_.c_str(); }

View File

@@ -10,37 +10,36 @@
#ifndef XENIA_KERNEL_FS_DEVICE_H_
#define XENIA_KERNEL_FS_DEVICE_H_
#include <string>
#include <xenia/common.h>
#include <xenia/core.h>
#include <xenia/kernel/fs/entry.h>
namespace xe {
namespace kernel {
namespace fs {
class Device {
public:
Device(const char* path);
public:
Device(const std::string& path);
virtual ~Device();
const char* path();
const char* path() const;
virtual Entry* ResolvePath(const char* path) = 0;
virtual X_STATUS QueryVolume(XVolumeInfo* out_info, size_t length) = 0;
virtual X_STATUS QueryFileSystemAttributes(XFileSystemAttributeInfo* out_info, size_t length) = 0;
virtual X_STATUS QueryFileSystemAttributes(XFileSystemAttributeInfo* out_info,
size_t length) = 0;
protected:
char* path_;
protected:
std::string path_;
};
} // namespace fs
} // namespace kernel
} // namespace xe
#endif // XENIA_KERNEL_FS_DEVICE_H_

View File

@@ -17,23 +17,17 @@ using namespace xe;
using namespace xe::kernel;
using namespace xe::kernel::fs;
DiscImageDevice::DiscImageDevice(const char* path, const xechar_t* local_path) :
Device(path) {
local_path_ = xestrdup(local_path);
mmap_ = NULL;
gdfx_ = NULL;
}
DiscImageDevice::DiscImageDevice(const std::string& path,
const std::wstring& local_path)
: Device(path), local_path_(local_path), mmap_(nullptr), gdfx_(nullptr) {}
DiscImageDevice::~DiscImageDevice() {
delete gdfx_;
xe_mmap_release(mmap_);
xe_free(local_path_);
}
int DiscImageDevice::Init() {
mmap_ = xe_mmap_open(kXEFileModeRead, local_path_, 0, 0);
mmap_ = xe_mmap_open(kXEFileModeRead, local_path_.c_str(), 0, 0);
if (!mmap_) {
XELOGE("Disc image could not be mapped");
return 1;

View File

@@ -10,42 +10,40 @@
#ifndef XENIA_KERNEL_FS_DEVICES_DISC_IMAGE_DEVICE_H_
#define XENIA_KERNEL_FS_DEVICES_DISC_IMAGE_DEVICE_H_
#include <string>
#include <xenia/common.h>
#include <xenia/core.h>
#include <xenia/kernel/fs/device.h>
namespace xe {
namespace kernel {
namespace fs {
class GDFX;
class DiscImageDevice : public Device {
public:
DiscImageDevice(const char* path, const xechar_t* local_path);
virtual ~DiscImageDevice();
public:
DiscImageDevice(const std::string& path, const std::wstring& local_path);
~DiscImageDevice() override;
int Init();
virtual Entry* ResolvePath(const char* path);
Entry* ResolvePath(const char* path) override;
virtual X_STATUS QueryVolume(XVolumeInfo* out_info, size_t length);
virtual X_STATUS QueryFileSystemAttributes(XFileSystemAttributeInfo* out_info, size_t length);
X_STATUS QueryVolume(XVolumeInfo* out_info, size_t length) override;
X_STATUS QueryFileSystemAttributes(XFileSystemAttributeInfo* out_info,
size_t length) override;
private:
xechar_t* local_path_;
private:
std::wstring local_path_;
xe_mmap_ref mmap_;
GDFX* gdfx_;
GDFX* gdfx_;
};
} // namespace fs
} // namespace kernel
} // namespace xe
#endif // XENIA_KERNEL_FS_DEVICES_DISC_IMAGE_DEVICE_H_

View File

@@ -17,15 +17,11 @@ using namespace xe;
using namespace xe::kernel;
using namespace xe::kernel::fs;
HostPathDevice::HostPathDevice(const std::string& path,
const std::wstring& local_path)
: Device(path), local_path_(local_path) {}
HostPathDevice::HostPathDevice(const char* path, const xechar_t* local_path) :
Device(path) {
local_path_ = xestrdup(local_path);
}
HostPathDevice::~HostPathDevice() {
xe_free(local_path_);
}
HostPathDevice::~HostPathDevice() {}
Entry* HostPathDevice::ResolvePath(const char* path) {
// The filesystem will have stripped our prefix off already, so the path will
@@ -42,7 +38,7 @@ Entry* HostPathDevice::ResolvePath(const char* path) {
#endif
xechar_t full_path[poly::max_path];
xe_path_join(local_path_, rel_path, full_path, XECOUNT(full_path));
xe_path_join(local_path_.c_str(), rel_path, full_path, XECOUNT(full_path));
// Swap around path separators.
if (poly::path_separator != '\\') {

View File

@@ -10,35 +10,34 @@
#ifndef XENIA_KERNEL_FS_DEVICES_HOST_PATH_DEVICE_H_
#define XENIA_KERNEL_FS_DEVICES_HOST_PATH_DEVICE_H_
#include <string>
#include <xenia/common.h>
#include <xenia/core.h>
#include <xenia/kernel/fs/device.h>
namespace xe {
namespace kernel {
namespace fs {
class HostPathDevice : public Device {
public:
HostPathDevice(const char* path, const xechar_t* local_path);
virtual ~HostPathDevice();
public:
HostPathDevice(const std::string& path, const std::wstring& local_path);
~HostPathDevice() override;
virtual Entry* ResolvePath(const char* path);
Entry* ResolvePath(const char* path) override;
virtual X_STATUS QueryVolume(XVolumeInfo* out_info, size_t length);
virtual X_STATUS QueryFileSystemAttributes(XFileSystemAttributeInfo* out_info, size_t length);
X_STATUS QueryVolume(XVolumeInfo* out_info, size_t length) override;
X_STATUS QueryFileSystemAttributes(XFileSystemAttributeInfo* out_info,
size_t length) override;
private:
xechar_t* local_path_;
private:
std::wstring local_path_;
};
} // namespace fs
} // namespace kernel
} // namespace xe
#endif // XENIA_KERNEL_FS_DEVICES_HOST_PATH_DEVICE_H_

View File

@@ -17,24 +17,17 @@ using namespace xe;
using namespace xe::kernel;
using namespace xe::kernel::fs;
STFSContainerDevice::STFSContainerDevice(
const char* path, const xechar_t* local_path) :
Device(path) {
local_path_ = xestrdup(local_path);
mmap_ = NULL;
stfs_ = NULL;
}
STFSContainerDevice::STFSContainerDevice(const std::string& path,
const std::wstring& local_path)
: Device(path), local_path_(local_path), mmap_(nullptr), stfs_(nullptr) {}
STFSContainerDevice::~STFSContainerDevice() {
delete stfs_;
xe_mmap_release(mmap_);
xe_free(local_path_);
}
int STFSContainerDevice::Init() {
mmap_ = xe_mmap_open(kXEFileModeRead, local_path_, 0, 0);
mmap_ = xe_mmap_open(kXEFileModeRead, local_path_.c_str(), 0, 0);
if (!mmap_) {
XELOGE("STFS container could not be mapped");
return 1;

View File

@@ -10,42 +10,40 @@
#ifndef XENIA_KERNEL_FS_DEVICES_STFS_CONTAINER_DEVICE_H_
#define XENIA_KERNEL_FS_DEVICES_STFS_CONTAINER_DEVICE_H_
#include <string>
#include <xenia/common.h>
#include <xenia/core.h>
#include <xenia/kernel/fs/device.h>
namespace xe {
namespace kernel {
namespace fs {
class STFS;
class STFSContainerDevice : public Device {
public:
STFSContainerDevice(const char* path, const xechar_t* local_path);
virtual ~STFSContainerDevice();
public:
STFSContainerDevice(const std::string& path, const std::wstring& local_path);
~STFSContainerDevice() override;
int Init();
virtual Entry* ResolvePath(const char* path);
Entry* ResolvePath(const char* path) override;
virtual X_STATUS QueryVolume(XVolumeInfo* out_info, size_t length);
virtual X_STATUS QueryFileSystemAttributes(XFileSystemAttributeInfo* out_info, size_t length);
X_STATUS QueryVolume(XVolumeInfo* out_info, size_t length) override;
X_STATUS QueryFileSystemAttributes(XFileSystemAttributeInfo* out_info,
size_t length) override;
private:
xechar_t* local_path_;
private:
std::wstring local_path_;
xe_mmap_ref mmap_;
STFS* stfs_;
STFS* stfs_;
};
} // namespace fs
} // namespace kernel
} // namespace xe
#endif // XENIA_KERNEL_FS_DEVICES_STFS_CONTAINER_DEVICE_H_

View File

@@ -33,19 +33,86 @@ FileSystem::~FileSystem() {
symlinks_.clear();
}
int FileSystem::RegisterDevice(const char* path, Device* device) {
fs::FileSystemType FileSystem::InferType(const std::wstring& local_path) {
auto last_dot = local_path.find_last_of('.');
if (last_dot == std::wstring::npos) {
// Likely an STFS container.
return FileSystemType::STFS_TITLE;
} else if (local_path.substr(last_dot) == L".xex") {
// Treat as a naked xex file.
return FileSystemType::XEX_FILE;
} else {
// Assume a disc image.
return FileSystemType::DISC_IMAGE;
}
}
int FileSystem::InitializeFromPath(fs::FileSystemType type,
const std::wstring& local_path) {
switch (type) {
case FileSystemType::STFS_TITLE: {
// Register the container in the virtual filesystem.
int result_code =
RegisterSTFSContainerDevice("\\Device\\Cdrom0", local_path);
if (result_code) {
XELOGE("Unable to mount STFS container");
return result_code;
}
// TODO(benvanik): figure out paths.
// Create symlinks to the device.
CreateSymbolicLink("game:", "\\Device\\Cdrom0");
CreateSymbolicLink("d:", "\\Device\\Cdrom0");
break;
}
case FileSystemType::XEX_FILE: {
// Get the parent path of the file.
auto last_slash = local_path.find_last_of(poly::path_separator);
std::wstring parent_path = local_path.substr(0, last_slash);
// Register the local directory in the virtual filesystem.
int result_code = RegisterHostPathDevice(
"\\Device\\Harddisk1\\Partition0", parent_path);
if (result_code) {
XELOGE("Unable to mount local directory");
return result_code;
}
// Create symlinks to the device.
CreateSymbolicLink("game:", "\\Device\\Harddisk1\\Partition0");
CreateSymbolicLink("d:", "\\Device\\Harddisk1\\Partition0");
break;
}
case FileSystemType::DISC_IMAGE: {
// Register the disc image in the virtual filesystem.
int result_code = RegisterDiscImageDevice("\\Device\\Cdrom0", local_path);
if (result_code) {
XELOGE("Unable to mount disc image");
return result_code;
}
// Create symlinks to the device.
CreateSymbolicLink("game:", "\\Device\\Cdrom0");
CreateSymbolicLink("d:", "\\Device\\Cdrom0");
break;
}
}
return 0;
}
int FileSystem::RegisterDevice(const std::string& path, Device* device) {
devices_.push_back(device);
return 0;
}
int FileSystem::RegisterHostPathDevice(
const char* path, const xechar_t* local_path) {
const std::string& path, const std::wstring& local_path) {
Device* device = new HostPathDevice(path, local_path);
return RegisterDevice(path, device);
}
int FileSystem::RegisterDiscImageDevice(
const char* path, const xechar_t* local_path) {
const std::string& path, const std::wstring& local_path) {
DiscImageDevice* device = new DiscImageDevice(path, local_path);
if (device->Init()) {
return 1;
@@ -54,7 +121,7 @@ int FileSystem::RegisterDiscImageDevice(
}
int FileSystem::RegisterSTFSContainerDevice(
const char* path, const xechar_t* local_path) {
const std::string& path, const std::wstring& local_path) {
STFSContainerDevice* device = new STFSContainerDevice(path, local_path);
if (device->Init()) {
return 1;

View File

@@ -10,6 +10,7 @@
#ifndef XENIA_KERNEL_FS_FILESYSTEM_H_
#define XENIA_KERNEL_FS_FILESYSTEM_H_
#include <string>
#include <unordered_map>
#include <vector>
@@ -18,39 +19,46 @@
#include <xenia/kernel/fs/entry.h>
namespace xe {
namespace kernel {
namespace fs {
class Device;
enum class FileSystemType {
STFS_TITLE,
DISC_IMAGE,
XEX_FILE,
};
class FileSystem {
public:
public:
FileSystem();
~FileSystem();
int RegisterDevice(const char* path, Device* device);
int RegisterHostPathDevice(const char* path, const xechar_t* local_path);
int RegisterDiscImageDevice(const char* path, const xechar_t* local_path);
int RegisterSTFSContainerDevice(const char* path, const xechar_t* local_path);
FileSystemType InferType(const std::wstring& local_path);
int InitializeFromPath(FileSystemType type, const std::wstring& local_path);
int RegisterDevice(const std::string& path, Device* device);
int RegisterHostPathDevice(const std::string& path,
const std::wstring& local_path);
int RegisterDiscImageDevice(const std::string& path,
const std::wstring& local_path);
int RegisterSTFSContainerDevice(const std::string& path,
const std::wstring& local_path);
int CreateSymbolicLink(const char* path, const char* target);
int DeleteSymbolicLink(const char* path);
Entry* ResolvePath(const char* path);
private:
std::vector<Device*> devices_;
private:
std::vector<Device*> devices_;
std::unordered_map<std::string, std::string> symlinks_;
};
} // namespace fs
} // namespace kernel
} // namespace xe
#endif // XENIA_KERNEL_FS_FILESYSTEM_H_

View File

@@ -9,9 +9,7 @@
#include <xenia/kernel/xboxkrnl_rtl.h>
#include <locale>
#include <codecvt>
#include <poly/string.h>
#include <xenia/kernel/kernel_state.h>
#include <xenia/kernel/xboxkrnl_private.h>
#include <xenia/kernel/objects/xthread.h>
@@ -329,8 +327,7 @@ X_STATUS xeRtlUnicodeStringToAnsiString(uint32_t destination_ptr,
std::wstring unicode_str = poly::load_and_swap<std::wstring>(
IMPL_MEM_ADDR(IMPL_MEM_32(source_ptr + 4)));
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
std::string ansi_str = converter.to_bytes(unicode_str);
std::string ansi_str = poly::to_string(unicode_str);
if (ansi_str.size() > 0xFFFF - 1) {
return X_STATUS_INVALID_PARAMETER_2;
}