fix crash from precompiling out of range funcs, add xexcache version, increment xexcache version (all priors are version 0 thanks to 0 initialization)

This commit is contained in:
chss95cs@gmail.com
2022-11-07 05:40:18 -08:00
parent e21fd22d09
commit 7a17fad88a
4 changed files with 73 additions and 18 deletions

View File

@@ -789,6 +789,9 @@ int InstrEmit_mtspr(PPCHIRBuilder& f, const InstrData& i) {
// code requires it. Sequences of mtmsr/lwar/stcw/mtmsr come up a lot, and // code requires it. Sequences of mtmsr/lwar/stcw/mtmsr come up a lot, and
// without the lock here threads can livelock. // without the lock here threads can livelock.
//0x400 = debug singlestep i think
//ive seen 0x8000 used in kernel code
int InstrEmit_mfmsr(PPCHIRBuilder& f, const InstrData& i) { int InstrEmit_mfmsr(PPCHIRBuilder& f, const InstrData& i) {
// bit 48 = EE; interrupt enabled // bit 48 = EE; interrupt enabled
// bit 62 = RI; recoverable interrupt // bit 62 = RI; recoverable interrupt

View File

@@ -263,6 +263,12 @@ Function* Processor::ResolveFunction(uint32_t address) {
return nullptr; return nullptr;
} }
if (!DemandFunction(function)) {
entry->status = Entry::STATUS_FAILED;
return nullptr;
}
//only add it to the list of resolved functions if resolving succeeded
auto module_for = function->module(); auto module_for = function->module();
auto xexmod = dynamic_cast<XexModule*>(module_for); auto xexmod = dynamic_cast<XexModule*>(module_for);
@@ -273,10 +279,6 @@ Function* Processor::ResolveFunction(uint32_t address) {
} }
} }
if (!DemandFunction(function)) {
entry->status = Entry::STATUS_FAILED;
return nullptr;
}
entry->function = function; entry->function = function;
entry->end_address = function->end_address(); entry->end_address = function->end_address();
status = entry->status = Entry::STATUS_READY; status = entry->status = Entry::STATUS_READY;

View File

@@ -1328,6 +1328,7 @@ void XexInfoCache::Init(XexModule* xexmod) {
if (cvars::disable_instruction_infocache) { if (cvars::disable_instruction_infocache) {
return; return;
} }
auto emu = xexmod->kernel_state_->emulator(); auto emu = xexmod->kernel_state_->emulator();
std::filesystem::path infocache_path = emu->cache_root(); std::filesystem::path infocache_path = emu->cache_root();
@@ -1341,13 +1342,16 @@ void XexInfoCache::Init(XexModule* xexmod) {
unsigned num_codebytes = xexmod->high_address_ - xexmod->low_address_; unsigned num_codebytes = xexmod->high_address_ - xexmod->low_address_;
num_codebytes += 3; // round up to nearest multiple of 4 num_codebytes += 3; // round up to nearest multiple of 4
num_codebytes &= ~3; num_codebytes &= ~3;
bool did_exist = true; bool did_exist = true;
if (!std::filesystem::exists(infocache_path)) { if (!std::filesystem::exists(infocache_path)) {
recreate:
xe::filesystem::CreateEmptyFile(infocache_path); xe::filesystem::CreateEmptyFile(infocache_path);
did_exist = false; did_exist = false;
} }
// todo: prepopulate with stuff from pdata, dll exports // todo: prepopulate with stuff from pdata, dll exports
this->executable_addr_flags_ = std::move(xe::MappedMemory::Open( this->executable_addr_flags_ = std::move(xe::MappedMemory::Open(
infocache_path, xe::MappedMemory::Mode::kReadWrite, 0, infocache_path, xe::MappedMemory::Mode::kReadWrite, 0,
sizeof(InfoCacheFlagsHeader) + sizeof(InfoCacheFlagsHeader) +
@@ -1355,11 +1359,17 @@ void XexInfoCache::Init(XexModule* xexmod) {
(num_codebytes / (num_codebytes /
4)))); // one infocacheflags entry for each PPC instr-sized addr 4)))); // one infocacheflags entry for each PPC instr-sized addr
if (did_exist) { if (!did_exist) {
xexmod->PrecompileKnownFunctions(); GetHeader()->version = CURRENT_INFOCACHE_VERSION;
} else {
if (GetHeader()->version != CURRENT_INFOCACHE_VERSION) {
this->executable_addr_flags_->Close();
std::filesystem::remove(infocache_path);
goto recreate;
}
} }
} }
InfoCacheFlags* XexModule::GetInstructionAddressFlags(uint32_t guest_addr) { InfoCacheFlags* XexModule::GetInstructionAddressFlags(uint32_t guest_addr) {
if (guest_addr < low_address_ || guest_addr > high_address_) { if (guest_addr < low_address_ || guest_addr > high_address_) {
return nullptr; return nullptr;
@@ -1371,7 +1381,7 @@ InfoCacheFlags* XexModule::GetInstructionAddressFlags(uint32_t guest_addr) {
} }
void XexModule::PrecompileDiscoveredFunctions() { void XexModule::PrecompileDiscoveredFunctions() {
if (cvars::disable_early_precompilation) { if (cvars::disable_early_precompilation) {
return; return;
} }
auto others = PreanalyzeCode(); auto others = PreanalyzeCode();
@@ -1396,7 +1406,7 @@ void XexModule::PrecompileKnownFunctions() {
if (!flags) { if (!flags) {
return; return;
} }
//maybe should pre-acquire global crit? // maybe should pre-acquire global crit?
for (uint32_t i = 0; i < end; i++) { for (uint32_t i = 0; i < end; i++) {
if (flags[i].was_resolved) { if (flags[i].was_resolved) {
uint32_t addr = low_address_ + (i * 4); uint32_t addr = low_address_ + (i * 4);
@@ -1425,8 +1435,20 @@ static bool IsOpcodeBL(unsigned w) {
std::vector<uint32_t> XexModule::PreanalyzeCode() { std::vector<uint32_t> XexModule::PreanalyzeCode() {
uint32_t low_8_aligned = xe::align<uint32_t>(low_address_, 8); uint32_t low_8_aligned = xe::align<uint32_t>(low_address_, 8);
uint32_t high_8_aligned = high_address_ & ~(8U - 1);
uint32_t highest_exec_addr = 0;
for (auto&& sec : pe_sections_) {
if ((sec.flags & kXEPESectionContainsCode)) {
highest_exec_addr =
std::max<uint32_t>(highest_exec_addr, sec.address + sec.size);
}
}
uint32_t high_8_aligned = highest_exec_addr & ~(8U - 1);
uint32_t n_possible_8byte_addresses = (high_8_aligned - low_8_aligned) / 8; uint32_t n_possible_8byte_addresses = (high_8_aligned - low_8_aligned) / 8;
uint32_t* funcstart_candidate_stack = uint32_t* funcstart_candidate_stack =
new uint32_t[n_possible_8byte_addresses]; new uint32_t[n_possible_8byte_addresses];
@@ -1453,6 +1475,10 @@ std::vector<uint32_t> XexModule::PreanalyzeCode() {
uint32_t mfspr_r12_lr32 = uint32_t mfspr_r12_lr32 =
*reinterpret_cast<const uint32_t*>(&mfspr_r12_lr[0]); *reinterpret_cast<const uint32_t*>(&mfspr_r12_lr[0]);
auto add_new_func = [funcstart_candidate_stack, &stack_pos](uint32_t addr) {
funcstart_candidate_stack[stack_pos++] = addr;
};
/* /*
First pass: detect save of the link register at an eight byte First pass: detect save of the link register at an eight byte
aligned address aligned address
@@ -1462,10 +1488,10 @@ std::vector<uint32_t> XexModule::PreanalyzeCode() {
if (*first_pass == mfspr_r12_lr32) { if (*first_pass == mfspr_r12_lr32) {
// Push our newly discovered function start into our list // Push our newly discovered function start into our list
// All addresses in the list are sorted until the second pass // All addresses in the list are sorted until the second pass
funcstart_candidate_stack[stack_pos++] = add_new_func(
static_cast<uint32_t>(reinterpret_cast<uintptr_t>(first_pass) - static_cast<uint32_t>(reinterpret_cast<uintptr_t>(first_pass) -
reinterpret_cast<uintptr_t>(range_start)) + reinterpret_cast<uintptr_t>(range_start)) +
low_8_aligned; low_8_aligned);
} else if (first_pass[-1] == 0 && *first_pass != 0) { } else if (first_pass[-1] == 0 && *first_pass != 0) {
// originally i checked for blr followed by 0, but some functions are // originally i checked for blr followed by 0, but some functions are
// actually aligned to greater boundaries. something that appears to be // actually aligned to greater boundaries. something that appears to be
@@ -1478,10 +1504,10 @@ std::vector<uint32_t> XexModule::PreanalyzeCode() {
} }
XE_LIKELY_IF(*check_iter == blr32) { XE_LIKELY_IF(*check_iter == blr32) {
funcstart_candidate_stack[stack_pos++] = add_new_func(
static_cast<uint32_t>(reinterpret_cast<uintptr_t>(first_pass) - static_cast<uint32_t>(reinterpret_cast<uintptr_t>(first_pass) -
reinterpret_cast<uintptr_t>(range_start)) + reinterpret_cast<uintptr_t>(range_start)) +
low_8_aligned; low_8_aligned);
} }
} }
} }
@@ -1494,8 +1520,14 @@ std::vector<uint32_t> XexModule::PreanalyzeCode() {
uint32_t current_call = xe::byte_swap(*second_pass); uint32_t current_call = xe::byte_swap(*second_pass);
if (IsOpcodeBL(current_call)) { if (IsOpcodeBL(current_call)) {
funcstart_candidate_stack[stack_pos++] = GetBLCalledFunction( uint32_t called_function = GetBLCalledFunction(
this, current_guestaddr, ppc::PPCOpcodeBits{current_call}); this, current_guestaddr, ppc::PPCOpcodeBits{current_call});
// must be 8 byte aligned and in range
if ((called_function & (8 - 1)) == 0 &&
called_function >= low_address_ &&
called_function < high_address_) {
add_new_func(called_function);
}
} }
} }
@@ -1509,8 +1541,8 @@ std::vector<uint32_t> XexModule::PreanalyzeCode() {
for (uint32_t i = 0; i < n_pdata_entries; ++i) { for (uint32_t i = 0; i < n_pdata_entries; ++i) {
uint32_t funcaddr = xe::load_and_swap<uint32_t>(&pdata_base[i * 2]); uint32_t funcaddr = xe::load_and_swap<uint32_t>(&pdata_base[i * 2]);
if (funcaddr >= low_address_ && funcaddr <= high_address_) { if (funcaddr >= low_address_ && funcaddr <= highest_exec_addr) {
funcstart_candidate_stack[stack_pos++] = funcaddr; add_new_func(funcaddr);
} else { } else {
// we hit 0 for func addr, that means we're done // we hit 0 for func addr, that means we're done
break; break;

View File

@@ -29,6 +29,7 @@ constexpr fourcc_t kXEX1Signature = make_fourcc("XEX1");
constexpr fourcc_t kXEX2Signature = make_fourcc("XEX2"); constexpr fourcc_t kXEX2Signature = make_fourcc("XEX2");
constexpr fourcc_t kElfSignature = make_fourcc(0x7F, 'E', 'L', 'F'); constexpr fourcc_t kElfSignature = make_fourcc(0x7F, 'E', 'L', 'F');
class Runtime; class Runtime;
struct InfoCacheFlags { struct InfoCacheFlags {
uint32_t was_resolved : 1; // has this address ever been called/requested uint32_t was_resolved : 1; // has this address ever been called/requested
@@ -38,8 +39,13 @@ struct InfoCacheFlags {
uint32_t reserved : 29; uint32_t reserved : 29;
}; };
struct XexInfoCache { struct XexInfoCache {
//increment this to invalidate all user infocaches
static constexpr uint32_t CURRENT_INFOCACHE_VERSION = 1;
struct InfoCacheFlagsHeader { struct InfoCacheFlagsHeader {
unsigned char reserved[256]; // put xenia version here uint32_t version;
unsigned char reserved[252];
InfoCacheFlags* LookupFlags(unsigned offset) { InfoCacheFlags* LookupFlags(unsigned offset) {
return &reinterpret_cast<InfoCacheFlags*>(&this[1])[offset]; return &reinterpret_cast<InfoCacheFlags*>(&this[1])[offset];
@@ -51,6 +57,18 @@ struct XexInfoCache {
std::unique_ptr<MappedMemory> executable_addr_flags_; std::unique_ptr<MappedMemory> executable_addr_flags_;
void Init(class XexModule*); void Init(class XexModule*);
InfoCacheFlagsHeader* GetHeader() {
if (!executable_addr_flags_) {
return nullptr;
}
uint8_t* data = executable_addr_flags_->data();
if (!data) {
return nullptr;
}
return reinterpret_cast<InfoCacheFlagsHeader*>(data);
}
InfoCacheFlags* LookupFlags(unsigned offset) { InfoCacheFlags* LookupFlags(unsigned offset) {
offset /= 4; offset /= 4;
if (!executable_addr_flags_) { if (!executable_addr_flags_) {