Real modules and threads (mostly).
Need events/waiting to get proper launch thread behavior.
This commit is contained in:
@@ -19,17 +19,16 @@ using namespace xe::kernel;
|
||||
using namespace xe::kernel::xam;
|
||||
|
||||
|
||||
XamModule::XamModule(xe_pal_ref pal, xe_memory_ref memory,
|
||||
shared_ptr<ExportResolver> resolver) :
|
||||
KernelModule(pal, memory, resolver) {
|
||||
resolver->RegisterTable(
|
||||
XamModule::XamModule(Runtime* runtime) :
|
||||
KernelModule(runtime) {
|
||||
export_resolver_->RegisterTable(
|
||||
"xam.xex", xam_export_table, XECOUNT(xam_export_table));
|
||||
|
||||
// Setup the xam state instance.
|
||||
xam_state = auto_ptr<XamState>(new XamState(pal, memory, resolver));
|
||||
xam_state = auto_ptr<XamState>(new XamState(pal_, memory_, export_resolver_));
|
||||
|
||||
// Register all exported functions.
|
||||
RegisterInfoExports(resolver.get(), xam_state.get());
|
||||
RegisterInfoExports(export_resolver_.get(), xam_state.get());
|
||||
}
|
||||
|
||||
XamModule::~XamModule() {
|
||||
|
||||
@@ -26,8 +26,7 @@ class XamState;
|
||||
|
||||
class XamModule : public KernelModule {
|
||||
public:
|
||||
XamModule(xe_pal_ref pal, xe_memory_ref memory,
|
||||
shared_ptr<ExportResolver> resolver);
|
||||
XamModule(Runtime* runtime);
|
||||
virtual ~XamModule();
|
||||
|
||||
private:
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
|
||||
#include "kernel/modules/xboxkrnl/kernel_state.h"
|
||||
|
||||
#include "kernel/modules/xboxkrnl/xobject.h"
|
||||
|
||||
|
||||
using namespace xe;
|
||||
using namespace xe::kernel;
|
||||
@@ -20,14 +22,88 @@ namespace {
|
||||
}
|
||||
|
||||
|
||||
KernelState::KernelState(xe_pal_ref pal, xe_memory_ref memory,
|
||||
shared_ptr<ExportResolver> export_resolver) {
|
||||
this->pal = xe_pal_retain(pal);
|
||||
this->memory = xe_memory_retain(memory);
|
||||
export_resolver_ = export_resolver;
|
||||
KernelState::KernelState(Runtime* runtime) :
|
||||
runtime_(runtime),
|
||||
next_handle_(0) {
|
||||
pal_ = runtime->pal();
|
||||
memory_ = runtime->memory();
|
||||
processor_ = runtime->processor();
|
||||
|
||||
objects_mutex_ = xe_mutex_alloc(0);
|
||||
XEASSERTNOTNULL(objects_mutex_);
|
||||
}
|
||||
|
||||
KernelState::~KernelState() {
|
||||
xe_memory_release(memory);
|
||||
xe_pal_release(pal);
|
||||
// Delete all objects.
|
||||
// We first copy the list to another list so that the deletion of the objects
|
||||
// doesn't mess up iteration.
|
||||
std::vector<XObject*> all_objects;
|
||||
xe_mutex_lock(objects_mutex_);
|
||||
for (std::tr1::unordered_map<X_HANDLE, XObject*>::iterator it =
|
||||
objects_.begin(); it != objects_.end(); ++it) {
|
||||
all_objects.push_back(it->second);
|
||||
}
|
||||
objects_.clear();
|
||||
xe_mutex_unlock(objects_mutex_);
|
||||
for (std::vector<XObject*>::iterator it = all_objects.begin();
|
||||
it != all_objects.end(); ++it) {
|
||||
// Perhaps call a special ForceRelease method or something?
|
||||
XObject* obj = *it;
|
||||
delete obj;
|
||||
}
|
||||
|
||||
xe_mutex_free(objects_mutex_);
|
||||
objects_mutex_ = NULL;
|
||||
|
||||
processor_.reset();
|
||||
xe_memory_release(memory_);
|
||||
xe_pal_release(pal_);
|
||||
}
|
||||
|
||||
Runtime* KernelState::runtime() {
|
||||
return runtime_;
|
||||
}
|
||||
|
||||
xe_pal_ref KernelState::pal() {
|
||||
return pal_;
|
||||
}
|
||||
|
||||
xe_memory_ref KernelState::memory() {
|
||||
return memory_;
|
||||
}
|
||||
|
||||
cpu::Processor* KernelState::processor() {
|
||||
return processor_.get();
|
||||
}
|
||||
|
||||
// TODO(benvanik): invesitgate better handle storage/structure.
|
||||
// A much better way of doing handles, if performance becomes an issue, would
|
||||
// be to try to make the pointers 32bit. Then we could round-trip them through
|
||||
// PPC code without needing to keep a map.
|
||||
// To achieve this we could try doing allocs in the 32-bit address space via
|
||||
// the OS alloc calls, or maybe create a section with a reserved size at load
|
||||
// time (65k handles * 4 is more than enough?).
|
||||
// We could then use a free list of handle IDs and allocate/release lock-free.
|
||||
|
||||
XObject* KernelState::GetObject(X_HANDLE handle) {
|
||||
xe_mutex_lock(objects_mutex_);
|
||||
std::tr1::unordered_map<X_HANDLE, XObject*>::iterator it =
|
||||
objects_.find(handle);
|
||||
XObject* value = it != objects_.end() ? it->second : NULL;
|
||||
xe_mutex_unlock(objects_mutex_);
|
||||
return value;
|
||||
}
|
||||
|
||||
X_HANDLE KernelState::InsertObject(XObject* obj) {
|
||||
xe_mutex_lock(objects_mutex_);
|
||||
X_HANDLE handle = 0x00001000 + (++next_handle_);
|
||||
objects_.insert(std::pair<X_HANDLE, XObject*>(handle, obj));
|
||||
xe_mutex_unlock(objects_mutex_);
|
||||
return handle;
|
||||
}
|
||||
|
||||
void KernelState::RemoveObject(XObject* obj) {
|
||||
xe_mutex_lock(objects_mutex_);
|
||||
objects_.erase(obj->handle());
|
||||
xe_mutex_unlock(objects_mutex_);
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
#include <xenia/kernel/export.h>
|
||||
#include <xenia/kernel/kernel_module.h>
|
||||
#include <xenia/kernel/xbox.h>
|
||||
|
||||
|
||||
namespace xe {
|
||||
@@ -22,17 +23,35 @@ namespace kernel {
|
||||
namespace xboxkrnl {
|
||||
|
||||
|
||||
class XObject;
|
||||
|
||||
|
||||
class KernelState {
|
||||
public:
|
||||
KernelState(xe_pal_ref pal, xe_memory_ref memory,
|
||||
shared_ptr<ExportResolver> export_resolver);
|
||||
KernelState(Runtime* runtime);
|
||||
~KernelState();
|
||||
|
||||
xe_pal_ref pal;
|
||||
xe_memory_ref memory;
|
||||
XObject* GetObject(X_HANDLE handle);
|
||||
|
||||
Runtime* runtime();
|
||||
xe_pal_ref pal();
|
||||
xe_memory_ref memory();
|
||||
cpu::Processor* processor();
|
||||
|
||||
private:
|
||||
shared_ptr<ExportResolver> export_resolver_;
|
||||
X_HANDLE InsertObject(XObject* obj);
|
||||
void RemoveObject(XObject* obj);
|
||||
|
||||
Runtime* runtime_;
|
||||
xe_pal_ref pal_;
|
||||
xe_memory_ref memory_;
|
||||
shared_ptr<cpu::Processor> processor_;
|
||||
|
||||
xe_mutex_t* objects_mutex_;
|
||||
X_HANDLE next_handle_;
|
||||
std::tr1::unordered_map<X_HANDLE, XObject*> objects_;
|
||||
|
||||
friend class XObject;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
#include "kernel/modules/xboxkrnl/module.h"
|
||||
|
||||
#include "kernel/modules/xboxkrnl/kernel_state.h"
|
||||
#include "kernel/modules/xboxkrnl/objects/xmodule.h"
|
||||
|
||||
#include "kernel/modules/xboxkrnl/xboxkrnl_hal.h"
|
||||
#include "kernel/modules/xboxkrnl/xboxkrnl_memory.h"
|
||||
#include "kernel/modules/xboxkrnl/xboxkrnl_module.h"
|
||||
@@ -29,27 +31,28 @@ namespace {
|
||||
}
|
||||
|
||||
|
||||
XboxkrnlModule::XboxkrnlModule(xe_pal_ref pal, xe_memory_ref memory,
|
||||
shared_ptr<ExportResolver> resolver) :
|
||||
KernelModule(pal, memory, resolver) {
|
||||
XboxkrnlModule::XboxkrnlModule(Runtime* runtime) :
|
||||
KernelModule(runtime) {
|
||||
ExportResolver* resolver = export_resolver_.get();
|
||||
|
||||
resolver->RegisterTable(
|
||||
"xboxkrnl.exe", xboxkrnl_export_table, XECOUNT(xboxkrnl_export_table));
|
||||
|
||||
// Setup the kernel state instance.
|
||||
// This is where all kernel objects are kept while running.
|
||||
kernel_state = auto_ptr<KernelState>(new KernelState(pal, memory, resolver));
|
||||
kernel_state_ = auto_ptr<KernelState>(new KernelState(runtime));
|
||||
|
||||
// Register all exported functions.
|
||||
RegisterHalExports(resolver.get(), kernel_state.get());
|
||||
RegisterMemoryExports(resolver.get(), kernel_state.get());
|
||||
RegisterModuleExports(resolver.get(), kernel_state.get());
|
||||
RegisterRtlExports(resolver.get(), kernel_state.get());
|
||||
RegisterThreadingExports(resolver.get(), kernel_state.get());
|
||||
RegisterHalExports(resolver, kernel_state_.get());
|
||||
RegisterMemoryExports(resolver, kernel_state_.get());
|
||||
RegisterModuleExports(resolver, kernel_state_.get());
|
||||
RegisterRtlExports(resolver, kernel_state_.get());
|
||||
RegisterThreadingExports(resolver, kernel_state_.get());
|
||||
|
||||
// TODO(benvanik): alloc heap memory somewhere in user space
|
||||
// TODO(benvanik): tools for reading/writing to heap memory
|
||||
|
||||
uint8_t* mem = xe_memory_addr(memory, 0);
|
||||
uint8_t* mem = xe_memory_addr(memory_, 0);
|
||||
|
||||
// KeDebugMonitorData (?*)
|
||||
// I'm not sure what this is for, but games make sure it's not null and
|
||||
@@ -100,3 +103,42 @@ XboxkrnlModule::XboxkrnlModule(xe_pal_ref pal, xe_memory_ref memory,
|
||||
|
||||
XboxkrnlModule::~XboxkrnlModule() {
|
||||
}
|
||||
|
||||
int XboxkrnlModule::LaunchModule(const xechar_t* path) {
|
||||
// TODO(benvanik): setup the virtual filesystem map and use LoadFromFile.
|
||||
|
||||
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);
|
||||
|
||||
char path_a[2048];
|
||||
XEIGNORE(xestrnarrow(path_a, XECOUNT(path_a), path));
|
||||
|
||||
// Create and load the module.
|
||||
XModule* module = new XModule(kernel_state_.get(), path_a);
|
||||
X_STATUS status = module->LoadFromMemory(addr, length);
|
||||
|
||||
// TODO(benvanik): retain memory somehow? is it needed?
|
||||
xe_mmap_release(mmap);
|
||||
|
||||
if (XFAILED(status)) {
|
||||
XELOGE(XT("Failed to load module"));
|
||||
module->Release();
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Launch the module.
|
||||
status = module->Launch(0);
|
||||
if (XFAILED(status)) {
|
||||
XELOGE(XT("Failed to launch module"));
|
||||
module->Release();
|
||||
return 2;
|
||||
}
|
||||
|
||||
module->Release();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -26,12 +26,13 @@ class KernelState;
|
||||
|
||||
class XboxkrnlModule : public KernelModule {
|
||||
public:
|
||||
XboxkrnlModule(xe_pal_ref pal, xe_memory_ref memory,
|
||||
shared_ptr<ExportResolver> resolver);
|
||||
XboxkrnlModule(Runtime* runtime);
|
||||
virtual ~XboxkrnlModule();
|
||||
|
||||
int LaunchModule(const xechar_t* path);
|
||||
|
||||
private:
|
||||
auto_ptr<KernelState> kernel_state;
|
||||
auto_ptr<KernelState> kernel_state_;
|
||||
};
|
||||
|
||||
|
||||
|
||||
7
src/kernel/modules/xboxkrnl/objects/sources.gypi
Normal file
7
src/kernel/modules/xboxkrnl/objects/sources.gypi
Normal file
@@ -0,0 +1,7 @@
|
||||
# Copyright 2013 Ben Vanik. All Rights Reserved.
|
||||
{
|
||||
'sources': [
|
||||
'xmodule.cc',
|
||||
'xthread.cc',
|
||||
],
|
||||
}
|
||||
@@ -7,244 +7,124 @@
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#include <xenia/kernel/user_module.h>
|
||||
#include "kernel/modules/xboxkrnl/objects/xmodule.h"
|
||||
|
||||
#include <third_party/pe/pe_image.h>
|
||||
#include "kernel/modules/xboxkrnl/objects/xthread.h"
|
||||
|
||||
|
||||
using namespace xe;
|
||||
using namespace kernel;
|
||||
using namespace xe::kernel;
|
||||
using namespace xe::kernel::xboxkrnl;
|
||||
|
||||
|
||||
UserModule::UserModule(xe_memory_ref memory) {
|
||||
memory_ = xe_memory_retain(memory);
|
||||
xex_ = NULL;
|
||||
namespace {
|
||||
}
|
||||
|
||||
UserModule::~UserModule() {
|
||||
for (std::vector<PESection*>::iterator it = sections_.begin();
|
||||
it != sections_.end(); ++it) {
|
||||
delete *it;
|
||||
}
|
||||
|
||||
xe_xex2_release(xex_);
|
||||
xe_memory_release(memory_);
|
||||
}
|
||||
|
||||
int UserModule::Load(const void* addr, const size_t length,
|
||||
const xechar_t* path) {
|
||||
XModule::XModule(KernelState* kernel_state, const char* path) :
|
||||
XObject(kernel_state, kTypeModule),
|
||||
xex_(NULL) {
|
||||
XEIGNORE(xestrcpy(path_, XECOUNT(path_), path));
|
||||
const xechar_t *slash = xestrrchr(path, '/');
|
||||
if (slash) {
|
||||
XEIGNORE(xestrcpy(name_, XECOUNT(name_), slash + 1));
|
||||
}
|
||||
|
||||
xe_xex2_options_t xex_options;
|
||||
xex_ = xe_xex2_load(memory_, addr, length, xex_options);
|
||||
XEEXPECTNOTNULL(xex_);
|
||||
|
||||
XEEXPECTZERO(LoadPE());
|
||||
|
||||
return 0;
|
||||
|
||||
XECLEANUP:
|
||||
return 1;
|
||||
}
|
||||
|
||||
const xechar_t* UserModule::path() {
|
||||
XModule::~XModule() {
|
||||
xe_xex2_release(xex_);
|
||||
}
|
||||
|
||||
const char* XModule::path() {
|
||||
return path_;
|
||||
}
|
||||
|
||||
const xechar_t* UserModule::name() {
|
||||
const char* XModule::name() {
|
||||
return name_;
|
||||
}
|
||||
|
||||
uint32_t UserModule::handle() {
|
||||
return handle_;
|
||||
}
|
||||
|
||||
xe_xex2_ref UserModule::xex() {
|
||||
xe_xex2_ref XModule::xex() {
|
||||
return xe_xex2_retain(xex_);
|
||||
}
|
||||
|
||||
const xe_xex2_header_t* UserModule::xex_header() {
|
||||
const xe_xex2_header_t* XModule::xex_header() {
|
||||
return xe_xex2_get_header(xex_);
|
||||
}
|
||||
|
||||
void* UserModule::GetProcAddress(const uint32_t ordinal) {
|
||||
X_STATUS XModule::LoadFromFile(const char* path) {
|
||||
// TODO(benvanik): load from virtual filesystem.
|
||||
XEASSERTALWAYS();
|
||||
return NULL;
|
||||
return X_STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
// IMAGE_CE_RUNTIME_FUNCTION_ENTRY
|
||||
// http://msdn.microsoft.com/en-us/library/ms879748.aspx
|
||||
typedef struct IMAGE_XBOX_RUNTIME_FUNCTION_ENTRY_t {
|
||||
uint32_t FuncStart; // Virtual address
|
||||
union {
|
||||
struct {
|
||||
uint32_t PrologLen : 8; // # of prolog instructions (size = x4)
|
||||
uint32_t FuncLen : 22; // # of instructions total (size = x4)
|
||||
uint32_t ThirtyTwoBit : 1; // Always 1
|
||||
uint32_t ExceptionFlag : 1; // 1 if PDATA_EH in .text -- unknown if used
|
||||
} Flags;
|
||||
uint32_t FlagsValue; // To make byte swapping easier
|
||||
};
|
||||
} IMAGE_XBOX_RUNTIME_FUNCTION_ENTRY;
|
||||
X_STATUS XModule::LoadFromMemory(const void* addr, const size_t length) {
|
||||
// Load the XEX into memory and decrypt.
|
||||
xe_xex2_options_t xex_options;
|
||||
xex_ = xe_xex2_load(kernel_state()->memory(), addr, length, xex_options);
|
||||
XEEXPECTNOTNULL(xex_);
|
||||
|
||||
int UserModule::LoadPE() {
|
||||
const xe_xex2_header_t* xex_header = xe_xex2_get_header(xex_);
|
||||
uint8_t* mem = xe_memory_addr(memory_, 0);
|
||||
const uint8_t* p = mem + xex_header->exe_address;
|
||||
// Prepare the module for execution.
|
||||
XEEXPECTZERO(kernel_state()->processor()->PrepareModule(
|
||||
name_, path_, xex_, runtime()->export_resolver()));
|
||||
|
||||
// Verify DOS signature (MZ).
|
||||
const IMAGE_DOS_HEADER* doshdr = (const IMAGE_DOS_HEADER*)p;
|
||||
if (doshdr->e_magic != IMAGE_DOS_SIGNATURE) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Move to the NT header offset from the DOS header.
|
||||
p += doshdr->e_lfanew;
|
||||
|
||||
// Verify NT signature (PE\0\0).
|
||||
const IMAGE_NT_HEADERS32* nthdr = (const IMAGE_NT_HEADERS32*)(p);
|
||||
if (nthdr->Signature != IMAGE_NT_SIGNATURE) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Verify matches an Xbox PE.
|
||||
const IMAGE_FILE_HEADER* filehdr = &nthdr->FileHeader;
|
||||
if ((filehdr->Machine != IMAGE_FILE_MACHINE_POWERPCBE) ||
|
||||
!(filehdr->Characteristics & IMAGE_FILE_32BIT_MACHINE)) {
|
||||
return 1;
|
||||
}
|
||||
// Verify the expected size.
|
||||
if (filehdr->SizeOfOptionalHeader != IMAGE_SIZEOF_NT_OPTIONAL_HEADER) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Verify optional header is 32bit.
|
||||
const IMAGE_OPTIONAL_HEADER32* opthdr = &nthdr->OptionalHeader;
|
||||
if (opthdr->Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
|
||||
return 1;
|
||||
}
|
||||
// Verify subsystem.
|
||||
if (opthdr->Subsystem != IMAGE_SUBSYSTEM_XBOX) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Linker version - likely 8+
|
||||
// Could be useful for recognizing certain patterns
|
||||
//opthdr->MajorLinkerVersion; opthdr->MinorLinkerVersion;
|
||||
|
||||
// Data directories of interest:
|
||||
// EXPORT IMAGE_EXPORT_DIRECTORY
|
||||
// IMPORT IMAGE_IMPORT_DESCRIPTOR[]
|
||||
// EXCEPTION IMAGE_CE_RUNTIME_FUNCTION_ENTRY[]
|
||||
// BASERELOC
|
||||
// DEBUG IMAGE_DEBUG_DIRECTORY[]
|
||||
// ARCHITECTURE /IMAGE_ARCHITECTURE_HEADER/ ----- import thunks!
|
||||
// TLS IMAGE_TLS_DIRECTORY
|
||||
// IAT Import Address Table ptr
|
||||
//opthdr->DataDirectory[IMAGE_DIRECTORY_ENTRY_X].VirtualAddress / .Size
|
||||
|
||||
// Quick scan to determine bounds of sections.
|
||||
size_t upper_address = 0;
|
||||
const IMAGE_SECTION_HEADER* sechdr = IMAGE_FIRST_SECTION(nthdr);
|
||||
for (size_t n = 0; n < filehdr->NumberOfSections; n++, sechdr++) {
|
||||
const size_t physical_address = opthdr->ImageBase + sechdr->VirtualAddress;
|
||||
upper_address =
|
||||
MAX(upper_address, physical_address + sechdr->Misc.VirtualSize);
|
||||
}
|
||||
|
||||
// Setup/load sections.
|
||||
sechdr = IMAGE_FIRST_SECTION(nthdr);
|
||||
for (size_t n = 0; n < filehdr->NumberOfSections; n++, sechdr++) {
|
||||
PESection* section = (PESection*)xe_calloc(sizeof(PESection));
|
||||
xe_copy_memory(section->name, sizeof(section->name),
|
||||
sechdr->Name, sizeof(sechdr->Name));
|
||||
section->name[8] = 0;
|
||||
section->raw_address = sechdr->PointerToRawData;
|
||||
section->raw_size = sechdr->SizeOfRawData;
|
||||
section->address = xex_header->exe_address + sechdr->VirtualAddress;
|
||||
section->size = sechdr->Misc.VirtualSize;
|
||||
section->flags = sechdr->Characteristics;
|
||||
sections_.push_back(section);
|
||||
}
|
||||
|
||||
//DumpTLSDirectory(pImageBase, pNTHeader, (PIMAGE_TLS_DIRECTORY32)0);
|
||||
//DumpExportsSection(pImageBase, pNTHeader);
|
||||
return 0;
|
||||
}
|
||||
|
||||
PESection* UserModule::GetSection(const char *name) {
|
||||
for (std::vector<PESection*>::iterator it = sections_.begin();
|
||||
it != sections_.end(); ++it) {
|
||||
if (!xestrcmpa((*it)->name, name)) {
|
||||
return *it;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int UserModule::GetMethodHints(PEMethodInfo** out_method_infos,
|
||||
size_t* out_method_info_count) {
|
||||
uint8_t* mem = xe_memory_addr(memory_, 0);
|
||||
|
||||
*out_method_infos = NULL;
|
||||
*out_method_info_count = 0;
|
||||
|
||||
const IMAGE_XBOX_RUNTIME_FUNCTION_ENTRY* entry = NULL;
|
||||
|
||||
// Find pdata, which contains the exception handling entries.
|
||||
PESection* pdata = GetSection(".pdata");
|
||||
if (!pdata) {
|
||||
// No exception data to go on.
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Resolve.
|
||||
const uint8_t* p = mem + pdata->address;
|
||||
|
||||
// Entry count = pdata size / sizeof(entry).
|
||||
size_t entry_count = pdata->size / sizeof(IMAGE_XBOX_RUNTIME_FUNCTION_ENTRY);
|
||||
if (!entry_count) {
|
||||
// Empty?
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Allocate output.
|
||||
PEMethodInfo* method_infos = (PEMethodInfo*)xe_calloc(
|
||||
entry_count * sizeof(PEMethodInfo));
|
||||
XEEXPECTNOTNULL(method_infos);
|
||||
|
||||
// Parse entries.
|
||||
// NOTE: entries are in memory as big endian, so pull them out and swap the
|
||||
// values before using them.
|
||||
entry = (const IMAGE_XBOX_RUNTIME_FUNCTION_ENTRY*)p;
|
||||
IMAGE_XBOX_RUNTIME_FUNCTION_ENTRY temp_entry;
|
||||
for (size_t n = 0; n < entry_count; n++, entry++) {
|
||||
PEMethodInfo* method_info = &method_infos[n];
|
||||
method_info->address = XESWAP32BE(entry->FuncStart);
|
||||
|
||||
// The bitfield needs to be swapped by hand.
|
||||
temp_entry.FlagsValue = XESWAP32BE(entry->FlagsValue);
|
||||
method_info->total_length = temp_entry.Flags.FuncLen * 4;
|
||||
method_info->prolog_length = temp_entry.Flags.PrologLen * 4;
|
||||
}
|
||||
|
||||
*out_method_infos = method_infos;
|
||||
*out_method_info_count = entry_count;
|
||||
return 0;
|
||||
return X_STATUS_SUCCESS;
|
||||
|
||||
XECLEANUP:
|
||||
if (method_infos) {
|
||||
xe_free(method_infos);
|
||||
}
|
||||
return 1;
|
||||
return X_STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
void UserModule::Dump(ExportResolver* export_resolver) {
|
||||
//const uint8_t *mem = (const uint8_t*)xe_memory_addr(memory_, 0);
|
||||
X_STATUS XModule::GetSection(const char* name,
|
||||
uint32_t* out_data, uint32_t* out_size) {
|
||||
const PESection* section = xe_xex2_get_pe_section(xex_, name);
|
||||
if (!section) {
|
||||
return X_STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
*out_data = section->address;
|
||||
*out_size = section->size;
|
||||
return X_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
void* XModule::GetProcAddressByOrdinal(uint16_t ordinal) {
|
||||
// TODO(benvanik): check export tables.
|
||||
XELOGE(XT("GetProcAddressByOrdinal not implemented"));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
X_STATUS XModule::Launch(uint32_t flags) {
|
||||
const xe_xex2_header_t* header = xex_header();
|
||||
|
||||
// TODO(benvanik): set as main module/etc
|
||||
// xekXexExecutableModuleHandle = xe_module_get_handle(module);
|
||||
|
||||
// Create a thread to run in.
|
||||
XThread* thread = new XThread(
|
||||
kernel_state(),
|
||||
header->exe_stack_size,
|
||||
0,
|
||||
header->exe_entry_point, NULL,
|
||||
0);
|
||||
|
||||
X_STATUS result = thread->Create();
|
||||
if (XFAILED(result)) {
|
||||
XELOGE(XT("Could not create launch thread: %.8X"), result);
|
||||
return result;
|
||||
}
|
||||
|
||||
// Wait until thread completes.
|
||||
// XLARGE_INTEGER timeout = XINFINITE;
|
||||
// xekNtWaitForSingleObjectEx(thread_handle, TRUE, &timeout);
|
||||
|
||||
while (true) {
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
thread->Release();
|
||||
|
||||
return X_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
void XModule::Dump() {
|
||||
ExportResolver* export_resolver = runtime()->export_resolver().get();
|
||||
const xe_xex2_header_t* header = xe_xex2_get_header(xex_);
|
||||
|
||||
// XEX info.
|
||||
62
src/kernel/modules/xboxkrnl/objects/xmodule.h
Normal file
62
src/kernel/modules/xboxkrnl/objects/xmodule.h
Normal file
@@ -0,0 +1,62 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* 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. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef XENIA_KERNEL_MODULES_XBOXKRNL_XMODULE_H_
|
||||
#define XENIA_KERNEL_MODULES_XBOXKRNL_XMODULE_H_
|
||||
|
||||
#include "kernel/modules/xboxkrnl/xobject.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <xenia/kernel/export.h>
|
||||
#include <xenia/kernel/xbox.h>
|
||||
#include <xenia/kernel/xex2.h>
|
||||
|
||||
|
||||
namespace xe {
|
||||
namespace kernel {
|
||||
namespace xboxkrnl {
|
||||
|
||||
|
||||
class XModule : public XObject {
|
||||
public:
|
||||
XModule(KernelState* kernel_state, const char* path);
|
||||
virtual ~XModule();
|
||||
|
||||
const char* path();
|
||||
const char* name();
|
||||
xe_xex2_ref xex();
|
||||
const xe_xex2_header_t* xex_header();
|
||||
|
||||
X_STATUS LoadFromFile(const char* path);
|
||||
X_STATUS LoadFromMemory(const void* addr, const size_t length);
|
||||
|
||||
X_STATUS GetSection(const char* name, uint32_t* out_data, uint32_t* out_size);
|
||||
void* GetProcAddressByOrdinal(uint16_t ordinal);
|
||||
|
||||
X_STATUS Launch(uint32_t flags);
|
||||
|
||||
void Dump();
|
||||
|
||||
private:
|
||||
int LoadPE();
|
||||
|
||||
char name_[256];
|
||||
char path_[2048];
|
||||
|
||||
xe_xex2_ref xex_;
|
||||
};
|
||||
|
||||
|
||||
} // namespace xboxkrnl
|
||||
} // namespace kernel
|
||||
} // namespace xe
|
||||
|
||||
|
||||
#endif // XENIA_KERNEL_MODULES_XBOXKRNL_XMODULE_H_
|
||||
232
src/kernel/modules/xboxkrnl/objects/xthread.cc
Normal file
232
src/kernel/modules/xboxkrnl/objects/xthread.cc
Normal file
@@ -0,0 +1,232 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* 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 "kernel/modules/xboxkrnl/objects/xthread.h"
|
||||
|
||||
|
||||
using namespace xe;
|
||||
using namespace xe::kernel;
|
||||
using namespace xe::kernel::xboxkrnl;
|
||||
|
||||
|
||||
namespace {
|
||||
static uint32_t next_xthread_id = 0;
|
||||
}
|
||||
|
||||
|
||||
XThread::XThread(KernelState* kernel_state,
|
||||
uint32_t stack_size,
|
||||
uint32_t xapi_thread_startup,
|
||||
uint32_t start_address, uint32_t start_context,
|
||||
uint32_t creation_flags) :
|
||||
XObject(kernel_state, kTypeThread),
|
||||
thread_id_(++next_xthread_id),
|
||||
thread_handle_(0),
|
||||
thread_state_address_(0),
|
||||
processor_state_(0) {
|
||||
creation_params_.stack_size = stack_size;
|
||||
creation_params_.xapi_thread_startup = xapi_thread_startup;
|
||||
creation_params_.start_address = start_address;
|
||||
creation_params_.start_context = start_context;
|
||||
creation_params_.creation_flags = creation_flags;
|
||||
|
||||
// Adjust stack size - min of 16k.
|
||||
if (creation_params_.stack_size < 16 * 1024 * 1024) {
|
||||
creation_params_.stack_size = 16 * 1024 * 1024;
|
||||
}
|
||||
}
|
||||
|
||||
XThread::~XThread() {
|
||||
// TODO(benvanik): if executing, kill it?
|
||||
|
||||
if (processor_state_) {
|
||||
kernel_state()->processor()->DeallocThread(processor_state_);
|
||||
}
|
||||
if (thread_state_address_) {
|
||||
xe_memory_heap_free(kernel_state()->memory(), thread_state_address_, 0);
|
||||
}
|
||||
|
||||
if (thread_handle_) {
|
||||
// TODO(benvanik): platform kill
|
||||
XELOGE(XT("Thread disposed without exiting"));
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t XThread::thread_id() {
|
||||
return thread_id_;
|
||||
}
|
||||
|
||||
uint32_t XThread::last_error() {
|
||||
uint8_t *p = xe_memory_addr(memory(), thread_state_address_);
|
||||
return XEGETUINT32BE(p + 0x160);
|
||||
}
|
||||
|
||||
void XThread::set_last_error(uint32_t error_code) {
|
||||
uint8_t *p = xe_memory_addr(memory(), thread_state_address_);
|
||||
XESETUINT32BE(p + 0x160, error_code);
|
||||
}
|
||||
|
||||
X_STATUS XThread::Create() {
|
||||
// Allocate thread state block from heap.
|
||||
// This is set as r13 for user code and some special inlined Win32 calls
|
||||
// (like GetLastError/etc) will poke it directly.
|
||||
// We try to use it as our primary store of data just to keep things all
|
||||
// consistent.
|
||||
thread_state_address_ = xe_memory_heap_alloc(memory(), 0, 2048, 0);
|
||||
if (!thread_state_address_) {
|
||||
XELOGW(XT("Unable to allocate thread state block"));
|
||||
return X_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
// Setup the thread state block (last error/etc).
|
||||
// 0x100: pointer to self?
|
||||
// 0x14C: thread id
|
||||
// 0x150: if >0 then error states don't get set
|
||||
// 0x160: last error
|
||||
// So, at offset 0x100 we have a 4b pointer to offset 200, then have the
|
||||
// structure.
|
||||
uint8_t *p = xe_memory_addr(memory(), thread_state_address_);
|
||||
XESETUINT32BE(p + 0x100, thread_state_address_);
|
||||
XESETUINT32BE(p + 0x14C, thread_id_);
|
||||
XESETUINT32BE(p + 0x150, 0); // ?
|
||||
XESETUINT32BE(p + 0x160, 0); // last error
|
||||
|
||||
// Allocate processor thread state.
|
||||
// This is thread safe.
|
||||
processor_state_ = kernel_state()->processor()->AllocThread(
|
||||
creation_params_.stack_size, thread_state_address_);
|
||||
if (!processor_state_) {
|
||||
XELOGW(XT("Unable to allocate processor thread state"));
|
||||
return X_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
X_STATUS return_code = PlatformCreate();
|
||||
if (XFAILED(return_code)) {
|
||||
XELOGW(XT("Unable to create platform thread (%.8X)"), return_code);
|
||||
return return_code;
|
||||
}
|
||||
|
||||
return X_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
X_STATUS XThread::Exit(int exit_code) {
|
||||
// TODO(benvanik): set exit code in thread state block
|
||||
// TODO(benvanik); dispatch events? waiters? etc?
|
||||
|
||||
// NOTE: unless PlatformExit fails, expect it to never return!
|
||||
X_STATUS return_code = PlatformExit(exit_code);
|
||||
if (XFAILED(return_code)) {
|
||||
return return_code;
|
||||
}
|
||||
return X_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
#if XE_PLATFORM(WIN32)
|
||||
|
||||
static uint32_t __stdcall XThreadStartCallbackWin32(void* param) {
|
||||
XThread* thread = reinterpret_cast<XThread*>(param);
|
||||
thread->Execute();
|
||||
thread->Release();
|
||||
return 0;
|
||||
}
|
||||
|
||||
X_STATUS XThread::PlatformCreate() {
|
||||
XEASSERTALWAYS();
|
||||
|
||||
thread_handle_ = CreateThread(
|
||||
NULL,
|
||||
creation_params_.stack_size,
|
||||
(LPTHREAD_START_ROUTINE)XThreadStartCallbackWin32,
|
||||
this,
|
||||
creation_params.creation_flags,
|
||||
NULL);
|
||||
if (!handle) {
|
||||
uint32_t last_error = GetLastError();
|
||||
// TODO(benvanik): translate?
|
||||
XELOGE(XT("CreateThread failed with %d"), last_error);
|
||||
return last_error;
|
||||
}
|
||||
|
||||
return X_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
X_STATUS XThread::PlatformExit(int exit_code) {
|
||||
// NOTE: does not return.
|
||||
ExitThread(exit_code);
|
||||
return X_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static void* XThreadStartCallbackPthreads(void* param) {
|
||||
XThread* thread = reinterpret_cast<XThread*>(param);
|
||||
thread->Execute();
|
||||
thread->Release();
|
||||
return 0;
|
||||
}
|
||||
|
||||
X_STATUS XThread::PlatformCreate() {
|
||||
pthread_attr_t attr;
|
||||
|
||||
pthread_attr_init(&attr);
|
||||
pthread_attr_setstacksize(&attr, creation_params_.stack_size);
|
||||
|
||||
int result_code;
|
||||
if (creation_params_.creation_flags & X_CREATE_SUSPENDED) {
|
||||
result_code = pthread_create_suspended_np(
|
||||
reinterpret_cast<pthread_t*>(&thread_handle_),
|
||||
&attr,
|
||||
&XThreadStartCallbackPthreads,
|
||||
this);
|
||||
} else {
|
||||
result_code = pthread_create(
|
||||
reinterpret_cast<pthread_t*>(&thread_handle_),
|
||||
&attr,
|
||||
&XThreadStartCallbackPthreads,
|
||||
this);
|
||||
}
|
||||
|
||||
pthread_attr_destroy(&attr);
|
||||
|
||||
switch (result_code) {
|
||||
case 0:
|
||||
// Succeeded!
|
||||
return X_STATUS_SUCCESS;
|
||||
default:
|
||||
case EAGAIN:
|
||||
return X_STATUS_NO_MEMORY;
|
||||
case EINVAL:
|
||||
case EPERM:
|
||||
return X_STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
}
|
||||
|
||||
X_STATUS XThread::PlatformExit(int exit_code) {
|
||||
// NOTE: does not return.
|
||||
pthread_exit((void*)exit_code);
|
||||
return X_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
#endif // WIN32
|
||||
|
||||
void XThread::Execute() {
|
||||
// Run XapiThreadStartup first, if present.
|
||||
if (creation_params_.xapi_thread_startup) {
|
||||
XELOGE(XT("xapi_thread_startup not implemented"));
|
||||
}
|
||||
|
||||
// Run user code.
|
||||
int exit_code = kernel_state()->processor()->Execute(
|
||||
processor_state_,
|
||||
creation_params_.start_address, creation_params_.start_context);
|
||||
|
||||
// If we got here it means the execute completed without an exit being called.
|
||||
// Treat the return code as an implicit exit code.
|
||||
Exit(exit_code);
|
||||
}
|
||||
65
src/kernel/modules/xboxkrnl/objects/xthread.h
Normal file
65
src/kernel/modules/xboxkrnl/objects/xthread.h
Normal file
@@ -0,0 +1,65 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* 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. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef XENIA_KERNEL_MODULES_XBOXKRNL_XTHREAD_H_
|
||||
#define XENIA_KERNEL_MODULES_XBOXKRNL_XTHREAD_H_
|
||||
|
||||
#include "kernel/modules/xboxkrnl/xobject.h"
|
||||
|
||||
#include <xenia/kernel/xbox.h>
|
||||
|
||||
|
||||
namespace xe {
|
||||
namespace kernel {
|
||||
namespace xboxkrnl {
|
||||
|
||||
|
||||
class XThread : public XObject {
|
||||
public:
|
||||
XThread(KernelState* kernel_state,
|
||||
uint32_t stack_size,
|
||||
uint32_t xapi_thread_startup,
|
||||
uint32_t start_address, uint32_t start_context,
|
||||
uint32_t creation_flags);
|
||||
virtual ~XThread();
|
||||
|
||||
uint32_t thread_id();
|
||||
uint32_t last_error();
|
||||
void set_last_error(uint32_t error_code);
|
||||
|
||||
X_STATUS Create();
|
||||
X_STATUS Exit(int exit_code);
|
||||
|
||||
void Execute();
|
||||
|
||||
private:
|
||||
X_STATUS PlatformCreate();
|
||||
X_STATUS PlatformExit(int exit_code);
|
||||
|
||||
struct {
|
||||
uint32_t stack_size;
|
||||
uint32_t xapi_thread_startup;
|
||||
uint32_t start_address;
|
||||
uint32_t start_context;
|
||||
uint32_t creation_flags;
|
||||
} creation_params_;
|
||||
|
||||
uint32_t thread_id_;
|
||||
void* thread_handle_;
|
||||
uint32_t thread_state_address_;
|
||||
cpu::ThreadState* processor_state_;
|
||||
};
|
||||
|
||||
|
||||
} // namespace xboxkrnl
|
||||
} // namespace kernel
|
||||
} // namespace xe
|
||||
|
||||
|
||||
#endif // XENIA_KERNEL_MODULES_XBOXKRNL_XTHREAD_H_
|
||||
@@ -8,5 +8,10 @@
|
||||
'xboxkrnl_module.cc',
|
||||
'xboxkrnl_rtl.cc',
|
||||
'xboxkrnl_threading.cc',
|
||||
'xobject.cc',
|
||||
],
|
||||
|
||||
'includes': [
|
||||
'objects/sources.gypi',
|
||||
],
|
||||
}
|
||||
|
||||
@@ -1,87 +0,0 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* 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. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef XENIA_KERNEL_MODULES_XBOXKRNL_H_
|
||||
#define XENIA_KERNEL_MODULES_XBOXKRNL_H_
|
||||
|
||||
#include <xenia/common.h>
|
||||
#include <xenia/core.h>
|
||||
|
||||
|
||||
namespace xe {
|
||||
namespace kernel {
|
||||
namespace xboxkrnl {
|
||||
|
||||
|
||||
typedef uint32_t X_HANDLE;
|
||||
#define X_INVALID_HANDLE_VALUE ((X_HANDLE)-1)
|
||||
|
||||
|
||||
// NT_STATUS (STATUS_*)
|
||||
// http://msdn.microsoft.com/en-us/library/cc704588.aspx
|
||||
// Adding as needed.
|
||||
#define X_STATUS_SUCCESS ((uint32_t)0x00000000L)
|
||||
#define X_STATUS_UNSUCCESSFUL ((uint32_t)0xC0000001L)
|
||||
#define X_STATUS_NOT_IMPLEMENTED ((uint32_t)0xC0000002L)
|
||||
#define X_STATUS_ACCESS_VIOLATION ((uint32_t)0xC0000005L)
|
||||
#define X_STATUS_INVALID_HANDLE ((uint32_t)0xC0000008L)
|
||||
#define X_STATUS_INVALID_PARAMETER ((uint32_t)0xC000000DL)
|
||||
#define X_STATUS_NO_MEMORY ((uint32_t)0xC0000017L)
|
||||
#define X_STATUS_ALREADY_COMMITTED ((uint32_t)0xC0000021L)
|
||||
#define X_STATUS_ACCESS_DENIED ((uint32_t)0xC0000022L)
|
||||
#define X_STATUS_BUFFER_TOO_SMALL ((uint32_t)0xC0000023L)
|
||||
#define X_STATUS_OBJECT_TYPE_MISMATCH ((uint32_t)0xC0000024L)
|
||||
#define X_STATUS_INVALID_PAGE_PROTECTION ((uint32_t)0xC0000045L)
|
||||
|
||||
|
||||
// MEM_*, used by NtAllocateVirtualMemory
|
||||
#define X_MEM_COMMIT 0x00001000
|
||||
#define X_MEM_RESERVE 0x00002000
|
||||
#define X_MEM_DECOMMIT 0x00004000
|
||||
#define X_MEM_RELEASE 0x00008000
|
||||
#define X_MEM_FREE 0x00010000
|
||||
#define X_MEM_PRIVATE 0x00020000
|
||||
#define X_MEM_RESET 0x00080000
|
||||
#define X_MEM_TOP_DOWN 0x00100000
|
||||
#define X_MEM_NOZERO 0x00800000
|
||||
#define X_MEM_LARGE_PAGES 0x20000000
|
||||
#define X_MEM_HEAP 0x40000000
|
||||
#define X_MEM_16MB_PAGES 0x80000000 // from Valve SDK
|
||||
|
||||
|
||||
// PAGE_*, used by NtAllocateVirtualMemory
|
||||
#define X_PAGE_NOACCESS 0x00000001
|
||||
#define X_PAGE_READONLY 0x00000002
|
||||
#define X_PAGE_READWRITE 0x00000004
|
||||
#define X_PAGE_WRITECOPY 0x00000008
|
||||
#define X_PAGE_EXECUTE 0x00000010
|
||||
#define X_PAGE_EXECUTE_READ 0x00000020
|
||||
#define X_PAGE_EXECUTE_READWRITE 0x00000040
|
||||
#define X_PAGE_EXECUTE_WRITECOPY 0x00000080
|
||||
#define X_PAGE_GUARD 0x00000100
|
||||
#define X_PAGE_NOCACHE 0x00000200
|
||||
#define X_PAGE_WRITECOMBINE 0x00000400
|
||||
|
||||
|
||||
// (?), used by KeGetCurrentProcessType
|
||||
#define X_PROCTYPE_IDLE 0
|
||||
#define X_PROCTYPE_USER 1
|
||||
#define X_PROCTYPE_SYSTEM 2
|
||||
|
||||
|
||||
// TLS specials.
|
||||
#define X_TLS_OUT_OF_INDEXES UINT32_MAX // (-1)
|
||||
|
||||
|
||||
} // namespace xboxkrnl
|
||||
} // namespace kernel
|
||||
} // namespace xe
|
||||
|
||||
|
||||
#endif // XENIA_KERNEL_MODULES_XBOXKRNL_H_
|
||||
@@ -9,8 +9,9 @@
|
||||
|
||||
#include "kernel/modules/xboxkrnl/xboxkrnl_hal.h"
|
||||
|
||||
#include <xenia/kernel/xbox.h>
|
||||
|
||||
#include "kernel/shim_utils.h"
|
||||
#include "kernel/modules/xboxkrnl/xboxkrnl.h"
|
||||
|
||||
|
||||
using namespace xe;
|
||||
|
||||
@@ -9,8 +9,9 @@
|
||||
|
||||
#include "kernel/modules/xboxkrnl/xboxkrnl_memory.h"
|
||||
|
||||
#include <xenia/kernel/xbox.h>
|
||||
|
||||
#include "kernel/shim_utils.h"
|
||||
#include "kernel/modules/xboxkrnl/xboxkrnl.h"
|
||||
|
||||
|
||||
using namespace xe;
|
||||
@@ -82,7 +83,7 @@ void NtAllocateVirtualMemory_shim(
|
||||
// Allocate.
|
||||
uint32_t flags = 0;
|
||||
uint32_t addr = xe_memory_heap_alloc(
|
||||
state->memory, base_addr_value, adjusted_size, flags);
|
||||
state->memory(), base_addr_value, adjusted_size, flags);
|
||||
if (!addr) {
|
||||
// Failed - assume no memory available.
|
||||
SHIM_SET_RETURN(X_STATUS_NO_MEMORY);
|
||||
@@ -123,7 +124,7 @@ void NtFreeVirtualMemory_shim(
|
||||
|
||||
// Free.
|
||||
uint32_t flags = 0;
|
||||
uint32_t freed_size = xe_memory_heap_free(state->memory, base_addr_value,
|
||||
uint32_t freed_size = xe_memory_heap_free(state->memory(), base_addr_value,
|
||||
flags);
|
||||
if (!freed_size) {
|
||||
SHIM_SET_RETURN(X_STATUS_UNSUCCESSFUL);
|
||||
|
||||
@@ -9,10 +9,10 @@
|
||||
|
||||
#include "kernel/modules/xboxkrnl/xboxkrnl_module.h"
|
||||
|
||||
#include <xenia/kernel/xbox.h>
|
||||
#include <xenia/kernel/xex2.h>
|
||||
|
||||
#include "kernel/shim_utils.h"
|
||||
#include "kernel/modules/xboxkrnl/xboxkrnl.h"
|
||||
|
||||
|
||||
using namespace xe;
|
||||
|
||||
@@ -9,10 +9,10 @@
|
||||
|
||||
#include "kernel/modules/xboxkrnl/xboxkrnl_rtl.h"
|
||||
|
||||
#include <xenia/kernel/xbox.h>
|
||||
#include <xenia/kernel/xex2.h>
|
||||
|
||||
#include "kernel/shim_utils.h"
|
||||
#include "kernel/modules/xboxkrnl/xboxkrnl.h"
|
||||
|
||||
|
||||
using namespace xe;
|
||||
|
||||
@@ -9,8 +9,10 @@
|
||||
|
||||
#include "kernel/modules/xboxkrnl/xboxkrnl_threading.h"
|
||||
|
||||
#include <xenia/kernel/xbox.h>
|
||||
|
||||
#include "kernel/shim_utils.h"
|
||||
#include "kernel/modules/xboxkrnl/xboxkrnl.h"
|
||||
#include "kernel/modules/xboxkrnl/objects/xthread.h"
|
||||
|
||||
|
||||
using namespace xe;
|
||||
@@ -54,19 +56,55 @@ namespace {
|
||||
// }
|
||||
|
||||
|
||||
void ExCreateThread() {
|
||||
// launch native thread
|
||||
//
|
||||
}
|
||||
|
||||
|
||||
void ExCreateThread_shim(
|
||||
xe_ppc_state_t* ppc_state, KernelState* state) {
|
||||
// DWORD
|
||||
// LPHANDLE Handle,
|
||||
// DWORD StackSize,
|
||||
// LPDWORD ThreadId,
|
||||
// LPVOID XapiThreadStartup, ?? often 0
|
||||
// LPVOID StartAddress,
|
||||
// LPVOID StartContext,
|
||||
// DWORD CreationFlags // 0x80?
|
||||
|
||||
uint32_t handle_ptr = SHIM_GET_ARG_32(0);
|
||||
uint32_t stack_size = SHIM_GET_ARG_32(1);
|
||||
uint32_t thread_id_ptr = SHIM_GET_ARG_32(2);
|
||||
uint32_t xapi_thread_startup = SHIM_GET_ARG_32(3);
|
||||
uint32_t start_address = SHIM_GET_ARG_32(4);
|
||||
uint32_t start_context = SHIM_GET_ARG_32(5);
|
||||
uint32_t creation_flags = SHIM_GET_ARG_32(6);
|
||||
|
||||
XELOGD(
|
||||
XT("ExCreateThread()"));
|
||||
XT("ExCreateThread(%.8X, %d, %.8X, %.8X, %.8X, %.8X, %.8X)"),
|
||||
handle_ptr,
|
||||
stack_size,
|
||||
thread_id_ptr,
|
||||
xapi_thread_startup,
|
||||
start_address,
|
||||
start_context,
|
||||
creation_flags);
|
||||
|
||||
SHIM_SET_RETURN(0);
|
||||
XThread* thread = new XThread(
|
||||
state, stack_size, xapi_thread_startup, start_address, start_context,
|
||||
creation_flags);
|
||||
|
||||
X_STATUS result_code = thread->Create();
|
||||
if (XFAILED(result_code)) {
|
||||
// Failed!
|
||||
thread->Release();
|
||||
XELOGE(XT("Thread creation failed: %.8X"), result_code);
|
||||
SHIM_SET_RETURN(result_code);
|
||||
return;
|
||||
}
|
||||
|
||||
if (handle_ptr) {
|
||||
SHIM_SET_MEM_32(handle_ptr, thread->handle());
|
||||
}
|
||||
if (thread_id_ptr) {
|
||||
SHIM_SET_MEM_32(thread_id_ptr, thread->thread_id());
|
||||
}
|
||||
SHIM_SET_RETURN(result_code);
|
||||
}
|
||||
|
||||
|
||||
@@ -205,7 +243,7 @@ void xe::kernel::xboxkrnl::RegisterThreadingExports(
|
||||
export_resolver->SetFunctionMapping("xboxkrnl.exe", ordinal, \
|
||||
state, (xe_kernel_export_shim_fn)shim, (xe_kernel_export_impl_fn)impl)
|
||||
|
||||
SHIM_SET_MAPPING(0x0000000D, ExCreateThread_shim, ExCreateThread);
|
||||
SHIM_SET_MAPPING(0x0000000D, ExCreateThread_shim, NULL);
|
||||
|
||||
SHIM_SET_MAPPING(0x00000066, KeGetCurrentProcessType_shim, NULL);
|
||||
|
||||
|
||||
62
src/kernel/modules/xboxkrnl/xobject.cc
Normal file
62
src/kernel/modules/xboxkrnl/xobject.cc
Normal file
@@ -0,0 +1,62 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* 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 "kernel/modules/xboxkrnl/xobject.h"
|
||||
|
||||
|
||||
using namespace xe;
|
||||
using namespace xe::kernel;
|
||||
using namespace xe::kernel::xboxkrnl;
|
||||
|
||||
|
||||
XObject::XObject(KernelState* kernel_state, Type type) :
|
||||
kernel_state_(kernel_state),
|
||||
ref_count_(1),
|
||||
type_(type), handle_(X_INVALID_HANDLE_VALUE) {
|
||||
handle_ = kernel_state->InsertObject(this);
|
||||
}
|
||||
|
||||
XObject::~XObject() {
|
||||
XEASSERTZERO(ref_count_);
|
||||
|
||||
if (handle_ != X_INVALID_HANDLE_VALUE) {
|
||||
// Remove from state table.
|
||||
kernel_state_->RemoveObject(this);
|
||||
}
|
||||
}
|
||||
|
||||
Runtime* XObject::runtime() {
|
||||
return kernel_state_->runtime_;
|
||||
}
|
||||
|
||||
KernelState* XObject::kernel_state() {
|
||||
return kernel_state_;
|
||||
}
|
||||
|
||||
xe_memory_ref XObject::memory() {
|
||||
return kernel_state_->memory();
|
||||
}
|
||||
|
||||
XObject::Type XObject::type() {
|
||||
return type_;
|
||||
}
|
||||
|
||||
X_HANDLE XObject::handle() {
|
||||
return handle_;
|
||||
}
|
||||
|
||||
void XObject::Retain() {
|
||||
xe_atomic_inc_32(&ref_count_);
|
||||
}
|
||||
|
||||
void XObject::Release() {
|
||||
if (!xe_atomic_dec_32(&ref_count_)) {
|
||||
delete this;
|
||||
}
|
||||
}
|
||||
67
src/kernel/modules/xboxkrnl/xobject.h
Normal file
67
src/kernel/modules/xboxkrnl/xobject.h
Normal file
@@ -0,0 +1,67 @@
|
||||
/**
|
||||
******************************************************************************
|
||||
* 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. *
|
||||
******************************************************************************
|
||||
*/
|
||||
|
||||
#ifndef XENIA_KERNEL_MODULES_XBOXKRNL_XOBJECT_H_
|
||||
#define XENIA_KERNEL_MODULES_XBOXKRNL_XOBJECT_H_
|
||||
|
||||
#include "kernel/modules/xboxkrnl/kernel_state.h"
|
||||
|
||||
#include <xenia/kernel/xbox.h>
|
||||
|
||||
|
||||
namespace xe {
|
||||
namespace kernel {
|
||||
class Runtime;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
namespace xe {
|
||||
namespace kernel {
|
||||
namespace xboxkrnl {
|
||||
|
||||
|
||||
class XObject {
|
||||
public:
|
||||
enum Type {
|
||||
kTypeModule = 0x00000001,
|
||||
kTypeThread = 0x00000002,
|
||||
};
|
||||
|
||||
XObject(KernelState* kernel_state, Type type);
|
||||
virtual ~XObject();
|
||||
|
||||
KernelState* kernel_state();
|
||||
|
||||
Type type();
|
||||
X_HANDLE handle();
|
||||
|
||||
void Retain();
|
||||
void Release();
|
||||
|
||||
protected:
|
||||
Runtime* runtime();
|
||||
xe_memory_ref memory(); // unretained
|
||||
|
||||
private:
|
||||
KernelState* kernel_state_;
|
||||
|
||||
volatile int32_t ref_count_;
|
||||
|
||||
Type type_;
|
||||
X_HANDLE handle_;
|
||||
};
|
||||
|
||||
|
||||
} // namespace xboxkrnl
|
||||
} // namespace kernel
|
||||
} // namespace xe
|
||||
|
||||
|
||||
#endif // XENIA_KERNEL_MODULES_XBOXKRNL_XOBJECT_H_
|
||||
@@ -25,22 +25,13 @@ Runtime::Runtime(xe_pal_ref pal, shared_ptr<cpu::Processor> processor,
|
||||
XEIGNORE(xestrcpy(command_line_, XECOUNT(command_line_), command_line));
|
||||
export_resolver_ = shared_ptr<ExportResolver>(new ExportResolver());
|
||||
|
||||
kernel_modules_.push_back(
|
||||
new xboxkrnl::XboxkrnlModule(pal_, memory_, export_resolver_));
|
||||
kernel_modules_.push_back(
|
||||
new xam::XamModule(pal_, memory_, export_resolver_));
|
||||
xboxkrnl_ = auto_ptr<xboxkrnl::XboxkrnlModule>(
|
||||
new xboxkrnl::XboxkrnlModule(this));
|
||||
xam_ = auto_ptr<xam::XamModule>(
|
||||
new xam::XamModule(this));
|
||||
}
|
||||
|
||||
Runtime::~Runtime() {
|
||||
for (std::map<const xechar_t*, UserModule*>::iterator it =
|
||||
user_modules_.begin(); it != user_modules_.end(); ++it) {
|
||||
delete it->second;
|
||||
}
|
||||
for (std::vector<KernelModule*>::iterator it = kernel_modules_.begin();
|
||||
it != kernel_modules_.end(); ++it) {
|
||||
delete *it;
|
||||
}
|
||||
|
||||
xe_memory_release(memory_);
|
||||
xe_pal_release(pal_);
|
||||
}
|
||||
@@ -65,117 +56,6 @@ 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.
|
||||
char name_a[2048];
|
||||
XEEXPECTTRUE(xestrnarrow(name_a, XECOUNT(name_a), name));
|
||||
char path_a[2048];
|
||||
XEEXPECTTRUE(xestrnarrow(path_a, XECOUNT(path_a), path));
|
||||
XEEXPECTZERO(processor_->PrepareModule(
|
||||
name_a, path_a, 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;
|
||||
}
|
||||
|
||||
// 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);
|
||||
|
||||
UserModule* module = new UserModule(memory_);
|
||||
int result_code = module->Load(addr, length, path);
|
||||
|
||||
// TODO(benvanik): retain memory somehow? is it needed?
|
||||
xe_mmap_release(mmap);
|
||||
|
||||
if (result_code) {
|
||||
delete module;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Prepare the module.
|
||||
XEEXPECTZERO(processor_->PrepareModule(module, export_resolver_));
|
||||
|
||||
// Stash in modules list (takes reference).
|
||||
user_modules_.insert(std::pair<const xechar_t*, UserModule*>(path, module));
|
||||
|
||||
return 0;
|
||||
|
||||
XECLEANUP:
|
||||
delete module;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void Runtime::LaunchModule(UserModule* user_module) {
|
||||
const xe_xex2_header_t *xex_header = user_module->xex_header();
|
||||
|
||||
// TODO(benvanik): set as main module/etc
|
||||
// xekXexExecutableModuleHandle = xe_module_get_handle(module);
|
||||
|
||||
// Setup the heap (and TLS?).
|
||||
// xex_header->exe_heap_size;
|
||||
|
||||
// Launch thread.
|
||||
// XHANDLE thread_handle;
|
||||
// XDWORD thread_id;
|
||||
// XBOOL result = xekExCreateThread(&thread_handle, xex_header->exe_stack_size, &thread_id, NULL, (void*)xex_header->exe_entry_point, NULL, 0);
|
||||
|
||||
// Wait until thread completes.
|
||||
// XLARGE_INTEGER timeout = XINFINITE;
|
||||
// xekNtWaitForSingleObjectEx(thread_handle, TRUE, &timeout);
|
||||
|
||||
// Simulate a thread.
|
||||
uint32_t stack_size = xex_header->exe_stack_size;
|
||||
if (stack_size < 16 * 1024 * 1024) {
|
||||
stack_size = 16 * 1024 * 1024;
|
||||
}
|
||||
ThreadState* thread_state = processor_->AllocThread(
|
||||
0x80000000, stack_size);
|
||||
|
||||
// Execute test.
|
||||
processor_->Execute(thread_state, xex_header->exe_entry_point);
|
||||
|
||||
processor_->DeallocThread(thread_state);
|
||||
}
|
||||
|
||||
UserModule* Runtime::GetModule(const xechar_t* path) {
|
||||
std::map<const xechar_t*, UserModule*>::iterator it =
|
||||
user_modules_.find(path);
|
||||
if (it != user_modules_.end()) {
|
||||
return it->second;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void Runtime::UnloadModule(UserModule* user_module) {
|
||||
// TODO(benvanik): unload module
|
||||
XEASSERTALWAYS();
|
||||
int Runtime::LaunchModule(const xechar_t* path) {
|
||||
return xboxkrnl_->LaunchModule(path);
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
'sources': [
|
||||
'export.cc',
|
||||
'runtime.cc',
|
||||
'user_module.cc',
|
||||
'xex2.cc',
|
||||
],
|
||||
|
||||
|
||||
@@ -9,11 +9,14 @@
|
||||
|
||||
#include <xenia/kernel/xex2.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <third_party/crypto/rijndael-alg-fst.h>
|
||||
#include <third_party/crypto/rijndael-alg-fst.c>
|
||||
#include <third_party/mspack/lzx.h>
|
||||
#include <third_party/mspack/lzxd.c>
|
||||
#include <third_party/mspack/mspack.h>
|
||||
#include <third_party/pe/pe_image.h>
|
||||
|
||||
|
||||
typedef struct xe_xex2 {
|
||||
@@ -22,6 +25,8 @@ typedef struct xe_xex2 {
|
||||
xe_memory_ref memory;
|
||||
|
||||
xe_xex2_header_t header;
|
||||
|
||||
std::vector<PESection*>* sections;
|
||||
} xe_xex2_t;
|
||||
|
||||
|
||||
@@ -31,6 +36,7 @@ int xe_xex2_decrypt_key(xe_xex2_header_t *header);
|
||||
int xe_xex2_read_image(xe_xex2_ref xex,
|
||||
const uint8_t *xex_addr, const size_t xex_length,
|
||||
xe_memory_ref memory);
|
||||
int xe_xex2_load_pe(xe_xex2_ref xex);
|
||||
|
||||
|
||||
xe_xex2_ref xe_xex2_load(xe_memory_ref memory,
|
||||
@@ -40,6 +46,7 @@ xe_xex2_ref xe_xex2_load(xe_memory_ref memory,
|
||||
xe_ref_init((xe_ref)xex);
|
||||
|
||||
xex->memory = xe_memory_retain(memory);
|
||||
xex->sections = new std::vector<PESection*>();
|
||||
|
||||
XEEXPECTZERO(xe_xex2_read_header((const uint8_t*)addr, length, &xex->header));
|
||||
|
||||
@@ -47,6 +54,8 @@ xe_xex2_ref xe_xex2_load(xe_memory_ref memory,
|
||||
|
||||
XEEXPECTZERO(xe_xex2_read_image(xex, (const uint8_t*)addr, length, memory));
|
||||
|
||||
XEEXPECTZERO(xe_xex2_load_pe(xex));
|
||||
|
||||
return xex;
|
||||
|
||||
XECLEANUP:
|
||||
@@ -55,6 +64,11 @@ XECLEANUP:
|
||||
}
|
||||
|
||||
void xe_xex2_dealloc(xe_xex2_ref xex) {
|
||||
for (std::vector<PESection*>::iterator it = xex->sections->begin();
|
||||
it != xex->sections->end(); ++it) {
|
||||
delete *it;
|
||||
}
|
||||
|
||||
xe_xex2_header_t *header = &xex->header;
|
||||
xe_free(header->sections);
|
||||
if (header->file_format_info.compression_type == XEX_COMPRESSION_BASIC) {
|
||||
@@ -743,6 +757,100 @@ int xe_xex2_read_image(xe_xex2_ref xex, const uint8_t *xex_addr,
|
||||
}
|
||||
}
|
||||
|
||||
int xe_xex2_load_pe(xe_xex2_ref xex) {
|
||||
const xe_xex2_header_t* header = &xex->header;
|
||||
const uint8_t* p = xe_memory_addr(xex->memory, header->exe_address);
|
||||
|
||||
// Verify DOS signature (MZ).
|
||||
const IMAGE_DOS_HEADER* doshdr = (const IMAGE_DOS_HEADER*)p;
|
||||
if (doshdr->e_magic != IMAGE_DOS_SIGNATURE) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Move to the NT header offset from the DOS header.
|
||||
p += doshdr->e_lfanew;
|
||||
|
||||
// Verify NT signature (PE\0\0).
|
||||
const IMAGE_NT_HEADERS32* nthdr = (const IMAGE_NT_HEADERS32*)(p);
|
||||
if (nthdr->Signature != IMAGE_NT_SIGNATURE) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Verify matches an Xbox PE.
|
||||
const IMAGE_FILE_HEADER* filehdr = &nthdr->FileHeader;
|
||||
if ((filehdr->Machine != IMAGE_FILE_MACHINE_POWERPCBE) ||
|
||||
!(filehdr->Characteristics & IMAGE_FILE_32BIT_MACHINE)) {
|
||||
return 1;
|
||||
}
|
||||
// Verify the expected size.
|
||||
if (filehdr->SizeOfOptionalHeader != IMAGE_SIZEOF_NT_OPTIONAL_HEADER) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Verify optional header is 32bit.
|
||||
const IMAGE_OPTIONAL_HEADER32* opthdr = &nthdr->OptionalHeader;
|
||||
if (opthdr->Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
|
||||
return 1;
|
||||
}
|
||||
// Verify subsystem.
|
||||
if (opthdr->Subsystem != IMAGE_SUBSYSTEM_XBOX) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Linker version - likely 8+
|
||||
// Could be useful for recognizing certain patterns
|
||||
//opthdr->MajorLinkerVersion; opthdr->MinorLinkerVersion;
|
||||
|
||||
// Data directories of interest:
|
||||
// EXPORT IMAGE_EXPORT_DIRECTORY
|
||||
// IMPORT IMAGE_IMPORT_DESCRIPTOR[]
|
||||
// EXCEPTION IMAGE_CE_RUNTIME_FUNCTION_ENTRY[]
|
||||
// BASERELOC
|
||||
// DEBUG IMAGE_DEBUG_DIRECTORY[]
|
||||
// ARCHITECTURE /IMAGE_ARCHITECTURE_HEADER/ ----- import thunks!
|
||||
// TLS IMAGE_TLS_DIRECTORY
|
||||
// IAT Import Address Table ptr
|
||||
//opthdr->DataDirectory[IMAGE_DIRECTORY_ENTRY_X].VirtualAddress / .Size
|
||||
|
||||
// Quick scan to determine bounds of sections.
|
||||
size_t upper_address = 0;
|
||||
const IMAGE_SECTION_HEADER* sechdr = IMAGE_FIRST_SECTION(nthdr);
|
||||
for (size_t n = 0; n < filehdr->NumberOfSections; n++, sechdr++) {
|
||||
const size_t physical_address = opthdr->ImageBase + sechdr->VirtualAddress;
|
||||
upper_address =
|
||||
MAX(upper_address, physical_address + sechdr->Misc.VirtualSize);
|
||||
}
|
||||
|
||||
// Setup/load sections.
|
||||
sechdr = IMAGE_FIRST_SECTION(nthdr);
|
||||
for (size_t n = 0; n < filehdr->NumberOfSections; n++, sechdr++) {
|
||||
PESection* section = (PESection*)xe_calloc(sizeof(PESection));
|
||||
xe_copy_memory(section->name, sizeof(section->name),
|
||||
sechdr->Name, sizeof(sechdr->Name));
|
||||
section->name[8] = 0;
|
||||
section->raw_address = sechdr->PointerToRawData;
|
||||
section->raw_size = sechdr->SizeOfRawData;
|
||||
section->address = header->exe_address + sechdr->VirtualAddress;
|
||||
section->size = sechdr->Misc.VirtualSize;
|
||||
section->flags = sechdr->Characteristics;
|
||||
xex->sections->push_back(section);
|
||||
}
|
||||
|
||||
//DumpTLSDirectory(pImageBase, pNTHeader, (PIMAGE_TLS_DIRECTORY32)0);
|
||||
//DumpExportsSection(pImageBase, pNTHeader);
|
||||
return 0;
|
||||
}
|
||||
|
||||
const PESection* xe_xex2_get_pe_section(xe_xex2_ref xex, const char* name) {
|
||||
for (std::vector<PESection*>::iterator it = xex->sections->begin();
|
||||
it != xex->sections->end(); ++it) {
|
||||
if (!xestrcmpa((*it)->name, name)) {
|
||||
return *it;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int xe_xex2_get_import_infos(xe_xex2_ref xex,
|
||||
const xe_xex2_import_library_t *library,
|
||||
xe_xex2_import_info_t **out_import_infos,
|
||||
|
||||
Reference in New Issue
Block a user