xenia-canary/src/xenia/cpu/exec_module.cc

162 lines
4.9 KiB
C++

/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2013 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#include <xenia/cpu/exec_module.h>
#include <xenia/cpu/cpu-private.h>
#include <xenia/cpu/sdb.h>
using namespace xe;
using namespace xe::cpu;
using namespace xe::cpu::sdb;
using namespace xe::kernel;
ExecModule::ExecModule(
xe_memory_ref memory, shared_ptr<ExportResolver> export_resolver,
SymbolTable* sym_table,
const char* module_name, const char* module_path) {
memory_ = xe_memory_retain(memory);
export_resolver_ = export_resolver;
sym_table_ = sym_table;
module_name_ = xestrdupa(module_name);
module_path_ = xestrdupa(module_path);
}
ExecModule::~ExecModule() {
xe_free(module_path_);
xe_free(module_name_);
xe_memory_release(memory_);
}
SymbolDatabase* ExecModule::sdb() {
return sdb_.get();
}
int ExecModule::PrepareRawBinary(uint32_t start_address, uint32_t end_address) {
sdb_ = shared_ptr<sdb::SymbolDatabase>(
new sdb::RawSymbolDatabase(memory_, export_resolver_.get(),
sym_table_, start_address, end_address));
code_addr_low_ = start_address;
code_addr_high_ = end_address;
return Prepare();
}
int ExecModule::PrepareXexModule(xe_xex2_ref xex) {
sdb_ = shared_ptr<sdb::SymbolDatabase>(
new sdb::XexSymbolDatabase(memory_, export_resolver_.get(),
sym_table_, xex));
code_addr_low_ = 0;
code_addr_high_ = 0;
const xe_xex2_header_t* header = xe_xex2_get_header(xex);
for (size_t n = 0, i = 0; n < header->section_count; n++) {
const xe_xex2_section_t* section = &header->sections[n];
const size_t start_address =
header->exe_address + (i * xe_xex2_section_length);
const size_t end_address =
start_address + (section->info.page_count * xe_xex2_section_length);
if (section->info.type == XEX_SECTION_CODE) {
code_addr_low_ = (uint32_t)MIN(code_addr_low_, start_address);
code_addr_high_ = (uint32_t)MAX(code_addr_high_, end_address);
}
i += section->info.page_count;
}
int result_code = Prepare();
if (result_code) {
return result_code;
}
return 0;
}
int ExecModule::Prepare() {
int result_code = 1;
char file_name[XE_MAX_PATH];
// Analyze the module and add its symbols to the symbol database.
// This always happens, even if we have a cached copy of the library, as
// we may end up needing this information later.
// TODO(benvanik): see how much memory this is using - it may be worth
// dropping and keeping around a smaller structure for future lookups
// instead.
XEEXPECTZERO(sdb_->Analyze());
// Load a specified module map and diff.
if (FLAGS_load_module_map.size()) {
sdb_->ReadMap(FLAGS_load_module_map.c_str());
}
// Dump the symbol database.
if (FLAGS_dump_module_map) {
xesnprintfa(file_name, XECOUNT(file_name),
"%s%s.map", FLAGS_dump_path.c_str(), module_name_);
sdb_->WriteMap(file_name);
}
// If recompiling, setup a recompiler and run.
// Note that this will just load the library if it's present and valid.
// TODO(benvanik): recompiler logic.
// Initialize the module.
XEEXPECTZERO(Init());
result_code = 0;
XECLEANUP:
return result_code;
}
int ExecModule::Init() {
// Setup all kernel variables.
std::vector<VariableSymbol*> variables;
if (sdb_->GetAllVariables(variables)) {
return 1;
}
uint8_t* mem = xe_memory_addr(memory_, 0);
for (std::vector<VariableSymbol*>::iterator it = variables.begin();
it != variables.end(); ++it) {
VariableSymbol* var = *it;
if (!var->kernel_export) {
continue;
}
KernelExport* kernel_export = var->kernel_export;
// Grab, if available.
uint32_t* slot = (uint32_t*)(mem + var->address);
if (kernel_export->type == KernelExport::Function) {
// Not exactly sure what this should be...
// TODO(benvanik): find out what import variables are.
} else {
if (kernel_export->is_implemented) {
// Implemented - replace with pointer.
*slot = XESWAP32BE(kernel_export->variable_ptr);
} else {
// Not implemented - write with a dummy value.
*slot = XESWAP32BE(0xD000BEEF | (kernel_export->ordinal & 0xFFF) << 16);
XELOGCPU("WARNING: imported a variable with no value: %s",
kernel_export->name);
}
}
}
return 0;
}
FunctionSymbol* ExecModule::FindFunctionSymbol(uint32_t address) {
return sdb_->GetFunction(address, true);
}
void ExecModule::Dump() {
sdb_->Dump(stdout);
}