Refactoring to allow for raw binary loading.
This commit is contained in:
parent
26d5df0d38
commit
bba99d4a22
|
@ -35,7 +35,8 @@ class ModuleGenerator {
|
|||
public:
|
||||
ModuleGenerator(
|
||||
xe_memory_ref memory, kernel::ExportResolver* export_resolver,
|
||||
kernel::UserModule* module, sdb::SymbolDatabase* sdb,
|
||||
const char* module_name, const char* module_path,
|
||||
sdb::SymbolDatabase* sdb,
|
||||
llvm::LLVMContext* context, llvm::Module* gen_module);
|
||||
~ModuleGenerator();
|
||||
|
||||
|
@ -61,7 +62,8 @@ private:
|
|||
|
||||
xe_memory_ref memory_;
|
||||
kernel::ExportResolver* export_resolver_;
|
||||
kernel::UserModule* module_;
|
||||
char* module_name_;
|
||||
char* module_path_;
|
||||
sdb::SymbolDatabase* sdb_;
|
||||
|
||||
llvm::LLVMContext* context_;
|
||||
|
|
|
@ -41,22 +41,25 @@ class ExecModule {
|
|||
public:
|
||||
ExecModule(
|
||||
xe_memory_ref memory, shared_ptr<kernel::ExportResolver> export_resolver,
|
||||
kernel::UserModule* user_module,
|
||||
const char* module_name, const char* module_path,
|
||||
shared_ptr<llvm::ExecutionEngine>& engine);
|
||||
~ExecModule();
|
||||
|
||||
int Prepare();
|
||||
int PrepareUserModule(kernel::UserModule* user_module);
|
||||
int PrepareRawBinary(uint32_t start_address, uint32_t end_address);
|
||||
|
||||
void Dump();
|
||||
|
||||
private:
|
||||
int Prepare();
|
||||
int InjectGlobals();
|
||||
int Init();
|
||||
int Uninit();
|
||||
|
||||
xe_memory_ref memory_;
|
||||
shared_ptr<kernel::ExportResolver> export_resolver_;
|
||||
kernel::UserModule* module_;
|
||||
char* module_name_;
|
||||
char* module_path_;
|
||||
shared_ptr<llvm::ExecutionEngine> engine_;
|
||||
shared_ptr<sdb::SymbolDatabase> sdb_;
|
||||
shared_ptr<llvm::LLVMContext> context_;
|
||||
|
|
|
@ -38,6 +38,9 @@ public:
|
|||
|
||||
int Setup();
|
||||
|
||||
int PrepareModule(const char* module_name, const char* module_path,
|
||||
uint32_t start_address, uint32_t end_address,
|
||||
shared_ptr<kernel::ExportResolver> export_resolver);
|
||||
int PrepareModule(kernel::UserModule* user_module,
|
||||
shared_ptr<kernel::ExportResolver> export_resolver);
|
||||
|
||||
|
|
|
@ -142,11 +142,10 @@ public:
|
|||
|
||||
class SymbolDatabase {
|
||||
public:
|
||||
SymbolDatabase(xe_memory_ref memory, kernel::ExportResolver* export_resolver,
|
||||
kernel::UserModule* module);
|
||||
~SymbolDatabase();
|
||||
SymbolDatabase(xe_memory_ref memory, kernel::ExportResolver* export_resolver);
|
||||
virtual ~SymbolDatabase();
|
||||
|
||||
int Analyze();
|
||||
virtual int Analyze();
|
||||
|
||||
ExceptionEntrySymbol* GetOrInsertExceptionEntry(uint32_t address);
|
||||
FunctionSymbol* GetOrInsertFunction(uint32_t address);
|
||||
|
@ -161,24 +160,21 @@ public:
|
|||
void Dump();
|
||||
void DumpFunctionBlocks(FunctionSymbol* fn);
|
||||
|
||||
private:
|
||||
protected:
|
||||
typedef std::map<uint32_t, Symbol*> SymbolMap;
|
||||
typedef std::list<FunctionSymbol*> FunctionList;
|
||||
|
||||
int FindGplr();
|
||||
int AddImports(const xe_xex2_import_library_t *library);
|
||||
int AddMethodHints();
|
||||
int AnalyzeFunction(FunctionSymbol* fn);
|
||||
int CompleteFunctionGraph(FunctionSymbol* fn);
|
||||
bool FillHoles();
|
||||
int FlushQueue();
|
||||
|
||||
bool IsValueInTextRange(uint32_t value);
|
||||
bool IsRestGprLr(uint32_t addr);
|
||||
virtual uint32_t GetEntryPoint() = 0;
|
||||
virtual bool IsValueInTextRange(uint32_t value) = 0;
|
||||
|
||||
xe_memory_ref memory_;
|
||||
kernel::ExportResolver* export_resolver_;
|
||||
kernel::UserModule* module_;
|
||||
size_t function_count_;
|
||||
size_t variable_count_;
|
||||
SymbolMap symbols_;
|
||||
|
@ -186,6 +182,43 @@ private:
|
|||
};
|
||||
|
||||
|
||||
class RawSymbolDatabase : public SymbolDatabase {
|
||||
public:
|
||||
RawSymbolDatabase(xe_memory_ref memory,
|
||||
kernel::ExportResolver* export_resolver,
|
||||
uint32_t start_address, uint32_t end_address);
|
||||
virtual ~RawSymbolDatabase();
|
||||
|
||||
private:
|
||||
virtual uint32_t GetEntryPoint();
|
||||
virtual bool IsValueInTextRange(uint32_t value);
|
||||
|
||||
uint32_t start_address_;
|
||||
uint32_t end_address_;
|
||||
};
|
||||
|
||||
|
||||
class XexSymbolDatabase : public SymbolDatabase {
|
||||
public:
|
||||
XexSymbolDatabase(xe_memory_ref memory,
|
||||
kernel::ExportResolver* export_resolver,
|
||||
kernel::UserModule* module);
|
||||
virtual ~XexSymbolDatabase();
|
||||
|
||||
virtual int Analyze();
|
||||
|
||||
private:
|
||||
int FindGplr();
|
||||
int AddImports(const xe_xex2_import_library_t *library);
|
||||
int AddMethodHints();
|
||||
|
||||
virtual uint32_t GetEntryPoint();
|
||||
virtual bool IsValueInTextRange(uint32_t value);
|
||||
|
||||
kernel::UserModule* module_;
|
||||
};
|
||||
|
||||
|
||||
} // namespace sdb
|
||||
} // namespace cpu
|
||||
} // namespace xe
|
||||
|
|
|
@ -44,6 +44,8 @@ public:
|
|||
shared_ptr<ExportResolver> export_resolver();
|
||||
const xechar_t* command_line();
|
||||
|
||||
int LoadBinaryModule(const xechar_t* path, uint32_t start_address);
|
||||
|
||||
int LoadModule(const xechar_t* path);
|
||||
void LaunchModule(UserModule* user_module);
|
||||
UserModule* GetModule(const xechar_t* path);
|
||||
|
|
|
@ -39,11 +39,12 @@ using namespace xe::kernel;
|
|||
|
||||
ModuleGenerator::ModuleGenerator(
|
||||
xe_memory_ref memory, ExportResolver* export_resolver,
|
||||
UserModule* module, SymbolDatabase* sdb,
|
||||
const char* module_name, const char* module_path, SymbolDatabase* sdb,
|
||||
LLVMContext* context, Module* gen_module) {
|
||||
memory_ = xe_memory_retain(memory);
|
||||
export_resolver_ = export_resolver;
|
||||
module_ = module;
|
||||
module_name_ = xestrdupa(module_name);
|
||||
module_path_ = xestrdupa(module_path);
|
||||
sdb_ = sdb;
|
||||
context_ = context;
|
||||
gen_module_ = gen_module;
|
||||
|
@ -57,6 +58,8 @@ ModuleGenerator::~ModuleGenerator() {
|
|||
}
|
||||
|
||||
delete di_builder_;
|
||||
xe_free(module_path_);
|
||||
xe_free(module_name_);
|
||||
xe_memory_release(memory_);
|
||||
}
|
||||
|
||||
|
@ -67,7 +70,7 @@ int ModuleGenerator::Generate() {
|
|||
// This is used when creating any debug info. We may want to go more
|
||||
// fine grained than this, but for now it's something.
|
||||
xechar_t dir[2048];
|
||||
XEIGNORE(xestrcpy(dir, XECOUNT(dir), module_->path()));
|
||||
XEIGNORE(xestrcpy(dir, XECOUNT(dir), module_path_));
|
||||
xechar_t* slash = xestrrchr(dir, '/');
|
||||
if (slash) {
|
||||
*(slash + 1) = 0;
|
||||
|
@ -75,7 +78,7 @@ int ModuleGenerator::Generate() {
|
|||
di_builder_ = new DIBuilder(*gen_module_);
|
||||
di_builder_->createCompileUnit(
|
||||
0,
|
||||
StringRef(module_->name()),
|
||||
StringRef(module_name_),
|
||||
StringRef(dir),
|
||||
StringRef("xenia"),
|
||||
true,
|
||||
|
|
|
@ -46,13 +46,13 @@ using namespace xe::kernel;
|
|||
|
||||
ExecModule::ExecModule(
|
||||
xe_memory_ref memory, shared_ptr<ExportResolver> export_resolver,
|
||||
UserModule* user_module, shared_ptr<llvm::ExecutionEngine>& engine) {
|
||||
const char* module_name, const char* module_path,
|
||||
shared_ptr<llvm::ExecutionEngine>& engine) {
|
||||
memory_ = xe_memory_retain(memory);
|
||||
export_resolver_ = export_resolver;
|
||||
module_ = user_module;
|
||||
module_name_ = xestrdupa(module_name);
|
||||
module_path_ = xestrdupa(module_path);
|
||||
engine_ = engine;
|
||||
sdb_ = shared_ptr<sdb::SymbolDatabase>(
|
||||
new sdb::SymbolDatabase(memory_, export_resolver_.get(), module_));
|
||||
|
||||
context_ = shared_ptr<LLVMContext>(new LLVMContext());
|
||||
}
|
||||
|
@ -63,9 +63,26 @@ ExecModule::~ExecModule() {
|
|||
engine_->removeModule(gen_module_.get());
|
||||
}
|
||||
|
||||
xe_free(module_path_);
|
||||
xe_free(module_name_);
|
||||
xe_memory_release(memory_);
|
||||
}
|
||||
|
||||
int ExecModule::PrepareUserModule(kernel::UserModule* user_module) {
|
||||
sdb_ = shared_ptr<sdb::SymbolDatabase>(
|
||||
new sdb::XexSymbolDatabase(memory_, export_resolver_.get(), user_module));
|
||||
|
||||
return Prepare();
|
||||
}
|
||||
|
||||
int ExecModule::PrepareRawBinary(uint32_t start_address, uint32_t end_address) {
|
||||
sdb_ = shared_ptr<sdb::SymbolDatabase>(
|
||||
new sdb::RawSymbolDatabase(memory_, export_resolver_.get(),
|
||||
start_address, end_address));
|
||||
|
||||
return Prepare();
|
||||
}
|
||||
|
||||
int ExecModule::Prepare() {
|
||||
int result_code = 1;
|
||||
std::string error_message;
|
||||
|
@ -112,13 +129,13 @@ int ExecModule::Prepare() {
|
|||
// Dump the symbol database.
|
||||
if (FLAGS_dump_module_map) {
|
||||
xesnprintf(file_name, XECOUNT(file_name),
|
||||
"%s%s.map", FLAGS_dump_path.c_str(), module_->name());
|
||||
"%s%s.map", FLAGS_dump_path.c_str(), module_name_);
|
||||
sdb_->Write(file_name);
|
||||
}
|
||||
|
||||
// Initialize the module.
|
||||
gen_module_ = shared_ptr<Module>(
|
||||
new Module(module_->name(), *context_.get()));
|
||||
new Module(module_name_, *context_.get()));
|
||||
// TODO(benavnik): addModuleFlag?
|
||||
|
||||
// Inject globals.
|
||||
|
@ -134,8 +151,8 @@ int ExecModule::Prepare() {
|
|||
|
||||
// Build the module from the source code.
|
||||
codegen_ = auto_ptr<ModuleGenerator>(new ModuleGenerator(
|
||||
memory_, export_resolver_.get(), module_, sdb_.get(),
|
||||
context_.get(), gen_module_.get()));
|
||||
memory_, export_resolver_.get(), module_name_, module_path_,
|
||||
sdb_.get(), context_.get(), gen_module_.get()));
|
||||
XEEXPECTZERO(codegen_->Generate());
|
||||
|
||||
// Write to cache.
|
||||
|
@ -144,7 +161,7 @@ int ExecModule::Prepare() {
|
|||
// Dump pre-optimized module to disk.
|
||||
if (FLAGS_dump_module_bitcode) {
|
||||
xesnprintf(file_name, XECOUNT(file_name),
|
||||
"%s%s-preopt.bc", FLAGS_dump_path.c_str(), module_->name());
|
||||
"%s%s-preopt.bc", FLAGS_dump_path.c_str(), module_name_);
|
||||
outs = auto_ptr<raw_ostream>(new raw_fd_ostream(
|
||||
file_name, error_message, raw_fd_ostream::F_Binary));
|
||||
XEEXPECTTRUE(error_message.empty());
|
||||
|
@ -176,7 +193,7 @@ int ExecModule::Prepare() {
|
|||
// Dump post-optimized module to disk.
|
||||
if (FLAGS_optimize_ir_modules && FLAGS_dump_module_bitcode) {
|
||||
xesnprintf(file_name, XECOUNT(file_name),
|
||||
"%s%s.bc", FLAGS_dump_path.c_str(), module_->name());
|
||||
"%s%s.bc", FLAGS_dump_path.c_str(), module_name_);
|
||||
outs = auto_ptr<raw_ostream>(new raw_fd_ostream(
|
||||
file_name, error_message, raw_fd_ostream::F_Binary));
|
||||
XEEXPECTTRUE(error_message.empty());
|
||||
|
|
|
@ -85,12 +85,32 @@ int Processor::Setup() {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int Processor::PrepareModule(
|
||||
const char* module_name, const char* module_path,
|
||||
uint32_t start_address, uint32_t end_address,
|
||||
shared_ptr<ExportResolver> export_resolver) {
|
||||
ExecModule* exec_module = new ExecModule(
|
||||
memory_, export_resolver, module_name, module_path, engine_);
|
||||
|
||||
if (exec_module->PrepareRawBinary(start_address, end_address)) {
|
||||
delete exec_module;
|
||||
return 1;
|
||||
}
|
||||
|
||||
modules_.push_back(exec_module);
|
||||
|
||||
exec_module->Dump();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Processor::PrepareModule(UserModule* user_module,
|
||||
shared_ptr<ExportResolver> export_resolver) {
|
||||
ExecModule* exec_module = new ExecModule(
|
||||
memory_, export_resolver, user_module, engine_);
|
||||
memory_, export_resolver, user_module->name(), user_module->path(),
|
||||
engine_);
|
||||
|
||||
if (exec_module->Prepare()) {
|
||||
if (exec_module->PrepareUserModule(user_module)) {
|
||||
delete exec_module;
|
||||
return 1;
|
||||
}
|
||||
|
|
428
src/cpu/sdb.cc
428
src/cpu/sdb.cc
|
@ -95,11 +95,10 @@ ExceptionEntrySymbol::ExceptionEntrySymbol() :
|
|||
address(0), function(0) {
|
||||
}
|
||||
|
||||
SymbolDatabase::SymbolDatabase(
|
||||
xe_memory_ref memory, ExportResolver* export_resolver, UserModule* module) {
|
||||
SymbolDatabase::SymbolDatabase(xe_memory_ref memory,
|
||||
ExportResolver* export_resolver) {
|
||||
memory_ = xe_memory_retain(memory);
|
||||
export_resolver_ = export_resolver;
|
||||
module_ = module;
|
||||
}
|
||||
|
||||
SymbolDatabase::~SymbolDatabase() {
|
||||
|
@ -115,27 +114,8 @@ int SymbolDatabase::Analyze() {
|
|||
// This uses a queue to do a breadth-first search of all accessible
|
||||
// functions. Callbacks and such likely won't be hit.
|
||||
|
||||
const xe_xex2_header_t *header = module_->xex_header();
|
||||
|
||||
// Find __savegprlr_* and __restgprlr_*.
|
||||
FindGplr();
|
||||
|
||||
// Add each import thunk.
|
||||
for (size_t n = 0; n < header->import_library_count; n++) {
|
||||
AddImports(&header->import_libraries[n]);
|
||||
}
|
||||
|
||||
// Add each export root.
|
||||
// TODO(benvanik): exports.
|
||||
// - insert fn or variable
|
||||
// - queue fn
|
||||
|
||||
// Add method hints, if available.
|
||||
// Not all XEXs have these.
|
||||
AddMethodHints();
|
||||
|
||||
// Queue entry point of the application.
|
||||
FunctionSymbol* fn = GetOrInsertFunction(header->exe_entry_point);
|
||||
FunctionSymbol* fn = GetOrInsertFunction(GetEntryPoint());
|
||||
fn->name = xestrdupa("start");
|
||||
|
||||
// Keep pumping the queue until there's nothing left to do.
|
||||
|
@ -316,173 +296,6 @@ void SymbolDatabase::DumpFunctionBlocks(FunctionSymbol* fn) {
|
|||
}
|
||||
}
|
||||
|
||||
int SymbolDatabase::FindGplr() {
|
||||
// Special stack save/restore functions.
|
||||
// __savegprlr_14 to __savegprlr_31
|
||||
// __restgprlr_14 to __restgprlr_31
|
||||
// http://research.microsoft.com/en-us/um/redmond/projects/invisible/src/crt/md/ppc/xxx.s.htm
|
||||
// It'd be nice to stash these away and mark them as such to allow for
|
||||
// special codegen.
|
||||
static const uint32_t code_values[] = {
|
||||
0x68FFC1F9, // __savegprlr_14
|
||||
0x70FFE1F9, // __savegprlr_15
|
||||
0x78FF01FA, // __savegprlr_16
|
||||
0x80FF21FA, // __savegprlr_17
|
||||
0x88FF41FA, // __savegprlr_18
|
||||
0x90FF61FA, // __savegprlr_19
|
||||
0x98FF81FA, // __savegprlr_20
|
||||
0xA0FFA1FA, // __savegprlr_21
|
||||
0xA8FFC1FA, // __savegprlr_22
|
||||
0xB0FFE1FA, // __savegprlr_23
|
||||
0xB8FF01FB, // __savegprlr_24
|
||||
0xC0FF21FB, // __savegprlr_25
|
||||
0xC8FF41FB, // __savegprlr_26
|
||||
0xD0FF61FB, // __savegprlr_27
|
||||
0xD8FF81FB, // __savegprlr_28
|
||||
0xE0FFA1FB, // __savegprlr_29
|
||||
0xE8FFC1FB, // __savegprlr_30
|
||||
0xF0FFE1FB, // __savegprlr_31
|
||||
0xF8FF8191,
|
||||
0x2000804E,
|
||||
0x68FFC1E9, // __restgprlr_14
|
||||
0x70FFE1E9, // __restgprlr_15
|
||||
0x78FF01EA, // __restgprlr_16
|
||||
0x80FF21EA, // __restgprlr_17
|
||||
0x88FF41EA, // __restgprlr_18
|
||||
0x90FF61EA, // __restgprlr_19
|
||||
0x98FF81EA, // __restgprlr_20
|
||||
0xA0FFA1EA, // __restgprlr_21
|
||||
0xA8FFC1EA, // __restgprlr_22
|
||||
0xB0FFE1EA, // __restgprlr_23
|
||||
0xB8FF01EB, // __restgprlr_24
|
||||
0xC0FF21EB, // __restgprlr_25
|
||||
0xC8FF41EB, // __restgprlr_26
|
||||
0xD0FF61EB, // __restgprlr_27
|
||||
0xD8FF81EB, // __restgprlr_28
|
||||
0xE0FFA1EB, // __restgprlr_29
|
||||
0xE8FFC1EB, // __restgprlr_30
|
||||
0xF0FFE1EB, // __restgprlr_31
|
||||
0xF8FF8181,
|
||||
0xA603887D,
|
||||
0x2000804E,
|
||||
};
|
||||
|
||||
uint32_t gplr_start = 0;
|
||||
const xe_xex2_header_t* header = module_->xex_header();
|
||||
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) {
|
||||
gplr_start = xe_memory_search_aligned(
|
||||
memory_, start_address, end_address,
|
||||
code_values, XECOUNT(code_values));
|
||||
if (gplr_start) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
i += section->info.page_count;
|
||||
}
|
||||
if (!gplr_start) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Add function stubs.
|
||||
char name[32];
|
||||
uint32_t address = gplr_start;
|
||||
for (int n = 14; n <= 31; n++) {
|
||||
xesnprintf(name, XECOUNT(name), "__savegprlr_%d", n);
|
||||
FunctionSymbol* fn = GetOrInsertFunction(address);
|
||||
fn->end_address = fn->start_address + (31 - n) * 4 + 2 * 4;
|
||||
fn->name = xestrdupa(name);
|
||||
fn->type = FunctionSymbol::User;
|
||||
fn->flags |= FunctionSymbol::kFlagSaveGprLr;
|
||||
address += 4;
|
||||
}
|
||||
address = gplr_start + 20 * 4;
|
||||
for (int n = 14; n <= 31; n++) {
|
||||
xesnprintf(name, XECOUNT(name), "__restgprlr_%d", n);
|
||||
FunctionSymbol* fn = GetOrInsertFunction(address);
|
||||
fn->end_address = fn->start_address + (31 - n) * 4 + 3 * 4;
|
||||
fn->name = xestrdupa(name);
|
||||
fn->type = FunctionSymbol::User;
|
||||
fn->flags |= FunctionSymbol::kFlagRestGprLr;
|
||||
address += 4;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SymbolDatabase::AddImports(const xe_xex2_import_library_t* library) {
|
||||
xe_xex2_ref xex = module_->xex();
|
||||
xe_xex2_import_info_t* import_infos;
|
||||
size_t import_info_count;
|
||||
if (xe_xex2_get_import_infos(xex, library, &import_infos,
|
||||
&import_info_count)) {
|
||||
xe_xex2_release(xex);
|
||||
return 1;
|
||||
}
|
||||
|
||||
char name[128];
|
||||
for (size_t n = 0; n < import_info_count; n++) {
|
||||
const xe_xex2_import_info_t* info = &import_infos[n];
|
||||
|
||||
KernelExport* kernel_export = export_resolver_->GetExportByOrdinal(
|
||||
library->name, info->ordinal);
|
||||
|
||||
VariableSymbol* var = GetOrInsertVariable(info->value_address);
|
||||
if (kernel_export) {
|
||||
if (info->thunk_address) {
|
||||
xesnprintfa(name, XECOUNT(name), "__imp__%s", kernel_export->name);
|
||||
} else {
|
||||
xesnprintfa(name, XECOUNT(name), "%s", kernel_export->name);
|
||||
}
|
||||
} else {
|
||||
xesnprintfa(name, XECOUNT(name), "__imp__%s_%.3X", library->name,
|
||||
info->ordinal);
|
||||
}
|
||||
var->name = xestrdupa(name);
|
||||
if (info->thunk_address) {
|
||||
FunctionSymbol* fn = GetOrInsertFunction(info->thunk_address);
|
||||
fn->end_address = fn->start_address + 16 - 4;
|
||||
fn->type = FunctionSymbol::Kernel;
|
||||
fn->kernel_export = kernel_export;
|
||||
if (kernel_export) {
|
||||
xesnprintfa(name, XECOUNT(name), "%s", kernel_export->name);
|
||||
} else {
|
||||
xesnprintfa(name, XECOUNT(name), "__kernel_%s_%.3X", library->name,
|
||||
info->ordinal);
|
||||
}
|
||||
fn->name = xestrdupa(name);
|
||||
}
|
||||
}
|
||||
|
||||
xe_free(import_infos);
|
||||
xe_xex2_release(xex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SymbolDatabase::AddMethodHints() {
|
||||
PEMethodInfo* method_infos;
|
||||
size_t method_info_count;
|
||||
if (module_->GetMethodHints(&method_infos, &method_info_count)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (size_t n = 0; n < method_info_count; n++) {
|
||||
PEMethodInfo* method_info = &method_infos[n];
|
||||
FunctionSymbol* fn = GetOrInsertFunction(method_info->address);
|
||||
fn->end_address = method_info->address + method_info->total_length - 4;
|
||||
fn->type = FunctionSymbol::User;
|
||||
// TODO(benvanik): something with prolog_length?
|
||||
}
|
||||
|
||||
xe_free(method_infos);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SymbolDatabase::AnalyzeFunction(FunctionSymbol* fn) {
|
||||
// Ignore functions already analyzed.
|
||||
if (fn->blocks.size()) {
|
||||
|
@ -849,7 +662,235 @@ int SymbolDatabase::FlushQueue() {
|
|||
return 0;
|
||||
}
|
||||
|
||||
bool SymbolDatabase::IsValueInTextRange(uint32_t value) {
|
||||
bool SymbolDatabase::IsRestGprLr(uint32_t addr) {
|
||||
FunctionSymbol* fn = GetFunction(addr);
|
||||
return fn && (fn->flags & FunctionSymbol::kFlagRestGprLr);
|
||||
}
|
||||
|
||||
RawSymbolDatabase::RawSymbolDatabase(
|
||||
xe_memory_ref memory, ExportResolver* export_resolver,
|
||||
uint32_t start_address, uint32_t end_address) :
|
||||
SymbolDatabase(memory, export_resolver) {
|
||||
start_address_ = start_address;
|
||||
end_address_ = end_address;
|
||||
}
|
||||
|
||||
RawSymbolDatabase::~RawSymbolDatabase() {
|
||||
}
|
||||
|
||||
uint32_t RawSymbolDatabase::GetEntryPoint() {
|
||||
return start_address_;
|
||||
}
|
||||
|
||||
bool RawSymbolDatabase::IsValueInTextRange(uint32_t value) {
|
||||
return value >= start_address_ && value < end_address_;
|
||||
}
|
||||
|
||||
XexSymbolDatabase::XexSymbolDatabase(
|
||||
xe_memory_ref memory, ExportResolver* export_resolver, UserModule* module) :
|
||||
SymbolDatabase(memory, export_resolver) {
|
||||
module_ = module;
|
||||
}
|
||||
|
||||
XexSymbolDatabase::~XexSymbolDatabase() {
|
||||
}
|
||||
|
||||
int XexSymbolDatabase::Analyze() {
|
||||
const xe_xex2_header_t *header = module_->xex_header();
|
||||
|
||||
// Find __savegprlr_* and __restgprlr_*.
|
||||
FindGplr();
|
||||
|
||||
// Add each import thunk.
|
||||
for (size_t n = 0; n < header->import_library_count; n++) {
|
||||
AddImports(&header->import_libraries[n]);
|
||||
}
|
||||
|
||||
// Add each export root.
|
||||
// TODO(benvanik): exports.
|
||||
// - insert fn or variable
|
||||
// - queue fn
|
||||
|
||||
// Add method hints, if available.
|
||||
// Not all XEXs have these.
|
||||
AddMethodHints();
|
||||
|
||||
return SymbolDatabase::Analyze();
|
||||
}
|
||||
|
||||
int XexSymbolDatabase::FindGplr() {
|
||||
// Special stack save/restore functions.
|
||||
// __savegprlr_14 to __savegprlr_31
|
||||
// __restgprlr_14 to __restgprlr_31
|
||||
// http://research.microsoft.com/en-us/um/redmond/projects/invisible/src/crt/md/ppc/xxx.s.htm
|
||||
// It'd be nice to stash these away and mark them as such to allow for
|
||||
// special codegen.
|
||||
static const uint32_t code_values[] = {
|
||||
0x68FFC1F9, // __savegprlr_14
|
||||
0x70FFE1F9, // __savegprlr_15
|
||||
0x78FF01FA, // __savegprlr_16
|
||||
0x80FF21FA, // __savegprlr_17
|
||||
0x88FF41FA, // __savegprlr_18
|
||||
0x90FF61FA, // __savegprlr_19
|
||||
0x98FF81FA, // __savegprlr_20
|
||||
0xA0FFA1FA, // __savegprlr_21
|
||||
0xA8FFC1FA, // __savegprlr_22
|
||||
0xB0FFE1FA, // __savegprlr_23
|
||||
0xB8FF01FB, // __savegprlr_24
|
||||
0xC0FF21FB, // __savegprlr_25
|
||||
0xC8FF41FB, // __savegprlr_26
|
||||
0xD0FF61FB, // __savegprlr_27
|
||||
0xD8FF81FB, // __savegprlr_28
|
||||
0xE0FFA1FB, // __savegprlr_29
|
||||
0xE8FFC1FB, // __savegprlr_30
|
||||
0xF0FFE1FB, // __savegprlr_31
|
||||
0xF8FF8191,
|
||||
0x2000804E,
|
||||
0x68FFC1E9, // __restgprlr_14
|
||||
0x70FFE1E9, // __restgprlr_15
|
||||
0x78FF01EA, // __restgprlr_16
|
||||
0x80FF21EA, // __restgprlr_17
|
||||
0x88FF41EA, // __restgprlr_18
|
||||
0x90FF61EA, // __restgprlr_19
|
||||
0x98FF81EA, // __restgprlr_20
|
||||
0xA0FFA1EA, // __restgprlr_21
|
||||
0xA8FFC1EA, // __restgprlr_22
|
||||
0xB0FFE1EA, // __restgprlr_23
|
||||
0xB8FF01EB, // __restgprlr_24
|
||||
0xC0FF21EB, // __restgprlr_25
|
||||
0xC8FF41EB, // __restgprlr_26
|
||||
0xD0FF61EB, // __restgprlr_27
|
||||
0xD8FF81EB, // __restgprlr_28
|
||||
0xE0FFA1EB, // __restgprlr_29
|
||||
0xE8FFC1EB, // __restgprlr_30
|
||||
0xF0FFE1EB, // __restgprlr_31
|
||||
0xF8FF8181,
|
||||
0xA603887D,
|
||||
0x2000804E,
|
||||
};
|
||||
|
||||
uint32_t gplr_start = 0;
|
||||
const xe_xex2_header_t* header = module_->xex_header();
|
||||
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) {
|
||||
gplr_start = xe_memory_search_aligned(
|
||||
memory_, start_address, end_address,
|
||||
code_values, XECOUNT(code_values));
|
||||
if (gplr_start) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
i += section->info.page_count;
|
||||
}
|
||||
if (!gplr_start) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Add function stubs.
|
||||
char name[32];
|
||||
uint32_t address = gplr_start;
|
||||
for (int n = 14; n <= 31; n++) {
|
||||
xesnprintf(name, XECOUNT(name), "__savegprlr_%d", n);
|
||||
FunctionSymbol* fn = GetOrInsertFunction(address);
|
||||
fn->end_address = fn->start_address + (31 - n) * 4 + 2 * 4;
|
||||
fn->name = xestrdupa(name);
|
||||
fn->type = FunctionSymbol::User;
|
||||
fn->flags |= FunctionSymbol::kFlagSaveGprLr;
|
||||
address += 4;
|
||||
}
|
||||
address = gplr_start + 20 * 4;
|
||||
for (int n = 14; n <= 31; n++) {
|
||||
xesnprintf(name, XECOUNT(name), "__restgprlr_%d", n);
|
||||
FunctionSymbol* fn = GetOrInsertFunction(address);
|
||||
fn->end_address = fn->start_address + (31 - n) * 4 + 3 * 4;
|
||||
fn->name = xestrdupa(name);
|
||||
fn->type = FunctionSymbol::User;
|
||||
fn->flags |= FunctionSymbol::kFlagRestGprLr;
|
||||
address += 4;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int XexSymbolDatabase::AddImports(const xe_xex2_import_library_t* library) {
|
||||
xe_xex2_ref xex = module_->xex();
|
||||
xe_xex2_import_info_t* import_infos;
|
||||
size_t import_info_count;
|
||||
if (xe_xex2_get_import_infos(xex, library, &import_infos,
|
||||
&import_info_count)) {
|
||||
xe_xex2_release(xex);
|
||||
return 1;
|
||||
}
|
||||
|
||||
char name[128];
|
||||
for (size_t n = 0; n < import_info_count; n++) {
|
||||
const xe_xex2_import_info_t* info = &import_infos[n];
|
||||
|
||||
KernelExport* kernel_export = export_resolver_->GetExportByOrdinal(
|
||||
library->name, info->ordinal);
|
||||
|
||||
VariableSymbol* var = GetOrInsertVariable(info->value_address);
|
||||
if (kernel_export) {
|
||||
if (info->thunk_address) {
|
||||
xesnprintfa(name, XECOUNT(name), "__imp__%s", kernel_export->name);
|
||||
} else {
|
||||
xesnprintfa(name, XECOUNT(name), "%s", kernel_export->name);
|
||||
}
|
||||
} else {
|
||||
xesnprintfa(name, XECOUNT(name), "__imp__%s_%.3X", library->name,
|
||||
info->ordinal);
|
||||
}
|
||||
var->name = xestrdupa(name);
|
||||
if (info->thunk_address) {
|
||||
FunctionSymbol* fn = GetOrInsertFunction(info->thunk_address);
|
||||
fn->end_address = fn->start_address + 16 - 4;
|
||||
fn->type = FunctionSymbol::Kernel;
|
||||
fn->kernel_export = kernel_export;
|
||||
if (kernel_export) {
|
||||
xesnprintfa(name, XECOUNT(name), "%s", kernel_export->name);
|
||||
} else {
|
||||
xesnprintfa(name, XECOUNT(name), "__kernel_%s_%.3X", library->name,
|
||||
info->ordinal);
|
||||
}
|
||||
fn->name = xestrdupa(name);
|
||||
}
|
||||
}
|
||||
|
||||
xe_free(import_infos);
|
||||
xe_xex2_release(xex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int XexSymbolDatabase::AddMethodHints() {
|
||||
PEMethodInfo* method_infos;
|
||||
size_t method_info_count;
|
||||
if (module_->GetMethodHints(&method_infos, &method_info_count)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (size_t n = 0; n < method_info_count; n++) {
|
||||
PEMethodInfo* method_info = &method_infos[n];
|
||||
FunctionSymbol* fn = GetOrInsertFunction(method_info->address);
|
||||
fn->end_address = method_info->address + method_info->total_length - 4;
|
||||
fn->type = FunctionSymbol::User;
|
||||
// TODO(benvanik): something with prolog_length?
|
||||
}
|
||||
|
||||
xe_free(method_infos);
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t XexSymbolDatabase::GetEntryPoint() {
|
||||
const xe_xex2_header_t* header = module_->xex_header();
|
||||
return header->exe_entry_point;
|
||||
};
|
||||
|
||||
bool XexSymbolDatabase::IsValueInTextRange(uint32_t value) {
|
||||
const xe_xex2_header_t* header = module_->xex_header();
|
||||
for (size_t n = 0, i = 0; n < header->section_count; n++) {
|
||||
const xe_xex2_section_t* section = &header->sections[n];
|
||||
|
@ -864,8 +905,3 @@ bool SymbolDatabase::IsValueInTextRange(uint32_t value) {
|
|||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SymbolDatabase::IsRestGprLr(uint32_t addr) {
|
||||
FunctionSymbol* fn = GetFunction(addr);
|
||||
return fn && (fn->flags & FunctionSymbol::kFlagRestGprLr);
|
||||
}
|
||||
|
|
|
@ -66,6 +66,33 @@ const xechar_t* Runtime::command_line() {
|
|||
return command_line_;
|
||||
}
|
||||
|
||||
int Runtime::LoadBinaryModule(const xechar_t* path, uint32_t start_address) {
|
||||
const xechar_t* name = xestrrchr(path, '/') + 1;
|
||||
|
||||
// TODO(benvanik): map file from filesystem
|
||||
xe_mmap_ref mmap = xe_mmap_open(pal_, kXEFileModeRead, path, 0, 0);
|
||||
if (!mmap) {
|
||||
return NULL;
|
||||
}
|
||||
void* addr = xe_mmap_get_addr(mmap);
|
||||
size_t length = xe_mmap_get_length(mmap);
|
||||
|
||||
int result_code = 1;
|
||||
|
||||
XEEXPECTZERO(xe_copy_memory(xe_memory_addr(memory_, start_address),
|
||||
xe_memory_get_length(memory_),
|
||||
addr, length));
|
||||
|
||||
// Prepare the module.
|
||||
XEEXPECTZERO(processor_->PrepareModule(
|
||||
name, path, start_address, start_address + length, export_resolver_));
|
||||
|
||||
result_code = 0;
|
||||
XECLEANUP:
|
||||
xe_mmap_release(mmap);
|
||||
return result_code;
|
||||
}
|
||||
|
||||
int Runtime::LoadModule(const xechar_t* path) {
|
||||
if (GetModule(path)) {
|
||||
return 0;
|
||||
|
|
Binary file not shown.
|
@ -6,3 +6,4 @@ Disassembly of section .text:
|
|||
|
||||
0000000082010000 <.text>:
|
||||
82010000: 60 83 ff ff ori r3,r4,65535
|
||||
82010004: 4e 80 00 20 blr
|
||||
|
|
|
@ -2,4 +2,5 @@
|
|||
|
||||
ori r3, r4, 0xFFFF
|
||||
|
||||
blr
|
||||
# REGISTER_OUT r3 0xBABE
|
||||
|
|
|
@ -102,15 +102,14 @@ int run_test(xe_pal_ref pal, string& src_file_path) {
|
|||
|
||||
runtime = shared_ptr<Runtime>(new Runtime(pal, processor, XT("")));
|
||||
|
||||
// TODO(benvanik): load test binary file into memory
|
||||
// bin_file_path
|
||||
// XEEXPECTZERO(runtime->LoadModule(path));
|
||||
// Load the binary module.
|
||||
XEEXPECTZERO(runtime->LoadBinaryModule(bin_file_path.c_str(), 0x82010000));
|
||||
|
||||
// Setup test state from annotations.
|
||||
XEEXPECTZERO(setup_test_state(memory, processor.get(), annotations));
|
||||
|
||||
// Execute test.
|
||||
// TODO(benvanik): execute test
|
||||
XEEXPECTZERO(processor->Execute(0x82010000));
|
||||
|
||||
// Assert test state expectations.
|
||||
XEEXPECTZERO(check_test_results(memory, processor.get(), annotations));
|
||||
|
|
Loading…
Reference in New Issue