summaryrefslogtreecommitdiff
path: root/src/ps3
diff options
context:
space:
mode:
authoraerosoul94 <aerosoul94@hotmail.com>2017-04-05 12:32:29 -0500
committeraerosoul94 <aerosoul94@hotmail.com>2017-04-05 12:32:29 -0500
commit991de71c144a0d2b70034593b03b6b93a96a0791 (patch)
treebe40962e1428e5953bfd44cf6d83ede85aa1f502 /src/ps3
First commit
Diffstat (limited to 'src/ps3')
-rw-r--r--src/ps3/CMakeLists.txt35
-rw-r--r--src/ps3/cell_loader.cpp865
-rw-r--r--src/ps3/cell_loader.h61
-rw-r--r--src/ps3/ps3.cpp67
-rw-r--r--src/ps3/sce.h167
5 files changed, 1195 insertions, 0 deletions
diff --git a/src/ps3/CMakeLists.txt b/src/ps3/CMakeLists.txt
new file mode 100644
index 0000000..ce530e3
--- /dev/null
+++ b/src/ps3/CMakeLists.txt
@@ -0,0 +1,35 @@
+cmake_minimum_required(VERSION 2.8)
+project(ps3ldr)
+
+set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_SOURCE_DIR}/../../cmake)
+set(ELF_COMMON_PATH ${CMAKE_SOURCE_DIR}/../elf_common)
+set(THIRD_PARTY_PATH ${CMAKE_SOURCE_DIR}/../../third_party)
+
+set(SOURCES
+ ${ELF_COMMON_PATH}/elf_reader.h
+ ${ELF_COMMON_PATH}/elf.h
+ ${THIRD_PARTY_PATH}/tinyxml/tinystr.cpp
+ ${THIRD_PARTY_PATH}/tinyxml/tinystr.h
+ ${THIRD_PARTY_PATH}/tinyxml/tinyxml.cpp
+ ${THIRD_PARTY_PATH}/tinyxml/tinyxml.h
+ ${THIRD_PARTY_PATH}/tinyxml/tinyxmlerror.cpp
+ ${THIRD_PARTY_PATH}/tinyxml/tinyxmlparser.cpp
+ cell_loader.cpp
+ cell_loader.h
+ ps3.cpp
+ sce.h
+)
+
+find_package(IDA)
+
+include_directories(${IDA_INCLUDE_DIR})
+include_directories(${IDA_SDK_PATH}/ldr)
+include_directories(${ELF_COMMON_PATH})
+include_directories(${THIRD_PARTY_PATH}/tinyxml)
+
+add_definitions(${IDA_DEFINITIONS})
+add_definitions(-DUSE_STANDARD_FILE_FUNCTIONS) # for tinyxml...
+
+add_library(ps3ldr SHARED ${SOURCES})
+target_link_libraries(ps3ldr ${IDA_LIBRARIES})
+set_target_properties(ps3ldr PROPERTIES OUTPUT_NAME "ps3" PREFIX "" SUFFIX "${IDA_PLUGIN_EXT}") \ No newline at end of file
diff --git a/src/ps3/cell_loader.cpp b/src/ps3/cell_loader.cpp
new file mode 100644
index 0000000..f548185
--- /dev/null
+++ b/src/ps3/cell_loader.cpp
@@ -0,0 +1,865 @@
+#include "cell_loader.h"
+
+#include <idaldr.h>
+#include <struct.hpp>
+
+#include <memory>
+#include <vector>
+
+cell_loader::cell_loader(elf_reader<elf64> *elf,
+ uint64 relocAddr,
+ std::string databaseFile)
+ : m_elf(elf)
+{
+ m_hasSegSym = false;
+ m_relocAddr = 0;
+
+ // only PRX's contain relocations
+ if ( isLoadingPrx() )
+ m_relocAddr = relocAddr;
+
+ inf.demnames |= DEMNAM_GCC3; // assume gcc3 names
+ inf.af |= AF_PROCPTR; // Create function if data xref data->code32 exists
+
+ char databasePath[QMAXPATH];
+
+ if ( getsysfile(databasePath, QMAXFILE, databaseFile.c_str(), LDR_SUBDIR) == NULL )
+ loader_failure("Could not locate database file (%s).\n", databaseFile.c_str());
+
+ if ( m_database.LoadFile(databasePath) == false )
+ loader_failure("Failed to load database file (%s).\n", databaseFile.c_str());
+}
+
+void cell_loader::apply() {
+ declareStructures();
+
+ applySegments();
+
+ swapSymbols();
+
+ if ( isLoadingPrx() ) {
+ // the only way I know to check if its a 0.85 PRX
+ for ( auto &segment : m_elf->getSegments() ) {
+ if ( segment.p_type == PT_SCE_SEGSYM ) {
+ m_hasSegSym = true;
+ break;
+ }
+ }
+
+ // we need gpValue for relocations on 0.85
+ // otherwise, I don't think newer PRX's have
+ // TOC based relocations. TOC is not set in
+ // moduleInfo. It seems to always be zero.
+ if ( m_hasSegSym ) {
+ //msg("Looking for .toc section\n");
+ auto tocSection = m_elf->getSectionByName(".toc");
+ if ( tocSection ) {
+ //msg("Found toc section!\n");
+ m_gpValue = tocSection->sh_addr + m_relocAddr;
+ }
+ }
+
+ // gpValue can be found at sceModuleInfo->gp_value
+ // 0.85 gpValue is base address of .toc
+ applyRelocations();
+
+ // if not a 0.85 PRX
+ if ( !m_hasSegSym ) {
+ // p_paddr is an offset into the file.
+ auto firstSegment = m_elf->getSegments()[0];
+ m_gpValue = get_long( (firstSegment.p_vaddr + m_relocAddr) + // file offset to address
+ (firstSegment.p_paddr - firstSegment.p_offset) +
+ offsetof(_scemoduleinfo_ppu32, gp_value) );
+ }
+
+ applyModuleInfo();
+ } else if ( isLoadingExec() ) {
+ // gpValue can be found at m_elf->entry() + 4
+ // _start is actually what loads TOC which is hardcoded to lwz(entry + 4)
+ // there are also function stubs which set TOC to a different value
+ m_gpValue = get_long(m_elf->entry() + 4);
+
+ applyProcessInfo();
+
+ add_entry(0, m_elf->entry(), "_start", true);
+ }
+
+ msg("gpValue = %08x\n", m_gpValue);
+
+ // set TOC in IDA
+ ph.notify(processor_t::idp_notify(ph.loader+1), m_gpValue);
+
+ // we want to apply the symbols last so that symbols
+ // always override our own custom symbols.
+ applySymbols();
+}
+
+void cell_loader::applySegments() {
+ // we prefer section headers
+ if ( m_elf->getNumSections() > 0 )
+ applySectionHeaders();
+ // otherwise load program headers
+ else if ( m_elf->getNumSegments() > 0 )
+ applyProgramHeaders();
+ else
+ loader_failure("No segments available!");
+}
+
+void cell_loader::applySectionHeaders() {
+ msg("Applying section headers...\n");
+ auto &sections = m_elf->getSections();
+ const char *strTab = m_elf->getSectionStringTable()->data();
+
+ size_t index = 0;
+ for ( const auto &section : sections ) {
+ // only load allocatable sections
+ if ( section.sh_flags & SHF_ALLOC &&
+ section.sh_size > 0 ) {
+ if ( section.sh_type == SHT_NULL )
+ continue;
+
+ uchar perm = SEGPERM_READ;
+ char *sclass;
+
+ if ( section.sh_flags & SHF_WRITE )
+ perm |= SEGPERM_WRITE;
+ if ( section.sh_flags & SHF_EXECINSTR )
+ perm |= SEGPERM_EXEC;
+
+ if ( section.sh_flags & SHF_EXECINSTR )
+ sclass = CLASS_CODE;
+ else if ( section.sh_type == SHT_NOBITS )
+ sclass = CLASS_BSS;
+ else
+ sclass = CLASS_DATA;
+
+ const char *name = NULL;
+ if ( section.sh_name != NULL )
+ name = &strTab[section.sh_name];
+
+ applySegment( index,
+ section.sh_offset,
+ section.sh_addr,
+ section.sh_size,
+ name,
+ sclass,
+ perm,
+ m_elf->getAlignment(section.sh_addralign),
+ (section.sh_type == SHT_NOBITS) ? false : true );
+
+ ++index;
+ }
+ }
+}
+
+void cell_loader::applyProgramHeaders() {
+ msg("Applying program headers...\n");
+ auto &segments = m_elf->getSegments();
+
+ size_t index = 0;
+ for ( const auto &segment : segments ) {
+ if ( segment.p_memsz > 0 ) {
+ uchar perm;
+ char *sclass;
+
+ if ( segment.p_flags & PF_W ) // if its writable
+ sclass = CLASS_DATA;
+ if ( (segment.p_flags & PF_R) && // if its only readable
+ !(segment.p_flags & PF_W) &&
+ !(segment.p_flags & PF_X) )
+ sclass = CLASS_CONST;
+ if ( segment.p_flags & PF_X ) // if its executable
+ sclass = CLASS_CODE;
+
+ if ( segment.p_filesz == 0 &&
+ segment.p_memsz > 0 )
+ sclass = CLASS_BSS;
+
+ if ( segment.p_flags & PF_X )
+ perm |= SEGPERM_EXEC;
+ if ( segment.p_flags & PF_W )
+ perm |= SEGPERM_WRITE;
+ if ( segment.p_flags & PF_R )
+ perm |= SEGPERM_READ;
+
+ applySegment( index,
+ segment.p_offset,
+ segment.p_vaddr,
+ segment.p_memsz,
+ NULL,
+ sclass,
+ perm,
+ m_elf->getAlignment(segment.p_align) );
+
+ ++index;
+ }
+ }
+}
+
+void cell_loader::applySegment(uint32 sel,
+ uint64 offset,
+ uint64 addr,
+ uint64 size,
+ const char *name,
+ const char *sclass,
+ uchar perm,
+ uchar align,
+ bool load) {
+ addr += m_relocAddr;
+
+ segment_t seg;
+ seg.startEA = addr;
+ seg.endEA = addr + size;
+ seg.color = DEFCOLOR;
+ seg.sel = sel;
+ seg.bitness = 1;
+ seg.orgbase = sel;
+ seg.comb = scPub;
+ seg.perm = perm;
+ seg.flags = SFL_LOADER;
+ seg.align = align;
+
+ set_selector(sel, 0);
+
+ if ( name == NULL )
+ name = "";
+
+ add_segm_ex(&seg, name, sclass, NULL);
+
+ if ( load == true )
+ file2base(m_elf->getReader(), offset, addr, addr + size, true);
+}
+
+void cell_loader::applyRelocations() {
+ if ( m_hasSegSym )
+ applySectionRelocations(); // pretty much only for 0.85
+ else
+ applySegmentRelocations();
+}
+
+void cell_loader::applySectionRelocations() {
+ msg("Applying section based relocations..\n");
+
+ auto &sections = m_elf->getSections();
+ auto symbols = m_elf->getSymbols();
+
+ for ( auto &section : sections ) {
+ // NOTE: the only SHT_RELA sections I see after 0.85
+ // are non-allocatable so no reason to consider those
+ if ( section.sh_type == SHT_RELA ) {
+
+ auto nrela = section.sh_size / sizeof(Elf64_Rela);
+ auto relocations = reinterpret_cast<Elf64_Rela *>(section.data());
+
+ for ( size_t i = 0; i < nrela; ++i ) {
+ auto &rela = relocations[i];
+
+ swap(rela.r_offset);
+ swap(rela.r_info);
+ swap(rela.r_addend);
+
+ uint32 type = ELF64_R_TYPE(rela.r_info);
+ uint32 sym = ELF64_R_SYM (rela.r_info);
+
+ //msg("r_type: %08x\n", type);
+ //msg("r_sym: %08x\n", sym);
+
+ if ( type == R_PPC64_NONE ) {
+ msg("Skipping relocation..\n");
+ continue;
+ }
+
+ if ( type > R_PPC64_TLSGD ) {
+ msg("Invalid relocation type (%i)!\n", type);
+ continue;
+ }
+
+ //msg("nsyms = %08x\n", m_elf->getNumSymbols());
+ //msg("symsec = %04x\n", symbols[ sym ].st_shndx);
+
+ if ( sym > m_elf->getNumSymbols() ) {
+ msg("Invalid symbol index!\n");
+ continue;
+ }
+
+
+ if ( symbols[ sym ].st_shndx > m_elf->getNumSections() ) {
+ if ( symbols[ sym ].st_shndx != SHN_ABS ) {
+ msg("Invalid symbol section index!\n");
+ continue;
+ }
+ }
+
+ uint32 addr = sections[ section.sh_info ].sh_addr +
+ rela.r_offset;
+ uint32 saddr = sections[ symbols[ sym ].st_shndx ].sh_addr +
+ symbols[ sym ].st_value + rela.r_addend;
+
+ applyRelocation(type, addr, saddr);
+ }
+ }
+ }
+}
+
+void cell_loader::applySegmentRelocations() {
+ msg("Applying segment based relocations..\n");
+
+ auto &segments = m_elf->getSegments();
+
+ for ( auto &segment : segments ) {
+ if ( segment.p_type == PT_SCE_PPURELA ) {
+ auto nrela = segment.p_filesz / sizeof(Elf64_Rela);
+ auto relocations = reinterpret_cast<Elf64_Rela *>(segment.data());
+
+ for ( size_t i = 0; i < nrela; ++i ) {
+ auto &rela = relocations[i];
+
+ swap(rela.r_offset);
+ swap(rela.r_info);
+ swap(rela.r_addend);
+
+ auto type = ELF64_R_TYPE(rela.r_info);
+
+ if ( type == R_PPC64_NONE )
+ continue;
+
+ auto sym = ELF64_R_SYM(rela.r_info);
+ auto patchseg = (sym & 0x000000ff);
+ auto symseg = (sym & 0x7fffff00) >> 8;
+
+ uint32 addr, saddr;
+ if ( patchseg == 0xFF )
+ addr = 0;
+ else
+ addr = segments[patchseg].p_vaddr + rela.r_offset;
+
+ if ( symseg == 0xFF )
+ saddr = 0;
+ else
+ saddr = segments[symseg].p_vaddr + rela.r_addend;
+
+ applyRelocation(type, addr, saddr);
+ }
+ break; // TODO: should only be one segment right?
+ }
+ }
+}
+
+void cell_loader::applyRelocation(uint32 type, uint32 addr, uint32 saddr) {
+ uint32 value;
+
+ addr += m_relocAddr;
+ saddr += m_relocAddr;
+
+ //msg("Applying relocation %i (%08x -> %08x)\n", type, addr, saddr);
+
+ switch ( type ) {
+ case R_PPC64_ADDR32:
+ value = saddr;
+ patch_long(addr, value);
+ break;
+ case R_PPC64_ADDR16_LO:
+ value = saddr & 0xFFFF;
+ patch_word(addr, value);
+ break;
+ case R_PPC64_ADDR16_HA:
+ value = (((saddr + 0x8000) >> 16) & 0xFFFF);
+ patch_word(addr, value);
+ break;
+ case R_PPC64_REL24:
+ value = get_original_long(addr);
+ value = (value & ~0x03fffffc) | ((saddr - addr) & 0x3fffffc);
+ patch_long(addr, value);
+ break;
+ case R_PPC64_TOC16:
+ value = saddr - m_gpValue;
+ patch_word(addr, value);
+ break;
+ case R_PPC64_TOC16_DS:
+ value = get_word(addr);
+ value = (value & ~0xFFFC) | ((saddr - m_gpValue) & 0xFFFC);
+ patch_word(addr, value);
+ break;
+ case R_PPC64_TLSGD:
+ value = m_gpValue;
+ patch_long(addr, value);
+ break;
+ default:
+ msg("Unsupported relocation (%i).\n", type);
+ break;
+ }
+}
+
+void cell_loader::loadExports(uint32 entTop, uint32 entEnd) {
+ msg("Loading exports...\n");
+
+ tid_t tid = get_struc_id("_scelibent_ppu32");
+ do_name_anyway(entTop - 4, "__begin_of_section_lib_ent");
+ do_name_anyway(entEnd, "__end_of_section_lib_ent");
+
+ uchar structsize;
+
+ for ( ea_t ea = entTop; ea < entEnd; ea += structsize ) {
+ structsize = get_byte(ea);
+
+ auto nfunc = get_word(ea + offsetof(_scelibent_common, nfunc));
+ auto nvar = get_word(ea + offsetof(_scelibent_common, nvar));
+ auto ntlsvar = get_word(ea + offsetof(_scelibent_common, ntlsvar));
+ auto count = nfunc + nvar + ntlsvar;
+
+ //msg("Num Functions: %i\n", nfunc);
+ //msg("Num Variables: %i\n", nvar);
+ //msg("Num TLS Variables: %i\n", ntlsvar);
+
+ if ( structsize == sizeof(_scelibent_ppu32) ) {
+ doStruct(ea, sizeof(_scelibent_ppu32), tid);
+
+ auto libNamePtr = get_long(ea + offsetof(_scelibent_ppu32, libname));
+ auto nidTable = get_long(ea + offsetof(_scelibent_ppu32, nidtable));
+ auto addTable = get_long(ea + offsetof(_scelibent_ppu32, addtable));
+
+ char libName[256];
+ char symName[MAXNAMELEN];
+ if ( libNamePtr == NULL ) {
+ do_name_anyway(nidTable, "_NONAMEnid_table");
+ do_name_anyway(addTable, "_NONAMEentry_table");
+ } else {
+ get_ascii_contents(libNamePtr, get_max_ascii_length(libNamePtr, ASCSTR_C), ASCSTR_C, libName, 256);
+
+ qsnprintf(symName, MAXNAMELEN, "_%s_str", libName);
+ do_name_anyway(libNamePtr, symName);
+
+ qsnprintf(symName, MAXNAMELEN, "__%s_Functions_NID_table", libName);
+ do_name_anyway(nidTable, symName);
+
+ qsnprintf(symName, MAXNAMELEN, "__%s_Functions_table", libName);
+ do_name_anyway(addTable, symName);
+ }
+
+ //msg("Processing entries..\n");
+ if ( nidTable != NULL && addTable != NULL ) {
+ for ( int i = 0; i < count; ++i ) {
+ const char *resolvedNid;
+ ea_t nidOffset = nidTable + (i * 4);
+ ea_t addOffset = addTable + (i * 4);
+
+ uint32 nid = get_long(nidOffset);
+ uint32 add = get_long(addOffset);
+
+ if ( libNamePtr ) {
+ uint32 addToc = get_long(add);
+ resolvedNid = getNameFromDatabase(libName, nid);
+ if ( resolvedNid ) {
+ set_cmt(nidOffset, resolvedNid, false);
+ do_name_anyway(add, resolvedNid);
+
+ // only label functions this way
+ if ( i < nfunc ) {
+ qsnprintf(symName, MAXNAMELEN, ".%s", resolvedNid);
+ do_name_anyway(addToc, symName);
+ }
+ }
+
+ if ( i < nfunc )
+ auto_make_proc(addToc);
+ }
+
+ //msg("doDwrd: %08x\n", nidOffset);
+ //msg("doDwrd: %08x\n", addOffset);
+ doDwrd(nidOffset, 4);
+ doDwrd(addOffset, 4);
+ }
+ }
+ } else {
+ msg("Unknown export structure at %08x.\n", ea);
+ continue;
+ }
+ }
+}
+
+void cell_loader::loadImports(uint32 stubTop, uint32 stubEnd) {
+ msg("Loading imports...\n");
+
+ tid_t tid = get_struc_id("_scelibstub_ppu32");
+
+ do_name_anyway(stubTop - 4, "__begin_of_section_lib_stub");
+ do_name_anyway(stubEnd, "__end_of_section_lib_stub");
+
+ uchar structsize;
+
+ // define data for lib stub
+ for ( ea_t ea = stubTop; ea < stubEnd; ea += structsize ) {
+ structsize = get_byte(ea);
+
+ auto nFunc = get_word(ea + offsetof(_scelibstub_common, nfunc));
+ auto nVar = get_word(ea + offsetof(_scelibstub_common, nvar));
+ auto nTlsVar = get_word(ea + offsetof(_scelibstub_common, ntlsvar));
+
+ //msg("Num Functions: %i\n", nFunc);
+ //msg("Num Variables: %i\n", nVar);
+ //msg("Num TLS Variables: %i\n", nTlsVar);
+
+ if (structsize == sizeof(_scelibstub_ppu32)) {
+ doStruct(ea, sizeof(_scelibstub_ppu32), tid);
+
+ ea_t libNamePtr = get_long(ea + offsetof(_scelibstub_ppu32, libname));
+ ea_t funcNidTable = get_long(ea + offsetof(_scelibstub_ppu32, func_nidtable));
+ ea_t funcTable = get_long(ea + offsetof(_scelibstub_ppu32, func_table));
+ ea_t varNidTable = get_long(ea + offsetof(_scelibstub_ppu32, var_nidtable));
+ ea_t varTable = get_long(ea + offsetof(_scelibstub_ppu32, var_table));
+ ea_t tlsNidTable = get_long(ea + offsetof(_scelibstub_ppu32, tls_nidtable));
+ ea_t tlsTable = get_long(ea + offsetof(_scelibstub_ppu32, tls_table));
+
+ char libName[256];
+ char symName[MAXNAMELEN];
+ get_ascii_contents(libNamePtr, get_max_ascii_length(libNamePtr, ASCSTR_C), ASCSTR_C, libName, 256);
+
+ qsnprintf(symName, MAXNAMELEN, "_%s_0001_stub_head", libName);
+ do_name_anyway(ea, symName);
+
+ qsnprintf(symName, MAXNAMELEN, "_%s_stub_str", libName);
+ do_name_anyway(libNamePtr, symName);
+
+ qsnprintf(symName, MAXNAMELEN, "_sce_package_version_%s", libName);
+ do_name_anyway(libNamePtr - 4, symName);
+
+ //msg("Processing %i exported functions...\n", nFunc);
+ if ( funcNidTable != NULL && funcTable != NULL ) {
+ for ( int i = 0; i < nFunc; ++i ) {
+ const char *resolvedNid;
+
+ ea_t nidOffset = funcNidTable + (i * 4);
+ ea_t funcOffset = funcTable + (i * 4);
+
+ uint32 nid = get_long(nidOffset);
+ uint32 func = get_long(funcOffset);
+
+ resolvedNid = getNameFromDatabase(libName, nid);
+ if ( resolvedNid ) {
+ set_cmt(nidOffset, resolvedNid, false);
+ qsnprintf(symName, MAXNAMELEN, "%s.stub_entry", resolvedNid);
+ do_name_anyway(funcOffset, symName);
+ qsnprintf(symName, MAXNAMELEN, ".%s", resolvedNid);
+ do_name_anyway(func, symName);
+ }
+
+ //msg("doDwrd: %08x\n", nidOffset);
+ //msg("doDwrd: %08x\n", funcOffset);
+ doDwrd(nidOffset, 4); // nid
+ doDwrd(funcOffset, 4); // func
+ if ( add_func(func, BADADDR) ) {
+ get_func(func)->flags |= FUNC_LIB;
+ //add_entry(func, func, ...)
+ }
+ }
+ }
+
+ //msg("Processing exported variables...\n");
+ if ( varNidTable != NULL && varTable ) {
+ for ( int i = 0; i < nVar; ++i ) {
+ const char *resolvedNid;
+
+ ea_t nidOffset = varNidTable + (i * 4);
+ ea_t varOffset = varTable + (i * 4);
+
+ uint32 nid = get_long(nidOffset);
+ uint32 func = get_long(varOffset);
+
+ resolvedNid = getNameFromDatabase(libName, nid);
+ if ( resolvedNid ) {
+ set_cmt(nidOffset, resolvedNid, false);
+ do_name_anyway(varOffset, resolvedNid);
+ }
+
+ //msg("doDwrd: %08x\n", nidOffset);
+ //msg("doDwrd: %08x\n", varOffset);
+ doDwrd(nidOffset, 4);
+ doDwrd(varOffset, 4);
+ }
+ }
+
+ //msg("Processing exported TLS variables...\n");
+ if ( tlsNidTable != NULL && tlsTable != NULL ) {
+ for ( int i = 0; i < nVar; ++i ) {
+ const char *resolvedNid;
+
+ ea_t nidOffset = tlsNidTable + (i * 4);
+ ea_t tlsOffset = tlsTable + (i * 4);
+
+ uint32 nid = get_long(nidOffset);
+ uint32 func = get_long(tlsOffset);
+
+ resolvedNid = getNameFromDatabase(libName, nid);
+ if ( resolvedNid ) {
+ set_cmt(nidOffset, resolvedNid, false);
+ do_name_anyway(tlsOffset, resolvedNid);
+ }
+
+ //msg("doDwrd: %08x\n", nidOffset);
+ //msg("doDwrd: %08x\n", tlsOffset);
+ doDwrd(nidOffset, 4);
+ doDwrd(tlsOffset, 4);
+ }
+ }
+ } else {
+ msg("Unknown import structure at %08x.\n", ea);
+ continue;
+ }
+ }
+}
+
+const char *cell_loader::getNameFromDatabase(
+ const char *library, unsigned int nid) {
+ auto header = m_database.FirstChildElement();
+
+ if ( header ) {
+ auto group = header->FirstChildElement();
+ if ( group ) {
+ // find library in xml
+ do {
+ if ( !strcmp(library, group->Attribute("name")) ) {
+ auto entry = group->FirstChildElement();
+ if ( entry ) {
+ // find NID in library group
+ do {
+ if ( strtoul(entry->Attribute("id"),0,0) == nid )
+ return entry->Attribute("name");
+ } while ( entry = entry->NextSiblingElement() );
+ }
+ }
+ } while ( group = group->NextSiblingElement() );
+ }
+ }
+
+ return nullptr;
+}
+
+void cell_loader::applyModuleInfo() {
+ auto firstSegment = m_elf->getSegments()[0];
+
+ ea_t modInfoEa = (firstSegment.p_vaddr + m_relocAddr) +
+ (firstSegment.p_paddr - firstSegment.p_offset);
+
+ tid_t tid = get_struc_id("_scemoduleinfo");
+ doStruct(modInfoEa, sizeof(_scemoduleinfo_ppu32), tid);
+
+ loadExports( get_long(modInfoEa + offsetof(_scemoduleinfo_ppu32, ent_top)),
+ get_long(modInfoEa + offsetof(_scemoduleinfo_ppu32, ent_end)) );
+
+ loadImports( get_long(modInfoEa + offsetof(_scemoduleinfo_ppu32, stub_top)),
+ get_long(modInfoEa + offsetof(_scemoduleinfo_ppu32, stub_end)) );
+
+ add_entry(0, modInfoEa, "module_info", false);
+
+}
+
+void cell_loader::applyProcessInfo() {
+ for ( auto segment : m_elf->getSegments() ) {
+ if ( segment.p_type == PT_PROC_PARAM ) {
+ tid_t tid = get_struc_id("sys_process_param_t");
+ doStruct(segment.p_vaddr, sizeof(sys_process_param_t), tid);
+ } else if ( segment.p_type == PT_PROC_PRX ) {
+ tid_t tid = get_struc_id("sys_process_prx_info_t");
+ doStruct(segment.p_vaddr, sizeof(sys_process_prx_info_t), tid);
+
+ loadExports( get_long(segment.p_vaddr + offsetof(sys_process_prx_info_t, libent_start)),
+ get_long(segment.p_vaddr + offsetof(sys_process_prx_info_t, libent_end)) );
+
+ loadImports( get_long(segment.p_vaddr + offsetof(sys_process_prx_info_t, libstub_start)),
+ get_long(segment.p_vaddr + offsetof(sys_process_prx_info_t, libstub_end)) );
+ }
+ }
+}
+
+void cell_loader::swapSymbols() {
+ // Since section based relocations depend on symbols
+ // we need to swap symbols before we get to relocations.
+ // Pretty much only for 0.85 PRX's but we still need to
+ // swap them anyway.
+ auto section = m_elf->getSymbolsSection();
+
+ if (section == NULL)
+ return;
+
+ //msg("Swapping symbols...\n");
+
+ auto symbols = m_elf->getSymbols();
+
+ for ( size_t i = 0; i < m_elf->getNumSymbols(); ++i ) {
+ auto symbol = &symbols[i];
+
+ swap(symbol->st_name);
+ swap(symbol->st_shndx);
+ swap(symbol->st_size);
+ swap(symbol->st_value);
+ }
+}
+
+void cell_loader::applySymbols() {
+ auto section = m_elf->getSymbolsSection();
+
+ if (section == NULL)
+ return;
+
+ msg("Applying symbols...\n");
+
+ auto nsym = m_elf->getNumSymbols();
+ auto symbols = m_elf->getSymbols();
+
+ const char *stringTable = m_elf->getSections().at(section->sh_link).data();
+
+ for ( size_t i = 0; i < nsym; ++i ) {
+ auto &symbol = symbols[i];
+
+ auto type = ELF64_ST_TYPE(symbol.st_info),
+ bind = ELF64_ST_BIND(symbol.st_info);
+ auto value = symbol.st_value;
+
+ //msg("st_name: %08x\n", symbol.st_name);
+ //msg("st_type: %08x\n", type);
+ //msg("st_bind: %08x\n", bind);
+
+ if ( symbol.st_shndx > m_elf->getNumSections() ||
+ !(m_elf->getSections()[ symbol.st_shndx ].sh_flags & SHF_ALLOC) )
+ continue;
+
+ if ( symbol.st_shndx == SHN_ABS )
+ continue;
+
+ if ( isLoadingPrx() )
+ value += m_elf->getSections()[ symbol.st_shndx ].sh_addr + m_relocAddr;
+
+ switch ( type ) {
+ case STT_OBJECT:
+ do_name_anyway(value, &stringTable[ symbol.st_name ]);
+ break;
+ case STT_FILE:
+ describe(value, true, "Source File: %s", &stringTable[ symbol.st_name ]);
+ break;
+ case STT_FUNC:
+ do_name_anyway(value, &stringTable[ symbol.st_name ]);
+ auto_make_proc(value);
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+void cell_loader::declareStructures() {
+ struc_t *sptr;
+
+ // offset type
+ typeinfo_t ot;
+ ot.ri.flags = REF_OFF32;
+ ot.ri.target = BADADDR;
+ ot.ri.base = 0;
+ ot.ri.tdelta = 0;
+
+ tid_t modInfoCommon = add_struc(BADADDR, "_scemoduleinfo_common");
+ sptr = get_struc(modInfoCommon);
+ if ( sptr != NULL ) {
+ add_struc_member(sptr, "modattribute", BADADDR, wordflag(), NULL, 2);
+ add_struc_member(sptr, "modversion", BADADDR, byteflag(), NULL, 2);
+ add_struc_member(sptr, "modname", BADADDR, byteflag(), NULL, SYS_MODULE_NAME_LEN);
+ add_struc_member(sptr, "terminal", BADADDR, byteflag(), NULL, 1);
+
+ sptr = get_struc(add_struc(BADADDR, "_scemoduleinfo"));
+ if ( sptr != NULL ) {
+ typeinfo_t mt;
+ mt.tid = modInfoCommon;
+ add_struc_member(sptr, "c", BADADDR, struflag(), &mt, get_struc_size(mt.tid));
+
+ add_struc_member(sptr, "gp_value", BADADDR, offflag() | dwrdflag(), &ot, 4);
+ add_struc_member(sptr, "ent_top", BADADDR, offflag() | dwrdflag(), &ot, 4);
+ add_struc_member(sptr, "ent_end", BADADDR, offflag() | dwrdflag(), &ot, 4);
+ add_struc_member(sptr, "stub_top", BADADDR, offflag() | dwrdflag(), &ot, 4);
+ add_struc_member(sptr, "stub_end", BADADDR, offflag() | dwrdflag(), &ot, 4);
+ }
+ }
+
+ tid_t libStubCommon = add_struc(BADADDR, "_scelibstub_ppu_common");
+ sptr = get_struc(libStubCommon);
+ if ( sptr != NULL ) {
+ add_struc_member(sptr, "structsize", BADADDR, byteflag(), NULL, 1);
+ add_struc_member(sptr, "reserved1", BADADDR, byteflag(), NULL, 1);
+ add_struc_member(sptr, "version", BADADDR, wordflag(), NULL, 2);
+ add_struc_member(sptr, "attribute", BADADDR, wordflag(), NULL, 2);
+ add_struc_member(sptr, "nfunc", BADADDR, wordflag(), NULL, 2);
+ add_struc_member(sptr, "nvar", BADADDR, wordflag(), NULL, 2);
+ add_struc_member(sptr, "ntlsvar", BADADDR, wordflag(), NULL, 2);
+ add_struc_member(sptr, "reserved2", BADADDR, byteflag(), NULL, 4);
+
+ sptr = get_struc(add_struc(BADADDR, "_scelibstub_ppu32"));
+ if ( sptr != NULL ) {
+ typeinfo_t mt;
+ mt.tid = libStubCommon;
+ add_struc_member(sptr, "c", BADADDR, struflag(), &mt, get_struc_size(mt.tid));
+
+ add_struc_member(sptr, "libname", BADADDR, offflag() | dwrdflag(), &ot, 4);
+ add_struc_member(sptr, "func_nidtable", BADADDR, offflag() | dwrdflag(), &ot, 4);
+ add_struc_member(sptr, "func_table", BADADDR, offflag() | dwrdflag(), &ot, 4);
+ add_struc_member(sptr, "var_nidtable", BADADDR, offflag() | dwrdflag(), &ot, 4);
+ add_struc_member(sptr, "var_table", BADADDR, offflag() | dwrdflag(), &ot, 4);
+ add_struc_member(sptr, "tls_nidtable", BADADDR, offflag() | dwrdflag(), &ot, 4);
+ add_struc_member(sptr, "tls_table", BADADDR, offflag() | dwrdflag(), &ot, 4);
+ }
+ }
+
+ tid_t libEntCommon = add_struc(BADADDR, "_scelibent_ppu_common");
+ sptr = get_struc(libEntCommon);
+ if ( sptr != NULL ) {
+ add_struc_member(sptr, "structsize", BADADDR, byteflag(), NULL, 1);
+ add_struc_member(sptr, "reserved1", BADADDR, byteflag(), NULL, 1);
+ add_struc_member(sptr, "version", BADADDR, wordflag(), NULL, 2);
+ add_struc_member(sptr, "attribute", BADADDR, wordflag(), NULL, 2);
+ add_struc_member(sptr, "nfunc", BADADDR, wordflag(), NULL, 2);
+ add_struc_member(sptr, "nvar", BADADDR, wordflag(), NULL, 2);
+ add_struc_member(sptr, "ntlsvar", BADADDR, wordflag(), NULL, 2);
+ add_struc_member(sptr, "hashinfo", BADADDR, byteflag(), NULL, 1);
+ add_struc_member(sptr, "hashinfotls", BADADDR, byteflag(), NULL, 1);
+ add_struc_member(sptr, "reserved2", BADADDR, byteflag(), NULL, 1);
+ add_struc_member(sptr, "nidaltsets", BADADDR, byteflag(), NULL, 1);
+
+ sptr = get_struc(add_struc(BADADDR, "_scelibent_ppu32"));
+ if ( sptr != NULL ) {
+ typeinfo_t mt;
+ mt.tid = libEntCommon;
+ add_struc_member(sptr, "c", BADADDR, struflag(), &mt, get_struc_size(mt.tid));
+
+ add_struc_member(sptr, "libname", BADADDR, offflag() | dwrdflag(), &ot, 4);
+ add_struc_member(sptr, "nidtable", BADADDR, offflag() | dwrdflag(), &ot, 4);
+ add_struc_member(sptr, "addtable", BADADDR, offflag() | dwrdflag(), &ot, 4);
+ }
+ }
+
+ tid_t procParamInfo = add_struc(BADADDR, "sys_process_param_t");
+ sptr = get_struc(procParamInfo);
+ if ( sptr != NULL ) {
+ add_struc_member(sptr, "size", BADADDR, dwrdflag(), NULL, 4);
+ add_struc_member(sptr, "magic", BADADDR, dwrdflag(), NULL, 4);
+ add_struc_member(sptr, "version", BADADDR, dwrdflag(), NULL, 4);
+ add_struc_member(sptr, "sdk_version", BADADDR, dwrdflag(), NULL, 4);
+ add_struc_member(sptr, "primary_prio", BADADDR, dwrdflag(), NULL, 4);
+ add_struc_member(sptr, "primary_stacksize", BADADDR, dwrdflag(), NULL, 4);
+ add_struc_member(sptr, "malloc_pagesize", BADADDR, dwrdflag(), NULL, 4);
+ add_struc_member(sptr, "ppc_seg", BADADDR, dwrdflag(), NULL, 4);
+ add_struc_member(sptr, "crash_dump_param_addr", BADADDR, dwrdflag(), NULL, 4);
+ }
+
+ tid_t procPrxInfo = add_struc(BADADDR, "sys_process_prx_info_t");
+ sptr = get_struc(procPrxInfo);
+ if ( sptr != NULL ) {
+ add_struc_member(sptr, "size", BADADDR, dwrdflag(), NULL, 4);
+ add_struc_member(sptr, "magic", BADADDR, dwrdflag(), NULL, 4);
+ add_struc_member(sptr, "version", BADADDR, dwrdflag(), NULL, 4);
+ add_struc_member(sptr, "sdk_version", BADADDR, dwrdflag(), NULL, 4);
+ add_struc_member(sptr, "libent_start", BADADDR, offflag() | dwrdflag(), &ot, 4);
+ add_struc_member(sptr, "libent_end", BADADDR, offflag() | dwrdflag(), &ot, 4);
+ add_struc_member(sptr, "libstub_start", BADADDR, offflag() | dwrdflag(), &ot, 4);
+ add_struc_member(sptr, "libstub_end", BADADDR, offflag() | dwrdflag(), &ot, 4);
+ add_struc_member(sptr, "major_version", BADADDR, byteflag(), NULL, 1);
+ add_struc_member(sptr, "minor_version", BADADDR, byteflag(), NULL, 1);
+ add_struc_member(sptr, "reserved", BADADDR, byteflag(), NULL, 6);
+ }
+}
diff --git a/src/ps3/cell_loader.h b/src/ps3/cell_loader.h
new file mode 100644
index 0000000..40581d5
--- /dev/null
+++ b/src/ps3/cell_loader.h
@@ -0,0 +1,61 @@
+
+#pragma once
+
+#include "elf_reader.h"
+#include "tinyxml.h"
+#include "sce.h"
+#include <string>
+
+class cell_loader {
+ elf_reader<elf64> *m_elf; ///< Handle for this loader's ELF reader.
+ TiXmlDocument m_database; ///< Handle for this loader's NID xml database.
+ uint64 m_relocAddr; // Base relocaton address for PRX's.
+ uint64 m_gpValue; // TOC value
+ bool m_hasSegSym; // has seg sym, but the real meaning
+ // is if its a 0.85 PRX since its the only
+ // way I know how to check
+
+public:
+ cell_loader(elf_reader<elf64> *elf, uint64 relocAddr, std::string databasePath);
+
+ void apply();
+
+ bool isLoadingExec() const
+ { return m_elf->type() == ET_EXEC; }
+
+ bool isLoadingPrx() const
+ { return m_elf->type() == ET_SCE_PPURELEXEC; }
+
+private:
+ void applySegments();
+ void applySegment(uint32 sel,
+ uint64 offset,
+ uint64 addr,
+ uint64 size,
+ const char *name,
+ const char *sclass,
+ uchar perm,
+ uchar align,
+ bool load = true);
+
+ void applySectionHeaders();
+ void applyProgramHeaders();
+
+ void applyRelocations();
+ void applySectionRelocations();
+ void applySegmentRelocations();
+ void applyRelocation(uint32 type, uint32 addr, uint32 saddr);
+
+ void declareStructures();
+
+ void applyModuleInfo();
+ void loadExports(uint32 entTop, uint32 entEnd);
+ void loadImports(uint32 stubTop, uint32 stubEnd);
+
+ const char *getNameFromDatabase(const char *group, unsigned int nid);
+
+ void applyProcessInfo();
+
+ void swapSymbols();
+ void applySymbols();
+}; \ No newline at end of file
diff --git a/src/ps3/ps3.cpp b/src/ps3/ps3.cpp
new file mode 100644
index 0000000..19920a8
--- /dev/null
+++ b/src/ps3/ps3.cpp
@@ -0,0 +1,67 @@
+
+#include "../elf_common/elf_reader.h"
+#include "cell_loader.h"
+#include "sce.h"
+
+#include <idaldr.h>
+
+#include <memory>
+
+#define DATABASE_FILE "ps3.xml"
+
+static int idaapi
+ accept_file(linput_t *li, char fileformatname[MAX_FILE_FORMAT_NAME], int n)
+{
+ if (n > 0)
+ return 0;
+
+ elf_reader<elf64> elf(li);
+
+ if (elf.verifyHeader() &&
+ elf.machine() == EM_PPC64 &&
+ elf.osabi() == ELFOSABI_CELLOSLV2) {
+ const char *type;
+
+ if (elf.type() == ET_EXEC)
+ type = "Executable";
+ else if (elf.type() == ET_SCE_PPURELEXEC)
+ type = "Relocatable Executable";
+ else
+ return 0;
+
+ set_processor_type("ppc", SETPROC_ALL);
+
+ qsnprintf(fileformatname, MAX_FILE_FORMAT_NAME, "Playstation 3 PPU %s", type);
+
+ return 1 | ACCEPT_FIRST;
+ }
+
+ return 0;
+}
+
+static void idaapi
+ load_file(linput_t *li, ushort neflags, const char *fileformatname)
+{
+ elf_reader<elf64> elf(li); elf.read();
+
+ ea_t relocAddr = 0;
+ if (elf.type() == ET_SCE_PPURELEXEC) {
+ if (neflags & NEF_MAN) {
+ askaddr(&relocAddr, "Please specify a relocation address base.");
+ }
+ }
+
+ cell_loader ldr(&elf, relocAddr, DATABASE_FILE); ldr.apply();
+}
+
+__declspec(dllexport)
+loader_t LDSC =
+{
+ IDP_INTERFACE_VERSION,
+ 0,
+ accept_file,
+ load_file,
+ NULL,
+ NULL,
+ NULL
+}; \ No newline at end of file
diff --git a/src/ps3/sce.h b/src/ps3/sce.h
new file mode 100644
index 0000000..a11463d
--- /dev/null
+++ b/src/ps3/sce.h
@@ -0,0 +1,167 @@
+#pragma once
+
+#include "elf.h"
+
+#define ELFOSABI_CELLOSLV2 102 /* CellOS Lv2 */ /* sce local */
+
+#define ET_SCE_PPURELEXEC 0xffa4
+
+#define SHT_SCE_PPURELA 0x700000a4
+
+#define PT_PROC_PARAM 0x60000001
+#define PT_PROC_PRX 0x60000002
+
+#define PT_SCE_COMMENT 0x6fffff00
+#define PT_SCE_VERSION 0x6fffff01
+
+#define PT_SCE_PPURELA 0x700000a4
+#define PT_SCE_SEGSYM 0x700000a8
+
+#define PF_SPU_X (0x00100000) /* SPU executable defined, but unused.*/
+#define PF_SPU_W (0x00200000) /* SPU writable */
+#define PF_SPU_R (0x00400000) /* SPU readable */
+#define PF_RSX_X (0x01000000) /* RSX executable defined, but unused. */
+#define PF_RSX_W (0x02000000) /* RSX writable */
+#define PF_RSX_R (0x04000000) /* RSX readable */
+
+#define SYS_MODULE_NAME_LEN 27
+#define SYS_MODULE_MAX_SEGMENTS 4
+
+#define SYS_LIB_AUTO_EXPORT (0x0001)
+#define SYS_LIB_WEAK_EXPORT (0x0002)
+#define SYS_LIB_NOLINK_EXPORT (0x0004)
+#define SYS_LIB_WEAK_IMPORT (0x0008)
+
+/* MODULE INFO */
+
+typedef struct _scemoduleinfo_common {
+ unsigned short modattribute;
+ unsigned char modversion[2];
+ char modname[SYS_MODULE_NAME_LEN];
+ char terminal;
+} sceModuleInfo_common;
+
+typedef struct _scemoduleinfo_ppu32 {
+ sceModuleInfo_common c;
+ Elf32_Addr gp_value;
+ Elf32_Addr ent_top;
+ Elf32_Addr ent_end;
+ Elf32_Addr stub_top;
+ Elf32_Addr stub_end;
+} sceModuleInfo_ppu32;
+
+typedef struct _scemoduleinfo_ppu64 {
+ sceModuleInfo_common c;
+ Elf64_Addr gp_value;
+ Elf64_Addr ent_top;
+ Elf64_Addr ent_end;
+ Elf64_Addr stub_top;
+ Elf64_Addr stub_end;
+} sceModuleInfo_ppu64;
+
+
+/* IMPORTS */
+
+typedef struct _scelibstub_common {
+ unsigned char structsize;
+ unsigned char reserved1[1];
+ unsigned short version;
+ unsigned short attribute;
+ unsigned short nfunc;
+ unsigned short nvar;
+ unsigned short ntlsvar;
+ unsigned char reserved2[4];
+} sceKernelLibraryStubTable_common;
+
+typedef sceKernelLibraryStubTable_common
+ sceKernelLibraryStubTable_ppu_common;
+
+typedef struct _scelibstub_ppu32 {
+ sceKernelLibraryStubTable_ppu_common c;
+ Elf32_Addr libname;
+ Elf32_Addr func_nidtable;
+ Elf32_Addr func_table;
+ Elf32_Addr var_nidtable;
+ Elf32_Addr var_table;
+ Elf32_Addr tls_nidtable;
+ Elf32_Addr tls_table;
+} sceKernelLibraryStubTable_ppu32;
+
+typedef struct _scelibstub_ppu64 {
+ sceKernelLibraryStubTable_ppu_common c;
+ Elf64_Addr libname;
+ Elf64_Addr func_nidtable;
+ Elf64_Addr func_table;
+ Elf64_Addr var_nidtable;
+ Elf64_Addr var_table;
+ Elf64_Addr tls_nidtable;
+ Elf64_Addr tls_table;
+} sceKernelLibraryStubTable_ppu64;
+
+/* EXPORTS */
+
+typedef struct _scelibent_common {
+ unsigned char structsize;
+ unsigned char auxattribute;
+ short unsigned int version;
+ short unsigned int attribute;
+ short unsigned int nfunc;
+ short unsigned int nvar;
+ short unsigned int ntlsvar;
+ unsigned char hashinfo;
+ unsigned char hashinfotls;
+ unsigned char reserved2[1];
+ unsigned char nidaltsets;
+} sceKernelLibraryEntryTable_common;
+
+typedef sceKernelLibraryEntryTable_common
+ sceKernelLibraryEntryTable_ppu_common;
+
+typedef struct _scelibent_ppu32 {
+ sceKernelLibraryEntryTable_ppu_common c;
+ Elf32_Addr libname;
+ Elf32_Addr nidtable;
+ Elf32_Addr addtable;
+} sceKernelLibraryEntryTable_ppu32;
+
+typedef struct _scelibent_ppu64 {
+ sceKernelLibraryEntryTable_ppu_common c;
+ Elf64_Addr libname;
+ Elf64_Addr nidtable;
+ Elf64_Addr addtable;
+} sceKernelLibraryEntryTable_ppu64;
+
+/* PROCESS PARAM */
+
+#define SYS_PROCESS_PARAM_MAGIC 0x13bcc5f6
+
+typedef struct {
+ unsigned int size;
+ unsigned int magic;
+ unsigned int version;
+ unsigned int sdk_version;
+ int primary_prio;
+ unsigned int primary_stacksize;
+ unsigned int malloc_pagesize;
+ unsigned int ppc_seg;
+ unsigned int crash_dump_param_addr;
+} sys_process_param_t;
+
+/* PROCESS PRX */
+
+#define SYS_PROCESS_PRX_MAGIC 0x1b434cec
+#define SYS_PROCESS_PRX_VERSION 4 /* latest */
+
+typedef struct sys_process_prx_info_t {
+ unsigned int size;
+ unsigned int magic;
+ unsigned int version;
+ unsigned int sdk_version;
+ unsigned int libent_start;
+ unsigned int libent_end;
+ unsigned int libstub_start;
+ unsigned int libstub_end;
+ unsigned char major_version;
+ unsigned char minor_version;
+ unsigned char reserved[6];
+} sys_process_prx_info_t;