mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-20 10:56:58 +02:00
Initial commit
This commit is contained in:
@@ -0,0 +1,33 @@
|
||||
#ifndef KYTY_COMMON_PLATFORM_SYSDBG_H_
|
||||
#define KYTY_COMMON_PLATFORM_SYSDBG_H_
|
||||
|
||||
#include "common/common.h"
|
||||
|
||||
// NOLINTNEXTLINE(readability-identifier-naming)
|
||||
struct sys_dbg_stack_info_t {
|
||||
#if KYTY_PLATFORM == KYTY_PLATFORM_WINDOWS
|
||||
uintptr_t addr;
|
||||
|
||||
uintptr_t reserved_addr;
|
||||
size_t reserved_size;
|
||||
uintptr_t guard_addr;
|
||||
size_t guard_size;
|
||||
uintptr_t commited_addr;
|
||||
size_t commited_size;
|
||||
|
||||
size_t total_size;
|
||||
#elif KYTY_PLATFORM == KYTY_PLATFORM_LINUX
|
||||
uintptr_t code_addr;
|
||||
uintptr_t addr;
|
||||
uintptr_t commited_addr;
|
||||
size_t commited_size;
|
||||
size_t total_size;
|
||||
size_t code_size;
|
||||
#endif
|
||||
};
|
||||
|
||||
void SysStackWalk(void** stack, int* depth);
|
||||
void SysStackUsage(sys_dbg_stack_info_t& s); // NOLINT(google-runtime-references)
|
||||
void SysStackUsagePrint(sys_dbg_stack_info_t& stack); // NOLINT(google-runtime-references)
|
||||
|
||||
#endif /* KYTY_COMMON_PLATFORM_SYSDBG_H_ */
|
||||
@@ -0,0 +1,86 @@
|
||||
#ifndef KYTY_COMMON_PLATFORM_SYSFILEIO_H_
|
||||
#define KYTY_COMMON_PLATFORM_SYSFILEIO_H_
|
||||
|
||||
#include "common/common.h"
|
||||
#include "common/platform/sysTimer.h"
|
||||
|
||||
#include <filesystem>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
// The native file representation is private to the platform implementation.
|
||||
struct sys_file_t; // NOLINT(readability-identifier-naming)
|
||||
|
||||
// NOLINTNEXTLINE(readability-identifier-naming)
|
||||
enum sys_file_cache_type_t {
|
||||
SYS_FILE_CACHE_AUTO = 0, // NOLINT(readability-identifier-naming)
|
||||
SYS_FILE_CACHE_RANDOM_ACCESS = 1, // NOLINT(readability-identifier-naming)
|
||||
SYS_FILE_CACHE_SEQUENTIAL_SCAN = 2 // NOLINT(readability-identifier-naming)
|
||||
};
|
||||
|
||||
// NOLINTNEXTLINE(readability-identifier-naming)
|
||||
struct sys_file_find_t {
|
||||
std::filesystem::path path_with_name;
|
||||
SysFileTimeStruct last_access_time;
|
||||
SysFileTimeStruct last_write_time;
|
||||
uint64_t size;
|
||||
};
|
||||
|
||||
// NOLINTNEXTLINE(readability-identifier-naming)
|
||||
struct sys_dir_entry_t {
|
||||
std::string name;
|
||||
bool is_file;
|
||||
};
|
||||
|
||||
void SysFileRead(void* data, uint32_t size, sys_file_t& f,
|
||||
uint32_t* bytes_read = nullptr); // NOLINT(google-runtime-references)
|
||||
void SysFileWrite(const void* data, uint32_t size, sys_file_t& f,
|
||||
uint32_t* bytes_written = nullptr); // NOLINT(google-runtime-references)
|
||||
sys_file_t* SysFileCreate(const std::filesystem::path& file_name);
|
||||
sys_file_t* SysFileOpenR(const std::filesystem::path& file_name,
|
||||
sys_file_cache_type_t cache_type = SYS_FILE_CACHE_AUTO);
|
||||
sys_file_t* SysFileOpenW(const std::filesystem::path& file_name,
|
||||
sys_file_cache_type_t cache_type = SYS_FILE_CACHE_AUTO);
|
||||
sys_file_t* SysFileOpen(uint8_t* buf, uint32_t buf_size);
|
||||
sys_file_t* SysFileCreate();
|
||||
sys_file_t* SysFileOpenRw(const std::filesystem::path& file_name,
|
||||
sys_file_cache_type_t cache_type = SYS_FILE_CACHE_AUTO);
|
||||
void SysFileClose(sys_file_t* f);
|
||||
uint64_t SysFileSize(sys_file_t& f); // NOLINT(google-runtime-references)
|
||||
bool SysFileSeek(sys_file_t& f, uint64_t offset); // NOLINT(google-runtime-references)
|
||||
uint64_t SysFileTell(sys_file_t& f); // NOLINT(google-runtime-references)
|
||||
bool SysFileTruncate(sys_file_t& f, uint64_t size); // NOLINT(google-runtime-references)
|
||||
bool SysFileUnlink(sys_file_t& f,
|
||||
const std::filesystem::path& name); // NOLINT(google-runtime-references)
|
||||
void SysFileWrite(uint32_t n, sys_file_t& f); // NOLINT(google-runtime-references)
|
||||
uint64_t SysFileSize(const std::filesystem::path& file_name);
|
||||
bool SysFileIsError(sys_file_t& f); // NOLINT(google-runtime-references)
|
||||
bool SysFileIsDirectoryExisting(const std::filesystem::path& path);
|
||||
bool SysFileIsFileExisting(const std::filesystem::path& name);
|
||||
bool SysFileCreateDirectory(const std::filesystem::path& path);
|
||||
bool SysFileDeleteDirectory(const std::filesystem::path& path);
|
||||
bool SysFileDeleteFile(const std::filesystem::path& name);
|
||||
bool SysFileFlush(sys_file_t& f); // NOLINT(google-runtime-references)
|
||||
SysFileTimeStruct SysFileGetLastAccessTimeUtc(const std::filesystem::path& name);
|
||||
SysFileTimeStruct SysFileGetLastWriteTimeUtc(const std::filesystem::path& name);
|
||||
// NOLINTNEXTLINE(google-runtime-references)
|
||||
void SysFileGetLastAccessAndWriteTimeUtc(const std::filesystem::path& name, SysFileTimeStruct& a,
|
||||
SysFileTimeStruct& w);
|
||||
// NOLINTNEXTLINE(google-runtime-references)
|
||||
void SysFileGetLastAccessAndWriteTimeUtc(sys_file_t& f, SysFileTimeStruct& a, SysFileTimeStruct& w);
|
||||
// NOLINTNEXTLINE(google-runtime-references)
|
||||
bool SysFileSetLastAccessTimeUtc(const std::filesystem::path& name, SysFileTimeStruct& access);
|
||||
// NOLINTNEXTLINE(google-runtime-references)
|
||||
bool SysFileSetLastWriteTimeUtc(const std::filesystem::path& name, SysFileTimeStruct& write);
|
||||
// NOLINTNEXTLINE(google-runtime-references)
|
||||
bool SysFileSetLastAccessAndWriteTimeUtc(const std::filesystem::path& name,
|
||||
SysFileTimeStruct& access, SysFileTimeStruct& write);
|
||||
// NOLINTNEXTLINE(google-runtime-references)
|
||||
void SysFileFindFiles(const std::filesystem::path& path, std::vector<sys_file_find_t>& out);
|
||||
// NOLINTNEXTLINE(google-runtime-references)
|
||||
void SysFileGetDents(const std::filesystem::path& path, std::vector<sys_dir_entry_t>& out);
|
||||
bool SysFileCopyFile(const std::filesystem::path& src, const std::filesystem::path& dst);
|
||||
bool SysFileMoveFile(const std::filesystem::path& src, const std::filesystem::path& dst);
|
||||
void SysFileRemoveReadonly(const std::filesystem::path& name);
|
||||
|
||||
#endif /* KYTY_COMMON_PLATFORM_SYSFILEIO_H_ */
|
||||
@@ -0,0 +1,123 @@
|
||||
#include "common/common.h"
|
||||
|
||||
#if KYTY_PLATFORM != KYTY_PLATFORM_LINUX
|
||||
// #error "KYTY_PLATFORM != KYTY_PLATFORM_LINUX"
|
||||
#else
|
||||
|
||||
#include "common/platform/sysDbg.h"
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <sys/param.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
void SysStackWalk(void** /*stack*/, int* depth) {
|
||||
*depth = 0;
|
||||
}
|
||||
|
||||
void SysStackUsagePrint(sys_dbg_stack_info_t& stack) {
|
||||
printf("stack: (0x%" PRIx64 ", %" PRIu64 ")\n", static_cast<uint64_t>(stack.commited_addr),
|
||||
static_cast<uint64_t>(stack.commited_size));
|
||||
printf("code: (0x%" PRIx64 ", %" PRIu64 ")\n", static_cast<uint64_t>(stack.code_addr),
|
||||
static_cast<uint64_t>(stack.code_size));
|
||||
}
|
||||
|
||||
void SysStackUsage(sys_dbg_stack_info_t& s) {
|
||||
pid_t pid = getpid();
|
||||
|
||||
// printf("pid = %"I64"d\n", (int64_t)pid);
|
||||
|
||||
[[maybe_unused]] int result = 0;
|
||||
|
||||
char str[1024];
|
||||
char str2[1024];
|
||||
result = sprintf(str, "/proc/%d/exe", static_cast<int>(pid));
|
||||
|
||||
ssize_t buff_len = 0;
|
||||
if ((buff_len = readlink(str, str2, 1023)) == -1) {
|
||||
return;
|
||||
}
|
||||
str2[buff_len] = '\0';
|
||||
const char* name = basename(str2);
|
||||
|
||||
result = sprintf(str, "/proc/%d/maps", static_cast<int>(pid));
|
||||
|
||||
memset(&s, 0, sizeof(sys_dbg_stack_info_t));
|
||||
|
||||
FILE* f = fopen(str, "r");
|
||||
|
||||
if (f == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
// printf("&str = %"I64"x\n", (uint64_t)&str);
|
||||
|
||||
uint64_t addr = 0;
|
||||
uint64_t endaddr = 0;
|
||||
[[maybe_unused]] uint64_t size = 0;
|
||||
uint64_t offset = 0;
|
||||
uint64_t inode = 0;
|
||||
char permissions[8] = {};
|
||||
char device[8] = {};
|
||||
char filename[MAXPATHLEN] = {};
|
||||
|
||||
auto check_addr = reinterpret_cast<uintptr_t>(&f);
|
||||
|
||||
while (true) {
|
||||
if (feof(f) != 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (fgets(str, sizeof(str), f) == nullptr) {
|
||||
break;
|
||||
}
|
||||
|
||||
filename[0] = 0;
|
||||
permissions[0] = 0;
|
||||
addr = 0;
|
||||
size = 0;
|
||||
|
||||
// printf("%s", str);
|
||||
|
||||
// NOLINTNEXTLINE(cert-err34-c)
|
||||
result = sscanf(str, "%" SCNx64 "-%" SCNx64 " %s %" SCNx64 " %s %" SCNx64 " %s", &addr,
|
||||
&endaddr, permissions, &offset, device, &inode, filename);
|
||||
|
||||
size = endaddr - addr;
|
||||
|
||||
bool read = (strchr(permissions, 'r') != nullptr);
|
||||
bool write = (strchr(permissions, 'w') != nullptr);
|
||||
bool exec = (strchr(permissions, 'x') != nullptr);
|
||||
|
||||
// printf("%016"I64"x, %"I64"d, %s, %d, %d\n", addr, size, filename, read, write);
|
||||
|
||||
if (read && write && !exec && strncmp(filename, "[stack", 6) == 0) {
|
||||
// printf("stack: %016"I64"x, %"I64"d\n", addr, size);
|
||||
|
||||
if (check_addr >= addr && check_addr < addr + size) {
|
||||
s.addr = addr;
|
||||
s.total_size = size;
|
||||
s.commited_addr = addr;
|
||||
s.commited_size = size;
|
||||
|
||||
if (s.code_addr != 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (read && !write && exec && strstr(filename, name) != nullptr) {
|
||||
s.code_addr = addr;
|
||||
s.code_size = size;
|
||||
|
||||
if (s.addr != 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result = fclose(f);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,557 @@
|
||||
#include "common/common.h"
|
||||
|
||||
#if KYTY_PLATFORM != KYTY_PLATFORM_LINUX
|
||||
// #error "KYTY_PLATFORM != KYTY_PLATFORM_LINUX"
|
||||
#else
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/platform/sysFileIO.h"
|
||||
#include "common/platform/sysTimer.h"
|
||||
#include "common/stringUtils.h"
|
||||
|
||||
#include <cerrno>
|
||||
#include <cstdlib>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <utime.h>
|
||||
|
||||
// NOLINTNEXTLINE(readability-identifier-naming)
|
||||
enum sys_file_type_t {
|
||||
SYS_FILE_ERROR, // NOLINT(readability-identifier-naming)
|
||||
SYS_FILE_MEMORY_STAT, // NOLINT(readability-identifier-naming)
|
||||
SYS_FILE_FILE, // NOLINT(readability-identifier-naming)
|
||||
SYS_FILE_MEMORY_DYN // NOLINT(readability-identifier-naming)
|
||||
};
|
||||
|
||||
// NOLINTNEXTLINE(readability-identifier-naming)
|
||||
struct sys_file_mem_buf_t {
|
||||
uint8_t* base;
|
||||
uint8_t* ptr;
|
||||
uint32_t size;
|
||||
};
|
||||
|
||||
// NOLINTNEXTLINE(readability-identifier-naming)
|
||||
struct sys_file_t {
|
||||
sys_file_type_t type;
|
||||
union {
|
||||
FILE* f;
|
||||
sys_file_mem_buf_t* buf;
|
||||
};
|
||||
};
|
||||
|
||||
static std::filesystem::path get_internal_name(const std::filesystem::path& name) {
|
||||
return name.is_absolute() ? name : (std::filesystem::path(".") / name);
|
||||
}
|
||||
|
||||
void SysFileRead(void* data, uint32_t size, sys_file_t& f, uint32_t* bytes_read) {
|
||||
if (f.type == SYS_FILE_FILE) {
|
||||
size_t w = fread(data, 1, size, f.f);
|
||||
if (bytes_read != nullptr) {
|
||||
*bytes_read = w;
|
||||
}
|
||||
} else if (f.type == SYS_FILE_MEMORY_STAT) {
|
||||
uint32_t s = size;
|
||||
if (f.buf->size != 0) {
|
||||
uint32_t l = f.buf->size - (f.buf->ptr - f.buf->base);
|
||||
if (s > l) {
|
||||
s = l;
|
||||
}
|
||||
}
|
||||
memcpy(data, f.buf->ptr, s);
|
||||
f.buf->ptr += s;
|
||||
if (bytes_read != nullptr) {
|
||||
*bytes_read = s;
|
||||
}
|
||||
} else if (f.type == SYS_FILE_MEMORY_DYN) {
|
||||
uint32_t s = size;
|
||||
if (f.buf->size != 0) {
|
||||
uint32_t l = f.buf->size - (f.buf->ptr - f.buf->base);
|
||||
if (s > l) {
|
||||
s = l;
|
||||
}
|
||||
} else {
|
||||
s = 0;
|
||||
}
|
||||
memcpy(data, f.buf->ptr, s);
|
||||
f.buf->ptr += s;
|
||||
if (bytes_read != nullptr) {
|
||||
*bytes_read = s;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SysFileWrite(const void* data, uint32_t size, sys_file_t& f, uint32_t* bytes_written) {
|
||||
if (f.type == SYS_FILE_FILE) {
|
||||
size_t w = fwrite(data, 1, size, f.f);
|
||||
if (bytes_written != nullptr) {
|
||||
*bytes_written = w;
|
||||
}
|
||||
} else if (f.type == SYS_FILE_MEMORY_STAT) {
|
||||
uint32_t s = size;
|
||||
if (f.buf->size != 0) {
|
||||
uint32_t l = f.buf->size - (f.buf->ptr - f.buf->base);
|
||||
if (s > l) {
|
||||
s = l;
|
||||
}
|
||||
}
|
||||
memcpy(f.buf->ptr, data, s);
|
||||
f.buf->ptr += s;
|
||||
if (bytes_written != nullptr) {
|
||||
*bytes_written = s;
|
||||
}
|
||||
} else if (f.type == SYS_FILE_MEMORY_DYN) {
|
||||
uint32_t pos = f.buf->ptr - f.buf->base;
|
||||
if (f.buf->size < pos + size) {
|
||||
f.buf->base = static_cast<uint8_t*>(std::realloc(f.buf->base, pos + size));
|
||||
f.buf->ptr = f.buf->base + pos;
|
||||
f.buf->size = pos + size;
|
||||
}
|
||||
memcpy(f.buf->ptr, data, size);
|
||||
f.buf->ptr += size;
|
||||
if (bytes_written != nullptr) {
|
||||
*bytes_written = size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SysFileWrite(uint32_t n, sys_file_t& f) {
|
||||
SysFileWrite(&n, 4, f);
|
||||
}
|
||||
|
||||
sys_file_t* SysFileCreate(const std::filesystem::path& file_name) {
|
||||
auto* ret = new sys_file_t;
|
||||
|
||||
auto real_name = get_internal_name(file_name);
|
||||
auto real_name_str = real_name.string();
|
||||
|
||||
ret->f = fopen(real_name_str.c_str(), "w+");
|
||||
|
||||
if (ret->f == nullptr) {
|
||||
printf("can't create file: %s\n", real_name_str.c_str());
|
||||
}
|
||||
|
||||
ret->type = SYS_FILE_FILE;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
sys_file_t* SysFileOpenR(const std::filesystem::path& file_name,
|
||||
sys_file_cache_type_t /*cache_type*/) {
|
||||
auto* ret = new sys_file_t;
|
||||
|
||||
ret->type = SYS_FILE_FILE;
|
||||
|
||||
auto internal_name = get_internal_name(file_name);
|
||||
auto internal_name_str = internal_name.string();
|
||||
|
||||
FILE* f = fopen(internal_name_str.c_str(), "r");
|
||||
|
||||
if (f == nullptr) {
|
||||
ret->type = SYS_FILE_ERROR;
|
||||
}
|
||||
|
||||
ret->f = f;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
sys_file_t* SysFileOpen(uint8_t* buf, uint32_t buf_size) {
|
||||
auto* ret = new sys_file_t;
|
||||
|
||||
ret->type = SYS_FILE_MEMORY_STAT;
|
||||
ret->buf = new sys_file_mem_buf_t;
|
||||
ret->buf->base = buf;
|
||||
ret->buf->ptr = buf;
|
||||
ret->buf->size = buf_size;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
sys_file_t* SysFileCreate() {
|
||||
auto* ret = new sys_file_t;
|
||||
|
||||
ret->type = SYS_FILE_MEMORY_DYN;
|
||||
ret->buf = new sys_file_mem_buf_t;
|
||||
ret->buf->base = nullptr;
|
||||
ret->buf->ptr = nullptr;
|
||||
ret->buf->size = 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
sys_file_t* SysFileOpenW(const std::filesystem::path& file_name,
|
||||
sys_file_cache_type_t /*cache_type*/) {
|
||||
auto* ret = new sys_file_t;
|
||||
|
||||
auto real_name = get_internal_name(file_name);
|
||||
auto real_name_str = real_name.string();
|
||||
|
||||
FILE* f = fopen(real_name_str.c_str(), "r+");
|
||||
|
||||
if (f == nullptr) {
|
||||
ret->type = SYS_FILE_ERROR;
|
||||
} else {
|
||||
ret->type = SYS_FILE_FILE;
|
||||
}
|
||||
|
||||
ret->f = f;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
sys_file_t* SysFileOpenRw(const std::filesystem::path& file_name,
|
||||
sys_file_cache_type_t /*cache_type*/) {
|
||||
auto* ret = new sys_file_t;
|
||||
|
||||
auto real_name = get_internal_name(file_name);
|
||||
auto real_name_str = real_name.string();
|
||||
|
||||
FILE* f = fopen(real_name_str.c_str(), "r+");
|
||||
|
||||
if (f == nullptr) {
|
||||
ret->type = SYS_FILE_ERROR;
|
||||
} else {
|
||||
ret->type = SYS_FILE_FILE;
|
||||
}
|
||||
|
||||
ret->f = f;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void SysFileClose(sys_file_t* f) {
|
||||
[[maybe_unused]] int result = 0;
|
||||
|
||||
if (f->type == SYS_FILE_FILE && f->f != nullptr) {
|
||||
result = fclose(f->f);
|
||||
} else if (f->type == SYS_FILE_MEMORY_STAT) {
|
||||
delete f->buf;
|
||||
} else if (f->type == SYS_FILE_MEMORY_DYN) {
|
||||
std::free(f->buf->base);
|
||||
delete f->buf;
|
||||
}
|
||||
|
||||
// f.type = SYS_FILE_ERROR;
|
||||
delete f;
|
||||
}
|
||||
|
||||
uint64_t SysFileSize(sys_file_t& f) {
|
||||
[[maybe_unused]] int result = 0;
|
||||
|
||||
if (f.type == SYS_FILE_FILE) {
|
||||
uint32_t pos = ftell(f.f);
|
||||
result = fseek(f.f, 0, SEEK_END);
|
||||
uint32_t size = ftell(f.f);
|
||||
result = fseek(f.f, pos, SEEK_SET);
|
||||
return size;
|
||||
}
|
||||
|
||||
if (f.type == SYS_FILE_MEMORY_STAT || f.type == SYS_FILE_MEMORY_DYN) {
|
||||
return f.buf->size;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint64_t SysFileSize(const std::filesystem::path& file_name) {
|
||||
sys_file_t* f = SysFileOpenR(file_name);
|
||||
uint64_t size = SysFileSize(*f);
|
||||
SysFileClose(f);
|
||||
return size;
|
||||
}
|
||||
|
||||
bool SysFileTruncate(sys_file_t& /*f*/, uint64_t /*size*/) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SysFileUnlink(sys_file_t& /*f*/, const std::filesystem::path& name) {
|
||||
return SysFileDeleteFile(name);
|
||||
}
|
||||
|
||||
bool SysFileSeek(sys_file_t& f, uint64_t offset) {
|
||||
bool ok = true;
|
||||
if (f.type == SYS_FILE_FILE) {
|
||||
ok = (fseek(f.f, static_cast<int64_t>(offset), SEEK_SET) == 0);
|
||||
// LARGE_INTEGER s;
|
||||
// s.QuadPart = offset;
|
||||
// SetFilePointerEx(f.handle, s, 0, FILE_BEGIN);
|
||||
// printf("seek: %u\n", offset);
|
||||
} else if (f.type == SYS_FILE_MEMORY_STAT || f.type == SYS_FILE_MEMORY_DYN) {
|
||||
f.buf->ptr = f.buf->base + offset;
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
uint64_t SysFileTell(sys_file_t& f) {
|
||||
if (f.type == SYS_FILE_FILE) {
|
||||
return ftell(f.f);
|
||||
}
|
||||
|
||||
if (f.type == SYS_FILE_MEMORY_STAT || f.type == SYS_FILE_MEMORY_DYN) {
|
||||
return f.buf->ptr - f.buf->base;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool SysFileIsError(sys_file_t& f) {
|
||||
return f.type == SYS_FILE_ERROR || (f.type == SYS_FILE_FILE && f.f == nullptr);
|
||||
}
|
||||
|
||||
bool SysFileIsDirectoryExisting(const std::filesystem::path& path) {
|
||||
auto real_name = get_internal_name(path);
|
||||
auto real_name_str = real_name.string();
|
||||
|
||||
struct stat s {};
|
||||
|
||||
if (0 != stat(real_name_str.c_str(), &s)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return S_ISDIR(s.st_mode); // NOLINT
|
||||
}
|
||||
|
||||
bool SysFileIsFileExisting(const std::filesystem::path& name) {
|
||||
auto real_name = get_internal_name(name);
|
||||
auto real_name_str = real_name.string();
|
||||
|
||||
struct stat s {};
|
||||
|
||||
if (0 != stat(real_name_str.c_str(), &s)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return !S_ISDIR(s.st_mode); // NOLINT
|
||||
}
|
||||
|
||||
bool SysFileCreateDirectory(const std::filesystem::path& path) {
|
||||
auto real_name = get_internal_name(path);
|
||||
auto real_name_str = real_name.string();
|
||||
|
||||
mode_t m = S_IRWXU | S_IRWXG | S_IRWXO; // NOLINT
|
||||
|
||||
int r = mkdir(real_name_str.c_str(), m);
|
||||
|
||||
if (r != 0) {
|
||||
int e = errno;
|
||||
if (e == EEXIST) {
|
||||
printf("mkdir(%s, %" PRIx32 ") failed: The named file exists\n", real_name_str.c_str(),
|
||||
static_cast<uint32_t>(m));
|
||||
} else {
|
||||
printf("mkdir(%s, %" PRIx32 ") failed: %d\n", real_name_str.c_str(),
|
||||
static_cast<uint32_t>(m), e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SysFileDeleteDirectory(const std::filesystem::path& path) {
|
||||
auto real_name = get_internal_name(path);
|
||||
auto real_name_str = real_name.string();
|
||||
|
||||
return 0 == remove(real_name_str.c_str());
|
||||
}
|
||||
|
||||
bool SysFileDeleteFile(const std::filesystem::path& name) {
|
||||
auto real_name = get_internal_name(name);
|
||||
auto real_name_str = real_name.string();
|
||||
|
||||
return 0 == unlink(real_name_str.c_str());
|
||||
}
|
||||
|
||||
bool SysFileFlush(sys_file_t& f) {
|
||||
if (f.type == SYS_FILE_FILE && f.f != nullptr) {
|
||||
return (fflush(f.f) == 0);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
SysFileTimeStruct SysFileGetLastAccessTimeUtc(const std::filesystem::path& name) {
|
||||
SysFileTimeStruct r {};
|
||||
|
||||
auto real_name = get_internal_name(name);
|
||||
auto real_name_str = real_name.string();
|
||||
|
||||
struct stat s {};
|
||||
|
||||
if (0 != stat(real_name_str.c_str(), &s)) {
|
||||
r.is_invalid = true;
|
||||
} else {
|
||||
r.is_invalid = false;
|
||||
r.time = s.st_atime;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
SysFileTimeStruct SysFileGetLastWriteTimeUtc(const std::filesystem::path& name) {
|
||||
SysFileTimeStruct r {};
|
||||
|
||||
auto real_name = get_internal_name(name);
|
||||
auto real_name_str = real_name.string();
|
||||
|
||||
struct stat s {};
|
||||
|
||||
if (0 != stat(real_name_str.c_str(), &s)) {
|
||||
r.is_invalid = true;
|
||||
} else {
|
||||
r.is_invalid = false;
|
||||
r.time = s.st_mtime;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
void SysFileGetLastAccessAndWriteTimeUtc(const std::filesystem::path& name, SysFileTimeStruct& a,
|
||||
SysFileTimeStruct& w) {
|
||||
auto real_name = get_internal_name(name);
|
||||
auto real_name_str = real_name.string();
|
||||
|
||||
struct stat s {};
|
||||
|
||||
if (0 != stat(real_name_str.c_str(), &s)) {
|
||||
a.is_invalid = true;
|
||||
w.is_invalid = true;
|
||||
} else {
|
||||
a.is_invalid = false;
|
||||
w.is_invalid = false;
|
||||
a.time = s.st_atime;
|
||||
w.time = s.st_mtime;
|
||||
}
|
||||
}
|
||||
|
||||
void SysFileGetLastAccessAndWriteTimeUtc(sys_file_t& /*f*/, SysFileTimeStruct& /*a*/,
|
||||
SysFileTimeStruct& /*w*/) {
|
||||
EXIT("not implemented\n");
|
||||
}
|
||||
|
||||
bool SysFileSetLastAccessTimeUtc(const std::filesystem::path& name, SysFileTimeStruct& access) {
|
||||
if (access.is_invalid) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto real_name = get_internal_name(name);
|
||||
auto real_name_str = real_name.string();
|
||||
|
||||
struct stat s {};
|
||||
|
||||
if (0 != stat(real_name_str.c_str(), &s)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
utimbuf times {};
|
||||
times.actime = access.time;
|
||||
times.modtime = s.st_mtime;
|
||||
|
||||
return !(0 != utime(real_name_str.c_str(), ×));
|
||||
|
||||
// if (0 != stat(n.data(), &s))
|
||||
// {
|
||||
// return false;
|
||||
// }
|
||||
//
|
||||
// times.actime += times.actime - s.st_atime;
|
||||
// times.modtime += times.modtime - s.st_mtime;
|
||||
//
|
||||
// if (0 != utime(n.data(), ×))
|
||||
// {
|
||||
// return false;
|
||||
// }
|
||||
}
|
||||
|
||||
bool SysFileSetLastWriteTimeUtc(const std::filesystem::path& name, SysFileTimeStruct& write) {
|
||||
if (write.is_invalid) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto real_name = get_internal_name(name);
|
||||
auto real_name_str = real_name.string();
|
||||
|
||||
struct stat s {};
|
||||
|
||||
if (0 != stat(real_name_str.c_str(), &s)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
utimbuf times {};
|
||||
times.actime = s.st_atime;
|
||||
times.modtime = write.time;
|
||||
|
||||
return !(0 != utime(real_name_str.c_str(), ×));
|
||||
|
||||
// if (0 != stat(n.data(), &s))
|
||||
// {
|
||||
// return false;
|
||||
// }
|
||||
//
|
||||
// times.actime += times.actime - s.st_atime;
|
||||
// times.modtime += times.modtime - s.st_mtime;
|
||||
//
|
||||
// if (0 != utime(n.data(), ×))
|
||||
// {
|
||||
// return false;
|
||||
// }
|
||||
}
|
||||
|
||||
bool SysFileSetLastAccessAndWriteTimeUtc(const std::filesystem::path& name,
|
||||
SysFileTimeStruct& access, SysFileTimeStruct& write) {
|
||||
if (access.is_invalid || write.is_invalid) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto real_name = get_internal_name(name);
|
||||
auto real_name_str = real_name.string();
|
||||
|
||||
struct stat s {};
|
||||
|
||||
if (0 != stat(real_name_str.c_str(), &s)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
utimbuf times {};
|
||||
times.actime = access.time;
|
||||
times.modtime = write.time;
|
||||
|
||||
return !(0 != utime(real_name_str.c_str(), ×));
|
||||
|
||||
// if (0 != stat(n.data(), &s))
|
||||
// {
|
||||
// return false;
|
||||
// }
|
||||
//
|
||||
// times.actime += times.actime - s.st_atime;
|
||||
// times.modtime += times.modtime - s.st_mtime;
|
||||
//
|
||||
// if (0 != utime(n.data(), ×))
|
||||
// {
|
||||
// return false;
|
||||
// }
|
||||
}
|
||||
|
||||
void SysFileFindFiles(const std::filesystem::path& /*path*/,
|
||||
std::vector<sys_file_find_t>& /*out*/) {
|
||||
EXIT("not implemented\n");
|
||||
}
|
||||
|
||||
void SysFileGetDents(const std::filesystem::path& /*path*/, std::vector<sys_dir_entry_t>& /*out*/) {
|
||||
EXIT("not implemented\n");
|
||||
}
|
||||
|
||||
bool SysFileCopyFile(const std::filesystem::path& /*src*/, const std::filesystem::path& /*dst*/) {
|
||||
EXIT("not implemented\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SysFileMoveFile(const std::filesystem::path& /*src*/, const std::filesystem::path& /*dst*/) {
|
||||
EXIT("not implemented\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
void SysFileRemoveReadonly(const std::filesystem::path& /*name*/) {
|
||||
EXIT("not implemented\n");
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,451 @@
|
||||
#include "common/common.h"
|
||||
|
||||
#if KYTY_PLATFORM != KYTY_PLATFORM_LINUX
|
||||
// #error "KYTY_PLATFORM != KYTY_PLATFORM_LINUX"
|
||||
#else
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/platform/sysVirtual.h"
|
||||
#include "common/virtualMemory.h"
|
||||
|
||||
#include <map>
|
||||
#include <pthread.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
// IWYU pragma: no_include <asm/mman-common.h>
|
||||
// IWYU pragma: no_include <asm/mman.h>
|
||||
// IWYU pragma: no_include <bits/pthread_types.h>
|
||||
// IWYU pragma: no_include <linux/mman.h>
|
||||
|
||||
#if defined(MAP_FIXED_NOREPLACE) && KYTY_PLATFORM == KYTY_PLATFORM_LINUX
|
||||
#define KYTY_FIXED_NOREPLACE
|
||||
#endif
|
||||
|
||||
namespace Common {
|
||||
|
||||
static pthread_mutex_t g_virtual_mutex {};
|
||||
static std::map<uintptr_t, size_t>* g_allocs = nullptr;
|
||||
static std::map<uintptr_t, int>* g_protects = nullptr;
|
||||
|
||||
void SysVirtualInit() {
|
||||
pthread_mutexattr_t attr {};
|
||||
|
||||
pthread_mutexattr_init(&attr);
|
||||
#if KYTY_PLATFORM == KYTY_PLATFORM_LINUX
|
||||
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_FAST_NP);
|
||||
#else
|
||||
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL);
|
||||
#endif
|
||||
pthread_mutex_init(&g_virtual_mutex, &attr);
|
||||
pthread_mutexattr_destroy(&attr);
|
||||
|
||||
g_allocs = new std::map<uintptr_t, size_t>;
|
||||
g_protects = new std::map<uintptr_t, int>;
|
||||
}
|
||||
|
||||
static int get_protection_flag(VirtualMemory::Mode mode) {
|
||||
int protect = PROT_NONE;
|
||||
switch (mode) {
|
||||
case VirtualMemory::Mode::Read: protect = PROT_READ; break;
|
||||
case VirtualMemory::Mode::Write:
|
||||
case VirtualMemory::Mode::ReadWrite: protect = PROT_READ | PROT_WRITE; break; // NOLINT
|
||||
case VirtualMemory::Mode::Execute: protect = PROT_EXEC; break;
|
||||
case VirtualMemory::Mode::ExecuteRead: protect = PROT_EXEC | PROT_READ; break; // NOLINT
|
||||
case VirtualMemory::Mode::ExecuteWrite:
|
||||
case VirtualMemory::Mode::ExecuteReadWrite:
|
||||
protect = PROT_EXEC | PROT_WRITE | PROT_READ;
|
||||
break; // NOLINT
|
||||
case VirtualMemory::Mode::NoAccess:
|
||||
default: protect = PROT_NONE; break;
|
||||
}
|
||||
return protect;
|
||||
}
|
||||
|
||||
static VirtualMemory::Mode get_protection_flag(int mode) {
|
||||
switch (mode) {
|
||||
case PROT_NONE: return VirtualMemory::Mode::NoAccess;
|
||||
case PROT_READ: return VirtualMemory::Mode::Read;
|
||||
case PROT_WRITE: return VirtualMemory::Mode::Write;
|
||||
case PROT_READ | PROT_WRITE: return VirtualMemory::Mode::ReadWrite; // NOLINT
|
||||
case PROT_EXEC: return VirtualMemory::Mode::Execute;
|
||||
case PROT_EXEC | PROT_WRITE: return VirtualMemory::Mode::ExecuteWrite; // NOLINT
|
||||
case PROT_EXEC | PROT_READ: return VirtualMemory::Mode::ExecuteRead; // NOLINT
|
||||
case PROT_EXEC | PROT_WRITE | PROT_READ:
|
||||
return VirtualMemory::Mode::ExecuteReadWrite; // NOLINT
|
||||
default: return VirtualMemory::Mode::NoAccess;
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t SysVirtualAlloc(uint64_t address, uint64_t size, VirtualMemory::Mode mode) {
|
||||
EXIT_IF(g_allocs == nullptr);
|
||||
|
||||
auto addr = static_cast<uintptr_t>(address);
|
||||
|
||||
int protect = get_protection_flag(mode);
|
||||
|
||||
void* ptr =
|
||||
mmap(reinterpret_cast<void*>(addr), size, protect, MAP_PRIVATE | MAP_ANON, -1, 0); // NOLINT
|
||||
|
||||
auto ret_addr = reinterpret_cast<uintptr_t>(ptr);
|
||||
|
||||
if (ptr != MAP_FAILED) {
|
||||
pthread_mutex_lock(&g_virtual_mutex);
|
||||
(*g_allocs)[ret_addr] = size;
|
||||
uintptr_t page_start = ret_addr >> 12u;
|
||||
uintptr_t page_end = (ret_addr + size - 1) >> 12u;
|
||||
for (uintptr_t page = page_start; page <= page_end; page++) {
|
||||
(*g_protects)[page] = protect;
|
||||
}
|
||||
pthread_mutex_unlock(&g_virtual_mutex);
|
||||
}
|
||||
|
||||
return ret_addr;
|
||||
}
|
||||
|
||||
static uintptr_t align_up(uintptr_t addr, uint64_t alignment) {
|
||||
return (addr + alignment - 1) & ~(alignment - 1);
|
||||
}
|
||||
|
||||
uint64_t SysVirtualAllocAligned(uint64_t address, uint64_t size, VirtualMemory::Mode mode,
|
||||
uint64_t alignment) {
|
||||
if (alignment == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
EXIT_IF(g_allocs == nullptr);
|
||||
|
||||
auto addr = static_cast<uintptr_t>(address);
|
||||
int protect = get_protection_flag(mode);
|
||||
|
||||
void* ptr =
|
||||
mmap(reinterpret_cast<void*>(addr), size, protect, MAP_PRIVATE | MAP_ANON, -1, 0); // NOLINT
|
||||
|
||||
auto ret_addr = reinterpret_cast<uintptr_t>(ptr);
|
||||
|
||||
if (ptr != MAP_FAILED && ((ret_addr & (alignment - 1)) != 0)) {
|
||||
munmap(ptr, size);
|
||||
|
||||
ptr = mmap(reinterpret_cast<void*>(addr), size + alignment, protect,
|
||||
MAP_PRIVATE | MAP_ANON | MAP_NORESERVE, -1, 0); // NOLINT
|
||||
ret_addr = reinterpret_cast<uintptr_t>(ptr);
|
||||
if (ptr != MAP_FAILED) {
|
||||
munmap(ptr, size + alignment);
|
||||
auto aligned_addr = align_up(ret_addr, alignment);
|
||||
#ifdef KYTY_FIXED_NOREPLACE
|
||||
// NOLINTNEXTLINE
|
||||
ptr = mmap(reinterpret_cast<void*>(aligned_addr), size, protect,
|
||||
MAP_FIXED_NOREPLACE | MAP_PRIVATE | MAP_ANON, -1, 0);
|
||||
#else
|
||||
// NOLINTNEXTLINE
|
||||
ptr = mmap(reinterpret_cast<void*>(aligned_addr), size, protect,
|
||||
MAP_FIXED | MAP_PRIVATE | MAP_ANON, -1, 0);
|
||||
#endif
|
||||
ret_addr = reinterpret_cast<uintptr_t>(ptr);
|
||||
if (ptr != MAP_FAILED && ((ret_addr & (alignment - 1)) != 0)) {
|
||||
munmap(ptr, size);
|
||||
ret_addr = 0;
|
||||
ptr = MAP_FAILED;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ptr == MAP_FAILED) {
|
||||
return SysVirtualAllocAligned(address, size, mode, alignment << 1u);
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&g_virtual_mutex);
|
||||
(*g_allocs)[ret_addr] = size;
|
||||
uintptr_t page_start = ret_addr >> 12u;
|
||||
uintptr_t page_end = (ret_addr + size - 1) >> 12u;
|
||||
for (uintptr_t page = page_start; page <= page_end; page++) {
|
||||
(*g_protects)[page] = protect;
|
||||
}
|
||||
pthread_mutex_unlock(&g_virtual_mutex);
|
||||
|
||||
return ret_addr;
|
||||
}
|
||||
|
||||
static bool is_mapped(void* ptr, size_t length) {
|
||||
FILE* file = fopen("/proc/self/maps", "r");
|
||||
char line[1024];
|
||||
bool ret = false;
|
||||
auto addr = reinterpret_cast<uintptr_t>(ptr);
|
||||
|
||||
while (feof(file) == 0) {
|
||||
if (fgets(line, 1024, file) == nullptr) {
|
||||
break;
|
||||
}
|
||||
uint64_t start = 0;
|
||||
uint64_t end = 0;
|
||||
// NOLINTNEXTLINE(cert-err34-c)
|
||||
if (sscanf(line, "%" SCNx64 "-%" SCNx64, &start, &end) != 2) {
|
||||
continue;
|
||||
}
|
||||
if (addr >= start && addr + length <= end) {
|
||||
ret = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
fclose(file);
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool SysVirtualAllocFixed(uint64_t address, uint64_t size, VirtualMemory::Mode mode) {
|
||||
EXIT_IF(g_allocs == nullptr);
|
||||
|
||||
auto addr = static_cast<uintptr_t>(address);
|
||||
int protect = get_protection_flag(mode);
|
||||
|
||||
#ifdef KYTY_FIXED_NOREPLACE
|
||||
// NOLINTNEXTLINE
|
||||
void* ptr = mmap(reinterpret_cast<void*>(addr), size, protect,
|
||||
MAP_FIXED_NOREPLACE | MAP_PRIVATE | MAP_ANON, -1, 0);
|
||||
#else
|
||||
// NOLINTNEXTLINE
|
||||
void* ptr = (is_mapped(reinterpret_cast<void*>(addr), size)
|
||||
? MAP_FAILED
|
||||
: mmap(reinterpret_cast<void*>(addr), size, protect,
|
||||
MAP_FIXED | MAP_PRIVATE | MAP_ANON, -1, 0));
|
||||
#endif
|
||||
|
||||
auto ret_addr = reinterpret_cast<uintptr_t>(ptr);
|
||||
|
||||
if (ptr != MAP_FAILED && ret_addr != addr) {
|
||||
munmap(ptr, size);
|
||||
ret_addr = 0;
|
||||
ptr = MAP_FAILED;
|
||||
}
|
||||
|
||||
if (ptr != MAP_FAILED) {
|
||||
pthread_mutex_lock(&g_virtual_mutex);
|
||||
(*g_allocs)[ret_addr] = size;
|
||||
uintptr_t page_start = ret_addr >> 12u;
|
||||
uintptr_t page_end = (ret_addr + size - 1) >> 12u;
|
||||
for (uintptr_t page = page_start; page <= page_end; page++) {
|
||||
(*g_protects)[page] = protect;
|
||||
}
|
||||
pthread_mutex_unlock(&g_virtual_mutex);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SysVirtualCommit(uint64_t address, uint64_t size, VirtualMemory::Mode mode) {
|
||||
return SysVirtualProtect(address, size, mode);
|
||||
}
|
||||
|
||||
uint64_t SysVirtualReserve(uint64_t address, uint64_t size) {
|
||||
return SysVirtualReserveAligned(address, size, 1);
|
||||
}
|
||||
|
||||
uint64_t SysVirtualReserveAligned(uint64_t address, uint64_t size, uint64_t alignment) {
|
||||
if (alignment == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
EXIT_IF(g_allocs == nullptr);
|
||||
|
||||
auto addr = static_cast<uintptr_t>(address);
|
||||
|
||||
void* ptr = mmap(reinterpret_cast<void*>(addr), size, PROT_NONE,
|
||||
MAP_PRIVATE | MAP_ANON | MAP_NORESERVE, -1, 0); // NOLINT
|
||||
|
||||
auto ret_addr = reinterpret_cast<uintptr_t>(ptr);
|
||||
|
||||
if (ptr != MAP_FAILED && ((ret_addr & (alignment - 1)) != 0)) {
|
||||
munmap(ptr, size);
|
||||
|
||||
ptr = mmap(reinterpret_cast<void*>(addr), size + alignment, PROT_NONE,
|
||||
MAP_PRIVATE | MAP_ANON | MAP_NORESERVE, -1, 0); // NOLINT
|
||||
ret_addr = reinterpret_cast<uintptr_t>(ptr);
|
||||
if (ptr != MAP_FAILED) {
|
||||
munmap(ptr, size + alignment);
|
||||
auto aligned_addr = align_up(ret_addr, alignment);
|
||||
#ifdef KYTY_FIXED_NOREPLACE
|
||||
// NOLINTNEXTLINE
|
||||
ptr = mmap(reinterpret_cast<void*>(aligned_addr), size, PROT_NONE,
|
||||
MAP_FIXED_NOREPLACE | MAP_PRIVATE | MAP_ANON | MAP_NORESERVE, -1, 0);
|
||||
#else
|
||||
// NOLINTNEXTLINE
|
||||
ptr = mmap(reinterpret_cast<void*>(aligned_addr), size, PROT_NONE,
|
||||
MAP_FIXED | MAP_PRIVATE | MAP_ANON | MAP_NORESERVE, -1, 0);
|
||||
#endif
|
||||
ret_addr = reinterpret_cast<uintptr_t>(ptr);
|
||||
if (ptr != MAP_FAILED && ((ret_addr & (alignment - 1)) != 0)) {
|
||||
munmap(ptr, size);
|
||||
ret_addr = 0;
|
||||
ptr = MAP_FAILED;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ptr == MAP_FAILED) {
|
||||
return SysVirtualReserveAligned(address, size, alignment << 1u);
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&g_virtual_mutex);
|
||||
(*g_allocs)[ret_addr] = size;
|
||||
uintptr_t page_start = ret_addr >> 12u;
|
||||
uintptr_t page_end = (ret_addr + size - 1) >> 12u;
|
||||
for (uintptr_t page = page_start; page <= page_end; page++) {
|
||||
(*g_protects)[page] = PROT_NONE;
|
||||
}
|
||||
pthread_mutex_unlock(&g_virtual_mutex);
|
||||
|
||||
return ret_addr;
|
||||
}
|
||||
|
||||
bool SysVirtualReserveFixed(uint64_t address, uint64_t size) {
|
||||
EXIT_IF(g_allocs == nullptr);
|
||||
|
||||
auto addr = static_cast<uintptr_t>(address);
|
||||
|
||||
#ifdef KYTY_FIXED_NOREPLACE
|
||||
// NOLINTNEXTLINE
|
||||
void* ptr = mmap(reinterpret_cast<void*>(addr), size, PROT_NONE,
|
||||
MAP_FIXED_NOREPLACE | MAP_PRIVATE | MAP_ANON | MAP_NORESERVE, -1, 0);
|
||||
#else
|
||||
// NOLINTNEXTLINE
|
||||
void* ptr = (is_mapped(reinterpret_cast<void*>(addr), size)
|
||||
? MAP_FAILED
|
||||
: mmap(reinterpret_cast<void*>(addr), size, PROT_NONE,
|
||||
MAP_FIXED | MAP_PRIVATE | MAP_ANON | MAP_NORESERVE, -1, 0));
|
||||
#endif
|
||||
|
||||
auto ret_addr = reinterpret_cast<uintptr_t>(ptr);
|
||||
|
||||
if (ptr != MAP_FAILED && ret_addr != addr) {
|
||||
munmap(ptr, size);
|
||||
ret_addr = 0;
|
||||
ptr = MAP_FAILED;
|
||||
}
|
||||
|
||||
if (ptr != MAP_FAILED) {
|
||||
pthread_mutex_lock(&g_virtual_mutex);
|
||||
(*g_allocs)[ret_addr] = size;
|
||||
uintptr_t page_start = ret_addr >> 12u;
|
||||
uintptr_t page_end = (ret_addr + size - 1) >> 12u;
|
||||
for (uintptr_t page = page_start; page <= page_end; page++) {
|
||||
(*g_protects)[page] = PROT_NONE;
|
||||
}
|
||||
pthread_mutex_unlock(&g_virtual_mutex);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SysVirtualDecommit(uint64_t address, uint64_t size) {
|
||||
return SysVirtualProtect(address, size, VirtualMemory::Mode::NoAccess);
|
||||
}
|
||||
|
||||
bool SysVirtualFree(uint64_t address) {
|
||||
EXIT_IF(g_allocs == nullptr);
|
||||
size_t size = 0;
|
||||
|
||||
auto addr = static_cast<uintptr_t>(address & ~static_cast<uint64_t>(0xfffu));
|
||||
|
||||
pthread_mutex_lock(&g_virtual_mutex);
|
||||
if (auto s = g_allocs->find(addr); s != g_allocs->end()) {
|
||||
size = s->second;
|
||||
g_allocs->erase(s);
|
||||
}
|
||||
pthread_mutex_unlock(&g_virtual_mutex);
|
||||
|
||||
if (size == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (munmap(reinterpret_cast<void*>(addr), size) == 0) {
|
||||
uintptr_t page_start = addr >> 12u;
|
||||
uintptr_t page_end = (addr + size - 1) >> 12u;
|
||||
pthread_mutex_lock(&g_virtual_mutex);
|
||||
for (uintptr_t page = page_start; page <= page_end; page++) {
|
||||
g_protects->erase(page);
|
||||
}
|
||||
pthread_mutex_unlock(&g_virtual_mutex);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SysVirtualFreeRange(uint64_t address, uint64_t size) {
|
||||
EXIT_IF(g_allocs == nullptr);
|
||||
if (size == 0 || (address & 0xfffu) != 0 || (size & 0xfffu) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto addr = static_cast<uintptr_t>(address);
|
||||
const auto end = addr + size;
|
||||
if (end < addr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&g_virtual_mutex);
|
||||
auto next = g_allocs->upper_bound(addr);
|
||||
if (next == g_allocs->begin()) {
|
||||
pthread_mutex_unlock(&g_virtual_mutex);
|
||||
return false;
|
||||
}
|
||||
auto it = std::prev(next);
|
||||
const auto alloc_addr = it->first;
|
||||
const auto alloc_end = alloc_addr + it->second;
|
||||
if (addr < alloc_addr || end > alloc_end || munmap(reinterpret_cast<void*>(addr), size) != 0) {
|
||||
pthread_mutex_unlock(&g_virtual_mutex);
|
||||
return false;
|
||||
}
|
||||
|
||||
g_allocs->erase(it);
|
||||
if (alloc_addr < addr) {
|
||||
(*g_allocs)[alloc_addr] = addr - alloc_addr;
|
||||
}
|
||||
if (end < alloc_end) {
|
||||
(*g_allocs)[end] = alloc_end - end;
|
||||
}
|
||||
for (uintptr_t page = addr >> 12u; page <= (end - 1u) >> 12u; page++) {
|
||||
g_protects->erase(page);
|
||||
}
|
||||
pthread_mutex_unlock(&g_virtual_mutex);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SysVirtualProtect(uint64_t address, uint64_t size, VirtualMemory::Mode mode,
|
||||
VirtualMemory::Mode* old_mode) {
|
||||
auto addr = static_cast<uintptr_t>(address);
|
||||
|
||||
pthread_mutex_lock(&g_virtual_mutex);
|
||||
if (old_mode != nullptr) {
|
||||
if (auto s = g_protects->find(addr >> 12u); s != g_protects->end()) {
|
||||
*old_mode = get_protection_flag(s->second);
|
||||
} else {
|
||||
*old_mode = VirtualMemory::Mode::NoAccess;
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&g_virtual_mutex);
|
||||
|
||||
uintptr_t page_start = addr >> 12u;
|
||||
uintptr_t page_end = (addr + size - 1) >> 12u;
|
||||
if (mprotect(reinterpret_cast<void*>(page_start << 12u), (page_end - page_start + 1) << 12u,
|
||||
get_protection_flag(mode)) == 0) {
|
||||
pthread_mutex_lock(&g_virtual_mutex);
|
||||
for (uintptr_t page = page_start; page <= page_end; page++) {
|
||||
(*g_protects)[page] = get_protection_flag(mode);
|
||||
}
|
||||
pthread_mutex_unlock(&g_virtual_mutex);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SysVirtualFlushInstructionCache(uint64_t /*address*/, uint64_t /*size*/) {
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace Common
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,53 @@
|
||||
#ifndef KYTY_COMMON_PLATFORM_SYSSWAPBYTEORDER_H_
|
||||
#define KYTY_COMMON_PLATFORM_SYSSWAPBYTEORDER_H_
|
||||
|
||||
#include "common/common.h"
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
inline uint16_t SwapByteOrder16(uint16_t value) {
|
||||
uint16_t hi = value << 8u;
|
||||
uint16_t lo = value >> 8u;
|
||||
return hi | lo;
|
||||
}
|
||||
|
||||
inline uint32_t SwapByteOrder32(uint32_t value) {
|
||||
return __builtin_bswap32(value);
|
||||
}
|
||||
|
||||
inline uint64_t SwapByteOrder64(uint64_t value) {
|
||||
return __builtin_bswap64(value);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void SwapByteOrder(T& x) {
|
||||
if (sizeof(x) == 2) {
|
||||
if (std::is_signed_v<T>) {
|
||||
x = static_cast<std::make_signed_t<T>>(
|
||||
SwapByteOrder16(static_cast<std::make_unsigned_t<uint16_t>>(x)));
|
||||
} else {
|
||||
x = SwapByteOrder16(x);
|
||||
}
|
||||
}
|
||||
if (sizeof(x) == 4) {
|
||||
if (std::is_signed_v<T>) {
|
||||
x = static_cast<std::make_signed_t<T>>(
|
||||
SwapByteOrder32(static_cast<std::make_unsigned_t<uint32_t>>(x)));
|
||||
} else {
|
||||
x = SwapByteOrder32(x);
|
||||
}
|
||||
}
|
||||
if (sizeof(x) == 8) {
|
||||
if (std::is_signed_v<T>) {
|
||||
x = static_cast<std::make_signed_t<T>>(
|
||||
SwapByteOrder64(static_cast<std::make_unsigned_t<uint64_t>>(x)));
|
||||
} else {
|
||||
x = SwapByteOrder64(x);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void NoSwapByteOrder(T& x) {}
|
||||
|
||||
#endif /* KYTY_COMMON_PLATFORM_SYSSWAPBYTEORDER_H_ */
|
||||
@@ -0,0 +1,221 @@
|
||||
#ifndef KYTY_COMMON_PLATFORM_SYSTIMER_H_
|
||||
#define KYTY_COMMON_PLATFORM_SYSTIMER_H_
|
||||
|
||||
#include "common/common.h"
|
||||
|
||||
#include <ctime>
|
||||
|
||||
#if KYTY_PLATFORM == KYTY_PLATFORM_WINDOWS
|
||||
#ifndef NOMINMAX
|
||||
#define NOMINMAX
|
||||
#endif
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
struct SysTimeStruct {
|
||||
uint16_t Year; // NOLINT(readability-identifier-naming)
|
||||
uint16_t Month; // NOLINT(readability-identifier-naming)
|
||||
uint16_t Day; // NOLINT(readability-identifier-naming)
|
||||
uint16_t Hour; // NOLINT(readability-identifier-naming)
|
||||
uint16_t Minute; // NOLINT(readability-identifier-naming)
|
||||
uint16_t Second; // NOLINT(readability-identifier-naming)
|
||||
uint16_t Milliseconds; // NOLINT(readability-identifier-naming)
|
||||
bool is_invalid; // NOLINT(readability-identifier-naming)
|
||||
};
|
||||
|
||||
struct SysFileTimeStruct {
|
||||
#if KYTY_PLATFORM == KYTY_PLATFORM_WINDOWS
|
||||
FILETIME time;
|
||||
#elif KYTY_PLATFORM == KYTY_PLATFORM_LINUX
|
||||
time_t time;
|
||||
#endif
|
||||
bool is_invalid;
|
||||
};
|
||||
|
||||
#if KYTY_PLATFORM == KYTY_PLATFORM_WINDOWS
|
||||
|
||||
// NOLINTNEXTLINE(google-runtime-references)
|
||||
inline void SysFileToSystemTimeUtc(const SysFileTimeStruct& f, SysTimeStruct& t) {
|
||||
SYSTEMTIME s;
|
||||
|
||||
if (f.is_invalid || (FileTimeToSystemTime(&f.time, &s) == 0)) {
|
||||
t.is_invalid = true;
|
||||
return;
|
||||
}
|
||||
|
||||
t.is_invalid = false;
|
||||
t.Year = s.wYear;
|
||||
t.Month = s.wMonth;
|
||||
t.Day = s.wDay;
|
||||
t.Hour = s.wHour;
|
||||
t.Minute = s.wMinute;
|
||||
t.Second = (s.wSecond == 60 ? 59 : s.wSecond);
|
||||
t.Milliseconds = s.wMilliseconds;
|
||||
}
|
||||
|
||||
// NOLINTNEXTLINE(google-runtime-references)
|
||||
inline void SysTimeTToSystem(time_t t, SysTimeStruct& s) {
|
||||
SysFileTimeStruct ft {};
|
||||
LONGLONG ll = Int32x32To64(t, 10000000) + 116444736000000000;
|
||||
ft.time.dwLowDateTime = static_cast<DWORD>(ll);
|
||||
ft.time.dwHighDateTime = static_cast<DWORD>(static_cast<uint64_t>(ll) >> 32u);
|
||||
ft.is_invalid = false;
|
||||
SysFileToSystemTimeUtc(ft, s);
|
||||
}
|
||||
|
||||
// NOLINTNEXTLINE(google-runtime-references)
|
||||
inline void SysSystemToFileTimeUtc(const SysTimeStruct& f, SysFileTimeStruct& t) {
|
||||
SYSTEMTIME s;
|
||||
|
||||
s.wYear = f.Year;
|
||||
s.wMonth = f.Month;
|
||||
s.wDay = f.Day;
|
||||
s.wHour = f.Hour;
|
||||
s.wMinute = f.Minute;
|
||||
s.wSecond = f.Second;
|
||||
s.wMilliseconds = f.Milliseconds;
|
||||
|
||||
t.is_invalid = (f.is_invalid || (SystemTimeToFileTime(&s, &t.time) == 0));
|
||||
}
|
||||
|
||||
// Retrieves the current local date and time.
|
||||
// NOLINTNEXTLINE(google-runtime-references)
|
||||
inline void SysGetSystemTime(SysTimeStruct& t) {
|
||||
SYSTEMTIME s;
|
||||
GetLocalTime(&s);
|
||||
|
||||
t.is_invalid = false;
|
||||
t.Year = s.wYear;
|
||||
t.Month = s.wMonth;
|
||||
t.Day = s.wDay;
|
||||
t.Hour = s.wHour;
|
||||
t.Minute = s.wMinute;
|
||||
t.Second = (s.wSecond == 60 ? 59 : s.wSecond);
|
||||
t.Milliseconds = s.wMilliseconds;
|
||||
}
|
||||
|
||||
// Retrieves the current system date and time in Coordinated Universal Time (UTC).
|
||||
// NOLINTNEXTLINE(google-runtime-references)
|
||||
inline void SysGetSystemTimeUtc(SysTimeStruct& t) {
|
||||
SYSTEMTIME s;
|
||||
GetSystemTime(&s);
|
||||
|
||||
t.is_invalid = false;
|
||||
t.Year = s.wYear;
|
||||
t.Month = s.wMonth;
|
||||
t.Day = s.wDay;
|
||||
t.Hour = s.wHour;
|
||||
t.Minute = s.wMinute;
|
||||
t.Second = (s.wSecond == 60 ? 59 : s.wSecond);
|
||||
t.Milliseconds = s.wMilliseconds;
|
||||
}
|
||||
|
||||
inline void SysQueryPerformanceFrequency(uint64_t* freq) {
|
||||
LARGE_INTEGER f;
|
||||
QueryPerformanceFrequency(&f);
|
||||
*freq = f.QuadPart;
|
||||
}
|
||||
|
||||
inline void SysQueryPerformanceCounter(uint64_t* counter) {
|
||||
LARGE_INTEGER c;
|
||||
QueryPerformanceCounter(&c);
|
||||
*counter = c.QuadPart;
|
||||
}
|
||||
|
||||
#elif KYTY_PLATFORM == KYTY_PLATFORM_LINUX
|
||||
|
||||
inline void SysFileToSystemTimeUtc(const SysFileTimeStruct& f, SysTimeStruct& t) {
|
||||
struct tm i {};
|
||||
|
||||
if (f.is_invalid || gmtime_r(&f.time, &i) == nullptr) {
|
||||
t.is_invalid = true;
|
||||
return;
|
||||
}
|
||||
|
||||
t.is_invalid = false;
|
||||
t.Year = i.tm_year + 1900;
|
||||
t.Month = i.tm_mon + 1;
|
||||
t.Day = i.tm_mday;
|
||||
t.Hour = i.tm_hour;
|
||||
t.Minute = i.tm_min;
|
||||
t.Second = (i.tm_sec == 60 ? 59 : i.tm_sec);
|
||||
t.Milliseconds = 0;
|
||||
}
|
||||
|
||||
inline void SysTimeTToSystem(time_t t, SysTimeStruct& s) {
|
||||
SysFileTimeStruct ft {};
|
||||
ft.time = t;
|
||||
ft.is_invalid = false;
|
||||
SysFileToSystemTimeUtc(ft, s);
|
||||
}
|
||||
|
||||
inline time_t SysTimegm(struct tm* tm) {
|
||||
return timegm(tm);
|
||||
}
|
||||
|
||||
inline void SysSystemToFileTimeUtc(const SysTimeStruct& f, SysFileTimeStruct& t) {
|
||||
struct tm i {};
|
||||
|
||||
i.tm_year = f.Year - 1900;
|
||||
i.tm_mon = f.Month - 1;
|
||||
i.tm_mday = f.Day;
|
||||
i.tm_hour = f.Hour;
|
||||
i.tm_min = f.Minute;
|
||||
i.tm_sec = f.Second;
|
||||
|
||||
t.is_invalid = (f.is_invalid || (t.time = SysTimegm(&i)) == static_cast<time_t>(-1));
|
||||
}
|
||||
|
||||
// Retrieves the current local date and time.
|
||||
inline void SysGetSystemTime(SysTimeStruct& t) {
|
||||
time_t st {};
|
||||
struct tm i {};
|
||||
|
||||
if (time(&st) == static_cast<time_t>(-1) || localtime_r(&st, &i) == nullptr) {
|
||||
t.is_invalid = true;
|
||||
return;
|
||||
}
|
||||
|
||||
t.is_invalid = false;
|
||||
t.Year = i.tm_year + 1900;
|
||||
t.Month = i.tm_mon + 1;
|
||||
t.Day = i.tm_mday;
|
||||
t.Hour = i.tm_hour;
|
||||
t.Minute = i.tm_min;
|
||||
t.Second = (i.tm_sec == 60 ? 59 : i.tm_sec);
|
||||
t.Milliseconds = 0;
|
||||
}
|
||||
|
||||
// Retrieves the current system date and time in Coordinated Universal Time (UTC).
|
||||
inline void SysGetSystemTimeUtc(SysTimeStruct& t) {
|
||||
time_t st {};
|
||||
struct tm i {};
|
||||
|
||||
if (time(&st) == static_cast<time_t>(-1) || gmtime_r(&st, &i) == nullptr) {
|
||||
t.is_invalid = true;
|
||||
return;
|
||||
}
|
||||
|
||||
t.is_invalid = false;
|
||||
t.Year = i.tm_year + 1900;
|
||||
t.Month = i.tm_mon + 1;
|
||||
t.Day = i.tm_mday;
|
||||
t.Hour = i.tm_hour;
|
||||
t.Minute = i.tm_min;
|
||||
t.Second = (i.tm_sec == 60 ? 59 : i.tm_sec);
|
||||
t.Milliseconds = 0;
|
||||
}
|
||||
|
||||
inline void SysQueryPerformanceFrequency(uint64_t* freq) {
|
||||
*freq = 1000000000LL;
|
||||
}
|
||||
|
||||
inline void SysQueryPerformanceCounter(uint64_t* counter) {
|
||||
struct timespec now {};
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
*counter = now.tv_sec * 1000000000LL + now.tv_nsec;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* KYTY_COMMON_PLATFORM_SYSTIMER_H_ */
|
||||
@@ -0,0 +1,28 @@
|
||||
#ifndef KYTY_COMMON_PLATFORM_SYSVIRTUAL_H_
|
||||
#define KYTY_COMMON_PLATFORM_SYSVIRTUAL_H_
|
||||
|
||||
#include "common/common.h"
|
||||
#include "common/virtualMemory.h"
|
||||
|
||||
namespace Common {
|
||||
|
||||
void SysVirtualInit();
|
||||
|
||||
uint64_t SysVirtualAlloc(uint64_t address, uint64_t size, VirtualMemory::Mode mode);
|
||||
uint64_t SysVirtualAllocAligned(uint64_t address, uint64_t size, VirtualMemory::Mode mode,
|
||||
uint64_t alignment);
|
||||
bool SysVirtualAllocFixed(uint64_t address, uint64_t size, VirtualMemory::Mode mode);
|
||||
bool SysVirtualCommit(uint64_t address, uint64_t size, VirtualMemory::Mode mode);
|
||||
uint64_t SysVirtualReserve(uint64_t address, uint64_t size);
|
||||
uint64_t SysVirtualReserveAligned(uint64_t address, uint64_t size, uint64_t alignment);
|
||||
bool SysVirtualReserveFixed(uint64_t address, uint64_t size);
|
||||
bool SysVirtualDecommit(uint64_t address, uint64_t size);
|
||||
bool SysVirtualFree(uint64_t address);
|
||||
bool SysVirtualFreeRange(uint64_t address, uint64_t size);
|
||||
bool SysVirtualProtect(uint64_t address, uint64_t size, VirtualMemory::Mode mode,
|
||||
VirtualMemory::Mode* old_mode = nullptr);
|
||||
bool SysVirtualFlushInstructionCache(uint64_t address, uint64_t size);
|
||||
|
||||
} // namespace Common
|
||||
|
||||
#endif /* KYTY_COMMON_PLATFORM_SYSVIRTUAL_H_ */
|
||||
@@ -0,0 +1,105 @@
|
||||
#include "common/common.h"
|
||||
|
||||
// IWYU pragma: no_include <basetsd.h>
|
||||
// IWYU pragma: no_include <memoryapi.h>
|
||||
// IWYU pragma: no_include <minwindef.h>
|
||||
// IWYU pragma: no_include <processthreadsapi.h>
|
||||
// IWYU pragma: no_include <winbase.h>
|
||||
|
||||
#if KYTY_PLATFORM != KYTY_PLATFORM_WINDOWS
|
||||
// #error "KYTY_PLATFORM != KYTY_PLATFORM_WINDOWS"
|
||||
#else
|
||||
|
||||
#include <windows.h> // IWYU pragma: keep
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/platform/sysDbg.h"
|
||||
|
||||
struct FrameS {
|
||||
struct FrameS* next;
|
||||
void* ret_addr;
|
||||
};
|
||||
|
||||
int WalkStack(int z_stack_depth, void** z_stack_trace) {
|
||||
CONTEXT context;
|
||||
// KNONVOLATILE_CONTEXT_POINTERS NvContext;
|
||||
PRUNTIME_FUNCTION runtime_function = nullptr;
|
||||
PVOID handler_data = nullptr;
|
||||
ULONG64 establisher_frame = 0;
|
||||
ULONG64 image_base = 0;
|
||||
|
||||
RtlCaptureContext(&context);
|
||||
|
||||
int frame = 0;
|
||||
|
||||
while (true) {
|
||||
if (frame >= z_stack_depth) {
|
||||
break;
|
||||
}
|
||||
|
||||
z_stack_trace[frame] = reinterpret_cast<void*>(context.Rip);
|
||||
|
||||
frame++;
|
||||
|
||||
runtime_function = RtlLookupFunctionEntry(context.Rip, &image_base, nullptr);
|
||||
|
||||
if (runtime_function == nullptr) {
|
||||
break;
|
||||
}
|
||||
|
||||
// RtlZeroMemory(&NvContext, sizeof(KNONVOLATILE_CONTEXT_POINTERS));
|
||||
RtlVirtualUnwind(0, image_base, context.Rip, runtime_function, &context, &handler_data,
|
||||
&establisher_frame, nullptr /*&NvContext*/);
|
||||
|
||||
if (context.Rip == 0u) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return frame;
|
||||
}
|
||||
|
||||
void SysStackWalk(void** stack, int* depth) {
|
||||
int n = WalkStack(*depth, stack);
|
||||
*depth = n;
|
||||
// unwind_info_t info = {stack, 0, *depth};
|
||||
// _Unwind_Backtrace(&trace_fcn, &info);
|
||||
// *depth = info.depth;
|
||||
}
|
||||
|
||||
void SysStackUsagePrint(sys_dbg_stack_info_t& stack) {
|
||||
printf("stack: (0x%" PRIx64 ", %" PRIu64 ") + (0x%" PRIx64 ", %" PRIu64 ") + (0x%" PRIx64
|
||||
", %" PRIu64 ")\n",
|
||||
static_cast<uint64_t>(stack.reserved_addr), static_cast<uint64_t>(stack.reserved_size),
|
||||
static_cast<uint64_t>(stack.guard_addr), static_cast<uint64_t>(stack.guard_size),
|
||||
static_cast<uint64_t>(stack.commited_addr), static_cast<uint64_t>(stack.commited_size));
|
||||
}
|
||||
|
||||
void SysStackUsage(sys_dbg_stack_info_t& s) {
|
||||
MEMORY_BASIC_INFORMATION mbi {};
|
||||
[[maybe_unused]] size_t ss = VirtualQuery(&mbi, &mbi, sizeof(mbi));
|
||||
EXIT_IF(ss == 0);
|
||||
PVOID reserved = mbi.AllocationBase;
|
||||
ss = VirtualQuery(reserved, &mbi, sizeof(mbi));
|
||||
EXIT_IF(ss == 0);
|
||||
size_t reserved_size = mbi.RegionSize;
|
||||
ss = VirtualQuery(static_cast<char*>(reserved) + reserved_size, &mbi, sizeof(mbi));
|
||||
EXIT_IF(ss == 0);
|
||||
void* guard_page = mbi.BaseAddress;
|
||||
size_t guard_page_size = mbi.RegionSize;
|
||||
ss = VirtualQuery(static_cast<char*>(guard_page) + guard_page_size, &mbi, sizeof(mbi));
|
||||
EXIT_IF(ss == 0);
|
||||
void* commited = mbi.BaseAddress;
|
||||
size_t commited_size = mbi.RegionSize;
|
||||
s.reserved_addr = reinterpret_cast<uintptr_t>(reserved);
|
||||
s.reserved_size = reserved_size;
|
||||
s.guard_addr = reinterpret_cast<uintptr_t>(guard_page);
|
||||
s.guard_size = guard_page_size;
|
||||
s.commited_addr = reinterpret_cast<uintptr_t>(commited);
|
||||
s.commited_size = commited_size;
|
||||
|
||||
s.addr = s.reserved_addr;
|
||||
s.total_size = s.reserved_size + s.guard_size + s.commited_size;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,576 @@
|
||||
#include "common/common.h"
|
||||
|
||||
#if KYTY_PLATFORM != KYTY_PLATFORM_WINDOWS
|
||||
// #error "KYTY_PLATFORM != KYTY_PLATFORM_WINDOWS"
|
||||
#else
|
||||
|
||||
#include "common/platform/sysFileIO.h"
|
||||
#include "common/platform/sysTimer.h"
|
||||
#include "common/stringUtils.h"
|
||||
|
||||
#include <cstdlib>
|
||||
#include <vector>
|
||||
#include <windows.h> // IWYU pragma: keep
|
||||
|
||||
// NOLINTNEXTLINE(readability-identifier-naming)
|
||||
enum sys_file_type_t {
|
||||
SYS_FILE_ERROR, // NOLINT(readability-identifier-naming)
|
||||
SYS_FILE_MEMORY_STAT, // NOLINT(readability-identifier-naming)
|
||||
SYS_FILE_FILE, // NOLINT(readability-identifier-naming)
|
||||
SYS_FILE_MEMORY_DYN // NOLINT(readability-identifier-naming)
|
||||
};
|
||||
|
||||
// NOLINTNEXTLINE(readability-identifier-naming)
|
||||
struct sys_file_mem_buf_t {
|
||||
uint8_t* base;
|
||||
uint8_t* ptr;
|
||||
uint32_t size;
|
||||
};
|
||||
|
||||
// NOLINTNEXTLINE(readability-identifier-naming)
|
||||
struct sys_file_t {
|
||||
sys_file_type_t type;
|
||||
union {
|
||||
HANDLE handle;
|
||||
sys_file_mem_buf_t* buf;
|
||||
};
|
||||
};
|
||||
|
||||
// IWYU pragma: no_include <fileapi.h>
|
||||
// IWYU pragma: no_include <handleapi.h>
|
||||
// IWYU pragma: no_include <minwinbase.h>
|
||||
// IWYU pragma: no_include <minwindef.h>
|
||||
// IWYU pragma: no_include <winbase.h>
|
||||
|
||||
constexpr DWORD FILE_SHARE_POSIX = static_cast<DWORD>(FILE_SHARE_READ) |
|
||||
static_cast<DWORD>(FILE_SHARE_WRITE) |
|
||||
static_cast<DWORD>(FILE_SHARE_DELETE);
|
||||
|
||||
static DWORD GetCacheAccessType(sys_file_cache_type_t t) {
|
||||
if (t == SYS_FILE_CACHE_RANDOM_ACCESS) {
|
||||
return FILE_FLAG_RANDOM_ACCESS;
|
||||
}
|
||||
|
||||
if (t == SYS_FILE_CACHE_SEQUENTIAL_SCAN) {
|
||||
return SYS_FILE_CACHE_SEQUENTIAL_SCAN;
|
||||
}
|
||||
|
||||
return SYS_FILE_CACHE_AUTO;
|
||||
}
|
||||
|
||||
void SysFileRead(void* data, uint32_t size, sys_file_t& f, uint32_t* bytes_read) {
|
||||
if (f.type == SYS_FILE_FILE) {
|
||||
DWORD w = 0;
|
||||
ReadFile(f.handle, data, size, &w, nullptr);
|
||||
if (bytes_read != nullptr) {
|
||||
*bytes_read = w;
|
||||
}
|
||||
} else if (f.type == SYS_FILE_MEMORY_STAT) {
|
||||
uint32_t s = size;
|
||||
if (f.buf->size != 0u) {
|
||||
uint32_t l = f.buf->size - (f.buf->ptr - f.buf->base);
|
||||
if (s > l) {
|
||||
s = l;
|
||||
}
|
||||
}
|
||||
std::memcpy(data, f.buf->ptr, s);
|
||||
f.buf->ptr += s;
|
||||
if (bytes_read != nullptr) {
|
||||
*bytes_read = s;
|
||||
}
|
||||
} else if (f.type == SYS_FILE_MEMORY_DYN) {
|
||||
uint32_t s = size;
|
||||
if (f.buf->size != 0u) {
|
||||
uint32_t l = f.buf->size - (f.buf->ptr - f.buf->base);
|
||||
if (s > l) {
|
||||
s = l;
|
||||
}
|
||||
} else {
|
||||
s = 0;
|
||||
}
|
||||
std::memcpy(data, f.buf->ptr, s);
|
||||
f.buf->ptr += s;
|
||||
if (bytes_read != nullptr) {
|
||||
*bytes_read = s;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SysFileWrite(const void* data, uint32_t size, sys_file_t& f, uint32_t* bytes_written) {
|
||||
if (f.type == SYS_FILE_FILE) {
|
||||
DWORD w = 0;
|
||||
WriteFile(f.handle, data, size, &w, nullptr);
|
||||
if (bytes_written != nullptr) {
|
||||
*bytes_written = w;
|
||||
}
|
||||
} else if (f.type == SYS_FILE_MEMORY_STAT) {
|
||||
uint32_t s = size;
|
||||
if (f.buf->size != 0u) {
|
||||
uint32_t l = f.buf->size - (f.buf->ptr - f.buf->base);
|
||||
if (s > l) {
|
||||
s = l;
|
||||
}
|
||||
}
|
||||
std::memcpy(f.buf->ptr, data, s);
|
||||
f.buf->ptr += s;
|
||||
if (bytes_written != nullptr) {
|
||||
*bytes_written = s;
|
||||
}
|
||||
} else if (f.type == SYS_FILE_MEMORY_DYN) {
|
||||
uint32_t pos = f.buf->ptr - f.buf->base;
|
||||
if (f.buf->size < pos + size) {
|
||||
f.buf->base = static_cast<uint8_t*>(std::realloc(f.buf->base, pos + size));
|
||||
f.buf->ptr = f.buf->base + pos;
|
||||
f.buf->size = pos + size;
|
||||
}
|
||||
std::memcpy(f.buf->ptr, data, size);
|
||||
f.buf->ptr += size;
|
||||
if (bytes_written != nullptr) {
|
||||
*bytes_written = size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SysFileWrite(uint32_t n, sys_file_t& f) {
|
||||
SysFileWrite(&n, 4, f);
|
||||
}
|
||||
|
||||
sys_file_t* SysFileCreate(const std::filesystem::path& file_name) {
|
||||
auto* ret = new sys_file_t;
|
||||
|
||||
auto wide = file_name.wstring();
|
||||
HANDLE h_file = nullptr;
|
||||
h_file = CreateFileW(wide.c_str(),
|
||||
static_cast<DWORD>(GENERIC_READ) | static_cast<DWORD>(GENERIC_WRITE) |
|
||||
static_cast<DWORD>(DELETE),
|
||||
FILE_SHARE_POSIX, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
|
||||
|
||||
ret->handle = h_file;
|
||||
ret->type = SYS_FILE_FILE;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
sys_file_t* SysFileOpenR(const std::filesystem::path& file_name, sys_file_cache_type_t cache_type) {
|
||||
auto* ret = new sys_file_t;
|
||||
|
||||
auto wide = file_name.wstring();
|
||||
HANDLE h_file = nullptr;
|
||||
h_file = CreateFileW(wide.c_str(), GENERIC_READ, FILE_SHARE_POSIX, nullptr, OPEN_EXISTING,
|
||||
GetCacheAccessType(cache_type), nullptr);
|
||||
|
||||
if (h_file == INVALID_HANDLE_VALUE) {
|
||||
ret->type = SYS_FILE_ERROR;
|
||||
} else {
|
||||
ret->type = SYS_FILE_FILE;
|
||||
}
|
||||
|
||||
ret->handle = h_file;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
sys_file_t* SysFileOpen(uint8_t* buf, uint32_t buf_size) {
|
||||
auto* ret = new sys_file_t;
|
||||
|
||||
ret->type = SYS_FILE_MEMORY_STAT;
|
||||
ret->buf = new sys_file_mem_buf_t;
|
||||
ret->buf->base = buf;
|
||||
ret->buf->ptr = buf;
|
||||
ret->buf->size = buf_size;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
sys_file_t* SysFileCreate() {
|
||||
auto* ret = new sys_file_t;
|
||||
|
||||
ret->type = SYS_FILE_MEMORY_DYN;
|
||||
ret->buf = new sys_file_mem_buf_t;
|
||||
ret->buf->base = nullptr;
|
||||
ret->buf->ptr = nullptr;
|
||||
ret->buf->size = 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
sys_file_t* SysFileOpenW(const std::filesystem::path& file_name, sys_file_cache_type_t cache_type) {
|
||||
auto* ret = new sys_file_t;
|
||||
|
||||
auto wide = file_name.wstring();
|
||||
HANDLE h_file = nullptr;
|
||||
h_file = CreateFileW(
|
||||
wide.c_str(), static_cast<DWORD>(GENERIC_WRITE) | static_cast<DWORD>(DELETE),
|
||||
FILE_SHARE_POSIX, nullptr, OPEN_EXISTING, GetCacheAccessType(cache_type), nullptr);
|
||||
|
||||
if (h_file == INVALID_HANDLE_VALUE) {
|
||||
ret->type = SYS_FILE_ERROR;
|
||||
} else {
|
||||
ret->type = SYS_FILE_FILE;
|
||||
}
|
||||
|
||||
ret->handle = h_file;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
sys_file_t* SysFileOpenRw(const std::filesystem::path& file_name,
|
||||
sys_file_cache_type_t cache_type) {
|
||||
auto* ret = new sys_file_t;
|
||||
|
||||
auto wide = file_name.wstring();
|
||||
HANDLE h_file = nullptr;
|
||||
h_file = CreateFileW(wide.c_str(),
|
||||
static_cast<DWORD>(GENERIC_READ) | static_cast<DWORD>(GENERIC_WRITE) |
|
||||
static_cast<DWORD>(DELETE),
|
||||
FILE_SHARE_POSIX, nullptr, OPEN_EXISTING, GetCacheAccessType(cache_type),
|
||||
nullptr);
|
||||
|
||||
if (h_file == INVALID_HANDLE_VALUE) {
|
||||
ret->type = SYS_FILE_ERROR;
|
||||
} else {
|
||||
ret->type = SYS_FILE_FILE;
|
||||
}
|
||||
|
||||
ret->handle = h_file;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void SysFileClose(sys_file_t* f) {
|
||||
if (f->type == SYS_FILE_FILE) {
|
||||
CloseHandle(f->handle);
|
||||
} else if (f->type == SYS_FILE_MEMORY_STAT) {
|
||||
delete f->buf;
|
||||
} else if (f->type == SYS_FILE_MEMORY_DYN) {
|
||||
std::free(f->buf->base);
|
||||
delete f->buf;
|
||||
}
|
||||
|
||||
// f.type = SYS_FILE_ERROR;
|
||||
delete f;
|
||||
}
|
||||
|
||||
uint64_t SysFileSize(sys_file_t& f) {
|
||||
if (f.type == SYS_FILE_FILE) {
|
||||
LARGE_INTEGER s;
|
||||
GetFileSizeEx(f.handle, &s);
|
||||
return s.QuadPart;
|
||||
}
|
||||
|
||||
if (f.type == SYS_FILE_MEMORY_STAT || f.type == SYS_FILE_MEMORY_DYN) {
|
||||
return f.buf->size;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint64_t SysFileSize(const std::filesystem::path& file_name) {
|
||||
LARGE_INTEGER s;
|
||||
WIN32_FILE_ATTRIBUTE_DATA a;
|
||||
|
||||
auto wide = file_name.wstring();
|
||||
if (GetFileAttributesExW(wide.c_str(), GetFileExInfoStandard, &a) == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
s.HighPart = static_cast<LONG>(a.nFileSizeHigh);
|
||||
s.LowPart = a.nFileSizeLow;
|
||||
|
||||
return s.QuadPart;
|
||||
}
|
||||
|
||||
bool SysFileTruncate(sys_file_t& f, uint64_t size) {
|
||||
bool ok = false;
|
||||
if (f.type == SYS_FILE_FILE) {
|
||||
LARGE_INTEGER s {};
|
||||
LARGE_INTEGER r {};
|
||||
s.QuadPart = 0;
|
||||
SetFilePointerEx(f.handle, s, &r, FILE_CURRENT);
|
||||
s.QuadPart = static_cast<LONGLONG>(size);
|
||||
ok = (SetFilePointerEx(f.handle, s, nullptr, FILE_BEGIN) != 0 &&
|
||||
SetEndOfFile(f.handle) != 0);
|
||||
SetFilePointerEx(f.handle, r, nullptr, FILE_BEGIN);
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool SysFileUnlink(sys_file_t& f, const std::filesystem::path& name) {
|
||||
if (f.type == SYS_FILE_FILE) {
|
||||
FILE_DISPOSITION_INFO info {};
|
||||
info.DeleteFile = TRUE;
|
||||
if (SetFileInformationByHandle(f.handle, FileDispositionInfo, &info, sizeof(info)) != 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return SysFileDeleteFile(name);
|
||||
}
|
||||
|
||||
bool SysFileSeek(sys_file_t& f, uint64_t offset) {
|
||||
bool ok = true;
|
||||
if (f.type == SYS_FILE_FILE) {
|
||||
LARGE_INTEGER s;
|
||||
s.QuadPart = static_cast<LONGLONG>(offset);
|
||||
ok = (SetFilePointerEx(f.handle, s, nullptr, FILE_BEGIN) != 0);
|
||||
// printf("seek: %u\n", offset);
|
||||
} else if (f.type == SYS_FILE_MEMORY_STAT || f.type == SYS_FILE_MEMORY_DYN) {
|
||||
f.buf->ptr = f.buf->base + offset;
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
uint64_t SysFileTell(sys_file_t& f) {
|
||||
if (f.type == SYS_FILE_FILE) {
|
||||
LARGE_INTEGER s {};
|
||||
LARGE_INTEGER r {};
|
||||
s.QuadPart = 0;
|
||||
SetFilePointerEx(f.handle, s, &r, FILE_CURRENT);
|
||||
// printf("tell: %u\n", r.QuadPart);
|
||||
return r.QuadPart;
|
||||
}
|
||||
|
||||
if (f.type == SYS_FILE_MEMORY_STAT || f.type == SYS_FILE_MEMORY_DYN) {
|
||||
return f.buf->ptr - f.buf->base;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool SysFileIsError(sys_file_t& f) {
|
||||
return f.type == SYS_FILE_ERROR ||
|
||||
(f.type == SYS_FILE_FILE && f.handle == INVALID_HANDLE_VALUE);
|
||||
}
|
||||
|
||||
bool SysFileIsDirectoryExisting(const std::filesystem::path& path) {
|
||||
auto wide = path.wstring();
|
||||
DWORD a = GetFileAttributesW(wide.c_str());
|
||||
return a != INVALID_FILE_ATTRIBUTES &&
|
||||
((a & static_cast<DWORD>(FILE_ATTRIBUTE_DIRECTORY)) != 0u);
|
||||
}
|
||||
|
||||
bool SysFileIsFileExisting(const std::filesystem::path& name) {
|
||||
auto wide = name.wstring();
|
||||
DWORD a = GetFileAttributesW(wide.c_str());
|
||||
return a != INVALID_FILE_ATTRIBUTES &&
|
||||
((a & static_cast<DWORD>(FILE_ATTRIBUTE_DIRECTORY)) == 0u);
|
||||
}
|
||||
|
||||
bool SysFileCreateDirectory(const std::filesystem::path& path) {
|
||||
auto wide = path.wstring();
|
||||
return CreateDirectoryW(wide.c_str(), nullptr) != 0;
|
||||
}
|
||||
|
||||
bool SysFileDeleteDirectory(const std::filesystem::path& path) {
|
||||
auto wide = path.wstring();
|
||||
return RemoveDirectoryW(wide.c_str()) != 0;
|
||||
}
|
||||
|
||||
bool SysFileDeleteFile(const std::filesystem::path& name) {
|
||||
auto wide = name.wstring();
|
||||
return DeleteFileW(wide.c_str()) != 0;
|
||||
}
|
||||
|
||||
bool SysFileFlush(sys_file_t& f) {
|
||||
if (f.type == SYS_FILE_FILE && f.handle != INVALID_HANDLE_VALUE) {
|
||||
return (FlushFileBuffers(f.handle) != 0);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
SysFileTimeStruct SysFileGetLastAccessTimeUtc(const std::filesystem::path& name) {
|
||||
SysFileTimeStruct r {};
|
||||
sys_file_t* f = SysFileOpenR(name);
|
||||
r.is_invalid =
|
||||
(f->type == SYS_FILE_ERROR || (GetFileTime(f->handle, nullptr, &r.time, nullptr) == 0));
|
||||
SysFileClose(f);
|
||||
return r;
|
||||
}
|
||||
|
||||
SysFileTimeStruct SysFileGetLastWriteTimeUtc(const std::filesystem::path& name) {
|
||||
SysFileTimeStruct r {};
|
||||
sys_file_t* f = SysFileOpenR(name);
|
||||
r.is_invalid =
|
||||
(f->type == SYS_FILE_ERROR || (GetFileTime(f->handle, nullptr, nullptr, &r.time) == 0));
|
||||
SysFileClose(f);
|
||||
return r;
|
||||
}
|
||||
|
||||
void SysFileGetLastAccessAndWriteTimeUtc(const std::filesystem::path& name, SysFileTimeStruct& a,
|
||||
SysFileTimeStruct& w) {
|
||||
// TODO() open file with dwDesiredAccess = 0
|
||||
// TODO() open directory
|
||||
sys_file_t* f = SysFileOpenR(name);
|
||||
a.is_invalid = w.is_invalid =
|
||||
(f->type == SYS_FILE_ERROR || (GetFileTime(f->handle, nullptr, &a.time, &w.time) == 0));
|
||||
SysFileClose(f);
|
||||
}
|
||||
|
||||
void SysFileGetLastAccessAndWriteTimeUtc(sys_file_t& f, SysFileTimeStruct& a,
|
||||
SysFileTimeStruct& w) {
|
||||
if (f.type == SYS_FILE_FILE) {
|
||||
a.is_invalid = w.is_invalid = (GetFileTime(f.handle, nullptr, &a.time, &w.time) == 0);
|
||||
} else if (f.type == SYS_FILE_MEMORY_STAT || f.type == SYS_FILE_MEMORY_DYN) {
|
||||
SysTimeStruct t {};
|
||||
SysGetSystemTimeUtc(t);
|
||||
SysSystemToFileTimeUtc(t, a);
|
||||
SysSystemToFileTimeUtc(t, w);
|
||||
} else {
|
||||
a.is_invalid = w.is_invalid = true;
|
||||
}
|
||||
}
|
||||
|
||||
bool SysFileSetLastAccessTimeUtc(const std::filesystem::path& name, SysFileTimeStruct& access) {
|
||||
if (access.is_invalid) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ok = true;
|
||||
|
||||
sys_file_t* f = SysFileOpenW(name);
|
||||
|
||||
ok = !(f->type == SYS_FILE_ERROR ||
|
||||
(SetFileTime(f->handle, nullptr, &access.time, nullptr) == 0));
|
||||
|
||||
SysFileClose(f);
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool SysFileSetLastWriteTimeUtc(const std::filesystem::path& name, SysFileTimeStruct& write) {
|
||||
if (write.is_invalid) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ok = true;
|
||||
|
||||
sys_file_t* f = SysFileOpenW(name);
|
||||
|
||||
ok = !(f->type == SYS_FILE_ERROR ||
|
||||
(SetFileTime(f->handle, nullptr, nullptr, &write.time) == 0));
|
||||
|
||||
SysFileClose(f);
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool SysFileSetLastAccessAndWriteTimeUtc(const std::filesystem::path& name,
|
||||
SysFileTimeStruct& access, SysFileTimeStruct& write) {
|
||||
if (access.is_invalid || write.is_invalid) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ok = true;
|
||||
|
||||
sys_file_t* f = SysFileOpenW(name);
|
||||
|
||||
ok = !(f->type == SYS_FILE_ERROR ||
|
||||
(SetFileTime(f->handle, nullptr, &access.time, &write.time) == 0));
|
||||
|
||||
SysFileClose(f);
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
void SysFileFindFiles(const std::filesystem::path& path, std::vector<sys_file_find_t>& out) {
|
||||
std::string real_path = Common::ReplaceChar(Common::PathToGenericString(path), '\\', '/');
|
||||
if (!Common::EndsWith(real_path, "/")) {
|
||||
real_path += "/";
|
||||
}
|
||||
|
||||
std::string pattern = real_path + "*";
|
||||
|
||||
HANDLE h = nullptr;
|
||||
WIN32_FIND_DATAW data;
|
||||
|
||||
auto wide_pattern = std::filesystem::path(pattern).wstring();
|
||||
h = FindFirstFileW(wide_pattern.c_str(), &data);
|
||||
|
||||
if (h == INVALID_HANDLE_VALUE) {
|
||||
return;
|
||||
}
|
||||
|
||||
do {
|
||||
std::filesystem::path file_name(data.cFileName);
|
||||
auto file_name_str = Common::PathToString(file_name);
|
||||
|
||||
if (file_name_str == "." || file_name_str == "..") {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((data.dwFileAttributes & static_cast<DWORD>(FILE_ATTRIBUTE_DIRECTORY)) != 0u) {
|
||||
SysFileFindFiles(std::filesystem::path(real_path) / file_name, out);
|
||||
} else {
|
||||
sys_file_find_t r {};
|
||||
|
||||
r.path_with_name = std::filesystem::path(real_path) / file_name;
|
||||
r.size = (static_cast<uint64_t>(data.nFileSizeHigh) << 32u) +
|
||||
static_cast<uint64_t>(data.nFileSizeLow);
|
||||
r.last_access_time.is_invalid = false;
|
||||
r.last_access_time.time = data.ftLastAccessTime;
|
||||
r.last_write_time.is_invalid = false;
|
||||
r.last_write_time.time = data.ftLastWriteTime;
|
||||
|
||||
out.push_back(r);
|
||||
}
|
||||
|
||||
} while (FindNextFileW(h, &data) != 0);
|
||||
|
||||
FindClose(h);
|
||||
}
|
||||
|
||||
void SysFileGetDents(const std::filesystem::path& path, std::vector<sys_dir_entry_t>& out) {
|
||||
std::string real_path = Common::ReplaceChar(Common::PathToGenericString(path), '\\', '/');
|
||||
if (!Common::EndsWith(real_path, "/")) {
|
||||
real_path += "/";
|
||||
}
|
||||
|
||||
std::string pattern = real_path + "*";
|
||||
|
||||
HANDLE h = nullptr;
|
||||
WIN32_FIND_DATAW data;
|
||||
|
||||
auto wide_pattern = std::filesystem::path(pattern).wstring();
|
||||
h = FindFirstFileW(wide_pattern.c_str(), &data);
|
||||
|
||||
if (h == INVALID_HANDLE_VALUE) {
|
||||
return;
|
||||
}
|
||||
|
||||
do {
|
||||
std::filesystem::path file_name(data.cFileName);
|
||||
|
||||
sys_dir_entry_t r {};
|
||||
|
||||
r.is_file = ((data.dwFileAttributes & static_cast<DWORD>(FILE_ATTRIBUTE_DIRECTORY)) == 0u);
|
||||
r.name = Common::PathToString(file_name);
|
||||
|
||||
out.push_back(r);
|
||||
|
||||
} while (FindNextFileW(h, &data) != 0);
|
||||
|
||||
FindClose(h);
|
||||
}
|
||||
|
||||
bool SysFileCopyFile(const std::filesystem::path& src, const std::filesystem::path& dst) {
|
||||
auto src_wide = src.wstring();
|
||||
auto dst_wide = dst.wstring();
|
||||
return CopyFileW(src_wide.c_str(), dst_wide.c_str(), FALSE) != 0;
|
||||
}
|
||||
|
||||
bool SysFileMoveFile(const std::filesystem::path& src, const std::filesystem::path& dst) {
|
||||
auto src_wide = src.wstring();
|
||||
auto dst_wide = dst.wstring();
|
||||
return MoveFileW(src_wide.c_str(), dst_wide.c_str()) != 0;
|
||||
}
|
||||
|
||||
void SysFileRemoveReadonly(const std::filesystem::path& name) {
|
||||
auto wide = name.wstring();
|
||||
SetFileAttributesW(wide.c_str(), GetFileAttributesW(wide.c_str()) &
|
||||
(~static_cast<DWORD>(FILE_ATTRIBUTE_READONLY)));
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,355 @@
|
||||
#include "common/common.h"
|
||||
|
||||
#if KYTY_PLATFORM != KYTY_PLATFORM_WINDOWS
|
||||
// #error "KYTY_PLATFORM != KYTY_PLATFORM_WINDOWS"
|
||||
#else
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/platform/sysVirtual.h"
|
||||
#include "common/virtualMemory.h"
|
||||
|
||||
#include <windows.h> // IWYU pragma: keep
|
||||
|
||||
// IWYU pragma: no_include <basetsd.h>
|
||||
// IWYU pragma: no_include <errhandlingapi.h>
|
||||
// IWYU pragma: no_include <memoryapi.h>
|
||||
// IWYU pragma: no_include <minwindef.h>
|
||||
// IWYU pragma: no_include <processthreadsapi.h>
|
||||
// IWYU pragma: no_include <winbase.h>
|
||||
// IWYU pragma: no_include <winerror.h>
|
||||
// IWYU pragma: no_include <wtypes.h>
|
||||
|
||||
namespace Common {
|
||||
|
||||
static DWORD GetProtectionFlag(VirtualMemory::Mode mode) {
|
||||
DWORD protect = PAGE_NOACCESS;
|
||||
switch (mode) {
|
||||
case VirtualMemory::Mode::Read: protect = PAGE_READONLY; break;
|
||||
|
||||
case VirtualMemory::Mode::Write:
|
||||
case VirtualMemory::Mode::ReadWrite: protect = PAGE_READWRITE; break;
|
||||
|
||||
case VirtualMemory::Mode::Execute: protect = PAGE_EXECUTE; break;
|
||||
|
||||
case VirtualMemory::Mode::ExecuteRead: protect = PAGE_EXECUTE_READ; break;
|
||||
|
||||
case VirtualMemory::Mode::ExecuteWrite:
|
||||
case VirtualMemory::Mode::ExecuteReadWrite: protect = PAGE_EXECUTE_READWRITE; break;
|
||||
|
||||
case VirtualMemory::Mode::NoAccess:
|
||||
default: protect = PAGE_NOACCESS; break;
|
||||
}
|
||||
return protect;
|
||||
}
|
||||
|
||||
static VirtualMemory::Mode GetProtectionFlag(DWORD mode) {
|
||||
switch (mode) {
|
||||
case PAGE_NOACCESS: return VirtualMemory::Mode::NoAccess;
|
||||
case PAGE_READONLY: return VirtualMemory::Mode::Read;
|
||||
case PAGE_READWRITE: return VirtualMemory::Mode::ReadWrite;
|
||||
case PAGE_EXECUTE: return VirtualMemory::Mode::Execute;
|
||||
case PAGE_EXECUTE_READ: return VirtualMemory::Mode::ExecuteRead;
|
||||
case PAGE_EXECUTE_READWRITE: return VirtualMemory::Mode::ExecuteReadWrite;
|
||||
default: return VirtualMemory::Mode::NoAccess;
|
||||
}
|
||||
}
|
||||
|
||||
void SysVirtualInit() {}
|
||||
|
||||
uint64_t SysVirtualAlloc(uint64_t address, uint64_t size, VirtualMemory::Mode mode) {
|
||||
auto ptr = (address == 0 ? SysVirtualAllocAligned(address, size, mode, 1)
|
||||
: reinterpret_cast<uintptr_t>(VirtualAlloc(
|
||||
reinterpret_cast<LPVOID>(static_cast<uintptr_t>(address)), size,
|
||||
static_cast<DWORD>(MEM_COMMIT) | static_cast<DWORD>(MEM_RESERVE),
|
||||
GetProtectionFlag(mode))));
|
||||
if (ptr == 0) {
|
||||
auto err = static_cast<uint32_t>(GetLastError());
|
||||
|
||||
if (err != ERROR_INVALID_ADDRESS) {
|
||||
printf("VirtualAlloc() failed: 0x%08" PRIx32 "\n", err);
|
||||
} else {
|
||||
return SysVirtualAllocAligned(address, size, mode, 1);
|
||||
}
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
using VirtualAlloc2_func_t = /*WINBASEAPI*/ PVOID WINAPI (*)(HANDLE, PVOID, SIZE_T, ULONG, ULONG,
|
||||
MEM_EXTENDED_PARAMETER*, ULONG);
|
||||
|
||||
static VirtualAlloc2_func_t ResolveVirtualAlloc2() {
|
||||
HMODULE h = GetModuleHandle("KernelBase"); // @suppress("Invalid arguments")
|
||||
if (h != nullptr) {
|
||||
return reinterpret_cast<VirtualAlloc2_func_t>(GetProcAddress(h, "VirtualAlloc2"));
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static uint64_t AlignUp(uint64_t addr, uint64_t alignment) {
|
||||
return (addr + alignment - 1) & ~(alignment - 1);
|
||||
}
|
||||
|
||||
uint64_t SysVirtualAllocAligned(uint64_t address, uint64_t size, VirtualMemory::Mode mode,
|
||||
uint64_t alignment) {
|
||||
if (alignment == 0) {
|
||||
printf("VirtualAlloc2 failed: 0x%08" PRIx32 "\n", static_cast<uint32_t>(GetLastError()));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static constexpr uint64_t SYSTEM_MANAGED_MIN = 0x0000040000u;
|
||||
static constexpr uint64_t SYSTEM_MANAGED_MAX = 0x07FFFFBFFFu;
|
||||
static constexpr uint64_t USER_MIN = 0x1000000000u;
|
||||
static constexpr uint64_t USER_MAX = 0xFBFFFFFFFFu;
|
||||
|
||||
MEM_ADDRESS_REQUIREMENTS req {};
|
||||
MEM_EXTENDED_PARAMETER param {};
|
||||
req.LowestStartingAddress =
|
||||
(address == 0 ? reinterpret_cast<PVOID>(SYSTEM_MANAGED_MIN)
|
||||
: reinterpret_cast<PVOID>(AlignUp(address, alignment)));
|
||||
req.HighestEndingAddress = (address == 0 ? reinterpret_cast<PVOID>(SYSTEM_MANAGED_MAX)
|
||||
: reinterpret_cast<PVOID>(USER_MAX));
|
||||
req.Alignment = alignment;
|
||||
param.Type = MemExtendedParameterAddressRequirements;
|
||||
param.Pointer = &req;
|
||||
|
||||
MEM_ADDRESS_REQUIREMENTS req2 {};
|
||||
MEM_EXTENDED_PARAMETER param2 {};
|
||||
req2.LowestStartingAddress =
|
||||
(address == 0 ? reinterpret_cast<PVOID>(USER_MIN)
|
||||
: reinterpret_cast<PVOID>(AlignUp(address, alignment)));
|
||||
req2.HighestEndingAddress = reinterpret_cast<PVOID>(USER_MAX);
|
||||
req2.Alignment = alignment;
|
||||
param2.Type = MemExtendedParameterAddressRequirements;
|
||||
param2.Pointer = &req2;
|
||||
|
||||
static auto virtual_alloc2 = ResolveVirtualAlloc2();
|
||||
|
||||
EXIT_NOT_IMPLEMENTED(virtual_alloc2 == nullptr);
|
||||
|
||||
auto ptr = reinterpret_cast<uintptr_t>(
|
||||
virtual_alloc2(GetCurrentProcess(), nullptr, size,
|
||||
static_cast<DWORD>(MEM_COMMIT) | static_cast<DWORD>(MEM_RESERVE),
|
||||
GetProtectionFlag(mode), ¶m, 1));
|
||||
|
||||
if (ptr == 0) {
|
||||
ptr = reinterpret_cast<uintptr_t>(
|
||||
virtual_alloc2(GetCurrentProcess(), nullptr, size,
|
||||
static_cast<DWORD>(MEM_COMMIT) | static_cast<DWORD>(MEM_RESERVE),
|
||||
GetProtectionFlag(mode), ¶m2, 1));
|
||||
}
|
||||
|
||||
if (ptr == 0) {
|
||||
auto err = static_cast<uint32_t>(GetLastError());
|
||||
if (err != ERROR_INVALID_PARAMETER) {
|
||||
printf("VirtualAlloc2(alignment = 0x%016" PRIx64 ") failed: 0x%08" PRIx32 "\n",
|
||||
alignment, err);
|
||||
} else {
|
||||
return SysVirtualAllocAligned(address, size, mode, alignment << 1u);
|
||||
}
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
bool SysVirtualAllocFixed(uint64_t address, uint64_t size, VirtualMemory::Mode mode) {
|
||||
auto ptr = reinterpret_cast<uintptr_t>(VirtualAlloc(
|
||||
reinterpret_cast<LPVOID>(static_cast<uintptr_t>(address)), size,
|
||||
static_cast<DWORD>(MEM_COMMIT) | static_cast<DWORD>(MEM_RESERVE), GetProtectionFlag(mode)));
|
||||
if (ptr == 0) {
|
||||
auto err = static_cast<uint32_t>(GetLastError());
|
||||
|
||||
printf("VirtualAlloc() failed: 0x%08" PRIx32 "\n", err);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ptr != address) {
|
||||
printf("VirtualAlloc() failed: wrong address\n");
|
||||
VirtualFree(reinterpret_cast<LPVOID>(ptr), 0, MEM_RELEASE);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SysVirtualCommit(uint64_t address, uint64_t size, VirtualMemory::Mode mode) {
|
||||
auto ptr = reinterpret_cast<uintptr_t>(
|
||||
VirtualAlloc(reinterpret_cast<LPVOID>(static_cast<uintptr_t>(address)), size,
|
||||
static_cast<DWORD>(MEM_COMMIT), GetProtectionFlag(mode)));
|
||||
if (ptr == 0) {
|
||||
printf("VirtualAlloc(MEM_COMMIT) failed: 0x%08" PRIx32 "\n",
|
||||
static_cast<uint32_t>(GetLastError()));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ptr != address) {
|
||||
printf("VirtualAlloc(MEM_COMMIT) failed: wrong address\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint64_t SysVirtualReserve(uint64_t address, uint64_t size) {
|
||||
auto ptr = (address == 0 ? SysVirtualReserveAligned(address, size, 1)
|
||||
: reinterpret_cast<uintptr_t>(VirtualAlloc(
|
||||
reinterpret_cast<LPVOID>(static_cast<uintptr_t>(address)), size,
|
||||
static_cast<DWORD>(MEM_RESERVE), PAGE_NOACCESS)));
|
||||
if (ptr == 0) {
|
||||
auto err = static_cast<uint32_t>(GetLastError());
|
||||
|
||||
if (err != ERROR_INVALID_ADDRESS) {
|
||||
printf("VirtualAlloc(MEM_RESERVE) failed: 0x%08" PRIx32 "\n", err);
|
||||
} else {
|
||||
return SysVirtualReserveAligned(address, size, 1);
|
||||
}
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
uint64_t SysVirtualReserveAligned(uint64_t address, uint64_t size, uint64_t alignment) {
|
||||
if (alignment == 0) {
|
||||
printf("VirtualAlloc2(MEM_RESERVE) failed: 0x%08" PRIx32 "\n",
|
||||
static_cast<uint32_t>(GetLastError()));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static constexpr uint64_t SYSTEM_MANAGED_MIN = 0x0000040000u;
|
||||
static constexpr uint64_t SYSTEM_MANAGED_MAX = 0x07FFFFBFFFu;
|
||||
static constexpr uint64_t USER_MIN = 0x1000000000u;
|
||||
static constexpr uint64_t USER_MAX = 0xFBFFFFFFFFu;
|
||||
|
||||
MEM_ADDRESS_REQUIREMENTS req {};
|
||||
MEM_EXTENDED_PARAMETER param {};
|
||||
req.LowestStartingAddress =
|
||||
(address == 0 ? reinterpret_cast<PVOID>(SYSTEM_MANAGED_MIN)
|
||||
: reinterpret_cast<PVOID>(AlignUp(address, alignment)));
|
||||
req.HighestEndingAddress = (address == 0 ? reinterpret_cast<PVOID>(SYSTEM_MANAGED_MAX)
|
||||
: reinterpret_cast<PVOID>(USER_MAX));
|
||||
req.Alignment = alignment;
|
||||
param.Type = MemExtendedParameterAddressRequirements;
|
||||
param.Pointer = &req;
|
||||
|
||||
MEM_ADDRESS_REQUIREMENTS req2 {};
|
||||
MEM_EXTENDED_PARAMETER param2 {};
|
||||
req2.LowestStartingAddress =
|
||||
(address == 0 ? reinterpret_cast<PVOID>(USER_MIN)
|
||||
: reinterpret_cast<PVOID>(AlignUp(address, alignment)));
|
||||
req2.HighestEndingAddress = reinterpret_cast<PVOID>(USER_MAX);
|
||||
req2.Alignment = alignment;
|
||||
param2.Type = MemExtendedParameterAddressRequirements;
|
||||
param2.Pointer = &req2;
|
||||
|
||||
static auto virtual_alloc2 = ResolveVirtualAlloc2();
|
||||
|
||||
EXIT_NOT_IMPLEMENTED(virtual_alloc2 == nullptr);
|
||||
|
||||
auto ptr = reinterpret_cast<uintptr_t>(virtual_alloc2(GetCurrentProcess(), nullptr, size,
|
||||
static_cast<DWORD>(MEM_RESERVE),
|
||||
PAGE_NOACCESS, ¶m, 1));
|
||||
|
||||
if (ptr == 0) {
|
||||
ptr = reinterpret_cast<uintptr_t>(virtual_alloc2(GetCurrentProcess(), nullptr, size,
|
||||
static_cast<DWORD>(MEM_RESERVE),
|
||||
PAGE_NOACCESS, ¶m2, 1));
|
||||
}
|
||||
|
||||
if (ptr == 0) {
|
||||
auto err = static_cast<uint32_t>(GetLastError());
|
||||
if (err != ERROR_INVALID_PARAMETER) {
|
||||
printf("VirtualAlloc2(MEM_RESERVE, alignment = 0x%016" PRIx64 ") failed: 0x%08" PRIx32
|
||||
"\n",
|
||||
alignment, err);
|
||||
} else {
|
||||
return SysVirtualReserveAligned(address, size, alignment << 1u);
|
||||
}
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
bool SysVirtualReserveFixed(uint64_t address, uint64_t size) {
|
||||
auto ptr = reinterpret_cast<uintptr_t>(
|
||||
VirtualAlloc(reinterpret_cast<LPVOID>(static_cast<uintptr_t>(address)), size,
|
||||
static_cast<DWORD>(MEM_RESERVE), PAGE_NOACCESS));
|
||||
if (ptr == 0) {
|
||||
printf("VirtualAlloc(MEM_RESERVE) failed: address=0x%016" PRIx64 ", size=0x%016" PRIx64
|
||||
", err=0x%08" PRIx32 "\n",
|
||||
address, size, static_cast<uint32_t>(GetLastError()));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ptr != address) {
|
||||
printf("VirtualAlloc(MEM_RESERVE) failed: wrong address\n");
|
||||
VirtualFree(reinterpret_cast<LPVOID>(ptr), 0, MEM_RELEASE);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SysVirtualDecommit(uint64_t address, uint64_t size) {
|
||||
if (VirtualFree(reinterpret_cast<LPVOID>(static_cast<uintptr_t>(address)), size,
|
||||
MEM_DECOMMIT) == 0) {
|
||||
printf("VirtualFree(MEM_DECOMMIT) failed: 0x%08" PRIx32 "\n",
|
||||
static_cast<uint32_t>(GetLastError()));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SysVirtualFree(uint64_t address) {
|
||||
if (VirtualFree(reinterpret_cast<LPVOID>(static_cast<uintptr_t>(address)), 0, MEM_RELEASE) ==
|
||||
0) {
|
||||
printf("VirtualFree() failed: 0x%08" PRIx32 "\n", static_cast<uint32_t>(GetLastError()));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SysVirtualFreeRange(uint64_t address, uint64_t size) {
|
||||
if (address == 0 || size == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint64_t current = address;
|
||||
while (current - address < size) {
|
||||
MEMORY_BASIC_INFORMATION info {};
|
||||
if (VirtualQuery(reinterpret_cast<const void*>(current), &info, sizeof(info)) == 0 ||
|
||||
reinterpret_cast<uint64_t>(info.AllocationBase) != address || info.State == MEM_FREE) {
|
||||
return false;
|
||||
}
|
||||
const auto next = reinterpret_cast<uint64_t>(info.BaseAddress) + info.RegionSize;
|
||||
if (next <= current || next - address > size) {
|
||||
return false;
|
||||
}
|
||||
current = next;
|
||||
}
|
||||
return current - address == size && SysVirtualFree(address);
|
||||
}
|
||||
|
||||
bool SysVirtualProtect(uint64_t address, uint64_t size, VirtualMemory::Mode mode,
|
||||
VirtualMemory::Mode* old_mode) {
|
||||
DWORD old_protect = 0;
|
||||
if (VirtualProtect(reinterpret_cast<LPVOID>(static_cast<uintptr_t>(address)), size,
|
||||
GetProtectionFlag(mode), &old_protect) == 0) {
|
||||
printf("VirtualProtect() failed: 0x%08" PRIx32 "\n", static_cast<uint32_t>(GetLastError()));
|
||||
return false;
|
||||
}
|
||||
if (old_mode != nullptr) {
|
||||
*old_mode = GetProtectionFlag(old_protect);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SysVirtualFlushInstructionCache(uint64_t address, uint64_t size) {
|
||||
if (::FlushInstructionCache(GetCurrentProcess(),
|
||||
reinterpret_cast<LPVOID>(static_cast<uintptr_t>(address)),
|
||||
size) == 0) {
|
||||
printf("FlushInstructionCache() failed: 0x%08" PRIx32 "\n",
|
||||
static_cast<uint32_t>(GetLastError()));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace Common
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user