Module: Refactor stub imports to dedicated func.

This commit is contained in:
Unknown W. Brackets 2016-05-29 08:05:42 -07:00
parent 12b907ed60
commit 47f16ed97b

View File

@ -221,7 +221,7 @@ enum NativeModuleStatus {
class Module : public KernelObject {
public:
Module() : textStart(0), textEnd(0), memoryBlockAddr(0), isFake(false) {}
Module() : textStart(0), textEnd(0), libstub(0), libstubend(0), memoryBlockAddr(0), isFake(false) {}
~Module() {
if (memoryBlockAddr) {
// If it's either below user memory, or using a high kernel bit, it's in kernel.
@ -374,6 +374,10 @@ public:
u32 textStart;
u32 textEnd;
// Keep track of the libstub pointers so we can recheck on load state.
u32 libstub;
u32 libstubend;
u32 memoryBlockAddr;
u32 memoryBlockSize;
bool isFake;
@ -844,6 +848,160 @@ static bool IsHLEVersionedModule(const char *name) {
return false;
}
static bool KernelImportModuleFuncs(Module *module, u32 *firstImportStubAddr) {
struct PspLibStubEntry {
u32_le name;
u16_le version;
u16_le flags;
u8 size;
u8 numVars;
u16_le numFuncs;
// each symbol has an associated nid; nidData is a pointer
// (in .rodata.sceNid section) to an array of longs, one
// for each function, which identifies the function whose
// address is to be inserted.
//
// The hash is the first 4 bytes of a SHA-1 hash of the function
// name. (Represented as a little-endian long, so the order
// of the bytes is reversed.)
u32_le nidData;
// the address of the function stubs where the function address jumps
// should be filled in
u32_le firstSymAddr;
// Optional, this is where var relocations are.
// They use the format: u32 addr, u32 nid, ...
// WARNING: May have garbage if size < 6.
u32_le varData;
// Not sure what this is yet, assume garbage for now.
// TODO: Tales of the World: Radiant Mythology 2 has something here?
u32_le extra;
};
// Can't run - we didn't keep track of the libstub entry.
if (module->libstub == 0) {
return false;
}
if (!Memory::IsValidRange(module->libstub, module->libstubend - module->libstub)) {
ERROR_LOG_REPORT(LOADER, "Garbage libstub address or end");
return false;
}
u32_le *entryPos = (u32_le *)Memory::GetPointerUnchecked(module->libstub);
u32_le *entryEnd = (u32_le *)Memory::GetPointerUnchecked(module->libstubend);
bool needReport = false;
while (entryPos < entryEnd) {
PspLibStubEntry *entry = (PspLibStubEntry *)entryPos;
entryPos += entry->size;
const char *modulename;
if (Memory::IsValidAddress(entry->name)) {
modulename = Memory::GetCharPointer(entry->name);
} else {
modulename = "(invalidname)";
needReport = true;
}
DEBUG_LOG(LOADER, "Importing Module %s, stubs at %08x", modulename, entry->firstSymAddr);
if (entry->size != 5 && entry->size != 6) {
if (entry->size != 7) {
WARN_LOG_REPORT(LOADER, "Unexpected module entry size %d", entry->size);
needReport = true;
} else if (entry->extra != 0) {
WARN_LOG_REPORT(LOADER, "Unexpected module entry with non-zero 7th value %08x", entry->extra);
needReport = true;
}
}
// If nidData is 0, only variables are being imported.
if (entry->nidData != 0) {
if (!Memory::IsValidAddress(entry->nidData)) {
ERROR_LOG_REPORT(LOADER, "Crazy nidData address %08x, skipping entire module", entry->nidData);
needReport = true;
continue;
}
FuncSymbolImport func;
strncpy(func.moduleName, modulename, KERNELOBJECT_MAX_NAME_LENGTH);
func.moduleName[KERNELOBJECT_MAX_NAME_LENGTH] = '\0';
u32_le *nidDataPtr = (u32_le *)Memory::GetPointer(entry->nidData);
for (int i = 0; i < entry->numFuncs; ++i) {
// This is the id of the import.
func.nid = nidDataPtr[i];
// This is the address to write the j and delay slot to.
func.stubAddr = entry->firstSymAddr + i * 8;
module->ImportFunc(func);
}
if (firstImportStubAddr && (!*firstImportStubAddr || *firstImportStubAddr > (u32)entry->firstSymAddr))
*firstImportStubAddr = entry->firstSymAddr;
} else if (entry->numFuncs > 0) {
WARN_LOG_REPORT(LOADER, "Module entry with %d imports but no valid address", entry->numFuncs);
needReport = true;
}
if (entry->varData != 0) {
if (!Memory::IsValidAddress(entry->varData)) {
ERROR_LOG_REPORT(LOADER, "Crazy varData address %08x, skipping rest of module", entry->varData);
needReport = true;
continue;
}
VarSymbolImport var;
strncpy(var.moduleName, modulename, KERNELOBJECT_MAX_NAME_LENGTH);
var.moduleName[KERNELOBJECT_MAX_NAME_LENGTH] = '\0';
for (int i = 0; i < entry->numVars; ++i) {
u32 varRefsPtr = Memory::Read_U32(entry->varData + i * 8);
u32 nid = Memory::Read_U32(entry->varData + i * 8 + 4);
if (!Memory::IsValidAddress(varRefsPtr)) {
WARN_LOG_REPORT(LOADER, "Bad relocation list address for nid %08x in %s", nid, modulename);
continue;
}
u32_le *varRef = (u32_le *)Memory::GetPointer(varRefsPtr);
for (; *varRef != 0; ++varRef) {
var.nid = nid;
var.stubAddr = (*varRef & 0x03FFFFFF) << 2;
var.type = *varRef >> 26;
module->ImportVar(var);
}
}
} else if (entry->numVars > 0) {
WARN_LOG_REPORT(LOADER, "Module entry with %d var imports but no valid address", entry->numVars);
needReport = true;
}
DEBUG_LOG(LOADER, "-------------------------------------------------------------");
}
if (needReport) {
std::string debugInfo;
entryPos = (u32_le *)Memory::GetPointer(module->libstub);
while (entryPos < entryEnd) {
PspLibStubEntry *entry = (PspLibStubEntry *)entryPos;
entryPos += entry->size;
char temp[512];
const char *modulename;
if (Memory::IsValidAddress(entry->name)) {
modulename = Memory::GetCharPointer(entry->name);
} else {
modulename = "(invalidname)";
}
snprintf(temp, sizeof(temp), "%s ver=%04x, flags=%04x, size=%d, numVars=%d, numFuncs=%d, nidData=%08x, firstSym=%08x, varData=%08x, extra=%08x\n",
modulename, entry->version, entry->flags, entry->size, entry->numVars, entry->numFuncs, entry->nidData, entry->firstSymAddr, entry->size >= 6 ? entry->varData : 0, entry->size >= 7 ? entry->extra : 0);
debugInfo += temp;
}
Reporting::ReportMessage("Module linking debug info:\n%s", debugInfo.c_str());
}
return true;
}
static Module *__KernelLoadELFFromPtr(const u8 *ptr, u32 loadAddress, bool fromTop, std::string *error_string, u32 *magic, u32 &error) {
Module *module = new Module;
kernelObjects.Create(module);
@ -1038,153 +1196,14 @@ static Module *__KernelLoadELFFromPtr(const u8 *ptr, u32 loadAddress, bool fromT
module->nm.bss_size = reader.GetTotalSectionSizeByPrefix(".bss");
module->nm.data_size = reader.GetTotalDataSize() - module->nm.bss_size;
module->libstub = modinfo->libstub;
module->libstubend = modinfo->libstubend;
INFO_LOG(LOADER, "Module %s: %08x %08x %08x", modinfo->name, modinfo->gp, modinfo->libent, modinfo->libstub);
struct PspLibStubEntry {
u32_le name;
u16_le version;
u16_le flags;
u8 size;
u8 numVars;
u16_le numFuncs;
// each symbol has an associated nid; nidData is a pointer
// (in .rodata.sceNid section) to an array of longs, one
// for each function, which identifies the function whose
// address is to be inserted.
//
// The hash is the first 4 bytes of a SHA-1 hash of the function
// name. (Represented as a little-endian long, so the order
// of the bytes is reversed.)
u32_le nidData;
// the address of the function stubs where the function address jumps
// should be filled in
u32_le firstSymAddr;
// Optional, this is where var relocations are.
// They use the format: u32 addr, u32 nid, ...
// WARNING: May have garbage if size < 6.
u32_le varData;
// Not sure what this is yet, assume garbage for now.
// TODO: Tales of the World: Radiant Mythology 2 has something here?
u32_le extra;
};
DEBUG_LOG(LOADER,"===================================================");
u32_le *entryPos = (u32_le *)Memory::GetPointer(modinfo->libstub);
u32_le *entryEnd = (u32_le *)Memory::GetPointer(modinfo->libstubend);
u32_le firstImportStubAddr = 0;
bool needReport = false;
while (entryPos < entryEnd) {
PspLibStubEntry *entry = (PspLibStubEntry *)entryPos;
entryPos += entry->size;
const char *modulename;
if (Memory::IsValidAddress(entry->name)) {
modulename = Memory::GetCharPointer(entry->name);
} else {
modulename = "(invalidname)";
needReport = true;
}
DEBUG_LOG(LOADER, "Importing Module %s, stubs at %08x", modulename, entry->firstSymAddr);
if (entry->size != 5 && entry->size != 6) {
if (entry->size != 7) {
WARN_LOG_REPORT(LOADER, "Unexpected module entry size %d", entry->size);
needReport = true;
} else if (entry->extra != 0) {
WARN_LOG_REPORT(LOADER, "Unexpected module entry with non-zero 7th value %08x", entry->extra);
needReport = true;
}
}
// If nidData is 0, only variables are being imported.
if (entry->nidData != 0) {
if (!Memory::IsValidAddress(entry->nidData)) {
ERROR_LOG_REPORT(LOADER, "Crazy nidData address %08x, skipping entire module", entry->nidData);
needReport = true;
continue;
}
FuncSymbolImport func;
strncpy(func.moduleName, modulename, KERNELOBJECT_MAX_NAME_LENGTH);
func.moduleName[KERNELOBJECT_MAX_NAME_LENGTH] = '\0';
u32_le *nidDataPtr = (u32_le *)Memory::GetPointer(entry->nidData);
for (int i = 0; i < entry->numFuncs; ++i) {
// This is the id of the import.
func.nid = nidDataPtr[i];
// This is the address to write the j and delay slot to.
func.stubAddr = entry->firstSymAddr + i * 8;
module->ImportFunc(func);
}
if (!firstImportStubAddr || firstImportStubAddr > entry->firstSymAddr)
firstImportStubAddr = entry->firstSymAddr;
} else if (entry->numFuncs > 0) {
WARN_LOG_REPORT(LOADER, "Module entry with %d imports but no valid address", entry->numFuncs);
needReport = true;
}
if (entry->varData != 0) {
if (!Memory::IsValidAddress(entry->varData)) {
ERROR_LOG_REPORT(LOADER, "Crazy varData address %08x, skipping rest of module", entry->varData);
needReport = true;
continue;
}
VarSymbolImport var;
strncpy(var.moduleName, modulename, KERNELOBJECT_MAX_NAME_LENGTH);
var.moduleName[KERNELOBJECT_MAX_NAME_LENGTH] = '\0';
for (int i = 0; i < entry->numVars; ++i) {
u32 varRefsPtr = Memory::Read_U32(entry->varData + i * 8);
u32 nid = Memory::Read_U32(entry->varData + i * 8 + 4);
if (!Memory::IsValidAddress(varRefsPtr)) {
WARN_LOG_REPORT(LOADER, "Bad relocation list address for nid %08x in %s", nid, modulename);
continue;
}
u32_le *varRef = (u32_le *)Memory::GetPointer(varRefsPtr);
for (; *varRef != 0; ++varRef) {
var.nid = nid;
var.stubAddr = (*varRef & 0x03FFFFFF) << 2;
var.type = *varRef >> 26;
module->ImportVar(var);
}
}
} else if (entry->numVars > 0) {
WARN_LOG_REPORT(LOADER, "Module entry with %d var imports but no valid address", entry->numVars);
needReport = true;
}
DEBUG_LOG(LOADER, "-------------------------------------------------------------");
}
if (needReport) {
std::string debugInfo;
entryPos = (u32_le *)Memory::GetPointer(modinfo->libstub);
while (entryPos < entryEnd) {
PspLibStubEntry *entry = (PspLibStubEntry *)entryPos;
entryPos += entry->size;
char temp[512];
const char *modulename;
if (Memory::IsValidAddress(entry->name)) {
modulename = Memory::GetCharPointer(entry->name);
} else {
modulename = "(invalidname)";
}
snprintf(temp, sizeof(temp), "%s ver=%04x, flags=%04x, size=%d, numVars=%d, numFuncs=%d, nidData=%08x, firstSym=%08x, varData=%08x, extra=%08x\n",
modulename, entry->version, entry->flags, entry->size, entry->numVars, entry->numFuncs, entry->nidData, entry->firstSymAddr, entry->size >= 6 ? entry->varData : 0, entry->size >= 7 ? entry->extra : 0);
debugInfo += temp;
}
Reporting::ReportMessage("Module linking debug info:\n%s", debugInfo.c_str());
}
u32 firstImportStubAddr = 0;
KernelImportModuleFuncs(module, &firstImportStubAddr);
if (textSection == -1) {
module->textStart = reader.GetVaddr();