First commit

This commit is contained in:
aerosoul94 2017-04-05 12:32:29 -05:00
commit 991de71c14
16 changed files with 6730 additions and 0 deletions

3
.gitmodules vendored Normal file
View File

@ -0,0 +1,3 @@
[submodule "third_party/tinyxml"]
path = third_party/tinyxml
url = https://github.com/icebreaker/TinyXML

29
ReadMe.md Normal file
View File

@ -0,0 +1,29 @@
# ida_game_elf_loaders
A collection of user mode ELF loaders for the following game consoles:
* PS3
* PS Vita
## Installation
Copy loader plugins to IDA loaders directory.
## Building
### Dependencies
* IDA SDK
* [CMake](https://cmake.org/download/)
### Generate Projects With CMake
The IDA cmake module included will expect to find the IDA SDK in an `IDA_SDK_DIR` or `IDA_SDK` environment variable.
If you would like to generate 64-bit EA targeted loaders, you need to add `-DIDA_64_BIT_EA_T=YES` to cmake command line.
Navigate to the directory of the loader you would like to build in 'src/', then run the following command
`mkdir build && cd build && cmake ../`
This should create a build directory with your generated project files.
### Building
Optionally, you can also build using cmake with the following command
`cmake --build ./`
## Notes
These have only been tested and built using Visual Studio 2015 using IDA SDK 6.8.

144
cmake/FindIDA.cmake Normal file
View File

@ -0,0 +1,144 @@
set(IDA_FOUND FALSE)
set(IDA_SDK_FOUND FALSE)
#
# Find IDA.
#
find_path(IDA_PATH
NAME "idag.exe" "idaq.exe"
HINTS $ENV{IDA_DIR} $ENV{IDADIR}
PATHS "C:/Program Files/IDA" "C:/Program Files (x86)/IDA"
DOC "IDA installation directory.")
if(IDA_PATH)
set(IDA_FOUND TRUE)
message(STATUS "Looking for IDA - found at ${IDA_PATH}")
else()
message(STATUS "Looking for IDA - not found")
endif()
#
# Make up the name of the SDK library subdirectory.
#
# Detect the platform.
set(platform "unknown")
if(WIN32)
set(platform "win")
endif()
if(UNIX)
set(platform "linux")
endif()
if(APPLE)
set(platform "mac")
endif()
# Detect the compiler.
set(compiler "unknown")
if(BORLAND)
set(compiler "bcc")
endif()
if(CMAKE_COMPILER_IS_GNUCXX OR ${CMAKE_CXX_COMPILER_ID} MATCHES "Clang")
set(compiler "gcc")
endif()
if(MSVC)
set(compiler "vc")
endif()
if(CMAKE_COMPILER_IS_GNUCXX OR ${CMAKE_CXX_COMPILER_ID} MATCHES "Clang")
set(compiler "gcc")
endif()
if(MSVC)
set(compiler "vc")
endif()
set(IDA_64_BIT_EA_T OFF CACHE BOOL "Use 64-bit ea_t. Set this to build 64-bit code capable IDA plugins.")
if(IDA_64_BIT_EA_T)
set(suffix "64")
else()
set(suffix "32")
endif()
if(CMAKE_SIZEOF_VOID_P EQUAL 8 AND NOT NC_M32)
set(library_dir "lib/x64_${platform}_${compiler}_${suffix}")
else()
set(library_dir "lib/x86_${platform}_${compiler}_${suffix}")
endif()
#
# Find IDA SDK.
#
find_path(IDA_SDK_PATH
NAME ${library_dir}
HINTS $ENV{IDA_SDK_DIR} $ENV{IDA_SDK}
PATHS "${IDA_PATH}/sdk"
DOC "IDA SDK directory.")
if(IDA_SDK_PATH)
set(IDA_SDK_FOUND TRUE)
set(IDA_INCLUDE_DIR ${IDA_SDK_PATH}/include)
set(IDA_LIBRARY_DIR ${IDA_SDK_PATH}/${library_dir})
if(MSVC)
file(GLOB IDA_LIBRARIES "${IDA_LIBRARY_DIR}/*.lib")
else()
file(GLOB IDA_LIBRARIES "${IDA_LIBRARY_DIR}/*.a")
endif()
set(IDA_DEFINITIONS -D__IDP__)
if(WIN32)
set(IDA_DEFINITIONS ${IDA_DEFINITIONS} -D__NT__)
endif()
if(UNIX)
set(IDA_DEFINITIONS ${IDA_DEFINITIONS} -D__LINUX__)
endif()
if(APPLE)
set(IDA_DEFINITIONS ${IDA_DEFINITIONS} -D__MAC__)
endif()
if(CMAKE_SIZEOF_VOID_P EQUAL 8 AND NOT NC_M32)
set(IDA_DEFINITIONS ${IDA_DEFINITIONS} -D__X64__)
endif()
if(IDA_64_BIT_EA_T)
set(IDA_DEFINITIONS ${IDA_DEFINITIONS} -D__EA64__)
endif()
if(WIN32)
if(IDA_64_BIT_EA_T)
set(IDA_PLUGIN_EXT "64.l64")
else()
set(IDA_PLUGIN_EXT ".ldw")
endif()
elseif(APPLE)
if(IDA_64_BIT_EA_T)
set(IDA_PLUGIN_EXT "64.lmc64")
set(IDA_SHARED_LIB_NAME ida64)
else()
set(IDA_PLUGIN_EXT ".lmc")
set(IDA_SHARED_LIB_NAME ida)
endif()
if (IDA_PATH)
file(GLOB_RECURSE IDA_SHARED_LIBRARY "${IDA_PATH}/*/lib${IDA_SHARED_LIB_NAME}.dylib")
else()
file(GLOB_RECURSE IDA_SHARED_LIBRARY "/Applications/IDA*/lib${IDA_SHARED_LIB_NAME}.dylib")
endif()
set(IDA_LIBRARIES ${IDA_LIBRARIES} ${IDA_SHARED_LIBRARY})
elseif(UNIX)
if(IDA_64_BIT_EA_T)
set(IDA_PLUGIN_EXT "64.llx64")
else()
set(IDA_PLUGIN_EXT ".llx")
endif()
endif()
message(STATUS "Looking for IDA SDK - found at ${IDA_SDK_PATH}")
else()
message(STATUS "Looking for IDA SDK - not found")
endif()
unset(platform)
unset(compiler)
unset(suffix)
unset(library_dir)

3753
src/elf_common/elf.h Normal file

File diff suppressed because it is too large Load Diff

432
src/elf_common/elf_reader.h Normal file
View File

@ -0,0 +1,432 @@
/**
* A very basic template based ELF reader. It is very common for OS's
* to implement their own ELF ABI. Section and segment headers are most
* commonly kept standard.
*
* Assumes that:
* - Elf_Ehdr is standard.
* - Elf_Shdr is standard.
* - Elf_Phdr is standard.
* - Only one SYMTAB section according to ELF ABI.
* - This system is little endian. If there is a problem with this,
* please let the author know.
*
* What it stores info for:
* - Elf_Ehdr as read from file.
* - vector of Elf_Shdr abstracted as Section.
* - vector of Elf_Phdr abstracted as Segment.
* - index of symbol section.
* - index of dynamic segment. <- TODO
* - index of section header string table section.
*
* Important facts about this reader:
* - Elf_Ehdr, Elf_Shdr, and Elf_Phdr is swapped if ELFDATA2MSB is set.
* This is to facilitate faster header/section/segment handling without
* the user needing to swap them.
* - Section/segment data is not modified by this reader.
* - Any section/segment data must be swapped by the user.
* - Data is only loaded when requested. (see Segment/Section data())
**/
#pragma once
#include "elf.h"
#include <idaldr.h> // TODO: do not depend on this
#include <vector>
static void printhex(const unsigned char *data, size_t size)
{
msg("00000000 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F\n");
for (size_t i = 0; i < size; i += 16)
{
msg("%08x ", i);
msg("%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
data[i + 0], data[i + 1], data[i + 2], data[i + 3], data[i + 4],
data[i + 5], data[i + 6], data[i + 7], data[i + 8], data[i + 9],
data[i + 10], data[i + 11], data[i + 12], data[i + 13], data[i + 14],
data[i + 15]);
}
}
template <typename T>
void swap(T &buf) {
unsigned char &pbuf = reinterpret_cast<unsigned char &>(buf);
std::reverse(&pbuf, &pbuf + sizeof(T));
}
class elf32 {
public:
typedef Elf32_Ehdr Ehdr;
typedef Elf32_Shdr Shdr;
typedef Elf32_Phdr Phdr;
typedef Elf32_Sym Sym;
typedef Elf32_Word Word;
typedef Elf32_Addr Addr;
};
class elf64 {
public:
typedef Elf64_Ehdr Ehdr;
typedef Elf64_Shdr Shdr;
typedef Elf64_Phdr Phdr;
typedef Elf64_Sym Sym;
typedef Elf64_Word Word;
typedef Elf64_Addr Addr;
};
template <class Elf>
class Segment
: public Elf::Phdr {
linput_t *m_reader;
std::vector<char> m_data;
public:
Segment() {}
Segment(linput_t *li)
: m_reader(li)
{
}
char *data()
{
if (m_data.empty())
{
m_data.resize(this->p_filesz);
qlseek(m_reader, this->p_offset);
qlread(m_reader, (void *)m_data.data(), this->p_filesz);
}
return m_data.data();
}
void setData(const char *data, size_t length)
{
m_data.assign(data, length);
}
void setReader(linput_t *li)
{
this->m_reader = li;
}
};
template <class Elf>
class Section
: public Elf::Shdr {
linput_t *m_reader;
std::vector<char> m_data; // TODO: switch to std::vector
public:
Section() {}
char *data()
{
if (m_data.empty()) {
m_data.resize(this->sh_size);
if (qlseek(m_reader, this->sh_offset) != this->sh_offset)
msg("Failed to seek to data.\n");
if (qlread(m_reader, (void *)m_data.data(), this->sh_size) == -1)
msg("Failed to read data.\n");
}
return m_data.data();
}
void setData(const char *data, size_t length)
{
m_data.assign(data, length);
}
void setReader(linput_t *li)
{
this->m_reader = li;
}
uint32 getNumEntries() const
{
if (this->sh_entsize != 0)
return this->sh_size / this->sh_entsize;
return 0;
}
uint32 getSize() const
{
return m_data.size();
}
};
template <
class Elf // Elf type
/*TODO: class reader*/ // reader interface
/*TODO: class logger*/ // log file interface
>
class elf_reader {
typename Elf::Ehdr m_header;
std::vector< Segment<Elf> > m_segments;
std::vector< Section<Elf> > m_sections;
Section<Elf> *m_symbolTableSection;
Section<Elf> *m_sectionStringTable;
linput_t *m_reader;
public:
elf_reader(linput_t *li)
: m_reader(li)
{
m_symbolTableSection = NULL;
m_sectionStringTable = NULL;
}
void read() {
readHeader();
readSegments();
readSections();
}
void print() {
printHeader();
printSegment();
printSections();
printSymbols();
}
bool verifyHeader() {
readHeader();
if (m_header.e_ident[EI_MAG0] == ELFMAG0 &&
m_header.e_ident[EI_MAG1] == ELFMAG1 &&
m_header.e_ident[EI_MAG2] == ELFMAG2 &&
m_header.e_ident[EI_MAG3] == ELFMAG3) {
return true;
}
return false;
}
linput_t *getReader() const
{ return this->m_reader; }
uchar osabi() const
{ return m_header.e_ident[EI_OSABI]; }
uchar bitsize() const
{ return m_header.e_ident[EI_CLASS]; }
uchar endian() const
{ return m_header.e_ident[EI_DATA]; }
typename Elf::Word type() const
{ return m_header.e_type; }
typename Elf::Word machine() const
{ return m_header.e_machine; }
typename Elf::Addr entry() const
{ return m_header.e_entry; }
typename Elf::Word flags() const
{ return m_header.e_flags; }
uint32_t getNumSegments() const
{ return m_segments.size(); }
uint32_t getNumSections() const
{ return m_sections.size(); }
std::vector< Segment<Elf> > &getSegments()
{ return m_segments; }
std::vector< Section<Elf> > &getSections()
{ return m_sections; }
Section<Elf> *getSectionStringTable() const
{ return m_sectionStringTable; }
Section<Elf> *getSymbolsSection() const
{ return m_symbolTableSection; }
uint32_t getNumSymbols() const
{ return m_symbolTableSection->getNumEntries(); }
typename Elf::Sym *getSymbols() const
{ return (typename Elf::Sym *)m_symbolTableSection->data(); }
Section<Elf> *getSectionByName(const char *name)
{
const char *strTab = m_sectionStringTable->data();
for (auto &section : m_sections) {
if (strcmp(&strTab[section.sh_name], name) == 0)
return &section;
}
return NULL;
}
uchar getAlignment(typename Elf::Word align)
{
switch (align) {
case 0x1: return saRelByte;
case 0x2: return saRelWord;
case 0x4: return saRelDble;
case 0x8: return saRelQword;
case 0x40: return saRel64Bytes;
case 0x80: return saRel128Bytes;
case 0x100: return saRelPage;
case 0x200: return saRel512Bytes;
case 0x400: return saRel2048Bytes;
case 0x1000: return saRel4K;
default: return saRelDble;
}
}
private:
void readHeader() {
//msg("Reading header.\n");
qlseek(m_reader, 0);
qlread(m_reader, &m_header, sizeof(m_header));
if (m_header.e_ident[EI_DATA] == ELFDATA2MSB) {
swap(m_header.e_type);
swap(m_header.e_machine);
swap(m_header.e_version);
swap(m_header.e_entry);
swap(m_header.e_phoff);
swap(m_header.e_shoff);
swap(m_header.e_flags);
swap(m_header.e_ehsize);
swap(m_header.e_phentsize);
swap(m_header.e_phnum);
swap(m_header.e_shentsize);
swap(m_header.e_shnum);
swap(m_header.e_shstrndx);
}
//printHeader();
}
void readSegments() {
if (m_header.e_phnum > 0) {
//msg("Reading segments.\n");
m_segments.resize(m_header.e_phnum);
qlseek(m_reader, m_header.e_phoff);
for (auto &segment : m_segments) {
qlread(m_reader, (typename Elf::Phdr *)&segment, m_header.e_phentsize);
if (m_header.e_ident[EI_DATA] == ELFDATA2MSB) {
swap(segment.p_type);
swap(segment.p_flags);
swap(segment.p_offset);
swap(segment.p_vaddr);
swap(segment.p_paddr);
swap(segment.p_filesz);
swap(segment.p_memsz);
swap(segment.p_align);
}
segment.setReader(m_reader);
}
//printSegments();
}
}
void readSections() {
if (m_header.e_shnum > 0) {
//msg("Reading sections...\n");
m_sections.resize(m_header.e_shnum);
size_t index = 0;
for (auto &section : m_sections) {
qlseek(m_reader, m_header.e_shoff + index * m_header.e_shentsize);
qlread(m_reader, (typename Elf::Shdr *)&section, m_header.e_shentsize);
if (m_header.e_ident[EI_DATA] == ELFDATA2MSB) {
swap(section.sh_name);
swap(section.sh_type);
swap(section.sh_flags);
swap(section.sh_addr);
swap(section.sh_offset);
swap(section.sh_size);
swap(section.sh_link);
swap(section.sh_info);
swap(section.sh_addralign);
swap(section.sh_entsize);
}
section.setReader(m_reader);
// only one symbol table per ELF
if (section.sh_type == SHT_SYMTAB)
m_symbolTableSection = &section;
++index;
}
if (m_header.e_shstrndx != SHN_UNDEF &&
m_sections[m_header.e_shstrndx].sh_type == SHT_STRTAB)
m_sectionStringTable = &m_sections[m_header.e_shstrndx];
//printSections();
}
}
void printHeader() {
msg("Elf Header:\n");
msg(" e_ident ");
for (int i = 0; i < EI_NIDENT; i++)
msg(" %02x", m_header.e_ident[i]);
msg("\n");
msg(" e_type %04x\n", m_header.e_type);
msg(" e_machine %04x\n", m_header.e_machine);
msg(" e_version %08x\n", m_header.e_version);
msg(" e_entry %08x\n", m_header.e_entry);
msg(" e_phoff %08x\n", m_header.e_phoff);
msg(" e_shoff %08x\n", m_header.e_shoff);
msg(" e_flags %08x\n", m_header.e_flags);
msg(" e_ehsize %d\n", m_header.e_ehsize);
msg(" e_phentsize %d\n", m_header.e_phentsize);
msg(" e_phnum %d\n", m_header.e_phnum);
msg(" e_shentsize %d\n", m_header.e_shentsize);
msg(" e_shnum %d\n", m_header.e_shnum);
msg(" e_shstrndx %d\n", m_header.e_shstrndx);
}
void printSegments() {
size_t index = 0;
for (auto &segment : m_segments) {
msg("Program Header #%d\n", index);
msg(" p_type %08x\n", segment.p_type);
msg(" p_offset %08x\n", segment.p_offset);
msg(" p_vaddr %08x\n", segment.p_vaddr);
msg(" p_paddr %08x\n", segment.p_paddr);
msg(" p_filesz %08x\n", segment.p_filesz);
msg(" p_memsz %08x\n", segment.p_memsz);
msg(" p_flags %08x\n", segment.p_flags);
msg(" p_align %08x\n", segment.p_align);
++index;
}
}
void printSections() {
size_t index = 0;
for (auto &section : m_sections) {
msg("Section Header #%d\n", index);
msg(" sh_name %08x\n", section.sh_name);
msg(" sh_type %08x\n", section.sh_type);
msg(" sh_addr %08x\n", section.sh_addr);
msg(" sh_offset %08x\n", section.sh_offset);
msg(" sh_size %08x\n", section.sh_size);
msg(" sh_link %08x\n", section.sh_link);
msg(" sh_info %08x\n", section.sh_info);
msg(" sh_addralign %08x\n", section.sh_addralign);
msg(" sh_entsize %08x\n", section.sh_entsize);
++index;
}
}
};

35
src/ps3/CMakeLists.txt Normal file
View File

@ -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}")

865
src/ps3/cell_loader.cpp Normal file
View File

@ -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);
}
}

61
src/ps3/cell_loader.h Normal file
View File

@ -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();
};

67
src/ps3/ps3.cpp Normal file
View File

@ -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
};

167
src/ps3/sce.h Normal file
View File

@ -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;

28
src/vita/CMakeLists.txt Normal file
View File

@ -0,0 +1,28 @@
cmake_minimum_required(VERSION 2.8)
project(vitaldr)
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
psp2_loader.cpp
psp2_loader.h
vita.cpp
sce.h
)
find_package(IDA)
include_directories(${IDA_INCLUDE_DIR})
include_directories(${IDA_SDK_PATH}/ldr)
include_directories(${ELF_COMMON_PATH})
add_definitions(${IDA_DEFINITIONS})
add_definitions(-DUSE_STANDARD_FILE_FUNCTIONS)
add_library(vitaldr SHARED ${SOURCES})
target_link_libraries(vitaldr ${IDA_LIBRARIES})
set_target_properties(vitaldr PROPERTIES OUTPUT_NAME "vita" PREFIX "" SUFFIX "${IDA_PLUGIN_EXT}")

926
src/vita/psp2_loader.cpp Normal file
View File

@ -0,0 +1,926 @@
#include "psp2_loader.h"
#include <struct.hpp>
#include <pro.h>
#include <string>
psp2_loader::psp2_loader(elf_reader<elf32> *elf, std::string databaseFile)
: m_elf(elf)
{
inf.demnames |= DEMNAM_GCC3; // assume gcc3 names
inf.af |= AF_PROCPTR; // Create function if data xref data->code32 exists
//inf.af |= AF_IMMOFF; // Convert 32bit instruction operand to offset
inf.af |= AF_DREFOFF; // Create offset if data xref to seg32 exists
inf.af2 |= AF2_DATOFF;
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());
m_database.open(databasePath);
if (m_database.is_open() == false)
loader_failure("Failed to open database file (%s).\n", databaseFile.c_str());
unsigned int nid;
std::string symbol;
while (m_database >> std::hex >> nid >> symbol) {
m_nidset.insert(std::pair<unsigned int, std::string>(nid, symbol));
}
}
void psp2_loader::apply() {
declareStructures();
applySegments();
if ( isLoadingPrx() )
applyRelocations();
applyModuleInfo();
applySymbols();
}
void psp2_loader::applySegments() {
if ( m_elf->getNumSections() > 0 )
applySectionHeaders();
else if ( m_elf->getNumSegments() > 0 )
applyProgramHeaders();
}
void psp2_loader::applySectionHeaders() {
auto &sections = m_elf->getSections();
const char *strTab = m_elf->getSectionStringTable()->data();
size_t index = 0;
for (const auto &section : sections) {
if (!(section.sh_flags & SHF_ALLOC) || // is not allocatable
section.sh_size == NULL || // has no data
section.sh_type == SHT_NULL) // skip unused entry
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 = "";
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 psp2_loader::applyProgramHeaders() {
auto &segments = m_elf->getSegments();
size_t index = 0;
for (const auto &segment : segments) {
if (segment.p_memsz == 0)
continue;
uchar perm = 0;
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),
(segment.p_filesz == 0) ? false : true);
++index;
}
}
void psp2_loader::applySegment(
uint32 sel,
uint64 offset,
uint64 addr,
uint64 size,
const char *name,
const char *sclass,
uchar perm,
uchar align,
bool load) {
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 psp2_loader::applyRelocations() {
auto &segments = m_elf->getSegments();
msg("Searching for relocation segments...\n");
for (auto &segment : segments) {
if (segment.p_type != PT_SCE_RELA)
continue;
//msg("This segment offset: %08x\n", segment.p_offset);
//msg("This segment filesz: %08x\n", segment.p_filesz);
auto nwords = segment.p_filesz / sizeof(Elf32_Word);
auto rel = reinterpret_cast<Elf32_Word *>(segment.data());
//msg("Relocation segment at offset %08x\n", segment.p_offset);
// initialized in format 1 and 2
uint32 g_addr = 0,
g_offset = 0,
g_patchseg = 0;
// initiliazed in format 0, 1, 2, and 3
uint32 g_saddr = 0,
g_addend = 0,
g_type = 0,
g_type2 = 0;
size_t index = 0;
for (size_t pos = 0; pos < nwords; ++pos) {
auto r_format = rel[pos] & 0xF;
//msg("Relocation %i\n", index);
//msg("r_format %i\n", r_format);
switch (r_format) {
case 0: {
//msg("%08x %08x %08x\n", rel[pos], rel[pos+1], rel[pos+2]);
auto r_symseg = (rel[pos] >> 4) & 0xF; // index into phdrs
g_type = (rel[pos] >> 8) & 0xFF; // relocation type
g_patchseg = (rel[pos] >> 16) & 0xF; // index into phdrs
g_type2 = (rel[pos] >> 20) & 0x7F; // second relocation
auto r_dist2 = (rel[pos] >> 27) & 0xF8; // distance from first offset
g_addend = (rel[pos+1]); // addend
g_offset = (rel[pos+2]); // first offset
// save these
g_addr = segments[g_patchseg].p_vaddr;
g_saddr = segments[r_symseg].p_vaddr;
/*msg(" r_symseg %i [%08x]\n", r_symseg, segments[r_symseg].p_vaddr);
msg(" r_type %i\n", g_type);
msg(" r_patchseg %i [%08x]\n", g_patchseg, segments[g_patchseg].p_vaddr);
msg(" r_type2 %i\n", g_type2);
msg(" r_dist2 %x\n", r_dist2);
msg(" r_addend %08x\n", g_addend);
msg(" r_offset %08x\n", g_offset);
msg(" relocation info[1]\n");
msg(" patch addr %08x\n", segments[g_patchseg].p_vaddr + g_offset);
msg(" sym addr %08x\n", segments[r_symseg].p_vaddr);
msg(" + addend %08x\n", g_addend);
if (g_type2) {
msg(" relocation info[2]\n");
msg(" patch addr %08x\n", segments[g_patchseg].p_vaddr + r_dist2 + g_offset);
msg(" sym addr %08x\n", segments[r_symseg].p_vaddr);
msg(" + addend %08x\n", g_addend);
}*/
pos += 2;
applyRelocation(g_type,
g_addr + g_offset,
g_saddr,
g_addend);
if (g_type2 != R_ARM_NONE) {
applyRelocation(g_type2,
g_addr + g_offset + r_dist2,
g_saddr,
g_addend);
}
break; // size = 12
}
case 1: {
//msg("%08x %08x\n", rel[pos], rel[pos + 1]);
auto r_symseg = (rel[pos] >> 4) & 0xF; // index into phdrs
g_type = (rel[pos] >> 8) & 0xFF; // relocation type
g_patchseg = (rel[pos] >> 16) & 0xF; // index into phdrs
g_offset = (rel[pos] >> 20) | // offset
((rel[pos+1] & 0x3FF) << 12);
g_addend = (rel[pos+1] >> 10); // addend
// save these
g_addr = segments[g_patchseg].p_vaddr;
g_saddr = segments[r_symseg].p_vaddr;
/*msg(" r_symseg %i [%08x]\n", r_symseg, segments[r_symseg].p_vaddr);
msg(" r_type %i\n", g_type);
msg(" r_patchseg %i [%08x]\n", g_patchseg, segments[g_patchseg].p_vaddr);
msg(" r_offset %08x\n", g_offset);
msg(" r_addend %08x\n", g_addend);
msg(" relocation info [1]\n");
msg(" patch addr %08x\n", segments[g_patchseg].p_vaddr + g_offset);
msg(" sym addr %08x\n", segments[r_symseg].p_vaddr);
msg(" + addend %08x\n", g_addend);*/
applyRelocation(g_type,
g_addr + g_offset,
g_saddr,
g_addend);
g_type2 = 0;
pos += 1;
break; // size = 8
}
case 2: {
//msg("%08x %08x\n", rel[pos], rel[pos + 1]);
auto r_symseg = (rel[pos] >> 4) & 0xF;
g_type = (rel[pos] >> 8) & 0xFF;
auto r_offset = (rel[pos] >> 16);
g_addend = (rel[pos+1]);
g_offset += r_offset;
g_saddr = segments[r_symseg].p_vaddr;
/*msg(" r_symseg %i [%08x]\n", r_symseg, segments[r_symseg].p_vaddr);
msg(" r_type %i\n", g_type);
msg(" r_offset %08x\n", r_offset);
msg(" r_addend %08x\n", g_addend);
msg(" relocation info [1]\n");
msg(" patch addr %08x + %08x\n", g_addr, r_offset);
msg(" sym addr %08x\n", segments[r_symseg].p_vaddr);
msg(" + addend %08x\n", g_addend);*/
applyRelocation(g_type,
g_addr + g_offset,
g_saddr,
g_addend);
g_type2 = 0;
pos += 1;
break; // size = 8
}
case 3: { // for THUMB/ARM MOVW/MOVT pairs
//msg("%08x %08x\n", rel[pos], rel[pos + 1]);
auto r_symseg = (rel[pos] >> 4) & 0xF;
auto r_mode = (rel[pos] >> 8) & 1; // 1 = THUMB, 0 = ARM
auto r_offset = (rel[pos] >> 9) & 0x3FFFF;
auto r_dist2 = (rel[pos] >> 27) & 0x1F;
g_addend = (rel[pos+1]);
// if r_mode rtype1 = R_ARM_THM_MOVW_ABS_NC <- THUMB
// else rtype1 = R_ARM_MOVW_ABS_NC <- ARM
// if r_mode rtype2 = R_ARM_THM_MOVT_ABS <- THUMB
// else rtype2 = R_ARM_MOVT_ABS <- ARM
// offset = prevoffset + r_offset
// offset2 = offset + r_offset2
/*msg(" r_symseg %i\n", r_symseg);
msg(" r_mode %i\n", r_mode);
msg(" r_offset %08x\n", r_offset);
msg(" r_dist2 %08x\n", r_dist2);
msg(" r_addend %08x\n", g_addend);*/
if (r_mode == 1)
g_type = R_ARM_THM_MOVW_ABS_NC;
else if (r_mode == 0)
g_type = R_ARM_MOVW_ABS_NC;
if (r_mode == 1)
g_type2 = R_ARM_THM_MOVT_ABS;
else if (r_mode == 0)
g_type2 = R_ARM_MOVT_ABS;
g_offset += r_offset;
g_saddr = segments[r_symseg].p_vaddr;
/*msg(" relocation info [1]\n");
msg(" r_type %i\n", g_type);
msg(" patch addr %08x + %08x\n", g_addr, g_offset);
msg(" sym addr %08x\n", segments[r_symseg].p_vaddr);
msg(" + addend %08x\n", g_addend);
msg(" relocation info [2]\n");
msg(" r_type2 %i\n", g_type2);
msg(" patch addr %08x + %08x + %08x\n", g_addr, g_offset, r_dist2);
msg(" sym addr %08x\n", segments[r_symseg].p_vaddr);
msg(" + addend %08x\n", g_addend);*/
applyRelocation(g_type,
g_addr + g_offset,
g_saddr,
g_addend);
applyRelocation(g_type2,
g_addr + g_offset + r_dist2,
g_saddr,
g_addend);
pos += 1;
break; // size = 8
}
case 4: {
//msg("%08x\n", rel[pos]);
auto r_offset = (rel[pos] >> 4) & 0x7FFFFF;
auto r_dist2 = (rel[pos] >> 27) & 0x1F;
// offset = prevoffset + r_offset
// offset2 = r_offset +
// uses previous rtype1 and rtype2
/*msg(" r_offset %08x\n", r_offset);
msg(" r_dist2 %08x\n", r_dist2);*/
g_offset += r_offset;
/*msg(" relocation info [1]\n");
msg(" r_type %i\n", g_type);
msg(" patch addr %08x + %08x\n", g_addr, g_offset);
msg(" sym addr %08x\n", g_saddr);
msg(" + addend %08x\n", g_addend);
msg(" relocation info [2]\n");
msg(" r_type2 %i\n", g_type2);
msg(" patch addr %08x + %08x + %08x\n", g_addr, g_offset, r_dist2);
msg(" sym addr %08x\n", g_saddr);
msg(" + addend %08x\n", g_addend);*/
applyRelocation(g_type,
g_addr + g_offset,
g_saddr,
g_addend);
applyRelocation(g_type2,
g_addr + g_offset + r_dist2,
g_saddr,
g_addend);
pos += 0; break; // size = 4
}
case 5: {
//msg("%08x\n", rel[pos]);
auto r_dist_1 = (rel[pos] >> 4) & 0x1FF;
auto r_dist_2 = (rel[pos] >> 13) & 0x1F;
auto r_dist_3 = (rel[pos] >> 18) & 0x1FF;
auto r_dist_4 = (rel[pos] >> 27) & 0x1F;
/*msg("r_dist_1 %08x\n", r_dist_2);
msg("r_dist_2 %08x\n", r_dist_2);
msg("r_dist_3 %08x\n", r_dist_3);
msg("r_dist_4 %08x\n", r_dist_4);
msg(" relocation info [1]\n");
msg(" r_type %i\n", g_type);
msg(" patch addr %08x + %08x\n", g_addr, g_offset + r_dist_1);
msg(" sym addr %08x\n", g_saddr);
msg(" + addend %08x\n", g_addend);
msg(" relocation info [2]\n");
msg(" r_type2 %i\n", g_type2);
msg(" patch addr %08x + %08x + %08x\n", g_addr, g_offset, r_dist_2);
msg(" sym addr %08x\n", g_saddr);
msg(" + addend %08x\n", g_addend);*/
applyRelocation(g_type,
g_addr + g_offset + r_dist_1,
g_saddr,
g_addend);
applyRelocation(g_type2,
g_addr + g_offset + r_dist_2,
g_saddr,
g_addend);
g_offset += r_dist_1 + r_dist_3;
/*msg(" relocation info [3]\n");
msg(" r_type %i\n", g_type);
msg(" patch addr %08x + %08x\n", g_addr, g_offset + r_dist_3);
msg(" sym addr %08x\n", g_saddr);
msg(" + addend %08x\n", g_addend);
msg(" relocation info [4]\n");
msg(" r_type2 %i\n", g_type2);
msg(" patch addr %08x + %08x + %08x\n", g_addr, g_offset, r_dist_4);
msg(" sym addr %08x\n", g_saddr);
msg(" + addend %08x\n", g_addend);*/
applyRelocation(g_type,
g_addr + g_offset,
g_saddr,
g_addend);
applyRelocation(g_type2,
g_addr + g_offset + r_dist_4,
g_saddr,
g_addend);
pos += 0; break; // size = 4
}
case 6: {
//msg("%08x\n", rel[pos]);
auto r_offset = (rel[pos] >> 4);
//msg(" r_offset %08x\n", r_offset);
g_offset += r_offset;
// assumes value is already stored
auto orgval = get_original_long(segments[g_patchseg].p_vaddr + g_offset);
uint32 segbase = 0;
for (auto seg : m_elf->getSegments()) {
if (orgval >= seg.p_vaddr &&
orgval < seg.p_vaddr + seg.p_filesz) {
segbase = seg.p_vaddr;
}
}
auto r_addend = orgval - segbase;
g_saddr = segbase; //+ m_relocAddr;
/*msg(" relocation info [1]\n");
msg(" r_patchseg %i [%08x]\n", g_patchseg, segments[g_patchseg].p_vaddr);
msg(" patch addr %08x + %08x\n", g_addr, g_offset);
msg(" sym addr %08x\n", g_saddr + r_addend);*/
g_type2 = 0;
g_type = R_ARM_ABS32;
applyRelocation(g_type,
g_addr + g_offset,
g_saddr,
r_addend);
pos += 0; break; // size = 4
}
case 7: // 7 bit offsets
case 8: // 4 bit offsets
case 9: { // 2 bit offsets
//msg("%08x\n", rel[pos]);
auto r_offsets = (rel[pos] >> 4);
//msg("r_offsets %08x\n", r_offsets);
uint32 bitsize;
uint32 mask;
switch (r_format) {
case 7: bitsize = 7; mask = 0x7F; break;
case 8: bitsize = 4; mask = 0x0F; break;
case 9: bitsize = 2; mask = 0x03; break;
}
do {
auto offset = (r_offsets & mask) * sizeof(uint32);
g_offset += offset;
auto orgval = get_original_long(segments[g_patchseg].p_vaddr + g_offset);
uint32 segbase = 0;
for (auto seg : m_elf->getSegments()) {
if (orgval >= seg.p_vaddr &&
orgval < seg.p_vaddr + seg.p_filesz) {
segbase = seg.p_vaddr;
}
}
auto r_addend = orgval - segbase;
g_saddr = segbase;// + m_relocAddr;
/*msg(" relocation info [1]\n");
msg(" offset %08x\n", offset);
msg(" r_patchseg %i [%08x]\n", g_patchseg, segments[g_patchseg].p_vaddr);
msg(" patch addr %08x + %08x\n", g_addr, g_offset);
msg(" sym addr %08x\n", g_saddr);
msg(" + addend %08x\n", r_addend);*/
//doDwrd(g_addr + g_offset, 4);
g_type2 = 0;
g_type = R_ARM_ABS32;
applyRelocation(g_type,
g_addr + g_offset,
g_saddr,
r_addend);
} while (r_offsets >>= bitsize);
pos += 0; break;
}
default:
msg("Invalid r_format %i at offset %x!n", r_format, pos * 4);
break;
}
++index;
}
}
}
void psp2_loader::applyRelocation(uint32 type, uint32 addr, uint32 symval, uint32 addend) {
switch (type) {
case R_ARM_NONE:
case R_ARM_V4BX:
break;
case R_ARM_ABS32:
case R_ARM_TARGET1:
patch_long(addr, symval + addend);
break;
case R_ARM_REL32:
case R_ARM_TARGET2:
patch_long(addr, symval - addr + addend);
break;
default:
msg("Unsupported relocation type (%i)!\n", type);
}
}
void psp2_loader::applyModuleInfo() {
auto firstSegment = m_elf->getSegments()[0].p_vaddr;
auto modInfoAddr = m_elf->entry() + firstSegment;
tid_t tid = get_struc_id("_scemoduleinfo");
doStruct(modInfoAddr, sizeof(_scemoduleinfo_prx2arm), tid);
auto entTop = get_long(modInfoAddr + offsetof(_scemoduleinfo_prx2arm, ent_top));
auto entEnd = get_long(modInfoAddr + offsetof(_scemoduleinfo_prx2arm, ent_end));
loadExports( firstSegment + entTop, firstSegment + entEnd );
auto stubTop = get_long(modInfoAddr + offsetof(_scemoduleinfo_prx2arm, stub_top));
auto stubEnd = get_long(modInfoAddr + offsetof(_scemoduleinfo_prx2arm, stub_end));
loadImports( firstSegment + stubTop, firstSegment + stubEnd );
}
void psp2_loader::loadExports(uint32 entTop, uint32 entEnd) {
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;
if (structsize == sizeof(_scelibent_prx2arm)) {
doStruct(ea, sizeof(_scelibent_prx2arm), get_struc_id("_scelibent"));
auto nidtable = get_long(ea + offsetof(_scelibent_prx2arm, nidtable));
auto addtable = get_long(ea + offsetof(_scelibent_prx2arm, addtable));
if (nidtable != NULL && addtable != NULL) {
for (size_t i = 0; i < count; i++) {
auto nidoffset = nidtable + (i * 4);
auto addoffset = addtable + (i * 4);
auto nid = get_long(nidoffset);
auto add = get_long(addoffset);
auto resolvedNid = getNameFromDatabase(nid);
if (resolvedNid) {
set_cmt(nidoffset, resolvedNid, false);
if (add & 1)
add -= 1;
do_name_anyway(add, resolvedNid);
}
if (i < nfunc)
auto_make_proc(add);
doDwrd(nidoffset, 4);
doDwrd(addoffset, 4);
}
}
} else {
msg("Unknown export structure at %08x\n", ea);
}
}
}
void psp2_loader::loadImports(uint32 stubTop, uint32 stubEnd) {
uchar structsize;
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));
if (structsize == sizeof(_scelibstub_prx2arm)) {
doStruct(ea, sizeof(_scelibstub_prx2arm), get_struc_id("_scelibstub"));
auto funcnidtable = get_long(ea + offsetof(_scelibstub_prx2arm, func_nidtable));
auto functable = get_long(ea + offsetof(_scelibstub_prx2arm, func_table));
auto varnidtable = get_long(ea + offsetof(_scelibstub_prx2arm, var_nidtable));
auto vartable = get_long(ea + offsetof(_scelibstub_prx2arm, var_table));
auto tlsnidtable = get_long(ea + offsetof(_scelibstub_prx2arm, tls_nidtable));
auto tlstable = get_long(ea + offsetof(_scelibstub_prx2arm, tls_table));
if (funcnidtable != NULL && functable != NULL) {
for (size_t i = 0; i < nfunc; ++i) {
auto nidoffset = funcnidtable + (i * 4);
auto funcoffset = functable + (i * 4);
auto nid = get_long(nidoffset);
auto func = get_long(funcoffset);
auto resolvedNid = getNameFromDatabase(nid);
if (resolvedNid) {
set_cmt(nidoffset, resolvedNid, false);
if (func & 1)
func -= 1;
do_name_anyway(func, resolvedNid);
}
doDwrd(nidoffset, 4);
doDwrd(funcoffset, 4);
if (add_func(func, BADADDR)) {
get_func(func)->flags |= FUNC_LIB;
}
}
}
if (varnidtable != NULL && vartable != NULL) {
for (size_t i = 0; i < nvar; ++i) {
auto nidoffset = varnidtable + (i * 4);
auto varoffset = vartable + (i * 4);
auto nid = get_long(nidoffset);
auto var = get_long(varoffset);
doDwrd(nidoffset, 4);
doDwrd(varoffset, 4);
}
}
if (tlsnidtable != NULL && tlstable != NULL) {
for (size_t i = 0; i < nvar; ++i) {
auto nidoffset = tlsnidtable + (i * 4);
auto tlsoffset = tlstable + (i * 4);
auto nid = get_long(nidoffset);
auto tls = get_long(tlsoffset);
doDwrd(nidoffset, 4);
doDwrd(tlsoffset, 4);
}
}
} else if (structsize == 0x24) {
doByte(ea+0, 1); // structsize
doByte(ea+1, 1); // auxattribute
doWord(ea+2, 2); // version
doWord(ea+4, 2); // attribute
doWord(ea+6, 2); // nfunc
doWord(ea+8, 2); // nvar
doWord(ea+10, 2); // reserved?
doDwrd(ea+12, 4); // libname_nid
doDwrd(ea+16, 4); // libname
doDwrd(ea+20, 4); // funcnidtable
doDwrd(ea+24, 4); // functable
doDwrd(ea+28, 4); // varnidtable
doDwrd(ea+32, 4); // vartable
auto funcnidtable = get_long(ea + 0x14);
auto functable = get_long(ea + 0x18);
auto varnidtable = get_long(ea + 0x1C);
auto vartable = get_long(ea + 0x20);
if (funcnidtable != NULL && functable != NULL) {
for (size_t i = 0; i < nfunc; ++i) {
auto nidoffset = funcnidtable + (i * 4);
auto funcoffset = functable + (i * 4);
auto nid = get_long(nidoffset);
auto func = get_long(funcoffset);
auto resolvedNid = getNameFromDatabase(nid);
if (resolvedNid) {
set_cmt(nidoffset, resolvedNid, false);
if (func & 1)
func -= 1;
do_name_anyway(func, resolvedNid);
}
doDwrd(nidoffset, 4);
doDwrd(funcoffset, 4);
if (add_func(func, BADADDR)) {
get_func(func)->flags |= FUNC_LIB;
}
}
}
if (varnidtable != NULL && vartable != NULL) {
for (size_t i = 0; i < nvar; ++i) {
auto nidoffset = varnidtable + (i * 4);
auto varoffset = vartable + (i * 4);
auto nid = get_long(nidoffset);
auto var = get_long(varoffset);
doDwrd(nidoffset, 4);
doDwrd(varoffset, 4);
}
}
} else {
msg("Unknown import structure at %08x\n", ea);
}
}
}
const char *psp2_loader::getNameFromDatabase(unsigned int nid) {
auto value = m_nidset.find(nid);
if (value != m_nidset.end())
return value->second.c_str();
return nullptr;
}
void psp2_loader::applySymbols() {
msg("Applying symbols...\n");
auto section = m_elf->getSymbolsSection();
if (section == NULL)
return;
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;
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;
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 psp2_loader::declareStructures() {
struc_t *sptr;
tid_t modInfoCommon = add_struc(-1, "_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(-1, "_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, "resreve", BADADDR, dwrdflag(), NULL, 4);
add_struc_member(sptr, "ent_top", BADADDR, dwrdflag(), NULL, 4);
add_struc_member(sptr, "ent_end", BADADDR, dwrdflag(), NULL, 4);
add_struc_member(sptr, "stub_top", BADADDR, dwrdflag(), NULL, 4);
add_struc_member(sptr, "stub_end", BADADDR, dwrdflag(), NULL, 4);
add_struc_member(sptr, "dbg_fingerprint", BADADDR, dwrdflag(), NULL, 4);
add_struc_member(sptr, "tls_top", BADADDR, dwrdflag(), NULL, 4);
add_struc_member(sptr, "tls_filesz", BADADDR, dwrdflag(), NULL, 4);
add_struc_member(sptr, "tls_memsz", BADADDR, dwrdflag(), NULL, 4);
add_struc_member(sptr, "start_entry", BADADDR, dwrdflag(), NULL, 4);
add_struc_member(sptr, "stop_entry", BADADDR, dwrdflag(), NULL, 4);
add_struc_member(sptr, "arm_exidx_top", BADADDR, dwrdflag(), NULL, 4);
add_struc_member(sptr, "arm_exidx_end", BADADDR, dwrdflag(), NULL, 4);
add_struc_member(sptr, "arm_extab_top", BADADDR, dwrdflag(), NULL, 4);
add_struc_member(sptr, "arm_extab_end", BADADDR, dwrdflag(), NULL, 4);
}
}
tid_t libStubCommon = add_struc(-1, "_scelibstub_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(-1, "_scelibstub"));
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_nid", BADADDR, dwrdflag(), NULL, 4);
add_struc_member(sptr, "libname", BADADDR, dwrdflag(), NULL, 4);
add_struc_member(sptr, "sce_sdk_version", BADADDR, dwrdflag(), NULL, 4);
add_struc_member(sptr, "func_nidtable", BADADDR, dwrdflag(), NULL, 4);
add_struc_member(sptr, "func_table", BADADDR, dwrdflag(), NULL, 4);
add_struc_member(sptr, "var_nidtable", BADADDR, dwrdflag(), NULL, 4);
add_struc_member(sptr, "var_table", BADADDR, dwrdflag(), NULL, 4);
add_struc_member(sptr, "tls_nidtable", BADADDR, dwrdflag(), NULL, 4);
add_struc_member(sptr, "tls_table", BADADDR, dwrdflag(), NULL, 4);
}
}
tid_t libEntCommon = add_struc(-1, "_scelibent_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(-1, "_scelibent"));
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_nid", BADADDR, dwrdflag(), NULL, 4);
add_struc_member(sptr, "libname", BADADDR, dwrdflag(), NULL, 4);
add_struc_member(sptr, "nidtable", BADADDR, dwrdflag(), NULL, 4);
add_struc_member(sptr, "addtable", BADADDR, dwrdflag(), NULL, 4);
}
}
}

54
src/vita/psp2_loader.h Normal file
View File

@ -0,0 +1,54 @@
#pragma once
#include "elf_reader.h"
#include "sce.h"
#include <fstream>
#include <array>
#include <map>
class psp2_loader
{
elf_reader<elf32> *m_elf;
uint64 m_relocAddr;
std::ifstream m_database;
std::map<uint32, std::string> m_nidset;
public:
psp2_loader(elf_reader<elf32> *elf, std::string databaseFile);
void apply();
bool isLoadingPrx() const
{ return m_elf->type() == ET_SCE_RELEXEC; }
bool isLoadingExec() const
{ return m_elf->type() == ET_EXEC; }
private:
void declareStructures();
void applySegments();
void applySectionHeaders();
void applyProgramHeaders();
void applySegment(
uint32 sel, uint64 offset,
uint64 addr, uint64 size,
const char *name, const char *sclass,
uchar perm, uchar align,
bool load = true
);
void applyRelocations();
void applyRelocation(uint32 type, uint32 addr, uint32 addend, uint32 value);
void applyModuleInfo();
void loadExports(uint32 entTop, uint32 entEnd);
void loadImports(uint32 stubTop, uint32 stubEnd);
const char *getNameFromDatabase(unsigned int nid);
void applySymbols();
};

110
src/vita/sce.h Normal file
View File

@ -0,0 +1,110 @@
#pragma once
#include "elf.h"
#define ET_SCE_EXEC 0xfe00
#define ET_SCE_RELEXEC 0xfe04 /* PRX */
#define ET_SCE_ARMRELEXEC 0xffa5
#define SHT_SCE_ARMRELA 0x700000a4
#define PT_SCE_RELA 0x60000000
#define PT_SCE_COMMENT 0x6fffff00
#define PT_SCE_VERSION 0x6fffff01
#define PT_SCE_ARMRELA 0x700000A4
#define PT_SCE_SEGSYM 0x700000A8
#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_prx2arm {
sceModuleInfo_common c;
Elf32_Addr resreve;
Elf32_Addr ent_top;
Elf32_Addr ent_end;
Elf32_Addr stub_top;
Elf32_Addr stub_end;
Elf32_Word dbg_fingerprint;
Elf32_Addr tls_top;
Elf32_Addr tls_filesz;
Elf32_Addr tls_memsz;
Elf32_Addr start_entry;
Elf32_Addr stop_entry;
Elf32_Addr arm_exidx_top;
Elf32_Addr arm_exidx_end;
Elf32_Addr arm_extab_top;
Elf32_Addr arm_extab_end;
} sceModuleInfo_prx2arm;
/* 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_prx2_common;
typedef struct _scelibstub_prx2arm {
sceKernelLibraryStubTable_prx2_common c;
Elf32_Word libname_nid;
Elf32_Addr libname;
Elf32_Word sce_sdk_version;
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_prx2arm;
/* 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_prx2_common;
typedef struct _scelibent_prx2arm {
sceKernelLibraryEntryTable_prx2_common c;
Elf32_Word libname_nid;
Elf32_Addr libname;
Elf32_Addr nidtable;
Elf32_Addr addtable;
} sceKernelLibraryEntryTable_prx2arm;

55
src/vita/vita.cpp Normal file
View File

@ -0,0 +1,55 @@
#include "../elf_common/elf_reader.h"
#include "psp2_loader.h"
#include "sce.h"
#include <idaldr.h>
#include <memory>
static int idaapi
accept_file(linput_t *li, char fileformatname[MAX_FILE_FORMAT_NAME], int n)
{
if (n > 0)
return 0;
elf_reader<elf32> elf(li);
if (elf.verifyHeader() &&
elf.machine() == EM_ARM) {
const char *type;
if (elf.type() == ET_SCE_EXEC)
type = "Executable";
else if (elf.type() == ET_SCE_RELEXEC)
type = "Relocatable Executable";
else
return 0;
set_processor_type("ARM", SETPROC_ALL);
qsnprintf(fileformatname, MAX_FILE_FORMAT_NAME, "Playstation Vita %s", type);
return ACCEPT_FIRST | 1;
}
return 0;
}
static void idaapi
load_file(linput_t *li, ushort neflags, const char *fileformatname)
{
elf_reader<elf32> elf(li); elf.read();
psp2_loader ldr(&elf, "vita.txt"); ldr.apply();
}
__declspec(dllexport)
loader_t LDSC =
{
IDP_INTERFACE_VERSION,
0,
accept_file,
load_file,
NULL,
NULL,
NULL
};

1
third_party/tinyxml vendored Submodule

@ -0,0 +1 @@
Subproject commit b3e5aabf9c0272fdfd05487b5ea12eaf4522713d