mirror of
https://github.com/wiiu-env/WiiUPluginSystem.git
synced 2026-09-27 11:26:42 -05:00
Replaced all instances of the word "module" with "plugin"
This commit is contained in:
428
loader/src/plugin/ElfTools.cpp
Normal file
428
loader/src/plugin/ElfTools.cpp
Normal file
@@ -0,0 +1,428 @@
|
||||
/* based on module.c
|
||||
* by Alex Chadwick
|
||||
*
|
||||
* Copyright (C) 2014, Alex Chadwick
|
||||
* Modified 2018, Maschell
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "ElfTools.h"
|
||||
#include <string.h>
|
||||
#include <malloc.h>
|
||||
#include <libelf.h>
|
||||
#include <utils/logger.h>
|
||||
|
||||
bool ElfTools::elfLoadSection(const Elf *elf, Elf_Scn *scn, const Elf32_Shdr *shdr,void *destination) {
|
||||
if (destination == NULL) { return false; }
|
||||
|
||||
switch (shdr->sh_type) {
|
||||
case SHT_SYMTAB:
|
||||
case SHT_PROGBITS: {
|
||||
Elf_Data *data;
|
||||
size_t n;
|
||||
|
||||
n = 0;
|
||||
for (data = elf_getdata(scn, NULL); data != NULL; data = elf_getdata(scn, data)) {
|
||||
memcpy((char *)destination + n, data->d_buf, data->d_size);
|
||||
n += data->d_size;
|
||||
}
|
||||
return true;
|
||||
} case SHT_NOBITS: {
|
||||
memset(destination, 0, shdr->sh_size);
|
||||
return true;
|
||||
} default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool ElfTools::loadElfSymtab(Elf *elf, Elf32_Sym **symtab, size_t *symtab_count, size_t *symtab_strndx) {
|
||||
Elf_Scn *scn;
|
||||
bool result = false;
|
||||
|
||||
for (scn = elf_nextscn(elf, NULL); scn != NULL; scn = elf_nextscn(elf, scn)) {
|
||||
|
||||
Elf32_Shdr *shdr;
|
||||
|
||||
shdr = elf32_getshdr(scn);
|
||||
if (shdr == NULL){
|
||||
continue;
|
||||
}
|
||||
|
||||
if (shdr->sh_type == SHT_SYMTAB) {
|
||||
size_t sym;
|
||||
|
||||
if (*symtab != NULL){
|
||||
continue;
|
||||
}
|
||||
|
||||
*symtab = (Elf32_Sym *)malloc(shdr->sh_size);
|
||||
if (*symtab == NULL){
|
||||
continue;
|
||||
}
|
||||
|
||||
*symtab_count = shdr->sh_size / sizeof(Elf32_Sym);
|
||||
*symtab_strndx = shdr->sh_link;
|
||||
|
||||
if (!elfLoadSection(elf, scn, shdr, *symtab)){
|
||||
goto exit_error;
|
||||
}
|
||||
|
||||
for (sym = 0; sym < *symtab_count; sym++){
|
||||
(*symtab)[sym].st_other = 0;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (*symtab == NULL){
|
||||
goto exit_error;
|
||||
}
|
||||
|
||||
result = true;
|
||||
exit_error:
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
void ElfTools::elfLoadSymbols(size_t shndx, const void *destination, Elf32_Sym *symtab, size_t symtab_count) {
|
||||
size_t i;
|
||||
|
||||
/* use the st_other field (no defined meaning) to indicate whether or not a
|
||||
* symbol address has been calculated. */
|
||||
for (i = 0; i < symtab_count; i++) {
|
||||
if (symtab[i].st_shndx == shndx &&
|
||||
symtab[i].st_other == 0) {
|
||||
|
||||
symtab[i].st_value += (Elf32_Addr)destination;
|
||||
symtab[i].st_other = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool ElfTools::elfLink(Elf *elf, size_t shndx, void *destination, Elf32_Sym *symtab, size_t symtab_count, size_t symtab_strndx, bool allow_globals) {
|
||||
Elf_Scn *scn;
|
||||
|
||||
for (scn = elf_nextscn(elf, NULL); scn != NULL; scn = elf_nextscn(elf, scn)) {
|
||||
Elf32_Shdr *shdr;
|
||||
|
||||
shdr = elf32_getshdr(scn);
|
||||
if (shdr == NULL)
|
||||
continue;
|
||||
|
||||
switch (shdr->sh_type) {
|
||||
case SHT_REL: {
|
||||
const Elf32_Rel *rel;
|
||||
Elf_Data *data;
|
||||
size_t i;
|
||||
|
||||
if (shdr->sh_info != shndx){
|
||||
continue;
|
||||
}
|
||||
|
||||
data = elf_getdata(scn, NULL);
|
||||
if (data == NULL){
|
||||
continue;
|
||||
}
|
||||
|
||||
rel = (const Elf32_Rel *) data->d_buf;
|
||||
|
||||
for (i = 0; i < shdr->sh_size / sizeof(Elf32_Rel); i++) {
|
||||
uint32_t symbol_addr;
|
||||
size_t symbol;
|
||||
|
||||
symbol = ELF32_R_SYM(rel[i].r_info);
|
||||
|
||||
if (symbol > symtab_count)
|
||||
return false;
|
||||
|
||||
switch (symtab[symbol].st_shndx) {
|
||||
case SHN_ABS: {
|
||||
symbol_addr = symtab[symbol].st_value;
|
||||
break;
|
||||
} case SHN_COMMON: {
|
||||
return false;
|
||||
} case SHN_UNDEF: {
|
||||
|
||||
if (allow_globals) {
|
||||
DEBUG_FUNCTION_LINE("The elf still have unresolved relocations. This is not supported.");
|
||||
/*
|
||||
Not support and not needed.
|
||||
|
||||
module_unresolved_relocation_t *reloc;
|
||||
char *name;
|
||||
|
||||
reloc = (module_unresolved_relocation_t *) Module_ListAllocate(
|
||||
&module_relocations,
|
||||
sizeof(module_unresolved_relocation_t), 1,
|
||||
&module_relocations_capacity,
|
||||
&module_relocations_count,
|
||||
PLUGIN_RELOCATIONS_CAPCITY_DEFAULT);
|
||||
if (reloc == NULL)
|
||||
return false;
|
||||
|
||||
name = elf_strptr(
|
||||
elf, symtab_strndx, symtab[symbol].st_name);
|
||||
|
||||
if (name == NULL) {
|
||||
module_relocations_count--;
|
||||
return false;
|
||||
}
|
||||
|
||||
reloc->name = strdup(name);
|
||||
if (reloc->name == NULL) {
|
||||
module_relocations_count--;
|
||||
return false;
|
||||
}
|
||||
|
||||
reloc->module = index;
|
||||
reloc->address = destination;
|
||||
reloc->offset = rel[i].r_offset;
|
||||
reloc->type = ELF32_R_TYPE(rel[i].r_info);
|
||||
reloc->addend = *(int *)((char *)destination + rel[i].r_offset);
|
||||
|
||||
continue;
|
||||
*/
|
||||
return false;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} default: {
|
||||
if (symtab[symbol].st_other != 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
symbol_addr = symtab[symbol].st_value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ElfTools::elfLinkOne(ELF32_R_TYPE(rel[i].r_info), rel[i].r_offset, *(int *)((char *)destination + rel[i].r_offset), destination, symbol_addr)){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
} case SHT_RELA: {
|
||||
const Elf32_Rela *rela;
|
||||
Elf_Data *data;
|
||||
size_t i;
|
||||
|
||||
if (shdr->sh_info != shndx)
|
||||
continue;
|
||||
|
||||
data = elf_getdata(scn, NULL);
|
||||
if (data == NULL)
|
||||
continue;
|
||||
|
||||
rela = (const Elf32_Rela *) data->d_buf;
|
||||
|
||||
for (i = 0; i < shdr->sh_size / sizeof(Elf32_Rela); i++) {
|
||||
uint32_t symbol_addr;
|
||||
size_t symbol;
|
||||
|
||||
symbol = ELF32_R_SYM(rela[i].r_info);
|
||||
|
||||
if (symbol > symtab_count)
|
||||
return false;
|
||||
|
||||
switch (symtab[symbol].st_shndx) {
|
||||
case SHN_ABS: {
|
||||
symbol_addr = symtab[symbol].st_value;
|
||||
break;
|
||||
} case SHN_COMMON: {
|
||||
return false;
|
||||
} case SHN_UNDEF: {
|
||||
if (allow_globals) {
|
||||
DEBUG_FUNCTION_LINE("The elf still have unresolved relocations. This is not supported.");
|
||||
/*
|
||||
Not support and not needed.
|
||||
module_unresolved_relocation_t *reloc;
|
||||
char *name;
|
||||
|
||||
reloc = (module_unresolved_relocation_t *) Module_ListAllocate(
|
||||
&module_relocations,
|
||||
sizeof(module_unresolved_relocation_t), 1,
|
||||
&module_relocations_capacity,
|
||||
&module_relocations_count,
|
||||
PLUGIN_RELOCATIONS_CAPCITY_DEFAULT);
|
||||
if (reloc == NULL)
|
||||
return false;
|
||||
|
||||
name = elf_strptr(
|
||||
elf, symtab_strndx, symtab[symbol].st_name);
|
||||
|
||||
if (name == NULL) {
|
||||
module_relocations_count--;
|
||||
return false;
|
||||
}
|
||||
|
||||
reloc->name = strdup(name);
|
||||
if (reloc->name == NULL) {
|
||||
module_relocations_count--;
|
||||
return false;
|
||||
}
|
||||
|
||||
DEBUG_FUNCTION_LINE("Adding relocation!\n");
|
||||
|
||||
reloc->module = index;
|
||||
reloc->address = destination;
|
||||
reloc->offset = rela[i].r_offset;
|
||||
reloc->type = ELF32_R_TYPE(rela[i].r_info);
|
||||
reloc->addend = rela[i].r_addend;
|
||||
|
||||
continue;*/
|
||||
return false;
|
||||
} else
|
||||
return false;
|
||||
} default: {
|
||||
|
||||
if (symtab[symbol].st_other != 1){
|
||||
return false;
|
||||
}
|
||||
symbol_addr = symtab[symbol].st_value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ElfTools::elfLinkOne(ELF32_R_TYPE(rela[i].r_info), rela[i].r_offset,rela[i].r_addend, destination, symbol_addr)){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ElfTools::elfLinkOne(char type, size_t offset, int addend, void *destination, uint32_t symbol_addr) {
|
||||
int value;
|
||||
char *target = (char *)destination + offset;
|
||||
bool result = false;
|
||||
|
||||
switch (type) {
|
||||
case R_PPC_ADDR32:
|
||||
case R_PPC_ADDR24:
|
||||
case R_PPC_ADDR16:
|
||||
case R_PPC_ADDR16_HI:
|
||||
case R_PPC_ADDR16_HA:
|
||||
case R_PPC_ADDR16_LO:
|
||||
case R_PPC_ADDR14:
|
||||
case R_PPC_ADDR14_BRTAKEN:
|
||||
case R_PPC_ADDR14_BRNTAKEN:
|
||||
case R_PPC_UADDR32:
|
||||
case R_PPC_UADDR16: {
|
||||
value = (int)symbol_addr + addend;
|
||||
break;
|
||||
} case R_PPC_REL24:
|
||||
case R_PPC_PLTREL24:
|
||||
case R_PPC_LOCAL24PC:
|
||||
case R_PPC_REL14:
|
||||
case R_PPC_REL14_BRTAKEN:
|
||||
case R_PPC_REL14_BRNTAKEN:
|
||||
case R_PPC_REL32:
|
||||
case R_PPC_ADDR30: {
|
||||
value = (int)symbol_addr + addend - (int)target;
|
||||
break;
|
||||
} case R_PPC_SECTOFF:
|
||||
case R_PPC_SECTOFF_LO:
|
||||
case R_PPC_SECTOFF_HI:
|
||||
case R_PPC_SECTOFF_HA: {
|
||||
value = offset + addend;
|
||||
break;
|
||||
} case R_PPC_EMB_NADDR32:
|
||||
case R_PPC_EMB_NADDR16:
|
||||
case R_PPC_EMB_NADDR16_LO:
|
||||
case R_PPC_EMB_NADDR16_HI:
|
||||
case R_PPC_EMB_NADDR16_HA: {
|
||||
value = addend - (int)symbol_addr;
|
||||
break;
|
||||
} default:
|
||||
DEBUG_FUNCTION_LINE("Unknown relocation type: %02X\n",type);
|
||||
goto exit_error;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case R_PPC_ADDR32:
|
||||
case R_PPC_UADDR32:
|
||||
case R_PPC_REL32:
|
||||
case R_PPC_SECTOFF:
|
||||
case R_PPC_EMB_NADDR32: {
|
||||
*(int *)target = value;
|
||||
break;
|
||||
} case R_PPC_ADDR24:
|
||||
case R_PPC_PLTREL24:
|
||||
case R_PPC_LOCAL24PC:
|
||||
case R_PPC_REL24: {
|
||||
*(int *)target =
|
||||
(*(int *)target & 0xfc000003) | (value & 0x03fffffc);
|
||||
break;
|
||||
} case R_PPC_ADDR16:
|
||||
case R_PPC_UADDR16:
|
||||
case R_PPC_EMB_NADDR16: {
|
||||
*(short *)target = value;
|
||||
break;
|
||||
} case R_PPC_ADDR16_HI:
|
||||
case R_PPC_SECTOFF_HI:
|
||||
case R_PPC_EMB_NADDR16_HI: {
|
||||
*(short *)target = value >> 16;
|
||||
break;
|
||||
} case R_PPC_ADDR16_HA:
|
||||
case R_PPC_SECTOFF_HA:
|
||||
case R_PPC_EMB_NADDR16_HA: {
|
||||
*(short *)target = (value >> 16) + ((value >> 15) & 1);
|
||||
break;
|
||||
} case R_PPC_ADDR16_LO:
|
||||
case R_PPC_SECTOFF_LO:
|
||||
case R_PPC_EMB_NADDR16_LO: {
|
||||
*(short *)target = value & 0xffff;
|
||||
break;
|
||||
} case R_PPC_ADDR14:
|
||||
case R_PPC_REL14: {
|
||||
*(int *)target =
|
||||
(*(int *)target & 0xffff0003) | (value & 0x0000fffc);
|
||||
break;
|
||||
} case R_PPC_ADDR14_BRTAKEN:
|
||||
case R_PPC_REL14_BRTAKEN: {
|
||||
*(int *)target =
|
||||
(*(int *)target & 0xffdf0003) | (value & 0x0000fffc) |
|
||||
0x00200000;
|
||||
break;
|
||||
} case R_PPC_ADDR14_BRNTAKEN:
|
||||
case R_PPC_REL14_BRNTAKEN: {
|
||||
*(int *)target =
|
||||
(*(int *)target & 0xffdf0003) | (value & 0x0000fffc);
|
||||
break;
|
||||
} case R_PPC_ADDR30: {
|
||||
*(int *)target =
|
||||
(*(int *)target & 0x00000003) | (value & 0xfffffffc);
|
||||
break;
|
||||
}default:
|
||||
goto exit_error;
|
||||
}
|
||||
|
||||
result = true;
|
||||
exit_error:
|
||||
if (!result) DEBUG_FUNCTION_LINE("Plugin_ElfLinkOne: exit_error\n");
|
||||
return result;
|
||||
}
|
||||
|
||||
49
loader/src/plugin/ElfTools.h
Normal file
49
loader/src/plugin/ElfTools.h
Normal file
@@ -0,0 +1,49 @@
|
||||
/* based on module.c
|
||||
* by Alex Chadwick
|
||||
*
|
||||
* Copyright (C) 2014, Alex Chadwick
|
||||
* Modified 2018, Maschell
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef _ELF_TOOLS_H_
|
||||
#define _ELF_TOOLS_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <libelf.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
class ElfTools{
|
||||
|
||||
public:
|
||||
static bool elfLoadSection(const Elf *elf, Elf_Scn *scn, const Elf32_Shdr *shdr,void *destination);
|
||||
static bool loadElfSymtab(Elf *elf, Elf32_Sym **symtab, size_t *symtab_count, size_t *symtab_strndx);
|
||||
static void elfLoadSymbols(size_t shndx, const void *destination, Elf32_Sym *symtab, size_t symtab_count);
|
||||
static bool elfLink(Elf *elf, size_t shndx, void *destination, Elf32_Sym *symtab, size_t symtab_count, size_t symtab_strndx, bool allow_globals);
|
||||
static bool elfLinkOne(char type, size_t offset, int addend, void *destination, uint32_t symbol_addr);
|
||||
};
|
||||
|
||||
#endif
|
||||
62
loader/src/plugin/EntryData.h
Normal file
62
loader/src/plugin/EntryData.h
Normal file
@@ -0,0 +1,62 @@
|
||||
/****************************************************************************
|
||||
* Copyright (C) 2018 Maschell
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef _ENTRY_DATA_H_
|
||||
#define _ENTRY_DATA_H_
|
||||
|
||||
#include <wups.h>
|
||||
#include <string>
|
||||
|
||||
class EntryData{
|
||||
|
||||
public:
|
||||
EntryData(const char * name, wups_loader_library_type_t library, void * target, void * call_addr){
|
||||
this->name = name;
|
||||
this->library = library;
|
||||
this->replaceAddr = target;
|
||||
this->replaceCall = call_addr;
|
||||
}
|
||||
|
||||
~EntryData(){
|
||||
|
||||
}
|
||||
|
||||
std::string getName(){
|
||||
return this->name;
|
||||
}
|
||||
|
||||
wups_loader_library_type_t getLibrary(){
|
||||
return this->library;
|
||||
}
|
||||
|
||||
void * getReplaceAddress(){
|
||||
return replaceAddr;
|
||||
}
|
||||
|
||||
void * getReplaceCall(){
|
||||
return replaceCall;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string name;
|
||||
wups_loader_library_type_t library;
|
||||
void * replaceAddr = NULL;
|
||||
void * replaceCall = NULL;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
49
loader/src/plugin/HookData.h
Normal file
49
loader/src/plugin/HookData.h
Normal file
@@ -0,0 +1,49 @@
|
||||
/****************************************************************************
|
||||
* Copyright (C) 2018 Maschell
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef _HOOK_DATA_H_
|
||||
#define _HOOK_DATA_H_
|
||||
|
||||
#include <wups.h>
|
||||
#include <string>
|
||||
|
||||
class HookData{
|
||||
|
||||
public:
|
||||
HookData(void * function_pointer, wups_loader_hook_type_t type){
|
||||
this->function_pointer = function_pointer;
|
||||
this->type = type;
|
||||
}
|
||||
|
||||
~HookData(){
|
||||
|
||||
}
|
||||
|
||||
void * getFunctionPointer(){
|
||||
return function_pointer;
|
||||
}
|
||||
|
||||
wups_loader_hook_type_t getType(){
|
||||
return this->type;
|
||||
}
|
||||
private:
|
||||
void * function_pointer;
|
||||
wups_loader_hook_type_t type;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
87
loader/src/plugin/PluginData.h
Normal file
87
loader/src/plugin/PluginData.h
Normal file
@@ -0,0 +1,87 @@
|
||||
/****************************************************************************
|
||||
* Copyright (C) 2018 Maschell
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef _PLUGIN_DATA_H_
|
||||
#define _PLUGIN_DATA_H_
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "EntryData.h"
|
||||
#include "HookData.h"
|
||||
#include "PluginInformation.h"
|
||||
#include <utils/logger.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <libelf.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
class PluginData{
|
||||
public:
|
||||
PluginData(PluginInformation * pluginInformation){
|
||||
this->pluginInformation = pluginInformation;
|
||||
}
|
||||
|
||||
~PluginData(){
|
||||
for(size_t i = 0;i< entry_data_list.size();i++){
|
||||
if(entry_data_list[i] != NULL){
|
||||
delete entry_data_list[i];
|
||||
}
|
||||
}
|
||||
|
||||
for(size_t i = 0;i< hook_data_list.size();i++){
|
||||
if(hook_data_list[i] != NULL){
|
||||
delete hook_data_list[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void addEntryData(EntryData * entry_data){
|
||||
entry_data_list.push_back(entry_data);
|
||||
}
|
||||
|
||||
std::vector<EntryData *> getEntryDataList(){
|
||||
return entry_data_list;
|
||||
}
|
||||
|
||||
void addHookData(HookData * hook_data){
|
||||
hook_data_list.push_back(hook_data);
|
||||
}
|
||||
|
||||
std::vector<HookData *> getHookDataList(){
|
||||
return hook_data_list;
|
||||
}
|
||||
|
||||
PluginInformation * getPluginInformation(){
|
||||
return pluginInformation;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
PluginInformation * pluginInformation;
|
||||
|
||||
std::vector<EntryData *> entry_data_list;
|
||||
std::vector<HookData *> hook_data_list;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
404
loader/src/plugin/PluginInformation.cpp
Normal file
404
loader/src/plugin/PluginInformation.cpp
Normal file
@@ -0,0 +1,404 @@
|
||||
/* based on plugin.c
|
||||
* by Alex Chadwick
|
||||
*
|
||||
* Copyright (C) 2014, Alex Chadwick
|
||||
* Modified 2018, Maschell
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "PluginInformation.h"
|
||||
#include <utils/logger.h>
|
||||
#include <dynamic_libs/os_types.h>
|
||||
#include <libelf.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <wups.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <utils/utils.h>
|
||||
#include "ElfTools.h"
|
||||
|
||||
bool PluginInformation::checkFileExtenstion(const char * path) {
|
||||
if(path == NULL){
|
||||
return false;
|
||||
}
|
||||
const char *extension;
|
||||
|
||||
/* find the file extension */
|
||||
extension = strrchr(path, '.');
|
||||
if (extension == NULL){
|
||||
extension = strchr(path, '\0');
|
||||
}else{
|
||||
extension++;
|
||||
}
|
||||
|
||||
if(extension == NULL){
|
||||
return false;
|
||||
}
|
||||
|
||||
if (strcmp(extension, "mod") == 0 ||
|
||||
strcmp(extension, "o") == 0 ||
|
||||
strcmp(extension, "a") == 0 ||
|
||||
strcmp(extension, "elf") == 0) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool PluginInformation::openAndParseElf() {
|
||||
bool result = false;
|
||||
int fd = -1;
|
||||
Elf *elf = NULL;
|
||||
|
||||
/* check for compile errors */
|
||||
if (elf_version(EV_CURRENT) == EV_NONE){
|
||||
goto exit_error;
|
||||
}
|
||||
|
||||
fd = open(getPath().c_str(), O_RDONLY, 0);
|
||||
|
||||
if (fd == -1){
|
||||
DEBUG_FUNCTION_LINE("failed to open '%s' \n", getPath().c_str());
|
||||
goto exit_error;
|
||||
}
|
||||
|
||||
elf = elf_begin(fd, ELF_C_READ, NULL);
|
||||
|
||||
if (elf == NULL){
|
||||
DEBUG_FUNCTION_LINE("elf was NULL\n");
|
||||
goto exit_error;
|
||||
}
|
||||
|
||||
switch (elf_kind(elf)) {
|
||||
case ELF_K_AR:
|
||||
/* TODO */
|
||||
DEBUG_FUNCTION_LINE("Warning: Ignoring '%s' - Archives not yet supported.\n", getPath().c_str());
|
||||
goto exit_error;
|
||||
case ELF_K_ELF:
|
||||
result = this->parseElf(elf);
|
||||
break;
|
||||
default:
|
||||
DEBUG_FUNCTION_LINE("Warning: Ignoring '%s' - Invalid ELF file.\n", getPath().c_str());
|
||||
goto exit_error;
|
||||
}
|
||||
|
||||
exit_error:
|
||||
if (elf != NULL){
|
||||
elf_end(elf);
|
||||
}
|
||||
if (fd != -1){
|
||||
close(fd);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool PluginInformation::parseElf( Elf *elf) {
|
||||
bool res = false;
|
||||
Elf_Scn *scn;
|
||||
Elf32_Ehdr *ehdr;
|
||||
char *ident;
|
||||
size_t shstrndx, sz, symtab_count, symtab_strndx;
|
||||
Elf32_Sym *symtab = NULL;
|
||||
|
||||
size_t cur_size = 0;
|
||||
|
||||
const char * path_c = getPath().c_str();
|
||||
|
||||
if(elf == NULL){ goto exit_error; }
|
||||
if(elf_kind(elf) != ELF_K_ELF){ goto exit_error; }
|
||||
|
||||
ident = elf_getident(elf, &sz);
|
||||
|
||||
if (ident == NULL) {
|
||||
DEBUG_FUNCTION_LINE("Warning: Ignoring '%s' - Invalid ELF header.\n", path_c);
|
||||
goto exit_error;
|
||||
}
|
||||
if (sz < 7) {
|
||||
DEBUG_FUNCTION_LINE("Warning: Ignoring '%s' - Invalid ELF header.\n", path_c);
|
||||
goto exit_error;
|
||||
}
|
||||
if (ident[4] != ELFCLASS32) {
|
||||
DEBUG_FUNCTION_LINE("Warning: Ignoring '%s' - Not 32 bit ELF.\n", path_c);
|
||||
goto exit_error;
|
||||
}
|
||||
if (ident[5] != ELFDATA2MSB) {
|
||||
DEBUG_FUNCTION_LINE("Warning: Ignoring '%s' - Not Big Endian.\n", path_c);
|
||||
goto exit_error;
|
||||
}
|
||||
if (ident[6] != EV_CURRENT) {
|
||||
DEBUG_FUNCTION_LINE("Warning: Ignoring '%s' - Unknown ELF version.\n", path_c);
|
||||
goto exit_error;
|
||||
}
|
||||
|
||||
ehdr = elf32_getehdr(elf);
|
||||
|
||||
if (ehdr == NULL) {
|
||||
DEBUG_FUNCTION_LINE("Warning: Ignoring '%s' - Invalid ELF header\n", path_c);
|
||||
goto exit_error;
|
||||
}
|
||||
if (ehdr->e_type != ET_REL) {
|
||||
DEBUG_FUNCTION_LINE("Warning: Ignoring '%s' - Not relocatable ELF.\n", path_c);
|
||||
goto exit_error;
|
||||
}
|
||||
if (ehdr->e_machine != EM_PPC) {
|
||||
DEBUG_FUNCTION_LINE("Warning: Ignoring '%s' - Architecture not EM_PPC.\n", path_c);
|
||||
goto exit_error;
|
||||
}
|
||||
if (ehdr->e_version != EV_CURRENT) {
|
||||
DEBUG_FUNCTION_LINE("Warning: Ignoring '%s' - Unknown ELF version.\n", path_c);
|
||||
goto exit_error;
|
||||
}
|
||||
|
||||
if (!ElfTools::loadElfSymtab(elf, &symtab, &symtab_count, &symtab_strndx)) {
|
||||
DEBUG_FUNCTION_LINE("Warning: Ignoring '%s' - Couldn't parse symtab.\n", path_c);
|
||||
goto exit_error;
|
||||
}
|
||||
|
||||
if(symtab == NULL){ goto exit_error; }
|
||||
|
||||
if(!metadataRead(elf, symtab, symtab_count, symtab_strndx)){
|
||||
goto exit_error;
|
||||
}
|
||||
|
||||
if (elf_getshdrstrndx(elf, &shstrndx) != 0) {
|
||||
DEBUG_FUNCTION_LINE("Warning: Ignoring '%s' - Couldn't find shdrstndx.\n", path_c);
|
||||
goto exit_error;
|
||||
}
|
||||
|
||||
for (scn = elf_nextscn(elf, NULL); scn != NULL; scn = elf_nextscn(elf, scn)) {
|
||||
Elf32_Shdr *shdr;
|
||||
|
||||
shdr = elf32_getshdr(scn);
|
||||
if (shdr == NULL){
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((shdr->sh_type == SHT_PROGBITS || shdr->sh_type == SHT_NOBITS) &&
|
||||
(shdr->sh_flags & SHF_ALLOC)) {
|
||||
|
||||
const char *name;
|
||||
|
||||
name = elf_strptr(elf, shstrndx, shdr->sh_name);
|
||||
if (name == NULL){
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strcmp(name, ".wups.meta") == 0) {
|
||||
continue;
|
||||
} else if (strcmp(name, ".wups.load") == 0) {
|
||||
cur_size +=
|
||||
shdr->sh_size / sizeof(wups_loader_entry_t) * 6*4;
|
||||
} else if (strcmp(name, ".wups.hooks") == 0) {
|
||||
cur_size +=
|
||||
shdr->sh_size / sizeof(wups_loader_hook_t) * 2*4;
|
||||
} else {
|
||||
cur_size += shdr->sh_size;
|
||||
/* add alignment padding to size */
|
||||
if (shdr->sh_addralign > 3){
|
||||
/* roundup to multiple of sh_addralign */
|
||||
cur_size += (-cur_size & (shdr->sh_addralign - 1));
|
||||
}else{
|
||||
/* roundup to multiple of 4 */
|
||||
cur_size += (-cur_size & 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* roundup to multiple of 4 */
|
||||
cur_size += (-cur_size & 3);
|
||||
|
||||
this->setSize(cur_size);
|
||||
|
||||
res = true;
|
||||
exit_error:
|
||||
if (symtab != NULL){
|
||||
free(symtab);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
bool PluginInformation::metadataRead(Elf *elf, Elf32_Sym *symtab, size_t symtab_count, size_t symtab_strndx) {
|
||||
char *metadata = NULL, *metadata_cur, *metadata_end;
|
||||
const char *game, *name, *author, *version, *license, *wups;
|
||||
|
||||
Elf_Scn *scn;
|
||||
size_t shstrndx;
|
||||
|
||||
if (elf_getshdrstrndx(elf, &shstrndx) != 0) {
|
||||
DEBUG_FUNCTION_LINE("Warning: Ignoring '%s' - Couldn't find shstrndx\n", path);
|
||||
goto exit_error;
|
||||
}
|
||||
|
||||
for (scn = elf_nextscn(elf, NULL); scn != NULL; scn = elf_nextscn(elf, scn)) {
|
||||
Elf32_Shdr *shdr;
|
||||
const char *name;
|
||||
|
||||
shdr = elf32_getshdr(scn);
|
||||
if (shdr == NULL){
|
||||
continue;
|
||||
}
|
||||
|
||||
name = elf_strptr(elf, shstrndx, shdr->sh_name);
|
||||
if (name == NULL){
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strcmp(name, ".wups.meta") == 0) {
|
||||
if (shdr->sh_size == 0){
|
||||
continue;
|
||||
}
|
||||
|
||||
if (metadata != NULL){
|
||||
continue;
|
||||
}
|
||||
|
||||
metadata = (char*) malloc(shdr->sh_size);
|
||||
|
||||
if (metadata == NULL){
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!ElfTools::elfLoadSection(elf, scn, shdr, metadata)) {
|
||||
DEBUG_FUNCTION_LINE("Warning: Ignoring '%s' - Couldn't load .wups.meta.\n", path);
|
||||
goto exit_error;
|
||||
}
|
||||
|
||||
ElfTools::elfLoadSymbols(elf_ndxscn(scn), metadata, symtab, symtab_count);
|
||||
|
||||
if (!ElfTools::elfLink(elf, elf_ndxscn(scn), metadata, symtab, symtab_count, symtab_strndx, false)) {
|
||||
DEBUG_FUNCTION_LINE("Warning: Ignoring '%s' - .wups.meta contains invalid relocations.\n", path);
|
||||
goto exit_error;
|
||||
}
|
||||
|
||||
metadata_end = metadata + shdr->sh_size;
|
||||
metadata_end[-1] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
if (metadata == NULL) {
|
||||
DEBUG_FUNCTION_LINE("Warning: Ignoring '%s' - Not a WUPS plugin file.\n", path);
|
||||
goto exit_error;
|
||||
}
|
||||
|
||||
game = NULL;
|
||||
name = NULL;
|
||||
author = NULL;
|
||||
version = NULL;
|
||||
license = NULL;
|
||||
wups = NULL;
|
||||
|
||||
for (metadata_cur = metadata; metadata_cur < metadata_end; metadata_cur = strchr(metadata_cur, '\0') + 1) {
|
||||
|
||||
char *eq;
|
||||
|
||||
if(metadata_cur < metadata || metadata_cur >= metadata_end){
|
||||
goto exit_error;
|
||||
}
|
||||
|
||||
if (*metadata_cur == '\0'){
|
||||
continue;
|
||||
}
|
||||
|
||||
eq = strchr(metadata_cur, '=');
|
||||
if (eq == NULL){
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strncmp(metadata_cur, "game", eq - metadata_cur) == 0) {
|
||||
if (game != NULL) {
|
||||
DEBUG_FUNCTION_LINE("Warning: Ignoring '%s' - Multiple WUPS_PLUGIN_GAME declarations.\n", path);
|
||||
goto exit_error;
|
||||
}
|
||||
game = eq + 1;
|
||||
} else if (strncmp(metadata_cur, "name", eq - metadata_cur) == 0) {
|
||||
if (name != NULL) {
|
||||
DEBUG_FUNCTION_LINE("Warning: Ignoring '%s' - Multiple WUPS_PLUGIN_NAME declarations.\n", path);
|
||||
goto exit_error;
|
||||
}
|
||||
name = eq + 1;
|
||||
} else if (strncmp(metadata_cur, "author", eq - metadata_cur) == 0) {
|
||||
if (author != NULL) {
|
||||
DEBUG_FUNCTION_LINE("Warning: Ignoring '%s' - Multiple WUPS_PLUGIN_AUTHOR declarations.\n", path);
|
||||
goto exit_error;
|
||||
}
|
||||
author = eq + 1;
|
||||
} else if (strncmp(metadata_cur, "version", eq - metadata_cur) == 0) {
|
||||
if (version != NULL) {
|
||||
DEBUG_FUNCTION_LINE("Warning: Ignoring '%s' - Multiple WUPS_PLUGIN_VERSION declarations.\n", path);
|
||||
goto exit_error;
|
||||
}
|
||||
version = eq + 1;
|
||||
} else if (strncmp(metadata_cur, "license", eq - metadata_cur) == 0) {
|
||||
if (license != NULL) {
|
||||
DEBUG_FUNCTION_LINE("Warning: Ignoring '%s' - Multiple WUPS_PLUGIN_LICENSE declarations.\n", path);
|
||||
goto exit_error;
|
||||
}
|
||||
license = eq + 1;
|
||||
} else if (strncmp(metadata_cur, "wups", eq - metadata_cur) == 0) {
|
||||
if (wups != NULL) {
|
||||
DEBUG_FUNCTION_LINE("Warning: Ignoring '%s' - Multiple WUPS_PLUGIN_NAME declarations.\n", path);
|
||||
goto exit_error;
|
||||
}
|
||||
wups = eq + 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (game == NULL){
|
||||
game = "";
|
||||
}
|
||||
// TODO:
|
||||
/*if (wups == NULL || strcmp(wups, "0.1") != 0) {
|
||||
DEBUG_FUNCTION_LINE("Warning: Ignoring '%s' - Unrecognised WUPS version.\n", path);
|
||||
goto exit_error;
|
||||
}*/
|
||||
if (name == NULL) {
|
||||
DEBUG_FUNCTION_LINE("Warning: Ignoring '%s' - Missing WUPS_PLUGIN_NAME declaration.\n",path);
|
||||
goto exit_error;
|
||||
}
|
||||
if (author == NULL) {
|
||||
DEBUG_FUNCTION_LINE("Warning: Ignoring '%s' - Missing WUPS_PLUGIN_AUTHOR declaration.\n", path);
|
||||
goto exit_error;
|
||||
}
|
||||
if (version == NULL) {
|
||||
DEBUG_FUNCTION_LINE("Warning: Ignoring '%s' - Missing WUPS_PLUGIN_VERSION declaration.\n", path);
|
||||
goto exit_error;
|
||||
}
|
||||
if (license == NULL) {
|
||||
DEBUG_FUNCTION_LINE("Warning: Ignoring '%s' - Missing WUPS_PLUGIN_LICENSE declaration.\n", path);
|
||||
goto exit_error;
|
||||
}
|
||||
|
||||
this->setName(name);
|
||||
this->setAuthor(author);
|
||||
this->setVersion(version);
|
||||
this->setLicense(license);
|
||||
|
||||
return true;
|
||||
|
||||
exit_error:
|
||||
|
||||
if (metadata != NULL){
|
||||
free(metadata);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
133
loader/src/plugin/PluginInformation.h
Normal file
133
loader/src/plugin/PluginInformation.h
Normal file
@@ -0,0 +1,133 @@
|
||||
/* based on module.c
|
||||
* by Alex Chadwick
|
||||
*
|
||||
* Copyright (C) 2014, Alex Chadwick
|
||||
* Modified 2018, Maschell
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef _PLUGIN_INFORMATION_H_
|
||||
#define _PLUGIN_INFORMATION_H_
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "EntryData.h"
|
||||
#include "HookData.h"
|
||||
#include <utils/logger.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <libelf.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
class PluginInformation{
|
||||
public:
|
||||
/**
|
||||
|
||||
returns PluginInformation* if a valid plugin was found at the given path. Otherwise returns NULL
|
||||
**/
|
||||
static PluginInformation * loadPluginInformation(std::string path){
|
||||
if(PluginInformation::checkFileExtenstion(path.c_str())){
|
||||
DEBUG_FUNCTION_LINE("Checkfile successfully, loading now Plugin Information\n");
|
||||
PluginInformation * pluginInformation = new PluginInformation(path);
|
||||
if(pluginInformation->openAndParseElf()){
|
||||
return pluginInformation;
|
||||
}else{
|
||||
delete pluginInformation;
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
std::string getName(){
|
||||
return this->name;
|
||||
}
|
||||
|
||||
std::string getAuthor(){
|
||||
return this->author;
|
||||
}
|
||||
|
||||
std::string getVersion(){
|
||||
return this->version;
|
||||
}
|
||||
|
||||
std::string getLicense(){
|
||||
return this->license;
|
||||
}
|
||||
|
||||
std::string getPath(){
|
||||
return path;
|
||||
}
|
||||
|
||||
size_t getSize(){
|
||||
return this->size;
|
||||
}
|
||||
private:
|
||||
PluginInformation(std::string path){
|
||||
this->path = path;
|
||||
}
|
||||
|
||||
void setName(const char * name){
|
||||
this->name = name;
|
||||
}
|
||||
|
||||
void setAuthor(const char * author){
|
||||
this->author = author;
|
||||
}
|
||||
|
||||
void setVersion(const char * version){
|
||||
this->version = version;
|
||||
}
|
||||
|
||||
void setLicense(const char * license){
|
||||
this->license = license;
|
||||
}
|
||||
|
||||
void setSize(size_t size){
|
||||
this->size = size;
|
||||
}
|
||||
|
||||
static bool checkFileExtenstion(const char * path);
|
||||
|
||||
bool openAndParseElf();
|
||||
|
||||
bool parseElf(Elf *elf);
|
||||
|
||||
bool metadataRead(Elf *elf, Elf32_Sym *symtab, size_t symtab_count, size_t symtab_strndx);
|
||||
|
||||
bool loadedSuccessfully = false;
|
||||
|
||||
std::string path;
|
||||
std::string name;
|
||||
std::string author;
|
||||
std::string version;
|
||||
std::string license;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
414
loader/src/plugin/PluginLoader.cpp
Normal file
414
loader/src/plugin/PluginLoader.cpp
Normal file
@@ -0,0 +1,414 @@
|
||||
/* based on module.c
|
||||
* by Alex Chadwick
|
||||
*
|
||||
* Copyright (C) 2014, Alex Chadwick
|
||||
* Modified 2018, Maschell
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include "ElfTools.h"
|
||||
#include "PluginData.h"
|
||||
#include "PluginLoader.h"
|
||||
#include "utils/StringTools.h"
|
||||
#include "common/retain_vars.h"
|
||||
|
||||
PluginLoader * PluginLoader::instance = NULL;
|
||||
|
||||
std::vector<PluginInformation *> PluginLoader::getPluginInformation(const char * path){
|
||||
std::vector<PluginInformation *> result;
|
||||
struct dirent *dp;
|
||||
DIR *dfd = NULL;
|
||||
|
||||
if(path == NULL){
|
||||
DEBUG_FUNCTION_LINE("Path was NULL");
|
||||
return result;
|
||||
}
|
||||
|
||||
if ((dfd = opendir(path)) == NULL){
|
||||
DEBUG_FUNCTION_LINE("Couldn't open dir %s",path);
|
||||
return result;
|
||||
}
|
||||
|
||||
while ((dp = readdir(dfd)) != NULL){
|
||||
struct stat stbuf ;
|
||||
std::string full_file_path = StringTools::strfmt("%s/%s",path,dp->d_name);
|
||||
StringTools::RemoveDoubleSlashs(full_file_path);
|
||||
if( stat(full_file_path.c_str(),&stbuf ) == -1 ){
|
||||
DEBUG_FUNCTION_LINE("Unable to stat file: %s\n",full_file_path.c_str()) ;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( ( stbuf.st_mode & S_IFMT ) == S_IFDIR ){ // Skip directories
|
||||
continue;
|
||||
}else{
|
||||
DEBUG_FUNCTION_LINE("Found file: %s\n",full_file_path.c_str()) ;
|
||||
PluginInformation * plugin = PluginInformation::loadPluginInformation(full_file_path);
|
||||
if(plugin != NULL){
|
||||
DEBUG_FUNCTION_LINE("Found plugin %s by %s. Size: %d kb \n",plugin->getName().c_str(),plugin->getAuthor().c_str(),plugin->getSize()/1024) ;
|
||||
result.push_back(plugin);
|
||||
} else {
|
||||
DEBUG_FUNCTION_LINE("%s is not a valid plugin\n",full_file_path.c_str()) ;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void PluginLoader::loadAndLinkPlugins(std::vector<PluginInformation *> pluginInformation){
|
||||
std::vector<PluginData *> loadedPlugins;
|
||||
for(size_t i = 0;i < pluginInformation.size(); i++){
|
||||
DEBUG_FUNCTION_LINE("loadAndLinkPlugins for %d\n",i) ;
|
||||
PluginInformation * cur_info = pluginInformation[i];
|
||||
PluginData * pluginData = loadAndLinkPlugin(cur_info);
|
||||
if(pluginData == NULL){
|
||||
DEBUG_FUNCTION_LINE("loadAndLinkPlugins failed for %d\n",i) ;
|
||||
continue;
|
||||
} else {
|
||||
loadedPlugins.push_back(pluginData);
|
||||
}
|
||||
}
|
||||
|
||||
copyPluginDataIntoGlobalStruct(loadedPlugins);
|
||||
clearPluginData(loadedPlugins);
|
||||
}
|
||||
|
||||
void PluginLoader::clearPluginData(std::vector<PluginData *> pluginData){
|
||||
for(size_t i = 0;i < pluginData.size(); i++){
|
||||
PluginData * curPluginData = pluginData[i];
|
||||
if(curPluginData != NULL){
|
||||
delete curPluginData;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
PluginData * PluginLoader::loadAndLinkPlugin(PluginInformation * pluginInformation){
|
||||
DEBUG_FUNCTION_LINE("\n");
|
||||
PluginData * result = NULL;
|
||||
int fd = -1;
|
||||
Elf *elf = NULL;
|
||||
|
||||
if(pluginInformation == NULL){
|
||||
DEBUG_FUNCTION_LINE("pluginInformation was NULL\n");
|
||||
goto exit_error;
|
||||
}
|
||||
|
||||
if(pluginInformation->getSize() > ((u32) this->getCurrentStoreAddress() - (u32) this->startAddress)){
|
||||
DEBUG_FUNCTION_LINE("Not enough space left to loader the plugin into memory\n");
|
||||
goto exit_error;
|
||||
}
|
||||
|
||||
/* check for compile errors */
|
||||
if (elf_version(EV_CURRENT) == EV_NONE){
|
||||
goto exit_error;
|
||||
}
|
||||
|
||||
fd = open(pluginInformation->getPath().c_str(), O_RDONLY, 0);
|
||||
|
||||
if (fd == -1){
|
||||
DEBUG_FUNCTION_LINE("failed to open '%s' \n", pluginInformation->getPath().c_str());
|
||||
goto exit_error;
|
||||
}
|
||||
|
||||
elf = elf_begin(fd, ELF_C_READ, NULL);
|
||||
|
||||
if (elf == NULL){
|
||||
DEBUG_FUNCTION_LINE("elf was NULL\n");
|
||||
goto exit_error;
|
||||
}
|
||||
|
||||
DEBUG_FUNCTION_LINE("\n");
|
||||
result = new PluginData(pluginInformation);
|
||||
if(result == NULL){
|
||||
DEBUG_FUNCTION_LINE("Failed to create object\n");
|
||||
goto exit_error;
|
||||
}
|
||||
|
||||
if(!this->loadAndLinkElf(result, elf, this->getCurrentStoreAddress())){
|
||||
delete result;
|
||||
result = NULL;
|
||||
}
|
||||
|
||||
exit_error:
|
||||
if (elf != NULL){
|
||||
elf_end(elf);
|
||||
}
|
||||
if (fd != -1){
|
||||
close(fd);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool PluginLoader::loadAndLinkElf(PluginData * pluginData, Elf *elf, void * endAddress) {
|
||||
if(pluginData == NULL || elf == NULL || endAddress == NULL){
|
||||
return false;
|
||||
}
|
||||
|
||||
DEBUG_FUNCTION_LINE("\n");
|
||||
|
||||
u32 curAddress = (u32) endAddress;
|
||||
|
||||
Elf_Scn *scn;
|
||||
size_t symtab_count, section_count, shstrndx, symtab_strndx, entries_count, hooks_count;
|
||||
Elf32_Sym *symtab = NULL;
|
||||
uint8_t **destinations = NULL;
|
||||
wups_loader_entry_t *entries = NULL;
|
||||
wups_loader_hook_t *hooks = NULL;
|
||||
bool result = false;
|
||||
|
||||
std::vector<wups_loader_entry_t *> entry_t_list;
|
||||
std::vector<wups_loader_hook_t *> hook_t_list;
|
||||
|
||||
std::vector<EntryData *> entry_data_list;
|
||||
std::vector<HookData *> hook_data_list;
|
||||
|
||||
if (!ElfTools::loadElfSymtab(elf, &symtab, &symtab_count, &symtab_strndx)){
|
||||
goto exit_error;
|
||||
}
|
||||
|
||||
if(symtab == NULL){
|
||||
goto exit_error;
|
||||
}
|
||||
|
||||
if (elf_getshdrnum(elf, §ion_count) != 0){
|
||||
goto exit_error;
|
||||
}
|
||||
if (elf_getshdrstrndx(elf, &shstrndx) != 0){
|
||||
goto exit_error;
|
||||
}
|
||||
|
||||
destinations = (uint8_t **) malloc(sizeof(uint8_t *) * section_count);
|
||||
|
||||
for (scn = elf_nextscn(elf, NULL); scn != NULL; scn = elf_nextscn(elf, scn)) {
|
||||
Elf32_Shdr *shdr;
|
||||
|
||||
shdr = elf32_getshdr(scn);
|
||||
if (shdr == NULL){
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((shdr->sh_type == SHT_PROGBITS || shdr->sh_type == SHT_NOBITS) &&
|
||||
(shdr->sh_flags & SHF_ALLOC)) {
|
||||
|
||||
const char *name;
|
||||
|
||||
destinations[elf_ndxscn(scn)] = NULL;
|
||||
|
||||
name = elf_strptr(elf, shstrndx, shdr->sh_name);
|
||||
if (name == NULL){
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strcmp(name, ".wups.meta") == 0) {
|
||||
continue;
|
||||
} else if (strcmp(name, ".wups.load") == 0) {
|
||||
if (entries != NULL){
|
||||
goto exit_error;
|
||||
}
|
||||
|
||||
entries_count = shdr->sh_size / sizeof(wups_loader_entry_t);
|
||||
entries = (wups_loader_entry_t *) malloc(sizeof(wups_loader_entry_t) * entries_count);
|
||||
|
||||
if (entries == NULL){
|
||||
goto exit_error;
|
||||
}
|
||||
|
||||
destinations[elf_ndxscn(scn)] = (uint8_t *)entries;
|
||||
if (!ElfTools::elfLoadSection(elf, scn, shdr, entries)){
|
||||
goto exit_error;
|
||||
}
|
||||
|
||||
ElfTools::elfLoadSymbols(elf_ndxscn(scn), entries, symtab, symtab_count);
|
||||
|
||||
for(size_t i = 0;i< entries_count;i++){
|
||||
entry_t_list.push_back(&entries[i]);
|
||||
}
|
||||
}else if (strcmp(name, ".wups.hooks") == 0) {
|
||||
if (hooks != NULL){
|
||||
goto exit_error;
|
||||
}
|
||||
|
||||
hooks_count = shdr->sh_size / sizeof(wups_loader_hook_t);
|
||||
hooks = (wups_loader_hook_t *) malloc(sizeof(wups_loader_hook_t) * hooks_count);
|
||||
|
||||
if (hooks == NULL){
|
||||
goto exit_error;
|
||||
}
|
||||
|
||||
destinations[elf_ndxscn(scn)] = (uint8_t *)hooks;
|
||||
if (!ElfTools::elfLoadSection(elf, scn, shdr, hooks)){
|
||||
goto exit_error;
|
||||
}
|
||||
ElfTools::elfLoadSymbols(elf_ndxscn(scn), hooks, symtab, symtab_count);
|
||||
|
||||
for(size_t i = 0;i< hooks_count;i++){
|
||||
hook_t_list.push_back(&hooks[i]);
|
||||
}
|
||||
|
||||
} else {
|
||||
curAddress -= shdr->sh_size;
|
||||
|
||||
if (shdr->sh_addralign > 3){
|
||||
curAddress = (u32)((int)curAddress & ~(shdr->sh_addralign - 1));
|
||||
} else {
|
||||
curAddress = (u32)((int)curAddress & ~3);
|
||||
}
|
||||
destinations[elf_ndxscn(scn)] = (uint8_t *) curAddress;
|
||||
|
||||
if((u32) curAddress < (u32) this->startAddress){
|
||||
DEBUG_FUNCTION_LINE("Not enough space to load function %s into memory at %08X.\n",name,curAddress);
|
||||
goto exit_error;
|
||||
}
|
||||
|
||||
DEBUG_FUNCTION_LINE("Copy section %s to %08X\n",name,curAddress);
|
||||
if (!ElfTools::elfLoadSection(elf, scn, shdr, (void*) curAddress)){
|
||||
goto exit_error;
|
||||
}
|
||||
ElfTools::elfLoadSymbols(elf_ndxscn(scn), (void*) curAddress, symtab, symtab_count);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (entries == NULL){
|
||||
goto exit_error;
|
||||
}
|
||||
|
||||
for (scn = elf_nextscn(elf, NULL); scn != NULL; scn = elf_nextscn(elf, scn)) {
|
||||
Elf32_Shdr *shdr;
|
||||
|
||||
shdr = elf32_getshdr(scn);
|
||||
if (shdr == NULL){
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((shdr->sh_type == SHT_PROGBITS || shdr->sh_type == SHT_NOBITS) &&
|
||||
(shdr->sh_flags & SHF_ALLOC) &&
|
||||
destinations[elf_ndxscn(scn)] != NULL) {
|
||||
|
||||
if (!ElfTools::elfLink(elf, elf_ndxscn(scn), destinations[elf_ndxscn(scn)], symtab, symtab_count, symtab_strndx, true)){
|
||||
goto exit_error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(size_t j=0;j<hook_t_list.size();j++){
|
||||
wups_loader_hook_t * hook = hook_t_list[j];
|
||||
|
||||
DEBUG_FUNCTION_LINE("Saving hook of plugin \"%s\". Type: %08X, target: %08X\n",pluginData->getPluginInformation()->getName().c_str(),hook->type,(void*) hook->target);
|
||||
HookData * hook_data = new HookData((void *) hook->target,hook->type);
|
||||
pluginData->addHookData(hook_data);
|
||||
}
|
||||
|
||||
for(size_t j=0;j<entry_t_list.size();j++){
|
||||
wups_loader_entry_t * entry = entry_t_list[j];
|
||||
DEBUG_FUNCTION_LINE("Saving entry \"%s\" of plugin \"%s\". Library: %08X, target: %08X, call_addr: %08X\n",entry->_function.name,pluginData->getPluginInformation()->getName().c_str(),entry->_function.library,entry->_function.target, (void *) entry->_function.call_addr);
|
||||
EntryData * entry_data = new EntryData(entry->_function.name,entry->_function.library, (void *) entry->_function.target, (void *) entry->_function.call_addr);
|
||||
pluginData->addEntryData(entry_data);
|
||||
}
|
||||
|
||||
this->setCurrentStoreAddress((void *) curAddress);
|
||||
|
||||
result = true;
|
||||
exit_error:
|
||||
if (!result) DEBUG_FUNCTION_LINE("exit_error\n");
|
||||
if (destinations != NULL){
|
||||
free(destinations);
|
||||
}
|
||||
if (symtab != NULL){
|
||||
free(symtab);
|
||||
}
|
||||
if (hooks != NULL){
|
||||
free(hooks);
|
||||
}
|
||||
if (entries != NULL){
|
||||
free(entries);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void PluginLoader::copyPluginDataIntoGlobalStruct(std::vector<PluginData *> plugins){
|
||||
// Reset data
|
||||
memset((void*)&gbl_replacement_data,0,sizeof(gbl_replacement_data));
|
||||
int plugin_index = 0;
|
||||
// Copy data to global struct.
|
||||
for(size_t i = 0; i< plugins.size();i++){
|
||||
PluginData * cur_plugin = plugins.at(i);
|
||||
PluginInformation * cur_pluginInformation = cur_plugin->getPluginInformation();
|
||||
|
||||
std::vector<EntryData *> entry_data_list = cur_plugin->getEntryDataList();
|
||||
std::vector<HookData *> hook_data_list = cur_plugin->getHookDataList();
|
||||
if(plugin_index >= MAXIMUM_PLUGINS ){
|
||||
DEBUG_FUNCTION_LINE("Maximum of %d plugins reached. %s won't be loaded!\n",MAXIMUM_PLUGINS,cur_pluginInformation->getName().c_str());
|
||||
continue;
|
||||
}
|
||||
if(entry_data_list.size() > MAXIMUM_FUNCTION_PER_PLUGIN){
|
||||
DEBUG_FUNCTION_LINE("Plugin %s would replace to many function (%d, maximum is %d). It won't be loaded.\n",cur_pluginInformation->getName().c_str(),entry_data_list.size(),MAXIMUM_FUNCTION_PER_PLUGIN);
|
||||
continue;
|
||||
}
|
||||
if(hook_data_list.size() > MAXIMUM_HOOKS_PER_PLUGIN){
|
||||
DEBUG_FUNCTION_LINE("Plugin %s would set too many hooks (%d, maximum is %d). It won't be loaded.\n",cur_pluginInformation->getName().c_str(),hook_data_list.size(),MAXIMUM_HOOKS_PER_PLUGIN);
|
||||
continue;
|
||||
}
|
||||
|
||||
replacement_data_plugin_t * plugin_data = &gbl_replacement_data.plugin_data[plugin_index];
|
||||
|
||||
strncpy(plugin_data->plugin_name,cur_pluginInformation->getName().c_str(),MAXIMUM_PLUGIN_NAME_LENGTH-1);
|
||||
|
||||
for(size_t j = 0; j < entry_data_list.size();j++){
|
||||
replacement_data_function_t * function_data = &plugin_data->functions[j];
|
||||
|
||||
EntryData * cur_entry = entry_data_list[j];
|
||||
DEBUG_FUNCTION_LINE("Adding entry \"%s\" for plugin \"%s\"\n",cur_entry->getName().c_str(),plugin_data->plugin_name);
|
||||
|
||||
//TODO: Warning/Error if string is too long.
|
||||
strncpy(function_data->function_name,cur_entry->getName().c_str(),MAXIMUM_FUNCTION_NAME_LENGTH-1);
|
||||
|
||||
function_data->library = cur_entry->getLibrary();
|
||||
function_data->replaceAddr = (u32) cur_entry->getReplaceAddress();
|
||||
function_data->replaceCall = (u32) cur_entry->getReplaceCall();
|
||||
|
||||
plugin_data->number_used_functions++;
|
||||
}
|
||||
|
||||
DEBUG_FUNCTION_LINE("Entries for plugin \"%s\": %d\n",plugin_data->plugin_name,plugin_data->number_used_functions);
|
||||
|
||||
for(size_t j = 0; j < hook_data_list.size();j++){
|
||||
replacement_data_hook_t * hook_data = &plugin_data->hooks[j];
|
||||
|
||||
HookData * hook_entry = hook_data_list[j];
|
||||
|
||||
DEBUG_FUNCTION_LINE("Set hook for plugin \"%s\" of type %08X to target %08X\n",plugin_data->plugin_name,hook_entry->getType(),(void*) hook_entry->getFunctionPointer());
|
||||
hook_data->func_pointer = (void*) hook_entry->getFunctionPointer();
|
||||
hook_data->type = hook_entry->getType();
|
||||
plugin_data->number_used_hooks++;
|
||||
}
|
||||
|
||||
DEBUG_FUNCTION_LINE("Hooks for plugin \"%s\": %d\n",plugin_data->plugin_name,plugin_data->number_used_hooks);
|
||||
|
||||
plugin_index++;
|
||||
gbl_replacement_data.number_used_plugins++;
|
||||
}
|
||||
}
|
||||
151
loader/src/plugin/PluginLoader.h
Normal file
151
loader/src/plugin/PluginLoader.h
Normal file
@@ -0,0 +1,151 @@
|
||||
/* based on module.c
|
||||
* by Alex Chadwick
|
||||
*
|
||||
* Copyright (C) 2014, Alex Chadwick
|
||||
* Modified 2018, Maschell
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef _PLUGIN_LOADER_H_
|
||||
#define _PLUGIN_LOADER_H_
|
||||
|
||||
#include <vector>
|
||||
#include "PluginInformation.h"
|
||||
#include "PluginData.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <utils/utils.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#define PLUGIN_LOCATION_END_ADDRESS 0x01000000
|
||||
|
||||
class PluginLoader{
|
||||
|
||||
public:
|
||||
static PluginLoader *getInstance() {
|
||||
if(!instance){
|
||||
instance = new PluginLoader((void*)getApplicationEndAddr(),(void *)PLUGIN_LOCATION_END_ADDRESS);
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
static void destroyInstance() {
|
||||
if(instance){
|
||||
delete instance;
|
||||
instance = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Parses the meta data of all plugins in the given directory.
|
||||
|
||||
\param path the path of the directory which should be scanned.
|
||||
|
||||
\return a list of PluginInformation objects, one for each valid plugin.
|
||||
**/
|
||||
std::vector<PluginInformation *> getPluginInformation(const char * path);
|
||||
|
||||
/**
|
||||
\brief Gets plugin information from the global struct.
|
||||
|
||||
\return a list of MetaInformation objects for all plugins currently loaded and linked (relocated). Will only contain
|
||||
plugin which are still on the sd card.
|
||||
**/
|
||||
//std::vector<PluginInformation *> getPluginsLoadedInMemory();
|
||||
|
||||
/**
|
||||
\brief Takes a list of plugins that should be linked (relocated) loaded into the memory.
|
||||
The function that should be replaced will be replaced in the order of the given plugin list.
|
||||
So two plugin will override the same function, the plugin first in this list will override the function first.
|
||||
Also the hooks of the plugins will be called in the order their plugin where passed to this method.
|
||||
|
||||
\param A list of plugin that should be linked (relocated) an loaded into memory
|
||||
**/
|
||||
void loadAndLinkPlugins(std::vector<PluginInformation *> pluginInformation);
|
||||
private:
|
||||
PluginLoader(void * startAddress, void * endAddress){
|
||||
// TODO: Check if endAddress > startAddress.
|
||||
this->startAddress = startAddress;
|
||||
this->endAddress = endAddress;
|
||||
this->currentStoreAddress = endAddress;
|
||||
}
|
||||
|
||||
~PluginLoader(){
|
||||
|
||||
}
|
||||
|
||||
static PluginLoader *instance;
|
||||
|
||||
/**
|
||||
\brief Iterates through the vector and delete all it's elements
|
||||
|
||||
\param A list of PluginData* that should be deleted.
|
||||
**/
|
||||
void clearPluginData(std::vector<PluginData *> pluginData);
|
||||
|
||||
/**
|
||||
\brief Load
|
||||
|
||||
\param pluginInformation a PluginInformation object of the plugin that should be linked (relocated) and loaded.
|
||||
|
||||
\return NULL on error. On success it will return a PluginData object.
|
||||
**/
|
||||
PluginData * loadAndLinkPlugin(PluginInformation * pluginInformation);
|
||||
|
||||
/**
|
||||
\brief Loads a plugin into memory (in the startAddress/endAddress range defined in this loader) and relocates it.
|
||||
Modifies the pluginData param. Adds loaded functions and hooks.
|
||||
\param pluginData object where the result should be stored
|
||||
\param elf source elf from where the sections will be loaded
|
||||
\param storeAddressEnd the address where the plugin data will be stored in memory. Saving BACKWARD.
|
||||
|
||||
**/
|
||||
bool loadAndLinkElf(PluginData * pluginData, Elf *elf, void * storeAddressEnd);
|
||||
|
||||
/**
|
||||
\brief Copies the needed information into a global, persistent struct. This struct holds information on which
|
||||
function should be override in which order and which hook should be called.
|
||||
\param plugins list of plugins that should be used.
|
||||
|
||||
**/
|
||||
void copyPluginDataIntoGlobalStruct(std::vector<PluginData *> plugins);
|
||||
|
||||
void * getCurrentStoreAddress(){
|
||||
return this->currentStoreAddress;
|
||||
}
|
||||
|
||||
void setCurrentStoreAddress(void * addr){
|
||||
this->currentStoreAddress = addr;
|
||||
}
|
||||
|
||||
void * startAddress = NULL;
|
||||
void * endAddress = NULL;
|
||||
void * currentStoreAddress = NULL;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user