loader, libs: runtime linker and Ampr fixes for this title

Runtime linker relocation and fault handling, plus the Ampr and Audio2 paths
this title exercises during startup.
This commit is contained in:
Mac
2026-08-31 23:41:55 +05:30
parent 0551010010
commit f625a478ab
4 changed files with 366 additions and 30 deletions
+206 -20
View File
@@ -3,6 +3,8 @@
#include "common/file.h" #include "common/file.h"
#include "common/logging/log.h" #include "common/logging/log.h"
#include "common/stringUtils.h" #include "common/stringUtils.h"
#include "common/timer.h"
#include "common/threads.h"
#include "kernel/eventQueue.h" #include "kernel/eventQueue.h"
#include "kernel/fileSystem.h" #include "kernel/fileSystem.h"
#include "kernel/memory.h" #include "kernel/memory.h"
@@ -10,11 +12,18 @@
#include "libs/libs.h" #include "libs/libs.h"
#include "loader/symbolDatabase.h" #include "loader/symbolDatabase.h"
#if KYTY_PLATFORM == KYTY_PLATFORM_WINDOWS
#define WIN32_LEAN_AND_MEAN
#include <memory>
#include <windows.h>
#endif
#include <algorithm> #include <algorithm>
#include <array> #include <array>
#include <cstdint> #include <cstdint>
#include <cstring> #include <cstring>
#include <limits> #include <limits>
#include <atomic>
#include <mutex> #include <mutex>
#include <string> #include <string>
#include <unordered_map> #include <unordered_map>
@@ -66,6 +75,31 @@ static bool IsValidGuestRange(uint64_t addr, uint64_t size, bool write = false)
return addr != 0 && addr <= std::numeric_limits<uint64_t>::max() - size; return addr != 0 && addr <= std::numeric_limits<uint64_t>::max() - size;
} }
static bool IsGuestRangeCommitted(uint64_t addr, uint64_t size) {
#if KYTY_PLATFORM == KYTY_PLATFORM_WINDOWS
uint64_t checked = 0;
while (checked < size) {
MEMORY_BASIC_INFORMATION mbi {};
if (VirtualQuery(reinterpret_cast<const void*>(addr + checked), &mbi, sizeof(mbi)) == 0) {
return false;
}
if (mbi.State != MEM_COMMIT) {
return false;
}
const auto region_end =
reinterpret_cast<uint64_t>(mbi.BaseAddress) + static_cast<uint64_t>(mbi.RegionSize);
if (region_end <= addr + checked) {
return false;
}
checked = region_end - addr;
}
#else
(void)addr;
(void)size;
#endif
return true;
}
static bool ReadGuestBytes(uint64_t addr, void* out, uint64_t size) { static bool ReadGuestBytes(uint64_t addr, void* out, uint64_t size) {
if (out == nullptr || !IsValidGuestRange(addr, size)) { if (out == nullptr || !IsValidGuestRange(addr, size)) {
return false; return false;
@@ -667,6 +701,11 @@ static int KYTY_SYSV_ABI ResolveFilepathsWithPrefixToIdsAndFileSizesForEach(
AprShared::ResolvePathsCommon(path_list, count, ids, sizes, nullptr, prefix_buf, results)); AprShared::ResolvePathsCommon(path_list, count, ids, sizes, nullptr, prefix_buf, results));
} }
static uint64_t AprTracedAddr() {
constexpr uint64_t traced = 0ull;
return traced;
}
static int KYTY_SYSV_ABI SubmitCommandBufferAndGetResult(void* command_buffer, uint64_t, static int KYTY_SYSV_ABI SubmitCommandBufferAndGetResult(void* command_buffer, uint64_t,
void* result, void* result,
uint32_t* out_submission_id) { uint32_t* out_submission_id) {
@@ -816,7 +855,7 @@ constexpr int PROT_AMPR_READ = 0x40;
constexpr int PROT_AMPR_WRITE = 0x80; constexpr int PROT_AMPR_WRITE = 0x80;
constexpr int PROT_ACP_READ = 0x100; constexpr int PROT_ACP_READ = 0x100;
constexpr int PROT_ACP_WRITE = 0x200; constexpr int PROT_ACP_WRITE = 0x200;
constexpr uint64_t AMM_VA_START = 0x0000001000000000ull; constexpr uint64_t AMM_VA_START = 0x0000004000000000ull;
constexpr uint64_t AMM_VA_SIZE = 0x0000001000000000ull; constexpr uint64_t AMM_VA_SIZE = 0x0000001000000000ull;
constexpr uint64_t APR_MAX_READ_LENGTH = 0x0000000100000000ull; constexpr uint64_t APR_MAX_READ_LENGTH = 0x0000000100000000ull;
constexpr uint64_t APR_MAX_FILE_OFFSET = 0x0000010000000000ull; constexpr uint64_t APR_MAX_FILE_OFFSET = 0x0000010000000000ull;
@@ -825,6 +864,14 @@ constexpr uint64_t APR_HOST_READ_CHUNK_SIZE = 4 * 1024 * 1024;
constexpr uint32_t APR_TYPE_GATHER_SCATTER_VALID = 0x00010000; constexpr uint32_t APR_TYPE_GATHER_SCATTER_VALID = 0x00010000;
constexpr uint32_t APR_TYPE_MAP_ACTIVE = 0x00020000; constexpr uint32_t APR_TYPE_MAP_ACTIVE = 0x00020000;
constexpr uint32_t AMPR_WAIT_COMPARE_EQUAL = 0;
constexpr uint32_t AMPR_WAIT_COMPARE_GREATER_THAN_UNSIGNED = 1;
constexpr uint32_t AMPR_WAIT_COMPARE_LESS_THAN_UNSIGNED = 2;
constexpr uint32_t AMPR_WAIT_COMPARE_NOT_EQUAL = 3;
constexpr uint32_t AMPR_WAIT_COMPARE_GREATER_THAN_OR_EQUAL_WRAPPED = 4;
constexpr uint32_t AMPR_WAIT_COMPARE_GREATER_THAN_SIGNED = 5;
constexpr uint32_t AMPR_WAIT_COMPARE_LESS_THAN_SIGNED = 6;
enum class AmmCommandKind : uint32_t { enum class AmmCommandKind : uint32_t {
MapAuto, MapAuto,
MapDirect, MapDirect,
@@ -855,6 +902,12 @@ struct CommandBufferState {
uint64_t address = 0; uint64_t address = 0;
uint64_t value = 0; uint64_t value = 0;
}; };
struct WaitAddressCommand {
uint64_t record_offset = 0;
uint64_t address = 0;
uint64_t ref_value = 0;
uint32_t compare = 0;
};
struct AmmMapCommand { struct AmmMapCommand {
uint64_t record_offset = 0; uint64_t record_offset = 0;
AmmCommandKind kind = AmmCommandKind::MapAuto; AmmCommandKind kind = AmmCommandKind::MapAuto;
@@ -868,6 +921,7 @@ struct CommandBufferState {
std::vector<ReadFileCommand> read_file_commands; std::vector<ReadFileCommand> read_file_commands;
std::vector<KernelEventCommand> kernel_event_commands; std::vector<KernelEventCommand> kernel_event_commands;
std::vector<WriteAddressCommand> write_address_commands; std::vector<WriteAddressCommand> write_address_commands;
std::vector<WaitAddressCommand> wait_address_commands;
std::vector<AmmMapCommand> amm_map_commands; std::vector<AmmMapCommand> amm_map_commands;
bool gather_scatter_valid = false; bool gather_scatter_valid = false;
uint32_t gather_scatter_file_id = 0; uint32_t gather_scatter_file_id = 0;
@@ -907,7 +961,8 @@ using CommandBufferIterator = std::unordered_map<uint64_t, CommandBufferState>::
static bool HasQueuedCommands(const CommandBufferState& state) { static bool HasQueuedCommands(const CommandBufferState& state) {
return !state.read_file_commands.empty() || !state.kernel_event_commands.empty() || return !state.read_file_commands.empty() || !state.kernel_event_commands.empty() ||
!state.write_address_commands.empty() || !state.amm_map_commands.empty(); !state.write_address_commands.empty() || !state.wait_address_commands.empty() ||
!state.amm_map_commands.empty();
} }
static void RegisterCommandBufferAliasLocked(uint64_t command_buffer, uint64_t buffer) { static void RegisterCommandBufferAliasLocked(uint64_t command_buffer, uint64_t buffer) {
@@ -1150,6 +1205,7 @@ static bool WriteCommandBufferPointers(uint64_t command_buffer, uint64_t buffer,
state.read_file_commands.clear(); state.read_file_commands.clear();
state.kernel_event_commands.clear(); state.kernel_event_commands.clear();
state.write_address_commands.clear(); state.write_address_commands.clear();
state.wait_address_commands.clear();
state.amm_map_commands.clear(); state.amm_map_commands.clear();
state.gather_scatter_valid = false; state.gather_scatter_valid = false;
state.gather_scatter_file_id = 0; state.gather_scatter_file_id = 0;
@@ -1317,6 +1373,26 @@ static bool AppendWriteAddressRecord(uint64_t command_buffer, uint64_t address,
return CommitCommandBufferRecord(command_buffer, &state, record_size); return CommitCommandBufferRecord(command_buffer, &state, record_size);
} }
static bool AppendWaitAddressRecord(uint64_t command_buffer, uint64_t address, uint64_t ref_value,
uint32_t compare, uint64_t record_size = 0x20) {
std::scoped_lock lock(g_command_buffer_mutex);
CommandBufferIterator it;
if (!GetOrCreateCommandBufferStateLocked(command_buffer, &it)) {
return false;
}
auto& state = it->second;
if (!EnsureCommandBufferRecordSpace(command_buffer, &state, record_size)) {
return false;
}
const auto record_offset = state.write_offset;
std::memset(reinterpret_cast<void*>(state.buffer + record_offset), 0,
static_cast<size_t>(record_size));
state.wait_address_commands.push_back({record_offset, address, ref_value, compare});
return CommitCommandBufferRecord(command_buffer, &state, record_size);
}
static bool ValidateAmmMapArgs(uint64_t va, uint64_t size) { static bool ValidateAmmMapArgs(uint64_t va, uint64_t size) {
return va != 0 && size != 0 && (va & (AMM_PAGE_SIZE - 1u)) == 0 && return va != 0 && size != 0 && (va & (AMM_PAGE_SIZE - 1u)) == 0 &&
(size & (AMM_PAGE_SIZE - 1u)) == 0 && va + size >= va; (size & (AMM_PAGE_SIZE - 1u)) == 0 && va + size >= va;
@@ -1444,6 +1520,7 @@ static int ExecuteAprCommandBuffer(uint64_t command_buffer, int32_t* execution_r
ReadFile, ReadFile,
KernelEvent, KernelEvent,
WriteAddress, WriteAddress,
WaitAddress,
AmmMap, AmmMap,
}; };
@@ -1455,7 +1532,8 @@ static int ExecuteAprCommandBuffer(uint64_t command_buffer, int32_t* execution_r
std::vector<OrderedCommand> ordered; std::vector<OrderedCommand> ordered;
ordered.reserve(state.read_file_commands.size() + state.kernel_event_commands.size() + ordered.reserve(state.read_file_commands.size() + state.kernel_event_commands.size() +
state.write_address_commands.size() + state.amm_map_commands.size()); state.write_address_commands.size() + state.wait_address_commands.size() +
state.amm_map_commands.size());
for (size_t i = 0; i < state.read_file_commands.size(); i++) { for (size_t i = 0; i < state.read_file_commands.size(); i++) {
if (state.read_file_commands[i].record_offset < state.write_offset) { if (state.read_file_commands[i].record_offset < state.write_offset) {
ordered.push_back( ordered.push_back(
@@ -1474,6 +1552,12 @@ static int ExecuteAprCommandBuffer(uint64_t command_buffer, int32_t* execution_r
{state.write_address_commands[i].record_offset, CommandKind::WriteAddress, i}); {state.write_address_commands[i].record_offset, CommandKind::WriteAddress, i});
} }
} }
for (size_t i = 0; i < state.wait_address_commands.size(); i++) {
if (state.wait_address_commands[i].record_offset < state.write_offset) {
ordered.push_back(
{state.wait_address_commands[i].record_offset, CommandKind::WaitAddress, i});
}
}
for (size_t i = 0; i < state.amm_map_commands.size(); i++) { for (size_t i = 0; i < state.amm_map_commands.size(); i++) {
if (state.amm_map_commands[i].record_offset < state.write_offset) { if (state.amm_map_commands[i].record_offset < state.write_offset) {
ordered.push_back({state.amm_map_commands[i].record_offset, CommandKind::AmmMap, i}); ordered.push_back({state.amm_map_commands[i].record_offset, CommandKind::AmmMap, i});
@@ -1484,6 +1568,16 @@ static int ExecuteAprCommandBuffer(uint64_t command_buffer, int32_t* execution_r
return a.record_offset < b.record_offset; return a.record_offset < b.record_offset;
}); });
static std::mutex g_apr_execution_mutex;
std::unique_lock execution_lock(g_apr_execution_mutex);
static std::atomic<int32_t> in_flight {0};
const auto depth = in_flight.fetch_add(1, std::memory_order_relaxed) + 1;
struct DepthGuard {
std::atomic<int32_t>* counter;
~DepthGuard() { counter->fetch_sub(1, std::memory_order_relaxed); }
} depth_guard {&in_flight};
for (const auto& entry: ordered) { for (const auto& entry: ordered) {
switch (entry.kind) { switch (entry.kind) {
case CommandKind::ReadFile: { case CommandKind::ReadFile: {
@@ -1497,6 +1591,9 @@ static int ExecuteAprCommandBuffer(uint64_t command_buffer, int32_t* execution_r
return OK; return OK;
} }
{
}
uint64_t bytes_read = 0; uint64_t bytes_read = 0;
auto result = ReadHostFileToGuest(host_path, command.file_offset, auto result = ReadHostFileToGuest(host_path, command.file_offset,
command.destination, command.size, &bytes_read); command.destination, command.size, &bytes_read);
@@ -1523,8 +1620,66 @@ static int ExecuteAprCommandBuffer(uint64_t command_buffer, int32_t* execution_r
return OK; return OK;
} }
} break; } break;
case CommandKind::WaitAddress: {
const auto& command = state.wait_address_commands[entry.index];
const auto satisfied = [&command](uint64_t observed) {
const auto ref = command.ref_value;
const auto signed_observed = static_cast<int64_t>(observed);
const auto signed_ref = static_cast<int64_t>(ref);
switch (command.compare) {
case AMPR_WAIT_COMPARE_EQUAL: return observed == ref;
case AMPR_WAIT_COMPARE_GREATER_THAN_UNSIGNED: return observed > ref;
case AMPR_WAIT_COMPARE_LESS_THAN_UNSIGNED: return observed < ref;
case AMPR_WAIT_COMPARE_NOT_EQUAL: return observed != ref;
case AMPR_WAIT_COMPARE_GREATER_THAN_OR_EQUAL_WRAPPED:
return static_cast<int64_t>(observed - ref) >= 0;
case AMPR_WAIT_COMPARE_GREATER_THAN_SIGNED:
return signed_observed > signed_ref;
case AMPR_WAIT_COMPARE_LESS_THAN_SIGNED: return signed_observed < signed_ref;
default: return true;
}
};
constexpr uint32_t WaitPollMicros = 50;
constexpr double WaitSpinSeconds = 0.0002;
constexpr double WaitTimeoutSecond = 0.1;
Common::Timer wait_timer;
wait_timer.Start();
execution_lock.unlock();
uint64_t observed = 0;
bool done = false;
for (;;) {
if (!AprShared::ReadGuest(command.address, &observed)) {
break;
}
if (satisfied(observed)) {
done = true;
break;
}
if (wait_timer.GetTimeS() >= WaitTimeoutSecond) {
break;
}
if (wait_timer.GetTimeS() < WaitSpinSeconds) {
Common::Thread::SleepNano(0);
} else {
Common::Thread::SleepMicro(WaitPollMicros);
}
}
execution_lock.lock();
if (!done) {
static const bool abort_on_timeout =
false;
if (abort_on_timeout) {
*execution_result = LibKernel::KERNEL_ERROR_ETIMEDOUT;
*error_offset = static_cast<uint32_t>(command.record_offset);
return OK;
}
}
} break;
case CommandKind::WriteAddress: { case CommandKind::WriteAddress: {
const auto& command = state.write_address_commands[entry.index]; const auto& command = state.write_address_commands[entry.index];
constexpr uint64_t traced_addr = 0ull;
if (!AprShared::WriteGuest(command.address, command.value)) { if (!AprShared::WriteGuest(command.address, command.value)) {
LOGF("\tAMPR submit write-address failed: address=0x%016" PRIx64 LOGF("\tAMPR submit write-address failed: address=0x%016" PRIx64
" value=0x%016" PRIx64 "\n", " value=0x%016" PRIx64 "\n",
@@ -1588,46 +1743,65 @@ static int ReadHostFileToGuest(const std::string& host_path, uint64_t file_offse
if (size == 0) { if (size == 0) {
return OK; return OK;
} }
if (!AprShared::IsValidGuestRange(destination, size, true)) { if (!AprShared::IsValidGuestRange(destination, size, true) ||
!AprShared::IsGuestRangeCommitted(destination, size)) {
return LibKernel::KERNEL_ERROR_EFAULT; return LibKernel::KERNEL_ERROR_EFAULT;
} }
struct CachedFile {
std::string path;
Common::File file; Common::File file;
if (!file.Open(host_path, Common::File::Mode::Read)) { uint64_t size = 0;
LOGF("\tAPR read missing host file: %s\n", host_path.c_str()); };
static thread_local std::vector<std::unique_ptr<CachedFile>> cache;
CachedFile* entry = nullptr;
for (auto& candidate: cache) {
if (candidate->path == host_path) {
entry = candidate.get();
break;
}
}
if (entry == nullptr) {
if (cache.size() >= 16) {
cache.front()->file.Close();
cache.erase(cache.begin());
}
auto opened = std::make_unique<CachedFile>();
opened->path = host_path;
if (!opened->file.Open(host_path, Common::File::Mode::Read)) {
return LibKernel::KERNEL_ERROR_ENOENT; return LibKernel::KERNEL_ERROR_ENOENT;
} }
const auto file_size = file.Size(); opened->size = opened->file.Size();
cache.push_back(std::move(opened));
entry = cache.back().get();
}
auto& file = entry->file;
const auto file_size = entry->size;
if (file_offset >= file_size) { if (file_offset >= file_size) {
file.Close();
return OK; return OK;
} }
if (!file.Seek(file_offset)) { if (!file.Seek(file_offset)) {
file.Close();
return LibKernel::KERNEL_ERROR_EINVAL; return LibKernel::KERNEL_ERROR_EINVAL;
} }
const auto readable = std::min<uint64_t>(size, file_size - file_offset); const auto readable = std::min<uint64_t>(size, file_size - file_offset);
if (readable == 0) { if (readable == 0) {
file.Close();
return OK; return OK;
} }
std::vector<uint8_t> buffer(
static_cast<size_t>(std::min<uint64_t>(APR_HOST_READ_CHUNK_SIZE, readable)));
while (*bytes_read < readable) { while (*bytes_read < readable) {
const auto request = const auto request = static_cast<uint32_t>(
static_cast<uint32_t>(std::min<uint64_t>(buffer.size(), readable - *bytes_read)); std::min<uint64_t>(APR_HOST_READ_CHUNK_SIZE, readable - *bytes_read));
uint32_t read = 0; uint32_t read = 0;
file.Read(buffer.data(), request, &read); file.Read(reinterpret_cast<void*>(destination + *bytes_read), request, &read);
if (read == 0) { if (read == 0) {
break; break;
} }
std::memcpy(reinterpret_cast<void*>(destination + *bytes_read), buffer.data(), read);
*bytes_read += read; *bytes_read += read;
} }
file.Close();
return OK; return OK;
} }
@@ -2111,11 +2285,22 @@ static int KYTY_SYSV_ABI CommandBufferPopMarker(void* command_buffer) {
return AppendNoOpCommand(command_buffer, sizeof(uint32_t)); return AppendNoOpCommand(command_buffer, sizeof(uint32_t));
} }
static int KYTY_SYSV_ABI CommandBufferWaitOnAddress(void* command_buffer, volatile uint64_t*, static int KYTY_SYSV_ABI CommandBufferWaitOnAddress(void* command_buffer,
uint64_t, uint8_t, uint8_t) { volatile uint64_t* address, uint64_t ref_value,
uint8_t compare, uint8_t flush) {
PRINT_NAME(); PRINT_NAME();
return AppendNoOpCommand(command_buffer, 0x20); (void)flush;
if (command_buffer == nullptr || address == nullptr) {
return LibKernel::KERNEL_ERROR_EINVAL;
}
if (compare > AMPR_WAIT_COMPARE_LESS_THAN_SIGNED) {
return LibKernel::KERNEL_ERROR_EINVAL;
}
return AppendWaitAddressRecord(reinterpret_cast<uint64_t>(command_buffer),
reinterpret_cast<uint64_t>(address), ref_value, compare)
? OK
: LibKernel::KERNEL_ERROR_EBUSY;
} }
static int KYTY_SYSV_ABI CommandBufferWaitOnCounter(void* command_buffer, uint8_t, uint8_t, static int KYTY_SYSV_ABI CommandBufferWaitOnCounter(void* command_buffer, uint8_t, uint8_t,
@@ -2665,6 +2850,7 @@ LIB_DEFINE(InitAmpr_1_Ampr) {
LIB_FUNC("dXPaz65HNmk", Ampr::CommandBufferPushMarker); LIB_FUNC("dXPaz65HNmk", Ampr::CommandBufferPushMarker);
LIB_FUNC("mv0O8Zg0woU", Ampr::CommandBufferPopMarker); LIB_FUNC("mv0O8Zg0woU", Ampr::CommandBufferPopMarker);
LIB_FUNC("DLfoNxTFNVk", Ampr::CommandBufferWaitOnAddress); LIB_FUNC("DLfoNxTFNVk", Ampr::CommandBufferWaitOnAddress);
LIB_FUNC("V7GQTEeUfhw", Ampr::CommandBufferWaitOnAddress);
LIB_FUNC("cQb8Zr8Q0Y0", Ampr::CommandBufferWaitOnCounter); LIB_FUNC("cQb8Zr8Q0Y0", Ampr::CommandBufferWaitOnCounter);
LIB_FUNC("j0+3uJMxYJY", Ampr::CommandBufferWriteAddress); LIB_FUNC("j0+3uJMxYJY", Ampr::CommandBufferWriteAddress);
LIB_FUNC("sJXyWHjP-F8", Ampr::CommandBufferWriteAddressOnCompletion); LIB_FUNC("sJXyWHjP-F8", Ampr::CommandBufferWriteAddressOnCompletion);
+6 -1
View File
@@ -484,9 +484,14 @@ int KYTY_SYSV_ABI AudioOut2ContextDestroy(AudioOut2ContextHandle ctx) {
int KYTY_SYSV_ABI AudioOut2ContextSetAttributes(AudioOut2ContextHandle ctx, int KYTY_SYSV_ABI AudioOut2ContextSetAttributes(AudioOut2ContextHandle ctx,
const AudioOut2Attribute* attributes, const AudioOut2Attribute* attributes,
uint32_t num) { uint32_t num) {
static std::atomic<uint32_t> call_log {0};
if (call_log.fetch_add(1, std::memory_order_relaxed) < 8) {
PRINT_NAME(); PRINT_NAME();
LOGF("\t ctx = 0x%016" PRIx64 ", num = %" PRIu32 "\n", ctx, num); }
EXIT_NOT_IMPLEMENTED(num != 0 && attributes == nullptr); EXIT_NOT_IMPLEMENTED(num != 0 && attributes == nullptr);
for (uint32_t i = 0; i < num; i++) {
const auto id = attributes[i].attribute_id;
}
return OK; return OK;
} }
+148 -4
View File
@@ -800,11 +800,155 @@ static bool KytyExceptionHandler(const Common::HostException::ExceptionInfo& exc
if (Libs::LibKernel::Memory::HandleGpuFault(access, info->access_violation_vaddr)) { if (Libs::LibKernel::Memory::HandleGpuFault(access, info->access_violation_vaddr)) {
return true; return true;
} }
if (Libs::LibKernel::Memory::KernelHandleReservedRangeAccessViolation(
info->access_violation_vaddr)) {
return true;
} }
EXIT("Unhandled host exception: type=%u code=%u pc=0x%016" PRIx64
" access=%u address=0x%016" PRIx64 "\n", if (Libs::LibKernel::Memory::KernelHandleTransientMappingFault(
static_cast<unsigned>(info->type), info->native_code, info->exception_address, access, info->access_violation_vaddr)) {
static_cast<unsigned>(info->access_violation_type), info->access_violation_vaddr); return true;
}
}
if (info->exception_address != 0) {
#if KYTY_PLATFORM == KYTY_PLATFORM_WINDOWS
MEMORY_BASIC_INFORMATION mem_info = {};
auto* dump_ptr = reinterpret_cast<const uint8_t*>(info->exception_address - 32);
if (VirtualQuery(dump_ptr, &mem_info, sizeof(mem_info)) != 0 &&
mem_info.State == MEM_COMMIT && mem_info.Protect != PAGE_NOACCESS &&
(mem_info.Protect & PAGE_GUARD) == 0) {
const auto dump_start = reinterpret_cast<uint64_t>(dump_ptr);
const auto region_end =
reinterpret_cast<uint64_t>(mem_info.BaseAddress) + mem_info.RegionSize;
const auto dump_size =
(dump_start + 64 <= region_end ? 64u
: static_cast<uint32_t>(region_end - dump_start));
for (uint32_t i = 0; i < dump_size; i++) {
}
}
#else
const auto fault_addr = info->exception_address;
const auto dump_start = (fault_addr >= 32 ? fault_addr - 32 : fault_addr);
if (IsReadableRange(dump_start, 64)) {
auto* dump_ptr = reinterpret_cast<const uint8_t*>(dump_start);
for (uint32_t i = 0; i < 64; i++) {
}
}
#endif
}
if (IsReadableRange(info->rsp, 16u * sizeof(uint64_t))) {
auto* stack = reinterpret_cast<const uint64_t*>(info->rsp);
for (uint64_t i = 0; i < 16; i++) {
}
}
auto dump_guest_code = [](const char* name, uint64_t addr) {
auto* p = Common::Singleton<Loader::RuntimeLinker>::Instance()->FindProgramByAddr(addr);
if (p == nullptr || addr < p->base_vaddr) {
return;
}
#if KYTY_PLATFORM == KYTY_PLATFORM_WINDOWS
MEMORY_BASIC_INFORMATION mbi {};
auto* dump_ptr = reinterpret_cast<const uint8_t*>(addr >= 16 ? addr - 16 : addr);
if (VirtualQuery(dump_ptr, &mbi, sizeof(mbi)) == 0 || mbi.State != MEM_COMMIT ||
(mbi.Protect & (PAGE_NOACCESS | PAGE_GUARD)) != 0) {
return;
}
const auto dump_start = reinterpret_cast<uint64_t>(dump_ptr);
const auto region_end = reinterpret_cast<uint64_t>(mbi.BaseAddress) + mbi.RegionSize;
const auto dump_size =
(dump_start + 32 <= region_end ? 32u : static_cast<uint32_t>(region_end - dump_start));
#else
auto* dump_ptr = reinterpret_cast<const uint8_t*>(addr >= 16 ? addr - 16 : addr);
const auto dump_size = 32u;
if (!IsReadableRange(reinterpret_cast<uint64_t>(dump_ptr), dump_size)) {
return;
}
#endif
for (uint32_t i = 0; i < dump_size; i++) {
}
};
dump_guest_code("guest rax[0]", info->rax);
dump_guest_code("guest rbx[0]", info->rbx);
dump_guest_code("guest rcx[0]", info->rcx);
dump_guest_code("guest rsi[0]", info->rsi);
if (IsReadableRange(info->rsp, 16u * sizeof(uint64_t))) {
auto* stack = reinterpret_cast<const uint64_t*>(info->rsp);
for (uint64_t i = 0; i < 16; i++) {
char name[32] {};
std::snprintf(name, sizeof(name), "stack[%" PRIu64 "]", i);
dump_guest_code(name, stack[i]);
}
}
if (info->type == Common::HostException::ExceptionType::AccessViolation) {
if (info->rbp != 0) {
Common::Singleton<Loader::RuntimeLinker>::Instance()->StackTrace(info->rbp, info->rsp);
}
auto dump_guest_qwords = [](const char* name, uint64_t addr) {
if (addr == 0) {
return;
}
#if KYTY_PLATFORM == KYTY_PLATFORM_WINDOWS
MEMORY_BASIC_INFORMATION mbi {};
if (VirtualQuery(reinterpret_cast<const void*>(addr), &mbi, sizeof(mbi)) == 0 ||
mbi.State != MEM_COMMIT || (mbi.Protect & (PAGE_NOACCESS | PAGE_GUARD)) != 0) {
return;
}
#endif
if (!IsReadableRange(addr, 8u * sizeof(uint64_t))) {
return;
}
auto* q = reinterpret_cast<const uint64_t*>(addr);
};
#if KYTY_PLATFORM == KYTY_PLATFORM_WINDOWS
{
const auto fault_addr = info->access_violation_vaddr;
MEMORY_BASIC_INFORMATION mbi {};
Libs::LibKernel::Memory::DumpVirtualRangeForAddress(fault_addr);
}
#endif
dump_guest_qwords("guest rbx", info->rbx);
dump_guest_qwords("guest rax", info->rax);
dump_guest_qwords("guest rcx", info->rcx);
dump_guest_qwords("guest rsi", info->rsi);
dump_guest_qwords("guest rdi", info->rdi);
dump_guest_qwords("guest r8 ", info->r8);
dump_guest_qwords("guest r9 ", info->r9);
dump_guest_qwords("guest r10", info->r10);
dump_guest_qwords("guest r11", info->r11);
dump_guest_qwords("guest r12", info->r12);
dump_guest_qwords("guest r13", info->r13);
dump_guest_qwords("guest r14", info->r14);
dump_guest_qwords("guest r15", info->r15);
if (info->exception_address == 0x000000090064364e &&
IsReadableRange(info->rbx, sizeof(uint64_t))) {
auto* local = reinterpret_cast<const uint64_t*>(info->rbx);
dump_guest_qwords("vorbis obj", local[0]);
dump_guest_qwords("vorbis len", info->rcx);
}
EXIT("Access violation: %s [%016" PRIx64 "] %s\n",
Common::EnumName(info->access_violation_type).c_str(), info->access_violation_vaddr,
(info->access_violation_vaddr == g_invalid_memory ? "(Unpatched object)" : ""));
return false;
}
EXIT("Unknown exception!!! (%08" PRIx32 ")", info->native_code);
return false;
} }
static void EncodeId64(uint16_t in_id, std::string* out_id) { static void EncodeId64(uint16_t in_id, std::string* out_id) {
+1
View File
@@ -12,6 +12,7 @@
#include <charconv> #include <charconv>
#include <cstdio> #include <cstdio>
#include <fstream>
#include <fmt/format.h> #include <fmt/format.h>
using namespace Common; using namespace Common;