Refactoring to allow for raw binary loading.

This commit is contained in:
Ben Vanik
2013-01-27 12:48:10 -08:00
parent 26d5df0d38
commit bba99d4a22
14 changed files with 378 additions and 231 deletions

View File

@@ -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,

View File

@@ -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());

View File

@@ -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;
}

View File

@@ -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);
}