8 #include <psp2kern/types.h> 9 #include <psp2kern/kernel/cpu.h> 10 #include <psp2kern/kernel/sysmem.h> 11 #include <psp2kern/kernel/modulemgr.h> 14 #include "taihen_internal.h" 20 uint16_t num_functions;
22 uint16_t num_tls_vars;
27 uint32_t *func_nid_table;
28 void **func_entry_table;
29 uint32_t *var_nid_table;
30 void **var_entry_table;
31 uint32_t *tls_nid_table;
32 void **tls_entry_table;
39 uint16_t num_functions;
43 uint32_t *func_nid_table;
44 void **func_entry_table;
57 uint8_t lib_version[2];
59 uint16_t num_functions;
62 uint32_t num_tls_vars;
70 uint16_t modattribute;
91 #define MOD_LIST_SIZE 0x80 94 static uint32_t fw_version = 0;
108 static int sce_to_tai_module_info(SceUID pid,
void *sceinfo,
tai_module_info_t *taiinfo) {
109 SceKernelFwInfo fwinfo;
112 if (fw_version == 0) {
113 fwinfo.size =
sizeof(fwinfo);
114 if (sceKernelGetSystemSwVersion(&fwinfo) < 0) {
115 fw_version = DEFAULT_FW_VERSION;
117 fw_version = fwinfo.version;
119 LOG(
"sceKernelGetSystemSwVersion: 0x%08X", fw_version);
123 LOG(
"Structure size too small: %d", taiinfo->
size);
124 return TAI_ERROR_SYSTEM;
127 info = (
char *)sceinfo;
128 if (fw_version >= 0x3600000) {
130 taiinfo->
modid = *(SceUID *)(info + 0xC);
132 taiinfo->
modid = *(SceUID *)(info + 0x10);
134 snprintf(taiinfo->
name, 27,
"%s", *(
const char **)(info + 0x1C));
135 taiinfo->
name[26] =
'\0';
136 taiinfo->
module_nid = *(uint32_t *)(info + 0x30);
138 taiinfo->
exports_end = *(uintptr_t *)(info + 0x24);
140 taiinfo->
imports_end = *(uintptr_t *)(info + 0x2C);
141 }
else if (fw_version >= 0x1692000) {
143 taiinfo->
modid = *(SceUID *)(info + 0x0);
145 taiinfo->
modid = *(SceUID *)(info + 0x4);
147 taiinfo->
module_nid = *(uint32_t *)(info + 0x3C);
148 snprintf(taiinfo->
name, 27,
"%s", (
const char *)(info + 0xC));
149 taiinfo->
name[26] =
'\0';
151 taiinfo->
exports_end = *(uintptr_t *)(info + 0x30);
153 taiinfo->
imports_end = *(uintptr_t *)(info + 0x38);
155 LOG(
"Unsupported FW 0x%08X", fw_version);
156 return TAI_ERROR_SYSTEM;
173 static int find_int_for_user(SceUID pid, uintptr_t src, uint32_t needle,
size_t size) {
183 end = (src + size) & ~3;
184 src = (src + 3) & ~3;
189 flags = sceKernelCpuDisableInterrupts();
190 sceKernelCpuSaveContext(my_context);
191 ret = sceKernelGetPidContext(pid, &other_context);
193 sceKernelCpuRestoreContext(other_context);
194 while (count < size) {
195 asm (
"ldrt %0, [%1]" :
"=r" (data) :
"r" (src+count));
196 if (data == needle) {
202 sceKernelCpuRestoreContext(my_context);
203 sceKernelCpuEnableInterrupts(flags);
205 LOG(
"Error trying to get context for %x", pid);
236 SceUID modlist[MOD_LIST_SIZE];
243 count = MOD_LIST_SIZE;
244 ret = sceKernelGetModuleListForKernel(pid, get_cur ? 1 : 0xff, 1, modlist, &count);
245 LOG(
"sceKernelGetModuleListForKernel(%x): 0x%08X, count: %d", pid, ret, count);
249 if (get_cur && count > 1) {
250 LOG(
"Cannot use TAI_MAIN_MODULE since there are multiple main modules");
251 return TAI_ERROR_INVALID_MODULE;
253 for (
int i = count-1; i >= 0; i--) {
254 ret = sceKernelGetModuleInternal(modlist[i], &sceinfo);
257 LOG(
"Error getting info for mod: %x, ret: %x", modlist[i], ret);
260 if (sce_to_tai_module_info(pid, sceinfo, info) < 0) {
263 if (name != NULL && strncmp(name, info->
name, 27) == 0) {
265 LOG(
"Found module %s, NID:0x%08X", name, info->
modid);
268 }
else if (name == NULL && (get_cur || info->
modid == nid)) {
269 LOG(
"Found module %s, NID:0x%08X", info->
name, info->
modid);
274 return TAI_ERROR_NOT_FOUND;
289 SceKernelModuleInfo sceinfo;
294 LOG(
"Invalid segment index: %d", segidx);
295 return TAI_ERROR_INVALID_ARGS;
297 LOG(
"Getting offset for pid:%x, modid:%x, segidx:%d, offset:%x", pid, modid, segidx, offset);
298 sceinfo.size =
sizeof(sceinfo);
299 ret = sceKernelGetModuleInfoForKernel(pid, modid, &sceinfo);
300 LOG(
"sceKernelGetModuleInfoForKernel(%x, %x): 0x%08X", pid, modid, ret);
302 LOG(
"Error getting segment info for %d", modid);
305 if (offset > sceinfo.segments[segidx].memsz) {
306 LOG(
"Offset %x overflows segment size %x", offset, sceinfo.segments[segidx].memsz);
307 return TAI_ERROR_INVALID_ARGS;
309 *addr = (uintptr_t)sceinfo.segments[segidx].vaddr + offset;
310 LOG(
"found address: 0x%08X", *addr);
335 LOG(
"Getting export for pid:%x, modname:%s, libnid:%x, funcnid:%x", pid, modname, libnid, funcnid);
336 info.
size =
sizeof(info);
338 LOG(
"Failed to find module: %s", modname);
339 return TAI_ERROR_NOT_FOUND;
346 if ((ret = sceKernelMemcpyUserToKernelForPid(pid, &local, cur,
sizeof(local))) < 0) {
347 LOG(
"Error trying to read address %p for %x: %x", cur, pid, ret);
355 for (i = 0; i < export->num_functions; i++) {
356 if (export->nid_table[i] == funcnid) {
357 *func = (uintptr_t)export->entry_table[i];
358 LOG(
"found kernel address: 0x%08X", *func);
363 found = find_int_for_user(pid, (uintptr_t)export->nid_table, funcnid, export->num_functions * 4);
365 if ((ret = sceKernelMemcpyUserToKernelForPid(pid, func, (uintptr_t)export->entry_table + found, 4)) < 0) {
366 LOG(
"Error trying to read address %p for %x: %x", (uintptr_t)export->entry_table + found, pid, ret);
369 LOG(
"found user address: 0x%08X", *func);
377 return TAI_ERROR_NOT_FOUND;
401 LOG(
"Getting import for pid:%x, modname:%s, target_libnid:%x, funcnid:%x", pid, modname, target_libnid, funcnid);
402 info.
size =
sizeof(info);
404 LOG(
"Failed to find module: %s", modname);
405 return TAI_ERROR_NOT_FOUND;
412 if ((ret = sceKernelMemcpyUserToKernelForPid(pid, &local.size, cur,
sizeof(local.size))) < 0) {
413 LOG(
"Error trying to read address %p for %x: %x", cur, pid, ret);
416 if (local.size <=
sizeof(local)) {
417 if ((ret = sceKernelMemcpyUserToKernelForPid(pid, &local, cur, local.size)) < 0) {
418 LOG(
"Error trying to read address %p for %x: %x", cur, pid, ret);
427 if (target_libnid ==
TAI_ANY_LIBRARY || import->type1.lib_nid == target_libnid) {
429 for (i = 0; i <
import->type1.num_functions; i++) {
430 if (import->type1.func_nid_table[i] == funcnid) {
431 *stub = (uintptr_t)import->type1.func_entry_table[i];
432 LOG(
"found kernel address: 0x%08X", *stub);
437 found = find_int_for_user(pid, (uintptr_t)import->type1.func_nid_table, funcnid, import->type1.num_functions * 4);
439 if ((ret = sceKernelMemcpyUserToKernelForPid(pid, stub, (uintptr_t)import->type1.func_entry_table + found, 4)) < 0) {
440 LOG(
"Error trying to read address %p for %x: %x", (uintptr_t)import->type1.func_entry_table + found, pid, ret);
443 LOG(
"found user address: 0x%08X", *stub);
449 if (target_libnid ==
TAI_ANY_LIBRARY || import->type2.lib_nid == target_libnid) {
451 for (i = 0; i <
import->type2.num_functions; i++) {
452 if (import->type2.func_nid_table[i] == funcnid) {
453 *stub = (uintptr_t)import->type2.func_entry_table[i];
454 LOG(
"found kernel address: 0x%08X", *stub);
459 found = find_int_for_user(pid, (uintptr_t)import->type2.func_nid_table, funcnid, import->type2.num_functions * 4);
461 if ((ret = sceKernelMemcpyUserToKernelForPid(pid, stub, (uintptr_t)import->type2.func_entry_table + found, 4)) < 0) {
462 LOG(
"Error trying to read address %p for %x: %x", (uintptr_t)import->type2.func_entry_table + found, pid, ret);
465 LOG(
"found user address: 0x%08X", *stub);
471 LOG(
"Invalid import size: %d", import->size);
476 return TAI_ERROR_NOT_FOUND;
char name[27]
Module name.
uintptr_t imports_start
Pointer to import table in process address space.
Extended module information.
uintptr_t exports_end
Pointer to end of export table.
uintptr_t imports_end
Pointer to end of import table.
uint32_t module_nid
Module NID.
int module_get_by_name_nid(SceUID pid, const char *name, uint32_t nid, tai_module_info_t *info)
Gets a loaded module by name or NID or both.
int module_get_export_func(SceUID pid, const char *modname, uint32_t libnid, uint32_t funcnid, uintptr_t *func)
Gets an exported function address.
uintptr_t exports_start
Pointer to export table in process address space.
#define TAI_IGNORE_MODULE_NID
int module_get_offset(SceUID pid, SceUID modid, int segidx, size_t offset, uintptr_t *addr)
Gets an offset from a segment in a module.
size_t size
Structure size, set to sizeof(tai_module_info_t)
int module_get_import_func(SceUID pid, const char *modname, uint32_t target_libnid, uint32_t funcnid, uintptr_t *stub)
Gets an imported function stub address.