From 0aca202ae936d3fccbab34f36d9246e0598849a5 Mon Sep 17 00:00:00 2001 From: bunnei Date: Mon, 16 Jun 2014 18:03:13 -0400 Subject: Loader: Moved elf and loader modules to a "loader" subdirectory. --- src/citra/citra.cpp | 2 +- src/citra_qt/bootmanager.cpp | 2 +- src/citra_qt/main.cpp | 3 +- src/core/CMakeLists.txt | 10 +- src/core/core.vcxproj | 12 +- src/core/core.vcxproj.filters | 34 ++--- src/core/elf/elf_reader.cpp | 190 ---------------------------- src/core/elf/elf_reader.h | 75 ----------- src/core/elf/elf_types.h | 281 ----------------------------------------- src/core/loader.cpp | 205 ------------------------------ src/core/loader.h | 54 -------- src/core/loader/elf_reader.cpp | 190 ++++++++++++++++++++++++++++ src/core/loader/elf_reader.h | 75 +++++++++++ src/core/loader/elf_types.h | 281 +++++++++++++++++++++++++++++++++++++++++ src/core/loader/loader.cpp | 205 ++++++++++++++++++++++++++++++ src/core/loader/loader.h | 54 ++++++++ 16 files changed, 839 insertions(+), 834 deletions(-) delete mode 100644 src/core/elf/elf_reader.cpp delete mode 100644 src/core/elf/elf_reader.h delete mode 100644 src/core/elf/elf_types.h delete mode 100644 src/core/loader.cpp delete mode 100644 src/core/loader.h create mode 100644 src/core/loader/elf_reader.cpp create mode 100644 src/core/loader/elf_reader.h create mode 100644 src/core/loader/elf_types.h create mode 100644 src/core/loader/loader.cpp create mode 100644 src/core/loader/loader.h diff --git a/src/citra/citra.cpp b/src/citra/citra.cpp index 5a8642d1..f6bb10f2 100644 --- a/src/citra/citra.cpp +++ b/src/citra/citra.cpp @@ -8,7 +8,7 @@ #include "core/system.h" #include "core/core.h" -#include "core/loader.h" +#include "core/loader/loader.h" #include "citra/emu_window/emu_window_glfw.h" diff --git a/src/citra_qt/bootmanager.cpp b/src/citra_qt/bootmanager.cpp index f8511641..421b2af5 100644 --- a/src/citra_qt/bootmanager.cpp +++ b/src/citra_qt/bootmanager.cpp @@ -5,7 +5,7 @@ #include "bootmanager.hxx" #include "core/core.h" -#include "core/loader.h" +#include "core/loader/loader.h" #include "core/hw/hw.h" #include "video_core/video_core.h" diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp index 087716c0..cff0b6a2 100644 --- a/src/citra_qt/main.cpp +++ b/src/citra_qt/main.cpp @@ -23,9 +23,10 @@ #include "debugger/graphics_cmdlists.hxx" #include "core/system.h" -#include "core/loader.h" #include "core/core.h" +#include "core/loader/loader.h" #include "core/arm/disassembler/load_symbol_map.h" + #include "version.h" diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 7116b88e..2361fd2e 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -1,6 +1,7 @@ set(SRCS core.cpp core_timing.cpp - loader.cpp + loader/elf_reader.cpp + loader/loader.cpp mem_map.cpp mem_map_funcs.cpp system.cpp @@ -27,7 +28,6 @@ set(SRCS core.cpp arm/interpreter/mmu/tlb.cpp arm/interpreter/mmu/wb.cpp arm/interpreter/mmu/xscale_copro.cpp - elf/elf_reader.cpp file_sys/directory_file_system.cpp file_sys/meta_file_system.cpp hle/hle.cpp @@ -50,7 +50,9 @@ set(SRCS core.cpp set(HEADERS core.h core_timing.h - loader.h + loader/elf_reader.h + loader/elf_types.h + loader/loader.h mem_map.h system.h arm/disassembler/arm_disasm.h @@ -72,8 +74,6 @@ set(HEADERS core.h arm/interpreter/vfp/asm_vfp.h arm/interpreter/vfp/vfp.h arm/interpreter/vfp/vfp_helper.h - elf/elf_reader.h - elf/elf_types.h file_sys/directory_file_system.h file_sys/file_sys.h file_sys/meta_file_system.h diff --git a/src/core/core.vcxproj b/src/core/core.vcxproj index 8eb189a8..07d3d57c 100644 --- a/src/core/core.vcxproj +++ b/src/core/core.vcxproj @@ -162,7 +162,6 @@ - @@ -182,7 +181,8 @@ - + + @@ -210,8 +210,6 @@ - - @@ -233,7 +231,9 @@ - + + + @@ -243,4 +243,4 @@ - + \ No newline at end of file diff --git a/src/core/core.vcxproj.filters b/src/core/core.vcxproj.filters index da781f81..5b2be339 100644 --- a/src/core/core.vcxproj.filters +++ b/src/core/core.vcxproj.filters @@ -16,9 +16,6 @@ {d1158fc4-3e0f-431f-9d3b-f30bbfeb4ad5} - - {7ae34319-6d72-4d12-bc62-9b438ba9241f} - {8b62769e-3e2a-4a57-a7bc-b3b2933c2bc7} @@ -34,6 +31,9 @@ {8089d94b-5faa-43dc-854b-ffd2fa2e7fe3} + + {491d5558-5f3a-4283-8ba4-0a58b1984e37} + @@ -72,11 +72,7 @@ hw - - elf - - @@ -171,6 +167,12 @@ hle\service + + loader + + + loader + @@ -212,18 +214,11 @@ hw - - elf - - - elf - arm - @@ -307,8 +302,17 @@ hle\service + + loader + + + loader + + + loader + - + \ No newline at end of file diff --git a/src/core/elf/elf_reader.cpp b/src/core/elf/elf_reader.cpp deleted file mode 100644 index c62332ce..00000000 --- a/src/core/elf/elf_reader.cpp +++ /dev/null @@ -1,190 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#include - -#include "common/common.h" - -#include "common/symbols.h" -#include "core/mem_map.h" -#include "core/elf/elf_reader.h" - -//void bswap(Elf32_Word &w) {w = Common::swap32(w);} -//void bswap(Elf32_Half &w) {w = Common::swap16(w);} - -#define bswap(w) w // Dirty bswap disable for now... 3DS is little endian, anyway - -static void byteswapHeader(Elf32_Ehdr &ELF_H) -{ - bswap(ELF_H.e_type); - bswap(ELF_H.e_machine); - bswap(ELF_H.e_ehsize); - bswap(ELF_H.e_phentsize); - bswap(ELF_H.e_phnum); - bswap(ELF_H.e_shentsize); - bswap(ELF_H.e_shnum); - bswap(ELF_H.e_shstrndx); - bswap(ELF_H.e_version); - bswap(ELF_H.e_entry); - bswap(ELF_H.e_phoff); - bswap(ELF_H.e_shoff); - bswap(ELF_H.e_flags); -} - -static void byteswapSegment(Elf32_Phdr &sec) -{ - bswap(sec.p_align); - bswap(sec.p_filesz); - bswap(sec.p_flags); - bswap(sec.p_memsz); - bswap(sec.p_offset); - bswap(sec.p_paddr); - bswap(sec.p_vaddr); - bswap(sec.p_type); -} - -static void byteswapSection(Elf32_Shdr &sec) -{ - bswap(sec.sh_addr); - bswap(sec.sh_addralign); - bswap(sec.sh_entsize); - bswap(sec.sh_flags); - bswap(sec.sh_info); - bswap(sec.sh_link); - bswap(sec.sh_name); - bswap(sec.sh_offset); - bswap(sec.sh_size); - bswap(sec.sh_type); -} - -ElfReader::ElfReader(void *ptr) -{ - base = (char*)ptr; - base32 = (u32 *)ptr; - header = (Elf32_Ehdr*)ptr; - byteswapHeader(*header); - - segments = (Elf32_Phdr *)(base + header->e_phoff); - sections = (Elf32_Shdr *)(base + header->e_shoff); - - entryPoint = header->e_entry; - - LoadSymbols(); -} - -const char *ElfReader::GetSectionName(int section) const -{ - if (sections[section].sh_type == SHT_NULL) - return nullptr; - - int nameOffset = sections[section].sh_name; - char *ptr = (char*)GetSectionDataPtr(header->e_shstrndx); - - if (ptr) - return ptr + nameOffset; - else - return nullptr; -} - -bool ElfReader::LoadInto(u32 vaddr) -{ - DEBUG_LOG(MASTER_LOG,"String section: %i", header->e_shstrndx); - - // Should we relocate? - bRelocate = (header->e_type != ET_EXEC); - - if (bRelocate) - { - DEBUG_LOG(MASTER_LOG,"Relocatable module"); - entryPoint += vaddr; - } - else - { - DEBUG_LOG(MASTER_LOG,"Prerelocated executable"); - } - - INFO_LOG(MASTER_LOG,"%i segments:", header->e_phnum); - - // First pass : Get the bits into RAM - u32 segmentVAddr[32]; - - u32 baseAddress = bRelocate?vaddr:0; - - for (int i = 0; i < header->e_phnum; i++) - { - Elf32_Phdr *p = segments + i; - - INFO_LOG(MASTER_LOG, "Type: %i Vaddr: %08x Filesz: %i Memsz: %i ", p->p_type, p->p_vaddr, p->p_filesz, p->p_memsz); - - if (p->p_type == PT_LOAD) - { - segmentVAddr[i] = baseAddress + p->p_vaddr; - u32 writeAddr = segmentVAddr[i]; - - const u8 *src = GetSegmentPtr(i); - u8 *dst = Memory::GetPointer(writeAddr); - u32 srcSize = p->p_filesz; - u32 dstSize = p->p_memsz; - u32 *s = (u32*)src; - u32 *d = (u32*)dst; - for (int j = 0; j < (int)(srcSize + 3) / 4; j++) - { - *d++ = /*_byteswap_ulong*/(*s++); - } - if (srcSize < dstSize) - { - //memset(dst + srcSize, 0, dstSize-srcSize); //zero out bss - } - INFO_LOG(MASTER_LOG,"Loadable Segment Copied to %08x, size %08x", writeAddr, p->p_memsz); - } - } - - - INFO_LOG(MASTER_LOG,"Done loading."); - return true; -} - -SectionID ElfReader::GetSectionByName(const char *name, int firstSection) const -{ - for (int i = firstSection; i < header->e_shnum; i++) - { - const char *secname = GetSectionName(i); - - if (secname != nullptr && strcmp(name, secname) == 0) - return i; - } - return -1; -} - -bool ElfReader::LoadSymbols() -{ - bool hasSymbols = false; - SectionID sec = GetSectionByName(".symtab"); - if (sec != -1) - { - int stringSection = sections[sec].sh_link; - const char *stringBase = (const char *)GetSectionDataPtr(stringSection); - - //We have a symbol table! - Elf32_Sym *symtab = (Elf32_Sym *)(GetSectionDataPtr(sec)); - int numSymbols = sections[sec].sh_size / sizeof(Elf32_Sym); - for (int sym = 0; sym < numSymbols; sym++) - { - int size = symtab[sym].st_size; - if (size == 0) - continue; - - // int bind = symtab[sym].st_info >> 4; - int type = symtab[sym].st_info & 0xF; - - const char *name = stringBase + symtab[sym].st_name; - - Symbols::Add(symtab[sym].st_value, name, size, type); - - hasSymbols = true; - } - } - - return hasSymbols; -} diff --git a/src/core/elf/elf_reader.h b/src/core/elf/elf_reader.h deleted file mode 100644 index 3e2869f8..00000000 --- a/src/core/elf/elf_reader.h +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#pragma once - -#include "core/elf/elf_types.h" - -enum KnownElfTypes -{ - KNOWNELF_PSP = 0, - KNOWNELF_DS = 1, - KNOWNELF_GBA = 2, - KNOWNELF_GC = 3, -}; - -typedef int SectionID; - -class ElfReader -{ -private: - char *base; - u32 *base32; - - Elf32_Ehdr *header; - Elf32_Phdr *segments; - Elf32_Shdr *sections; - - u32 *sectionAddrs; - bool bRelocate; - u32 entryPoint; - -public: - ElfReader(void *ptr); - ~ElfReader() { } - - u32 Read32(int off) const { return base32[off>>2]; } - - // Quick accessors - ElfType GetType() const { return (ElfType)(header->e_type); } - ElfMachine GetMachine() const { return (ElfMachine)(header->e_machine); } - u32 GetEntryPoint() const { return entryPoint; } - u32 GetFlags() const { return (u32)(header->e_flags); } - bool LoadInto(u32 vaddr); - bool LoadSymbols(); - - int GetNumSegments() const { return (int)(header->e_phnum); } - int GetNumSections() const { return (int)(header->e_shnum); } - const u8 *GetPtr(int offset) const { return (u8*)base + offset; } - const char *GetSectionName(int section) const; - const u8 *GetSectionDataPtr(int section) const - { - if (section < 0 || section >= header->e_shnum) - return nullptr; - if (sections[section].sh_type != SHT_NOBITS) - return GetPtr(sections[section].sh_offset); - else - return nullptr; - } - bool IsCodeSection(int section) const - { - return sections[section].sh_type == SHT_PROGBITS; - } - const u8 *GetSegmentPtr(int segment) - { - return GetPtr(segments[segment].p_offset); - } - u32 GetSectionAddr(SectionID section) const { return sectionAddrs[section]; } - int GetSectionSize(SectionID section) const { return sections[section].sh_size; } - SectionID GetSectionByName(const char *name, int firstSection = 0) const; //-1 for not found - - bool DidRelocate() { - return bRelocate; - } -}; diff --git a/src/core/elf/elf_types.h b/src/core/elf/elf_types.h deleted file mode 100644 index f1bf3db7..00000000 --- a/src/core/elf/elf_types.h +++ /dev/null @@ -1,281 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#pragma once - -// ELF Header Constants - -// File type -enum ElfType -{ - ET_NONE = 0, - ET_REL = 1, - ET_EXEC = 2, - ET_DYN = 3, - ET_CORE = 4, - ET_LOPROC = 0xFF00, - ET_HIPROC = 0xFFFF, -}; - -// Machine/Architecture -enum ElfMachine -{ - EM_NONE = 0, - EM_M32 = 1, - EM_SPARC = 2, - EM_386 = 3, - EM_68K = 4, - EM_88K = 5, - EM_860 = 7, - EM_MIPS = 8 -}; - -// File version -#define EV_NONE 0 -#define EV_CURRENT 1 - -// Identification index -#define EI_MAG0 0 -#define EI_MAG1 1 -#define EI_MAG2 2 -#define EI_MAG3 3 -#define EI_CLASS 4 -#define EI_DATA 5 -#define EI_VERSION 6 -#define EI_PAD 7 -#define EI_NIDENT 16 - -// Magic number -#define ELFMAG0 0x7F -#define ELFMAG1 'E' -#define ELFMAG2 'L' -#define ELFMAG3 'F' - -// File class -#define ELFCLASSNONE 0 -#define ELFCLASS32 1 -#define ELFCLASS64 2 - -// Encoding -#define ELFDATANONE 0 -#define ELFDATA2LSB 1 -#define ELFDATA2MSB 2 - - - -// Sections constants - -// Section indexes -#define SHN_UNDEF 0 -#define SHN_LORESERVE 0xFF00 -#define SHN_LOPROC 0xFF00 -#define SHN_HIPROC 0xFF1F -#define SHN_ABS 0xFFF1 -#define SHN_COMMON 0xFFF2 -#define SHN_HIRESERVE 0xFFFF - -// Section types -#define SHT_NULL 0 -#define SHT_PROGBITS 1 -#define SHT_SYMTAB 2 -#define SHT_STRTAB 3 -#define SHT_RELA 4 -#define SHT_HASH 5 -#define SHT_DYNAMIC 6 -#define SHT_NOTE 7 -#define SHT_NOBITS 8 -#define SHT_REL 9 -#define SHT_SHLIB 10 -#define SHT_DYNSYM 11 -#define SHT_LOPROC 0x70000000 -#define SHT_HIPROC 0x7FFFFFFF -#define SHT_LOUSER 0x80000000 -#define SHT_HIUSER 0xFFFFFFFF - -// Custom section types -#define SHT_PSPREL 0x700000a0 - - -// Section flags -enum ElfSectionFlags -{ - SHF_WRITE = 0x1, - SHF_ALLOC = 0x2, - SHF_EXECINSTR = 0x4, - SHF_MASKPROC = 0xF0000000, -}; - -// Symbol binding -#define STB_LOCAL 0 -#define STB_GLOBAL 1 -#define STB_WEAK 2 -#define STB_LOPROC 13 -#define STB_HIPROC 15 - -// Symbol types -#define STT_NOTYPE 0 -#define STT_OBJECT 1 -#define STT_FUNC 2 -#define STT_SECTION 3 -#define STT_FILE 4 -#define STT_LOPROC 13 -#define STT_HIPROC 15 - -// Undefined name -#define STN_UNDEF 0 - -// Relocation types -#define R_386_NONE 0 -#define R_386_32 1 -#define R_386_PC32 2 -#define R_386_GOT32 3 -#define R_386_PLT32 4 -#define R_386_COPY 5 -#define R_386_GLOB_DAT 6 -#define R_386_JMP_SLOT 7 -#define R_386_RELATIVE 8 -#define R_386_GOTOFF 9 -#define R_386_GOTPC 10 - -// Segment types -#define PT_NULL 0 -#define PT_LOAD 1 -#define PT_DYNAMIC 2 -#define PT_INTERP 3 -#define PT_NOTE 4 -#define PT_SHLIB 5 -#define PT_PHDR 6 -#define PT_LOPROC 0x70000000 -#define PT_HIPROC 0x7FFFFFFF - -// Segment flags -#define PF_X 1 -#define PF_W 2 -#define PF_R 4 - -// Dynamic Array Tags -#define DT_NULL 0 -#define DT_NEEDED 1 -#define DT_PLTRELSZ 2 -#define DT_PLTGOT 3 -#define DT_HASH 4 -#define DT_STRTAB 5 -#define DT_SYMTAB 6 -#define DT_RELA 7 -#define DT_RELASZ 8 -#define DT_RELAENT 9 -#define DT_STRSZ 10 -#define DT_SYMENT 11 -#define DT_INIT 12 -#define DT_FINI 13 -#define DT_SONAME 14 -#define DT_RPATH 15 -#define DT_SYMBOLIC 16 -#define DT_REL 17 -#define DT_RELSZ 18 -#define DT_RELENT 19 -#define DT_PLTREL 20 -#define DT_DEBUG 21 -#define DT_TEXTREL 22 -#define DT_JMPREL 23 -#define DT_LOPROC 0x70000000 -#define DT_HIPROC 0x7FFFFFFF - -typedef unsigned int Elf32_Addr; -typedef unsigned short Elf32_Half; -typedef unsigned int Elf32_Off; -typedef signed int Elf32_Sword; -typedef unsigned int Elf32_Word; - - -// ELF file header -struct Elf32_Ehdr -{ - unsigned char e_ident[EI_NIDENT]; - Elf32_Half e_type; - Elf32_Half e_machine; - Elf32_Word e_version; - Elf32_Addr e_entry; - Elf32_Off e_phoff; - Elf32_Off e_shoff; - Elf32_Word e_flags; - Elf32_Half e_ehsize; - Elf32_Half e_phentsize; - Elf32_Half e_phnum; - Elf32_Half e_shentsize; - Elf32_Half e_shnum; - Elf32_Half e_shstrndx; -}; - -// Section header -struct Elf32_Shdr -{ - Elf32_Word sh_name; - Elf32_Word sh_type; - Elf32_Word sh_flags; - Elf32_Addr sh_addr; - Elf32_Off sh_offset; - Elf32_Word sh_size; - Elf32_Word sh_link; - Elf32_Word sh_info; - Elf32_Word sh_addralign; - Elf32_Word sh_entsize; -}; - -// Segment header -struct Elf32_Phdr -{ - Elf32_Word p_type; - Elf32_Off p_offset; - Elf32_Addr p_vaddr; - Elf32_Addr p_paddr; - Elf32_Word p_filesz; - Elf32_Word p_memsz; - Elf32_Word p_flags; - Elf32_Word p_align; -}; - -// Symbol table entry -struct Elf32_Sym -{ - Elf32_Word st_name; - Elf32_Addr st_value; - Elf32_Word st_size; - unsigned char st_info; - unsigned char st_other; - Elf32_Half st_shndx; -}; - -#define ELF32_ST_BIND(i) ((i)>>4) -#define ELF32_ST_TYPE(i) ((i)&0xf) -#define ELF32_ST_INFO(b,t) (((b)<<4)+((t)&0xf)) - -// Relocation entries -struct Elf32_Rel -{ - Elf32_Addr r_offset; - Elf32_Word r_info; -}; - -struct Elf32_Rela -{ - Elf32_Addr r_offset; - Elf32_Word r_info; - Elf32_Sword r_addend; -}; - -#define ELF32_R_SYM(i) ((i)>>8) -#define ELF32_R_TYPE(i) ((unsigned char)(i)) -#define ELF32_R_INFO(s,t) (((s)<<8 )+(unsigned char)(t)) - - -struct Elf32_Dyn -{ - Elf32_Sword d_tag; - union - { - Elf32_Word d_val; - Elf32_Addr d_ptr; - } d_un; -}; diff --git a/src/core/loader.cpp b/src/core/loader.cpp deleted file mode 100644 index 94b59e5d..00000000 --- a/src/core/loader.cpp +++ /dev/null @@ -1,205 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#include "common/common_types.h" -#include "common/file_util.h" - -#include "core/loader.h" -#include "core/system.h" -#include "core/core.h" -#include "core/elf/elf_reader.h" -#include "core/hle/kernel/kernel.h" -#include "core/mem_map.h" - -//////////////////////////////////////////////////////////////////////////////////////////////////// - -/// Loads a CTR ELF file -bool Load_ELF(std::string &filename) { - std::string full_path = filename; - std::string path, file, extension; - SplitPath(ReplaceAll(full_path, "\\", "/"), &path, &file, &extension); -#if EMU_PLATFORM == PLATFORM_WINDOWS - path = ReplaceAll(path, "/", "\\"); -#endif - File::IOFile f(filename, "rb"); - - if (f.IsOpen()) { - u64 size = f.GetSize(); - u8* buffer = new u8[size]; - ElfReader* elf_reader = NULL; - - f.ReadBytes(buffer, size); - - elf_reader = new ElfReader(buffer); - elf_reader->LoadInto(0x00100000); - - Kernel::LoadExec(elf_reader->GetEntryPoint()); - - delete[] buffer; - delete elf_reader; - } else { - return false; - } - f.Close(); - - return true; -} - -/// Loads a CTR BIN file extracted from an ExeFS -bool Load_BIN(std::string &filename) { - std::string full_path = filename; - std::string path, file, extension; - SplitPath(ReplaceAll(full_path, "\\", "/"), &path, &file, &extension); -#if EMU_PLATFORM == PLATFORM_WINDOWS - path = ReplaceAll(path, "/", "\\"); -#endif - File::IOFile f(filename, "rb"); - - if (f.IsOpen()) { - u64 size = f.GetSize(); - u8* buffer = new u8[size]; - - f.ReadBytes(buffer, size); - - u32 entry_point = 0x00100000; // Hardcoded, read from exheader - - const u8 *src = buffer; - u8 *dst = Memory::GetPointer(entry_point); - u32 srcSize = size; - u32 *s = (u32*)src; - u32 *d = (u32*)dst; - for (int j = 0; j < (int)(srcSize + 3) / 4; j++) - { - *d++ = (*s++); - } - - Kernel::LoadExec(entry_point); - - delete[] buffer; - } - else { - return false; - } - f.Close(); - - return true; -} - -namespace Loader { - -bool IsBootableDirectory() { - ERROR_LOG(TIME, "Unimplemented function!"); - return true; -} - -/** - * Identifies the type of a bootable file - * @param filename String filename of bootable file - * @todo (ShizZy) this function sucks... make it actually check file contents etc. - * @return FileType of file - */ -FileType IdentifyFile(std::string &filename) { - if (filename.size() == 0) { - ERROR_LOG(LOADER, "invalid filename %s", filename.c_str()); - return FILETYPE_ERROR; - } - std::string extension = filename.size() >= 5 ? filename.substr(filename.size() - 4) : ""; - - if (File::IsDirectory(filename)) { - if (IsBootableDirectory()) { - return FILETYPE_DIRECTORY_CXI; - } - else { - return FILETYPE_NORMAL_DIRECTORY; - } - } - else if (!strcasecmp(extension.c_str(), ".elf")) { - return FILETYPE_CTR_ELF; // TODO(bunnei): Do some filetype checking :p - } - else if (!strcasecmp(extension.c_str(), ".axf")) { - return FILETYPE_CTR_ELF; // TODO(bunnei): Do some filetype checking :p - } - else if (!strcasecmp(extension.c_str(), ".cxi")) { - return FILETYPE_CTR_CXI; // TODO(bunnei): Do some filetype checking :p - } - else if (!strcasecmp(extension.c_str(), ".cci")) { - return FILETYPE_CTR_CCI; // TODO(bunnei): Do some filetype checking :p - } - else if (!strcasecmp(extension.c_str(), ".bin")) { - return FILETYPE_CTR_BIN; - } - else if (!strcasecmp(extension.c_str(), ".dat")) { - return FILETYPE_LAUNCHER_DAT; - } - else if (!strcasecmp(extension.c_str(), ".zip")) { - return FILETYPE_ARCHIVE_ZIP; - } - else if (!strcasecmp(extension.c_str(), ".rar")) { - return FILETYPE_ARCHIVE_RAR; - } - else if (!strcasecmp(extension.c_str(), ".r00")) { - return FILETYPE_ARCHIVE_RAR; - } - else if (!strcasecmp(extension.c_str(), ".r01")) { - return FILETYPE_ARCHIVE_RAR; - } - return FILETYPE_UNKNOWN; -} - -/** - * Identifies and loads a bootable file - * @param filename String filename of bootable file - * @param error_string Point to string to put error message if an error has occurred - * @return True on success, otherwise false - */ -bool LoadFile(std::string &filename, std::string *error_string) { - INFO_LOG(LOADER, "Identifying file..."); - - // Note that this can modify filename! - switch (IdentifyFile(filename)) { - - case FILETYPE_CTR_ELF: - return Load_ELF(filename); - - case FILETYPE_CTR_BIN: - return Load_BIN(filename); - - case FILETYPE_ERROR: - ERROR_LOG(LOADER, "Could not read file"); - *error_string = "Error reading file"; - break; - - case FILETYPE_ARCHIVE_RAR: -#ifdef WIN32 - *error_string = "RAR file detected (Require WINRAR)"; -#else - *error_string = "RAR file detected (Require UnRAR)"; -#endif - break; - - case FILETYPE_ARCHIVE_ZIP: -#ifdef WIN32 - *error_string = "ZIP file detected (Require WINRAR)"; -#else - *error_string = "ZIP file detected (Require UnRAR)"; -#endif - break; - - case FILETYPE_NORMAL_DIRECTORY: - ERROR_LOG(LOADER, "Just a directory."); - *error_string = "Just a directory."; - break; - - case FILETYPE_UNKNOWN_BIN: - case FILETYPE_UNKNOWN_ELF: - case FILETYPE_UNKNOWN: - default: - ERROR_LOG(LOADER, "Failed to identify file"); - *error_string = " Failed to identify file"; - break; - } - return false; -} - -} // namespace \ No newline at end of file diff --git a/src/core/loader.h b/src/core/loader.h deleted file mode 100644 index 9d4aaa87..00000000 --- a/src/core/loader.h +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#pragma once - -#include "common/common.h" - -//////////////////////////////////////////////////////////////////////////////////////////////////// - -namespace Loader { - -enum FileType { - FILETYPE_ERROR, - - FILETYPE_CTR_CCI, - FILETYPE_CTR_CIA, - FILETYPE_CTR_CXI, - FILETYPE_CTR_ELF, - FILETYPE_CTR_BIN, - - FILETYPE_LAUNCHER_DAT, - - FILETYPE_DIRECTORY_CXI, - - FILETYPE_UNKNOWN_BIN, - FILETYPE_UNKNOWN_ELF, - - FILETYPE_ARCHIVE_RAR, - FILETYPE_ARCHIVE_ZIP, - - FILETYPE_NORMAL_DIRECTORY, - - FILETYPE_UNKNOWN -}; - -//////////////////////////////////////////////////////////////////////////////////////////////////// - -/** - * Identifies the type of a bootable file - * @param filename String filename of bootable file - * @return FileType of file - */ -FileType IdentifyFile(std::string &filename); - -/** - * Identifies and loads a bootable file - * @param filename String filename of bootable file - * @param error_string Point to string to put error message if an error has occurred - * @return True on success, otherwise false - */ -bool LoadFile(std::string &filename, std::string *error_string); - -} // namespace diff --git a/src/core/loader/elf_reader.cpp b/src/core/loader/elf_reader.cpp new file mode 100644 index 00000000..123747f8 --- /dev/null +++ b/src/core/loader/elf_reader.cpp @@ -0,0 +1,190 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include + +#include "common/common.h" + +#include "common/symbols.h" +#include "core/mem_map.h" +#include "core/loader/elf_reader.h" + +//void bswap(Elf32_Word &w) {w = Common::swap32(w);} +//void bswap(Elf32_Half &w) {w = Common::swap16(w);} + +#define bswap(w) w // Dirty bswap disable for now... 3DS is little endian, anyway + +static void byteswapHeader(Elf32_Ehdr &ELF_H) +{ + bswap(ELF_H.e_type); + bswap(ELF_H.e_machine); + bswap(ELF_H.e_ehsize); + bswap(ELF_H.e_phentsize); + bswap(ELF_H.e_phnum); + bswap(ELF_H.e_shentsize); + bswap(ELF_H.e_shnum); + bswap(ELF_H.e_shstrndx); + bswap(ELF_H.e_version); + bswap(ELF_H.e_entry); + bswap(ELF_H.e_phoff); + bswap(ELF_H.e_shoff); + bswap(ELF_H.e_flags); +} + +static void byteswapSegment(Elf32_Phdr &sec) +{ + bswap(sec.p_align); + bswap(sec.p_filesz); + bswap(sec.p_flags); + bswap(sec.p_memsz); + bswap(sec.p_offset); + bswap(sec.p_paddr); + bswap(sec.p_vaddr); + bswap(sec.p_type); +} + +static void byteswapSection(Elf32_Shdr &sec) +{ + bswap(sec.sh_addr); + bswap(sec.sh_addralign); + bswap(sec.sh_entsize); + bswap(sec.sh_flags); + bswap(sec.sh_info); + bswap(sec.sh_link); + bswap(sec.sh_name); + bswap(sec.sh_offset); + bswap(sec.sh_size); + bswap(sec.sh_type); +} + +ElfReader::ElfReader(void *ptr) +{ + base = (char*)ptr; + base32 = (u32 *)ptr; + header = (Elf32_Ehdr*)ptr; + byteswapHeader(*header); + + segments = (Elf32_Phdr *)(base + header->e_phoff); + sections = (Elf32_Shdr *)(base + header->e_shoff); + + entryPoint = header->e_entry; + + LoadSymbols(); +} + +const char *ElfReader::GetSectionName(int section) const +{ + if (sections[section].sh_type == SHT_NULL) + return nullptr; + + int nameOffset = sections[section].sh_name; + char *ptr = (char*)GetSectionDataPtr(header->e_shstrndx); + + if (ptr) + return ptr + nameOffset; + else + return nullptr; +} + +bool ElfReader::LoadInto(u32 vaddr) +{ + DEBUG_LOG(MASTER_LOG,"String section: %i", header->e_shstrndx); + + // Should we relocate? + bRelocate = (header->e_type != ET_EXEC); + + if (bRelocate) + { + DEBUG_LOG(MASTER_LOG,"Relocatable module"); + entryPoint += vaddr; + } + else + { + DEBUG_LOG(MASTER_LOG,"Prerelocated executable"); + } + + INFO_LOG(MASTER_LOG,"%i segments:", header->e_phnum); + + // First pass : Get the bits into RAM + u32 segmentVAddr[32]; + + u32 baseAddress = bRelocate?vaddr:0; + + for (int i = 0; i < header->e_phnum; i++) + { + Elf32_Phdr *p = segments + i; + + INFO_LOG(MASTER_LOG, "Type: %i Vaddr: %08x Filesz: %i Memsz: %i ", p->p_type, p->p_vaddr, p->p_filesz, p->p_memsz); + + if (p->p_type == PT_LOAD) + { + segmentVAddr[i] = baseAddress + p->p_vaddr; + u32 writeAddr = segmentVAddr[i]; + + const u8 *src = GetSegmentPtr(i); + u8 *dst = Memory::GetPointer(writeAddr); + u32 srcSize = p->p_filesz; + u32 dstSize = p->p_memsz; + u32 *s = (u32*)src; + u32 *d = (u32*)dst; + for (int j = 0; j < (int)(srcSize + 3) / 4; j++) + { + *d++ = /*_byteswap_ulong*/(*s++); + } + if (srcSize < dstSize) + { + //memset(dst + srcSize, 0, dstSize-srcSize); //zero out bss + } + INFO_LOG(MASTER_LOG,"Loadable Segment Copied to %08x, size %08x", writeAddr, p->p_memsz); + } + } + + + INFO_LOG(MASTER_LOG,"Done loading."); + return true; +} + +SectionID ElfReader::GetSectionByName(const char *name, int firstSection) const +{ + for (int i = firstSection; i < header->e_shnum; i++) + { + const char *secname = GetSectionName(i); + + if (secname != nullptr && strcmp(name, secname) == 0) + return i; + } + return -1; +} + +bool ElfReader::LoadSymbols() +{ + bool hasSymbols = false; + SectionID sec = GetSectionByName(".symtab"); + if (sec != -1) + { + int stringSection = sections[sec].sh_link; + const char *stringBase = (const char *)GetSectionDataPtr(stringSection); + + //We have a symbol table! + Elf32_Sym *symtab = (Elf32_Sym *)(GetSectionDataPtr(sec)); + int numSymbols = sections[sec].sh_size / sizeof(Elf32_Sym); + for (int sym = 0; sym < numSymbols; sym++) + { + int size = symtab[sym].st_size; + if (size == 0) + continue; + + // int bind = symtab[sym].st_info >> 4; + int type = symtab[sym].st_info & 0xF; + + const char *name = stringBase + symtab[sym].st_name; + + Symbols::Add(symtab[sym].st_value, name, size, type); + + hasSymbols = true; + } + } + + return hasSymbols; +} diff --git a/src/core/loader/elf_reader.h b/src/core/loader/elf_reader.h new file mode 100644 index 00000000..6f0ad84b --- /dev/null +++ b/src/core/loader/elf_reader.h @@ -0,0 +1,75 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +#include "core/loader/elf_types.h" + +enum KnownElfTypes +{ + KNOWNELF_PSP = 0, + KNOWNELF_DS = 1, + KNOWNELF_GBA = 2, + KNOWNELF_GC = 3, +}; + +typedef int SectionID; + +class ElfReader +{ +private: + char *base; + u32 *base32; + + Elf32_Ehdr *header; + Elf32_Phdr *segments; + Elf32_Shdr *sections; + + u32 *sectionAddrs; + bool bRelocate; + u32 entryPoint; + +public: + ElfReader(void *ptr); + ~ElfReader() { } + + u32 Read32(int off) const { return base32[off>>2]; } + + // Quick accessors + ElfType GetType() const { return (ElfType)(header->e_type); } + ElfMachine GetMachine() const { return (ElfMachine)(header->e_machine); } + u32 GetEntryPoint() const { return entryPoint; } + u32 GetFlags() const { return (u32)(header->e_flags); } + bool LoadInto(u32 vaddr); + bool LoadSymbols(); + + int GetNumSegments() const { return (int)(header->e_phnum); } + int GetNumSections() const { return (int)(header->e_shnum); } + const u8 *GetPtr(int offset) const { return (u8*)base + offset; } + const char *GetSectionName(int section) const; + const u8 *GetSectionDataPtr(int section) const + { + if (section < 0 || section >= header->e_shnum) + return nullptr; + if (sections[section].sh_type != SHT_NOBITS) + return GetPtr(sections[section].sh_offset); + else + return nullptr; + } + bool IsCodeSection(int section) const + { + return sections[section].sh_type == SHT_PROGBITS; + } + const u8 *GetSegmentPtr(int segment) + { + return GetPtr(segments[segment].p_offset); + } + u32 GetSectionAddr(SectionID section) const { return sectionAddrs[section]; } + int GetSectionSize(SectionID section) const { return sections[section].sh_size; } + SectionID GetSectionByName(const char *name, int firstSection = 0) const; //-1 for not found + + bool DidRelocate() { + return bRelocate; + } +}; diff --git a/src/core/loader/elf_types.h b/src/core/loader/elf_types.h new file mode 100644 index 00000000..f1bf3db7 --- /dev/null +++ b/src/core/loader/elf_types.h @@ -0,0 +1,281 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +// ELF Header Constants + +// File type +enum ElfType +{ + ET_NONE = 0, + ET_REL = 1, + ET_EXEC = 2, + ET_DYN = 3, + ET_CORE = 4, + ET_LOPROC = 0xFF00, + ET_HIPROC = 0xFFFF, +}; + +// Machine/Architecture +enum ElfMachine +{ + EM_NONE = 0, + EM_M32 = 1, + EM_SPARC = 2, + EM_386 = 3, + EM_68K = 4, + EM_88K = 5, + EM_860 = 7, + EM_MIPS = 8 +}; + +// File version +#define EV_NONE 0 +#define EV_CURRENT 1 + +// Identification index +#define EI_MAG0 0 +#define EI_MAG1 1 +#define EI_MAG2 2 +#define EI_MAG3 3 +#define EI_CLASS 4 +#define EI_DATA 5 +#define EI_VERSION 6 +#define EI_PAD 7 +#define EI_NIDENT 16 + +// Magic number +#define ELFMAG0 0x7F +#define ELFMAG1 'E' +#define ELFMAG2 'L' +#define ELFMAG3 'F' + +// File class +#define ELFCLASSNONE 0 +#define ELFCLASS32 1 +#define ELFCLASS64 2 + +// Encoding +#define ELFDATANONE 0 +#define ELFDATA2LSB 1 +#define ELFDATA2MSB 2 + + + +// Sections constants + +// Section indexes +#define SHN_UNDEF 0 +#define SHN_LORESERVE 0xFF00 +#define SHN_LOPROC 0xFF00 +#define SHN_HIPROC 0xFF1F +#define SHN_ABS 0xFFF1 +#define SHN_COMMON 0xFFF2 +#define SHN_HIRESERVE 0xFFFF + +// Section types +#define SHT_NULL 0 +#define SHT_PROGBITS 1 +#define SHT_SYMTAB 2 +#define SHT_STRTAB 3 +#define SHT_RELA 4 +#define SHT_HASH 5 +#define SHT_DYNAMIC 6 +#define SHT_NOTE 7 +#define SHT_NOBITS 8 +#define SHT_REL 9 +#define SHT_SHLIB 10 +#define SHT_DYNSYM 11 +#define SHT_LOPROC 0x70000000 +#define SHT_HIPROC 0x7FFFFFFF +#define SHT_LOUSER 0x80000000 +#define SHT_HIUSER 0xFFFFFFFF + +// Custom section types +#define SHT_PSPREL 0x700000a0 + + +// Section flags +enum ElfSectionFlags +{ + SHF_WRITE = 0x1, + SHF_ALLOC = 0x2, + SHF_EXECINSTR = 0x4, + SHF_MASKPROC = 0xF0000000, +}; + +// Symbol binding +#define STB_LOCAL 0 +#define STB_GLOBAL 1 +#define STB_WEAK 2 +#define STB_LOPROC 13 +#define STB_HIPROC 15 + +// Symbol types +#define STT_NOTYPE 0 +#define STT_OBJECT 1 +#define STT_FUNC 2 +#define STT_SECTION 3 +#define STT_FILE 4 +#define STT_LOPROC 13 +#define STT_HIPROC 15 + +// Undefined name +#define STN_UNDEF 0 + +// Relocation types +#define R_386_NONE 0 +#define R_386_32 1 +#define R_386_PC32 2 +#define R_386_GOT32 3 +#define R_386_PLT32 4 +#define R_386_COPY 5 +#define R_386_GLOB_DAT 6 +#define R_386_JMP_SLOT 7 +#define R_386_RELATIVE 8 +#define R_386_GOTOFF 9 +#define R_386_GOTPC 10 + +// Segment types +#define PT_NULL 0 +#define PT_LOAD 1 +#define PT_DYNAMIC 2 +#define PT_INTERP 3 +#define PT_NOTE 4 +#define PT_SHLIB 5 +#define PT_PHDR 6 +#define PT_LOPROC 0x70000000 +#define PT_HIPROC 0x7FFFFFFF + +// Segment flags +#define PF_X 1 +#define PF_W 2 +#define PF_R 4 + +// Dynamic Array Tags +#define DT_NULL 0 +#define DT_NEEDED 1 +#define DT_PLTRELSZ 2 +#define DT_PLTGOT 3 +#define DT_HASH 4 +#define DT_STRTAB 5 +#define DT_SYMTAB 6 +#define DT_RELA 7 +#define DT_RELASZ 8 +#define DT_RELAENT 9 +#define DT_STRSZ 10 +#define DT_SYMENT 11 +#define DT_INIT 12 +#define DT_FINI 13 +#define DT_SONAME 14 +#define DT_RPATH 15 +#define DT_SYMBOLIC 16 +#define DT_REL 17 +#define DT_RELSZ 18 +#define DT_RELENT 19 +#define DT_PLTREL 20 +#define DT_DEBUG 21 +#define DT_TEXTREL 22 +#define DT_JMPREL 23 +#define DT_LOPROC 0x70000000 +#define DT_HIPROC 0x7FFFFFFF + +typedef unsigned int Elf32_Addr; +typedef unsigned short Elf32_Half; +typedef unsigned int Elf32_Off; +typedef signed int Elf32_Sword; +typedef unsigned int Elf32_Word; + + +// ELF file header +struct Elf32_Ehdr +{ + unsigned char e_ident[EI_NIDENT]; + Elf32_Half e_type; + Elf32_Half e_machine; + Elf32_Word e_version; + Elf32_Addr e_entry; + Elf32_Off e_phoff; + Elf32_Off e_shoff; + Elf32_Word e_flags; + Elf32_Half e_ehsize; + Elf32_Half e_phentsize; + Elf32_Half e_phnum; + Elf32_Half e_shentsize; + Elf32_Half e_shnum; + Elf32_Half e_shstrndx; +}; + +// Section header +struct Elf32_Shdr +{ + Elf32_Word sh_name; + Elf32_Word sh_type; + Elf32_Word sh_flags; + Elf32_Addr sh_addr; + Elf32_Off sh_offset; + Elf32_Word sh_size; + Elf32_Word sh_link; + Elf32_Word sh_info; + Elf32_Word sh_addralign; + Elf32_Word sh_entsize; +}; + +// Segment header +struct Elf32_Phdr +{ + Elf32_Word p_type; + Elf32_Off p_offset; + Elf32_Addr p_vaddr; + Elf32_Addr p_paddr; + Elf32_Word p_filesz; + Elf32_Word p_memsz; + Elf32_Word p_flags; + Elf32_Word p_align; +}; + +// Symbol table entry +struct Elf32_Sym +{ + Elf32_Word st_name; + Elf32_Addr st_value; + Elf32_Word st_size; + unsigned char st_info; + unsigned char st_other; + Elf32_Half st_shndx; +}; + +#define ELF32_ST_BIND(i) ((i)>>4) +#define ELF32_ST_TYPE(i) ((i)&0xf) +#define ELF32_ST_INFO(b,t) (((b)<<4)+((t)&0xf)) + +// Relocation entries +struct Elf32_Rel +{ + Elf32_Addr r_offset; + Elf32_Word r_info; +}; + +struct Elf32_Rela +{ + Elf32_Addr r_offset; + Elf32_Word r_info; + Elf32_Sword r_addend; +}; + +#define ELF32_R_SYM(i) ((i)>>8) +#define ELF32_R_TYPE(i) ((unsigned char)(i)) +#define ELF32_R_INFO(s,t) (((s)<<8 )+(unsigned char)(t)) + + +struct Elf32_Dyn +{ + Elf32_Sword d_tag; + union + { + Elf32_Word d_val; + Elf32_Addr d_ptr; + } d_un; +}; diff --git a/src/core/loader/loader.cpp b/src/core/loader/loader.cpp new file mode 100644 index 00000000..7e6922e0 --- /dev/null +++ b/src/core/loader/loader.cpp @@ -0,0 +1,205 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include "common/common_types.h" +#include "common/file_util.h" + +#include "core/loader/loader.h" +#include "core/loader/elf_reader.h" +#include "core/system.h" +#include "core/core.h" +#include "core/hle/kernel/kernel.h" +#include "core/mem_map.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/// Loads a CTR ELF file +bool Load_ELF(std::string &filename) { + std::string full_path = filename; + std::string path, file, extension; + SplitPath(ReplaceAll(full_path, "\\", "/"), &path, &file, &extension); +#if EMU_PLATFORM == PLATFORM_WINDOWS + path = ReplaceAll(path, "/", "\\"); +#endif + File::IOFile f(filename, "rb"); + + if (f.IsOpen()) { + u64 size = f.GetSize(); + u8* buffer = new u8[size]; + ElfReader* elf_reader = NULL; + + f.ReadBytes(buffer, size); + + elf_reader = new ElfReader(buffer); + elf_reader->LoadInto(0x00100000); + + Kernel::LoadExec(elf_reader->GetEntryPoint()); + + delete[] buffer; + delete elf_reader; + } else { + return false; + } + f.Close(); + + return true; +} + +/// Loads a CTR BIN file extracted from an ExeFS +bool Load_BIN(std::string &filename) { + std::string full_path = filename; + std::string path, file, extension; + SplitPath(ReplaceAll(full_path, "\\", "/"), &path, &file, &extension); +#if EMU_PLATFORM == PLATFORM_WINDOWS + path = ReplaceAll(path, "/", "\\"); +#endif + File::IOFile f(filename, "rb"); + + if (f.IsOpen()) { + u64 size = f.GetSize(); + u8* buffer = new u8[size]; + + f.ReadBytes(buffer, size); + + u32 entry_point = 0x00100000; // Hardcoded, read from exheader + + const u8 *src = buffer; + u8 *dst = Memory::GetPointer(entry_point); + u32 srcSize = size; + u32 *s = (u32*)src; + u32 *d = (u32*)dst; + for (int j = 0; j < (int)(srcSize + 3) / 4; j++) + { + *d++ = (*s++); + } + + Kernel::LoadExec(entry_point); + + delete[] buffer; + } + else { + return false; + } + f.Close(); + + return true; +} + +namespace Loader { + +bool IsBootableDirectory() { + ERROR_LOG(TIME, "Unimplemented function!"); + return true; +} + +/** + * Identifies the type of a bootable file + * @param filename String filename of bootable file + * @todo (ShizZy) this function sucks... make it actually check file contents etc. + * @return FileType of file + */ +FileType IdentifyFile(std::string &filename) { + if (filename.size() == 0) { + ERROR_LOG(LOADER, "invalid filename %s", filename.c_str()); + return FILETYPE_ERROR; + } + std::string extension = filename.size() >= 5 ? filename.substr(filename.size() - 4) : ""; + + if (File::IsDirectory(filename)) { + if (IsBootableDirectory()) { + return FILETYPE_DIRECTORY_CXI; + } + else { + return FILETYPE_NORMAL_DIRECTORY; + } + } + else if (!strcasecmp(extension.c_str(), ".elf")) { + return FILETYPE_CTR_ELF; // TODO(bunnei): Do some filetype checking :p + } + else if (!strcasecmp(extension.c_str(), ".axf")) { + return FILETYPE_CTR_ELF; // TODO(bunnei): Do some filetype checking :p + } + else if (!strcasecmp(extension.c_str(), ".cxi")) { + return FILETYPE_CTR_CXI; // TODO(bunnei): Do some filetype checking :p + } + else if (!strcasecmp(extension.c_str(), ".cci")) { + return FILETYPE_CTR_CCI; // TODO(bunnei): Do some filetype checking :p + } + else if (!strcasecmp(extension.c_str(), ".bin")) { + return FILETYPE_CTR_BIN; + } + else if (!strcasecmp(extension.c_str(), ".dat")) { + return FILETYPE_LAUNCHER_DAT; + } + else if (!strcasecmp(extension.c_str(), ".zip")) { + return FILETYPE_ARCHIVE_ZIP; + } + else if (!strcasecmp(extension.c_str(), ".rar")) { + return FILETYPE_ARCHIVE_RAR; + } + else if (!strcasecmp(extension.c_str(), ".r00")) { + return FILETYPE_ARCHIVE_RAR; + } + else if (!strcasecmp(extension.c_str(), ".r01")) { + return FILETYPE_ARCHIVE_RAR; + } + return FILETYPE_UNKNOWN; +} + +/** + * Identifies and loads a bootable file + * @param filename String filename of bootable file + * @param error_string Point to string to put error message if an error has occurred + * @return True on success, otherwise false + */ +bool LoadFile(std::string &filename, std::string *error_string) { + INFO_LOG(LOADER, "Identifying file..."); + + // Note that this can modify filename! + switch (IdentifyFile(filename)) { + + case FILETYPE_CTR_ELF: + return Load_ELF(filename); + + case FILETYPE_CTR_BIN: + return Load_BIN(filename); + + case FILETYPE_ERROR: + ERROR_LOG(LOADER, "Could not read file"); + *error_string = "Error reading file"; + break; + + case FILETYPE_ARCHIVE_RAR: +#ifdef WIN32 + *error_string = "RAR file detected (Require WINRAR)"; +#else + *error_string = "RAR file detected (Require UnRAR)"; +#endif + break; + + case FILETYPE_ARCHIVE_ZIP: +#ifdef WIN32 + *error_string = "ZIP file detected (Require WINRAR)"; +#else + *error_string = "ZIP file detected (Require UnRAR)"; +#endif + break; + + case FILETYPE_NORMAL_DIRECTORY: + ERROR_LOG(LOADER, "Just a directory."); + *error_string = "Just a directory."; + break; + + case FILETYPE_UNKNOWN_BIN: + case FILETYPE_UNKNOWN_ELF: + case FILETYPE_UNKNOWN: + default: + ERROR_LOG(LOADER, "Failed to identify file"); + *error_string = " Failed to identify file"; + break; + } + return false; +} + +} // namespace \ No newline at end of file diff --git a/src/core/loader/loader.h b/src/core/loader/loader.h new file mode 100644 index 00000000..9d4aaa87 --- /dev/null +++ b/src/core/loader/loader.h @@ -0,0 +1,54 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +#include "common/common.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +namespace Loader { + +enum FileType { + FILETYPE_ERROR, + + FILETYPE_CTR_CCI, + FILETYPE_CTR_CIA, + FILETYPE_CTR_CXI, + FILETYPE_CTR_ELF, + FILETYPE_CTR_BIN, + + FILETYPE_LAUNCHER_DAT, + + FILETYPE_DIRECTORY_CXI, + + FILETYPE_UNKNOWN_BIN, + FILETYPE_UNKNOWN_ELF, + + FILETYPE_ARCHIVE_RAR, + FILETYPE_ARCHIVE_ZIP, + + FILETYPE_NORMAL_DIRECTORY, + + FILETYPE_UNKNOWN +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +/** + * Identifies the type of a bootable file + * @param filename String filename of bootable file + * @return FileType of file + */ +FileType IdentifyFile(std::string &filename); + +/** + * Identifies and loads a bootable file + * @param filename String filename of bootable file + * @param error_string Point to string to put error message if an error has occurred + * @return True on success, otherwise false + */ +bool LoadFile(std::string &filename, std::string *error_string); + +} // namespace -- cgit v1.2.3