From 0bc49621d410e75bd2a81882f924d6044e699ec0 Mon Sep 17 00:00:00 2001 From: Ben Vanik Date: Sun, 19 Jan 2014 00:46:46 -0800 Subject: [PATCH] Properly parsing resource infos and implementing XexGetModuleSection. --- src/xenia/cpu/processor.cc | 20 +++++++++----- src/xenia/kernel/objects/xmodule.cc | 6 ++++ src/xenia/kernel/objects/xmodule.h | 3 ++ src/xenia/kernel/objects/xuser_module.cc | 35 ++++++++++++++---------- src/xenia/kernel/objects/xuser_module.h | 4 ++- src/xenia/kernel/util/xex2.cc | 29 ++++++++++++++------ src/xenia/kernel/util/xex2_info.h | 5 ++-- src/xenia/kernel/xboxkrnl_modules.cc | 34 ++++++++++++++++++++--- 8 files changed, 100 insertions(+), 36 deletions(-) diff --git a/src/xenia/cpu/processor.cc b/src/xenia/cpu/processor.cc index 281a33c07..743611ecd 100644 --- a/src/xenia/cpu/processor.cc +++ b/src/xenia/cpu/processor.cc @@ -526,13 +526,19 @@ json_t* Processor::DumpModule(XexModule* module, bool& succeeded) { } json_object_set_new(module_json, "headers", headers_json); - // TODO(benvanik): resources. - json_t* resource_info_json = json_object(); - json_object_set_integer_new( - resource_info_json, "address", header->resource_info.address); - json_object_set_integer_new( - resource_info_json, "size", header->resource_info.size); - json_object_set_new(module_json, "resourceInfo", resource_info_json); + json_t* resource_infos_json = json_array(); + for (size_t n = 0; n < header->resource_info_count; n++) { + auto& res = header->resource_infos[n]; + json_t* resource_info_json = json_object(); + json_object_set_string_new( + resource_info_json, "name", res.name); + json_object_set_integer_new( + resource_info_json, "address", res.address); + json_object_set_integer_new( + resource_info_json, "size", res.size); + json_array_append_new(resource_infos_json, resource_info_json); + } + json_object_set_new(module_json, "resourceInfos", resource_infos_json); json_t* sections_json = json_array(); for (size_t n = 0, i = 0; n < header->section_count; n++) { diff --git a/src/xenia/kernel/objects/xmodule.cc b/src/xenia/kernel/objects/xmodule.cc index bee54171d..c6efc9361 100644 --- a/src/xenia/kernel/objects/xmodule.cc +++ b/src/xenia/kernel/objects/xmodule.cc @@ -33,3 +33,9 @@ XModule::XModule(KernelState* kernel_state, const char* path) : XModule::~XModule() { } + +X_STATUS XModule::GetSection( + const char* name, + uint32_t* out_section_data, uint32_t* out_section_size) { + return X_STATUS_UNSUCCESSFUL; +} diff --git a/src/xenia/kernel/objects/xmodule.h b/src/xenia/kernel/objects/xmodule.h index 2c31e5ef6..97c49b907 100644 --- a/src/xenia/kernel/objects/xmodule.h +++ b/src/xenia/kernel/objects/xmodule.h @@ -28,6 +28,9 @@ public: const char* name() const { return name_; } virtual void* GetProcAddressByOrdinal(uint16_t ordinal) = 0; + virtual X_STATUS GetSection( + const char* name, + uint32_t* out_section_data, uint32_t* out_section_size); protected: char name_[256]; diff --git a/src/xenia/kernel/objects/xuser_module.cc b/src/xenia/kernel/objects/xuser_module.cc index 75ed75439..86d25847e 100644 --- a/src/xenia/kernel/objects/xuser_module.cc +++ b/src/xenia/kernel/objects/xuser_module.cc @@ -124,23 +124,28 @@ XECLEANUP: return X_STATUS_UNSUCCESSFUL; } -X_STATUS XUserModule::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* XUserModule::GetProcAddressByOrdinal(uint16_t ordinal) { // TODO(benvanik): check export tables. XELOGE("GetProcAddressByOrdinal not implemented"); return NULL; } +X_STATUS XUserModule::GetSection( + const char* name, + uint32_t* out_section_data, uint32_t* out_section_size) { + auto header = xe_xex2_get_header(xex_); + for (size_t n = 0; n < header->resource_info_count; n++) { + auto& res = header->resource_infos[n]; + if (xestrcmpa(name, res.name) == 0) { + // Found! + *out_section_data = res.address; + *out_section_size = res.size; + return X_STATUS_SUCCESS; + } + } + return X_STATUS_UNSUCCESSFUL; +} + X_STATUS XUserModule::Launch(uint32_t flags) { const xe_xex2_header_t* header = xex_header(); @@ -226,9 +231,11 @@ void XUserModule::Dump() { // Resources. printf("Resources:\n"); - printf(" %.8X, %db\n", header->resource_info.address, - header->resource_info.size); - printf(" TODO\n"); + for (size_t n = 0; n < header->resource_info_count; n++) { + auto& res = header->resource_infos[n]; + printf(" %-8s %.8X-%.8X, %db\n", + res.name, res.address, res.address + res.size, res.size); + } printf("\n"); // Section info. diff --git a/src/xenia/kernel/objects/xuser_module.h b/src/xenia/kernel/objects/xuser_module.h index 6f655011a..eae6337c4 100644 --- a/src/xenia/kernel/objects/xuser_module.h +++ b/src/xenia/kernel/objects/xuser_module.h @@ -32,8 +32,10 @@ public: 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); virtual void* GetProcAddressByOrdinal(uint16_t ordinal); + virtual X_STATUS GetSection( + const char* name, + uint32_t* out_section_data, uint32_t* out_section_size); X_STATUS Launch(uint32_t flags); diff --git a/src/xenia/kernel/util/xex2.cc b/src/xenia/kernel/util/xex2.cc index cc31c949d..082287b45 100644 --- a/src/xenia/kernel/util/xex2.cc +++ b/src/xenia/kernel/util/xex2.cc @@ -73,6 +73,7 @@ void xe_xex2_dealloc(xe_xex2_ref xex) { xe_xex2_header_t *header = &xex->header; xe_free(header->sections); + xe_free(header->resource_infos); if (header->file_format_info.compression_type == XEX_COMPRESSION_BASIC) { xe_free(header->file_format_info.compression_info.basic.blocks); } @@ -147,19 +148,31 @@ int xe_xex2_read_header(const uint8_t *addr, const size_t length, const uint8_t *pp = p + opt_header->offset; switch (opt_header->key) { + default: + XELOGW("Unknown XEX header key %.8X", opt_header->key); + break; + case XEX_HEADER_CHECKSUM_TIMESTAMP: + case XEX_HEADER_ORIGINAL_PE_NAME: + case XEX_HEADER_LAN_KEY: + case XEX_HEADER_XBOX360_LOGO: + // Ignored. + break; case XEX_HEADER_SYSTEM_FLAGS: header->system_flags = (xe_xex2_system_flags)data_offset; break; case XEX_HEADER_RESOURCE_INFO: { - xe_xex2_resource_info_t *res = &header->resource_info; - XEEXPECTZERO(xe_copy_memory(res->title_id, - sizeof(res->title_id), pp + 0x04, 8)); - res->address = XEGETUINT32BE(pp + 0x0C); - res->size = XEGETUINT32BE(pp + 0x10); - if ((opt_header->length - 4) / 16 > 1) { - // Ignoring extra resources (not yet seen) - XELOGW("ignoring extra XEX_HEADER_RESOURCE_INFO resources"); + header->resource_info_count = (opt_header->length - 4) / 16; + header->resource_infos = (xe_xex2_resource_info_t*)xe_calloc( + sizeof(xe_xex2_resource_info_t) * header->resource_info_count); + const uint8_t* ph = pp + 0x04; + for (size_t n = 0; n < header->resource_info_count; n++) { + auto& res = header->resource_infos[n]; + XEEXPECTZERO(xe_copy_memory(res.name, + sizeof(res.name), ph + 0x00, 8)); + res.address = XEGETUINT32BE(ph + 0x08); + res.size = XEGETUINT32BE(ph + 0x0C); + ph += 16; } } break; diff --git a/src/xenia/kernel/util/xex2_info.h b/src/xenia/kernel/util/xex2_info.h index 1e2e93d9f..ea4042dff 100644 --- a/src/xenia/kernel/util/xex2_info.h +++ b/src/xenia/kernel/util/xex2_info.h @@ -246,7 +246,7 @@ typedef struct { } xe_xex2_opt_header_t; typedef struct { - char title_id[8]; + char name[9]; uint32_t address; uint32_t size; } xe_xex2_resource_info_t; @@ -431,7 +431,6 @@ typedef struct { uint32_t certificate_offset; xe_xex2_system_flags system_flags; - xe_xex2_resource_info_t resource_info; xe_xex2_execution_info_t execution_info; xe_xex2_game_ratings_t game_ratings; xe_xex2_tls_info_t tls_info; @@ -451,6 +450,8 @@ typedef struct { size_t header_count; xe_xex2_opt_header_t headers[64]; + size_t resource_info_count; + xe_xex2_resource_info_t* resource_infos; size_t section_count; xe_xex2_section_t* sections; } xe_xex2_header_t; diff --git a/src/xenia/kernel/xboxkrnl_modules.cc b/src/xenia/kernel/xboxkrnl_modules.cc index d88d1a5a0..bcd5e5c49 100644 --- a/src/xenia/kernel/xboxkrnl_modules.cc +++ b/src/xenia/kernel/xboxkrnl_modules.cc @@ -204,9 +204,35 @@ SHIM_CALL XexGetModuleHandle_shim( } -// SHIM_CALL XexGetModuleSection_shim( -// PPCContext* ppc_state, KernelState* state) { -// } +SHIM_CALL XexGetModuleSection_shim( + PPCContext* ppc_state, KernelState* state) { + uint32_t handle = SHIM_GET_ARG_32(0); + uint32_t name_ptr = SHIM_GET_ARG_32(1); + const char* name = (const char*)SHIM_MEM_ADDR(name_ptr); + uint32_t data_ptr = SHIM_GET_ARG_32(2); + uint32_t size_ptr = SHIM_GET_ARG_32(3); + + XELOGD( + "XexGetModuleSection(%.8X, %s, %.8X, %.8X)", + handle, name, data_ptr, size_ptr); + + XModule* module = NULL; + X_STATUS result = + state->object_table()->GetObject(handle, (XObject**)&module); + if (XSUCCEEDED(result)) { + uint32_t section_data = 0; + uint32_t section_size = 0; + result = module->GetSection(name, §ion_data, §ion_size); + if (XSUCCEEDED(result)) { + SHIM_SET_MEM_32(data_ptr, section_data); + SHIM_SET_MEM_32(size_ptr, section_size); + } + + module->Release(); + } + + SHIM_SET_RETURN(result); +} SHIM_CALL XexLoadImage_shim( @@ -323,7 +349,7 @@ void xe::kernel::xboxkrnl::RegisterModuleExports( SHIM_SET_MAPPING("xboxkrnl.exe", XexCheckExecutablePrivilege, state); SHIM_SET_MAPPING("xboxkrnl.exe", XexGetModuleHandle, state); - // SHIM_SET_MAPPING("xboxkrnl.exe", XexGetModuleSection, state); + SHIM_SET_MAPPING("xboxkrnl.exe", XexGetModuleSection, state); SHIM_SET_MAPPING("xboxkrnl.exe", XexLoadImage, state); SHIM_SET_MAPPING("xboxkrnl.exe", XexUnloadImage, state); SHIM_SET_MAPPING("xboxkrnl.exe", XexGetProcedureAddress, state);