mirror of
https://github.com/wiiu-env/WiiUPluginSystem.git
synced 2024-11-05 10:25:10 +01:00
[Loader] Started to work on the module parsing
Based on the original brainslug code with some changes. Currently it's possible to parse the meta data.
This commit is contained in:
parent
b0f7567243
commit
76271cee58
432
loader/src/elf_utils.cpp
Normal file
432
loader/src/elf_utils.cpp
Normal file
@ -0,0 +1,432 @@
|
||||
/* 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>
|
||||
|
||||
int Module_ElfLoadSection(const Elf *elf, Elf_Scn *scn, const Elf32_Shdr *shdr, void *destination) {
|
||||
DEBUG_FUNCTION_LINE("\n");
|
||||
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 1;
|
||||
} case SHT_NOBITS: {
|
||||
memset(destination, 0, shdr->sh_size);
|
||||
return 1;
|
||||
} default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int Module_LoadElfSymtab(Elf *elf, Elf32_Sym **symtab, size_t *symtab_count,size_t *symtab_strndx) {
|
||||
Elf_Scn *scn;
|
||||
int result = 0;
|
||||
|
||||
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 shstrndx;
|
||||
if (elf_getshdrstrndx(elf, &shstrndx) == 0) {
|
||||
char* name = elf_strptr(elf, shstrndx, shdr->sh_name);
|
||||
if (name != NULL){
|
||||
DEBUG_FUNCTION_LINE("SHT_SYMTAB name: %s\n",name);
|
||||
}else{
|
||||
DEBUG_FUNCTION_LINE("Name null\n");
|
||||
}
|
||||
}else{
|
||||
DEBUG_FUNCTION_LINE("Couldn't find shstrndx\n");
|
||||
}
|
||||
|
||||
|
||||
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 = 1;
|
||||
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(module_information_t * module_information, Elf *elf, size_t shndx, void *destination,Elf32_Sym *symtab, size_t symtab_count, size_t symtab_strndx,int allow_globals) {
|
||||
DEBUG_FUNCTION_LINE("In Module_ElfLink\n");
|
||||
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;
|
||||
DEBUG_FUNCTION_LINE("shdr->sh_type: %d\n",shdr->sh_type);
|
||||
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: {
|
||||
DEBUG_FUNCTION_LINE("SHN_UNDEF\n");
|
||||
if (allow_globals) {
|
||||
module_unresolved_relocation_t *reloc;
|
||||
char *name;
|
||||
|
||||
reloc = (module_unresolved_relocation_t*) malloc(sizeof(module_unresolved_relocation_t));
|
||||
if (reloc == NULL){
|
||||
DEBUG_FUNCTION_LINE("WARNING: failed to allocate space for relocate struct.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
name = elf_strptr(elf, symtab_strndx, symtab[symbol].st_name);
|
||||
|
||||
if (name == NULL) {
|
||||
DEBUG_FUNCTION_LINE("WARNING: name == NULL.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
reloc->name = strdup(name);
|
||||
if (reloc->name == NULL) {
|
||||
DEBUG_FUNCTION_LINE("WARNING: strdup failed.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
|
||||
DEBUG_FUNCTION_LINE("Relocate push_back!.\n");
|
||||
|
||||
module_information->rel.push_back(reloc);
|
||||
|
||||
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 = (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: {
|
||||
DEBUG_FUNCTION_LINE("SHN_UNDEF2\n");
|
||||
if (allow_globals) {
|
||||
module_unresolved_relocation_t *reloc;
|
||||
char *name;
|
||||
|
||||
reloc = (module_unresolved_relocation_t*) malloc(sizeof(module_unresolved_relocation_t));
|
||||
if (reloc == NULL){
|
||||
DEBUG_FUNCTION_LINE("WARNING: failed to allocate space for relocate struct.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
name = elf_strptr(elf, symtab_strndx, symtab[symbol].st_name);
|
||||
|
||||
if (name == NULL) {
|
||||
DEBUG_FUNCTION_LINE("WARNING: name == NULL.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
reloc->name = strdup(name);
|
||||
if (reloc->name == NULL) {
|
||||
DEBUG_FUNCTION_LINE("WARNING: strdup failed.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
reloc->address = destination;
|
||||
reloc->offset = rela[i].r_offset;
|
||||
reloc->type = ELF32_R_TYPE(rela[i].r_info);
|
||||
reloc->addend = rela[i].r_addend;
|
||||
|
||||
DEBUG_FUNCTION_LINE("Relocate push_back!.\n");
|
||||
|
||||
module_information->rel.push_back(reloc);
|
||||
|
||||
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 1;
|
||||
}
|
||||
|
||||
int Module_ElfLinkOne(char type, size_t offset, int addend, void *destination, uint32_t symbol_addr) {
|
||||
DEBUG_FUNCTION_LINE("Module_ElfLinkOne\n");
|
||||
int value;
|
||||
char *target = (char *)destination + offset;
|
||||
int result = 0;
|
||||
|
||||
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_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:
|
||||
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_REL24: {
|
||||
*(int *)target =
|
||||
(*(int *)target & 0xfc000003) | (value & 0x03fffffc);
|
||||
break;
|
||||
} case R_PPC_ADDR16:
|
||||
case R_PPC_UADDR16:
|
||||
case R_PPC_EMB_NADDR16: {
|
||||
*(short *)target = value;
|
||||
break;
|
||||
} case R_PPC_ADDR16_HI:
|
||||
case R_PPC_SECTOFF_HI:
|
||||
case R_PPC_EMB_NADDR16_HI: {
|
||||
*(short *)target = value >> 16;
|
||||
break;
|
||||
} case R_PPC_ADDR16_HA:
|
||||
case R_PPC_SECTOFF_HA:
|
||||
case R_PPC_EMB_NADDR16_HA: {
|
||||
*(short *)target = (value >> 16) + ((value >> 15) & 1);
|
||||
break;
|
||||
} case R_PPC_ADDR16_LO:
|
||||
case R_PPC_SECTOFF_LO:
|
||||
case R_PPC_EMB_NADDR16_LO: {
|
||||
*(short *)target = value & 0xffff;
|
||||
break;
|
||||
} case R_PPC_ADDR14:
|
||||
case R_PPC_REL14: {
|
||||
*(int *)target =
|
||||
(*(int *)target & 0xffff0003) | (value & 0x0000fffc);
|
||||
break;
|
||||
} case R_PPC_ADDR14_BRTAKEN:
|
||||
case R_PPC_REL14_BRTAKEN: {
|
||||
*(int *)target =
|
||||
(*(int *)target & 0xffdf0003) | (value & 0x0000fffc) |
|
||||
0x00200000;
|
||||
break;
|
||||
} case R_PPC_ADDR14_BRNTAKEN:
|
||||
case R_PPC_REL14_BRNTAKEN: {
|
||||
*(int *)target =
|
||||
(*(int *)target & 0xffdf0003) | (value & 0x0000fffc);
|
||||
break;
|
||||
} case R_PPC_ADDR30: {
|
||||
*(int *)target =
|
||||
(*(int *)target & 0x00000003) | (value & 0xfffffffc);
|
||||
break;
|
||||
} default:
|
||||
goto exit_error;
|
||||
}
|
||||
|
||||
result = 1;
|
||||
exit_error:
|
||||
if (!result) DEBUG_FUNCTION_LINE("Module_ElfLinkOne: exit_error\n");
|
||||
return result;
|
||||
}
|
24
loader/src/elf_utils.h
Normal file
24
loader/src/elf_utils.h
Normal file
@ -0,0 +1,24 @@
|
||||
#ifndef _ELF_UTILS_H_
|
||||
#define _ELF_UTILS_H_
|
||||
|
||||
/* Main */
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <libelf.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#include "module_parser.h"
|
||||
|
||||
int Module_ElfLoadSection(const Elf *elf, Elf_Scn *scn, const Elf32_Shdr *shdr, void *destination);
|
||||
int 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(module_information_t * module_information, Elf *elf, size_t shndx, void *destination,Elf32_Sym *symtab, size_t symtab_count, size_t symtab_strndx,int allow_globals);
|
||||
int Module_ElfLinkOne(char type, size_t offset, int addend, void *destination, uint32_t symbol_addr);
|
||||
void *Module_ListAllocate(void *list, size_t entry_size, size_t num, size_t *capacity, size_t *count, size_t default_capacity);
|
||||
|
||||
#endif
|
@ -14,9 +14,12 @@
|
||||
#include <system/exception_handler.h>
|
||||
#include "common/common.h"
|
||||
|
||||
#include <wups.h>
|
||||
#include <libelf.h>
|
||||
#include "version.h"
|
||||
#include "main.h"
|
||||
#include "utils.h"
|
||||
#include "module_parser.h"
|
||||
|
||||
/* Entry point */
|
||||
extern "C" int Menu_Main(int argc, char **argv){
|
||||
@ -62,4 +65,11 @@ void loadAndProcessElf(const char * elfPath){
|
||||
dumpHex(elfData,dump_size);
|
||||
}
|
||||
|
||||
DEBUG_FUNCTION_LINE("Now try to use brainslug code\n");
|
||||
if(Module_CheckFile(elfPath)){
|
||||
module_information_t * moduleInformation = Module_LoadModuleInformation(elfPath);
|
||||
if(moduleInformation != NULL){
|
||||
printModuleInformation(moduleInformation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
505
loader/src/module_parser.cpp
Normal file
505
loader/src/module_parser.cpp
Normal file
@ -0,0 +1,505 @@
|
||||
/* 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>
|
||||
|
||||
static module_information_t* Module_LoadMetaDataFromElf(const char *path, Elf *elf);
|
||||
static module_information_t* Module_ModuleInformationRead(const char *path, Elf *elf, Elf32_Sym *symtab, size_t symtab_count, size_t symtab_strndx);
|
||||
|
||||
void printModuleInformation(module_information_t* module_information){
|
||||
if(module_information == NULL){
|
||||
DEBUG_FUNCTION_LINE("module_information is null\n");
|
||||
}
|
||||
|
||||
module_metadata_t * metadata = module_information->metadata;
|
||||
std::vector<module_unresolved_relocation_t *> relocations = module_information->rel;
|
||||
DEBUG_FUNCTION_LINE("relocations size: %d\n",relocations.size());
|
||||
for (std::vector<module_unresolved_relocation_t *>::iterator it = relocations.begin() ; it != relocations.end(); ++it){
|
||||
module_unresolved_relocation_t * relo = *it;
|
||||
DEBUG_FUNCTION_LINE("RELOCATION INFO %08X\n",relo);
|
||||
}
|
||||
|
||||
|
||||
if(metadata != NULL){
|
||||
if(metadata->author != NULL){
|
||||
DEBUG_FUNCTION_LINE("Author: %s.\n", metadata->author);
|
||||
}else{
|
||||
DEBUG_FUNCTION_LINE("Author: is null\n");
|
||||
}
|
||||
if(metadata->license != NULL){
|
||||
DEBUG_FUNCTION_LINE("License: %s.\n", metadata->license);
|
||||
}else{
|
||||
DEBUG_FUNCTION_LINE("License: is null\n");
|
||||
}
|
||||
if(metadata->name != NULL){
|
||||
DEBUG_FUNCTION_LINE("Name: %s.\n", metadata->name);
|
||||
}else{
|
||||
DEBUG_FUNCTION_LINE("Name: is null\n");
|
||||
}
|
||||
DEBUG_FUNCTION_LINE("Path: %s \n",metadata->path);
|
||||
DEBUG_FUNCTION_LINE("Size: %d \n",metadata->size);
|
||||
DEBUG_FUNCTION_LINE("entries_count: %d \n",metadata->entries_count);
|
||||
}else{
|
||||
DEBUG_FUNCTION_LINE("metadata is null\n");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
module_information_t* Module_LoadModuleInformation(const char *path) {
|
||||
DEBUG_FUNCTION_LINE("Loading path: %s\n", path);
|
||||
|
||||
module_information_t* result = NULL;
|
||||
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 = 1;
|
||||
goto exit_error;
|
||||
case ELF_K_ELF:
|
||||
DEBUG_FUNCTION_LINE("Module_LoadElf(path, elf);\n");
|
||||
result = Module_LoadMetaDataFromElf(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);
|
||||
return result;
|
||||
}
|
||||
|
||||
module_information_t* Module_LoadMetaDataFromElf(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_information_t* result = NULL;
|
||||
|
||||
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 = 1;
|
||||
goto exit_error;
|
||||
}
|
||||
if (sz < 7) {
|
||||
DEBUG_FUNCTION_LINE("Warning: Ignoring '%s' - Invalid ELF header.\n", path);
|
||||
//module_has_info = 1;
|
||||
goto exit_error;
|
||||
}
|
||||
if (ident[4] != ELFCLASS32) {
|
||||
DEBUG_FUNCTION_LINE("Warning: Ignoring '%s' - Not 32 bit ELF.\n", path);
|
||||
//module_has_info = 1;
|
||||
goto exit_error;
|
||||
}
|
||||
if (ident[5] != ELFDATA2MSB) {
|
||||
DEBUG_FUNCTION_LINE("Warning: Ignoring '%s' - Not Big Endian.\n", path);
|
||||
//module_has_info = 1;
|
||||
goto exit_error;
|
||||
}
|
||||
if (ident[6] != EV_CURRENT) {
|
||||
DEBUG_FUNCTION_LINE("Warning: Ignoring '%s' - Unknown ELF version.\n", path);
|
||||
//module_has_info = 1;
|
||||
goto exit_error;
|
||||
}
|
||||
|
||||
ehdr = elf32_getehdr(elf);
|
||||
|
||||
if (ehdr == NULL) {
|
||||
DEBUG_FUNCTION_LINE("Warning: Ignoring '%s' - Invalid ELF header\n", path);
|
||||
//module_has_info = 1;
|
||||
goto exit_error;
|
||||
}
|
||||
if (ehdr->e_type != ET_REL) {
|
||||
DEBUG_FUNCTION_LINE("Warning: Ignoring '%s' - Not relocatable ELF.\n", path);
|
||||
//module_has_info = 1;
|
||||
goto exit_error;
|
||||
}
|
||||
if (ehdr->e_machine != EM_PPC) {
|
||||
DEBUG_FUNCTION_LINE("Warning: Ignoring '%s' - Architecture not EM_PPC.\n", path);
|
||||
//module_has_info = 1;
|
||||
goto exit_error;
|
||||
}
|
||||
if (ehdr->e_version != EV_CURRENT) {
|
||||
DEBUG_FUNCTION_LINE("Warning: Ignoring '%s' - Unknown ELF version.\n", path);
|
||||
//module_has_info = 1;
|
||||
goto exit_error;
|
||||
}
|
||||
|
||||
|
||||
DEBUG_FUNCTION_LINE("Loading Elf symtab\n");
|
||||
if (!Module_LoadElfSymtab(elf, &symtab, &symtab_count, &symtab_strndx)) {
|
||||
DEBUG_FUNCTION_LINE("Warning: Ignoring '%s' - Couldn't parse symtab.\n", path);
|
||||
//module_has_info = 1;
|
||||
goto exit_error;
|
||||
}
|
||||
|
||||
assert(symtab != NULL);
|
||||
|
||||
result = Module_ModuleInformationRead(path, elf, symtab, symtab_count, symtab_strndx);
|
||||
|
||||
if (result == NULL){
|
||||
DEBUG_FUNCTION_LINE("Module_ModuleInformationRead was null\n");
|
||||
goto exit_error;
|
||||
}
|
||||
|
||||
metadata = result->metadata;
|
||||
|
||||
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 = 1;
|
||||
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) * 12;
|
||||
} 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);
|
||||
return result;
|
||||
|
||||
exit_error:
|
||||
if (metadata != NULL)
|
||||
free(metadata);
|
||||
if (symtab != NULL)
|
||||
free(symtab);
|
||||
return result;
|
||||
}
|
||||
|
||||
static module_information_t *Module_ModuleInformationRead(const char *path, Elf *elf, Elf32_Sym *symtab, size_t symtab_count, size_t symtab_strndx) {
|
||||
char *metadata = NULL, *metadata_cur, *metadata_end, *tmp;
|
||||
const char *name, *author, *version, *license, *wups;
|
||||
module_metadata_t *ret = NULL;
|
||||
module_information_t *result = NULL;
|
||||
Elf_Scn *scn;
|
||||
size_t shstrndx, entries_count;
|
||||
|
||||
result = (module_information_t *) malloc(sizeof(module_information_t));
|
||||
if (result == NULL){
|
||||
DEBUG_FUNCTION_LINE("Warning: Ignoring '%s' - couldn't allocate memory for meta information struct.\n", path);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (elf_getshdrstrndx(elf, &shstrndx) != 0) {
|
||||
DEBUG_FUNCTION_LINE("Warning: Ignoring '%s' - Couldn't find shstrndx\n", path);
|
||||
//module_has_info = 1;
|
||||
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) {
|
||||
DEBUG_FUNCTION_LINE("In section \"%s\" \n",name);
|
||||
|
||||
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 = 1;
|
||||
goto exit_error;
|
||||
}
|
||||
|
||||
Module_ElfLoadSymbols(elf_ndxscn(scn), metadata, symtab, symtab_count);
|
||||
|
||||
if (!Module_ElfLink(result, elf, elf_ndxscn(scn), metadata, symtab, symtab_count, symtab_strndx, 0)) {
|
||||
DEBUG_FUNCTION_LINE(
|
||||
"Warning: Ignoring '%s' - .wups.meta contains invalid "
|
||||
"relocations.\n", path);
|
||||
//module_has_info = 1;
|
||||
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 = 1;
|
||||
goto exit_error;
|
||||
}
|
||||
|
||||
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, "name", eq - metadata_cur) == 0) {
|
||||
if (name != NULL) {
|
||||
DEBUG_FUNCTION_LINE(
|
||||
"Warning: Ignoring '%s' - Multiple WUPS_MODULE_NAME "
|
||||
"declarations.\n", path);
|
||||
//module_has_info = 1;
|
||||
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 = 1;
|
||||
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 = 1;
|
||||
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 = 1;
|
||||
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 = 1;
|
||||
goto exit_error;
|
||||
}
|
||||
wups = eq + 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (wups == NULL || strcmp(wups, "0.1") != 0) {
|
||||
DEBUG_FUNCTION_LINE("Warning: Ignoring '%s' - Unrecognised BSlug version.\n", path);
|
||||
//module_has_info = 1;
|
||||
goto exit_error;
|
||||
}
|
||||
if (name == NULL) {
|
||||
DEBUG_FUNCTION_LINE(
|
||||
"Warning: Ignoring '%s' - Missing WUPS_MODULE_NAME declaration.\n",
|
||||
path);
|
||||
//module_has_info = 1;
|
||||
goto exit_error;
|
||||
}
|
||||
if (author == NULL) {
|
||||
DEBUG_FUNCTION_LINE(
|
||||
"Warning: Ignoring '%s' - Missing WUPS_MODULE_AUTHOR "
|
||||
"declaration.\n", path);
|
||||
//module_has_info = 1;
|
||||
goto exit_error;
|
||||
}
|
||||
if (version == NULL) {
|
||||
DEBUG_FUNCTION_LINE(
|
||||
"Warning: Ignoring '%s' - Missing WUPS_MODULE_VERSION "
|
||||
"declaration.\n", path);
|
||||
//module_has_info = 1;
|
||||
goto exit_error;
|
||||
}
|
||||
if (license == NULL) {
|
||||
DEBUG_FUNCTION_LINE(
|
||||
"Warning: Ignoring '%s' - Missing WUPS_MODULE_LICENSE "
|
||||
"declaration.\n", path);
|
||||
//module_has_info = 1;
|
||||
goto exit_error;
|
||||
}
|
||||
|
||||
ret = (module_metadata_t *) malloc(sizeof(module_metadata_t) + strlen(path) +
|
||||
strlen(name) + strlen(author) +
|
||||
strlen(version) + strlen(license) + 6);
|
||||
if (ret == NULL) {
|
||||
DEBUG_FUNCTION_LINE("Warning: Ignoring '%s' - Couldn't parse BSlug metadata.\n", path);
|
||||
//module_has_info = 1;
|
||||
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;
|
||||
|
||||
result->metadata = ret;
|
||||
exit_error:
|
||||
if (metadata != NULL)
|
||||
free(metadata);
|
||||
|
||||
return result;
|
||||
}
|
48
loader/src/module_parser.h
Normal file
48
loader/src/module_parser.h
Normal file
@ -0,0 +1,48 @@
|
||||
#ifndef _MODULE_PARSER_H_
|
||||
#define _MODULE_PARSER_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <libelf.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <vector>
|
||||
|
||||
typedef struct {
|
||||
const char *path;
|
||||
const char *game;
|
||||
const char *name;
|
||||
const char *author;
|
||||
const char *version;
|
||||
const char *license;
|
||||
size_t size;
|
||||
size_t entries_count;
|
||||
} module_metadata_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
const char *name;
|
||||
void *address;
|
||||
size_t offset;
|
||||
char type;
|
||||
int addend;
|
||||
} module_unresolved_relocation_t;
|
||||
|
||||
typedef struct {
|
||||
std::vector<module_unresolved_relocation_t *> rel;
|
||||
module_metadata_t * metadata;
|
||||
} module_information_t;
|
||||
|
||||
bool Module_CheckFile(const char *path);
|
||||
void printModuleInformation(module_information_t* module_information);
|
||||
module_information_t* Module_LoadModuleInformation(const char *path);
|
||||
|
||||
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user