Much better errors on undefined externs.

This commit is contained in:
Ben Vanik 2015-08-30 15:27:12 -07:00
parent 87094b8257
commit b80a028589
3 changed files with 33 additions and 33 deletions

View File

@ -36,6 +36,8 @@
DEFINE_bool(enable_debugprint_log, false,
"Log debugprint traps to the active debugger");
DEFINE_bool(ignore_undefined_externs, false,
"Don't exit when an undefined extern is called.");
namespace xe {
namespace cpu {
@ -299,6 +301,13 @@ uint64_t TrapDebugPrint(void* raw_context, uint64_t address) {
return 0;
}
uint64_t TrapDebugBreak(void* raw_context, uint64_t address) {
auto thread_state = *reinterpret_cast<ThreadState**>(raw_context);
XELOGE("Trap!");
xe::debugging::Break();
return 0;
}
void X64Emitter::Trap(uint16_t trap_type) {
switch (trap_type) {
case 20:
@ -310,6 +319,7 @@ void X64Emitter::Trap(uint16_t trap_type) {
case 22:
// Always trap?
// TODO(benvanik): post software interrupt to debugger.
CallNative(TrapDebugBreak, 0);
if (FLAGS_break_on_debugbreak) {
db(0xCC);
}
@ -417,8 +427,13 @@ void X64Emitter::CallIndirect(const hir::Instr* instr,
uint64_t UndefinedCallExtern(void* raw_context, uint64_t function_ptr) {
auto function = reinterpret_cast<Function*>(function_ptr);
XELOGW("undefined extern call to %.8X %s", function->address(),
function->name().c_str());
if (!FLAGS_ignore_undefined_externs) {
xe::FatalError("undefined extern call to %.8X %s", function->address(),
function->name().c_str());
} else {
XELOGE("undefined extern call to %.8X %s", function->address(),
function->name().c_str());
}
return 0;
}
void X64Emitter::CallExtern(const hir::Instr* instr, const Function* function) {

View File

@ -399,7 +399,20 @@ bool XexModule::SetupLibraryImports(const char* name,
function->set_end_address(record_addr + 16 - 4);
function->set_name(import_name.GetString());
if (kernel_export) {
if (user_export_addr) {
// Rewrite PPC code to set r11 to the target address
// So we'll have:
// lis r11, user_export_addr
// ori r11, r11, user_export_addr
// mtspr CTR, r11
// bctr
uint16_t hi_addr = (user_export_addr >> 16) & 0xFFFF;
uint16_t low_addr = user_export_addr & 0xFFFF;
uint8_t* p = memory()->TranslateVirtual(record_addr);
xe::store_and_swap<uint32_t>(p + 0x0, 0x3D600000 | hi_addr);
xe::store_and_swap<uint32_t>(p + 0x4, 0x616B0000 | low_addr);
} else {
// On load we have something like this in memory:
// li r3, 0
// li r4, 0x1F5
@ -420,6 +433,8 @@ bool XexModule::SetupLibraryImports(const char* name,
xe::store_and_swap<uint32_t>(p + 0x8, 0x60000000);
xe::store_and_swap<uint32_t>(p + 0xC, 0x60000000);
// Note that we may not have a handler registered - if not, eventually
// we'll get directed to UndefinedImport.
GuestFunction::ExternHandler handler = nullptr;
if (kernel_export) {
if (kernel_export->function_data.trampoline) {
@ -432,36 +447,9 @@ bool XexModule::SetupLibraryImports(const char* name,
} else {
XELOGW("WARNING: Imported kernel function %s is unimplemented!",
import_name.GetString());
handler = UndefinedImport;
}
static_cast<GuestFunction*>(function)->SetupExtern(handler);
} else if (user_export_addr) {
// Rewrite PPC code to set r11 to the target address
// So we'll have:
// lis r11, user_export_addr
// ori r11, r11, user_export_addr
// mtspr CTR, r11
// bctr
uint16_t hi_addr = (user_export_addr >> 16) & 0xFFFF;
uint16_t low_addr = user_export_addr & 0xFFFF;
uint8_t* p = memory()->TranslateVirtual(record_addr);
xe::store_and_swap<uint32_t>(p + 0x0, 0x3D600000 | hi_addr);
xe::store_and_swap<uint32_t>(p + 0x4, 0x616B0000 | low_addr);
} else {
// Import not resolved.
// We're gonna rewrite the PPC to trigger a debug trap:
// trap
// blr
// nop
// nop
uint8_t* p = memory()->TranslateVirtual(record_addr);
xe::store_and_swap<uint32_t>(p + 0x0, 0x7FE00008);
xe::store_and_swap<uint32_t>(p + 0x4, 0x4E800020);
xe::store_and_swap<uint32_t>(p + 0x8, 0x60000000);
xe::store_and_swap<uint32_t>(p + 0xC, 0x60000000);
}
function->set_status(Symbol::Status::kDeclared);
} else {
// Bad.

View File

@ -197,9 +197,6 @@ dword_result_t NtReadFile(dword_t file_handle, dword_t event_handle,
// Queue the APC callback. It must be delivered via the APC mechanism even
// though were are completing immediately.
if ((uint32_t)apc_routine_ptr & ~1) {
// Bejeweled 3 calls ReadFileEx with a NULL completion routine!
assert_not_zero((uint32_t)apc_context);
if (apc_context) {
auto thread = XThread::GetCurrentThread();
thread->EnqueueApc((uint32_t)apc_routine_ptr & ~1, apc_context,