mirror of
https://github.com/wiiu-env/WiiUPluginSystem.git
synced 2025-01-11 17:19:06 +01:00
[Loader] Huge refactoring. Getting rid of the global lists in C. Using std::vector now and classes.
This commit is contained in:
parent
78a160a74c
commit
a31d6e8db5
229
loader/src/ElfTools.cpp
Normal file
229
loader/src/ElfTools.cpp
Normal file
@ -0,0 +1,229 @@
|
|||||||
|
/* 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 <assert.h>
|
||||||
|
#include <libelf.h>
|
||||||
|
#include <utils/logger.h>
|
||||||
|
|
||||||
|
bool ElfTools::elfLoadSection(const Elf *elf, Elf_Scn *scn, const Elf32_Shdr *shdr,void *destination) {
|
||||||
|
|
||||||
|
assert(destination != NULL);
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
assert (*symtab == NULL);
|
||||||
|
*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::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("Module_ElfLinkOne01: %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:
|
||||||
|
DEBUG_FUNCTION_LINE("Module_ElfLinkOne01: %02X\n",type);
|
||||||
|
goto exit_error;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = true;
|
||||||
|
exit_error:
|
||||||
|
if (!result) DEBUG_FUNCTION_LINE("Module_ElfLinkOne: exit_error\n");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
48
loader/src/ElfTools.h
Normal file
48
loader/src/ElfTools.h
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
/* 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 elfLinkOne(char type, size_t offset, int addend, void *destination, uint32_t symbol_addr);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
62
loader/src/EntryData.h
Normal file
62
loader/src/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/HookData.h
Normal file
49
loader/src/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
|
778
loader/src/ModuleData.cpp
Normal file
778
loader/src/ModuleData.cpp
Normal file
@ -0,0 +1,778 @@
|
|||||||
|
/* 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 "ModuleData.h"
|
||||||
|
#include <utils/logger.h>
|
||||||
|
#include <dynamic_libs/os_types.h>
|
||||||
|
#include <libelf.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <assert.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 ModuleData::checkFile() {
|
||||||
|
const char *extension;
|
||||||
|
|
||||||
|
const char * path_c = getPath().c_str();
|
||||||
|
|
||||||
|
/* find the file extension */
|
||||||
|
extension = strrchr(path_c, '.');
|
||||||
|
if (extension == NULL){
|
||||||
|
extension = strchr(path_c, '\0');
|
||||||
|
}else{
|
||||||
|
extension++;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(extension != NULL);
|
||||||
|
|
||||||
|
if (strcmp(extension, "mod") == 0 ||
|
||||||
|
strcmp(extension, "o") == 0 ||
|
||||||
|
strcmp(extension, "a") == 0 ||
|
||||||
|
strcmp(extension, "elf") == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ModuleData::load(uint8_t ** space) {
|
||||||
|
bool result = false;
|
||||||
|
int fd = -1;
|
||||||
|
Elf *elf = NULL;
|
||||||
|
|
||||||
|
/* check for compile errors */
|
||||||
|
if (elf_version(EV_CURRENT) == EV_NONE){
|
||||||
|
DEBUG_FUNCTION_LINE("Compiler errors in '%s' \n", getPath().c_str());
|
||||||
|
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:
|
||||||
|
if(!this->loadElf(elf)){
|
||||||
|
goto exit_error;
|
||||||
|
}
|
||||||
|
result = linkModuleElf(elf,space);
|
||||||
|
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 ModuleData::loadElf( 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();
|
||||||
|
|
||||||
|
assert(elf != NULL);
|
||||||
|
assert(elf_kind(elf) == ELF_K_ELF);
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(symtab != NULL);
|
||||||
|
|
||||||
|
DEBUG_FUNCTION_LINE("Reading metadata from path %s.\n", path_c);
|
||||||
|
|
||||||
|
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 ModuleData::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 (!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 module 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;
|
||||||
|
|
||||||
|
assert(metadata_cur >= metadata && metadata_cur < metadata_end);
|
||||||
|
|
||||||
|
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_MODULE_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_MODULE_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_MODULE_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_MODULE_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_MODULE_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_MODULE_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_MODULE_NAME declaration.\n",path);
|
||||||
|
goto exit_error;
|
||||||
|
}
|
||||||
|
if (author == NULL) {
|
||||||
|
DEBUG_FUNCTION_LINE("Warning: Ignoring '%s' - Missing WUPS_MODULE_AUTHOR declaration.\n", path);
|
||||||
|
goto exit_error;
|
||||||
|
}
|
||||||
|
if (version == NULL) {
|
||||||
|
DEBUG_FUNCTION_LINE("Warning: Ignoring '%s' - Missing WUPS_MODULE_VERSION declaration.\n", path);
|
||||||
|
goto exit_error;
|
||||||
|
}
|
||||||
|
if (license == NULL) {
|
||||||
|
DEBUG_FUNCTION_LINE("Warning: Ignoring '%s' - Missing WUPS_MODULE_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;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ModuleData::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,
|
||||||
|
MODULE_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,
|
||||||
|
MODULE_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 ModuleData::linkModuleElf(Elf *elf, uint8_t **space) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(symtab != NULL);
|
||||||
|
|
||||||
|
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 {
|
||||||
|
*space -= shdr->sh_size;
|
||||||
|
|
||||||
|
if (shdr->sh_addralign > 3)
|
||||||
|
*space = (uint8_t *)((int)*space &
|
||||||
|
~(shdr->sh_addralign - 1));
|
||||||
|
else
|
||||||
|
*space = (uint8_t *)((int)*space & ~3);
|
||||||
|
|
||||||
|
destinations[elf_ndxscn(scn)] = *space;
|
||||||
|
|
||||||
|
assert(*space != NULL);
|
||||||
|
if((u32) *space < getApplicationEndAddr()){
|
||||||
|
DEBUG_FUNCTION_LINE("Not enough space to load function %s into memory at %08X.\n",name,*space);
|
||||||
|
goto exit_error;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUG_FUNCTION_LINE("Copy section %s to %08X\n",name,*space);
|
||||||
|
if (!ElfTools::elfLoadSection(elf, scn, shdr, *space)){
|
||||||
|
goto exit_error;
|
||||||
|
}
|
||||||
|
ElfTools::elfLoadSymbols(elf_ndxscn(scn), *space, 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 (!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("Set hook of module \"%s\" of type %08X to target %08X\n",getName().c_str(),hook->type,(void*) hook->target);
|
||||||
|
HookData * hook_data = new HookData((void *) hook->target,hook->type);
|
||||||
|
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("Set hook %s of module \"%s\" of type %08X to target %08X\n",entry->_function.name,getName().c_str(),entry->_function.library,entry->_function.target);
|
||||||
|
EntryData * entry_data = new EntryData(entry->_function.name,entry->_function.library, (void *) entry->_function.target, (void *) entry->_function.call_addr);
|
||||||
|
addEntryData(entry_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
159
loader/src/ModuleData.h
Normal file
159
loader/src/ModuleData.h
Normal file
@ -0,0 +1,159 @@
|
|||||||
|
/* 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 _MODULE_DATA_H_
|
||||||
|
#define _MODULE_DATA_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 ModuleData{
|
||||||
|
public:
|
||||||
|
ModuleData(std::string path, uint8_t ** space){
|
||||||
|
this->path = path;
|
||||||
|
if(checkFile()){
|
||||||
|
DEBUG_FUNCTION_LINE("Checkfile successfully, loading now \n");
|
||||||
|
this->loadedSuccessfully = load(space);
|
||||||
|
} else {
|
||||||
|
this->loadedSuccessfully = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
~ModuleData(){
|
||||||
|
for(size_t i = 0;i< entry_data_list.size();i++){
|
||||||
|
if(entry_data_list[i] != NULL){
|
||||||
|
free(entry_data_list[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(size_t i = 0;i< hook_data_list.size();i++){
|
||||||
|
if(hook_data_list[i] != NULL){
|
||||||
|
free(hook_data_list[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isLoadedSuccessfully(){
|
||||||
|
return loadedSuccessfully;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
bool checkFile();
|
||||||
|
|
||||||
|
bool load(uint8_t ** space);
|
||||||
|
|
||||||
|
bool loadElf(Elf *elf);
|
||||||
|
|
||||||
|
bool metadataRead(Elf *elf, Elf32_Sym *symtab, size_t symtab_count, size_t symtab_strndx);
|
||||||
|
|
||||||
|
bool elfLink(Elf *elf, size_t shndx, void *destination, Elf32_Sym *symtab, size_t symtab_count, size_t symtab_strndx, bool allow_globals);
|
||||||
|
|
||||||
|
bool linkModuleElf(Elf *elf, uint8_t **space);
|
||||||
|
|
||||||
|
bool loadedSuccessfully = false;
|
||||||
|
|
||||||
|
std::string path;
|
||||||
|
std::string name;
|
||||||
|
std::string author;
|
||||||
|
std::string version;
|
||||||
|
std::string license;
|
||||||
|
size_t size;
|
||||||
|
|
||||||
|
std::vector<EntryData *> entry_data_list;
|
||||||
|
std::vector<HookData *> hook_data_list;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
@ -1,430 +0,0 @@
|
|||||||
/* elf_utils.cpp
|
|
||||||
* 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 "elf_utils.h"
|
|
||||||
#include <wups.h>
|
|
||||||
#include <libelf.h>
|
|
||||||
#include <malloc.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <assert.h>
|
|
||||||
#include <utils/logger.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include "utils.h"
|
|
||||||
|
|
||||||
#define MODULE_RELOCATIONS_CAPCITY_DEFAULT 128
|
|
||||||
|
|
||||||
module_unresolved_relocation_t *module_relocations = NULL;
|
|
||||||
size_t module_relocations_count = 0;
|
|
||||||
size_t module_relocations_capacity = 0;
|
|
||||||
|
|
||||||
bool Module_ElfLoadSection(const Elf *elf, Elf_Scn *scn, const Elf32_Shdr *shdr,void *destination) {
|
|
||||||
|
|
||||||
assert(destination != NULL);
|
|
||||||
|
|
||||||
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 Module_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;
|
|
||||||
|
|
||||||
assert (*symtab == NULL);
|
|
||||||
*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 (!Module_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 Module_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 Module_ElfLink(size_t index, 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) {
|
|
||||||
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,
|
|
||||||
MODULE_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 = rel[i].r_offset;
|
|
||||||
reloc->type = ELF32_R_TYPE(rel[i].r_info);
|
|
||||||
reloc->addend =
|
|
||||||
*(int *)((char *)destination +
|
|
||||||
rel[i].r_offset);
|
|
||||||
|
|
||||||
continue;
|
|
||||||
} else
|
|
||||||
return false;
|
|
||||||
} default: {
|
|
||||||
if (symtab[symbol].st_other != 1)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
symbol_addr = symtab[symbol].st_value;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Module_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) {
|
|
||||||
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,
|
|
||||||
MODULE_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;
|
|
||||||
} else
|
|
||||||
return false;
|
|
||||||
} default: {
|
|
||||||
|
|
||||||
if (symtab[symbol].st_other != 1)
|
|
||||||
return false;
|
|
||||||
symbol_addr = symtab[symbol].st_value;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Module_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 Module_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("Module_ElfLinkOne01: %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:
|
|
||||||
DEBUG_FUNCTION_LINE("Module_ElfLinkOne01: %02X\n",type);
|
|
||||||
goto exit_error;
|
|
||||||
}
|
|
||||||
|
|
||||||
result = true;
|
|
||||||
exit_error:
|
|
||||||
if (!result) DEBUG_FUNCTION_LINE("Module_ElfLinkOne: exit_error\n");
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
@ -1,26 +0,0 @@
|
|||||||
#ifndef _ELF_UTILS_H_
|
|
||||||
#define _ELF_UTILS_H_
|
|
||||||
|
|
||||||
/* Main */
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <libelf.h>
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "module_parser.h"
|
|
||||||
|
|
||||||
bool Module_ElfLoadSection(const Elf *elf, Elf_Scn *scn, const Elf32_Shdr *shdr,void *destination);
|
|
||||||
bool Module_LoadElfSymtab(Elf *elf, Elf32_Sym **symtab, size_t *symtab_count, size_t *symtab_strndx);
|
|
||||||
void Module_ElfLoadSymbols(size_t shndx, const void *destination, Elf32_Sym *symtab, size_t symtab_count);
|
|
||||||
bool Module_ElfLink(size_t index, Elf *elf, size_t shndx, void *destination, Elf32_Sym *symtab, size_t symtab_count, size_t symtab_strndx, bool allow_globals);
|
|
||||||
bool Module_ElfLinkOne(char type, size_t offset, int addend, void *destination, uint32_t symbol_addr);
|
|
||||||
|
|
||||||
extern size_t module_relocations_count;
|
|
||||||
extern module_unresolved_relocation_t *module_relocations;
|
|
||||||
extern size_t module_relocations_capacity;
|
|
||||||
#endif
|
|
@ -1,362 +0,0 @@
|
|||||||
/* link_utils.cpp
|
|
||||||
* 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 "link_utils.h"
|
|
||||||
#include "elf_utils.h"
|
|
||||||
#include "utils.h"
|
|
||||||
#include <utils/utils.h>
|
|
||||||
#include <wups.h>
|
|
||||||
#include <libelf.h>
|
|
||||||
#include <malloc.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <assert.h>
|
|
||||||
#include <utils/logger.h>
|
|
||||||
#include <common/retain_vars.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <dynamic_libs/os_functions.h>
|
|
||||||
|
|
||||||
//TODO: Adjust this.
|
|
||||||
#define MODULE_ENTRIES_CAPACITY_DEFAULT 128
|
|
||||||
|
|
||||||
//TODO: Adjust this.
|
|
||||||
#define MODULE_HOOKS_CAPACITY_DEFAULT 128
|
|
||||||
|
|
||||||
wups_loader_hook_t *module_hooks = NULL;
|
|
||||||
size_t module_hooks_count = 0;
|
|
||||||
size_t module_hooks_capacity = 0;
|
|
||||||
|
|
||||||
wups_loader_entry_t *module_entries = NULL;
|
|
||||||
size_t module_entries_count = 0;
|
|
||||||
size_t module_entries_capacity = 0;
|
|
||||||
|
|
||||||
bool Module_ListLink(uint8_t **space) {
|
|
||||||
size_t i;
|
|
||||||
bool result = false;
|
|
||||||
|
|
||||||
for (i = 0; i < module_list_count; i++) {
|
|
||||||
if (!Module_LinkModule(i, module_list[i]->path, space))
|
|
||||||
goto exit_error;
|
|
||||||
}
|
|
||||||
|
|
||||||
result = true;
|
|
||||||
exit_error:
|
|
||||||
if (!result) DEBUG_FUNCTION_LINE("Module_ListLink: exit_error\n");
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Module_LinkModule(size_t index, const char *path, uint8_t **space) {
|
|
||||||
DEBUG_FUNCTION_LINE("Running Module_LinkModule for %s\n",path);
|
|
||||||
|
|
||||||
int fd = -1;
|
|
||||||
Elf *elf = NULL;
|
|
||||||
bool result = false;
|
|
||||||
|
|
||||||
/* check for compile errors */
|
|
||||||
assert(elf_version(EV_CURRENT) != EV_NONE);
|
|
||||||
|
|
||||||
fd = open(path, O_RDONLY, 0);
|
|
||||||
|
|
||||||
if (fd == -1)
|
|
||||||
goto exit_error;
|
|
||||||
|
|
||||||
elf = elf_begin(fd, ELF_C_READ, NULL);
|
|
||||||
|
|
||||||
if (elf == NULL)
|
|
||||||
goto exit_error;
|
|
||||||
|
|
||||||
switch (elf_kind(elf)) {
|
|
||||||
case ELF_K_AR:
|
|
||||||
/* TODO */
|
|
||||||
goto exit_error;
|
|
||||||
case ELF_K_ELF:
|
|
||||||
DEBUG_FUNCTION_LINE("Calling now Module_LinkModuleElf\n");
|
|
||||||
if (!Module_LinkModuleElf(index, elf, space))
|
|
||||||
goto exit_error;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
goto exit_error;
|
|
||||||
}
|
|
||||||
|
|
||||||
result = true;
|
|
||||||
exit_error:
|
|
||||||
if (!result) DEBUG_FUNCTION_LINE("Module_LinkModule: exit_error\n");
|
|
||||||
if (elf != NULL)
|
|
||||||
elf_end(elf);
|
|
||||||
if (fd != -1)
|
|
||||||
close(fd);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Module_LinkModuleElf(size_t index, Elf *elf, uint8_t **space) {
|
|
||||||
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;
|
|
||||||
|
|
||||||
if (!Module_LoadElfSymtab(elf, &symtab, &symtab_count, &symtab_strndx))
|
|
||||||
goto exit_error;
|
|
||||||
|
|
||||||
assert(symtab != NULL);
|
|
||||||
|
|
||||||
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*) Module_ListAllocate(
|
|
||||||
&module_entries, sizeof(wups_loader_entry_t),
|
|
||||||
entries_count, &module_entries_capacity,
|
|
||||||
&module_entries_count, MODULE_ENTRIES_CAPACITY_DEFAULT);
|
|
||||||
|
|
||||||
if (entries == NULL)
|
|
||||||
goto exit_error;
|
|
||||||
|
|
||||||
destinations[elf_ndxscn(scn)] = (uint8_t *)entries;
|
|
||||||
if (!Module_ElfLoadSection(elf, scn, shdr, entries))
|
|
||||||
goto exit_error;
|
|
||||||
Module_ElfLoadSymbols(elf_ndxscn(scn), entries, symtab, symtab_count);
|
|
||||||
|
|
||||||
int entries_offset = module_entries_count - entries_count;
|
|
||||||
|
|
||||||
for(int i = 0;i< entries_count;i++){
|
|
||||||
gbl_replacement_data.module_data[index].functions[i].entry_index = entries_offset +i;
|
|
||||||
gbl_replacement_data.module_data[index].number_used_functions++;
|
|
||||||
}
|
|
||||||
}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*) Module_ListAllocate(
|
|
||||||
&module_hooks, sizeof(wups_loader_hook_t),
|
|
||||||
hooks_count, &module_hooks_capacity,
|
|
||||||
&module_hooks_count, MODULE_HOOKS_CAPACITY_DEFAULT);
|
|
||||||
|
|
||||||
if (hooks == NULL)
|
|
||||||
goto exit_error;
|
|
||||||
|
|
||||||
destinations[elf_ndxscn(scn)] = (uint8_t *)hooks;
|
|
||||||
if (!Module_ElfLoadSection(elf, scn, shdr, hooks))
|
|
||||||
goto exit_error;
|
|
||||||
Module_ElfLoadSymbols(elf_ndxscn(scn), hooks, symtab, symtab_count);
|
|
||||||
|
|
||||||
int hook_offset = module_hooks_count - hooks_count;
|
|
||||||
|
|
||||||
for(int i = 0;i< hooks_count;i++){
|
|
||||||
gbl_replacement_data.module_data[index].hooks[i].hook_index = hook_offset +i;
|
|
||||||
gbl_replacement_data.module_data[index].number_used_hooks++;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
*space -= shdr->sh_size;
|
|
||||||
|
|
||||||
if (shdr->sh_addralign > 3)
|
|
||||||
*space = (uint8_t *)((int)*space &
|
|
||||||
~(shdr->sh_addralign - 1));
|
|
||||||
else
|
|
||||||
*space = (uint8_t *)((int)*space & ~3);
|
|
||||||
|
|
||||||
destinations[elf_ndxscn(scn)] = *space;
|
|
||||||
|
|
||||||
assert(*space != NULL);
|
|
||||||
if((u32) *space < getApplicationEndAddr()){
|
|
||||||
DEBUG_FUNCTION_LINE("Not enough space to load function %s into memory at %08X.\n",name,*space);
|
|
||||||
goto exit_error;
|
|
||||||
}
|
|
||||||
|
|
||||||
DEBUG_FUNCTION_LINE("Copy section %s to %08X\n",name,*space);
|
|
||||||
if (!Module_ElfLoadSection(elf, scn, shdr, *space))
|
|
||||||
goto exit_error;
|
|
||||||
Module_ElfLoadSymbols(
|
|
||||||
elf_ndxscn(scn), *space, 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 (!Module_ElfLink(
|
|
||||||
index, elf, elf_ndxscn(scn), destinations[elf_ndxscn(scn)],
|
|
||||||
symtab, symtab_count, symtab_strndx, true))
|
|
||||||
goto exit_error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
result = true;
|
|
||||||
exit_error:
|
|
||||||
if (!result) DEBUG_FUNCTION_LINE("Module_LinkModuleElf: exit_error\n");
|
|
||||||
if (destinations != NULL)
|
|
||||||
free(destinations);
|
|
||||||
if (symtab != NULL)
|
|
||||||
free(symtab);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
Relocation the real_XXX calls into the "replace_data" area of the replacement_data_function_t struct.
|
|
||||||
This function also fill the other data needed of the replacement_data_function_t struct.
|
|
||||||
**/
|
|
||||||
bool Module_ListLinkFinal() {
|
|
||||||
int has_error = 0;
|
|
||||||
bool result;
|
|
||||||
|
|
||||||
int relocations = 0;
|
|
||||||
DEBUG_FUNCTION_LINE("Found modules: %d\n",gbl_replacement_data.number_used_modules);
|
|
||||||
for(int module_index=0;module_index<gbl_replacement_data.number_used_modules;module_index++){
|
|
||||||
replacement_data_module_t * module_data = &gbl_replacement_data.module_data[module_index];
|
|
||||||
DEBUG_FUNCTION_LINE("Module name: %s\n",module_data->module_name);
|
|
||||||
for(int j=0;j<module_data->number_used_hooks;j++){
|
|
||||||
replacement_data_hook_t * hook_data = &module_data->hooks[j];
|
|
||||||
if(hook_data->hook_index > module_entries_count-1){
|
|
||||||
DEBUG_FUNCTION_LINE("Error. hook_index was too high: %d. maximum is %d\n",hook_data->hook_index,module_entries_count-1);
|
|
||||||
goto exit_error;
|
|
||||||
}
|
|
||||||
wups_loader_hook_t * hook = &module_hooks[hook_data->hook_index];
|
|
||||||
DEBUG_FUNCTION_LINE("Set hook %d of module \"%s\" of type %08X to target %08X\n",hook_data->hook_index,module_data->module_name,hook->type,(void*) hook->target);
|
|
||||||
hook_data->func_pointer = (void*) hook->target;
|
|
||||||
hook_data->type = hook->type;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
DEBUG_FUNCTION_LINE("number of used function: %d\n",module_data->number_used_functions);
|
|
||||||
for(int j=0;j<module_data->number_used_functions;j++){
|
|
||||||
replacement_data_function_t * function_data = &module_data->functions[j];
|
|
||||||
if(function_data->entry_index > module_entries_count-1){
|
|
||||||
DEBUG_FUNCTION_LINE("Error. entry_index was too high: %d. maximum is %d\n",function_data->entry_index,module_entries_count-1);
|
|
||||||
goto exit_error;
|
|
||||||
}
|
|
||||||
wups_loader_entry_t * entry = &module_entries[function_data->entry_index];
|
|
||||||
if(entry->_function.name != NULL){
|
|
||||||
strncpy(function_data->function_name,entry->_function.name,MAXIMUM_FUNCTION_NAME_LENGTH-1);
|
|
||||||
}else {
|
|
||||||
DEBUG_FUNCTION_LINE("WARNING NAME IS NULL\n");
|
|
||||||
}
|
|
||||||
function_data->library = entry->_function.library;
|
|
||||||
function_data->replaceAddr = (u32) entry->_function.target;
|
|
||||||
function_data->replaceCall = (u32) entry->_function.call_addr;
|
|
||||||
|
|
||||||
/*
|
|
||||||
We don't need this...
|
|
||||||
|
|
||||||
DEBUG_FUNCTION_LINE("Searching for relocations %d\n",module_relocations_count);
|
|
||||||
|
|
||||||
module_unresolved_relocation_t *reloc = NULL;
|
|
||||||
for (int relocation_index = 0;relocation_index < module_relocations_count;relocation_index++) {
|
|
||||||
DEBUG_FUNCTION_LINE("Try relocation %d\n",relocation_index);
|
|
||||||
if (module_relocations[relocation_index].module == module_index){
|
|
||||||
if(strcmp(entry->_function.real_function_name,module_relocations[relocation_index].name) == 0){
|
|
||||||
DEBUG_FUNCTION_LINE("Found the entry we want to replace %s\n",entry->_function.real_function_name);
|
|
||||||
reloc = &module_relocations[relocation_index];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(reloc != NULL){
|
|
||||||
u32 call_addr = (u32) &function_data->replace_data[0];
|
|
||||||
//DEBUG_FUNCTION_LINE("Found reloc. We need to find the symbol for: %s in lib %d\n",entry->_function.name,entry->_function.library);
|
|
||||||
//u32 call_addr = (u32) new_GetAddressOfFunction("OSFatal",WUPS_LOADER_LIBRARY_COREINIT);
|
|
||||||
DEBUG_FUNCTION_LINE("Relocating\n");
|
|
||||||
if (!Module_ElfLinkOne(reloc->type, reloc->offset, reloc->addend, reloc->address, (uint32_t)call_addr)){
|
|
||||||
goto exit_error;
|
|
||||||
}else{
|
|
||||||
relocations++;
|
|
||||||
DEBUG_FUNCTION_LINE("Success! relocated to %08X\n",call_addr);
|
|
||||||
}
|
|
||||||
}else{
|
|
||||||
|
|
||||||
}*/
|
|
||||||
}
|
|
||||||
}
|
|
||||||
module_relocations_count -= relocations;
|
|
||||||
|
|
||||||
//assert(entry_index == module_entries_count);
|
|
||||||
//assert(relocation_index == module_relocations_count);
|
|
||||||
|
|
||||||
if (has_error)
|
|
||||||
goto exit_error;
|
|
||||||
|
|
||||||
result = true;
|
|
||||||
exit_error:
|
|
||||||
if (!result) DEBUG_FUNCTION_LINE("Module_ListLinkFinal: exit_error\n");
|
|
||||||
//module_relocations_count = 0;
|
|
||||||
//module_relocations_capacity = 0;
|
|
||||||
if(module_relocations_count == 0){
|
|
||||||
free(module_relocations);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
@ -1,26 +0,0 @@
|
|||||||
#ifndef _LINK_UTILS_H_
|
|
||||||
#define _LINK_UTILS_H_
|
|
||||||
|
|
||||||
/* Main */
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <libelf.h>
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "module_parser.h"
|
|
||||||
|
|
||||||
bool Module_ListLink(uint8_t **space);
|
|
||||||
bool Module_LinkModule(size_t index, const char *path, uint8_t **space);
|
|
||||||
bool Module_LinkModuleElf(size_t index, Elf *elf, uint8_t **space);
|
|
||||||
bool Module_ListLinkFinal();
|
|
||||||
|
|
||||||
extern wups_loader_entry_t *module_entries;
|
|
||||||
extern size_t module_entries_count;
|
|
||||||
extern size_t module_entries_capacity;
|
|
||||||
|
|
||||||
#endif
|
|
@ -17,30 +17,26 @@
|
|||||||
#include <system/exception_handler.h>
|
#include <system/exception_handler.h>
|
||||||
#include "common/retain_vars.h"
|
#include "common/retain_vars.h"
|
||||||
#include "common/common.h"
|
#include "common/common.h"
|
||||||
|
#include "ModuleData.h"
|
||||||
|
|
||||||
#include <wups.h>
|
#include <wups.h>
|
||||||
#include <libelf.h>
|
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "module_parser.h"
|
|
||||||
#include "link_utils.h"
|
|
||||||
#include "elf_utils.h"
|
|
||||||
#include "patcher/function_patcher.h"
|
#include "patcher/function_patcher.h"
|
||||||
|
|
||||||
static void printModuleInfos();
|
static bool loadSamplePlugins();
|
||||||
static bool loadSamplePlugin();
|
|
||||||
static void printInfos();
|
|
||||||
static void printReplacementInfos();
|
|
||||||
static void ApplyPatches();
|
static void ApplyPatches();
|
||||||
void CallHook(wups_loader_hook_type_t hook_type);
|
void CallHook(wups_loader_hook_type_t hook_type);
|
||||||
static void RestorePatches();
|
static void RestorePatches();
|
||||||
s32 isInMiiMakerHBL();
|
s32 isInMiiMakerHBL();
|
||||||
|
|
||||||
|
static void copyDataIntoGlobalStruct(std::vector<ModuleData *>* modules);
|
||||||
|
static void loadElf(std::vector<ModuleData *>* modules, const char * elfPath, uint8_t ** space);
|
||||||
|
|
||||||
u8 isFirstBoot __attribute__((section(".data"))) = 1;
|
u8 isFirstBoot __attribute__((section(".data"))) = 1;
|
||||||
|
|
||||||
|
|
||||||
/* Entry point */
|
/* Entry point */
|
||||||
extern "C" int Menu_Main(int argc, char **argv){
|
extern "C" int Menu_Main(int argc, char **argv){
|
||||||
InitOSFunctionPointers();
|
InitOSFunctionPointers();
|
||||||
@ -56,16 +52,11 @@ extern "C" int Menu_Main(int argc, char **argv){
|
|||||||
|
|
||||||
if(isFirstBoot){
|
if(isFirstBoot){
|
||||||
memset((void*)&gbl_replacement_data,0,sizeof(gbl_replacement_data));
|
memset((void*)&gbl_replacement_data,0,sizeof(gbl_replacement_data));
|
||||||
if(!loadSamplePlugin()){
|
if(!loadSamplePlugins()){
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(module_relocations_count != 0){
|
|
||||||
DEBUG_FUNCTION_LINE("We still have undefined symbol. Make sure to link them in =/ Exiting!\n");
|
|
||||||
return EXIT_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Reset everything when were going back to the Mii Maker
|
//Reset everything when were going back to the Mii Maker
|
||||||
if(!isFirstBoot && isInMiiMakerHBL()){
|
if(!isFirstBoot && isInMiiMakerHBL()){
|
||||||
DEBUG_FUNCTION_LINE("Returing to the Homebrew Launcher!\n");
|
DEBUG_FUNCTION_LINE("Returing to the Homebrew Launcher!\n");
|
||||||
@ -78,6 +69,7 @@ extern "C" int Menu_Main(int argc, char **argv){
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(!isInMiiMakerHBL()){ //Starting the application
|
if(!isInMiiMakerHBL()){ //Starting the application
|
||||||
|
DEBUG_FUNCTION_LINE("Calling init hook.\n");
|
||||||
CallHook(WUPS_LOADER_HOOK_INIT_FUNCTION);
|
CallHook(WUPS_LOADER_HOOK_INIT_FUNCTION);
|
||||||
return EXIT_RELAUNCH_ON_LOAD;
|
return EXIT_RELAUNCH_ON_LOAD;
|
||||||
}
|
}
|
||||||
@ -120,7 +112,6 @@ void CallHook(wups_loader_hook_type_t hook_type){
|
|||||||
DEBUG_FUNCTION_LINE("Was not defined\n");
|
DEBUG_FUNCTION_LINE("Was not defined\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -144,100 +135,111 @@ s32 isInMiiMakerHBL(){
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool loadSamplePlugin(){
|
bool loadSamplePlugins(){
|
||||||
DEBUG_FUNCTION_LINE("Mount SD partition\n");
|
DEBUG_FUNCTION_LINE("Mount SD partition\n");
|
||||||
|
|
||||||
int res = 0;
|
int res = 0;
|
||||||
if((res = mount_sd_fat("sd")) >= 0){
|
if((res = mount_sd_fat("sd")) >= 0){
|
||||||
DEBUG_FUNCTION_LINE("Mounting successful\n");
|
DEBUG_FUNCTION_LINE("Mounting successful\n");
|
||||||
|
|
||||||
loadElf("sd:/wiiu/plugins/hid_to_vpad.mod");
|
std::vector<ModuleData *> modules;
|
||||||
loadElf("sd:/wiiu/plugins/sdcafiine.mod");
|
|
||||||
//loadElf("sd:/wiiu/plugins/example_plugin.mod");
|
|
||||||
loadElf("sd:/wiiu/plugins/padcon.mod");
|
|
||||||
loadElf("sd:/wiiu/plugins/swapdrc.mod");
|
|
||||||
|
|
||||||
if(module_list_count == 0){
|
|
||||||
DEBUG_FUNCTION_LINE("Found no valid modules! =( Exiting\n");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
DEBUG_FUNCTION_LINE("Found %d modules!\n",module_list_count);
|
|
||||||
|
|
||||||
printInfos();
|
|
||||||
|
|
||||||
DEBUG_FUNCTION_LINE("Relocating them now\n");
|
|
||||||
unsigned char * space = (unsigned char*)0x01000000;
|
unsigned char * space = (unsigned char*)0x01000000;
|
||||||
|
|
||||||
if(!Module_ListLink(&space)){
|
loadElf(&modules, "sd:/wiiu/plugins/hid_to_vpad.mod",&space);
|
||||||
return false;
|
loadElf(&modules, "sd:/wiiu/plugins/sdcafiine.mod",&space);
|
||||||
|
loadElf(&modules, "sd:/wiiu/plugins/padcon.mod",&space);
|
||||||
|
loadElf(&modules, "sd:/wiiu/plugins/swipswapme.mod",&space);
|
||||||
|
|
||||||
|
copyDataIntoGlobalStruct(&modules);
|
||||||
|
|
||||||
|
// Free memory.
|
||||||
|
for(size_t i = 0; i< modules.size();i++){
|
||||||
|
ModuleData * cur_module = modules[i];
|
||||||
|
if(cur_module != NULL){
|
||||||
|
free(cur_module);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Module_ListLinkFinal();
|
|
||||||
|
|
||||||
DEBUG_FUNCTION_LINE("Flush memory\n");
|
DEBUG_FUNCTION_LINE("Flush memory\n");
|
||||||
|
|
||||||
DCFlushRange ((void*)getApplicationEndAddr(),0x01000000-getApplicationEndAddr());
|
DCFlushRange ((void*)getApplicationEndAddr(),0x01000000-getApplicationEndAddr());
|
||||||
DCInvalidateRange((void*)getApplicationEndAddr(),0x01000000-getApplicationEndAddr());
|
DCInvalidateRange((void*)getApplicationEndAddr(),0x01000000-getApplicationEndAddr());
|
||||||
|
|
||||||
if(module_relocations_count != 0){
|
|
||||||
DEBUG_FUNCTION_LINE("We still have undefined symbol. Make sure to link them in =/ Exiting\n");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
DEBUG_FUNCTION_LINE("Printing some information before replacing the functions\n");
|
|
||||||
|
|
||||||
printReplacementInfos();
|
|
||||||
|
|
||||||
unmount_sd_fat("sd");
|
unmount_sd_fat("sd");
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void loadElf(const char * elfPath){
|
static void copyDataIntoGlobalStruct(std::vector<ModuleData *>* modules){
|
||||||
DEBUG_FUNCTION_LINE("Reading elf from path: %s\n",elfPath);
|
int module_index = 0;
|
||||||
|
// Copy data to global struct.
|
||||||
|
for(size_t i = 0; i< modules->size();i++){
|
||||||
|
ModuleData * cur_module = modules->at(i);
|
||||||
|
|
||||||
DEBUG_FUNCTION_LINE("Try to load %s\n",elfPath);
|
std::vector<EntryData *> entry_data_list = cur_module->getEntryDataList();
|
||||||
if(Module_CheckFile(elfPath)){
|
std::vector<HookData *> hook_data_list = cur_module->getHookDataList();
|
||||||
Module_Load(elfPath);
|
if(module_index >= MAXIMUM_MODULES ){
|
||||||
}
|
DEBUG_FUNCTION_LINE("Maximum of %d modules reached. %s won't be loaded!\n",MAXIMUM_MODULES,cur_module->getName().c_str());
|
||||||
}
|
continue;
|
||||||
|
}
|
||||||
|
if(entry_data_list.size() > MAXIMUM_FUNCTION_PER_MODULE){
|
||||||
|
DEBUG_FUNCTION_LINE("Module %s would replace to many function (%d, maximum is %d). It won't be loaded.\n",cur_module->getName().c_str(),entry_data_list.size(),MAXIMUM_FUNCTION_PER_MODULE);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(hook_data_list.size() > MAXIMUM_HOOKS_PER_MODULE){
|
||||||
|
DEBUG_FUNCTION_LINE("Module %s would set too many hooks (%d, maximum is %d). It won't be loaded.\n",cur_module->getName().c_str(),hook_data_list.size(),MAXIMUM_HOOKS_PER_MODULE);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
static void printReplacementInfos(){
|
|
||||||
DEBUG_FUNCTION_LINE("Found modules: %d\n",gbl_replacement_data.number_used_modules);
|
|
||||||
for(int module_index=0;module_index<gbl_replacement_data.number_used_modules;module_index++){
|
|
||||||
replacement_data_module_t * module_data = &gbl_replacement_data.module_data[module_index];
|
replacement_data_module_t * module_data = &gbl_replacement_data.module_data[module_index];
|
||||||
DEBUG_FUNCTION_LINE("Module name: %s\n",module_data->module_name);
|
|
||||||
DEBUG_FUNCTION_LINE("Functions that will be replaced: %d\n",module_data->number_used_functions);
|
strncpy(module_data->module_name,cur_module->getName().c_str(),MAXIMUM_MODULE_NAME_LENGTH-1);
|
||||||
for(int j=0;j<module_data->number_used_functions;j++){
|
|
||||||
|
for(size_t j = 0; j < entry_data_list.size();j++){
|
||||||
replacement_data_function_t * function_data = &module_data->functions[j];
|
replacement_data_function_t * function_data = &module_data->functions[j];
|
||||||
DEBUG_FUNCTION_LINE("[%d] function: %s from lib %d\n",j,function_data->function_name, function_data->library);
|
|
||||||
|
EntryData * cur_entry = entry_data_list[j];
|
||||||
|
DEBUG_FUNCTION_LINE("Adding entry \"%s\" for module \"%s\"\n",cur_entry->getName().c_str(),module_data->module_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();
|
||||||
|
|
||||||
|
module_data->number_used_functions++;
|
||||||
}
|
}
|
||||||
DEBUG_FUNCTION_LINE("--- function list end ---\n");
|
|
||||||
|
DEBUG_FUNCTION_LINE("Entries for module \"%s\": %d\n",module_data->module_name,module_data->number_used_functions);
|
||||||
|
|
||||||
|
for(size_t j = 0; j < hook_data_list.size();j++){
|
||||||
|
replacement_data_hook_t * hook_data = &module_data->hooks[j];
|
||||||
|
|
||||||
|
HookData * hook_entry = hook_data_list[j];
|
||||||
|
|
||||||
|
DEBUG_FUNCTION_LINE("Set hook for module \"%s\" of type %08X to target %08X\n",module_data->module_name,hook_entry->getType(),(void*) hook_entry->getFunctionPointer());
|
||||||
|
hook_data->func_pointer = (void*) hook_entry->getFunctionPointer();
|
||||||
|
hook_data->type = hook_entry->getType();
|
||||||
|
module_data->number_used_hooks++;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUG_FUNCTION_LINE("Hooks for module \"%s\": %d\n",module_data->module_name,module_data->number_used_hooks);
|
||||||
|
|
||||||
|
module_index++;
|
||||||
|
gbl_replacement_data.number_used_modules++;
|
||||||
}
|
}
|
||||||
DEBUG_FUNCTION_LINE("--- module list end ---\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void printInfos(){
|
static void loadElf(std::vector<ModuleData *>* modules, const char * elfPath, uint8_t ** space){
|
||||||
for (unsigned int i = 0; i < module_list_count; i++) {
|
DEBUG_FUNCTION_LINE("Try to load %s\n",elfPath);
|
||||||
DEBUG_FUNCTION_LINE("--- Module %d ---\n",i);
|
|
||||||
DEBUG_FUNCTION_LINE("name: %s\n",module_list[i]->name);
|
ModuleData * module = new ModuleData(elfPath,space);
|
||||||
DEBUG_FUNCTION_LINE("path: %s\n",module_list[i]->path);
|
if(module->isLoadedSuccessfully()){
|
||||||
DEBUG_FUNCTION_LINE("author: %s\n",module_list[i]->author);
|
DEBUG_FUNCTION_LINE("%s loading was successful!. \n", elfPath);
|
||||||
}
|
modules->push_back(module);
|
||||||
DEBUG_FUNCTION_LINE("--- Module list end ---\n");
|
} else {
|
||||||
for (unsigned int i = 0; i < module_entries_count; i++) {
|
DEBUG_FUNCTION_LINE("%s loading failed. \n", elfPath);
|
||||||
DEBUG_FUNCTION_LINE("--- Entry %d ---\n",i);
|
}
|
||||||
if( module_entries[i].type == WUPS_LOADER_ENTRY_FUNCTION ||
|
|
||||||
module_entries[i].type == WUPS_LOADER_ENTRY_FUNCTION_MANDATORY){
|
|
||||||
DEBUG_FUNCTION_LINE("library: %d \n",module_entries[i]._function.library);
|
|
||||||
DEBUG_FUNCTION_LINE("function: %s \n",module_entries[i]._function.name);
|
|
||||||
DEBUG_FUNCTION_LINE("pointer: %08X \n",module_entries[i]._function.target);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
DEBUG_FUNCTION_LINE("--- Entry list end ---\n");
|
|
||||||
for (unsigned int i = 0; i < module_relocations_count; i++) {
|
|
||||||
DEBUG_FUNCTION_LINE("--- Relocation %d ---\n",i);
|
|
||||||
DEBUG_FUNCTION_LINE("name: %s\n",module_relocations[i].name);
|
|
||||||
}
|
|
||||||
DEBUG_FUNCTION_LINE("--- Relocation list end ---\n");
|
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,20 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
* 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 _MAIN_H_
|
#ifndef _MAIN_H_
|
||||||
#define _MAIN_H_
|
#define _MAIN_H_
|
||||||
|
|
||||||
@ -9,9 +26,10 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <libelf.h>
|
||||||
|
|
||||||
//! C wrapper for our C++ functions
|
//! C wrapper for our C++ functions
|
||||||
int Menu_Main(int argc, char **argv);
|
int Menu_Main(int argc, char **argv);
|
||||||
void loadElf(const char * elfPath);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
@ -1,491 +0,0 @@
|
|||||||
/* module_parser.cpp
|
|
||||||
* 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 "module_parser.h"
|
|
||||||
#include "elf_utils.h"
|
|
||||||
#include <wups.h>
|
|
||||||
#include <libelf.h>
|
|
||||||
#include <malloc.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <assert.h>
|
|
||||||
#include <utils/logger.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include "common/retain_vars.h"
|
|
||||||
#include "utils.h"
|
|
||||||
|
|
||||||
bool module_has_error;
|
|
||||||
bool module_has_info;
|
|
||||||
|
|
||||||
#define MODULE_LIST_CAPACITY_DEFAULT 16
|
|
||||||
|
|
||||||
size_t module_list_size = 0;
|
|
||||||
module_metadata_t **module_list = NULL;
|
|
||||||
size_t module_list_count = 0;
|
|
||||||
static size_t module_list_capacity = 0;
|
|
||||||
|
|
||||||
static void Module_LoadElf(const char *path, Elf *elf);
|
|
||||||
static module_metadata_t *Module_MetadataRead(const char *path, size_t index, Elf *elf, Elf32_Sym *symtab, size_t symtab_count, size_t symtab_strndx);
|
|
||||||
|
|
||||||
bool Module_CheckFile(const char *path) {
|
|
||||||
const char *extension;
|
|
||||||
|
|
||||||
/* find the file extension */
|
|
||||||
extension = strrchr(path, '.');
|
|
||||||
if (extension == NULL){
|
|
||||||
extension = strchr(path, '\0');
|
|
||||||
}else{
|
|
||||||
extension++;
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(extension != NULL);
|
|
||||||
|
|
||||||
if (strcmp(extension, "mod") == 0 ||
|
|
||||||
strcmp(extension, "o") == 0 ||
|
|
||||||
strcmp(extension, "a") == 0 ||
|
|
||||||
strcmp(extension, "elf") == 0) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Module_Load(const char *path) {
|
|
||||||
int fd = -1;
|
|
||||||
Elf *elf = NULL;
|
|
||||||
|
|
||||||
/* check for compile errors */
|
|
||||||
if (elf_version(EV_CURRENT) == EV_NONE)
|
|
||||||
goto exit_error;
|
|
||||||
|
|
||||||
fd = open(path, O_RDONLY, 0);
|
|
||||||
|
|
||||||
if (fd == -1)
|
|
||||||
goto exit_error;
|
|
||||||
|
|
||||||
elf = elf_begin(fd, ELF_C_READ, NULL);
|
|
||||||
|
|
||||||
if (elf == NULL)
|
|
||||||
goto exit_error;
|
|
||||||
|
|
||||||
switch (elf_kind(elf)) {
|
|
||||||
case ELF_K_AR:
|
|
||||||
/* TODO */
|
|
||||||
DEBUG_FUNCTION_LINE("Warning: Ignoring '%s' - Archives not yet supported.\n", path);
|
|
||||||
module_has_info = true;
|
|
||||||
goto exit_error;
|
|
||||||
case ELF_K_ELF:
|
|
||||||
Module_LoadElf(path, elf);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
DEBUG_FUNCTION_LINE(
|
|
||||||
"Warning: Ignoring '%s' - Invalid ELF file.\n", path);
|
|
||||||
goto exit_error;
|
|
||||||
}
|
|
||||||
|
|
||||||
exit_error:
|
|
||||||
if (elf != NULL)
|
|
||||||
elf_end(elf);
|
|
||||||
if (fd != -1)
|
|
||||||
close(fd);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void Module_LoadElf(const char *path, Elf *elf) {
|
|
||||||
Elf_Scn *scn;
|
|
||||||
Elf32_Ehdr *ehdr;
|
|
||||||
char *ident;
|
|
||||||
size_t shstrndx, sz, symtab_count, i, symtab_strndx;
|
|
||||||
Elf32_Sym *symtab = NULL;
|
|
||||||
module_metadata_t *metadata = NULL;
|
|
||||||
module_metadata_t **list_ptr;
|
|
||||||
|
|
||||||
assert(elf != NULL);
|
|
||||||
assert(elf_kind(elf) == ELF_K_ELF);
|
|
||||||
|
|
||||||
ident = elf_getident(elf, &sz);
|
|
||||||
|
|
||||||
if (ident == NULL) {
|
|
||||||
DEBUG_FUNCTION_LINE("Warning: Ignoring '%s' - Invalid ELF header.\n", path);
|
|
||||||
module_has_info = true;
|
|
||||||
goto exit_error;
|
|
||||||
}
|
|
||||||
if (sz < 7) {
|
|
||||||
DEBUG_FUNCTION_LINE("Warning: Ignoring '%s' - Invalid ELF header.\n", path);
|
|
||||||
module_has_info = true;
|
|
||||||
goto exit_error;
|
|
||||||
}
|
|
||||||
if (ident[4] != ELFCLASS32) {
|
|
||||||
DEBUG_FUNCTION_LINE("Warning: Ignoring '%s' - Not 32 bit ELF.\n", path);
|
|
||||||
module_has_info = true;
|
|
||||||
goto exit_error;
|
|
||||||
}
|
|
||||||
if (ident[5] != ELFDATA2MSB) {
|
|
||||||
DEBUG_FUNCTION_LINE("Warning: Ignoring '%s' - Not Big Endian.\n", path);
|
|
||||||
module_has_info = true;
|
|
||||||
goto exit_error;
|
|
||||||
}
|
|
||||||
if (ident[6] != EV_CURRENT) {
|
|
||||||
DEBUG_FUNCTION_LINE("Warning: Ignoring '%s' - Unknown ELF version.\n", path);
|
|
||||||
module_has_info = true;
|
|
||||||
goto exit_error;
|
|
||||||
}
|
|
||||||
|
|
||||||
ehdr = elf32_getehdr(elf);
|
|
||||||
|
|
||||||
if (ehdr == NULL) {
|
|
||||||
DEBUG_FUNCTION_LINE("Warning: Ignoring '%s' - Invalid ELF header\n", path);
|
|
||||||
module_has_info = true;
|
|
||||||
goto exit_error;
|
|
||||||
}
|
|
||||||
if (ehdr->e_type != ET_REL) {
|
|
||||||
DEBUG_FUNCTION_LINE("Warning: Ignoring '%s' - Not relocatable ELF.\n", path);
|
|
||||||
module_has_info = true;
|
|
||||||
goto exit_error;
|
|
||||||
}
|
|
||||||
if (ehdr->e_machine != EM_PPC) {
|
|
||||||
DEBUG_FUNCTION_LINE("Warning: Ignoring '%s' - Architecture not EM_PPC.\n", path);
|
|
||||||
module_has_info = true;
|
|
||||||
goto exit_error;
|
|
||||||
}
|
|
||||||
if (ehdr->e_version != EV_CURRENT) {
|
|
||||||
DEBUG_FUNCTION_LINE("Warning: Ignoring '%s' - Unknown ELF version.\n", path);
|
|
||||||
module_has_info = true;
|
|
||||||
goto exit_error;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Module_LoadElfSymtab(elf, &symtab, &symtab_count, &symtab_strndx)) {
|
|
||||||
DEBUG_FUNCTION_LINE("Warning: Ignoring '%s' - Couldn't parse symtab.\n", path);
|
|
||||||
module_has_info = true;
|
|
||||||
goto exit_error;
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(symtab != NULL);
|
|
||||||
|
|
||||||
DEBUG_FUNCTION_LINE("Reading metadata from path %s.\n", path);
|
|
||||||
|
|
||||||
metadata = Module_MetadataRead(path, module_list_count, elf, symtab, symtab_count, symtab_strndx);
|
|
||||||
|
|
||||||
if (metadata == NULL) /* error reporting done inside method */
|
|
||||||
goto exit_error;
|
|
||||||
|
|
||||||
if (elf_getshdrstrndx(elf, &shstrndx) != 0) {
|
|
||||||
DEBUG_FUNCTION_LINE("Warning: Ignoring '%s' - Couldn't find shdrstndx.\n", path);
|
|
||||||
module_has_info = true;
|
|
||||||
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) {
|
|
||||||
metadata->size +=
|
|
||||||
shdr->sh_size / sizeof(wups_loader_entry_t) * 6*4;
|
|
||||||
} else if (strcmp(name, ".wups.hooks") == 0) {
|
|
||||||
metadata->size +=
|
|
||||||
shdr->sh_size / sizeof(wups_loader_hook_t) * 2*4;
|
|
||||||
} else {
|
|
||||||
metadata->size += shdr->sh_size;
|
|
||||||
/* add alignment padding to size */
|
|
||||||
if (shdr->sh_addralign > 3)
|
|
||||||
/* roundup to multiple of sh_addralign */
|
|
||||||
metadata->size +=
|
|
||||||
(-metadata->size & (shdr->sh_addralign - 1));
|
|
||||||
else
|
|
||||||
/* roundup to multiple of 4 */
|
|
||||||
metadata->size += (-metadata->size & 3);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* roundup to multiple of 4 */
|
|
||||||
metadata->size += (-metadata->size & 3);
|
|
||||||
|
|
||||||
strncpy(gbl_replacement_data.module_data[module_list_count].module_name,metadata->name,MAXIMUM_MODULE_NAME_LENGTH-1);
|
|
||||||
|
|
||||||
list_ptr = (module_metadata_t **)Module_ListAllocate(
|
|
||||||
&module_list, sizeof(module_metadata_t *), 1, &module_list_capacity,
|
|
||||||
&module_list_count, MODULE_LIST_CAPACITY_DEFAULT);
|
|
||||||
if (list_ptr == NULL) {
|
|
||||||
DEBUG_FUNCTION_LINE("Warning: Ignoring '%s' - ENOMEM.\n", path);
|
|
||||||
module_has_info = true;
|
|
||||||
goto exit_error;
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(module_list != NULL);
|
|
||||||
assert(module_list_count <= module_list_capacity);
|
|
||||||
|
|
||||||
*list_ptr = metadata;
|
|
||||||
module_list_size += metadata->size;
|
|
||||||
/* prevent the data being freed */
|
|
||||||
metadata = NULL;
|
|
||||||
|
|
||||||
gbl_replacement_data.number_used_modules++;
|
|
||||||
|
|
||||||
|
|
||||||
exit_error:
|
|
||||||
if (metadata != NULL)
|
|
||||||
free(metadata);
|
|
||||||
if (symtab != NULL)
|
|
||||||
free(symtab);
|
|
||||||
}
|
|
||||||
|
|
||||||
static module_metadata_t *Module_MetadataRead(const char *path, size_t index, Elf *elf, Elf32_Sym *symtab, size_t symtab_count, size_t symtab_strndx) {
|
|
||||||
char *metadata = NULL, *metadata_cur, *metadata_end, *tmp;
|
|
||||||
const char *game, *name, *author, *version, *license, *wups;
|
|
||||||
module_metadata_t *ret = NULL;
|
|
||||||
Elf_Scn *scn;
|
|
||||||
size_t shstrndx, entries_count;
|
|
||||||
|
|
||||||
if (elf_getshdrstrndx(elf, &shstrndx) != 0) {
|
|
||||||
DEBUG_FUNCTION_LINE("Warning: Ignoring '%s' - Couldn't find shstrndx\n", path);
|
|
||||||
module_has_info = true;
|
|
||||||
goto exit_error;
|
|
||||||
}
|
|
||||||
|
|
||||||
entries_count = 0;
|
|
||||||
|
|
||||||
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 (!Module_ElfLoadSection(elf, scn, shdr, metadata)) {
|
|
||||||
DEBUG_FUNCTION_LINE("Warning: Ignoring '%s' - Couldn't load .wups.meta.\n", path);
|
|
||||||
module_has_info = true;
|
|
||||||
goto exit_error;
|
|
||||||
}
|
|
||||||
|
|
||||||
Module_ElfLoadSymbols(
|
|
||||||
elf_ndxscn(scn), metadata, symtab, symtab_count);
|
|
||||||
|
|
||||||
if (!Module_ElfLink(
|
|
||||||
index, elf, elf_ndxscn(scn), metadata,
|
|
||||||
symtab, symtab_count, symtab_strndx, false)) {
|
|
||||||
DEBUG_FUNCTION_LINE("Warning: Ignoring '%s' - .wups.meta contains invalid relocations.\n", path);
|
|
||||||
module_has_info = true;
|
|
||||||
goto exit_error;
|
|
||||||
}
|
|
||||||
|
|
||||||
metadata_end = metadata + shdr->sh_size;
|
|
||||||
metadata_end[-1] = '\0';
|
|
||||||
} else if (strcmp(name, ".wups.load") == 0) {
|
|
||||||
entries_count = shdr->sh_size / sizeof(wups_loader_entry_t);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (metadata == NULL) {
|
|
||||||
DEBUG_FUNCTION_LINE("Warning: Ignoring '%s' - Not a WUPS module file.\n", path);
|
|
||||||
module_has_info = true;
|
|
||||||
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;
|
|
||||||
|
|
||||||
assert(metadata_cur >= metadata && metadata_cur < metadata_end);
|
|
||||||
|
|
||||||
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_MODULE_GAME "
|
|
||||||
"declarations.\n", path);
|
|
||||||
module_has_info = true;
|
|
||||||
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_MODULE_NAME "
|
|
||||||
"declarations.\n", path);
|
|
||||||
module_has_info = true;
|
|
||||||
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_MODULE_AUTHOR "
|
|
||||||
"declarations.\n", path);
|
|
||||||
module_has_info = true;
|
|
||||||
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_MODULE_VERSION "
|
|
||||||
"declarations.\n", path);
|
|
||||||
module_has_info = true;
|
|
||||||
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_MODULE_LICENSE "
|
|
||||||
"declarations.\n", path);
|
|
||||||
module_has_info = true;
|
|
||||||
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_MODULE_NAME "
|
|
||||||
"declarations.\n", path);
|
|
||||||
module_has_info = true;
|
|
||||||
goto exit_error;
|
|
||||||
}
|
|
||||||
wups = eq + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (game == NULL)
|
|
||||||
game = "";
|
|
||||||
if (wups == NULL || strcmp(wups, "0.1") != 0) {
|
|
||||||
DEBUG_FUNCTION_LINE("Warning: Ignoring '%s' - Unrecognised BSlug version.\n", path);
|
|
||||||
module_has_info = true;
|
|
||||||
goto exit_error;
|
|
||||||
}
|
|
||||||
if (name == NULL) {
|
|
||||||
DEBUG_FUNCTION_LINE(
|
|
||||||
"Warning: Ignoring '%s' - Missing WUPS_MODULE_NAME declaration.\n",
|
|
||||||
path);
|
|
||||||
module_has_info = true;
|
|
||||||
goto exit_error;
|
|
||||||
}
|
|
||||||
if (author == NULL) {
|
|
||||||
DEBUG_FUNCTION_LINE(
|
|
||||||
"Warning: Ignoring '%s' - Missing WUPS_MODULE_AUTHOR "
|
|
||||||
"declaration.\n", path);
|
|
||||||
module_has_info = true;
|
|
||||||
goto exit_error;
|
|
||||||
}
|
|
||||||
if (version == NULL) {
|
|
||||||
DEBUG_FUNCTION_LINE(
|
|
||||||
"Warning: Ignoring '%s' - Missing WUPS_MODULE_VERSION "
|
|
||||||
"declaration.\n", path);
|
|
||||||
module_has_info = true;
|
|
||||||
goto exit_error;
|
|
||||||
}
|
|
||||||
if (license == NULL) {
|
|
||||||
DEBUG_FUNCTION_LINE(
|
|
||||||
"Warning: Ignoring '%s' - Missing WUPS_MODULE_LICENSE "
|
|
||||||
"declaration.\n", path);
|
|
||||||
module_has_info = true;
|
|
||||||
goto exit_error;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = (module_metadata_t *)malloc(
|
|
||||||
sizeof(module_metadata_t) + strlen(path) +
|
|
||||||
strlen(game) + strlen(name) + strlen(author) +
|
|
||||||
strlen(version) + strlen(license) + 6);
|
|
||||||
if (ret == NULL) {
|
|
||||||
DEBUG_FUNCTION_LINE("Warning: Ignoring '%s' - Couldn't parse WUPS metadata.\n", path);
|
|
||||||
module_has_info = true;
|
|
||||||
goto exit_error;
|
|
||||||
}
|
|
||||||
|
|
||||||
tmp = (char *)(ret + 1);
|
|
||||||
strcpy(tmp, path);
|
|
||||||
ret->path = tmp;
|
|
||||||
tmp = tmp + strlen(path) + 1;
|
|
||||||
strcpy(tmp, name);
|
|
||||||
ret->name = tmp;
|
|
||||||
tmp = tmp + strlen(name) + 1;
|
|
||||||
strcpy(tmp, author);
|
|
||||||
ret->author = tmp;
|
|
||||||
tmp = tmp + strlen(author) + 1;
|
|
||||||
strcpy(tmp, version);
|
|
||||||
ret->version = tmp;
|
|
||||||
tmp = tmp + strlen(version) + 1;
|
|
||||||
strcpy(tmp, license);
|
|
||||||
ret->license = tmp;
|
|
||||||
ret->size = 0;
|
|
||||||
ret->entries_count = entries_count;
|
|
||||||
|
|
||||||
exit_error:
|
|
||||||
if (metadata != NULL)
|
|
||||||
free(metadata);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
@ -1,48 +0,0 @@
|
|||||||
#ifndef _MODULE_PARSER_H_
|
|
||||||
#define _MODULE_PARSER_H_
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <libelf.h>
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <wups.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
const char *path;
|
|
||||||
const char *name;
|
|
||||||
const char *author;
|
|
||||||
const char *version;
|
|
||||||
const char *license;
|
|
||||||
size_t size;
|
|
||||||
size_t entries_count;
|
|
||||||
} module_metadata_t;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
size_t module;
|
|
||||||
const char *name;
|
|
||||||
void *address;
|
|
||||||
size_t offset;
|
|
||||||
char type;
|
|
||||||
int addend;
|
|
||||||
} module_unresolved_relocation_t;
|
|
||||||
|
|
||||||
extern bool module_has_error;
|
|
||||||
/* whether or not to delay loading for debug messages. */
|
|
||||||
extern bool module_has_info;
|
|
||||||
|
|
||||||
extern size_t module_list_size;
|
|
||||||
extern module_metadata_t **module_list;
|
|
||||||
extern size_t module_list_count;
|
|
||||||
|
|
||||||
bool Module_CheckFile(const char *path);
|
|
||||||
void Module_Load(const char *path);
|
|
||||||
|
|
||||||
#endif
|
|
@ -62,7 +62,7 @@ struct replacement_data_hook_t{
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#define MAXIMUM_HOOKS_PER_MODULE 4
|
#define MAXIMUM_HOOKS_PER_MODULE 10
|
||||||
#define MAXIMUM_FUNCTION_PER_MODULE 100
|
#define MAXIMUM_FUNCTION_PER_MODULE 100
|
||||||
|
|
||||||
struct replacement_data_module_t{
|
struct replacement_data_module_t{
|
||||||
|
@ -38,32 +38,3 @@ void dumpHex(const void* data, size_t size) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void *Module_ListAllocate(void *list, size_t entry_size, size_t num, size_t *capacity, size_t *count, size_t default_capacity) {
|
|
||||||
void *result;
|
|
||||||
|
|
||||||
while (*capacity < *count + num) {
|
|
||||||
if (*count == 0) {
|
|
||||||
*(void **)list = malloc(entry_size * default_capacity);
|
|
||||||
|
|
||||||
if (*(void **)list == NULL)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
*capacity = default_capacity;
|
|
||||||
} else {
|
|
||||||
void *temp;
|
|
||||||
|
|
||||||
temp = realloc(*(void **)list, entry_size * *capacity * 2);
|
|
||||||
if (temp == NULL)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
*(void **)list = temp;
|
|
||||||
*capacity = *capacity * 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
result = *(char **)list + entry_size * *count;
|
|
||||||
(*count) += num;
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
@ -12,6 +12,4 @@ void dumpHex(const void* data, size_t size);
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void *Module_ListAllocate(void *list, size_t entry_size, size_t num,size_t *capacity, size_t *count, size_t default_capacity);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
x
Reference in New Issue
Block a user