├── .gitignore ├── .gitmodules ├── CMakeLists.txt ├── README.md ├── TODO.md ├── compile.bat └── llvm360 ├── LLVMApp ├── CMakeLists.txt └── src │ ├── Decoder │ ├── Instruction.h │ ├── InstructionDecoder.cpp │ └── InstructionDecoder.h │ ├── IR │ ├── IRFunc.cpp │ ├── IRFunc.h │ ├── IRGenerator.cpp │ ├── IRGenerator.h │ ├── InstructionEmitter.h │ ├── JumpTables.h │ └── Unit │ │ └── UnitTesting.h │ ├── LLVM360.cpp │ ├── Util.h │ ├── Xex │ ├── AES.cpp │ ├── AES.h │ ├── ImportTable.h │ ├── XEXImage.h │ ├── XexLoader.cpp │ └── XexLoader.h │ └── misc │ ├── Utils.cpp │ └── Utils.h └── Runtime ├── CMakeLists.txt └── src ├── Graphics ├── DX12Manager.cpp ├── DX12Manager.h ├── ImGuiDebugger.cpp ├── ImGuiDebugger.h └── ImGuiTest.h ├── Runtime ├── Kernel │ ├── XKernel.cpp │ ├── XKernel.h │ ├── XeThread.cpp │ └── XeThread.h ├── MemoryManager.h ├── Runtime.cpp ├── Runtime.h └── Xen │ ├── Xam_Entry.h │ ├── Xam_Impl.h │ ├── XboxKrnl_Entry.h │ ├── XboxKrnl_Impl.h │ └── XenUtils.h ├── dllmain.cpp ├── pch.cpp └── pch.h /.gitignore: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | # This .gitignore file was automatically created by Microsoft(R) Visual Studio. 3 | ################################################################################ 4 | 5 | /.vs 6 | /LLVM360/x64/Debug 7 | /x64 8 | *.xex 9 | /out 10 | /runtime/Runtime/.vs/Runtime 11 | /runtime/Runtime/Runtime/x64/Debug 12 | /runtime/Runtime/x64/Debug 13 | *.exe 14 | *.dll 15 | /runtime/Runtime/.vs 16 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "external/imgui"] 2 | path = external/imgui 3 | url = https://github.com/ocornut/imgui.git 4 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Master CMakeLists.txt 2 | cmake_minimum_required(VERSION 3.15) 3 | cmake_policy(SET CMP0091 NEW) 4 | 5 | project(LLVM360) 6 | 7 | # Prevent in-source builds 8 | if(CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR) 9 | message(FATAL_ERROR "In-tree builds are not supported. Run CMake from a separate directory: cmake -B build") 10 | endif() 11 | 12 | # Enable solution folders 13 | set_property(GLOBAL PROPERTY USE_FOLDERS ON) 14 | 15 | # Require C++20 16 | set(CMAKE_CXX_STANDARD 20) 17 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 18 | 19 | # Set output directories 20 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) 21 | 22 | # Add CMake modules 23 | list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") 24 | 25 | # Find LLVM 26 | find_package(LLVM CONFIG REQUIRED) 27 | if(LLVM_PACKAGE_VERSION VERSION_LESS "19.0" OR LLVM_PACKAGE_VERSION VERSION_GREATER_EQUAL "21.0") 28 | message(FATAL_ERROR "LLVM version ${LLVM_PACKAGE_VERSION} is incompatible. Expected version 19.x or 20.x.") 29 | else() 30 | message(STATUS "Using LLVM version ${LLVM_PACKAGE_VERSION}") 31 | endif() 32 | 33 | # Move LLVM-generated auxiliary projects to the LLVMGen filter 34 | get_property(LLVM_TARGETS GLOBAL PROPERTY LLVM_ALL_PROJECTS) 35 | foreach(LLVM_PROJECT IN LISTS LLVM_TARGETS) 36 | if(LLVM_PROJECT MATCHES "_gen$") # Matches *_gen projects 37 | set_property(TARGET ${LLVM_PROJECT} PROPERTY FOLDER "LLVMGen") 38 | endif() 39 | endforeach() 40 | 41 | # Suppress unwanted targets by overriding them as empty or excluding them 42 | set(REMOVE_TARGETS 43 | AArch64TargetParserTableGen 44 | acc_gen 45 | ARMTargetParserTableGen 46 | intrinsics_gen 47 | omp_gen 48 | RISCVTargetParserTableGen 49 | ) 50 | 51 | foreach(TARGET_NAME IN LISTS REMOVE_TARGETS) 52 | if(TARGET ${TARGET_NAME}) 53 | # Override the target as a dummy empty target 54 | set_property(TARGET ${TARGET_NAME} PROPERTY EXCLUDE_FROM_ALL TRUE) 55 | set_property(TARGET ${TARGET_NAME} PROPERTY FOLDER "llvm_gen") 56 | endif() 57 | endforeach() 58 | 59 | # Set the main project as the startup project 60 | set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT LLVM360) 61 | 62 | # Include LLVM directories 63 | list(APPEND CMAKE_MODULE_PATH "${LLVM_CMAKE_DIR}") 64 | include(AddLLVM) 65 | 66 | # Add subprojects 67 | add_subdirectory(llvm360/LLVMApp) 68 | add_subdirectory(llvm360/Runtime) 69 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # LLVM360 2 | 3 | ## Info 4 | 5 | This is just a little personal experiment i'm doing with llvm, the code is not good :} i took some stuff from the old redex's recompiler project like the XexLoader and some of the instructions decoded. 6 | 7 | --------------- 8 | Join the project [Discord][dis] server! 9 | 10 | ### Name 11 | "LLVM360" LLVM + xbox360, but it's just a temporany, i don't really like it so will probably change 12 | 13 | ## Building 14 | - Install LLVM Libs (I used [these][win-llvm]) 15 | - Move the files in something like C:/LLVM19 or wherever you prefer 16 | - Git Clone this repository 17 | - And Run `cmake -B out -DLLVM_USE_CRT_RELEASE=MT -DCMAKE_PREFIX_PATH=` (LLVM_BINS is the root folder where you stored your LLVM libs mine is "C:/LLVM19" for example) 18 | - In "out/" folder open the LLVM360.sln 19 | - If everything is good and i or you didn't messed up something, it should compile fine 20 | 21 | ## Contributing 22 | if want to contribute, make a fork and a PR :} also join the discord server! 23 | 24 | 25 | 26 | [win-llvm]: https://github.com/c3lang/win-llvm 27 | [dis]: https://discord.gg/JufwFS9mmf 28 | -------------------------------------------------------------------------------- /TODO.md: -------------------------------------------------------------------------------- 1 | # TODO LIST 2 | - Remove the need of the ctx tls Variable (i'm lazy), since now i'll just pass it as a parameter for new threads -------------------------------------------------------------------------------- /compile.bat: -------------------------------------------------------------------------------- 1 | C:/LLVM19/bin/llvm-as.exe output.ll -o input.bc 2 | #C:/LLVM19/bin/opt.exe -passes="mem2reg,sroa,gvn" input.bc -o optimized.bc 3 | #clang -O3 -target x86_64-pc-windows-msvc -fdeclspec -fms-extensions -fms-compatibility-version=19.42 -Wno-microsoft-cast -c optimized.bc -o input.o 4 | C:/LLVM19/bin/opt.exe input.bc -o optimized.bc 5 | clang -target x86_64-pc-windows-msvc -fdeclspec -fms-extensions -fms-compatibility-version=19.42 -Wno-microsoft-cast -c optimized.bc -o input.o 6 | 7 | "C:/Program Files/Microsoft Visual Studio/2022/Community/VC/Tools/MSVC/14.42.34433/bin/Hostx64/x64/link.exe" -out:output.exe -nologo input.o Runtime.lib "-libpath:C:\\Program Files\\Microsoft Visual Studio\\2022\\Community\\VC\\Tools\\MSVC\\14.42.34433\\lib\\x64" "-libpath:C:\\Program Files (x86)\\Windows Kits\\10\\Lib\\10.0.26100.0\\ucrt\\x64" "-libpath:C:\\Program Files (x86)\\Windows Kits\\10\\Lib\\10.0.26100.0\\um\\x64" -defaultlib:libcmt -defaultlib:oldnames kernel32.lib user32.lib advapi32.lib ole32.lib shell32.lib uuid.lib ucrt.lib vcruntime.lib -------------------------------------------------------------------------------- /llvm360/LLVMApp/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.15) 2 | cmake_policy(SET CMP0091 NEW) 3 | 4 | if(CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR) 5 | message(FATAL_ERROR "In-tree builds are not supported. Run CMake from a separate directory: cmake -B build") 6 | endif() 7 | 8 | # Hunter package configuration 9 | option(HUNTER_ENABLED "Enable the hunter package manager to automatically download and compile LLVM" OFF) 10 | if(HUNTER_ENABLED) 11 | include(cmake/HunterPackages.cmake) 12 | endif() 13 | 14 | 15 | project(LLVMApp) 16 | 17 | # Enable solution folder support 18 | set_property(GLOBAL PROPERTY USE_FOLDERS ON) 19 | 20 | # Require C++20 21 | set(CMAKE_CXX_STANDARD 20) 22 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 23 | set(CMAKE_PREFIX_PATH "C:/LLVM19/lib/cmake/llvm" ${CMAKE_PREFIX_PATH}) 24 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) 25 | 26 | 27 | list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") 28 | 29 | # Find LLVM 19 30 | find_package(LLVM CONFIG REQUIRED) 31 | 32 | if(LLVM_PACKAGE_VERSION VERSION_LESS "19.0" OR LLVM_PACKAGE_VERSION VERSION_GREATER_EQUAL "21.0") 33 | message(FATAL_ERROR "LLVM version ${LLVM_PACKAGE_VERSION} is incompatible. Expected version 19.x or 20.x.") 34 | else() 35 | message(STATUS "Using LLVM version ${LLVM_PACKAGE_VERSION}") 36 | endif() 37 | 38 | # Include LLVM directories 39 | list(APPEND CMAKE_MODULE_PATH "${LLVM_CMAKE_DIR}") 40 | include(AddLLVM) 41 | 42 | # MSVC-specific options 43 | if(MSVC) 44 | # Adjust compiler flags for better compatibility 45 | set(CMAKE_C_FLAGS_DEBUG "/ZI /Od /Ob0 /DNDEBUG" CACHE STRING "" FORCE) 46 | set(CMAKE_CXX_FLAGS_DEBUG "/ZI /Od /Ob0 /DNDEBUG" CACHE STRING "" FORCE) 47 | 48 | if(LLVM_USE_CRT_RELEASE STREQUAL "MD") 49 | set(CMAKE_MSVC_RUNTIME_LIBRARY MultiThreadedDLL) 50 | elseif(LLVM_USE_CRT_RELEASE STREQUAL "MT") 51 | set(CMAKE_MSVC_RUNTIME_LIBRARY MultiThreaded) 52 | else() 53 | message(FATAL_ERROR "Unsupported LLVM_USE_CRT_RELEASE=${LLVM_USE_CRT_RELEASE}") 54 | endif() 55 | endif() 56 | 57 | # Collect all source and header files in the src/ directory 58 | file(GLOB_RECURSE SOURCES "src/*.cpp" "src/*.h") 59 | 60 | # Add include directories for headers 61 | include_directories( 62 | ${CMAKE_CURRENT_SOURCE_DIR}/src # For local headers 63 | ${CMAKE_CURRENT_SOURCE_DIR}/../Xex # For headers in ../Xex 64 | ) 65 | 66 | # Add the executable target 67 | add_executable(LLVM360 ${SOURCES}) 68 | 69 | # Link with LLVM libraries 70 | llvm_map_components_to_libnames(LLVM_LIBS support core irreader bitwriter) 71 | target_link_libraries(LLVM360 PRIVATE ${LLVM_LIBS}) 72 | 73 | # Ensure LLVM headers and definitions are available 74 | include_directories(SYSTEM ${LLVM_INCLUDE_DIRS}) 75 | add_definitions(${LLVM_DEFINITIONS}) 76 | 77 | # Organize files into folders/filters matching the src/ directory 78 | foreach(SOURCE_FILE IN LISTS SOURCES) 79 | get_filename_component(SOURCE_PATH "${SOURCE_FILE}" PATH) 80 | file(RELATIVE_PATH REL_PATH "${CMAKE_CURRENT_SOURCE_DIR}/src" "${SOURCE_PATH}") 81 | string(REPLACE "/" "\\" FILTER_GROUP "${REL_PATH}") 82 | source_group("${FILTER_GROUP}" FILES "${SOURCE_FILE}") 83 | endforeach() 84 | -------------------------------------------------------------------------------- /llvm360/LLVMApp/src/Decoder/Instruction.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | 6 | struct Instruction { 7 | uint32_t address; 8 | uint32_t instrWord; 9 | std::string opcName; 10 | 11 | std::vector ops; 12 | 13 | inline operator std::string() { 14 | return opcName; 15 | } 16 | }; 17 | -------------------------------------------------------------------------------- /llvm360/LLVMApp/src/Decoder/InstructionDecoder.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "Instruction.h" 4 | #include "Xex/XexLoader.h" 5 | 6 | static inline uint32_t SwapInstrBytes(const uint32_t v) { 7 | uint32_t ret; 8 | const uint8_t *p = (const uint8_t *)&v; 9 | uint8_t *q = (uint8_t *)&ret; 10 | q[0] = p[3]; 11 | q[1] = p[2]; 12 | q[2] = p[1]; 13 | q[3] = p[0]; 14 | return ret; 15 | } 16 | 17 | class InstructionDecoder { 18 | public: 19 | InstructionDecoder(const Section *imageSection); 20 | uint32_t GetInstructionAt(uint32_t address, Instruction &instruction); 21 | uint32_t DecodeInstruction(const uint8_t *stride, Instruction &instruction); 22 | 23 | const Section *m_imageSection; 24 | uint64_t m_imageBaseAddress; 25 | uint64_t m_imageDataSize; 26 | const uint8_t *m_imageDataPtr; 27 | }; 28 | -------------------------------------------------------------------------------- /llvm360/LLVMApp/src/IR/IRFunc.cpp: -------------------------------------------------------------------------------- 1 | #include "IRFunc.h" 2 | #include 3 | #include 4 | 5 | 6 | 7 | 8 | // 9 | // Code Blocks 10 | // 11 | 12 | 13 | 14 | inline uint32_t signExtend(uint32_t value, int size) 15 | { 16 | if (value & (1 << (size - 1))) { 17 | return value | (~0 << size); 18 | } 19 | return value; 20 | } 21 | 22 | bool IRFunc::EmitFunction() 23 | { 24 | bool result; 25 | m_irGen->m_builder->SetInsertPoint(getCreateBBinMap(start_address)); 26 | 27 | uint32_t idx = this->start_address; 28 | if (start_address == 0x82014DA8) DebugBreak(); 29 | 30 | // discover start basic blocks 31 | while (idx <= this->end_address) 32 | { 33 | Instruction instr = m_irGen->instrsList.at(idx); 34 | if (strcmp(instr.opcName.c_str(), "b") == 0) 35 | { 36 | uint32_t target = idx + signExtend(instr.ops[0], 24); 37 | // check for tail calls 38 | if (!m_irGen->isIRFuncinMap(target)) 39 | { 40 | this->getCreateBBinMap(target); 41 | //this->getCreateBBinMap(instr.address + 4); 42 | } 43 | } 44 | if (strcmp(instr.opcName.c_str(), "bc") == 0) 45 | { 46 | this->getCreateBBinMap(instr.address + (int16_t)(instr.ops[2] << 2)); 47 | this->getCreateBBinMap(instr.address + 4); 48 | } 49 | 50 | 51 | if (has_jumpTable) 52 | { 53 | for (JumpTable* table : jumpTables) 54 | { 55 | if (instr.address >= table->start_Address && instr.address <= table->end_Address) 56 | { 57 | std::unordered_set processedValues; // do not allow duplicates 58 | for (uint32_t target : table->targets) 59 | { 60 | if (processedValues.find(target) == processedValues.end()) 61 | { 62 | getCreateBBinMap(target); 63 | processedValues.insert(target); 64 | } 65 | } 66 | } 67 | } 68 | } 69 | 70 | 71 | idx += 4; 72 | } 73 | 74 | CodeBlock* currentBlock = codeBlocks.at(start_address); 75 | idx = this->start_address; 76 | // discover end basic blocks 77 | while (idx <= this->end_address) 78 | { 79 | Instruction instr = m_irGen->instrsList.at(idx); 80 | if (isBBinMap(idx + 4)) 81 | { 82 | currentBlock->end = idx; 83 | currentBlock = codeBlocks.at(idx + 4); 84 | } 85 | if (strcmp(instr.opcName.c_str(), "bclr") == 0) 86 | { 87 | currentBlock->end = idx; 88 | } 89 | if(idx == this->end_address) 90 | { 91 | currentBlock->end = this->end_address; 92 | } 93 | idx += 4; 94 | } 95 | 96 | // can be optimized? 97 | // TODO 98 | 99 | // emit 100 | idx = this->start_address; 101 | while (idx <= this->end_address) 102 | { 103 | if (isBBinMap(idx)) 104 | { 105 | m_irGen->m_builder->SetInsertPoint(codeBlocks.at(idx)->bb_Block); 106 | 107 | CodeBlock* block = codeBlocks.at(idx); 108 | 109 | 110 | uint32_t blockIdx = block->address; 111 | while (blockIdx <= block->end) 112 | { 113 | Instruction instr = m_irGen->instrsList.at(blockIdx); 114 | 115 | if (!m_irGen->EmitInstruction(m_irGen->instrsList.at(blockIdx), this)) 116 | { 117 | __debugbreak(); 118 | return 1; 119 | } 120 | 121 | if (blockIdx != this->end_address && blockIdx == block->end && strcmp(instr.opcName.c_str(), "bclr") != 0 ) 122 | { 123 | m_irGen->m_builder->CreateBr(codeBlocks.at(block->end + 4)->bb_Block); 124 | } 125 | blockIdx += 4; 126 | 127 | } 128 | 129 | idx = blockIdx; 130 | } 131 | } 132 | 133 | 134 | return true; 135 | } 136 | 137 | void IRFunc::genBody() 138 | { 139 | std::ostringstream oss{}; 140 | oss << "func_" << std::hex << std::setfill('0') << std::setw(8) << start_address; 141 | 142 | llvm::FunctionType* mainType = llvm::FunctionType::get(m_irGen->m_builder->getVoidTy(), {m_irGen->XenonStateType->getPointerTo(), m_irGen->m_builder->getInt32Ty()}, false); 143 | m_irFunc = llvm::Function::Create(mainType, llvm::Function::ExternalLinkage, oss.str(), m_irGen->m_module); 144 | 145 | getCreateBBinMap(start_address); 146 | //m_irGen->m_builder->SetInsertPoint(getCreateBBinMap(start_address)); 147 | 148 | } 149 | 150 | llvm::BasicBlock* IRFunc::createBasicBlock(uint32_t address) 151 | { 152 | std::ostringstream oss{}; 153 | oss << "bb_" << std::hex << std::setfill('0') << std::setw(8) << address; 154 | return llvm::BasicBlock::Create(m_irGen->m_module->getContext(), oss.str(), m_irFunc); 155 | } 156 | 157 | llvm::BasicBlock* IRFunc::getCreateBBinMap(uint32_t address) 158 | { 159 | if (isBBinMap(address)) { 160 | return codeBlocks.at(address)->bb_Block; 161 | } 162 | CodeBlock* block = new CodeBlock(); 163 | block->bb_Block = createBasicBlock(address); 164 | block->address = address; 165 | codeBlocks.try_emplace(address, block); 166 | return block->bb_Block; 167 | } 168 | 169 | bool IRFunc::isBBinMap(uint32_t address) 170 | { 171 | return codeBlocks.find(address) != codeBlocks.end(); 172 | } 173 | 174 | 175 | // 176 | // LR -> 0 177 | // CTR -> 1 178 | // MSR -> 2 179 | // XER -> 3 180 | // CR -> 4 181 | // RR -> 5 182 | // FR -> 6 183 | // VX -> 7 184 | // 185 | 186 | llvm::Value* IRFunc::getRegister(const std::string& regName, int index1, int index2) 187 | { 188 | auto argIter = this->m_irFunc->arg_begin(); 189 | llvm::Argument* xCtx = &*argIter; 190 | 191 | 192 | if (regName == "LR" || regName == "CTR" || regName == "MSR" || regName == "XER") 193 | { 194 | int fieldIndex = (regName == "LR") ? 0 : 195 | (regName == "CTR") ? 1 : 196 | (regName == "MSR") ? 2 : 3; 197 | 198 | 199 | return m_irGen->m_builder->CreateStructGEP(m_irGen->XenonStateType, xCtx, fieldIndex, "spr_ptr"); 200 | } 201 | else if (regName == "CR") 202 | { 203 | return m_irGen->m_builder->CreateStructGEP(m_irGen->XenonStateType, xCtx, 4, "reg.CR"); 204 | } 205 | else if (regName == "RR") 206 | { 207 | assert(index1 != -1 && "Index for RR must be provided."); 208 | return m_irGen->m_builder->CreateGEP( 209 | llvm::Type::getInt64Ty(m_irGen->m_builder->getContext()), 210 | m_irGen->m_builder->CreateStructGEP(m_irGen->XenonStateType, xCtx, 5, "reg.RR"), 211 | llvm::ConstantInt::get(m_irGen->m_builder->getInt32Ty(), index1), 212 | "reg.RR[" + std::to_string(index1) + "]"); 213 | } 214 | else if (regName == "FR") 215 | { 216 | assert(index1 != -1 && "Index for FR must be provided."); 217 | return m_irGen->m_builder->CreateGEP( 218 | llvm::Type::getInt64Ty(m_irGen->m_builder->getContext()), 219 | m_irGen->m_builder->CreateStructGEP(m_irGen->XenonStateType, xCtx, 6, "reg.FR"), 220 | llvm::ConstantInt::get(m_irGen->m_builder->getInt32Ty(), index1), 221 | "reg.FR[" + std::to_string(index1) + "]"); 222 | } 223 | else { 224 | llvm::errs() << "Unknown register name: " << regName << "\n"; 225 | return nullptr; 226 | } 227 | } 228 | 229 | llvm::Value* IRFunc::getSPR(uint32_t n) 230 | { 231 | uint32_t spr4 = (n & 0b1111100000) >> 5; 232 | uint32_t spr9 = n & 0b0000011111; 233 | 234 | if (spr4 == 1) return this->getRegister("XER"); 235 | if (spr4 == 8) return this->getRegister("LR"); 236 | if (spr4 == 9) return this->getRegister("CTR"); 237 | return NULL; 238 | } -------------------------------------------------------------------------------- /llvm360/LLVMApp/src/IR/IRFunc.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include "IRGenerator.h" 5 | #include "JumpTables.h" 6 | 7 | 8 | struct CodeBlock 9 | { 10 | uint32_t address; 11 | uint32_t end; 12 | llvm::BasicBlock* bb_Block; 13 | }; 14 | 15 | class IRFunc { 16 | public: 17 | uint32_t start_address; 18 | uint32_t end_address; 19 | bool emission_done; 20 | std::unordered_map codeBlocks; 21 | llvm::Function* m_irFunc; 22 | 23 | bool EmitFunction(); 24 | void genBody(); 25 | 26 | llvm::BasicBlock* createBasicBlock(uint32_t address); 27 | llvm::BasicBlock* getCreateBBinMap(uint32_t address); 28 | bool isBBinMap(uint32_t address); 29 | llvm::Value* getRegister(const std::string& regName, int arrayIndex = -1, int index2 = -1); 30 | llvm::Value* getSPR(uint32_t n); 31 | 32 | IRGenerator* m_irGen; 33 | 34 | public: 35 | // 36 | // Metadata for bounds analyser 37 | // 38 | bool startW_MFSPR_LR; 39 | bool is_promotion; 40 | bool has_jumpTable; 41 | std::vector jumpTables; 42 | }; -------------------------------------------------------------------------------- /llvm360/LLVMApp/src/IR/IRGenerator.cpp: -------------------------------------------------------------------------------- 1 | #include "IRGenerator.h" 2 | #include "InstructionEmitter.h" 3 | #include 4 | #include 5 | #include 6 | 7 | 8 | 9 | IRGenerator::IRGenerator(XexImage *xex, llvm::Module* mod, llvm::IRBuilder* builder) 10 | : m_builder(builder) 11 | , m_module(mod) { 12 | m_xexImage = xex; 13 | } 14 | 15 | 16 | void IRGenerator::CxtSwapFunc() 17 | { 18 | tlsVariable = new llvm::GlobalVariable( 19 | *m_module, 20 | XenonStateType->getPointerTo(), 21 | false, 22 | llvm::GlobalValue::ExternalLinkage, 23 | llvm::ConstantPointerNull::get(XenonStateType->getPointerTo()), 24 | "xCtx", 25 | nullptr, 26 | llvm::GlobalValue::GeneralDynamicTLSModel, 27 | 0 28 | ); 29 | 30 | // getXCtxAddress func 31 | llvm::Type* retType = tlsVariable->getType(); 32 | 33 | llvm::FunctionType* funcType = llvm::FunctionType::get(retType, false); 34 | llvm::Function* getXCtxAddressFn = llvm::Function::Create( 35 | funcType, 36 | llvm::GlobalValue::ExternalLinkage, 37 | "getXCtxAddress", 38 | m_module 39 | ); 40 | 41 | getXCtxAddressFn->setDLLStorageClass(llvm::GlobalValue::DLLExportStorageClass); 42 | 43 | llvm::BasicBlock* entryBlock = llvm::BasicBlock::Create(m_builder->getContext(), "entry", getXCtxAddressFn); 44 | m_builder->SetInsertPoint(entryBlock); 45 | m_builder->CreateRet(tlsVariable); 46 | } 47 | 48 | void IRGenerator::initExtFunc() 49 | { 50 | llvm::FunctionType* importType = llvm::FunctionType::get(m_builder->getVoidTy(), { XenonStateType->getPointerTo(), m_builder->getInt32Ty() }, false); 51 | bcctrlFunc = llvm::Function::Create(importType, llvm::Function::ExternalLinkage, "HandleBcctrl", m_module); 52 | 53 | // XenonState, instrAddress, name 54 | llvm::FunctionType* callBkType = llvm::FunctionType::get(m_builder->getVoidTy(), { XenonStateType->getPointerTo(), m_builder->getInt32Ty(), m_builder->getInt8Ty()->getPointerTo() }, false); 55 | dBCallBackFunc = llvm::Function::Create(callBkType, llvm::Function::ExternalLinkage, "DebugCallBack", m_module); 56 | 57 | llvm::FunctionType* funcType = llvm::FunctionType::get(m_builder->getVoidTy(),false); 58 | dllTestFunc = llvm::Function::Create( 59 | funcType, 60 | llvm::Function::ExternalLinkage, 61 | "dllHack", 62 | m_module 63 | ); 64 | } 65 | 66 | void IRGenerator::InitLLVM() { 67 | 68 | CxtSwapFunc(); 69 | initExtFunc(); 70 | 71 | 72 | module_base = new llvm::GlobalVariable( 73 | *m_module, 74 | m_builder->getInt64Ty(), 75 | false, 76 | llvm::GlobalValue::ExternalLinkage, 77 | m_builder->getInt64(0), 78 | "moduleBase" 79 | ); 80 | module_base->setDLLStorageClass(llvm::GlobalValue::DLLExportStorageClass); 81 | 82 | // intrinsics types 83 | swap16 = llvm::Intrinsic::getDeclaration(m_module, llvm::Intrinsic::bswap, m_builder->getInt16Ty()); 84 | swap32 = llvm::Intrinsic::getDeclaration(m_module, llvm::Intrinsic::bswap, m_builder->getInt32Ty()); 85 | swap64 = llvm::Intrinsic::getDeclaration(m_module, llvm::Intrinsic::bswap, m_builder->getInt64Ty()); 86 | 87 | 88 | // main function / entry point 89 | llvm::FunctionType* mainType = llvm::FunctionType::get(m_builder->getInt32Ty(), false); 90 | mainFn = llvm::Function::Create(mainType, llvm::Function::ExternalLinkage, "main", m_module); 91 | llvm::BasicBlock* entry = llvm::BasicBlock::Create(m_module->getContext(), "Entry", mainFn); 92 | m_builder->SetInsertPoint(entry); 93 | 94 | xCtx = m_builder->CreateLoad( 95 | tlsVariable->getType()->getPointerTo(), 96 | tlsVariable, 97 | "xCtx" 98 | ); 99 | 100 | // 101 | // JUMP TO XEX ENTRY POINT 102 | // 103 | 104 | // add xex entry point function 105 | IRFunc* xex_entry = getCreateFuncInMap(m_xexImage->GetEntryAddress()); 106 | initFuncBody(xex_entry); 107 | m_builder->SetInsertPoint(entry); 108 | m_builder->CreateCall(dllTestFunc); 109 | m_builder->CreateCall(xex_entry->m_irFunc, { xCtx, llvm::ConstantInt::get(m_builder->getInt32Ty(), m_xexImage->GetEntryAddress())}); 110 | 111 | 112 | m_builder->SetInsertPoint(entry); 113 | 114 | m_builder->CreateCall(dllTestFunc); 115 | 116 | m_builder->CreateRet(llvm::ConstantInt::get(m_builder->getInt32Ty(), 0)); 117 | 118 | 119 | } 120 | 121 | void IRGenerator::exportFunctionArray() 122 | { 123 | 124 | llvm::Type* i32Ty = m_builder->getInt32Ty(); 125 | llvm::Type* i8PtrTy = m_builder->getInt8Ty()->getPointerTo(); 126 | 127 | // 128 | // Count 129 | // 130 | llvm::Constant* countConst = llvm::ConstantInt::get(i32Ty, m_function_map.size()); 131 | llvm::GlobalVariable* countGV = new llvm::GlobalVariable( 132 | *m_module, 133 | i32Ty, 134 | true, 135 | llvm::GlobalValue::ExternalLinkage, 136 | countConst, 137 | "X_FunctionArrayCount" 138 | ); 139 | 140 | // 141 | // Array 142 | // 143 | std::vector fieldTypes = { i32Ty, i8PtrTy }; 144 | llvm::StructType* xFuncType = llvm::StructType::create(m_module->getContext(), fieldTypes, "X_Function"); 145 | std::vector initElements; 146 | for (const auto& pair : m_function_map) 147 | { 148 | IRFunc* func = pair.second; 149 | llvm::Constant* addrConst = llvm::ConstantInt::get(i32Ty, func->start_address, false); 150 | llvm::Constant* funcPtr = llvm::ConstantExpr::getBitCast(func->m_irFunc, i8PtrTy); 151 | std::vector structFields = { addrConst, funcPtr }; 152 | llvm::Constant* xFuncConst = llvm::ConstantStruct::get(xFuncType, structFields); 153 | initElements.push_back(xFuncConst); 154 | } 155 | 156 | 157 | llvm::ArrayType* arrType = llvm::ArrayType::get(xFuncType, initElements.size()); 158 | llvm::Constant* arrInit = llvm::ConstantArray::get(arrType, initElements); 159 | llvm::GlobalVariable* exportArrGV = new llvm::GlobalVariable( 160 | *m_module, 161 | arrType, 162 | true, 163 | llvm::GlobalValue::ExternalLinkage, 164 | arrInit, 165 | "X_FunctionArray" 166 | ); 167 | 168 | countGV->setDLLStorageClass(llvm::GlobalValue::DLLExportStorageClass); 169 | exportArrGV->setDLLStorageClass(llvm::GlobalValue::DLLExportStorageClass); 170 | } 171 | 172 | void IRGenerator::Initialize() { 173 | InitLLVM(); 174 | } 175 | 176 | bool first = true; 177 | 178 | #define DEBUG_COMMENT(x) m_builder->CreateAdd(m_builder->getInt32(0), m_builder->getInt32(0), x); 179 | #define DEBUG_CALLBACK() m_builder->CreateCall(dBCallBackFunc, { &*func->m_irFunc->arg_begin(), m_builder->getInt32(instr.address), m_builder->CreateGlobalStringPtr(instr.opcName) }); 180 | 181 | bool IRGenerator::EmitInstruction(Instruction instr, IRFunc* func) { 182 | // EEHHE can't use a std::string in a switch statement sooo... 183 | // let's map all the instruction names (as i already needed to do with a switch statement) 184 | // in a vector, so i can look up the instr opcode name in that vector and call the instruction 185 | // emitter 186 | // all emitter functions take as parameter 187 | 188 | // Debug, help to find the instruction and debug IR code 189 | std::ostringstream oss; 190 | oss << std::hex << std::uppercase << std::setfill('0'); 191 | oss << "------ " << std::setw(8) << instr.address << ": " << instr.opcName; 192 | 193 | for (size_t i = 0; i < instr.ops.size(); ++i) { 194 | oss << " " << std::setw(2) << static_cast(instr.ops.at(i)); 195 | } 196 | oss << " ------"; 197 | DEBUG_COMMENT(oss.str().c_str()) 198 | 199 | if (m_dbCallBack) 200 | { 201 | DEBUG_CALLBACK(); 202 | } 203 | 204 | // _e = _emitter 205 | static std::unordered_map> 206 | instructionMap = 207 | { 208 | {"nop", nop_e }, 209 | {"twi", twi_e }, 210 | {"tdi", tdi_e}, 211 | {"mfspr", mfspr_e }, 212 | {"mfcr", mfcr_e}, // 213 | {"stw", stw_e }, 214 | {"stwu", stwu_e }, 215 | {"lis", addis_e }, // it's a simplified mnemonic 216 | {"addis", addis_e }, 217 | {"li", addi_e }, 218 | {"addi", addi_e }, 219 | {"lwz", lwz_e }, 220 | {"lwzu", lwzu_e }, 221 | {"lwzx", lwzx_e}, 222 | {"mtspr", mtspr_e }, 223 | {"or", orx_e }, 224 | {"orRC", orx_e}, 225 | {"sth", sth_e }, 226 | {"sthu", sthu_e}, 227 | {"sthx", sthx_e}, 228 | {"b", b_e }, 229 | {"bl", bl_e }, 230 | {"bclr", bclr_e }, 231 | {"bcctrl", bcctrl_e}, 232 | {"lhz", lhz_e }, 233 | {"lhzu", lhzu_e}, 234 | {"lha", lha_e}, 235 | {"lhzx", lhzx_e}, 236 | {"cmpw", cmpw_e}, 237 | {"bc", bcx_e}, 238 | {"add", add_e}, 239 | {"ori", ori_e}, 240 | {"cmpwi", cmpi_e}, 241 | {"cmpdi", cmpi_e}, 242 | {"neg", neg_e}, 243 | {"and", and_e}, 244 | {"xor", xor_e}, 245 | {"rlwinmRC", rlwinm_e}, 246 | {"rlwinm", rlwinm_e}, 247 | {"mullw", mullw_e}, 248 | {"mullwRC", mullw_e}, 249 | {"srawi", srawi_e}, 250 | {"divw", divwx_e}, 251 | {"andc", andc_e}, 252 | {"subf", subf_e}, 253 | {"subfe", subfe_e}, 254 | {"subfRC", subf_e}, 255 | {"subfeRC", subfe_e}, 256 | {"stwx", stwx_e}, 257 | {"cmplwi", cmpli_e}, 258 | {"mulli", mulli_e}, 259 | {"std", std_e}, 260 | {"stdu", stdu_e}, 261 | {"lbz", lbz_e}, 262 | {"lbzu", lbzu_e}, 263 | {"lbzx", lbzx_e}, 264 | {"bcctr", bcctr_e}, 265 | {"xori", xori_e}, 266 | {"nor", nor_e}, 267 | {"cntlzw", cntlzw_e}, 268 | {"andiRC", andiRC_e}, 269 | {"stb", stb_e}, 270 | {"stbu", stbu_e}, 271 | {"extsw", extsw_e}, 272 | {"extswRC", extsw_e}, 273 | {"extsh", extsh_e}, 274 | {"extshRC", extsh_e}, 275 | {"extsb", extsb_e}, // 276 | {"extsbRC", extsb_e}, // 277 | {"cmplw", cmpl_e}, // 278 | {"ld", ld_e}, 279 | {"adde", adde_e}, // 280 | {"addic", addic_e}, 281 | {"addicRC", addic_e}, // 282 | {"slw", slw_e}, // 283 | {"adde", adde_e}, // 284 | {"addze", addze_e}, 285 | {"addzeRC", addze_e}, 286 | {"oris", oris_e}, 287 | {"rlwimi", rlwimi_e}, 288 | {"subfic", subfic_e}, 289 | {"rldicl", rldicl_e}, 290 | {"lwa", lwa_e}, 291 | {"divdu", divdu_e}, 292 | {"divwu", divwux_e}, 293 | {"mulld", mulld_e}, 294 | {"dcbt", dcbt_e}, 295 | {"dcbtst", dcbtst_e}, 296 | {"ldu", ldu_e}, 297 | 298 | {"cmpldi", cmpli_e}, 299 | }; 300 | 301 | 302 | if (instructionMap.find(instr.opcName) != instructionMap.end()) { 303 | instructionMap[instr.opcName](instr, func); 304 | return true; 305 | } else { 306 | printf("Instruction: %s not Implemented\n", instr.opcName.c_str()); 307 | } 308 | 309 | writeIRtoFile(); 310 | 311 | return false; 312 | } 313 | 314 | 315 | 316 | 317 | void IRGenerator::writeIRtoFile() 318 | { 319 | 320 | 321 | printf("----IR DUMP----\n\n\n"); 322 | if (m_dumpIRConsole) 323 | { 324 | llvm::raw_fd_ostream& out = llvm::outs(); 325 | m_module->print(out, nullptr); 326 | } 327 | 328 | 329 | std::error_code EC; 330 | llvm::raw_fd_ostream OS("../../bin/Debug/output.ll", EC); 331 | if (EC) { 332 | llvm::errs() << "Error writing to file: " << EC.message() << "\n"; 333 | } 334 | else { 335 | m_module->print(OS, nullptr); 336 | } 337 | OS.close(); 338 | } 339 | 340 | 341 | 342 | // 343 | // Func Helpers 344 | // 345 | 346 | void IRGenerator::initFuncBody(IRFunc* func) 347 | { 348 | if (func->m_irFunc != nullptr) 349 | { 350 | printf("Function Body already exist\n"); 351 | return; 352 | } 353 | 354 | func->genBody(); 355 | } 356 | 357 | IRFunc* IRGenerator::getCreateFuncInMap(uint32_t address) 358 | { 359 | if (isIRFuncinMap(address)) { 360 | return m_function_map.at(address); 361 | } 362 | IRFunc* func = new IRFunc(); 363 | func->start_address = address; 364 | func->end_address = NULL; 365 | func->m_irGen = this; 366 | m_function_map.try_emplace(address, func); 367 | return func; 368 | } 369 | 370 | bool IRGenerator::isIRFuncinMap(uint32_t address) 371 | { 372 | return m_function_map.find(address) != m_function_map.end(); 373 | } -------------------------------------------------------------------------------- /llvm360/LLVMApp/src/IR/IRGenerator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include "llvm/IR/BasicBlock.h" 5 | #include "llvm/IR/IRBuilder.h" 6 | #include "llvm/IR/Module.h" 7 | #include 8 | #include "llvm/IR/LLVMContext.h" 9 | #include "llvm/Support/MemoryBuffer.h" 10 | #include "llvm/Support/raw_ostream.h" 11 | #include "llvm/IR/InlineAsm.h" 12 | 13 | #include "Xex/XexLoader.h" 14 | #include "Decoder/Instruction.h" 15 | #include 16 | #include 17 | 18 | class IRFunc; 19 | 20 | 21 | 22 | class IRGenerator { 23 | public: 24 | // llvm references 25 | llvm::IRBuilder* m_builder; 26 | llvm::Module* m_module; 27 | // Xenon State stuff 28 | XexImage *m_xexImage; 29 | bool m_dbCallBack; 30 | bool m_dumpIRConsole; 31 | 32 | IRGenerator(XexImage *xex, llvm::Module* mod, llvm::IRBuilder* builder); 33 | void Initialize(); 34 | bool EmitInstruction(Instruction instr, IRFunc* func); 35 | void InitLLVM(); 36 | void writeIRtoFile(); 37 | void CxtSwapFunc(); 38 | void exportFunctionArray(); 39 | void initExtFunc(); 40 | 41 | 42 | llvm::Function* dBCallBackFunc; 43 | llvm::Function* bcctrlFunc; 44 | llvm::Function* dllTestFunc; 45 | 46 | llvm::Function* swap16; 47 | llvm::Function* swap32; 48 | llvm::Function* swap64; 49 | llvm::Value* xCtx; 50 | llvm::GlobalVariable* tlsVariable; 51 | llvm::GlobalVariable* module_base; 52 | llvm::StructType* XenonStateType = llvm::StructType::create( 53 | m_builder->getContext(), { 54 | llvm::Type::getInt64Ty(m_builder->getContext()), // LR 55 | llvm::Type::getInt64Ty(m_builder->getContext()), // CTR 56 | llvm::Type::getInt64Ty(m_builder->getContext()), // MSR 57 | llvm::Type::getInt64Ty(m_builder->getContext()), // XER 58 | llvm::Type::getInt32Ty(m_builder->getContext()), // CR 59 | llvm::ArrayType::get(llvm::Type::getInt64Ty(m_builder->getContext()), 32), // RR 60 | llvm::ArrayType::get(llvm::Type::getDoubleTy(m_builder->getContext()), 32), // FR 61 | //llvm::ArrayType::get(llvm::ArrayType::get(llvm::Type::getInt64Ty(m_builder->getContext()), 2), 128) // VR 62 | }, "xenonState"); 63 | 64 | void initFuncBody(IRFunc* func); 65 | IRFunc* getCreateFuncInMap(uint32_t address); 66 | bool isIRFuncinMap(uint32_t address); 67 | 68 | llvm::Function* mainFn; 69 | std::unordered_map m_function_map; 70 | std::unordered_map instrsList; 71 | }; 72 | 73 | 74 | -------------------------------------------------------------------------------- /llvm360/LLVMApp/src/IR/JumpTables.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "IRGenerator.h" 3 | 4 | 5 | 6 | static const std::vector COMPUTED_TABLE_0_pattern = { "lis", "addi", "lbzx", "rlwinm", "lis", "ori", "addi", "add", "mtspr", "bcctr" }; 7 | static const std::vector OFFSET_TABLE_0_pattern = { "lis", "addi", "lbzx", "lis", "ori", "addi", "ori", "add", "mtspr", "bcctr" }; 8 | static const std::vector WORDOFFSET_TABLE_0_pattern = { "lis", "rlwinm", "addi", "lhzx", "lis", "addi", "ori", "add", "mtspr", "bcctr" }; 9 | 10 | enum JTVariantEnum 11 | { 12 | COMPUTED_TABLE_0, 13 | OFFSET_TABLE_0, 14 | WORDOFFSET_TABLE_0, 15 | ENUM_SIZE 16 | }; 17 | 18 | struct JTVariant 19 | { 20 | JTVariantEnum type; 21 | std::vector pattern; 22 | }; 23 | 24 | static const std::array jtVariantTypes = { 25 | JTVariant{COMPUTED_TABLE_0, COMPUTED_TABLE_0_pattern}, 26 | JTVariant{OFFSET_TABLE_0, OFFSET_TABLE_0_pattern}, 27 | JTVariant{WORDOFFSET_TABLE_0, WORDOFFSET_TABLE_0_pattern}, 28 | }; 29 | 30 | inline uint16_t ByteSwap16(uint16_t value) 31 | { 32 | return (value << 8) | (value >> 8); 33 | } 34 | 35 | // Define a jump table inside a function 36 | // `targets` are the addresses of the cases, index 0 is always the default case 37 | class JumpTable 38 | { 39 | public: 40 | uint32_t start_Address; 41 | uint32_t end_Address; 42 | JTVariant variant; 43 | uint32_t numTargets; 44 | std::vector targets; 45 | 46 | void ComputeTargets(IRGenerator* irGen) 47 | { 48 | 49 | findTargetsSize(irGen); 50 | 51 | switch (variant.type) 52 | { 53 | case COMPUTED_TABLE_0: 54 | { 55 | uint32_t off = 0; 56 | Instruction instr = irGen->instrsList.at(start_Address); 57 | off = instr.ops[2] << 16; 58 | instr = irGen->instrsList.at(start_Address + 4); 59 | off += instr.ops[2]; 60 | 61 | 62 | 63 | Section* sec = irGen->m_xexImage->getSectionByAddressBounds(off); 64 | const uint8_t* m_imageDataPtr = (const uint8_t*)sec->GetImage()->GetMemory() + (sec->GetVirtualOffset() - sec->GetImage()->GetBaseAddress()); 65 | const auto* offsets = (uint8_t*)m_imageDataPtr + off - sec->GetVirtualOffset(); 66 | 67 | instr = irGen->instrsList.at(start_Address + (4 * 4)); // lis 68 | uint32_t baseAddr = instr.ops[2] << 16; 69 | instr = irGen->instrsList.at(start_Address + (6 * 4)); // addi 70 | baseAddr += instr.ops[2]; 71 | instr = irGen->instrsList.at(start_Address + (3 * 4)); // rlwinm 72 | uint32_t sh = instr.ops[2]; 73 | 74 | for (size_t i = 1; i < numTargets; i++) 75 | { 76 | targets.push_back(baseAddr + (offsets[i] << sh)); 77 | } 78 | break; 79 | } 80 | 81 | case OFFSET_TABLE_0: 82 | { 83 | uint32_t off = 0; 84 | Instruction instr = irGen->instrsList.at(start_Address); 85 | off = instr.ops[2] << 16; 86 | instr = irGen->instrsList.at(start_Address + 4); 87 | off += instr.ops[2]; 88 | 89 | Section* sec = irGen->m_xexImage->getSectionByAddressBounds(off); 90 | const uint8_t* m_imageDataPtr = (const uint8_t*)sec->GetImage()->GetMemory() + (sec->GetVirtualOffset() - sec->GetImage()->GetBaseAddress()); 91 | const auto* offsets = (uint8_t*)m_imageDataPtr + off - sec->GetVirtualOffset(); 92 | 93 | instr = irGen->instrsList.at(start_Address + (3 * 4)); // lis 94 | uint32_t baseAddr = instr.ops[2] << 16; 95 | instr = irGen->instrsList.at(start_Address + (5 * 4)); // addi 96 | baseAddr += instr.ops[2]; 97 | 98 | 99 | for (size_t i = 1; i < numTargets; i++) 100 | { 101 | targets.push_back(baseAddr + offsets[i]); 102 | } 103 | break; 104 | } 105 | 106 | case WORDOFFSET_TABLE_0: 107 | { 108 | uint32_t off = 0; 109 | Instruction instr = irGen->instrsList.at(start_Address); 110 | off = instr.ops[2] << 16; 111 | instr = irGen->instrsList.at(start_Address + 8); // addi 112 | off += instr.ops[2]; 113 | 114 | Section* sec = irGen->m_xexImage->getSectionByAddressBounds(off); 115 | const uint8_t* m_imageDataPtr = (const uint8_t*)sec->GetImage()->GetMemory() + (sec->GetVirtualOffset() - sec->GetImage()->GetBaseAddress()); 116 | // uint16_t 117 | const uint8_t* offsets = (uint8_t*)m_imageDataPtr + off - sec->GetVirtualOffset(); 118 | const uint16_t* wordOffsets = reinterpret_cast(offsets); 119 | 120 | instr = irGen->instrsList.at(start_Address + (4 * 4)); // lis 121 | uint32_t baseAddr = instr.ops[2] << 16; 122 | instr = irGen->instrsList.at(start_Address + (5 * 4)); // addi 123 | baseAddr += instr.ops[2]; 124 | 125 | 126 | for (size_t i = 1; i < numTargets; i++) 127 | { 128 | targets.push_back(baseAddr + ByteSwap16( wordOffsets[i])); 129 | } 130 | break; 131 | } 132 | 133 | break; 134 | 135 | default: 136 | break; 137 | } 138 | } 139 | 140 | private: 141 | 142 | void findTargetsSize(IRGenerator* irGen) 143 | { 144 | uint32_t field = -1; 145 | for (size_t i = 0; i < 10; i++) 146 | { 147 | Instruction instr = irGen->instrsList.at(start_Address - (i * 4)); 148 | 149 | if (strcmp(instr.opcName.c_str(), "bc") == 0 || strcmp(instr.opcName.c_str(), "bca") == 0) 150 | { 151 | field = instr.ops[1] / 4; 152 | uint32_t defaultTarget = instr.address + (instr.ops[2] << 2); 153 | targets.push_back(defaultTarget); 154 | } 155 | else if (strcmp(instr.opcName.c_str(), "cmplwi") == 0 && field == instr.ops[0]) // check if the field is the same as the BC 156 | { 157 | numTargets = instr.ops[3] + 1; 158 | break; 159 | } 160 | } 161 | } 162 | }; 163 | -------------------------------------------------------------------------------- /llvm360/LLVMApp/src/IR/Unit/UnitTesting.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | //#include "../InstructionEmitter.h" 4 | 5 | // 6 | // This header contains all the various unit tests of every single insturction to ensure 7 | // it the instruction works exaclty how it should 8 | // i'll add unit tests each time i implement a new instruction emitter 9 | // i can view the register dump via the runtime CpuContext dumper 10 | // 11 | 12 | inline void unit_mfspr(IRFunc* func, IRGenerator* gen, std::vector ops) 13 | { 14 | Instruction instr; 15 | instr.ops = ops; 16 | mfspr_e(instr, func); 17 | } 18 | 19 | inline void unit_stfd(IRFunc* func, IRGenerator* gen, std::vector ops) 20 | { 21 | Instruction instr; 22 | instr.ops = ops; 23 | stfd_e(instr, func); 24 | } 25 | 26 | inline void unit_stw(IRFunc* func, IRGenerator* gen, std::vector ops) 27 | { 28 | Instruction instr; 29 | instr.ops = ops; 30 | stw_e(instr, func); 31 | } 32 | 33 | inline void unit_stwu(IRFunc* func, IRGenerator* gen, std::vector ops) 34 | { 35 | Instruction instr; 36 | instr.ops = ops; 37 | stwu_e(instr, func); 38 | } 39 | 40 | inline void unit_lis(IRFunc* func, IRGenerator* gen, std::vector ops) 41 | { 42 | Instruction instr; 43 | instr.ops = ops; 44 | addis_e(instr, func); 45 | } 46 | 47 | inline void unit_li(IRFunc* func, IRGenerator* gen, std::vector ops) 48 | { 49 | Instruction instr; 50 | instr.ops = ops; 51 | addi_e(instr, func); 52 | } 53 | 54 | inline void unit_divw(IRFunc* func, IRGenerator* gen, std::vector ops) 55 | { 56 | Instruction instr; 57 | instr.ops = ops; 58 | divwx_e(instr, func); 59 | } 60 | 61 | inline void unit_divdu(IRFunc* func, IRGenerator* gen, std::vector ops) 62 | { 63 | Instruction instr; 64 | instr.ops = ops; 65 | divdu_e(instr, func); 66 | } 67 | 68 | inline void unit_mulli(IRFunc* func, IRGenerator* gen, std::vector ops) 69 | { 70 | Instruction instr; 71 | instr.ops = ops; 72 | mulli_e(instr, func); 73 | } 74 | 75 | inline void unit_subf(IRFunc* func, IRGenerator* gen, std::vector ops) 76 | { 77 | Instruction instr; 78 | instr.ops = ops; 79 | subf_e(instr, func); 80 | } 81 | 82 | inline void unit_lwz(IRFunc* func, IRGenerator* gen, std::vector ops) 83 | { 84 | Instruction instr; 85 | instr.ops = ops; 86 | lwz_e(instr, func); 87 | } 88 | 89 | inline void unit_cmpw(IRFunc* func, IRGenerator* gen, std::vector ops) 90 | { 91 | Instruction instr; 92 | instr.ops = ops; 93 | cmpw_e(instr, func); 94 | } 95 | 96 | inline void unit_bclr(IRFunc* func, IRGenerator* gen, std::vector ops) 97 | { 98 | Instruction instr; 99 | instr.ops = ops; 100 | bclr_e(instr, func); 101 | } 102 | 103 | inline void unit_srawi(IRFunc* func, IRGenerator* gen, std::vector ops) 104 | { 105 | Instruction instr; 106 | instr.ops = ops; 107 | srawi_e(instr, func); 108 | } 109 | 110 | inline void unit_cntlzw(IRFunc* func, IRGenerator* gen, std::vector ops) 111 | { 112 | Instruction instr; 113 | instr.ops = ops; 114 | cntlzw_e(instr, func); 115 | } 116 | 117 | inline void unit_slw(IRFunc* func, IRGenerator* gen, std::vector ops) 118 | { 119 | Instruction instr; 120 | instr.ops = ops; 121 | slw_e(instr, func); 122 | } 123 | 124 | inline void unit_mfcr(IRFunc* func, IRGenerator* gen, std::vector ops) 125 | { 126 | Instruction instr; 127 | instr.ops = ops; 128 | mfcr_e(instr, func); 129 | } 130 | 131 | inline void unit_adde(IRFunc* func, IRGenerator* gen, std::vector ops) 132 | { 133 | Instruction instr; 134 | instr.ops = ops; 135 | adde_e(instr, func); 136 | } 137 | 138 | inline void unit_addicRC(IRFunc* func, IRGenerator* gen, std::vector ops) 139 | { 140 | Instruction instr; 141 | instr.ops = ops; 142 | instr.opcName = "addicRC"; 143 | addic_e(instr, func); 144 | } 145 | 146 | inline void unit_addic(IRFunc* func, IRGenerator* gen, std::vector ops) 147 | { 148 | Instruction instr; 149 | instr.ops = ops; 150 | addic_e(instr, func); 151 | } 152 | 153 | inline void unit_extsb(IRFunc* func, IRGenerator* gen, std::vector ops) 154 | { 155 | Instruction instr; 156 | instr.ops = ops; 157 | extsb_e(instr, func); 158 | } 159 | 160 | inline void unit_extsbRC(IRFunc* func, IRGenerator* gen, std::vector ops) 161 | { 162 | Instruction instr; 163 | instr.ops = ops; 164 | instr.opcName = "extsbRC"; 165 | extsb_e(instr, func); 166 | } 167 | 168 | inline void unit_cmplw(IRFunc* func, IRGenerator* gen, std::vector ops) 169 | { 170 | Instruction instr; 171 | instr.ops = ops; 172 | cmpl_e(instr, func); 173 | } 174 | 175 | inline void unit_rlwimi(IRFunc* func, IRGenerator* gen, std::vector ops) 176 | { 177 | Instruction instr; 178 | instr.ops = ops; 179 | rlwimi_e(instr, func); 180 | } 181 | 182 | inline void unit_ori(IRFunc* func, IRGenerator* gen, std::vector ops) 183 | { 184 | Instruction instr; 185 | instr.ops = ops; 186 | ori_e(instr, func); 187 | } 188 | 189 | inline void unit_oris(IRFunc* func, IRGenerator* gen, std::vector ops) 190 | { 191 | Instruction instr; 192 | instr.ops = ops; 193 | oris_e(instr, func); 194 | } 195 | 196 | inline void unit_rldicl(IRFunc* func, IRGenerator* gen, std::vector ops) 197 | { 198 | Instruction instr; 199 | instr.ops = ops; 200 | rldicl_e(instr, func); 201 | } 202 | 203 | inline void unit_cmpdi(IRFunc* func, IRGenerator* gen, std::vector ops) 204 | { 205 | Instruction instr; 206 | instr.ops = ops; 207 | cmpi_e(instr, func); 208 | } 209 | 210 | inline void unit_cmpwi(IRFunc* func, IRGenerator* gen, std::vector ops) 211 | { 212 | Instruction instr; 213 | instr.ops = ops; 214 | cmpi_e(instr, func); 215 | } -------------------------------------------------------------------------------- /llvm360/LLVMApp/src/LLVM360.cpp: -------------------------------------------------------------------------------- 1 | #include "Util.h" 2 | 3 | 4 | 5 | 6 | void SaveSectionToBin(const char* filename, const uint8_t* dataPtr, size_t dataSize) 7 | { 8 | std::ofstream binFile(filename, std::ios::binary); 9 | if (!binFile) 10 | { 11 | printf("Error: Cannot open file %s for writing\n", filename); 12 | return; 13 | } 14 | binFile.write(reinterpret_cast(dataPtr), dataSize); 15 | binFile.close(); 16 | } 17 | 18 | 19 | 20 | void saveSection(const char* path, uint32_t idx) 21 | { 22 | const Section* section = loadedXex->GetSection(idx); 23 | const auto baseAddress = loadedXex->GetBaseAddress(); 24 | const auto sectionBaseAddress = baseAddress + section->GetVirtualOffset(); 25 | auto endAddress = baseAddress + section->GetVirtualOffset() + section->GetVirtualSize(); 26 | auto address = sectionBaseAddress; 27 | const uint8_t* m_imageDataPtr = (const uint8_t*)section->GetImage()->GetMemory() + (section->GetVirtualOffset() - section->GetImage()->GetBaseAddress()); 28 | const uint64_t offset = address - section->GetVirtualOffset(); 29 | 30 | SaveSectionToBin(path, (uint8_t*)m_imageDataPtr + offset, section->GetVirtualSize()); 31 | } 32 | 33 | 34 | Section* findSection(std::string name) 35 | { 36 | for (uint32_t i = 0; i < loadedXex->GetNumSections(); i++) 37 | { 38 | if (strcmp(loadedXex->GetSection(i)->GetName().c_str(), name.c_str()) == 0) 39 | { 40 | return loadedXex->GetSection(i); 41 | } 42 | } 43 | 44 | printf("No Section with name: s& found", name); 45 | return nullptr; 46 | } 47 | 48 | 49 | 50 | void exportMetadata(const char* path) 51 | { 52 | EXPMD_Header header; 53 | header.magic = 0x54535338; 54 | header.version = 4; 55 | header.flags = 0; 56 | header.baseAddress = loadedXex->GetBaseAddress(); 57 | 58 | 59 | std::vector lonelyVariables; 60 | for (const auto& imp : loadedXex->m_imports) 61 | { 62 | if (imp->type == VARIABLE) { 63 | auto it = std::find_if(loadedXex->m_imports.begin(), loadedXex->m_imports.end(), [&](const Import* other) 64 | { 65 | return other->type == FUNCTION && other->name == imp->name; 66 | }); 67 | 68 | if (it == loadedXex->m_imports.end()) { 69 | lonelyVariables.push_back(imp); 70 | } 71 | } 72 | } 73 | 74 | header.num_impVars = lonelyVariables.size(); 75 | header.imp_Vars = new EXPMD_IMPVar * [header.num_impVars]; 76 | header.numSections = loadedXex->GetNumSections(); 77 | header.sections = new EXPMD_Section * [header.numSections]; 78 | 79 | for (uint32_t i = 0; i < header.numSections; i++) 80 | { 81 | Section* section = loadedXex->GetSection(i); 82 | EXPMD_Section* sec = new EXPMD_Section(); 83 | sec->dat_offset = section->GetVirtualOffset(); 84 | sec->size = section->GetVirtualSize(); 85 | sec->flags = 0; 86 | sec->sec_name = (char*)section->GetName().c_str(); 87 | 88 | 89 | const auto baseAddress = loadedXex->GetBaseAddress(); 90 | const auto sectionBaseAddress = baseAddress + section->GetVirtualOffset(); 91 | auto endAddress = baseAddress + section->GetVirtualOffset() + section->GetVirtualSize(); 92 | auto address = sectionBaseAddress; 93 | const uint8_t* m_imageDataPtr = (const uint8_t*)section->GetImage()->GetMemory() + (section->GetVirtualOffset() - section->GetImage()->GetBaseAddress()); 94 | const uint64_t offset = address - section->GetVirtualOffset(); 95 | 96 | sec->data = (uint8_t*)m_imageDataPtr + offset; 97 | header.sections[i] = sec; 98 | } 99 | 100 | for (uint32_t i = 0; i < header.num_impVars; i++) 101 | { 102 | Import* imp = lonelyVariables[i]; 103 | EXPMD_IMPVar* impVar = new EXPMD_IMPVar(); 104 | impVar->name = imp->name; 105 | impVar->addr = imp->tableAddr; 106 | header.imp_Vars[i] = impVar; 107 | } 108 | 109 | std::ofstream binFile(path, std::ios::binary); 110 | if (!binFile) 111 | { 112 | printf("Error: Cannot open file %s for writing\n", path); 113 | return; 114 | } 115 | 116 | binFile.write(reinterpret_cast(&header.magic), sizeof(uint32_t)); 117 | binFile.write(reinterpret_cast(&header.version), sizeof(uint32_t)); 118 | binFile.write(reinterpret_cast(&header.flags), sizeof(uint32_t)); 119 | binFile.write(reinterpret_cast(&header.baseAddress), sizeof(uint32_t)); 120 | binFile.write(reinterpret_cast(&header.numSections), sizeof(uint32_t)); 121 | binFile.write(reinterpret_cast(&header.num_impVars), sizeof(uint32_t)); 122 | 123 | for (uint32_t i = 0; i < header.num_impVars; i++) 124 | { 125 | EXPMD_IMPVar impVar = *header.imp_Vars[i]; 126 | uint32_t nameLength = impVar.name.size(); 127 | binFile.write(reinterpret_cast(&nameLength), sizeof(uint32_t)); 128 | binFile.write(impVar.name.c_str(), impVar.name.size()); 129 | 130 | binFile.write(reinterpret_cast(&impVar.addr), sizeof(uint32_t)); 131 | } 132 | 133 | for (uint32_t i = 0; i < header.numSections; i++) 134 | { 135 | EXPMD_Section sec = *header.sections[i]; 136 | binFile.write(reinterpret_cast(&sec.dat_offset), sizeof(uint32_t)); 137 | binFile.write(reinterpret_cast(&sec.size), sizeof(uint32_t)); 138 | binFile.write(reinterpret_cast(&sec.flags), sizeof(uint32_t)); 139 | uint32_t nameLength = sec.sec_name.size(); 140 | binFile.write(reinterpret_cast(&nameLength), sizeof(uint32_t)); 141 | binFile.write(sec.sec_name.c_str(), sec.sec_name.size()); 142 | binFile.write(reinterpret_cast(sec.data), sec.size); 143 | } 144 | 145 | binFile.close(); 146 | } 147 | 148 | void unitTest(IRGenerator* gen) 149 | { 150 | IRFunc* func = gen->getCreateFuncInMap(loadedXex->GetEntryAddress()); 151 | func->genBody(); 152 | gen->m_builder->SetInsertPoint(func->codeBlocks.at(func->start_address)->bb_Block); 153 | 154 | // 155 | // code 156 | // 157 | 158 | /*li r4, -1 159 | li r5, 1 160 | divdu r3, r4, r5 161 | blr 162 | #_ REGISTER_OUT r3 0xFFFFFFFFFFFFFFFF 163 | #_ REGISTER_OUT r4 0xFFFFFFFFFFFFFFFF 164 | #_ REGISTER_OUT r5 1*/ 165 | 166 | 167 | // 0x0000000100000000 168 | BUILD->CreateStore(i64Const(0x8000000000000000), func->getRegister("RR", 4)); 169 | //unit_li(func, gen, { 4, 0, (uint32_t)-1, }); 170 | unit_li(func, gen, { 5, 0, (uint32_t) - 1,}); 171 | unit_divdu(func, gen, { 3, 4, 5, }); 172 | 173 | unit_bclr(func, gen, {}); 174 | 175 | 176 | // 177 | // DUMP 178 | // 179 | printf("----IR DUMP----\n\n\n"); 180 | gen->writeIRtoFile(); 181 | } 182 | 183 | 184 | inline uint32_t recursiveNopCheck(uint32_t address) 185 | { 186 | const char* name = g_irGen->instrsList.at(address).opcName.c_str(); 187 | if (strcmp(name, "nop") == 0) 188 | { 189 | recursiveNopCheck(address + 4); 190 | } 191 | else 192 | { 193 | return address; 194 | } 195 | } 196 | 197 | void patchImportsFunctions() 198 | { 199 | for (Import* import : loadedXex->m_imports) 200 | { 201 | if(import->type == FUNCTION) 202 | { 203 | IRFunc* func = g_irGen->getCreateFuncInMap(import->funcImportAddr); 204 | func->end_address = func->start_address + 16; 205 | llvm::FunctionType* importType = llvm::FunctionType::get(g_irGen->m_builder->getVoidTy(), { g_irGen->XenonStateType->getPointerTo(), g_irGen->m_builder->getInt32Ty() }, false); 206 | llvm::Function* importFunc = llvm::Function::Create(importType, llvm::Function::ExternalLinkage,import->name.c_str(),g_irGen->m_module); 207 | func->m_irFunc = importFunc; 208 | func->emission_done = true; 209 | } 210 | } 211 | } 212 | 213 | 214 | 215 | bool pass_Flow() 216 | { 217 | bool ret = true; 218 | 219 | if (isUnitTesting) 220 | { 221 | return true; 222 | } 223 | patchImportsFunctions(); 224 | flow_pData(); // search pData 225 | 226 | for (size_t i = 0; i < loadedXex->GetNumSections(); i++) 227 | { 228 | const Section* section = loadedXex->GetSection(i); 229 | 230 | if (!section->CanExecute()) 231 | { 232 | continue; 233 | } 234 | printf("\nFlow for section %s\n\n", section->GetName().c_str()); 235 | // compute code range 236 | const auto baseAddress = loadedXex->GetBaseAddress(); 237 | const auto sectionBaseAddress = baseAddress + section->GetVirtualOffset(); 238 | auto endAddress = baseAddress + section->GetVirtualOffset() + section->GetVirtualSize(); 239 | auto address = sectionBaseAddress; 240 | 241 | // create the function for the first function 242 | 243 | IRFunc* first = g_irGen->getCreateFuncInMap(sectionBaseAddress); 244 | IRFunc* prevFunc = nullptr; 245 | IRFunc* currentFunc = first; 246 | 247 | 248 | // 249 | // Passes 250 | // 251 | 252 | flow_promoteSaveRest(address, endAddress); 253 | 254 | // prologue 255 | printf("-- prologue search --\n"); 256 | flow_blJumps(address, endAddress); 257 | flow_mfsprProl(address, endAddress); 258 | flow_promoteTailProl(address, endAddress); 259 | flow_stackInitProl(address, endAddress); 260 | flow_dataSecAdr(address, endAddress); 261 | // this break stuff :/ 262 | //flow_aftBclrProl(address, endAddress); // this as last resort, if called before could break everything 263 | 264 | // epilogue 265 | printf("\n-- epilogue search --\n"); 266 | flow_mtsprEpil(address, endAddress); 267 | flow_bclrAndTailEpil(address, endAddress); 268 | 269 | printf("\n-- prologue/epilogue second pass --\n"); 270 | //flow_undiscovered(address, endAddress); 271 | flow_fixIfAddresses(address, endAddress); 272 | flow_demoteInBounds(address, endAddress); 273 | flow_jumpTables(address, endAddress); 274 | flow_detectIncomplete(address, endAddress); 275 | } 276 | 277 | return ret; 278 | } 279 | 280 | 281 | bool pass_Decode() 282 | { 283 | 284 | bool ret = true; 285 | 286 | // Open the output file if printFile is true 287 | std::ofstream outFile; 288 | if (printFile) { 289 | outFile.open("instructions_output.txt"); 290 | if (!outFile.is_open()) { 291 | printf("Failed to open the file for writing instructions.\n"); 292 | ret = false; 293 | return ret; 294 | } 295 | } 296 | 297 | for (size_t i = 0; i < loadedXex->GetNumSections(); i++) 298 | { 299 | const Section* section = loadedXex->GetSection(i); 300 | 301 | if (!section->CanExecute()) 302 | { 303 | continue; 304 | } 305 | printf("Decoding Instructions for section %s\n", section->GetName().c_str()); 306 | // compute code range 307 | const auto baseAddress = loadedXex->GetBaseAddress(); 308 | const auto sectionBaseAddress = baseAddress + section->GetVirtualOffset(); 309 | auto endAddress = baseAddress + section->GetVirtualOffset() + section->GetVirtualSize(); 310 | auto address = sectionBaseAddress; 311 | 312 | InstructionDecoder decoder(section); 313 | if (doOverride) endAddress = overAddr; 314 | while (address < endAddress) 315 | { 316 | Instruction instruction; 317 | const auto instructionSize = decoder.GetInstructionAt(address, instruction); 318 | if (instructionSize == 0) 319 | { 320 | printf("Failed to decode instruction at %08X\n", address); 321 | ret = false; 322 | break; 323 | } 324 | 325 | // add instruction to map 326 | g_irGen->instrsList.try_emplace(address, instruction); 327 | 328 | if (printINST) { 329 | // print raw PPC decoded instruction + operands 330 | std::ostringstream oss; 331 | oss << std::hex << std::uppercase << std::setfill('0'); 332 | oss << std::setw(8) << address << ": " << instruction.opcName; 333 | 334 | for (size_t i = 0; i < instruction.ops.size(); ++i) { 335 | oss << " " << std::setw(2) << static_cast(instruction.ops.at(i)); 336 | } 337 | 338 | std::string output = oss.str(); 339 | if (printFile) { 340 | // Write output to file if printFile is true 341 | outFile << output << std::endl; 342 | } 343 | else { 344 | // Print output to the console 345 | printf("%s\n", output.c_str()); 346 | } 347 | } 348 | 349 | address += 4; // always 4 350 | instCount++; // instruction count 351 | } 352 | } 353 | 354 | // Close the output file if it was opened 355 | if (printFile) { 356 | outFile.close(); 357 | } 358 | 359 | return ret; 360 | } 361 | 362 | bool pass_Emit() 363 | { 364 | 365 | if (isUnitTesting) 366 | { 367 | unitTest(g_irGen); 368 | return true; 369 | } 370 | 371 | bool ret = true; 372 | 373 | for (size_t i = 0; i < loadedXex->GetNumSections(); i++) 374 | { 375 | const Section* section = loadedXex->GetSection(i); 376 | 377 | if (!section->CanExecute()) 378 | { 379 | continue; 380 | } 381 | printf("Emitting IR for section %s\n", section->GetName().c_str()); 382 | // compute code range 383 | const auto baseAddress = loadedXex->GetBaseAddress(); 384 | const auto sectionBaseAddress = baseAddress + section->GetVirtualOffset(); 385 | auto endAddress = baseAddress + section->GetVirtualOffset() + section->GetVirtualSize(); 386 | auto address = sectionBaseAddress; 387 | 388 | 389 | for (const auto& pair : g_irGen->m_function_map) 390 | { 391 | IRFunc* func = pair.second; 392 | if (genLLVMIR && !func->emission_done) 393 | { 394 | g_irGen->initFuncBody(func); 395 | ret = func->EmitFunction(); 396 | func->emission_done = true; 397 | } 398 | } 399 | } 400 | 401 | g_irGen->writeIRtoFile(); 402 | 403 | return ret; 404 | } 405 | 406 | 407 | 408 | int main() 409 | { 410 | loadedXex = new XexImage(L"LLVMTest1.xex"); 411 | loadedXex->LoadXex(); 412 | g_irGen = new IRGenerator(loadedXex, mod, &builder); 413 | g_irGen->Initialize(); 414 | g_irGen->m_dbCallBack = dbCallBack; 415 | g_irGen->m_dumpIRConsole = dumpIRConsole; 416 | 417 | printf("\n\n\n"); 418 | auto start = std::chrono::high_resolution_clock::now(); 419 | 420 | 421 | // 422 | // --- Passes --- 423 | // 424 | // Passes are *Not* optimization to speed up recompilation but rather to have a more 425 | // managable enviroment to scale up and keep each phase of the recompilation well 426 | // organized. they actually slow down a bit (literally seconds or tenths of a second) 427 | // recompilation compared to the more naive approach from before e.g just feeding the 428 | // decoded instruction to the emitter and not store all instrs in a map and Then emit them 429 | // so it will slow down but it keeps emission phase good and easier to work with :} 430 | // 431 | // Decode: decode ppc instructions and convert them into a Emitter friendly 432 | // format and add them into an unordered map, the map slow down a bit from 433 | // 0.3 seconds to 0.9 seconds but it's useful for later, before i was just 434 | // feeding instruction per instruction to the emitter. 435 | // 436 | // ContrFlow: TODO, this is a control flow pass that detects part of the visible branching 437 | // before emitting and the general skeleton of the executable, This can help with 438 | // Emission phase that could miss some branch labels etc, like it will help detect 439 | // the code block of a VTable function (if this pass find it). 440 | // 441 | // Emit: this is the big and complex one, it take every instructions and emit equivalent IR Code 442 | // compatible with the CPU Context, this will also resolve and patch all memory related operations 443 | // e.g Load / Store in .rdata or .data section and more stuff. 444 | // 445 | 446 | // first recomp pass: Decode xex instructions 447 | 448 | 449 | if (!pass_Decode()) 450 | { 451 | printf("something went wrong - Pass: DECODE\n"); 452 | return -1; 453 | } 454 | 455 | if (!pass_Flow()) 456 | { 457 | printf("something went wrong - Pass: FLOW\n"); 458 | return -1; 459 | } 460 | 461 | // third recomp pass: Emit IR code 462 | if (!pass_Emit()) 463 | { 464 | printf("something went wrong - Pass: EMIT\n"); 465 | return -1; 466 | } 467 | 468 | // sections 469 | saveSection("rdata.bin", 0); 470 | //saveSection("../bin/Debug/data.bin", 3); 471 | exportMetadata("MD.tss"); 472 | if(!isUnitTesting) 473 | g_irGen->exportFunctionArray(); 474 | 475 | // Stop the timer 476 | auto end = std::chrono::high_resolution_clock::now(); 477 | 478 | 479 | g_irGen->writeIRtoFile(); 480 | if(dbCallBack) 481 | serializeDBMapData(g_irGen->instrsList, "../../bin/Debug/dbMapData.bin"); 482 | // Calculate the duration 483 | auto duration = std::chrono::duration_cast(end - start); 484 | printf("\n\n\nDecoding process took: %f seconds\n", duration.count() / 1000000.0); 485 | printf("Decoded %i PPC Instructions\n", instCount); 486 | 487 | 488 | 489 | // Splash texts 490 | printf("Hello, World!\n"); 491 | printf("Say hi to the new galaxy note\n"); 492 | 493 | // 19/02/2025 494 | printf("Trans rights!!! @permdog99\n"); 495 | printf("Live and learn @ashrindy\n"); 496 | printf("On dog @.nover.\n"); 497 | printf("Gotta Go Fast @neoslyde\n"); 498 | } 499 | 500 | 501 | -------------------------------------------------------------------------------- /llvm360/LLVMApp/src/Util.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "misc/Utils.h" 8 | #include "Decoder/Instruction.h" 9 | #include "Decoder/InstructionDecoder.h" 10 | #include 11 | #include "IR/IRGenerator.h" 12 | #include 13 | #include // for _kbhit 14 | #include 15 | #include 16 | 17 | // Debug 18 | bool printINST = false; 19 | bool printFile = false; 20 | bool genLLVMIR = true; 21 | bool isUnitTesting = false; 22 | bool doOverride = false; // if it should override the endAddress to debug 23 | bool dbCallBack = true; // enables debug callbacks, break points etc 24 | bool dumpIRConsole = false; 25 | uint32_t overAddr = 0x82060150; 26 | 27 | // Benchmark / static analysis 28 | uint32_t instCount = 0; 29 | 30 | // Naive+ stuff 31 | XexImage* loadedXex; 32 | IRGenerator* g_irGen; 33 | llvm::LLVMContext cxt; 34 | llvm::Module* mod = new llvm::Module("Xenon", cxt); 35 | llvm::IRBuilder builder(cxt); 36 | 37 | Section* findSection(std::string name); 38 | 39 | struct EXPMD_IMPVar 40 | { 41 | std::string name; 42 | uint32_t addr; 43 | }; 44 | 45 | struct EXPMD_Section 46 | { 47 | uint32_t dat_offset; 48 | uint32_t size; 49 | uint32_t flags; 50 | uint32_t nameLength; 51 | std::string sec_name; 52 | uint8_t* data; 53 | }; 54 | 55 | struct EXPMD_Header 56 | { 57 | uint32_t magic; 58 | uint32_t version; 59 | uint32_t flags; 60 | uint32_t baseAddress; 61 | uint32_t num_impVars; 62 | EXPMD_IMPVar** imp_Vars; 63 | uint32_t numSections; 64 | EXPMD_Section** sections; 65 | }; 66 | 67 | struct pDataInfo 68 | { 69 | uint32_t funcAddr; 70 | union 71 | { 72 | uint32_t info; 73 | struct 74 | { 75 | uint32_t length : 8; 76 | uint32_t funcLength : 22; 77 | uint32_t flag1 : 1; 78 | uint32_t flag2 : 1; 79 | }; 80 | }; 81 | }; 82 | 83 | IRFunc* isInFuncBound(uint32_t addr) 84 | { 85 | for (const auto& pair : g_irGen->m_function_map) 86 | { 87 | IRFunc* func = pair.second; 88 | if (addr > func->start_address && addr < func->end_address) 89 | { 90 | return func; 91 | } 92 | } 93 | return nullptr; 94 | } 95 | 96 | 97 | void flow_pData() 98 | { 99 | Section* pData = findSection(".pdata"); 100 | 101 | if (pData) 102 | { 103 | const auto baseAddress = loadedXex->GetBaseAddress(); 104 | const auto sectionBaseAddress = baseAddress + pData->GetVirtualOffset(); 105 | const auto endAddress = sectionBaseAddress + pData->GetVirtualSize(); 106 | const auto address = sectionBaseAddress; 107 | const uint8_t* m_imageDataPtr = pData->GetImage()->GetMemory() + 108 | (pData->GetVirtualOffset() - pData->GetImage()->GetBaseAddress()); 109 | const uint64_t offset = address - pData->GetVirtualOffset(); 110 | const uint8_t* stride = m_imageDataPtr + offset; 111 | 112 | const uint32_t size = pData->GetVirtualSize() / 8; 113 | std::vector infoList; 114 | 115 | for (uint32_t i = 0; i < size; i++) 116 | { 117 | pDataInfo info; 118 | info.funcAddr = SwapInstrBytes(*(uint32_t*)(stride + (i * 8))); 119 | info.info = SwapInstrBytes(*(uint32_t*)(stride + (i * 8) + 4)); 120 | 121 | IRFunc* func = g_irGen->getCreateFuncInMap(info.funcAddr); 122 | func->end_address = (info.funcAddr + (info.funcLength * 4) - 4); 123 | infoList.push_back(info); 124 | } 125 | 126 | 127 | printf("%u Function bounds found in .pData\n", size); 128 | 129 | } 130 | } 131 | 132 | 133 | // 134 | // find and promote save/rest to functions 135 | // 136 | void flow_promoteSaveRest(uint32_t start, uint32_t end) 137 | { 138 | while (start < end) 139 | { 140 | if (start == end - 4) break; 141 | Instruction instr = g_irGen->instrsList.at(start); 142 | Instruction instrAfter = g_irGen->instrsList.at(start + 4); 143 | 144 | // 145 | // savegprlr_14 146 | // 147 | if (instr.instrWord == 0xf9c1ff68) 148 | { 149 | printf("savegprlr_14 Found at: %08X\n", instr.address); 150 | for (size_t i = 14; i < 32; i++) 151 | { 152 | IRFunc* func = g_irGen->getCreateFuncInMap(instr.address + (i - 14) * 4); 153 | func->end_address = func->start_address + ((32 - i) * 4) + 4; 154 | } 155 | } 156 | 157 | // 158 | // restgprlr_14 159 | // 160 | if (instr.instrWord == 0xe9c1ff68) 161 | { 162 | printf("restgprlr_14 Found at: %08X\n", instr.address); 163 | for (size_t i = 14; i < 32; i++) 164 | { 165 | IRFunc* func = g_irGen->getCreateFuncInMap(instr.address + (i - 14) * 4); 166 | func->end_address = func->start_address + ((32 - i) * 4) + 8; 167 | } 168 | } 169 | 170 | // 171 | // savefpr_14 172 | // 173 | if (instr.instrWord == 0xd9ccff70) 174 | { 175 | printf("savefpr_14 Found at: %08X\n", instr.address); 176 | DebugBreak(); 177 | } 178 | // 179 | // restfpr_14 180 | // 181 | if (instr.instrWord == 0xc9ccff70) 182 | { 183 | printf("restfpr_14 Found at: %08X\n", instr.address); 184 | DebugBreak(); 185 | } 186 | 187 | // 188 | // savevmx_14 189 | // 190 | if (instr.instrWord == 0x3960fee0) 191 | { 192 | if (instrAfter.instrWord == 0x7dcb61ce) 193 | { 194 | printf("savevmx_14 Found at: %08X\n", instr.address); 195 | DebugBreak(); 196 | } 197 | } 198 | // 199 | // restvmx_14 200 | // 201 | if (instr.instrWord == 0x3960fee0) 202 | { 203 | if (instrAfter.instrWord == 0x7dcb60ce) 204 | { 205 | printf("restvmx_14 Found at: %08X\n", instr.address); 206 | DebugBreak(); 207 | } 208 | } 209 | 210 | // 211 | // savevmx_64 212 | // 213 | if (instr.instrWord == 0x3960fc00) 214 | { 215 | if (instrAfter.instrWord == 0x100b61cb) 216 | { 217 | printf("savevmx_64 Found at: %08X\n", instr.address); 218 | DebugBreak(); 219 | } 220 | } 221 | // 222 | // restvmx_64 223 | // 224 | if (instr.instrWord == 0x3960fc00) 225 | { 226 | if (instrAfter.instrWord == 0x100b60cb) 227 | { 228 | printf("restvmx_64 Found at: %08X\n", instr.address); 229 | DebugBreak(); 230 | } 231 | } 232 | 233 | 234 | start += 4; 235 | } 236 | } 237 | 238 | // 239 | // this flow pass find every function prologue that are jumped from BL instructions 240 | // 241 | void flow_blJumps(uint32_t start, uint32_t end) 242 | { 243 | while (start < end) 244 | { 245 | Instruction instr = g_irGen->instrsList.at(start); 246 | if (strcmp(instr.opcName.c_str(), "bl") == 0) 247 | { 248 | uint32_t target = instr.address + signExtend(instr.ops[0], 24); 249 | if (!g_irGen->isIRFuncinMap(target)) 250 | { 251 | printf("{flow_blJumps} Found new start of function bounds at: %08X\n", target); 252 | g_irGen->getCreateFuncInMap(target); 253 | } 254 | } 255 | 256 | start += 4; 257 | } 258 | } 259 | 260 | // 261 | // this flow pass search every prolouge with mfspr R12 LR 262 | // and since i know that if it save the LR the epilogue will restore it with 263 | // mtspr (check epilogue passes) so i set a metadata flag 264 | // 265 | void flow_mfsprProl(uint32_t start, uint32_t end) 266 | { 267 | while (start < end) 268 | { 269 | Instruction instr = g_irGen->instrsList.at(start); 270 | if (instr.instrWord == 0x7d8802a6) // mfspr r12, LR 271 | { 272 | if (!g_irGen->isIRFuncinMap(start)) 273 | printf("{flow_mfsprProl} Found new start of function bounds at: %08X\n", start); 274 | IRFunc* func = g_irGen->getCreateFuncInMap(start); 275 | func->startW_MFSPR_LR = true; 276 | } 277 | 278 | start += 4; 279 | } 280 | } 281 | 282 | void flow_stackInitProl(uint32_t start, uint32_t end) 283 | { 284 | bool first = true; 285 | while (start < end) 286 | { 287 | if (start == end - 4) break; 288 | Instruction instr = g_irGen->instrsList.at(start); 289 | Instruction nextInstr = g_irGen->instrsList.at(start + 4);; 290 | Instruction prevInstr; 291 | if(first) 292 | { 293 | prevInstr = Instruction{ start, 0x0, std::string{"nop"}, std::vector{0, 0, 0} }; 294 | first = false; 295 | } 296 | else 297 | { 298 | prevInstr = g_irGen->instrsList.at(start - 4); 299 | } 300 | if (strcmp(instr.opcName.c_str(), "stw") == 0 && instr.ops[2] == 1) 301 | { 302 | if((strcmp(prevInstr.opcName.c_str(), "bclr") == 0 && instr.ops[2] == 1) || 303 | (strcmp(prevInstr.opcName.c_str(), "nop") == 0)) 304 | { 305 | if (!g_irGen->isIRFuncinMap(start)) 306 | { 307 | printf("{flow_stackInitProl} Found new start of function bounds at: %08X\n", start); 308 | g_irGen->getCreateFuncInMap(start); 309 | } 310 | 311 | if ((strcmp(nextInstr.opcName.c_str(), "stw") == 0 && instr.ops[2] == 1)) 312 | { 313 | start += 8; 314 | continue; 315 | } 316 | } 317 | start += 4; 318 | continue; 319 | } 320 | 321 | start += 4; 322 | } 323 | } 324 | 325 | void flow_aftBclrProl(uint32_t start, uint32_t end) 326 | { 327 | while (start < end) 328 | { 329 | if (start == end - 4) break; 330 | Instruction instr = g_irGen->instrsList.at(start); 331 | Instruction instrAfter; 332 | if (strcmp(instr.opcName.c_str(), "bclr") == 0) 333 | { 334 | instrAfter = g_irGen->instrsList.at(start + 4); 335 | if(strcmp(instrAfter.opcName.c_str(), "stw") == 0 && instrAfter.ops[2] == 1) 336 | { 337 | if (g_irGen->isIRFuncinMap(instrAfter.address)) 338 | { 339 | start += 4; 340 | continue; 341 | } 342 | 343 | printf("{flow_aftBclrProl} Found new start of function bounds at: %08X\n", instrAfter.address); 344 | g_irGen->getCreateFuncInMap(instrAfter.address); 345 | } 346 | 347 | 348 | uint32_t off = start + 4; 349 | do 350 | { 351 | instrAfter = g_irGen->instrsList.at(off); 352 | off += 4; 353 | } while (strcmp(instrAfter.opcName.c_str(), "nop") == 0); 354 | 355 | if (g_irGen->isIRFuncinMap(instrAfter.address)) 356 | { 357 | start += 4; 358 | continue; 359 | } 360 | 361 | printf("{flow_aftBclrProl} Found new start of function bounds at: %08X\n", instrAfter.address); 362 | g_irGen->getCreateFuncInMap(instrAfter.address); 363 | } 364 | 365 | start += 4; 366 | } 367 | } 368 | 369 | void flow_promoteTailProl(uint32_t start, uint32_t end) 370 | { 371 | while (start < end) 372 | { 373 | if (start == end - 4) break; 374 | Instruction instr = g_irGen->instrsList.at(start); 375 | Instruction instrAfter = g_irGen->instrsList.at(start + 4); 376 | if (strcmp(instr.opcName.c_str(), "b") == 0) 377 | { 378 | uint32_t target = instr.address + signExtend(instr.ops[0], 24); 379 | if (strcmp(instrAfter.opcName.c_str(), "nop") == 0 && instr.ops[0] > 0x40) // treshold of distance to be considered a tail call 380 | { 381 | // promote branched address to function if not in map 382 | if (!g_irGen->isIRFuncinMap(target)) 383 | { 384 | printf("{flow_bclrAndTailEpil} Promoted new function at: %08X\n", target); 385 | IRFunc* func = g_irGen->getCreateFuncInMap(target); 386 | func->is_promotion = true; 387 | } 388 | start += 4; 389 | continue; 390 | } 391 | 392 | // it's a tail call 100% 393 | if (g_irGen->isIRFuncinMap(start + 4)) 394 | { 395 | // promote branched address to function if not in map 396 | if (!g_irGen->isIRFuncinMap(target)) // probably the actual end 397 | { 398 | printf("{flow_bclrAndTailEpil} Promoted new function at: %08X\n", target); 399 | g_irGen->getCreateFuncInMap(target); 400 | IRFunc* func = g_irGen->getCreateFuncInMap(target); 401 | func->is_promotion = true; 402 | } 403 | start += 4; 404 | continue; 405 | } 406 | } 407 | 408 | /* 409 | bge LAB_82013ab0 410 | b FUN_820150d0 // Tail call 411 | LAB_82013ab0 412 | addi ...*/ 413 | if (strcmp(instr.opcName.c_str(), "bc") == 0 && 414 | strcmp(instrAfter.opcName.c_str(), "b") == 0) 415 | { 416 | if (instr.address + (int16_t)(instr.ops[2] << 2) == instrAfter.address + 4) 417 | { 418 | uint32_t targetAft = instrAfter.address + signExtend(instrAfter.ops[0], 24); 419 | if (!g_irGen->isIRFuncinMap(targetAft)) 420 | { 421 | printf("{flow_bclrAndTailEpil} Promoted new function at: %08X\n", targetAft); 422 | g_irGen->getCreateFuncInMap(targetAft); 423 | IRFunc* func = g_irGen->getCreateFuncInMap(targetAft); 424 | func->is_promotion = true; 425 | } 426 | start += 4; 427 | continue; 428 | } 429 | } 430 | 431 | 432 | start += 4; 433 | } 434 | } 435 | 436 | void flow_mtsprEpil(uint32_t start, uint32_t end) 437 | { 438 | for (const auto& pair : g_irGen->m_function_map) 439 | { 440 | IRFunc* func = pair.second; 441 | if (func->startW_MFSPR_LR && func->end_address == 0) 442 | { 443 | start = func->start_address; 444 | while (start < end) 445 | { 446 | Instruction instr = g_irGen->instrsList.at(start); 447 | if (instr.instrWord == 0x7d8803a6) // mtspr LR, r12 448 | { 449 | 450 | // this account for cases where there's some LD instructions 451 | uint32_t off = start + 4; 452 | do 453 | { 454 | instr = g_irGen->instrsList.at(off); 455 | off += 4; 456 | } while (strcmp(instr.opcName.c_str(), "bclr") != 0); 457 | 458 | func->end_address = off - 4; 459 | printf("{flow_mtsprEpil} Found new end of function bounds at: %08X\n", func->end_address); 460 | break; 461 | } 462 | 463 | start += 4; 464 | } 465 | } 466 | } 467 | } 468 | 469 | void flow_undiscovered(uint32_t start, uint32_t end) 470 | { 471 | for (const auto& pair : g_irGen->m_function_map) 472 | { 473 | 474 | IRFunc* func = pair.second; 475 | if(func->end_address != 0) 476 | { 477 | uint32_t addr = func->end_address + 4; 478 | if (g_irGen->instrsList.find(addr) == g_irGen->instrsList.end()) break; 479 | while (strcmp(g_irGen->instrsList.at(addr).opcName.c_str(), "nop") == 0) 480 | { 481 | addr += 4; 482 | } 483 | 484 | if (!g_irGen->isIRFuncinMap(addr) && isInFuncBound(addr) == nullptr) 485 | { 486 | printf("{flow_undiscovered} Found new function at: %08X\n", addr); 487 | g_irGen->getCreateFuncInMap(addr); 488 | } 489 | } 490 | } 491 | for (const auto& pair : g_irGen->m_function_map) 492 | { 493 | 494 | IRFunc* func = pair.second; 495 | if (func->end_address == 0) 496 | { 497 | uint32_t addr = func->start_address + 4; 498 | while (!g_irGen->isIRFuncinMap(addr)) 499 | { 500 | if (addr == end) 501 | { 502 | func->end_address = addr; 503 | return; 504 | } 505 | addr += 4; 506 | } 507 | func->end_address = addr - 4; 508 | } 509 | } 510 | } 511 | 512 | void flow_fixIfAddresses(uint32_t start, uint32_t end) 513 | { 514 | for (const auto& pair : g_irGen->m_function_map) 515 | { 516 | 517 | IRFunc* func = pair.second; 518 | if (func->end_address != 0) 519 | { 520 | 521 | 522 | if (func->end_address == end) continue; 523 | Instruction instr = g_irGen->instrsList.at(func->end_address); 524 | if (strcmp(instr.opcName.c_str(), "lwz") == 0 && g_irGen->m_xexImage->getSectionByAddressBounds(instr.instrWord) != nullptr 525 | && (((instr.instrWord & 0x82000000) >> 24) & 0x82) == 0x82) 526 | { 527 | Instruction instrBef; 528 | uint32_t off = func->end_address; 529 | do 530 | { 531 | off -= 4; 532 | instrBef = g_irGen->instrsList.at(off); 533 | } while (strcmp(instrBef.opcName.c_str(), "b") != 0 && 534 | strcmp(instrBef.opcName.c_str(), "bclr") != 0 && 535 | strcmp(instrBef.opcName.c_str(), "bc") != 0); 536 | printf("{flow_fixIfAddresses} Fixed func end at: %08X\n", instrBef.address); 537 | func->end_address = instrBef.address; 538 | } 539 | } 540 | } 541 | } 542 | 543 | void flow_demoteInBounds(uint32_t start, uint32_t end) 544 | { 545 | for (const auto& pair : g_irGen->m_function_map) 546 | { 547 | IRFunc* func = pair.second; 548 | if(func->is_promotion) 549 | { 550 | IRFunc* out = isInFuncBound(func->start_address); 551 | if(out != nullptr) 552 | { 553 | printf("{flow_demoteInBounds} Func demoted at: %08X\n", func->start_address); 554 | g_irGen->m_function_map.erase(func->start_address); 555 | } 556 | } 557 | } 558 | } 559 | 560 | void flow_dataSecAdr(uint32_t start, uint32_t end) 561 | { 562 | Section* pData = findSection(".data"); 563 | 564 | if (pData) 565 | { 566 | const auto baseAddress = loadedXex->GetBaseAddress(); 567 | const auto sectionBaseAddress = baseAddress + pData->GetVirtualOffset(); 568 | const auto endAddress = sectionBaseAddress + pData->GetVirtualSize(); 569 | const auto address = sectionBaseAddress; 570 | const uint8_t* m_imageDataPtr = pData->GetImage()->GetMemory() + 571 | (pData->GetVirtualOffset() - pData->GetImage()->GetBaseAddress()); 572 | const uint64_t offset = address - pData->GetVirtualOffset(); 573 | const uint8_t* stride = m_imageDataPtr + offset; 574 | 575 | const uint32_t size = pData->GetVirtualSize() / 4; 576 | 577 | for (uint32_t i = 0; i < size; i++) 578 | { 579 | uint32_t val = SwapInstrBytes(*(uint32_t*)(stride + (i * 4))); 580 | if (val >= start && val <= end) 581 | { 582 | IRFunc* func = g_irGen->getCreateFuncInMap(val); 583 | printf("Function address found in .Data\n"); 584 | } 585 | 586 | } 587 | } 588 | } 589 | 590 | void flow_jumpTables(uint32_t start, uint32_t end) 591 | { 592 | for (const auto& pair : g_irGen->m_function_map) 593 | { 594 | IRFunc* func = pair.second; 595 | if (func->emission_done) continue; 596 | for (JTVariant variant : jtVariantTypes) 597 | { 598 | uint32_t addr = func->start_address; 599 | while (addr <= func->end_address) 600 | { 601 | for (size_t i = 0; i < variant.pattern.size(); i++) 602 | { 603 | uint32_t off = addr + (i * 4); 604 | Instruction instr = g_irGen->instrsList.at(off); 605 | if(!(strcmp(instr.opcName.c_str(), variant.pattern[i]) == 0)) 606 | { 607 | break; 608 | } 609 | if (i == variant.pattern.size() - 1) 610 | { 611 | JumpTable* jt = new JumpTable(); 612 | jt->start_Address = addr; 613 | jt->end_Address = addr + (variant.pattern.size() * 4); 614 | jt->variant = variant; 615 | jt->ComputeTargets(func->m_irGen); 616 | func->jumpTables.push_back(jt); 617 | printf("{flow_jumpTables} Found new jump table at: %08X\n", addr); 618 | func->has_jumpTable = true; 619 | } 620 | } 621 | 622 | addr += 4; 623 | } 624 | } 625 | 626 | 627 | } 628 | } 629 | 630 | void flow_detectIncomplete(uint32_t start, uint32_t end) 631 | { 632 | for (const auto& pair : g_irGen->m_function_map) 633 | { 634 | IRFunc* func = pair.second; 635 | if (func->end_address == 0) 636 | { 637 | DebugBreak(); 638 | } 639 | } 640 | } 641 | 642 | void flow_bclrAndTailEpil(uint32_t start, uint32_t end) 643 | { 644 | for (const auto& pair : g_irGen->m_function_map) 645 | { 646 | IRFunc* func = pair.second; 647 | if (func->end_address == 0) 648 | { 649 | start = func->start_address; 650 | while (start < end) 651 | { 652 | if (start == end - 4) 653 | { 654 | func->end_address = start; 655 | printf("{flow_bclrAndTailEpil} Found new end of function bounds at: %08X\n", func->end_address); 656 | break; 657 | } 658 | 659 | Instruction instr = g_irGen->instrsList.at(start); 660 | Instruction instrAfter = g_irGen->instrsList.at(start + 4); 661 | if (strcmp(instr.opcName.c_str(), "b") == 0) 662 | { 663 | 664 | uint32_t target = instr.address + signExtend(instr.ops[0], 24); 665 | 666 | // check if "instruction" is addr, and fix the end 667 | if (strcmp(instrAfter.opcName.c_str(), "lwz") == 0 && g_irGen->m_xexImage->getSectionByAddressBounds(instrAfter.instrWord) != nullptr 668 | && (((instrAfter.instrWord & 0x82000000) >> 24) & 0x82) == 0x82) 669 | { 670 | func->end_address = instr.address; 671 | printf("{flow_bclrAndTailEpil} Fixed bound becasue of Addr: %08X\n", func->end_address); 672 | break; 673 | } 674 | 675 | 676 | if (strcmp(instrAfter.opcName.c_str(), "nop") == 0) 677 | { 678 | uint32_t offf = start + 4; 679 | while (!g_irGen->isIRFuncinMap(offf)) 680 | { 681 | offf += 4; 682 | } 683 | func->end_address = offf - 4; 684 | printf("{flow_bclrAndTailEpil} Found new end of function bounds at: %08X\n", func->end_address); 685 | break; 686 | } 687 | 688 | if (g_irGen->isIRFuncinMap(target)) 689 | { 690 | func->end_address = start; 691 | if (g_irGen->isIRFuncinMap(start + 4)) // probably the actual end 692 | { 693 | printf("{flow_bclrAndTailEpil} Found new end of function bounds at: %08X\n", func->end_address); 694 | break; 695 | } 696 | } 697 | 698 | // if it detects no function in map, it checks if the next address is a function, if it is 699 | // then it's the epilogue of the current one, and is indeed a tail call 700 | if (g_irGen->isIRFuncinMap(start + 4)) 701 | { 702 | func->end_address = start; 703 | printf("{flow_bclrAndTailEpil} Found new end of function bounds at: %08X\n", func->end_address); 704 | break; 705 | } 706 | } 707 | 708 | if (strcmp(instr.opcName.c_str(), "bclr") == 0) 709 | { 710 | // check if "instruction" is addr, and fix the end 711 | if (strcmp(instrAfter.opcName.c_str(), "lwz") == 0 && g_irGen->m_xexImage->getSectionByAddressBounds(instrAfter.instrWord) != nullptr 712 | && (((instrAfter.instrWord & 0x82000000) >> 24) & 0x82) == 0x82) 713 | { 714 | func->end_address = instr.address; 715 | printf("{flow_bclrAndTailEpil} Fixed bound becasue of Addr: %08X\n", func->end_address); 716 | break; 717 | } 718 | 719 | func->end_address = start; 720 | if (strcmp(instrAfter.opcName.c_str(), "nop") == 0) 721 | { 722 | func->end_address = start; 723 | printf("{flow_bclrAndTailEpil} Found new end of function bounds at: %08X\n", func->end_address); 724 | break; 725 | } 726 | 727 | if (g_irGen->isIRFuncinMap(start + 4)) 728 | { 729 | func->end_address = start; 730 | printf("{flow_bclrAndTailEpil} Found new end of function bounds at: %08X\n", func->end_address); 731 | break; 732 | } 733 | } 734 | 735 | start += 4; 736 | } 737 | } 738 | } 739 | } 740 | 741 | // 742 | // Detect "standart" tail calls, it checks if the function is in the map 743 | // 744 | void flow_stdTailDEpil(uint32_t start, uint32_t end) 745 | { 746 | for (const auto& pair : g_irGen->m_function_map) 747 | { 748 | IRFunc* func = pair.second; 749 | if (func->end_address == 0) 750 | { 751 | start = func->start_address; 752 | while (start < end) 753 | { 754 | Instruction instr = g_irGen->instrsList.at(start); 755 | if (strcmp(instr.opcName.c_str(), "b") == 0) 756 | { 757 | uint32_t target = instr.address + signExtend(instr.ops[0], 24); 758 | if(g_irGen->isIRFuncinMap(target)) 759 | { 760 | func->end_address = start; 761 | if (g_irGen->isIRFuncinMap(start + 4)) // probably the actual end 762 | { 763 | printf("{flow_stdTailDEpil} Found new end of function bounds at: %08X\n", func->end_address); 764 | start += 4; 765 | continue; 766 | } 767 | } 768 | } 769 | 770 | start += 4; 771 | } 772 | } 773 | } 774 | } 775 | 776 | void serializeDBMapData(const std::unordered_map& map, const std::string& filename) 777 | { 778 | std::ofstream ofs(filename, std::ios::binary); 779 | if (!ofs.is_open()) { 780 | printf("Error opening file for writing\n"); 781 | return; 782 | } 783 | 784 | // sort by address 785 | std::vector sorted_instructions; 786 | for (const auto& entry : map) { 787 | sorted_instructions.push_back(entry.second); 788 | } 789 | std::sort(sorted_instructions.begin(), sorted_instructions.end(), 790 | [](const Instruction& a, const Instruction& b) { return a.address < b.address; }); 791 | 792 | // serialize 793 | for (const Instruction& inst : sorted_instructions) { 794 | // address, instrWord 795 | ofs.write(reinterpret_cast(&inst.address), sizeof(inst.address)); 796 | ofs.write(reinterpret_cast(&inst.instrWord), sizeof(inst.instrWord)); 797 | // opcName 798 | uint32_t nameLength = inst.opcName.size(); 799 | ofs.write(reinterpret_cast(&nameLength), sizeof(nameLength)); 800 | ofs.write(inst.opcName.c_str(), nameLength + 1); 801 | // operands 802 | uint32_t opsSize = inst.ops.size(); 803 | ofs.write(reinterpret_cast(&opsSize), sizeof(opsSize)); 804 | if (opsSize > 0) { 805 | ofs.write(reinterpret_cast(inst.ops.data()), opsSize * sizeof(uint32_t)); 806 | } 807 | } 808 | 809 | ofs.close(); 810 | printf("Serialization completed successfully.\n"); 811 | } -------------------------------------------------------------------------------- /llvm360/LLVMApp/src/Xex/AES.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | /** 4 | * rijndael-alg-fst.h 5 | * 6 | * @version 3.0 (December 2000) 7 | * 8 | * Optimised ANSI C code for the Rijndael cipher (now AES) 9 | * 10 | * @author Vincent Rijmen 11 | * @author Antoon Bosselaers 12 | * @author Paulo Barreto 13 | * 14 | * This code is hereby placed in the public domain. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS 17 | * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE 20 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 23 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 24 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 25 | * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 26 | * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 | */ 28 | #ifndef __RIJNDAEL_ALG_FST_H 29 | #define __RIJNDAEL_ALG_FST_H 30 | 31 | #define MAXKC (256 / 32) 32 | #define MAXKB (256 / 8) 33 | #define MAXNR 14 34 | 35 | typedef unsigned char u8; 36 | typedef unsigned short u16; 37 | typedef unsigned int u32; 38 | 39 | #ifdef __cplusplus 40 | extern "C" { 41 | #endif 42 | 43 | int rijndaelKeySetupEnc(u32 rk[/*4*(Nr + 1)*/], const u8 cipherKey[], int keyBits); 44 | int rijndaelKeySetupDec(u32 rk[/*4*(Nr + 1)*/], const u8 cipherKey[], int keyBits); 45 | void rijndaelEncrypt(const u32 rk[/*4*(Nr + 1)*/], int Nr, const u8 pt[16], u8 ct[16]); 46 | void rijndaelDecrypt(const u32 rk[/*4*(Nr + 1)*/], int Nr, const u8 ct[16], u8 pt[16]); 47 | 48 | #ifdef INTERMEDIATE_VALUE_KAT 49 | void rijndaelEncryptRound(const u32 rk[/*4*(Nr + 1)*/], int Nr, u8 block[16], int rounds); 50 | void rijndaelDecryptRound(const u32 rk[/*4*(Nr + 1)*/], int Nr, u8 block[16], int rounds); 51 | #endif /* INTERMEDIATE_VALUE_KAT */ 52 | 53 | #ifdef __cplusplus 54 | } // extern "C" 55 | #endif 56 | 57 | #endif /* __RIJNDAEL_ALG_FST_H */ 58 | -------------------------------------------------------------------------------- /llvm360/LLVMApp/src/Xex/XEXImage.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | //----------------------------------------------------------------------------- 9 | 10 | #pragma pack(push) 11 | #pragma pack(1) 12 | 13 | struct DOSHeader { 14 | char signature[2]; // MZ 15 | short lastsize; 16 | short nblocks; 17 | short nreloc; 18 | short hdrsize; 19 | short minalloc; 20 | short maxalloc; 21 | uint16_t ss; 22 | uint16_t sp; 23 | short checksum; 24 | uint16_t ip; 25 | uint16_t cs; 26 | short relocpos; 27 | short noverlay; 28 | short reserved1[4]; 29 | short oem_id; 30 | short oem_info; 31 | short reserved2[10]; 32 | long e_lfanew; 33 | 34 | inline bool Validate() const { 35 | if (signature[0] != 'M' || signature[1] != 'Z') { 36 | printf("PE: Invalid file signature, should be MZ, found '%c%c'\n", 37 | signature[0] > 32 ? signature[0] : ' ', 38 | signature[1] > 32 ? signature[1] : ' '); 39 | return false; 40 | } 41 | 42 | return true; 43 | } 44 | }; 45 | 46 | #pragma pack(pop) 47 | 48 | struct COFFHeader { 49 | short Machine; 50 | short NumberOfSections; 51 | long TimeDateStamp; 52 | long PointerToSymbolTable; 53 | long NumberOfSymbols; 54 | short SizeOfOptionalHeader; 55 | short Characteristics; 56 | }; 57 | 58 | struct COFFSection { 59 | char Name[8]; 60 | uint32_t VirtualSize; 61 | uint32_t VirtualAddress; 62 | uint32_t SizeOfRawData; 63 | uint32_t PointerToRawData; 64 | uint32_t PointerToRelocations; 65 | uint32_t PointerToLinenumbers; 66 | uint16_t NumberOfRelocations; 67 | uint16_t NumberOfLinenumbers; 68 | uint32_t Flags; 69 | }; 70 | 71 | struct PEDataDirectory { 72 | long VirtualAddress; 73 | long Size; 74 | }; 75 | 76 | struct PEOptHeader { 77 | short signature; // decimal number 267. 78 | char MajorLinkerVersion; 79 | char MinorLinkerVersion; 80 | long SizeOfCode; 81 | long SizeOfInitializedData; 82 | long SizeOfUninitializedData; 83 | long AddressOfEntryPoint; // The RVA of the code entry point 84 | long BaseOfCode; 85 | long BaseOfData; 86 | long ImageBase; 87 | long SectionAlignment; 88 | long FileAlignment; 89 | short MajorOSVersion; 90 | short MinorOSVersion; 91 | short MajorImageVersion; 92 | short MinorImageVersion; 93 | short MajorSubsystemVersion; 94 | short MinorSubsystemVersion; 95 | long Reserved; 96 | long SizeOfImage; 97 | long SizeOfHeaders; 98 | long Checksum; 99 | short Subsystem; 100 | short DLLCharacteristics; 101 | long SizeOfStackReserve; 102 | long SizeOfStackCommit; 103 | long SizeOfHeapReserve; 104 | long SizeOfHeapCommit; 105 | long LoaderFlags; 106 | long NumberOfRvaAndSizes; 107 | PEDataDirectory DataDirectory[16]; // Can have any number of elements, matching the number in 108 | // NumberOfRvaAndSizes. 109 | 110 | bool Validate() const { 111 | if (signature != 267) { 112 | printf("Invalid optional PE signature, should be 267, found %d\n", signature); 113 | return false; 114 | } 115 | 116 | return true; 117 | } 118 | }; 119 | 120 | //----------------------------------------------------------------------------- 121 | 122 | class ImageByteReaderXEX { 123 | private: 124 | const uint8_t *m_data; 125 | uint32_t m_size; 126 | uint32_t m_offset; 127 | 128 | public: 129 | ImageByteReaderXEX(const uint8_t *data, const uint32_t size) 130 | : m_data(data) 131 | , m_size(size) 132 | , m_offset(0) { 133 | } 134 | 135 | inline bool Read(void *dest, uint32_t size) { 136 | if (m_offset + size > m_size) { 137 | printf("IO: Reading outside file size (offset: %d, size:%d, file size: %d)\n", 138 | m_offset, 139 | size, 140 | m_size); 141 | return false; 142 | } 143 | 144 | memcpy(dest, m_data + m_offset, size); 145 | m_offset += size; 146 | return true; 147 | } 148 | 149 | inline bool Seek(const uint32_t offset) { 150 | if (offset >= m_size) { 151 | printf("IO: Seeking to position outside file size (offset: %d, file size: %d)\n", 152 | offset, 153 | m_size); 154 | return false; 155 | } 156 | 157 | m_offset = offset; 158 | return true; 159 | } 160 | 161 | inline const uint8_t *GetData() const { 162 | return m_data; 163 | } 164 | 165 | inline const uint32_t GetSize() const { 166 | return m_size; 167 | } 168 | 169 | inline const uint32_t GetOffset() const { 170 | return m_offset; 171 | } 172 | }; 173 | 174 | //----------------------------------------------------------------------------- 175 | 176 | inline static void Swap64(void *ptr) { 177 | uint8_t *data = (uint8_t *)ptr; 178 | std::swap(data[0], data[7]); 179 | std::swap(data[1], data[6]); 180 | std::swap(data[2], data[5]); 181 | std::swap(data[3], data[4]); 182 | } 183 | 184 | inline static void Swap32(void *ptr) { 185 | uint8_t *data = (uint8_t *)ptr; 186 | std::swap(data[0], data[3]); 187 | std::swap(data[1], data[2]); 188 | } 189 | 190 | inline static void Swap16(void *ptr) { 191 | uint8_t *data = (uint8_t *)ptr; 192 | std::swap(data[0], data[1]); 193 | } 194 | 195 | //----------------------------------------------------------------------------- 196 | 197 | #define XEX2_SECTION_LENGTH 0x00010000 198 | 199 | //----------------------------------------------------------------------------- 200 | 201 | enum XEXHeaderKeys { 202 | XEX_HEADER_RESOURCE_INFO = 0x000002FF, 203 | XEX_HEADER_FILE_FORMAT_INFO = 0x000003FF, 204 | XEX_HEADER_DELTA_PATCH_DESCRIPTOR = 0x000005FF, 205 | XEX_HEADER_BASE_REFERENCE = 0x00000405, 206 | XEX_HEADER_BOUNDING_PATH = 0x000080FF, 207 | XEX_HEADER_DEVICE_ID = 0x00008105, 208 | XEX_HEADER_ORIGINAL_BASE_ADDRESS = 0x00010001, 209 | XEX_HEADER_ENTRY_POINT = 0x00010100, 210 | XEX_HEADER_IMAGE_BASE_ADDRESS = 0x00010201, 211 | XEX_HEADER_IMPORT_LIBRARIES = 0x000103FF, 212 | XEX_HEADER_CHECKSUM_TIMESTAMP = 0x00018002, 213 | XEX_HEADER_ENABLED_FOR_CALLCAP = 0x00018102, 214 | XEX_HEADER_ENABLED_FOR_FASTCAP = 0x00018200, 215 | XEX_HEADER_ORIGINAL_PE_NAME = 0x000183FF, 216 | XEX_HEADER_STATIC_LIBRARIES = 0x000200FF, 217 | XEX_HEADER_TLS_INFO = 0x00020104, 218 | XEX_HEADER_DEFAULT_STACK_SIZE = 0x00020200, 219 | XEX_HEADER_DEFAULT_FILESYSTEM_CACHE_SIZE = 0x00020301, 220 | XEX_HEADER_DEFAULT_HEAP_SIZE = 0x00020401, 221 | XEX_HEADER_PAGE_HEAP_SIZE_AND_FLAGS = 0x00028002, 222 | XEX_HEADER_SYSTEM_FLAGS = 0x00030000, 223 | XEX_HEADER_EXECUTION_INFO = 0x00040006, 224 | XEX_HEADER_TITLE_WORKSPACE_SIZE = 0x00040201, 225 | XEX_HEADER_GAME_RATINGS = 0x00040310, 226 | XEX_HEADER_LAN_KEY = 0x00040404, 227 | XEX_HEADER_XBOX360_LOGO = 0x000405FF, 228 | XEX_HEADER_MULTIDISC_MEDIA_IDS = 0x000406FF, 229 | XEX_HEADER_ALTERNATE_TITLE_IDS = 0x000407FF, 230 | XEX_HEADER_ADDITIONAL_TITLE_MEMORY = 0x00040801, 231 | XEX_HEADER_EXPORTS_BY_NAME = 0x00E10402, 232 | }; 233 | 234 | enum XEXModuleFlags { 235 | XEX_MODULE_TITLE = 0x00000001, 236 | XEX_MODULE_EXPORTS_TO_TITLE = 0x00000002, 237 | XEX_MODULE_SYSTEM_DEBUGGER = 0x00000004, 238 | XEX_MODULE_DLL_MODULE = 0x00000008, 239 | XEX_MODULE_MODULE_PATCH = 0x00000010, 240 | XEX_MODULE_PATCH_FULL = 0x00000020, 241 | XEX_MODULE_PATCH_DELTA = 0x00000040, 242 | XEX_MODULE_USER_MODE = 0x00000080, 243 | }; 244 | 245 | enum XEXSystemFlags { 246 | XEX_SYSTEM_NO_FORCED_REBOOT = 0x00000001, 247 | XEX_SYSTEM_FOREGROUND_TASKS = 0x00000002, 248 | XEX_SYSTEM_NO_ODD_MAPPING = 0x00000004, 249 | XEX_SYSTEM_HANDLE_MCE_INPUT = 0x00000008, 250 | XEX_SYSTEM_RESTRICTED_HUD_FEATURES = 0x00000010, 251 | XEX_SYSTEM_HANDLE_GAMEPAD_DISCONNECT = 0x00000020, 252 | XEX_SYSTEM_INSECURE_SOCKETS = 0x00000040, 253 | XEX_SYSTEM_XBOX1_INTEROPERABILITY = 0x00000080, 254 | XEX_SYSTEM_DASH_CONTEXT = 0x00000100, 255 | XEX_SYSTEM_USES_GAME_VOICE_CHANNEL = 0x00000200, 256 | XEX_SYSTEM_PAL50_INCOMPATIBLE = 0x00000400, 257 | XEX_SYSTEM_INSECURE_UTILITY_DRIVE = 0x00000800, 258 | XEX_SYSTEM_XAM_HOOKS = 0x00001000, 259 | XEX_SYSTEM_ACCESS_PII = 0x00002000, 260 | XEX_SYSTEM_CROSS_PLATFORM_SYSTEM_LINK = 0x00004000, 261 | XEX_SYSTEM_MULTIDISC_SWAP = 0x00008000, 262 | XEX_SYSTEM_MULTIDISC_INSECURE_MEDIA = 0x00010000, 263 | XEX_SYSTEM_AP25_MEDIA = 0x00020000, 264 | XEX_SYSTEM_NO_CONFIRM_EXIT = 0x00040000, 265 | XEX_SYSTEM_ALLOW_BACKGROUND_DOWNLOAD = 0x00080000, 266 | XEX_SYSTEM_CREATE_PERSISTABLE_RAMDRIVE = 0x00100000, 267 | XEX_SYSTEM_INHERIT_PERSISTENT_RAMDRIVE = 0x00200000, 268 | XEX_SYSTEM_ALLOW_HUD_VIBRATION = 0x00400000, 269 | XEX_SYSTEM_ACCESS_UTILITY_PARTITIONS = 0x00800000, 270 | XEX_SYSTEM_IPTV_INPUT_SUPPORTED = 0x01000000, 271 | XEX_SYSTEM_PREFER_BIG_BUTTON_INPUT = 0x02000000, 272 | XEX_SYSTEM_ALLOW_EXTENDED_SYSTEM_RESERVATION = 0x04000000, 273 | XEX_SYSTEM_MULTIDISC_CROSS_TITLE = 0x08000000, 274 | XEX_SYSTEM_INSTALL_INCOMPATIBLE = 0x10000000, 275 | XEX_SYSTEM_ALLOW_AVATAR_GET_METADATA_BY_XUID = 0x20000000, 276 | XEX_SYSTEM_ALLOW_CONTROLLER_SWAPPING = 0x40000000, 277 | XEX_SYSTEM_DASH_EXTENSIBILITY_MODULE = 0x80000000, 278 | // TODO: figure out how stored 279 | /*XEX_SYSTEM_ALLOW_NETWORK_READ_CANCEL = 0x0, 280 | XEX_SYSTEM_UNINTERRUPTABLE_READS = 0x0, 281 | XEX_SYSTEM_REQUIRE_FULL_EXPERIENCE = 0x0, 282 | XEX_SYSTEM_GAME_VOICE_REQUIRED_UI = 0x0, 283 | XEX_SYSTEM_CAMERA_ANGLE = 0x0, 284 | XEX_SYSTEM_SKELETAL_TRACKING_REQUIRED = 0x0, 285 | XEX_SYSTEM_SKELETAL_TRACKING_SUPPORTED = 0x0,*/ 286 | }; 287 | 288 | enum XEXAprovalType { 289 | XEX_APPROVAL_UNAPPROVED = 0, 290 | XEX_APPROVAL_POSSIBLE = 1, 291 | XEX_APPROVAL_APPROVED = 2, 292 | XEX_APPROVAL_EXPIRED = 3, 293 | }; 294 | 295 | enum XEXEncryptionType { 296 | XEX_ENCRYPTION_NONE = 0, 297 | XEX_ENCRYPTION_NORMAL = 1, 298 | }; 299 | 300 | enum XEXCompressionType { 301 | XEX_COMPRESSION_NONE = 0, 302 | XEX_COMPRESSION_BASIC = 1, 303 | XEX_COMPRESSION_NORMAL = 2, 304 | XEX_COMPRESSION_DELTA = 3, 305 | }; 306 | 307 | enum XEXImageFlags { 308 | XEX_IMAGE_MANUFACTURING_UTILITY = 0x00000002, 309 | XEX_IMAGE_MANUFACTURING_SUPPORT_TOOLS = 0x00000004, 310 | XEX_IMAGE_XGD2_MEDIA_ONLY = 0x00000008, 311 | XEX_IMAGE_CARDEA_KEY = 0x00000100, 312 | XEX_IMAGE_XEIKA_KEY = 0x00000200, 313 | XEX_IMAGE_USERMODE_TITLE = 0x00000400, 314 | XEX_IMAGE_USERMODE_SYSTEM = 0x00000800, 315 | XEX_IMAGE_ORANGE0 = 0x00001000, 316 | XEX_IMAGE_ORANGE1 = 0x00002000, 317 | XEX_IMAGE_ORANGE2 = 0x00004000, 318 | XEX_IMAGE_IPTV_SIGNUP_APPLICATION = 0x00010000, 319 | XEX_IMAGE_IPTV_TITLE_APPLICATION = 0x00020000, 320 | XEX_IMAGE_KEYVAULT_PRIVILEGES_REQUIRED = 0x04000000, 321 | XEX_IMAGE_ONLINE_ACTIVATION_REQUIRED = 0x08000000, 322 | XEX_IMAGE_PAGE_SIZE_4KB = 0x10000000, // else 64KB 323 | XEX_IMAGE_REGION_FREE = 0x20000000, 324 | XEX_IMAGE_REVOCATION_CHECK_OPTIONAL = 0x40000000, 325 | XEX_IMAGE_REVOCATION_CHECK_REQUIRED = 0x80000000, 326 | }; 327 | 328 | enum XEXMediaFlags { 329 | XEX_MEDIA_HARDDISK = 0x00000001, 330 | XEX_MEDIA_DVD_X2 = 0x00000002, 331 | XEX_MEDIA_DVD_CD = 0x00000004, 332 | XEX_MEDIA_DVD_5 = 0x00000008, 333 | XEX_MEDIA_DVD_9 = 0x00000010, 334 | XEX_MEDIA_SYSTEM_FLASH = 0x00000020, 335 | XEX_MEDIA_MEMORY_UNIT = 0x00000080, 336 | XEX_MEDIA_USB_MASS_STORAGE_DEVICE = 0x00000100, 337 | XEX_MEDIA_NETWORK = 0x00000200, 338 | XEX_MEDIA_DIRECT_FROM_MEMORY = 0x00000400, 339 | XEX_MEDIA_RAM_DRIVE = 0x00000800, 340 | XEX_MEDIA_SVOD = 0x00001000, 341 | XEX_MEDIA_INSECURE_PACKAGE = 0x01000000, 342 | XEX_MEDIA_SAVEGAME_PACKAGE = 0x02000000, 343 | XEX_MEDIA_LOCALLY_SIGNED_PACKAGE = 0x04000000, 344 | XEX_MEDIA_LIVE_SIGNED_PACKAGE = 0x08000000, 345 | XEX_MEDIA_XBOX_PACKAGE = 0x10000000, 346 | }; 347 | 348 | enum XEXRegion { 349 | XEX_REGION_NTSCU = 0x000000FF, 350 | XEX_REGION_NTSCJ = 0x0000FF00, 351 | XEX_REGION_NTSCJ_JAPAN = 0x00000100, 352 | XEX_REGION_NTSCJ_CHINA = 0x00000200, 353 | XEX_REGION_PAL = 0x00FF0000, 354 | XEX_REGION_PAL_AU_NZ = 0x00010000, 355 | XEX_REGION_OTHER = 0xFF000000, 356 | XEX_REGION_ALL = 0xFFFFFFFF, 357 | }; 358 | 359 | enum XEXSectionType { 360 | XEX_SECTION_CODE = 1, 361 | XEX_SECTION_DATA = 2, 362 | XEX_SECTION_READONLY_DATA = 3, 363 | }; 364 | 365 | //----------------------------------------------------------------------------- 366 | 367 | struct XEXRatings { 368 | uint8_t rating_esrb; 369 | uint8_t rating_pegi; 370 | uint8_t rating_pegifi; 371 | uint8_t rating_pegipt; 372 | uint8_t rating_bbfc; 373 | uint8_t rating_cero; 374 | uint8_t rating_usk; 375 | uint8_t rating_oflcau; 376 | uint8_t rating_oflcnz; 377 | uint8_t rating_kmrb; 378 | uint8_t rating_brazil; 379 | uint8_t rating_fpb; 380 | }; 381 | 382 | union XEXVersion { 383 | uint32_t value; 384 | 385 | struct { 386 | uint32_t major : 4; 387 | uint32_t minor : 4; 388 | uint32_t build : 16; 389 | uint32_t qfe : 8; 390 | }; 391 | }; 392 | 393 | struct XEXOptionalHeader { 394 | uint32_t offset; 395 | uint32_t length; 396 | uint32_t value; 397 | uint32_t key; 398 | 399 | bool Read(ImageByteReaderXEX &reader) { 400 | if (!reader.Read(&key, sizeof(key))) 401 | return false; 402 | if (!reader.Read(&offset, sizeof(offset))) 403 | return false; 404 | Swap32(&key); 405 | Swap32(&offset); 406 | length = 0; 407 | value = 0; 408 | return true; 409 | } 410 | }; 411 | 412 | struct XEXResourceInfo { 413 | char name[9]; 414 | uint32_t address; 415 | uint32_t size; 416 | 417 | bool Read(ImageByteReaderXEX &reader) { 418 | if (!reader.Read(&name, 8)) 419 | return false; 420 | if (!reader.Read(&address, 4)) 421 | return false; 422 | if (!reader.Read(&size, 4)) 423 | return false; 424 | Swap32(&address); 425 | Swap32(&size); 426 | return true; 427 | } 428 | }; 429 | 430 | struct XEXExecutionInfo { 431 | uint32_t media_id; 432 | XEXVersion version; 433 | XEXVersion base_version; 434 | uint32_t title_id; 435 | uint8_t platform; 436 | uint8_t executable_table; 437 | uint8_t disc_number; 438 | uint8_t disc_count; 439 | uint32_t savegame_id; 440 | 441 | bool Read(ImageByteReaderXEX &reader) { 442 | if (!reader.Read(this, sizeof(XEXExecutionInfo))) 443 | return false; 444 | Swap32(&media_id); 445 | Swap32(&version.value); 446 | Swap32(&base_version.value); 447 | Swap32(&title_id); 448 | Swap32(&savegame_id); 449 | return true; 450 | } 451 | }; 452 | 453 | struct XEXTLSInfo { 454 | uint32_t slot_count; 455 | uint32_t raw_data_address; 456 | uint32_t data_size; 457 | uint32_t raw_data_size; 458 | 459 | bool Read(ImageByteReaderXEX &reader) { 460 | if (!reader.Read(this, sizeof(XEXTLSInfo))) 461 | return false; 462 | Swap32(&slot_count); 463 | Swap32(&raw_data_address); 464 | Swap32(&data_size); 465 | Swap32(&raw_data_size); 466 | return true; 467 | } 468 | }; 469 | 470 | struct XEXImportLibraryBlockHeader { 471 | uint32_t string_table_size; 472 | uint32_t count; 473 | 474 | bool Read(ImageByteReaderXEX &reader) { 475 | if (!reader.Read(this, sizeof(XEXImportLibraryBlockHeader))) 476 | return false; 477 | Swap32(&count); 478 | Swap32(&string_table_size); 479 | return true; 480 | } 481 | }; 482 | 483 | #pragma pack(push) 484 | #pragma pack(2) 485 | 486 | struct XEXImportLibraryHeader { 487 | uint32_t unknown; 488 | uint8_t digest[20]; 489 | uint32_t import_id; 490 | XEXVersion version; 491 | XEXVersion min_version; 492 | uint16_t name_index; 493 | uint16_t record_count; 494 | 495 | bool Read(ImageByteReaderXEX &reader) { 496 | if (!reader.Read(this, sizeof(XEXImportLibraryHeader))) 497 | return false; 498 | Swap32(&unknown); 499 | Swap32(&import_id); 500 | Swap32(&version.value); 501 | Swap32(&min_version.value); 502 | Swap16(&name_index); 503 | Swap16(&record_count); 504 | return true; 505 | } 506 | }; 507 | 508 | #pragma pack(pop) 509 | 510 | struct XEXStaticLibrary { 511 | char name[9]; // 8 + 1 for \0 512 | uint16_t major; 513 | uint16_t minor; 514 | uint16_t build; 515 | uint16_t qfe; 516 | XEXAprovalType approval; 517 | }; 518 | 519 | struct XEXFileBasicCompressionBlock { 520 | uint32_t data_size; 521 | uint32_t zero_size; 522 | }; 523 | 524 | struct XEXFileNormalCompressionInfo { 525 | uint32_t window_size; 526 | uint32_t window_bits; 527 | uint32_t block_size; 528 | uint8_t block_hash[20]; 529 | 530 | bool Read(ImageByteReaderXEX &reader) { 531 | if (!reader.Read(&window_size, sizeof(window_size))) 532 | return false; 533 | if (!reader.Read(&block_size, sizeof(block_size))) 534 | return false; 535 | if (!reader.Read(&block_hash, sizeof(block_hash))) 536 | return false; 537 | Swap32(&window_size); 538 | Swap32(&block_size); 539 | 540 | window_bits = 0; 541 | uint32_t temp = window_size; 542 | for (uint32_t m = 0; m < 32; m++, window_bits++) { 543 | temp <<= 1; 544 | if (temp == 0x80000000) { 545 | break; 546 | } 547 | } 548 | 549 | return true; 550 | } 551 | }; 552 | 553 | struct XEXEncryptionHeader { 554 | uint16_t encryption_type; 555 | uint16_t compression_type; 556 | 557 | bool Read(ImageByteReaderXEX &reader) { 558 | if (!reader.Read(this, sizeof(XEXEncryptionHeader))) 559 | return false; 560 | Swap16(&compression_type); 561 | Swap16(&encryption_type); 562 | return true; 563 | } 564 | }; 565 | 566 | struct XEXFileFormat { 567 | XEXEncryptionType encryption_type; 568 | XEXCompressionType compression_type; 569 | 570 | // basic compression blocks (in case of basic compression) 571 | std::vector basic_blocks; 572 | 573 | // normal compression 574 | XEXFileNormalCompressionInfo normal; 575 | }; 576 | 577 | struct XEXLoaderInfo { 578 | uint32_t header_size; 579 | uint32_t image_size; 580 | uint8_t rsa_signature[256]; 581 | uint32_t unklength; 582 | uint32_t image_flags; 583 | uint32_t load_address; 584 | uint8_t section_digest[20]; 585 | uint32_t import_table_count; 586 | uint8_t import_table_digest[20]; 587 | uint8_t media_id[16]; 588 | uint8_t file_key[16]; 589 | uint32_t export_table; 590 | uint8_t header_digest[20]; 591 | uint32_t game_regions; 592 | uint32_t media_flags; 593 | 594 | bool Read(ImageByteReaderXEX &reader) { 595 | if (!reader.Read(this, sizeof(XEXLoaderInfo))) 596 | return false; 597 | Swap32(&header_size); 598 | Swap32(&image_size); 599 | Swap32(&unklength); 600 | Swap32(&image_flags); 601 | Swap32(&load_address); 602 | Swap32(&import_table_count); 603 | Swap32(&export_table); 604 | Swap32(&game_regions); 605 | Swap32(&media_flags); 606 | return true; 607 | } 608 | }; 609 | 610 | struct XEXSection { 611 | union { 612 | struct { 613 | uint32_t type : 4; // XEXSectionType 614 | uint32_t page_count : 28; // # of 64kb pages 615 | }; 616 | 617 | uint32_t value; // To make uint8_t_t swapping easier 618 | } info; 619 | 620 | uint8_t digest[20]; 621 | }; 622 | 623 | struct XEXHeader { 624 | uint32_t xex2; 625 | uint32_t module_flags; 626 | uint32_t exe_offset; 627 | uint32_t unknown0; 628 | uint32_t certificate_offset; 629 | uint32_t header_count; 630 | 631 | void Swap() { 632 | Swap32(&xex2); 633 | Swap32(&module_flags); 634 | Swap32(&exe_offset); 635 | Swap32(&unknown0); 636 | Swap32(&certificate_offset); 637 | Swap32(&header_count); 638 | } 639 | 640 | bool Validate() const { 641 | if (xex2 != 0x58455832) { 642 | printf("Loaded file is not a XEX2 file. Signature is 0x%08X\n", xex2); 643 | return false; 644 | } 645 | 646 | return true; 647 | } 648 | }; 649 | 650 | struct XEXImageData { 651 | // header stuff 652 | XEXHeader header; 653 | XEXSystemFlags system_flags; 654 | XEXExecutionInfo execution_info; 655 | XEXRatings game_ratings; 656 | XEXTLSInfo tls_info; 657 | XEXFileFormat file_format_info; 658 | XEXLoaderInfo loader_info; 659 | uint8_t session_key[16]; 660 | 661 | // executable info 662 | uint32_t exe_address; 663 | uint32_t exe_entry_point; 664 | uint32_t exe_stack_size; 665 | uint32_t exe_heap_size; 666 | 667 | // embedded resources 668 | typedef std::vector TResourceInfos; 669 | TResourceInfos resources; 670 | 671 | // file optional headers 672 | typedef std::vector TOptionalHeaders; 673 | TOptionalHeaders optional_headers; 674 | 675 | // data sections 676 | typedef std::vector TSections; 677 | TSections sections; 678 | 679 | // import records 680 | typedef std::vector TImportRecords; 681 | TImportRecords import_records; 682 | }; 683 | 684 | //----------------------------------------------------------------------------- 685 | -------------------------------------------------------------------------------- /llvm360/LLVMApp/src/Xex/XexLoader.cpp: -------------------------------------------------------------------------------- 1 | #include "XexLoader.h" 2 | #include "AES.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "ImportTable.h" 8 | 9 | 10 | XexImage::XexImage(const wchar_t *path) 11 | : m_path(path) // Initialize path 12 | { 13 | } 14 | 15 | bool XexImage::LoadXex() { 16 | 17 | 18 | // fill import table 19 | initImportTable(); 20 | 21 | // without initializing the xexData debugging in visual studio was messing with the title id (cause random value) ups :3 22 | m_xexData = {}; 23 | 24 | // open the file 25 | FILE *f = nullptr; 26 | _wfopen_s(&f, m_path.c_str(), L"rb"); 27 | 28 | if (nullptr == f) { 29 | printf("Unable to open file '%ls'", m_path.c_str()); 30 | return false; // Return false instead of S_OK 31 | } 32 | 33 | // get file size 34 | fseek(f, 0, SEEK_END); 35 | const uint32_t fileSize = ftell(f); 36 | fseek(f, 0, SEEK_SET); 37 | 38 | // load data 39 | uint8_t *fileData = new uint8_t[fileSize]; 40 | { 41 | const uint32_t bufferSize = 4096; 42 | for (uint32_t i = 0; i < fileSize; i += bufferSize) { 43 | const int bufferReadSize = ((fileSize - i) > bufferSize) ? bufferSize : fileSize - i; 44 | fread(fileData + i, bufferReadSize, 1, f); 45 | } 46 | fclose(f); 47 | } 48 | 49 | printf("Parsing headers...\n"); 50 | ImageByteReaderXEX reader(fileData, fileSize); 51 | if (!LoadHeaders(reader)) { 52 | delete[] fileData; 53 | return false; 54 | } 55 | 56 | // load, decompress and decrypt image data 57 | printf("Decompressing image...\n"); 58 | if (!LoadImageData(reader)) { 59 | delete[] fileData; 60 | return false; 61 | } 62 | 63 | // load the embedded PE image from memory image 64 | printf("Loading PE image...\n"); 65 | if (!LoadPEImage(fileData + m_xexData.header.exe_offset, 66 | fileSize - m_xexData.header.exe_offset)) { 67 | free((void *)m_memoryData); 68 | delete[] fileData; 69 | m_memoryData = nullptr; 70 | m_memorySize = 0; 71 | return false; 72 | } 73 | 74 | // the file data buffer can be freed 75 | delete[] fileData; 76 | 77 | 78 | // finally, patch the imports 79 | printf("Patching imports...\n"); 80 | if (!PatchImports()) 81 | { 82 | free((void*)m_memoryData); 83 | m_memoryData = nullptr; 84 | m_memorySize = 0; 85 | return false; 86 | } 87 | 88 | return true; // Return true if successful 89 | } 90 | 91 | bool XexImage::LoadImageData(ImageByteReaderXEX &data) { 92 | // decompress and decrypt 93 | const XEXCompressionType compType = m_xexData.file_format_info.compression_type; 94 | switch (compType) { 95 | case XEX_COMPRESSION_NONE: { 96 | printf("XEX: image::Binary is not compressed\n"); 97 | printf("-------- COMPRESSION UNSUPPORTED ---------\n"); 98 | // return LoadImageDataUncompressed(log, data); 99 | } 100 | 101 | case XEX_COMPRESSION_BASIC: { 102 | printf("XEX: image::Binary is using basic compression (zero blocks)\n"); 103 | return LoadImageDataBasic(data); 104 | } 105 | 106 | case XEX_COMPRESSION_NORMAL: { 107 | printf("XEX: image::Binary is using normal compression"); 108 | printf("-------- COMPRESSION UNSUPPORTED ---------\n"); 109 | // return LoadImageDataNormal(log, data); 110 | } 111 | } 112 | 113 | // unsupported compression 114 | // printf("Image '%ls' is using unsupported compression mode %d and cannot be loaded\n", 115 | // GetPath().c_str(), compType); 116 | return false; 117 | } 118 | 119 | bool XexImage::LoadImageDataBasic(ImageByteReaderXEX &data) { 120 | // calculate the uncompressed size 121 | uint32_t memorySize = 0; 122 | const uint32_t blockCount = (uint32_t)m_xexData.file_format_info.basic_blocks.size(); 123 | for (uint32_t i = 0; i < blockCount; ++i) { 124 | const XEXFileBasicCompressionBlock &block = m_xexData.file_format_info.basic_blocks[i]; 125 | memorySize += block.data_size + block.zero_size; 126 | } 127 | 128 | // source data 129 | const uint32_t sourceSize = (uint32_t)(data.GetSize() - m_xexData.header.exe_offset); 130 | const uint8_t *sourceBuffer = data.GetData() + m_xexData.header.exe_offset; 131 | 132 | // sanity check 133 | const uint32_t maxImageSize = 128 << 20; 134 | if (memorySize >= maxImageSize) { 135 | printf("Computed image size is to big (%X), the exe offset = 0x%X\n", 136 | memorySize, 137 | m_xexData.header.exe_offset); 138 | 139 | return false; 140 | } 141 | 142 | // Allocate in-place the XEX memory. 143 | uint8_t *memory = (uint8_t *)malloc(memorySize); 144 | if (nullptr == memory) { 145 | printf("Failed to allocate image memory (size = 0x%X)\n", memorySize); 146 | return false; 147 | } 148 | 149 | // The decryption state is global for all blocks 150 | uint32_t rk[4 * (MAXNR + 1)]; 151 | uint8_t ivec[16] = {0}; 152 | int Nr = rijndaelKeySetupDec(rk, m_xexData.session_key, 128); 153 | 154 | // Destination memory pointers 155 | uint8_t *destMemory = memory; 156 | memset(memory, 0, memorySize); 157 | 158 | // Copy/Decrypt blocks 159 | for (uint32_t n = 0; n < blockCount; n++) { 160 | // get the size of actual data and the zeros 161 | const XEXFileBasicCompressionBlock &block = m_xexData.file_format_info.basic_blocks[n]; 162 | const uint32_t data_size = block.data_size; 163 | const uint32_t zero_size = block.zero_size; 164 | 165 | // decompress/copy data 166 | const XEXEncryptionType encType = m_xexData.file_format_info.encryption_type; 167 | switch (encType) { 168 | // no encryption, copy data 169 | case XEX_ENCRYPTION_NONE: { 170 | memcpy(destMemory, sourceBuffer, data_size); 171 | break; 172 | } 173 | 174 | // AES 175 | case XEX_ENCRYPTION_NORMAL: { 176 | const uint8_t *ct = sourceBuffer; 177 | uint8_t *pt = destMemory; 178 | for (uint32_t n = 0; n < data_size; n += 16, ct += 16, pt += 16) { 179 | 180 | // Decrypt 16 uint8_ts from input -> output. 181 | rijndaelDecrypt(rk, Nr, ct, pt); 182 | 183 | // XOR with previous 184 | for (uint32_t i = 0; i < 16; i++) { 185 | pt[i] ^= ivec[i]; 186 | ivec[i] = ct[i]; 187 | } 188 | } 189 | 190 | break; 191 | } 192 | } 193 | 194 | // go to next block 195 | sourceBuffer += data_size; 196 | destMemory += data_size + zero_size; 197 | } 198 | 199 | // check if all source data was consumed 200 | const uint32_t consumed = (uint32_t)(sourceBuffer - data.GetData()); 201 | if (consumed > data.GetSize()) { 202 | printf("XEX: To much source data was consumed by block decompression (%d > %d)\n", 203 | consumed, 204 | data.GetSize()); 205 | free(memory); 206 | return false; 207 | } else if (consumed < data.GetSize()) { 208 | printf("XEX: %d bytes of data was not consumed in block decompression (out of %d)\n", 209 | data.GetSize() - consumed, 210 | data.GetSize()); 211 | } 212 | 213 | // check if all data was outputed 214 | const uint32_t numOutputed = (uint32_t)(destMemory - memory); 215 | if (numOutputed > memorySize) { 216 | printf("XEX: To much data was outputed in block decompression (%d > %d)\n", 217 | numOutputed, 218 | memorySize); 219 | free(memory); 220 | return false; 221 | } else if (numOutputed < memorySize) { 222 | printf("XEX: %d bytes of data was not outputed in block decompression (out of %d)\n", 223 | memorySize - numOutputed, 224 | memorySize); 225 | } 226 | 227 | // loaded 228 | m_memoryData = memory; 229 | m_memorySize = memorySize; 230 | printf("XEX: Decompressed %d bytes from %d disk bytes\n", memorySize, sourceSize); 231 | return true; 232 | } 233 | 234 | bool XexImage::LoadHeaders(ImageByteReaderXEX &reader) { 235 | // load the XEX header 236 | XEXImageData &imageData = m_xexData; 237 | XEXHeader &header = m_xexData.header; 238 | if (!reader.Read(&header, sizeof(header))) 239 | return false; 240 | 241 | // swap and validate 242 | header.Swap(); 243 | if (!header.Validate()) 244 | return false; 245 | 246 | // parse for optional headers 247 | // ID & FF 248 | for (uint32_t n = 0; n < header.header_count; n++) { 249 | // load the header 250 | XEXOptionalHeader optionalHeader; 251 | if (!optionalHeader.Read(reader)) 252 | return false; 253 | 254 | // extract the length 255 | bool add = true; 256 | switch (optionalHeader.key & 0xFF) { 257 | // just the data 258 | case 0x00: 259 | case 0x01: { 260 | optionalHeader.value = optionalHeader.offset; 261 | optionalHeader.offset = 0; 262 | break; 263 | } 264 | 265 | // data 266 | case 0xFF: { 267 | optionalHeader.length = *(uint32_t *)(reader.GetData() + optionalHeader.offset); 268 | optionalHeader.offset += 4; 269 | Swap32(&optionalHeader.length); 270 | 271 | // to big ? 272 | if (optionalHeader.length + optionalHeader.offset >= reader.GetSize()) { 273 | printf("Optional header %i (0x%X) crosses file boundary. Will not be read.\n", 274 | n, 275 | optionalHeader.key); 276 | add = false; 277 | } 278 | 279 | break; 280 | } 281 | 282 | // small data 283 | default: { 284 | optionalHeader.length = (optionalHeader.key & 0xFF) * 4; 285 | 286 | // to big ? 287 | if (optionalHeader.length + optionalHeader.offset >= reader.GetSize()) { 288 | printf("Optional header %i (0x%X) crosses file boundary. Will not be read.\n", 289 | n, 290 | optionalHeader.key); 291 | add = false; 292 | } 293 | 294 | break; 295 | } 296 | } 297 | 298 | // store local optional header 299 | if (add) { 300 | m_xexData.optional_headers.push_back(optionalHeader); 301 | } 302 | } 303 | 304 | // process the optional headers 305 | for (uint32_t i = 0; i < m_xexData.optional_headers.size(); ++i) { 306 | const XEXOptionalHeader &opt = m_xexData.optional_headers[i]; 307 | 308 | // go to the header offset 309 | if (opt.length > 0 && opt.offset != 0) { 310 | if (!reader.Seek(opt.offset)) { 311 | continue; 312 | } 313 | } 314 | 315 | // process the optional headers 316 | switch (opt.key) { 317 | // System flags 318 | case XEX_HEADER_SYSTEM_FLAGS: { 319 | imageData.system_flags = (XEXSystemFlags)opt.value; 320 | break; 321 | } 322 | 323 | // Resource info repository 324 | case XEX_HEADER_RESOURCE_INFO: { 325 | // get the count 326 | const uint32_t count = (opt.length - 4) / 16; 327 | m_xexData.resources.resize(count); 328 | 329 | // move to file position 330 | for (uint32_t n = 0; n < count; ++n) { 331 | // load the resource entry 332 | XEXResourceInfo &resInfo = m_xexData.resources[i]; 333 | if (!reader.Read(&resInfo, sizeof(resInfo))) 334 | return false; 335 | } 336 | 337 | break; 338 | } 339 | 340 | // Execution info 341 | case XEX_HEADER_EXECUTION_INFO: { 342 | if (!imageData.execution_info.Read(reader)) 343 | return false; 344 | break; 345 | } 346 | 347 | // TLS info 348 | case XEX_HEADER_TLS_INFO: { 349 | if (!imageData.tls_info.Read(reader)) 350 | return false; 351 | break; 352 | } 353 | 354 | // Base address 355 | case XEX_HEADER_IMAGE_BASE_ADDRESS: { 356 | imageData.exe_address = opt.value; 357 | printf("XEX: Found base addrses: 0x%08X\n", imageData.exe_address); 358 | break; 359 | } 360 | 361 | // Entry point 362 | case XEX_HEADER_ENTRY_POINT: { 363 | imageData.exe_entry_point = opt.value; 364 | printf("XEX: Found entry point: 0x%08X\n", imageData.exe_entry_point); 365 | break; 366 | } 367 | 368 | // Default stack size 369 | case XEX_HEADER_DEFAULT_STACK_SIZE: { 370 | imageData.exe_stack_size = opt.value; 371 | break; 372 | } 373 | 374 | // Default heap size 375 | case XEX_HEADER_DEFAULT_HEAP_SIZE: { 376 | imageData.exe_heap_size = opt.value; 377 | break; 378 | } 379 | 380 | // File format information 381 | case XEX_HEADER_FILE_FORMAT_INFO: { 382 | // load the encryption type 383 | XEXEncryptionHeader encHeader; 384 | if (!encHeader.Read(reader)) 385 | return false; 386 | 387 | // setup header info 388 | imageData.file_format_info.encryption_type = (XEXEncryptionType)encHeader.encryption_type; 389 | imageData.file_format_info.compression_type = (XEXCompressionType)encHeader.compression_type; 390 | 391 | // load compression blocks 392 | switch (encHeader.compression_type) { 393 | case XEX_COMPRESSION_NONE: { 394 | printf("XEX: image::Binary is using no compression\n"); 395 | break; 396 | } 397 | 398 | case XEX_COMPRESSION_DELTA: { 399 | printf("XEX: image::Binary is using unsupported delta compression\n"); 400 | break; 401 | } 402 | 403 | case XEX_COMPRESSION_BASIC: { 404 | // get the block count 405 | const uint32_t block_count = (opt.length - 8) / 8; 406 | imageData.file_format_info.basic_blocks.resize(block_count); 407 | 408 | // load the basic compression blocks 409 | for (uint32_t i = 0; i < block_count; ++i) { 410 | XEXFileBasicCompressionBlock &block = imageData.file_format_info.basic_blocks[i]; 411 | 412 | if (!reader.Read(&block, sizeof(block))) 413 | return false; 414 | Swap32(&block.data_size); 415 | Swap32(&block.zero_size); 416 | } 417 | 418 | printf("XEX: image::Binary is using basic compression with %d blocks\n", block_count); 419 | break; 420 | } 421 | 422 | case XEX_COMPRESSION_NORMAL: { 423 | XEXFileNormalCompressionInfo &normal_info = imageData.file_format_info.normal; 424 | if (!normal_info.Read(reader)) 425 | return false; 426 | 427 | printf("XEX: image::Binary is using normal compression with block size = %d\n", 428 | normal_info.block_size); 429 | break; 430 | } 431 | } 432 | 433 | // encryption type 434 | if (encHeader.encryption_type != XEX_ENCRYPTION_NONE) { 435 | printf("XEX: image::Binary is encrypted\n"); 436 | } 437 | 438 | // opt header 439 | break; 440 | } 441 | 442 | // Import libraries - very important piece 443 | case XEX_HEADER_IMPORT_LIBRARIES: { 444 | // Load the header data 445 | XEXImportLibraryBlockHeader blockHeader; 446 | if (!blockHeader.Read(reader)) 447 | return false; 448 | 449 | // get the string data 450 | const char *string_table = (const char *)reader.GetData() + reader.GetOffset(); 451 | reader.Seek(reader.GetOffset() + blockHeader.string_table_size); 452 | 453 | // load the imports 454 | for (uint32_t m = 0; m < blockHeader.count; m++) { 455 | XEXImportLibraryHeader header; 456 | if (!header.Read(reader)) 457 | return false; 458 | 459 | // get the library name 460 | const char *name = "Unknown"; 461 | const uint16_t name_index = header.name_index & 0xFF; 462 | for (uint32_t i = 0, j = 0; i < blockHeader.string_table_size;) { 463 | assert(j <= 0xFF); 464 | if (j == name_index) { 465 | name = string_table + i; 466 | break; 467 | } 468 | 469 | if (string_table[i] == 0) { 470 | i++; 471 | if (i % 4) { 472 | i += 4 - (i % 4); 473 | } 474 | j++; 475 | } else { 476 | i++; 477 | } 478 | } 479 | 480 | // save the import lib name 481 | if (name[0]) { 482 | printf("Found import library: '%s'\n", name); 483 | m_libNames.push_back(name); 484 | } 485 | 486 | // load the records 487 | for (uint32_t i = 0; i < header.record_count; ++i) { 488 | // load the record entry 489 | uint32_t recordEntry = 0; 490 | if (!reader.Read(&recordEntry, sizeof(recordEntry))) 491 | return false; 492 | Swap32(&recordEntry); 493 | 494 | // add to the global record entry list 495 | m_xexData.import_records.push_back(recordEntry); 496 | } 497 | } 498 | 499 | // done 500 | break; 501 | } 502 | } 503 | } 504 | 505 | // load the loader info 506 | { 507 | // go to the certificate region 508 | if (!reader.Seek(header.certificate_offset)) 509 | return false; 510 | 511 | // load the loader info 512 | XEXLoaderInfo &li = m_xexData.loader_info; 513 | if (!li.Read(reader)) 514 | return false; 515 | 516 | // print some stats 517 | printf("XEX: Binary size: 0x%X\n", li.image_size); 518 | } 519 | 520 | // load the sections 521 | { 522 | // go to the section region 523 | if (!reader.Seek(header.certificate_offset + 0x180)) 524 | return false; 525 | 526 | // get the section count 527 | uint32_t sectionCount = 0; 528 | if (!reader.Read(§ionCount, sizeof(sectionCount))) 529 | return false; 530 | Swap32(§ionCount); 531 | 532 | // load the sections 533 | m_xexData.sections.resize(sectionCount); 534 | for (uint32_t i = 0; i < sectionCount; ++i) { 535 | XEXSection §ion = m_xexData.sections[i]; 536 | if (!reader.Read(§ion, sizeof(XEXSection))) 537 | return false; 538 | Swap32(§ion.info.value); 539 | } 540 | } 541 | 542 | // decrypt the XEX key 543 | { 544 | // Key for retail executables 545 | const static uint8_t xe_xex2_retail_key[16] = {0x20, 546 | 0xB1, 547 | 0x85, 548 | 0xA5, 549 | 0x9D, 550 | 0x28, 551 | 0xFD, 552 | 0xC3, 553 | 0x40, 554 | 0x58, 555 | 0x3F, 556 | 0xBB, 557 | 0x08, 558 | 0x96, 559 | 0xBF, 560 | 0x91}; 561 | 562 | // Key for devkit executables 563 | const static uint8_t xe_xex2_devkit_key[16] = {0x00, 564 | 0x00, 565 | 0x00, 566 | 0x00, 567 | 0x00, 568 | 0x00, 569 | 0x00, 570 | 0x00, 571 | 0x00, 572 | 0x00, 573 | 0x00, 574 | 0x00, 575 | 0x00, 576 | 0x00, 577 | 0x00, 578 | 0x00}; 579 | 580 | // Guess key based on file info. 581 | const uint8_t *keyToUse = xe_xex2_devkit_key; 582 | if (m_xexData.execution_info.title_id != 0) { 583 | printf("XEX: Found TitleID 0x%X\n", m_xexData.execution_info.title_id); 584 | // if ( m_xexData.system_flags 585 | keyToUse = xe_xex2_retail_key; 586 | } 587 | 588 | // Decrypt the header and session key 589 | uint32_t buffer[4 * (MAXNR + 1)]; 590 | int32_t nr = rijndaelKeySetupDec(buffer, keyToUse, 128); 591 | rijndaelDecrypt(buffer, nr, m_xexData.loader_info.file_key, m_xexData.session_key); 592 | 593 | // stats 594 | { 595 | const uint32_t *keys = (const uint32_t *)&m_xexData.loader_info.file_key; 596 | printf("XEX: Decrypted file key: %08X-%08X-%08X-%08X\n", keys[0], keys[1], keys[2], keys[3]); 597 | 598 | const uint32_t *skeys = (const uint32_t *)&m_xexData.session_key; 599 | printf("XEX: Decrypted session key: %08X-%08X-%08X-%08X\n", 600 | skeys[0], 601 | skeys[1], 602 | skeys[2], 603 | skeys[3]); 604 | } 605 | } 606 | 607 | // headers loaded 608 | return true; 609 | } 610 | 611 | bool XexImage::LoadPEImage(const uint8_t *fileData, const uint32_t fileDataSize) { 612 | ImageByteReaderXEX loader(m_memoryData, m_memorySize); 613 | 614 | // LOAD DOS header 615 | DOSHeader dosHeader; 616 | if (!loader.Read(&dosHeader, sizeof(dosHeader))) 617 | return false; 618 | if (!dosHeader.Validate()) 619 | return false; 620 | 621 | // Move to the new header 622 | if (!loader.Seek(dosHeader.e_lfanew)) 623 | return false; 624 | 625 | // Verify NT signature (PE\0\0). 626 | uint32_t peSignature; 627 | if (!loader.Read(&peSignature, sizeof(peSignature))) 628 | return false; 629 | if (peSignature != 0x00004550) { 630 | printf("PE: Missing PE signature\n"); 631 | return false; 632 | } 633 | 634 | // Load the file header 635 | COFFHeader coffHeader; 636 | if (!loader.Read(&coffHeader, sizeof(COFFHeader))) 637 | return false; 638 | 639 | // Verify matches an Xbox PE 640 | if (coffHeader.Machine != 0x01F2) { 641 | printf("PE: Machine type does not match Xbox360 (found 0x%X)\n", coffHeader.Machine); 642 | return false; 643 | } 644 | 645 | // Should be 32-bit 646 | if ((coffHeader.Characteristics & 0x0100) == 0) { 647 | printf("PE: Only 32-bit images are supported\n"); 648 | return false; 649 | } 650 | 651 | // Verify the expected size. 652 | if (coffHeader.SizeOfOptionalHeader != 224) { 653 | printf("PE: Invalid size of optional header (got %d)\n", coffHeader.SizeOfOptionalHeader); 654 | return false; 655 | } 656 | 657 | // Read the optional header information 658 | PEOptHeader optHeader; 659 | if (!loader.Read(&optHeader, sizeof(optHeader))) 660 | return false; 661 | 662 | // Veriry the optional header is valid (32bit) 663 | if (optHeader.signature != 0x10b) { 664 | printf("PE: Invalid signature of optional header (got 0x%0X)\n", optHeader.signature); 665 | return false; 666 | } 667 | 668 | // Verify subsystem 669 | if (optHeader.Subsystem != IMAGE_SUBSYSTEM_XBOX) { 670 | printf("PE: Invalid subsystem (got %d)\n", optHeader.Subsystem); 671 | return false; 672 | } 673 | 674 | // Store the PE header 675 | m_peHeader = optHeader; 676 | 677 | // extend the virtual memory size 678 | uint32_t extendedMemorySize = 0; 679 | 680 | // Read the sections 681 | const uint32_t numSections = coffHeader.NumberOfSections; 682 | for (uint32_t i = 0; i < numSections; ++i) { 683 | // load section description 684 | COFFSection section; 685 | if (!loader.Read(§ion, sizeof(section))) 686 | return false; 687 | 688 | // get section name 689 | char sectionName[sizeof(section.Name) + 1]; 690 | memcpy(sectionName, section.Name, sizeof(section.Name)); 691 | sectionName[sizeof(section.Name)] = 0; 692 | 693 | // exend the memory size 694 | const uint32_t lastMemoryAddress = section.VirtualAddress + section.VirtualSize; 695 | if (lastMemoryAddress > extendedMemorySize) { 696 | extendedMemorySize = lastMemoryAddress; 697 | } 698 | 699 | // create section info 700 | m_sections.push_back(CreateSection(section)); 701 | 702 | // section info 703 | printf("PE: Section '%s': physical (%d,%d), virtual (%d, %d)\n", 704 | m_sections.back()->GetName().c_str(), 705 | section.PointerToRawData, 706 | section.SizeOfRawData, 707 | section.VirtualAddress, 708 | section.VirtualSize); 709 | } 710 | 711 | // extend image size 712 | if (extendedMemorySize > m_memorySize) { 713 | // we have extended image data 714 | printf("PE: Image sections extend beyond virtual memory range loaded from file (%06Xh > " 715 | "%06Xh). Extending by %d bytes.\n", 716 | extendedMemorySize, 717 | m_memorySize, 718 | extendedMemorySize - m_memorySize); 719 | 720 | // resize image data 721 | const uint32_t oldMemorySize = m_memorySize; 722 | uint8_t *newMemoryData = new uint8_t[extendedMemorySize]; 723 | memset(newMemoryData, 0, extendedMemorySize); 724 | memcpy(newMemoryData, m_memoryData, m_memorySize); 725 | delete[] m_memoryData; 726 | m_memorySize = extendedMemorySize; 727 | m_memoryData = newMemoryData; 728 | 729 | // copy extra sectiomn 730 | for (uint32_t i = 0; i < m_sections.size(); ++i) { 731 | const Section *section = m_sections[i]; 732 | 733 | // no physical data 734 | if (!section->GetPhysicalSize()) 735 | continue; 736 | 737 | // check physical size 738 | if (section->GetPhysicalSize() + section->GetPhysicalOffset() > fileDataSize) { 739 | printf("PE: Section '%hs' lies outside any phyisical data we have %d (size %d)\n", 740 | section->GetName().c_str(), 741 | section->GetPhysicalSize(), 742 | section->GetPhysicalOffset()); 743 | 744 | continue; 745 | } 746 | 747 | // valid section offset ? 748 | if (section->GetVirtualOffset() >= oldMemorySize) { 749 | printf("PE: Copying section '%hs' directly from raw file from offset %d (size %d)\n", 750 | section->GetName().c_str(), 751 | section->GetPhysicalSize(), 752 | section->GetPhysicalOffset()); 753 | 754 | uint32_t sizeToCopy = section->GetPhysicalSize(); 755 | if (section->GetVirtualSize() < sizeToCopy) 756 | sizeToCopy = section->GetVirtualSize(); 757 | 758 | memcpy(newMemoryData + section->GetVirtualOffset(), 759 | fileData + section->GetPhysicalOffset(), 760 | sizeToCopy); 761 | } 762 | } 763 | } 764 | 765 | // Set the base address and entry point 766 | m_baseAddress = m_xexData.exe_address; 767 | m_entryAddress = m_xexData.exe_entry_point; 768 | 769 | // image::Binary data loaded 770 | return true; 771 | } 772 | 773 | bool XexImage::PatchImports() 774 | { 775 | // process the records to get the actuall imports 776 | // The number of records does not correspond to the number of imports! 777 | // Each record points at either a location in text or data - dereferencing the 778 | // pointer will yield a value that & 0xFFFF = the import ordinal, 779 | // >> 16 & 0xFF = import library index, and >> 24 & 0xFF = 0 if a variable 780 | // (just get address) or 1 if a thunk (needs rewrite). 781 | for (uint32_t i = 0; i < m_xexData.import_records.size(); ++i) 782 | { 783 | const uint32_t tableAddress = m_xexData.import_records[i]; 784 | 785 | 786 | // get relative address 787 | const auto memOffset = tableAddress - GetBaseAddress(); 788 | if (memOffset > m_memorySize) 789 | { 790 | printf("XEX: invalid import record offset: 0x%X\n", memOffset); 791 | return false; 792 | } 793 | 794 | // get the value in the memory 795 | uint32_t value = *(const uint32_t*)(m_memoryData + memOffset); 796 | Swap32(&value); 797 | 798 | // Get record type 799 | const uint8_t type = (value & 0xFF000000) >> 24; 800 | const uint8_t libIndex = (value & 0x00FF0000) >> 16; 801 | 802 | // Import symbols 803 | if (type == 0) 804 | { 805 | if (libIndex >= m_libNames.size()) 806 | { 807 | printf("XEX: invalid import type 0 record lib index (%d, max:%d)\n", libIndex, m_libNames.size()); 808 | continue; 809 | } 810 | 811 | // get the export info 812 | const uint32_t importOrdinal = (value & 0xFFFF); 813 | const std::string importLibName = m_libNames[libIndex]; 814 | const uint32_t importAddress = (m_xexData.import_records[i]); 815 | 816 | // find the import 817 | Import* table_imp = findImport_FromLib(importLibName, importOrdinal); 818 | Import* impV = new Import(table_imp->lib, VARIABLE, std::string{ table_imp->name.c_str() }, table_imp->ordinal); 819 | 820 | // autogenerate import name if not known 821 | if (impV->name.empty()) 822 | { 823 | char autoExportName[256]; 824 | sprintf_s(autoExportName, 256, "Export%d", importOrdinal); 825 | impV->name = autoExportName; 826 | } 827 | 828 | // create import 829 | impV->tableAddr = tableAddress; 830 | impV->funcImportAddr = importAddress; 831 | printf("XEX: Import symbol '%s', table=%06Xh\n", impV->name.c_str(), importAddress); 832 | m_imports.push_back(impV); 833 | } 834 | 835 | // Import functions 836 | else if (type == 1) 837 | { 838 | if (libIndex >= m_libNames.size()) 839 | { 840 | printf("XEX: invalid import type 1 record lib index (%d, max:%d)\n", libIndex, m_libNames.size()); 841 | continue; 842 | } 843 | 844 | // get the export info 845 | const uint32_t importOrdinal = (value & 0xFFFF); 846 | const std::string importLibName = m_libNames[libIndex]; 847 | const uint32_t importAddress = (m_xexData.import_records[i]); 848 | 849 | // find the import 850 | Import* table_imp = findImport_FromLib(importLibName, importOrdinal); 851 | Import* imp = new Import(table_imp->lib, FUNCTION, std::string{ table_imp->name.c_str()}, table_imp->ordinal); 852 | 853 | // autogenerate import name if not known 854 | if (imp->name.empty()) 855 | { 856 | char autoExportName[256]; 857 | sprintf_s(autoExportName, 256, "Export%d", importOrdinal); 858 | imp->name = autoExportName; 859 | } 860 | 861 | // create import 862 | imp->tableAddr = tableAddress; 863 | imp->funcImportAddr = importAddress; 864 | printf("XEX: Import func '%s', table=%06Xh, entry=%06Xh\n", imp->name.c_str(), tableAddress, importAddress); 865 | m_imports.push_back(imp); 866 | } 867 | } 868 | 869 | // Done*/ 870 | return true; 871 | } 872 | 873 | Section *XexImage::CreateSection(const COFFSection §ion) { 874 | // copy name 875 | char localName[sizeof(section.Name) + 1]; 876 | memcpy(localName, section.Name, sizeof(section.Name)); 877 | localName[sizeof(section.Name)] = 0; 878 | 879 | // create section info 880 | return new Section(this, 881 | localName, 882 | section.VirtualAddress, 883 | section.VirtualSize, 884 | section.PointerToRawData, 885 | section.SizeOfRawData, 886 | 0 != (section.Flags & IMAGE_SCN_MEM_READ), 887 | 0 != (section.Flags & IMAGE_SCN_MEM_WRITE), 888 | 0 != (section.Flags & IMAGE_SCN_MEM_EXECUTE), 889 | "ppc"); 890 | }; 891 | 892 | Section::Section(XexImage *parent, 893 | const char *name, 894 | const uint32_t virtualOffset, 895 | const uint32_t virtualSize, 896 | const uint32_t physicalOffset, 897 | const uint32_t physicalSize, 898 | const bool isReadable, 899 | const bool isWritable, 900 | const bool isExecutable, 901 | const char *cpuName) 902 | : m_image(parent) 903 | , m_name(name) 904 | , m_virtualOffset(virtualOffset) 905 | , m_virtualSize(virtualSize) 906 | , m_physicalOffset(physicalOffset) 907 | , m_physicalSize(physicalSize) 908 | , m_isReadable(isReadable) 909 | , m_isWritable(isWritable) 910 | , m_isExecutable(isExecutable) 911 | , m_cpuName(cpuName) { 912 | } 913 | -------------------------------------------------------------------------------- /llvm360/LLVMApp/src/Xex/XexLoader.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "XEXImage.h" 3 | #include 4 | 5 | class Section; 6 | class XexImage; 7 | 8 | 9 | 10 | enum ImportType { 11 | FUNCTION = 0, 12 | VARIABLE = 1 13 | }; 14 | 15 | enum XboxLibrary { 16 | XboxKrnl = 0, 17 | Xam = 1, 18 | xbdm = 2, 19 | Xapi = 3, 20 | }; 21 | 22 | class Import 23 | { 24 | public: 25 | Import(XboxLibrary _lib, 26 | ImportType _type, 27 | std::string _name, 28 | uint32_t _ordinal) : lib(_lib), type(_type), name(_name), ordinal(_ordinal) 29 | { 30 | tableAddr = 0; 31 | funcImportAddr = 0; 32 | } 33 | 34 | XboxLibrary lib; 35 | ImportType type; 36 | std::string name; 37 | uint32_t ordinal; 38 | 39 | uint32_t tableAddr; 40 | uint32_t funcImportAddr; 41 | 42 | }; 43 | 44 | class Section { 45 | public: 46 | inline XexImage *GetImage() const { 47 | return m_image; 48 | } 49 | 50 | inline const std::string &GetName() const { 51 | return m_name; 52 | } 53 | inline const uint32_t GetVirtualOffset() const { 54 | return m_virtualOffset; 55 | } 56 | inline const uint32_t GetVirtualSize() const { 57 | return m_virtualSize; 58 | } 59 | inline const uint32_t GetPhysicalOffset() const { 60 | return m_physicalOffset; 61 | } 62 | inline const uint32_t GetPhysicalSize() const { 63 | return m_physicalSize; 64 | } 65 | inline const bool CanRead() const { 66 | return m_isReadable; 67 | } 68 | inline const bool CanWrite() const { 69 | return m_isWritable; 70 | } 71 | inline const bool CanExecute() const { 72 | return m_isExecutable; 73 | } 74 | inline const std::string &GetCPUName() const { 75 | return m_cpuName; 76 | } 77 | 78 | Section() 79 | : m_name("none") 80 | , m_cpuName("none") 81 | , m_virtualOffset(0) 82 | , m_virtualSize(0) 83 | , m_physicalOffset(0) 84 | , m_physicalSize(0) 85 | , m_isReadable(false) 86 | , m_isWritable(false) 87 | , m_isExecutable(false) { 88 | } 89 | Section(XexImage *parent, 90 | const char *name, 91 | const uint32_t virtualAddress, 92 | const uint32_t virtualSize, 93 | const uint32_t physicalAddress, 94 | const uint32_t physicalSize, 95 | const bool isReadable, 96 | const bool isWritable, 97 | const bool isExecutable, 98 | const char *cpuName); 99 | 100 | // save/load the object 101 | // void Save(IBinaryFileWriter& writer) const; 102 | // bool Load(XexImage* image, IBinaryFileReader& reader); 103 | 104 | // Check if specified offset is valid offset within the section 105 | const bool IsValidOffset(const uint32_t offset) const { 106 | return (offset >= m_virtualOffset) && (offset < (m_virtualOffset + m_virtualSize)); 107 | } 108 | 109 | private: 110 | XexImage *m_image; 111 | std::string m_name; 112 | 113 | uint32_t m_virtualOffset; 114 | uint32_t m_virtualSize; 115 | 116 | uint32_t m_physicalOffset; 117 | uint32_t m_physicalSize; 118 | 119 | bool m_isReadable; 120 | bool m_isWritable; 121 | bool m_isExecutable; 122 | 123 | std::string m_cpuName; 124 | }; 125 | 126 | class XexImage { 127 | public: 128 | XexImage(const wchar_t *path); 129 | 130 | //! Load from file, returns the loaded image 131 | bool LoadXex(); 132 | bool LoadHeaders(ImageByteReaderXEX &reader); 133 | bool LoadImageData(ImageByteReaderXEX &data); 134 | 135 | // Compression 136 | bool LoadImageDataBasic(ImageByteReaderXEX &data); 137 | 138 | // PE 139 | bool LoadPEImage(const uint8_t *fileData, const uint32_t fileDataSize); 140 | Section *CreateSection(const COFFSection §ion); 141 | 142 | bool PatchImports(); 143 | 144 | 145 | inline const std::wstring &GetPath() const { 146 | return m_path; 147 | } 148 | 149 | inline const uint32_t GetMemorySize() const { 150 | return m_memorySize; 151 | } 152 | inline const uint8_t *GetMemory() const { 153 | return m_memoryData; 154 | } 155 | 156 | inline const uint64_t GetBaseAddress() const { 157 | return m_baseAddress; 158 | } 159 | inline const uint64_t GetEntryAddress() const { 160 | return m_entryAddress; 161 | } 162 | 163 | inline const uint32_t GetNumSections() const { 164 | return (uint32_t)m_sections.size(); 165 | } 166 | 167 | Section* getSectionByAddressBounds(uint32_t address) 168 | { 169 | for (size_t i = 0; i < m_sections.size(); i++) 170 | { 171 | if (address >= m_sections[i]->GetVirtualOffset() + GetBaseAddress() && address < m_sections[i]->GetVirtualOffset() + m_sections[i]->GetVirtualSize() + GetBaseAddress()) 172 | { 173 | return m_sections[i]; 174 | } 175 | } 176 | return nullptr; 177 | } 178 | 179 | inline Section *GetSection(const uint32_t index) const { 180 | return m_sections[index]; 181 | } 182 | 183 | /*inline const uint32_t GetNumImports() const { return (uint32_t)m_imports.size(); } 184 | inline const Import* GetImport(const uint32_t index) const { return m_imports[index]; } 185 | 186 | inline const uint32_t GetNumExports() const { return (uint32_t)m_exports.size(); } 187 | inline const Export* GetExports(const uint32_t index) const { return m_exports[index]; } 188 | 189 | inline const uint32_t GetNumSymbols() const { return (uint32_t)m_symbols.size(); } 190 | inline const Symbol* GetSymbol(const uint32_t index) const { return m_symbols[index]; }*/ 191 | 192 | uint8_t *m_textData; 193 | 194 | // file header 195 | XEXImageData m_xexData; 196 | PEOptHeader m_peHeader; 197 | private: 198 | 199 | 200 | // library names 201 | std::vector m_libNames; 202 | 203 | // version info for the import module 204 | XEXVersion m_version; 205 | XEXVersion m_minimalVersion; 206 | 207 | uint32_t m_memorySize; 208 | const uint8_t *m_memoryData; 209 | std::wstring m_path; 210 | 211 | uint64_t m_baseAddress; 212 | uint64_t m_entryAddress; 213 | 214 | std::vector
m_sections; 215 | public: 216 | std::vector m_imports; 217 | /* 218 | typedef std::vector< Export* > TExports; 219 | TExports m_exports; 220 | 221 | typedef std::vector< Symbol* > TSymbols; 222 | TSymbols m_symbols;*/ 223 | }; 224 | -------------------------------------------------------------------------------- /llvm360/LLVMApp/src/misc/Utils.cpp: -------------------------------------------------------------------------------- 1 | #include "Utils.h" 2 | 3 | uint32_t Swap32(uint32_t val) { 4 | return ((((val) & 0xff000000) >> 24) | (((val) & 0x00ff0000) >> 8) | (((val) & 0x0000ff00) << 8) | 5 | (((val) & 0x000000ff) << 24)); 6 | } 7 | -------------------------------------------------------------------------------- /llvm360/LLVMApp/src/misc/Utils.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | uint32_t Swap32(uint32_t val); 5 | -------------------------------------------------------------------------------- /llvm360/Runtime/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.15) 2 | project(Runtime) 3 | 4 | # Collect source files 5 | file(GLOB_RECURSE SOURCES "src/*.cpp" "src/*.h") 6 | 7 | # Include directories 8 | include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include) 9 | 10 | 11 | # imgui 12 | set(IMGUI_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../external/imgui) 13 | include_directories(${IMGUI_DIR}) 14 | include_directories(${IMGUI_DIR}/backends) 15 | include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../../external/sdl2) 16 | 17 | 18 | if(MSVC) 19 | # Debug build flags 20 | set(CMAKE_C_FLAGS_DEBUG "/ZI /Od /Ob0 /DNDEBUG" CACHE STRING "" FORCE) 21 | set(CMAKE_CXX_FLAGS_DEBUG "/ZI /Od /Ob0 /DNDEBUG" CACHE STRING "" FORCE) 22 | 23 | # Release build flags (optimization) 24 | set(CMAKE_C_FLAGS_RELEASE "/O2" CACHE STRING "" FORCE) 25 | set(CMAKE_CXX_FLAGS_RELEASE "/O2" CACHE STRING "" FORCE) 26 | endif() 27 | 28 | 29 | 30 | set(IMGUI_SRC 31 | ${IMGUI_DIR}/imgui.cpp 32 | ${IMGUI_DIR}/imgui_demo.cpp 33 | ${IMGUI_DIR}/imgui_draw.cpp 34 | ${IMGUI_DIR}/imgui_tables.cpp 35 | ${IMGUI_DIR}/imgui_widgets.cpp 36 | ${IMGUI_DIR}/backends/imgui_impl_dx11.cpp 37 | ${IMGUI_DIR}/backends/imgui_impl_win32.cpp 38 | ) 39 | 40 | 41 | # Create a shared library 42 | add_library(Runtime SHARED ${SOURCES} ${IMGUI_SRC}) 43 | 44 | 45 | # Set output directories to the same folder as the master project (bin/) 46 | set_target_properties(Runtime PROPERTIES 47 | RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin 48 | LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin 49 | ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin 50 | ) 51 | 52 | # Ensure proper export symbols in the DLL (for MSVC) 53 | if(MSVC) 54 | target_compile_definitions(Runtime PRIVATE "RUNTIME_EXPORTS") 55 | endif() 56 | 57 | 58 | target_link_libraries(Runtime PRIVATE d3d12 d3d11 dxgi dxguid) 59 | 60 | # Link dependencies (if any) 61 | target_precompile_headers(Runtime PRIVATE src/pch.h) 62 | 63 | # Organize files into folders/filters matching the src/ directory 64 | foreach(SOURCE_FILE IN LISTS SOURCES) 65 | get_filename_component(SOURCE_PATH "${SOURCE_FILE}" PATH) 66 | file(RELATIVE_PATH REL_PATH "${CMAKE_CURRENT_SOURCE_DIR}/src" "${SOURCE_PATH}") 67 | string(REPLACE "/" "\\" FILTER_GROUP "${REL_PATH}") 68 | source_group("${FILTER_GROUP}" FILES "${SOURCE_FILE}") 69 | endforeach() 70 | -------------------------------------------------------------------------------- /llvm360/Runtime/src/Graphics/DX12Manager.cpp: -------------------------------------------------------------------------------- 1 | #include "DX12Manager.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | DirectX12Manager& DirectX12Manager::getInstance() { 8 | static DirectX12Manager instance; 9 | return instance; 10 | } 11 | 12 | void DirectX12Manager::initialize() { 13 | // Create Device, CommandQueue, SwapChain, etc. 14 | // Setup DX12 device 15 | if (FAILED(D3D12CreateDevice(nullptr, D3D_FEATURE_LEVEL_12_0, IID_PPV_ARGS(&device)))) { 16 | throw std::runtime_error("Failed to create DX12 device."); 17 | } 18 | 19 | // Create Command Queue 20 | D3D12_COMMAND_QUEUE_DESC queueDesc = {}; 21 | queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT; 22 | queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE; 23 | if (FAILED(device->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&commandQueue)))) { 24 | throw std::runtime_error("Failed to create command queue."); 25 | } 26 | 27 | // Initialize resources 28 | initializeResources(); 29 | } 30 | 31 | void DirectX12Manager::createSwapChain(HWND hwnd) { 32 | // Create swap chain for game window 33 | DXGI_SWAP_CHAIN_DESC swapChainDesc = {}; 34 | swapChainDesc.BufferCount = 2; 35 | swapChainDesc.BufferDesc.Width = 800; 36 | swapChainDesc.BufferDesc.Height = 600; 37 | swapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; 38 | swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; 39 | swapChainDesc.OutputWindow = hwnd; 40 | swapChainDesc.SampleDesc.Count = 1; 41 | swapChainDesc.Windowed = TRUE; 42 | swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD; 43 | 44 | Microsoft::WRL::ComPtr factory; 45 | CreateDXGIFactory1(IID_PPV_ARGS(&factory)); 46 | //factory->CreateSwapChain(commandQueue.Get(), &swapChainDesc, &gameSwapChain); 47 | 48 | // Create another swap chain for ImGui window if necessary 49 | // (similar setup) 50 | } 51 | 52 | void DirectX12Manager::renderFrame() { 53 | } 54 | 55 | void DirectX12Manager::initializeResources() { 56 | } 57 | 58 | void DirectX12Manager::cleanup() { 59 | } 60 | -------------------------------------------------------------------------------- /llvm360/Runtime/src/Graphics/DX12Manager.h: -------------------------------------------------------------------------------- 1 | #ifndef DIRECTX12_MANAGER_H 2 | #define DIRECTX12_MANAGER_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | HWND createWindow(const char* windowTitle, int width, int height) { 15 | WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, DefWindowProc, 0L, 0L, GetModuleHandle(nullptr), nullptr, nullptr, nullptr, nullptr, "DirectX12App", nullptr }; 16 | RegisterClassEx(&wc); 17 | 18 | HWND hwnd = CreateWindow(wc.lpszClassName, windowTitle, WS_OVERLAPPEDWINDOW, 100, 100, width, height, nullptr, nullptr, wc.hInstance, nullptr); 19 | ShowWindow(hwnd, SW_SHOWDEFAULT); 20 | UpdateWindow(hwnd); 21 | 22 | return hwnd; 23 | } 24 | 25 | 26 | class DirectX12Manager { 27 | public: 28 | static DirectX12Manager& getInstance(); 29 | 30 | void initialize(); // Initializes DX12 resources 31 | void createSwapChain(HWND hwnd); // Creates swap chain for rendering 32 | void renderFrame(); // Renders a frame (called by game thread or imgui thread) 33 | void cleanup(); // Cleanup resources 34 | 35 | // DirectX12 Resources 36 | ID3D12Device* device; 37 | ID3D12CommandQueue* commandQueue; 38 | ID3D12Fence* fence; 39 | 40 | 41 | Microsoft::WRL::ComPtr gameSwapChain; 42 | HWND gameWindow; 43 | Microsoft::WRL::ComPtr imguiSwapChain; 44 | HWND debugWindow; 45 | 46 | private: 47 | DirectX12Manager() {} 48 | ~DirectX12Manager() {} 49 | 50 | // Helper method to create command lists, allocators, etc. 51 | void initializeResources(); 52 | }; 53 | 54 | #endif // DIRECTX12_MANAGER_H 55 | -------------------------------------------------------------------------------- /llvm360/Runtime/src/Graphics/ImGuiDebugger.cpp: -------------------------------------------------------------------------------- 1 | #include "ImGuiDebugger.h" 2 | #include 3 | #include 4 | #include 5 | 6 | 7 | // Data 8 | static ID3D11Device* g_pd3dDevice = nullptr; 9 | static ID3D11DeviceContext* g_pd3dDeviceContext = nullptr; 10 | static IDXGISwapChain* g_pSwapChain = nullptr; 11 | static bool g_SwapChainOccluded = false; 12 | static UINT g_ResizeWidth = 0, g_ResizeHeight = 0; 13 | static ID3D11RenderTargetView* g_mainRenderTargetView = nullptr; 14 | 15 | 16 | // Forward declarations of helper functions 17 | bool CreateDeviceD3D(HWND hWnd); 18 | void CleanupDeviceD3D(); 19 | void CreateRenderTarget(); 20 | void CleanupRenderTarget(); 21 | LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); 22 | 23 | 24 | void ImGuiDebugger::initialize() { 25 | // Create application window 26 | //ImGui_ImplWin32_EnableDpiAwareness(); 27 | WNDCLASSEXW wc = { sizeof(wc), CS_CLASSDC, WndProc, 0L, 0L, GetModuleHandle(nullptr), nullptr, nullptr, nullptr, nullptr, L"ImGui Example", nullptr }; 28 | ::RegisterClassExW(&wc); 29 | HWND hwnd = ::CreateWindowW(wc.lpszClassName, L"Dear ImGui DirectX11 Example", WS_OVERLAPPEDWINDOW, 100, 100, 1280, 800, nullptr, nullptr, wc.hInstance, nullptr); 30 | 31 | debugWindow = hwnd; 32 | //deserialize("dbMapData.bin", dbInstrMap); 33 | 34 | 35 | // Initialize Direct3D 36 | if (!CreateDeviceD3D(hwnd)) 37 | { 38 | CleanupDeviceD3D(); 39 | ::UnregisterClassW(wc.lpszClassName, wc.hInstance); 40 | return; 41 | } 42 | 43 | // Show the window 44 | ::ShowWindow(hwnd, SW_SHOWDEFAULT); 45 | ::UpdateWindow(hwnd); 46 | 47 | // Setup Dear ImGui context 48 | IMGUI_CHECKVERSION(); 49 | ImGui::CreateContext(); 50 | ImGuiIO& io = ImGui::GetIO(); (void)io; 51 | io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls 52 | io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls 53 | 54 | // Setup Dear ImGui style 55 | ImGui::StyleColorsDark(); 56 | //ImGui::StyleColorsLight(); 57 | 58 | // Setup Platform/Renderer backends 59 | ImGui_ImplWin32_Init(hwnd); 60 | ImGui_ImplDX11_Init(g_pd3dDevice, g_pd3dDeviceContext); 61 | 62 | 63 | } 64 | 65 | void ImGuiDebugger::render() 66 | { 67 | // Our state 68 | bool show_demo_window = true; 69 | bool show_another_window = false; 70 | ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f); 71 | ImGuiIO& io = ImGui::GetIO(); (void)io; 72 | 73 | // Main loop 74 | bool done = false; 75 | while (!done) 76 | { 77 | 78 | update(); 79 | 80 | // Poll and handle messages (inputs, window resize, etc.) 81 | // See the WndProc() function below for our to dispatch events to the Win32 backend. 82 | MSG msg; 83 | while (::PeekMessage(&msg, nullptr, 0U, 0U, PM_REMOVE)) 84 | { 85 | ::TranslateMessage(&msg); 86 | ::DispatchMessage(&msg); 87 | if (msg.message == WM_QUIT) 88 | done = true; 89 | } 90 | if (done) 91 | break; 92 | 93 | // Handle window being minimized or screen locked 94 | if (g_SwapChainOccluded && g_pSwapChain->Present(0, DXGI_PRESENT_TEST) == DXGI_STATUS_OCCLUDED) 95 | { 96 | ::Sleep(10); 97 | continue; 98 | } 99 | g_SwapChainOccluded = false; 100 | 101 | // Handle window resize (we don't resize directly in the WM_SIZE handler) 102 | if (g_ResizeWidth != 0 && g_ResizeHeight != 0) 103 | { 104 | CleanupRenderTarget(); 105 | g_pSwapChain->ResizeBuffers(0, g_ResizeWidth, g_ResizeHeight, DXGI_FORMAT_UNKNOWN, 0); 106 | g_ResizeWidth = g_ResizeHeight = 0; 107 | CreateRenderTarget(); 108 | } 109 | 110 | // Start the Dear ImGui frame 111 | ImGui_ImplDX11_NewFrame(); 112 | ImGui_ImplWin32_NewFrame(); 113 | ImGui::NewFrame(); 114 | 115 | // 1. Show the big demo window (Most of the sample code is in ImGui::ShowDemoWindow()! You can browse its code to learn more about Dear ImGui!). 116 | if (show_demo_window) 117 | ImGui::ShowDemoWindow(&show_demo_window); 118 | 119 | // 2. Show a simple window that we create ourselves. We use a Begin/End pair to create a named window. 120 | { 121 | static float f = 0.0f; 122 | static int counter = 0; 123 | 124 | ImGui::Begin("Hello, world!"); // Create a window called "Hello, world!" and append into it. 125 | 126 | ImGui::Text("This is some useful text."); // Display some text (you can use a format strings too) 127 | ImGui::Checkbox("Demo Window", &show_demo_window); // Edit bools storing our window open/close state 128 | ImGui::Checkbox("Another Window", &show_another_window); 129 | 130 | ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f 131 | ImGui::ColorEdit3("clear color", (float*)&clear_color); // Edit 3 floats representing a color 132 | 133 | if (ImGui::Button("Button")) // Buttons return true when clicked (most widgets return true when edited/activated) 134 | counter++; 135 | ImGui::SameLine(); 136 | ImGui::Text("counter = %d", counter); 137 | 138 | ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate); 139 | ImGui::End(); 140 | } 141 | 142 | // 3. Show another simple window. 143 | if (show_another_window) 144 | { 145 | ImGui::Begin("Another Window", &show_another_window); // Pass a pointer to our bool variable (the window will have a closing button that will clear the bool when clicked) 146 | ImGui::Text("Hello from another window!"); 147 | if (ImGui::Button("Close Me")) 148 | show_another_window = false; 149 | ImGui::End(); 150 | } 151 | 152 | // Rendering 153 | ImGui::Render(); 154 | const float clear_color_with_alpha[4] = { clear_color.x * clear_color.w, clear_color.y * clear_color.w, clear_color.z * clear_color.w, clear_color.w }; 155 | g_pd3dDeviceContext->OMSetRenderTargets(1, &g_mainRenderTargetView, nullptr); 156 | g_pd3dDeviceContext->ClearRenderTargetView(g_mainRenderTargetView, clear_color_with_alpha); 157 | ImGui_ImplDX11_RenderDrawData(ImGui::GetDrawData()); 158 | 159 | // Present 160 | HRESULT hr = g_pSwapChain->Present(1, 0); // Present with vsync 161 | //HRESULT hr = g_pSwapChain->Present(0, 0); // Present without vsync 162 | g_SwapChainOccluded = (hr == DXGI_STATUS_OCCLUDED); 163 | } 164 | 165 | // Cleanup 166 | ImGui_ImplDX11_Shutdown(); 167 | ImGui_ImplWin32_Shutdown(); 168 | ImGui::DestroyContext(); 169 | 170 | CleanupDeviceD3D(); 171 | ::DestroyWindow(debugWindow); 172 | // ::UnregisterClassW(wc.lpszClassName, wc.hInstance); 173 | 174 | return; 175 | } 176 | 177 | void ImGuiDebugger::update() 178 | { 179 | 180 | 181 | 182 | } 183 | 184 | 185 | bool CreateDeviceD3D(HWND hWnd) 186 | { 187 | // Setup swap chain 188 | DXGI_SWAP_CHAIN_DESC sd; 189 | ZeroMemory(&sd, sizeof(sd)); 190 | sd.BufferCount = 2; 191 | 192 | sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; 193 | sd.BufferDesc.RefreshRate.Numerator = 60; 194 | sd.BufferDesc.RefreshRate.Denominator = 1; 195 | sd.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH; 196 | sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; 197 | sd.OutputWindow = hWnd; 198 | sd.SampleDesc.Count = 1; 199 | sd.SampleDesc.Quality = 0; 200 | sd.Windowed = TRUE; 201 | sd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; 202 | 203 | RECT rc; 204 | GetClientRect(hWnd, &rc); 205 | sd.BufferDesc.Width = rc.right - rc.left; 206 | sd.BufferDesc.Height = rc.bottom - rc.top; 207 | 208 | UINT createDeviceFlags = 0; 209 | createDeviceFlags |= D3D11_CREATE_DEVICE_DEBUG; 210 | D3D_FEATURE_LEVEL featureLevel; 211 | const D3D_FEATURE_LEVEL featureLevelArray[2] = { D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_10_0, }; 212 | HRESULT res = D3D11CreateDeviceAndSwapChain(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, createDeviceFlags, featureLevelArray, 2, D3D11_SDK_VERSION, &sd, &g_pSwapChain, &g_pd3dDevice, &featureLevel, &g_pd3dDeviceContext); 213 | if (res == DXGI_ERROR_UNSUPPORTED) // Try high-performance WARP software driver if hardware is not available. 214 | res = D3D11CreateDeviceAndSwapChain(nullptr, D3D_DRIVER_TYPE_WARP, nullptr, createDeviceFlags, featureLevelArray, 2, D3D11_SDK_VERSION, &sd, &g_pSwapChain, &g_pd3dDevice, &featureLevel, &g_pd3dDeviceContext); 215 | if (res != S_OK) 216 | return false; 217 | 218 | CreateRenderTarget(); 219 | return true; 220 | } 221 | 222 | void CleanupDeviceD3D() 223 | { 224 | CleanupRenderTarget(); 225 | if (g_pSwapChain) { g_pSwapChain->Release(); g_pSwapChain = nullptr; } 226 | if (g_pd3dDeviceContext) { g_pd3dDeviceContext->Release(); g_pd3dDeviceContext = nullptr; } 227 | if (g_pd3dDevice) { g_pd3dDevice->Release(); g_pd3dDevice = nullptr; } 228 | } 229 | 230 | void CreateRenderTarget() 231 | { 232 | ID3D11Texture2D* pBackBuffer; 233 | g_pSwapChain->GetBuffer(0, IID_PPV_ARGS(&pBackBuffer)); 234 | g_pd3dDevice->CreateRenderTargetView(pBackBuffer, nullptr, &g_mainRenderTargetView); 235 | pBackBuffer->Release(); 236 | } 237 | 238 | void CleanupRenderTarget() 239 | { 240 | if (g_mainRenderTargetView) { g_mainRenderTargetView->Release(); g_mainRenderTargetView = nullptr; } 241 | } 242 | 243 | // Forward declare message handler from imgui_impl_win32.cpp 244 | extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); 245 | 246 | // Win32 message handler 247 | // You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs. 248 | // - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application, or clear/overwrite your copy of the mouse data. 249 | // - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application, or clear/overwrite your copy of the keyboard data. 250 | // Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags. 251 | LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) 252 | { 253 | if (ImGui_ImplWin32_WndProcHandler(hWnd, msg, wParam, lParam)) 254 | return true; 255 | 256 | switch (msg) 257 | { 258 | case WM_SIZE: 259 | if (wParam == SIZE_MINIMIZED) 260 | return 0; 261 | g_ResizeWidth = (UINT)LOWORD(lParam); // Queue resize 262 | g_ResizeHeight = (UINT)HIWORD(lParam); 263 | return 0; 264 | case WM_SYSCOMMAND: 265 | if ((wParam & 0xfff0) == SC_KEYMENU) // Disable ALT application menu 266 | return 0; 267 | break; 268 | case WM_DESTROY: 269 | ::PostQuitMessage(0); 270 | return 0; 271 | } 272 | return ::DefWindowProcW(hWnd, msg, wParam, lParam); 273 | } 274 | 275 | 276 | 277 | 278 | ImGuiDebugger* ImGuiDebugger::g_debugger; 279 | void ImGuiDebugger::initStatic() 280 | { 281 | g_debugger = new ImGuiDebugger(); 282 | } 283 | -------------------------------------------------------------------------------- /llvm360/Runtime/src/Graphics/ImGuiDebugger.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); 4 | 5 | //std::atomic g_continue = false; 6 | //std::atomic g_dBUpdating = false; 7 | //std::vector g_dBlist; 8 | 9 | class ImGuiDebugger { 10 | public: 11 | static void initStatic(); 12 | 13 | void initialize(); 14 | void render(); 15 | void update(); 16 | 17 | HWND debugWindow; 18 | //std::unordered_map dbInstrMap; 19 | static ImGuiDebugger* g_debugger; 20 | 21 | }; 22 | 23 | 24 | -------------------------------------------------------------------------------- /llvm360/Runtime/src/Graphics/ImGuiTest.h: -------------------------------------------------------------------------------- 1 | /*/ Dear ImGui: standalone example application for Win32 + OpenGL 3 2 | 3 | // Learn about Dear ImGui: 4 | // - FAQ https://dearimgui.com/faq 5 | // - Getting Started https://dearimgui.com/getting-started 6 | // - Documentation https://dearimgui.com/docs (same as your local docs/ folder). 7 | // - Introduction, links and more at the top of imgui.cpp 8 | 9 | // This is provided for completeness, however it is strongly recommended you use OpenGL with SDL or GLFW. 10 | 11 | #include "imgui.h" 12 | #include "imgui_impl_opengl3.h" 13 | #include "imgui_impl_win32.h" 14 | #ifndef WIN32_LEAN_AND_MEAN 15 | #define WIN32_LEAN_AND_MEAN 16 | #endif 17 | #include 18 | #include 19 | #include 20 | 21 | // Data stored per platform window 22 | struct WGL_WindowData { HDC hDC; }; 23 | 24 | // Data 25 | static HGLRC g_hRC; 26 | static WGL_WindowData g_MainWindow; 27 | static int g_Width; 28 | static int g_Height; 29 | 30 | // Forward declarations of helper functions 31 | bool CreateDeviceWGL(HWND hWnd, WGL_WindowData* data); 32 | void CleanupDeviceWGL(HWND hWnd, WGL_WindowData* data); 33 | void ResetDeviceWGL(); 34 | LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); 35 | 36 | // Main code 37 | int main(int, char**) 38 | { 39 | // Create application window 40 | //ImGui_ImplWin32_EnableDpiAwareness(); 41 | WNDCLASSEXW wc = { sizeof(wc), CS_OWNDC, WndProc, 0L, 0L, GetModuleHandle(nullptr), nullptr, nullptr, nullptr, nullptr, L"ImGui Example", nullptr }; 42 | ::RegisterClassExW(&wc); 43 | HWND hwnd = ::CreateWindowW(wc.lpszClassName, L"Dear ImGui Win32+OpenGL3 Example", WS_OVERLAPPEDWINDOW, 100, 100, 1280, 800, nullptr, nullptr, wc.hInstance, nullptr); 44 | 45 | // Initialize OpenGL 46 | if (!CreateDeviceWGL(hwnd, &g_MainWindow)) 47 | { 48 | CleanupDeviceWGL(hwnd, &g_MainWindow); 49 | ::DestroyWindow(hwnd); 50 | ::UnregisterClassW(wc.lpszClassName, wc.hInstance); 51 | return 1; 52 | } 53 | wglMakeCurrent(g_MainWindow.hDC, g_hRC); 54 | 55 | // Show the window 56 | ::ShowWindow(hwnd, SW_SHOWDEFAULT); 57 | ::UpdateWindow(hwnd); 58 | 59 | // Setup Dear ImGui context 60 | IMGUI_CHECKVERSION(); 61 | ImGui::CreateContext(); 62 | ImGuiIO& io = ImGui::GetIO(); (void)io; 63 | io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls 64 | io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls 65 | 66 | // Setup Dear ImGui style 67 | ImGui::StyleColorsDark(); 68 | //ImGui::StyleColorsClassic(); 69 | 70 | // Setup Platform/Renderer backends 71 | ImGui_ImplWin32_InitForOpenGL(hwnd); 72 | ImGui_ImplOpenGL3_Init(); 73 | 74 | 75 | 76 | // Our state 77 | bool show_demo_window = true; 78 | bool show_another_window = false; 79 | ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f); 80 | 81 | // Main loop 82 | bool done = false; 83 | while (!done) 84 | { 85 | // Poll and handle messages (inputs, window resize, etc.) 86 | // See the WndProc() function below for our to dispatch events to the Win32 backend. 87 | MSG msg; 88 | while (::PeekMessage(&msg, nullptr, 0U, 0U, PM_REMOVE)) 89 | { 90 | ::TranslateMessage(&msg); 91 | ::DispatchMessage(&msg); 92 | if (msg.message == WM_QUIT) 93 | done = true; 94 | } 95 | if (done) 96 | break; 97 | if (::IsIconic(hwnd)) 98 | { 99 | ::Sleep(10); 100 | continue; 101 | } 102 | 103 | // Start the Dear ImGui frame 104 | ImGui_ImplOpenGL3_NewFrame(); 105 | ImGui_ImplWin32_NewFrame(); 106 | ImGui::NewFrame(); 107 | 108 | // 1. Show the big demo window (Most of the sample code is in ImGui::ShowDemoWindow()! You can browse its code to learn more about Dear ImGui!). 109 | if (show_demo_window) 110 | ImGui::ShowDemoWindow(&show_demo_window); 111 | 112 | // 2. Show a simple window that we create ourselves. We use a Begin/End pair to create a named window. 113 | { 114 | static float f = 0.0f; 115 | static int counter = 0; 116 | 117 | ImGui::Begin("Hello, world!"); // Create a window called "Hello, world!" and append into it. 118 | 119 | ImGui::Text("This is some useful text."); // Display some text (you can use a format strings too) 120 | ImGui::Checkbox("Demo Window", &show_demo_window); // Edit bools storing our window open/close state 121 | ImGui::Checkbox("Another Window", &show_another_window); 122 | 123 | ImGui::SliderFloat("float", &f, 0.0f, 1.0f); // Edit 1 float using a slider from 0.0f to 1.0f 124 | ImGui::ColorEdit3("clear color", (float*)&clear_color); // Edit 3 floats representing a color 125 | 126 | if (ImGui::Button("Button")) // Buttons return true when clicked (most widgets return true when edited/activated) 127 | counter++; 128 | ImGui::SameLine(); 129 | ImGui::Text("counter = %d", counter); 130 | 131 | ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate); 132 | ImGui::End(); 133 | } 134 | 135 | // 3. Show another simple window. 136 | if (show_another_window) 137 | { 138 | ImGui::Begin("Another Window", &show_another_window); // Pass a pointer to our bool variable (the window will have a closing button that will clear the bool when clicked) 139 | ImGui::Text("Hello from another window!"); 140 | if (ImGui::Button("Close Me")) 141 | show_another_window = false; 142 | ImGui::End(); 143 | } 144 | 145 | // Rendering 146 | ImGui::Render(); 147 | glViewport(0, 0, g_Width, g_Height); 148 | glClearColor(clear_color.x, clear_color.y, clear_color.z, clear_color.w); 149 | glClear(GL_COLOR_BUFFER_BIT); 150 | ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); 151 | 152 | // Present 153 | ::SwapBuffers(g_MainWindow.hDC); 154 | } 155 | 156 | ImGui_ImplOpenGL3_Shutdown(); 157 | ImGui_ImplWin32_Shutdown(); 158 | ImGui::DestroyContext(); 159 | 160 | CleanupDeviceWGL(hwnd, &g_MainWindow); 161 | wglDeleteContext(g_hRC); 162 | ::DestroyWindow(hwnd); 163 | ::UnregisterClassW(wc.lpszClassName, wc.hInstance); 164 | 165 | return 0; 166 | } 167 | 168 | // Helper functions 169 | bool CreateDeviceWGL(HWND hWnd, WGL_WindowData* data) 170 | { 171 | HDC hDc = ::GetDC(hWnd); 172 | PIXELFORMATDESCRIPTOR pfd = { 0 }; 173 | pfd.nSize = sizeof(pfd); 174 | pfd.nVersion = 1; 175 | pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; 176 | pfd.iPixelType = PFD_TYPE_RGBA; 177 | pfd.cColorBits = 32; 178 | 179 | const int pf = ::ChoosePixelFormat(hDc, &pfd); 180 | if (pf == 0) 181 | return false; 182 | if (::SetPixelFormat(hDc, pf, &pfd) == FALSE) 183 | return false; 184 | ::ReleaseDC(hWnd, hDc); 185 | 186 | data->hDC = ::GetDC(hWnd); 187 | if (!g_hRC) 188 | g_hRC = wglCreateContext(data->hDC); 189 | return true; 190 | } 191 | 192 | void CleanupDeviceWGL(HWND hWnd, WGL_WindowData* data) 193 | { 194 | wglMakeCurrent(nullptr, nullptr); 195 | ::ReleaseDC(hWnd, data->hDC); 196 | } 197 | 198 | // Forward declare message handler from imgui_impl_win32.cpp 199 | extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); 200 | 201 | // Win32 message handler 202 | // You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs. 203 | // - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application, or clear/overwrite your copy of the mouse data. 204 | // - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application, or clear/overwrite your copy of the keyboard data. 205 | // Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags. 206 | LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) 207 | { 208 | if (ImGui_ImplWin32_WndProcHandler(hWnd, msg, wParam, lParam)) 209 | return true; 210 | 211 | switch (msg) 212 | { 213 | case WM_SIZE: 214 | if (wParam != SIZE_MINIMIZED) 215 | { 216 | g_Width = LOWORD(lParam); 217 | g_Height = HIWORD(lParam); 218 | } 219 | return 0; 220 | case WM_SYSCOMMAND: 221 | if ((wParam & 0xfff0) == SC_KEYMENU) // Disable ALT application menu 222 | return 0; 223 | break; 224 | case WM_DESTROY: 225 | ::PostQuitMessage(0); 226 | return 0; 227 | } 228 | return ::DefWindowProcW(hWnd, msg, wParam, lParam); 229 | }*/ -------------------------------------------------------------------------------- /llvm360/Runtime/src/Runtime/Kernel/XKernel.cpp: -------------------------------------------------------------------------------- 1 | #include "XKernel.h" 2 | #include "../../pch.h" -------------------------------------------------------------------------------- /llvm360/Runtime/src/Runtime/Kernel/XKernel.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | class KeObj 4 | { 5 | //uint32_t obj_id; 6 | }; -------------------------------------------------------------------------------- /llvm360/Runtime/src/Runtime/Kernel/XeThread.cpp: -------------------------------------------------------------------------------- 1 | #include "XeThread.h" 2 | -------------------------------------------------------------------------------- /llvm360/Runtime/src/Runtime/Kernel/XeThread.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "XKernel.h" 3 | 4 | class XeThread : KeObj 5 | { 6 | private: 7 | std::thread actual_thread; 8 | uint32_t thread_id; 9 | }; -------------------------------------------------------------------------------- /llvm360/Runtime/src/Runtime/MemoryManager.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #define TOTALSIZE 0x100000000 10 | 11 | 12 | class XAlloc 13 | { 14 | public: 15 | XAlloc() { 16 | 17 | 18 | base = VirtualAlloc((void*)0x100000000, TOTALSIZE, MEM_RESERVE, PAGE_NOACCESS); 19 | if (!base) 20 | { 21 | base = VirtualAlloc(nullptr, TOTALSIZE, MEM_RESERVE, PAGE_NOACCESS); 22 | } 23 | if (!base) 24 | { 25 | throw std::runtime_error("Failed to reserve memory"); 26 | } 27 | 28 | 29 | *XRuntime::g_runtime->g_moduleBase = reinterpret_cast(base); 30 | // Initially, the entire reserved region is free. 31 | freeBlocks.push_back({ 0, TOTALSIZE }); 32 | } 33 | 34 | 35 | void* allocate(size_t preferredOffset, size_t size, uint32_t allocFlags, uint32_t protFlags) 36 | { 37 | size = alignSize(size); 38 | size_t allocOffset = 0; 39 | bool found = false; 40 | 41 | 42 | if (preferredOffset != NULL) 43 | { 44 | for (auto it = freeBlocks.begin(); it != freeBlocks.end(); ++it) 45 | { 46 | if (it->offset <= preferredOffset && (it->offset + it->size) >= (preferredOffset + size)) 47 | { 48 | allocOffset = preferredOffset; 49 | splitFreeBlock(it, allocOffset, size); 50 | found = true; 51 | break; 52 | } 53 | } 54 | } 55 | 56 | if (!found) { 57 | for (auto it = freeBlocks.begin(); it != freeBlocks.end(); ++it) 58 | { 59 | if (it->size >= size) 60 | { 61 | allocOffset = it->offset; 62 | splitFreeBlock(it, allocOffset, size); 63 | found = true; 64 | break; 65 | } 66 | } 67 | } 68 | if (!found) 69 | { 70 | return nullptr; 71 | } 72 | 73 | void* addr = reinterpret_cast(reinterpret_cast(base) + allocOffset); 74 | void* result = VirtualAlloc(addr, size, MEM_COMMIT | allocFlags, protFlags); 75 | if (!result) 76 | { 77 | throw std::runtime_error("VirtualAlloc commit failed"); 78 | } 79 | return result; 80 | } 81 | 82 | 83 | void free(void* ptr, size_t size) 84 | { 85 | size = alignSize(size); 86 | size_t offset = reinterpret_cast(ptr) - reinterpret_cast(base); 87 | // Decommit the pages. 88 | if (!VirtualFree(ptr, size, MEM_DECOMMIT)) 89 | { 90 | throw std::runtime_error("VirtualFree decommit failed"); 91 | } 92 | 93 | freeBlocks.push_back({ offset, size }); 94 | mergeFreeBlocks(); 95 | } 96 | 97 | void write64To(uint32_t guest, uint64_t val) { *(uint64_t*)((uint64_t)base + guest) = BeField(val).value; } 98 | void write32To(uint32_t guest, uint32_t val) { *(uint64_t*)((uint64_t)base + guest) = BeField(val).value; } 99 | void write16To(uint32_t guest, uint16_t val) { *(uint64_t*)((uint64_t)base + guest) = BeField(val).value; } 100 | void write8To(uint32_t guest, uint8_t val) { *(uint64_t*)((uint64_t)base + guest) = BeField(val).value; } 101 | 102 | uint64_t read64From(uint32_t guest) { return BeField((uint64_t)(*(uint64_t*)((uint64_t)base + guest))).value; } 103 | uint32_t read32From(uint32_t guest) { return BeField((uint32_t)(*(uint64_t*)((uint64_t)base + guest))).value; } 104 | uint16_t read16From(uint32_t guest) { return BeField((uint16_t)(*(uint64_t*)((uint64_t)base + guest))).value; } 105 | uint8_t read8From(uint32_t guest) { return BeField((uint8_t)(*(uint64_t*)((uint64_t)base + guest))).value; } 106 | 107 | uint32_t makeHostGuest(void* host) { return (uint64_t)host - (uint64_t)base; } 108 | void* makeGuestHost(uint32_t guest) { return (void*)((uint64_t)base + guest); } 109 | 110 | 111 | ~XAlloc() 112 | { 113 | if (base) 114 | { 115 | VirtualFree(base, 0, MEM_RELEASE); 116 | } 117 | } 118 | 119 | private: 120 | 121 | struct FreeBlock 122 | { 123 | size_t offset; 124 | size_t size; 125 | }; 126 | 127 | std::vector freeBlocks; 128 | void* base = nullptr; 129 | const size_t pageSize = 4096; 130 | 131 | 132 | size_t alignSize(size_t size) 133 | { 134 | return (size + pageSize - 1) & ~(pageSize - 1); 135 | } 136 | 137 | 138 | void splitFreeBlock(std::vector::iterator it, size_t allocOffset, size_t allocSize) 139 | { 140 | FreeBlock block = *it; 141 | freeBlocks.erase(it); 142 | 143 | if (allocOffset > block.offset) 144 | { 145 | freeBlocks.push_back({ block.offset, allocOffset - block.offset }); 146 | } 147 | 148 | size_t endAlloc = allocOffset + allocSize; 149 | size_t blockEnd = block.offset + block.size; 150 | if (endAlloc < blockEnd) 151 | { 152 | freeBlocks.push_back({ endAlloc, blockEnd - endAlloc }); 153 | } 154 | mergeFreeBlocks(); 155 | } 156 | 157 | 158 | void mergeFreeBlocks() 159 | { 160 | std::sort(freeBlocks.begin(), freeBlocks.end(), [](const FreeBlock& a, const FreeBlock& b) 161 | { 162 | return a.offset < b.offset; 163 | }); 164 | std::vector merged; 165 | for (const auto& block : freeBlocks) 166 | { 167 | if (!merged.empty() && (merged.back().offset + merged.back().size == block.offset)) 168 | { 169 | merged.back().size += block.size; 170 | } 171 | else 172 | { 173 | merged.push_back(block); 174 | } 175 | } 176 | freeBlocks = std::move(merged); 177 | } 178 | }; -------------------------------------------------------------------------------- /llvm360/Runtime/src/Runtime/Runtime.cpp: -------------------------------------------------------------------------------- 1 | #include "Runtime.h" 2 | #include "../pch.h" 3 | #include "MemoryManager.h" 4 | 5 | 6 | void initMainThread(XRuntime* run) 7 | { 8 | 9 | if (run->g_initTLS) 10 | { 11 | // Allocate 512 kb for the main thread stack 12 | constexpr size_t stackSize = 512 * 1024; 13 | void* ptr = run->m_memory->allocate(0, stackSize, 0, PAGE_READWRITE); 14 | run->mainStack = (uint8_t*)ptr; 15 | if (!run->mainStack) 16 | { 17 | std::cerr << "Failed to allocate stack memory\n"; 18 | return; 19 | } 20 | run->mainThreadState = new XenonState(); 21 | run->mainThreadState->LR = 0x3242; 22 | uintptr_t alignedStack = reinterpret_cast(run->mainStack) + stackSize; 23 | alignedStack &= ~0xF; // align 24 | run->mainThreadState->RR[1] = run->m_memory->makeHostGuest((void*)alignedStack); 25 | *run->g_initTLS() = run->mainThreadState; 26 | printf("MainThread allocation done\n"); 27 | } 28 | } 29 | 30 | #define MD_VER 4 31 | 32 | void XRuntime::importMetadata(const char* path) 33 | { 34 | std::ifstream ifs(path, std::ios::binary); 35 | if (!ifs.is_open()) { 36 | printf("Error opening file for reading\n"); 37 | return; 38 | } 39 | 40 | EXPMD_Header header; 41 | ifs.read(reinterpret_cast(&header.magic), sizeof(uint32_t)); 42 | ifs.read(reinterpret_cast(&header.version), sizeof(uint32_t)); 43 | ifs.read(reinterpret_cast(&header.flags), sizeof(uint32_t)); 44 | ifs.read(reinterpret_cast(&header.baseAddress), sizeof(uint32_t)); 45 | ifs.read(reinterpret_cast(&header.numSections), sizeof(uint32_t)); 46 | header.sections = new EXPMD_Section * [header.numSections]; 47 | ifs.read(reinterpret_cast(&header.num_impVars), sizeof(uint32_t)); 48 | header.imp_Vars = new EXPMD_IMPVar * [header.num_impVars]; 49 | 50 | if (header.magic != 0x54535338) 51 | { 52 | printf("Invalid metadata file\n"); 53 | return; 54 | } 55 | 56 | if (header.version != MD_VER) 57 | { 58 | printf("Invalid metadata file\n"); 59 | return; 60 | } 61 | 62 | for (size_t i = 0; i < header.num_impVars; i++) 63 | { 64 | EXPMD_IMPVar* impVar = new EXPMD_IMPVar; 65 | uint32_t nameLength; 66 | ifs.read(reinterpret_cast(&nameLength), sizeof(uint32_t)); 67 | impVar->name.resize(nameLength); 68 | ifs.read(&impVar->name[0], nameLength); 69 | ifs.read(reinterpret_cast(&impVar->addr), sizeof(uint32_t)); 70 | header.imp_Vars[i] = impVar; 71 | } 72 | 73 | 74 | for (size_t i = 0; i < header.numSections; i++) 75 | { 76 | EXPMD_Section* sec = new EXPMD_Section; 77 | ifs.read(reinterpret_cast(&sec->dat_offset), sizeof(uint32_t)); 78 | ifs.read(reinterpret_cast(&sec->size), sizeof(uint32_t)); 79 | ifs.read(reinterpret_cast(&sec->flags), sizeof(uint32_t)); 80 | uint32_t nameLength; 81 | ifs.read(reinterpret_cast(&nameLength), sizeof(uint32_t)); 82 | sec->sec_name.resize(nameLength); 83 | ifs.read(&sec->sec_name[0], nameLength); 84 | sec->data = new uint8_t[sec->size]; 85 | ifs.read(reinterpret_cast(sec->data), sec->size); 86 | header.sections[i] = sec; 87 | } 88 | 89 | // copy the data in the &header to m_metadata otherwise it will be stripped 90 | m_metadata = new EXPMD_Header; 91 | *m_metadata = header; 92 | } 93 | void XRuntime::allocateSectionsData() 94 | { 95 | if (!m_metadata) 96 | { 97 | printf("No metadata found\n"); 98 | return; 99 | } 100 | 101 | size_t allocationSize = 0; 102 | 103 | for (size_t i = 0; i < m_metadata->numSections; i++) 104 | { 105 | if (i == 0) 106 | { 107 | allocationSize = m_metadata->sections[i]->dat_offset; 108 | continue; 109 | } 110 | 111 | if (m_metadata->sections[i]->dat_offset > m_metadata->sections[i - 1]->dat_offset) 112 | { 113 | allocationSize = m_metadata->sections[i]->dat_offset; 114 | } 115 | } 116 | 117 | void* baseAddr = m_memory->allocate(m_metadata->baseAddress, allocationSize, 0, PAGE_READWRITE); 118 | if (!baseAddr) 119 | { 120 | printf("Failed to reserve memory\n"); 121 | return; 122 | } 123 | 124 | for (size_t i = 0; i < m_metadata->numSections; i++) 125 | { 126 | EXPMD_Section* sec = m_metadata->sections[i]; 127 | memcpy((void*)((uint64_t)baseAddr + sec->dat_offset), sec->data, sec->size); 128 | printf("Allocated section memory at %08llX\n", (uint32_t)m_metadata->baseAddress + sec->dat_offset); 129 | } 130 | } 131 | 132 | EXPMD_IMPVar* XRuntime::getImpByName(const char* name) 133 | { 134 | for (size_t i = 0; i < m_metadata->num_impVars; i++) 135 | { 136 | EXPMD_IMPVar* var = m_metadata->imp_Vars[i]; 137 | if (strcmp(var->name.c_str(), name) == 0) 138 | { 139 | return var; 140 | } 141 | } 142 | printf("No import with name [%s] found\n", name); 143 | return nullptr; 144 | } 145 | 146 | 147 | uint32_t m_nativeXexExecutableModuleHandle; 148 | uint32_t m_nativeXexExecutableModuleHandlePtr; 149 | 150 | uint32_t m_nativeXboxHardwareInfo; 151 | 152 | 153 | void XRuntime::initImpVars() 154 | { 155 | EXPMD_IMPVar* var = getImpByName("XexExecutableModuleHandle"); 156 | if(var != nullptr) 157 | { 158 | m_nativeXexExecutableModuleHandle = m_memory->makeHostGuest(m_memory->allocate(0, 2048, 0, PAGE_READWRITE)); 159 | m_nativeXexExecutableModuleHandlePtr = m_memory->makeHostGuest(m_memory->allocate(0, 4, 0, PAGE_READWRITE)); 160 | m_memory->write32To(var->addr, m_nativeXexExecutableModuleHandlePtr); 161 | m_memory->write32To(m_nativeXexExecutableModuleHandlePtr, m_nativeXexExecutableModuleHandle); 162 | m_memory->write32To(m_nativeXexExecutableModuleHandle, 0x4000000); 163 | m_memory->write32To(m_nativeXexExecutableModuleHandle + 0x58, 0x80101100); 164 | } 165 | 166 | var = getImpByName("XboxHardwareInfo"); 167 | if (var != nullptr) 168 | { 169 | // setup basics - XboxHardwareInfo 170 | m_nativeXboxHardwareInfo = m_memory->makeHostGuest(m_memory->allocate(0, 16, 0, PAGE_READWRITE)); 171 | m_memory->write32To(var->addr, m_nativeXboxHardwareInfo); 172 | m_memory->write32To(m_nativeXboxHardwareInfo, 0x00000000); // flags 173 | m_memory->write32To(m_nativeXboxHardwareInfo + 0x4, 0x6); // num cpus 174 | } 175 | } 176 | 177 | void XRuntime::init() 178 | { 179 | g_exeModule = GetModuleHandleW(NULL); 180 | if (g_exeModule) 181 | { 182 | g_initTLS = (getXCtxAddressFunc)GetProcAddress(g_exeModule, "getXCtxAddress"); 183 | exportedArray = (X_Function*)GetProcAddress(g_exeModule, "X_FunctionArray"); 184 | exportedCount = (int*)GetProcAddress(g_exeModule, "X_FunctionArrayCount"); 185 | g_moduleBase = (uint64_t*)GetProcAddress(g_exeModule, "moduleBase"); 186 | } 187 | m_memory = new XAlloc(); 188 | importMetadata("MD.tss"); 189 | allocateSectionsData(); 190 | initImpVars(); 191 | initMainThread(this); 192 | 193 | //m_graphics = new Graphics(); 194 | //m_graphics->initGraphics(); 195 | } 196 | 197 | 198 | XRuntime* XRuntime::g_runtime; 199 | void XRuntime::initGlobal() 200 | { 201 | g_runtime = new XRuntime(); 202 | } 203 | -------------------------------------------------------------------------------- /llvm360/Runtime/src/Runtime/Runtime.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include "../Graphics/ImGuiDebugger.h" 13 | 14 | class XAlloc; 15 | 16 | typedef struct { 17 | uint32_t xexAddress; 18 | void* funcPtr; 19 | } X_Function; 20 | 21 | struct Instruction { 22 | uint32_t address; 23 | uint32_t instrWord; 24 | std::string opcName; 25 | std::vector ops; 26 | 27 | inline operator std::string() { 28 | return opcName; 29 | } 30 | }; 31 | 32 | struct XenonState { 33 | uint64_t LR; 34 | uint64_t CTR; 35 | uint64_t MSR; 36 | uint64_t XER; 37 | uint32_t CR; 38 | uint64_t RR[32]; 39 | double FR[32]; 40 | 41 | uint64_t gpr(uint32_t reg) { 42 | return RR[reg]; 43 | } 44 | void setGpr(uint32_t reg, uint64_t val) { 45 | RR[reg] = val; 46 | } 47 | }; 48 | 49 | struct EXPMD_IMPVar 50 | { 51 | std::string name; 52 | uint32_t addr; 53 | }; 54 | 55 | struct EXPMD_Section 56 | { 57 | uint32_t dat_offset; 58 | uint32_t size; 59 | uint32_t flags; 60 | std::string sec_name; 61 | uint8_t* data; 62 | }; 63 | 64 | struct EXPMD_Header 65 | { 66 | uint32_t magic; 67 | uint32_t version; 68 | uint32_t flags; 69 | uint32_t baseAddress; 70 | uint32_t num_impVars; 71 | EXPMD_IMPVar** imp_Vars; 72 | uint32_t numSections; 73 | EXPMD_Section** sections; 74 | }; 75 | 76 | 77 | void deserialize(const std::string& filename, std::unordered_map& map) 78 | { 79 | std::ifstream ifs(filename, std::ios::binary); 80 | if (!ifs.is_open()) { 81 | printf("Error opening file for reading\n"); 82 | return; 83 | } 84 | 85 | while (ifs.peek() != EOF) 86 | { 87 | Instruction inst; 88 | 89 | // address and instrWord 90 | ifs.read(reinterpret_cast(&inst.address), sizeof(inst.address)); 91 | ifs.read(reinterpret_cast(&inst.instrWord), sizeof(inst.instrWord)); 92 | 93 | // opcName 94 | uint32_t nameLength; 95 | ifs.read(reinterpret_cast(&nameLength), sizeof(nameLength)); 96 | inst.opcName.resize(nameLength); 97 | ifs.read(&inst.opcName[0], nameLength + 1); 98 | 99 | // ops vector 100 | uint32_t opsSize; 101 | ifs.read(reinterpret_cast(&opsSize), sizeof(opsSize)); 102 | inst.ops.resize(opsSize); 103 | if (opsSize > 0) { 104 | ifs.read(reinterpret_cast(inst.ops.data()), opsSize * sizeof(uint32_t)); 105 | } 106 | 107 | map[inst.address] = inst; 108 | } 109 | 110 | ifs.close(); 111 | printf("Deserialization completed successfully.\n"); 112 | } 113 | 114 | std::mutex g_mutex; 115 | 116 | 117 | 118 | class XRuntime 119 | { 120 | public: 121 | void init(); 122 | void importMetadata(const char* path); 123 | void allocateSectionsData(); 124 | void initImpVars(); 125 | EXPMD_IMPVar* getImpByName(const char* name); 126 | 127 | typedef XenonState** (__cdecl* getXCtxAddressFunc)(); 128 | getXCtxAddressFunc g_initTLS; 129 | HMODULE g_exeModule; 130 | EXPMD_Header* m_metadata; 131 | 132 | 133 | XenonState* mainThreadState; 134 | uint8_t* mainStack; 135 | //X_LDR_DATA_TABLE_ENTRY* xex_module; 136 | 137 | X_Function* exportedArray; 138 | int* exportedCount; 139 | bool debuggerEnabled; 140 | uint64_t* g_moduleBase; 141 | 142 | //Graphics* m_graphics; 143 | XAlloc* m_memory; 144 | static XRuntime* g_runtime; 145 | static void initGlobal(); 146 | }; 147 | 148 | -------------------------------------------------------------------------------- /llvm360/Runtime/src/Runtime/Xen/Xam_Entry.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "XenUtils.h" 3 | #include "Xam_Impl.h" 4 | #include "../Runtime.h" 5 | 6 | 7 | extern "C" 8 | { 9 | DLL_API void XamLoaderTerminateTitle(XenonState* ctx, uint32_t lr) 10 | { 11 | XamLoaderTerminateTitle_X(); 12 | return; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /llvm360/Runtime/src/Runtime/Xen/Xam_Impl.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "XenUtils.h" 3 | 4 | void XamLoaderTerminateTitle_X() 5 | { 6 | X_LOG(X_WARNING, "{XamLoaderTerminateTitle} is stubbed"); 7 | return; 8 | } -------------------------------------------------------------------------------- /llvm360/Runtime/src/Runtime/Xen/XboxKrnl_Entry.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "XenUtils.h" 3 | #include "XboxKrnl_Impl.h" 4 | #include "../MemoryManager.h" 5 | 6 | 7 | extern "C" 8 | { 9 | DLL_API void RtlInitAnsiString(XenonState* ctx, uint32_t lr) 10 | { 11 | X_ANSI_STRING* ansiStr = (X_ANSI_STRING*)XRuntime::g_runtime->m_memory->makeGuestHost(ctx->gpr(3)); 12 | char* str = (char*)XRuntime::g_runtime->m_memory->makeGuestHost(ctx->gpr(4)); 13 | RtlInitAnsiString_X(ansiStr, str); 14 | return; 15 | } 16 | 17 | DLL_API void DbgPrint(XenonState* ctx, uint32_t lr) 18 | { 19 | DbgPrint_X(); 20 | return; 21 | } 22 | 23 | DLL_API void HalReturnToFirmware(XenonState* ctx, uint32_t lr) 24 | { 25 | uint32_t rout = (uint32_t)ctx->gpr(3); 26 | HalReturnToFirmware_X(rout); 27 | return; 28 | } 29 | 30 | 31 | 32 | 33 | DLL_API void RtlEnterCriticalSection(XenonState* ctx, uint32_t lr) 34 | { 35 | X_LOG(X_INFO, "{RtlEnterCriticalSection}"); 36 | ctx->setGpr(3, RtlEnterCriticalSection_X((XCRITICAL_SECTION*)XRuntime::g_runtime->m_memory->makeGuestHost(ctx->gpr(3)))); 37 | } 38 | DLL_API void RtlLeaveCriticalSection(XenonState* ctx, uint32_t lr) 39 | { 40 | X_LOG(X_INFO, "{RtlLeaveCriticalSection} "); 41 | } 42 | DLL_API void XexCheckExecutablePrivilege(XenonState* ctx, uint32_t lr) 43 | { 44 | X_LOG(X_INFO, "{XexCheckExecutablePrivilege} "); 45 | } 46 | DLL_API void XGetAVPack(XenonState* ctx, uint32_t lr) 47 | { 48 | X_LOG(X_INFO, "{XGetAVPack} "); 49 | } 50 | DLL_API void ExGetXConfigSetting(XenonState* ctx, uint32_t lr) 51 | { 52 | X_LOG(X_INFO, "{ExGetXConfigSetting} "); 53 | } 54 | DLL_API void KeTlsAlloc(XenonState* ctx, uint32_t lr) 55 | { 56 | X_LOG(X_INFO, "{KeTlsAlloc} "); 57 | } 58 | DLL_API void KeTlsSetValue(XenonState* ctx, uint32_t lr) 59 | { 60 | X_LOG(X_INFO, "{KeTlsSetValue} "); 61 | ctx->setGpr(3, 1); 62 | } 63 | DLL_API void RtlInitUnicodeString(XenonState* ctx, uint32_t lr) 64 | { 65 | X_LOG(X_INFO, "{RtlInitUnicodeString} "); 66 | } 67 | DLL_API void RtlUnicodeStringToAnsiString(XenonState* ctx, uint32_t lr) 68 | { 69 | X_LOG(X_INFO, "{RtlUnicodeStringToAnsiString} "); 70 | } 71 | DLL_API void RtlFreeAnsiString(XenonState* ctx, uint32_t lr) 72 | { 73 | X_LOG(X_INFO, "{RtlFreeAnsiString} "); 74 | } 75 | DLL_API void RtlNtStatusToDosError(XenonState* ctx, uint32_t lr) 76 | { 77 | X_LOG(X_INFO, "{RtlNtStatusToDosError} "); 78 | } 79 | 80 | DLL_API void NtAllocateVirtualMemory(XenonState* ctx, uint32_t lr) 81 | { 82 | X_LOG(X_INFO, "{NtAllocateVirtualMemory} "); 83 | ctx->setGpr(3, NtAllocateVirtualMemory_X((uint32_t*)XRuntime::g_runtime->m_memory->makeGuestHost(ctx->gpr(3)), 84 | (uint32_t*)XRuntime::g_runtime->m_memory->makeGuestHost(ctx->gpr(4)), 85 | (uint32_t)ctx->gpr(5), 86 | (uint32_t)ctx->gpr(6))); 87 | } 88 | 89 | 90 | DLL_API void NtFreeVirtualMemory(XenonState* ctx, uint32_t lr) 91 | { 92 | X_LOG(X_INFO, "{NtFreeVirtualMemory} "); 93 | } 94 | DLL_API void RtlCompareMemoryUlong(XenonState* ctx, uint32_t lr) 95 | { 96 | X_LOG(X_INFO, "{RtlCompareMemoryUlong} "); 97 | } 98 | DLL_API void XGetGameRegion(XenonState* ctx, uint32_t lr) 99 | { 100 | X_LOG(X_INFO, "{XGetGameRegion} "); 101 | } 102 | DLL_API void NtCreateEvent(XenonState* ctx, uint32_t lr) 103 | { 104 | X_LOG(X_INFO, "{NtCreateEvent} "); 105 | } 106 | DLL_API void XamShowMessageBoxUIEx(XenonState* ctx, uint32_t lr) 107 | { 108 | X_LOG(X_INFO, "{XamShowMessageBoxUIEx} "); 109 | } 110 | DLL_API void NtClose(XenonState* ctx, uint32_t lr) 111 | { 112 | X_LOG(X_INFO, "{NtClose} "); 113 | } 114 | DLL_API void RtlImageXexHeaderField(XenonState* ctx, uint32_t lr) 115 | { 116 | X_LOG(X_INFO, "{RtlImageXexHeaderField} "); 117 | ctx->setGpr(3, 0); 118 | } 119 | DLL_API void KeGetCurrentProcessType(XenonState* ctx, uint32_t lr) 120 | { 121 | X_LOG(X_INFO, "{KeGetCurrentProcessType} "); 122 | ctx->setGpr(3, KeGetCurrentProcessType_X()); 123 | } 124 | DLL_API void NtQueryVirtualMemory(XenonState* ctx, uint32_t lr) 125 | { 126 | X_LOG(X_INFO, "{NtQueryVirtualMemory} "); 127 | } 128 | DLL_API void RtlInitializeCriticalSection(XenonState* ctx, uint32_t lr) 129 | { 130 | X_LOG(X_INFO, "{RtlInitializeCriticalSection} "); 131 | RtlInitializeCriticalSection_X((XCRITICAL_SECTION*)XRuntime::g_runtime->m_memory->makeGuestHost(ctx->gpr(3))); 132 | } 133 | DLL_API void KeTlsFree(XenonState* ctx, uint32_t lr) 134 | { 135 | X_LOG(X_INFO, "{KeTlsFree} "); 136 | } 137 | DLL_API void KeBugCheckEx(XenonState* ctx, uint32_t lr) 138 | { 139 | X_LOG(X_INFO, "{KeBugCheckEx} "); 140 | } 141 | DLL_API void NtWaitForSingleObjectEx(XenonState* ctx, uint32_t lr) 142 | { 143 | X_LOG(X_INFO, "{NtWaitForSingleObjectEx} "); 144 | } 145 | DLL_API void KeBugCheck(XenonState* ctx, uint32_t lr) 146 | { 147 | X_LOG(X_INFO, "{KeBugCheck} "); 148 | } 149 | DLL_API void KeTlsGetValue(XenonState* ctx, uint32_t lr) 150 | { 151 | X_LOG(X_INFO, "{KeTlsGetValue} "); 152 | } 153 | DLL_API void NtWriteFile(XenonState* ctx, uint32_t lr) 154 | { 155 | X_LOG(X_INFO, "{NtWriteFile} "); 156 | } 157 | DLL_API void RtlInitializeCriticalSectionAndSpinCount(XenonState* ctx, uint32_t lr) 158 | { 159 | X_LOG(X_INFO, "{RtlInitializeCriticalSectionAndSpinCount} "); 160 | } 161 | DLL_API void NtFlushBuffersFile(XenonState* ctx, uint32_t lr) 162 | { 163 | X_LOG(X_INFO, "{NtFlushBuffersFile} "); 164 | } 165 | DLL_API void NtDuplicateObject(XenonState* ctx, uint32_t lr) 166 | { 167 | X_LOG(X_INFO, "{NtDuplicateObject} "); 168 | } 169 | DLL_API void NtQueryDirectoryFile(XenonState* ctx, uint32_t lr) 170 | { 171 | X_LOG(X_INFO, "{NtQueryDirectoryFile} "); 172 | } 173 | DLL_API void NtOpenFile(XenonState* ctx, uint32_t lr) 174 | { 175 | X_LOG(X_INFO, "{NtOpenFile} "); 176 | } 177 | DLL_API void NtReadFileScatter(XenonState* ctx, uint32_t lr) 178 | { 179 | X_LOG(X_INFO, "{NtReadFileScatter} "); 180 | } 181 | DLL_API void NtSetInformationFile(XenonState* ctx, uint32_t lr) 182 | { 183 | X_LOG(X_INFO, "{NtSetInformationFile} "); 184 | } 185 | DLL_API void NtReadFile(XenonState* ctx, uint32_t lr) 186 | { 187 | X_LOG(X_INFO, "{NtReadFile} "); 188 | } 189 | DLL_API void NtQueryInformationFile(XenonState* ctx, uint32_t lr) 190 | { 191 | X_LOG(X_INFO, "{NtQueryInformationFile} "); 192 | } 193 | DLL_API void NtCreateFile(XenonState* ctx, uint32_t lr) 194 | { 195 | X_LOG(X_INFO, "{NtCreateFile} "); 196 | } 197 | DLL_API void NtQueryVolumeInformationFile(XenonState* ctx, uint32_t lr) 198 | { 199 | X_LOG(X_INFO, "{NtQueryVolumeInformationFile} "); 200 | } 201 | DLL_API void NtQueryFullAttributesFile(XenonState* ctx, uint32_t lr) 202 | { 203 | X_LOG(X_INFO, "{NtQueryFullAttributesFile} "); 204 | } 205 | 206 | } 207 | -------------------------------------------------------------------------------- /llvm360/Runtime/src/Runtime/Xen/XboxKrnl_Impl.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "XenUtils.h" 3 | #include "../MemoryManager.h" 4 | void RtlInitAnsiString_X(X_ANSI_STRING* ansiStr, char* str) 5 | { 6 | uint16_t length = strlen(str); 7 | ansiStr->pointer = (uint32_t)str; 8 | ansiStr->length = length; 9 | ansiStr->maximum_length = length + 1; 10 | X_LOG(X_INFO, "{RtlInitAnsiString_X} str: %s\n", str); 11 | return; 12 | } 13 | 14 | void DbgPrint_X() 15 | { 16 | X_LOG(X_WARNING, "{DbgPrint_X} not implemented"); 17 | return; 18 | } 19 | 20 | void HalReturnToFirmware_X(uint32_t routine) 21 | { 22 | if (routine != 1) DebugBreak(); 23 | (X_INFO, "{HalReturnToFirmware_X} requested exit"); 24 | exit(0); 25 | return; 26 | } 27 | 28 | X_STATUS NtAllocateVirtualMemory_X(uint32_t* basePtr, uint32_t* sizePtr, uint32_t allocType, uint32_t protect) 29 | { 30 | const auto base = (uint32_t)*basePtr; 31 | const auto size = BeField((uint32_t)*sizePtr).value; 32 | if (allocType & XMEM_RESERVE && (base != NULL)) 33 | { 34 | X_LOG(X_ERROR, "MEM - TRIED TO ALLOCATE AT SPECIFIC ADDRESS"); 35 | *basePtr = 0; 36 | return X_STATUS_NOT_IMPLEMENTED; 37 | } 38 | 39 | // align Page 40 | uint32_t pageAlignment = 4096; 41 | if (allocType & XMEM_LARGE_PAGES) 42 | { 43 | pageAlignment = 0x10000; 44 | } 45 | else if (allocType & XMEM_16MB_PAGES) 46 | { 47 | pageAlignment = 0x1000000; 48 | } 49 | 50 | // align size 51 | uint32_t alignedSize = (size + (pageAlignment - 1)) & ~(pageAlignment - 1); 52 | if (alignedSize != size) 53 | { 54 | X_LOG(X_WARNING, "MEM - aligned to %08X->%08X.1", size, alignedSize); 55 | } 56 | 57 | void* allocated = 0; 58 | uint32_t allocTypeFixed = allocType; 59 | if (!(allocTypeFixed & XMEM_COMMIT)) 60 | { 61 | allocated = XRuntime::g_runtime->m_memory->allocate((size_t)base, alignedSize, 0, protect); 62 | *basePtr = BeField(XRuntime::g_runtime->m_memory->makeHostGuest(allocated)).value; 63 | if (!allocated) 64 | { 65 | X_LOG(X_ERROR, "MEM - Allocation failed"); 66 | *basePtr = 0; 67 | return X_STATUS_NO_MEMORY; 68 | } 69 | X_LOG(X_INFO, "MEM - Allocated %04X bytes", alignedSize); 70 | } 71 | else 72 | { 73 | *basePtr = base; 74 | X_LOG(X_ERROR, "MEM - Unknown allocType flag"); 75 | } 76 | 77 | // save allocated memory & size 78 | 79 | *sizePtr = BeField((uint32_t)alignedSize).value; 80 | 81 | // allocation was OK 82 | return X_STATUS_SUCCESS; 83 | } 84 | 85 | // STUB 86 | uint32_t thisProcessType = X_PROCTYPE_USER; 87 | 88 | uint32_t KeGetCurrentProcessType_X() 89 | { 90 | return thisProcessType; 91 | } 92 | 93 | 94 | 95 | void RtlInitializeCriticalSection_X(XCRITICAL_SECTION* xctrs) 96 | { 97 | //auto* cs = GPlatform.GetKernel().CreateCriticalSection(); 98 | //auto* thread = xenon::KernelThread::GetCurrentThread(); 99 | xctrs->LockCount = 1; 100 | xctrs->OwningThread = 2; 101 | xctrs->RecursionCount = 3; 102 | xctrs->Synchronization.RawEvent[0] = 4; 103 | xctrs->Synchronization.RawEvent[1] = 5; 104 | xctrs->Synchronization.RawEvent[2] = 6; 105 | xctrs->Synchronization.RawEvent[3] = 7; 106 | 107 | 108 | /*xctrs->Synchronization.RawEvent[0] = 0xDAAD0FF0; 109 | xctrs->Synchronization.RawEvent[1] = cs->GetHandle(); 110 | xctrs->OwningThread = thread ? thread->GetHandle() : 0; 111 | xctrs->RecursionCount = 0; 112 | xctrs->LockCount = 0;*/ 113 | 114 | /*xctrs->Synchronization.RawEvent[0] = 0; 115 | xctrs->LockCount = -1; 116 | xctrs->RecursionCount = 0; 117 | xctrs->OwningThread = GetCurrentThreadId(); 118 | const uint32_t kernelMarker = xctrs->Synchronization.RawEvent[0];*/ 119 | } 120 | 121 | X_STATUS RtlEnterCriticalSection_X(XCRITICAL_SECTION* xctrs) 122 | { 123 | 124 | //uint32_t spin_count = xctrs->header.absolute * 256; 125 | //xctrs->recursion_count = xctrs->recursion_count + 1; 126 | //InterlockedIncrement(reinterpret_cast(&xctrs->lock_count)); 127 | 128 | X_LOG(X_ERROR, "RtlEnterCriticalSection_X, NOT IMPLEMENTED"); 129 | return 0; 130 | } -------------------------------------------------------------------------------- /llvm360/Runtime/src/Runtime/Xen/XenUtils.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../Runtime.h" 3 | #include "../..//Graphics/DX12Manager.h" 4 | #include "../../Graphics/ImGuiDebugger.h" 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | typedef void(__cdecl* x_func)(XenonState*, uint32_t); 12 | #define DLL_API __declspec(dllexport) 13 | bool d3dinit = false; 14 | 15 | 16 | #define RESET "\033[0m" 17 | #define RED "\033[31m" 18 | #define YELLOW "\033[33m" 19 | #define GREEN "\033[32m" 20 | enum LogLevel { X_INFO, X_WARNING, X_ERROR }; 21 | void X_LOG(LogLevel level, const char* format, ...) { 22 | const char* color; 23 | switch (level) { 24 | case X_INFO: color = GREEN; break; 25 | case X_WARNING: color = YELLOW; break; 26 | case X_ERROR: color = RED; break; 27 | } 28 | printf("%s", color); 29 | va_list args; 30 | va_start(args, format); 31 | vprintf(format, args); 32 | va_end(args); 33 | printf("%s\n", RESET); 34 | } 35 | 36 | 37 | // optimize? 38 | inline uint16_t ByteSwap16(uint16_t value) 39 | { 40 | return (value << 8) | (value >> 8); 41 | } 42 | 43 | // optimize? 44 | inline uint32_t ByteSwap32(uint32_t value) 45 | { 46 | return ((value & 0x000000FF) << 24) | 47 | ((value & 0x0000FF00) << 8) | 48 | ((value & 0x00FF0000) >> 8) | 49 | ((value & 0xFF000000) >> 24); 50 | } 51 | 52 | // optimize? 53 | inline uint64_t ByteSwap64(uint64_t value) 54 | { 55 | return ((value & 0x00000000000000FFULL) << 56) | 56 | ((value & 0x000000000000FF00ULL) << 40) | 57 | ((value & 0x0000000000FF0000ULL) << 24) | 58 | ((value & 0x00000000FF000000ULL) << 8) | 59 | ((value & 0x000000FF00000000ULL) >> 8) | 60 | ((value & 0x0000FF0000000000ULL) >> 24) | 61 | ((value & 0x00FF000000000000ULL) >> 40) | 62 | ((value & 0xFF00000000000000ULL) >> 56); 63 | } 64 | 65 | // https://github.com/rexdex/recompiler/blob/7cd1d5a33d6c02a13f972c6564550ea816fc8b5b/dev/src/xenon_launcher/xenonLib.h#L416 66 | // https://github.com/xenia-canary/xenia-canary/blob/8926bdcdd695bcf7f8f95938f0e44c59fbf9be14/src/xenia/base/byte_order.h#L84 67 | template 68 | struct BeField 69 | { 70 | T value; 71 | 72 | BeField() : value(0) 73 | { 74 | } 75 | 76 | BeField(const T v) 77 | { 78 | set(v); 79 | } 80 | 81 | void set(const T v) 82 | { 83 | value = swap(v); 84 | } 85 | 86 | T get() const 87 | { 88 | return swap(value); 89 | } 90 | 91 | BeField& operator+(T v) 92 | { 93 | set(value + v); 94 | return *this; 95 | } 96 | 97 | 98 | BeField& operator=(T v) 99 | { 100 | set(v); 101 | return *this; 102 | } 103 | 104 | // https://github.com/xenia-canary/xenia-canary/blob/8926bdcdd695bcf7f8f95938f0e44c59fbf9be14/src/xenia/base/byte_order.h#L62 105 | static T swap(T value) 106 | { 107 | if (std::is_same_v) 108 | { 109 | const uint16_t swapped = ByteSwap16(*reinterpret_cast(&value)); 110 | return *reinterpret_cast(&swapped); 111 | } 112 | else if (std::is_same_v) 113 | { 114 | const uint32_t swapped = ByteSwap32(*reinterpret_cast(&value)); 115 | return *reinterpret_cast(&swapped); 116 | } 117 | else if (std::is_same_v) 118 | { 119 | const uint64_t swapped = ByteSwap64(*reinterpret_cast(&value)); 120 | return *reinterpret_cast(&swapped); 121 | } 122 | else if (std::is_same_v) 123 | { 124 | const uint64_t swapped = ByteSwap64(*reinterpret_cast(&value)); 125 | return *reinterpret_cast(&swapped); 126 | } 127 | else if (std::is_same_v) 128 | { 129 | const uint32_t swapped = ByteSwap32(*reinterpret_cast(&value)); 130 | return *reinterpret_cast(&swapped); 131 | } 132 | else 133 | { 134 | printf("SWAP: Unsupported type\n"); 135 | static_assert(std::is_integral_v, "Unsupported type"); 136 | DebugBreak(); 137 | exit(1); 138 | } 139 | } 140 | }; 141 | 142 | struct X_ANSI_STRING 143 | { 144 | BeField length; 145 | BeField maximum_length; 146 | BeField pointer; 147 | }; 148 | 149 | 150 | struct X_LDR_DATA_TABLE_ENTRY { 151 | //X_LIST_ENTRY in_load_order_links; // 0x0 152 | //X_LIST_ENTRY in_memory_order_links; // 0x8 153 | //X_LIST_ENTRY in_initialization_order_links; // 0x10 154 | uint32_t in_load_order_links; // 0x0 155 | uint32_t in_memory_order_links; // 0x8 156 | uint32_t in_initialization_order_links; // 0x10 157 | 158 | BeField dll_base; // 0x18 159 | BeField image_base; // 0x1C 160 | BeField image_size; // 0x20 161 | 162 | //X_UNICODE_STRING full_dll_name; // 0x24 163 | //X_UNICODE_STRING base_dll_name; // 0x2C 164 | uint32_t full_dll_name; 165 | uint32_t base_dll_name; 166 | 167 | BeField flags; // 0x34 168 | BeField full_image_size; // 0x38 169 | BeField entry_point; // 0x3C 170 | BeField load_count; // 0x40 171 | BeField module_index; // 0x42 172 | BeField dll_base_original; // 0x44 173 | BeField checksum; // 0x48 hijacked to hold kernel handle 174 | BeField load_flags; // 0x4C 175 | BeField time_date_stamp; // 0x50 176 | BeField loaded_imports; // 0x54 177 | BeField xex_header_base; // 0x58 178 | // X_ANSI_STRING load_file_name; // 0x5C 179 | BeField closure_root; // 0x5C 180 | BeField traversal_parent; // 0x60 181 | }; 182 | 183 | // https://github.com/rexdex/recompiler/blob/7cd1d5a33d6c02a13f972c6564550ea816fc8b5b/dev/src/xenon_launcher/xenonLibNatives.h# 184 | typedef uint32_t X_STATUS; 185 | enum XStatus 186 | { 187 | X_STATUS_SUCCESS = ((X_STATUS)0x00000000L), 188 | X_STATUS_ABANDONED_WAIT_0 = ((X_STATUS)0x00000080L), 189 | X_STATUS_USER_APC = ((X_STATUS)0x000000C0L), 190 | X_STATUS_ALERTED = ((X_STATUS)0x00000101L), 191 | X_STATUS_TIMEOUT = ((X_STATUS)0x00000102L), 192 | X_STATUS_PENDING = ((X_STATUS)0x00000103L), 193 | X_STATUS_TIMER_RESUME_IGNORED = ((X_STATUS)0x40000025L), 194 | X_STATUS_BUFFER_OVERFLOW = ((X_STATUS)0x80000005L), 195 | X_STATUS_NO_MORE_FILES = ((X_STATUS)0x80000006L), 196 | X_STATUS_UNSUCCESSFUL = ((X_STATUS)0xC0000001L), 197 | X_STATUS_NOT_IMPLEMENTED = ((X_STATUS)0xC0000002L), 198 | X_STATUS_INFO_LENGTH_MISMATCH = ((X_STATUS)0xC0000004L), 199 | X_STATUS_ACCESS_VIOLATION = ((X_STATUS)0xC0000005L), 200 | X_STATUS_INVALID_HANDLE = ((X_STATUS)0xC0000008L), 201 | X_STATUS_INVALID_PARAMETER = ((X_STATUS)0xC000000DL), 202 | X_STATUS_NO_SUCH_FILE = ((X_STATUS)0xC000000FL), 203 | X_STATUS_END_OF_FILE = ((X_STATUS)0xC0000011L), 204 | X_STATUS_NO_MEMORY = ((X_STATUS)0xC0000017L), 205 | X_STATUS_ALREADY_COMMITTED = ((X_STATUS)0xC0000021L), 206 | X_STATUS_ACCESS_DENIED = ((X_STATUS)0xC0000022L), 207 | X_STATUS_BUFFER_TOO_SMALL = ((X_STATUS)0xC0000023L), 208 | X_STATUS_OBJECT_TYPE_MISMATCH = ((X_STATUS)0xC0000024L), 209 | X_STATUS_INVALID_PAGE_PROTECTION = ((X_STATUS)0xC0000045L), 210 | X_STATUS_MUTANT_NOT_OWNED = ((X_STATUS)0xC0000046L), 211 | X_STATUS_MEMORY_NOT_ALLOCATED = ((X_STATUS)0xC00000A0L), 212 | X_STATUS_INVALID_PARAMETER_1 = ((X_STATUS)0xC00000EFL), 213 | X_STATUS_INVALID_PARAMETER_2 = ((X_STATUS)0xC00000F0L), 214 | X_STATUS_INVALID_PARAMETER_3 = ((X_STATUS)0xC00000F1L), 215 | }; 216 | 217 | enum XVirtualFlags 218 | { 219 | XMEM_COMMIT = 0x1000, 220 | XMEM_RESERVE = 0x2000, 221 | XMEM_DECOMMIT = 0x4000, 222 | XMEM_RELEASE = 0x8000, 223 | XMEM_FREE = 0x10000, 224 | XMEM_PRIVATE = 0x20000, 225 | XMEM_RESET = 0x80000, 226 | XMEM_TOP_DOWN = 0x100000, 227 | XMEM_NOZERO = 0x800000, 228 | XMEM_LARGE_PAGES = 0x20000000, 229 | XMEM_HEAP = 0x40000000, 230 | XMEM_16MB_PAGES = 0x80000000, 231 | }; 232 | 233 | enum XProcessType 234 | { 235 | X_PROCTYPE_IDLE = 0, 236 | X_PROCTYPE_USER = 1, 237 | X_PROCTYPE_SYSTEM = 2, 238 | }; 239 | 240 | 241 | // https://www.nirsoft.net/kernel_struct/vista/DISPATCHER_HEADER.html 242 | typedef struct { 243 | struct { 244 | uint8_t type; 245 | 246 | union { 247 | uint8_t abandoned; 248 | uint8_t absolute; 249 | uint8_t npx_irql; 250 | uint8_t signalling; 251 | }; 252 | union { 253 | uint8_t size; 254 | uint8_t hand; 255 | }; 256 | union { 257 | uint8_t inserted; 258 | uint8_t debug_active; 259 | uint8_t dpc_active; 260 | }; 261 | }; 262 | 263 | BeField signal_state; 264 | BeField wait_list_flink; 265 | BeField wait_list_blink; 266 | } X_DISPATCH_HEADER; 267 | 268 | 269 | #pragma pack(push, 1) 270 | struct XCRITICAL_SECTION { 271 | /*X_DISPATCH_HEADER header; 272 | int32_t lock_count; // 0x10 -1 -> 0 on first lock 273 | BeField recursion_count; // 0x14 0 -> 1 on first lock 274 | BeField owning_thread; // 0x18 PKTHREAD 0 unless locked 275 | */ 276 | union { 277 | uint32_t RawEvent[4]; 278 | } Synchronization; 279 | 280 | // 281 | // The following three fields control entering and exiting the critical 282 | // section for the resource 283 | // 284 | 285 | uint32_t LockCount; 286 | uint32_t RecursionCount; 287 | uint32_t OwningThread; 288 | }; 289 | #pragma pack(pop) 290 | 291 | 292 | extern "C" 293 | { 294 | DLL_API int dllHack() 295 | { 296 | if (!d3dinit) 297 | { 298 | XRuntime::g_runtime->debuggerEnabled = true; 299 | DirectX12Manager& inst = DirectX12Manager::getInstance(); 300 | if (XRuntime::g_runtime->debuggerEnabled) 301 | { 302 | 303 | 304 | /*/create a new thread and call ImGuiDebugger::getInstance().initialize(nullptr); 305 | ImGuiDebugger::g_debugger->initialize(); 306 | std::thread imguiThread([]() { 307 | printf("Starting ImGui Thread\n"); 308 | 309 | ImGuiDebugger::g_debugger->render(); 310 | 311 | }); 312 | std::this_thread::sleep_for(std::chrono::seconds(1)); 313 | 314 | imguiThread.detach();*/ 315 | 316 | } 317 | 318 | d3dinit = true; 319 | } 320 | 321 | return 1; 322 | } 323 | 324 | DLL_API void HandleBcctrl(XenonState* ctx, uint32_t lr) 325 | { 326 | for (uint32_t i = 0; i < *XRuntime::g_runtime->exportedCount; i++) 327 | { 328 | if (ctx->CTR == XRuntime::g_runtime->exportedArray[i].xexAddress) 329 | { 330 | (*(x_func)XRuntime::g_runtime->exportedArray[i].funcPtr)(ctx, lr); 331 | return; 332 | } 333 | } 334 | printf("-------- {HandleBcctrl} ERROR: NO FUNCTION AT: %u \n", ctx->CTR); 335 | return; 336 | } 337 | 338 | enum DebugState 339 | { 340 | RUNNING, 341 | STEP_INTO, 342 | STEP_OVER 343 | }; 344 | 345 | DebugState prevState; 346 | DebugState currentState = RUNNING; 347 | std::vector stepOverPoints; 348 | 349 | void inline HaltState(uint32_t addr, char* name) 350 | { 351 | while (true) 352 | { 353 | // continue 354 | if (GetAsyncKeyState('C') & 0x8000) 355 | { 356 | prevState = currentState; 357 | currentState = RUNNING; 358 | break; 359 | } 360 | 361 | // step Into 362 | if (GetAsyncKeyState('I') & 0x8000) 363 | { 364 | prevState = currentState; 365 | currentState = STEP_INTO; 366 | break; 367 | } 368 | 369 | // step Over 370 | if (GetAsyncKeyState('O') & 0x8000) 371 | { 372 | prevState = currentState; 373 | currentState = STEP_OVER; 374 | if (strcmp(name, "bc") == 0 || strcmp(name, "b") == 0 || strcmp(name, "bl") == 0) 375 | { 376 | stepOverPoints.push_back(addr + 4); 377 | prevState = currentState; 378 | currentState = RUNNING; 379 | } 380 | break; 381 | } 382 | } 383 | } 384 | 385 | DLL_API void DebugCallBack(XenonState* ctx, uint32_t addr, char* name) 386 | { 387 | std::vector breakPoints = { 0x82010634 }; 388 | if (IsDebuggerPresent() && true) 389 | { 390 | 391 | for(uint32_t bp : breakPoints) 392 | { 393 | if(bp == addr) 394 | { 395 | DebugBreak(); 396 | HaltState(addr, name); 397 | return; 398 | } 399 | } 400 | 401 | if (currentState == STEP_INTO) 402 | { 403 | DebugBreak(); 404 | HaltState(addr, name); 405 | return; 406 | } 407 | 408 | if(currentState == RUNNING && prevState == STEP_OVER) 409 | { 410 | for (uint32_t bp : stepOverPoints) 411 | { 412 | if (bp == addr) 413 | { 414 | DebugBreak(); 415 | HaltState(addr, name); 416 | currentState = prevState; 417 | return; 418 | } 419 | } 420 | } 421 | 422 | if (currentState == STEP_OVER) 423 | { 424 | DebugBreak(); 425 | HaltState(addr, name); 426 | return; 427 | } 428 | } 429 | 430 | } 431 | } 432 | -------------------------------------------------------------------------------- /llvm360/Runtime/src/dllmain.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | 3 | 4 | BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) 5 | { 6 | switch (fdwReason) { 7 | case DLL_PROCESS_ATTACH: 8 | 9 | XRuntime::initGlobal(); 10 | XRuntime::g_runtime->init(); 11 | ImGuiDebugger::initStatic(); 12 | 13 | 14 | break; 15 | case DLL_THREAD_ATTACH: 16 | case DLL_THREAD_DETACH: 17 | 18 | 19 | break; 20 | case DLL_PROCESS_DETACH: 21 | { 22 | 23 | printf("---- Main Thread ----\n"); 24 | printf("LR: %016llX\n", XRuntime::g_runtime->mainThreadState->LR); 25 | printf("CR: %08llX\n", XRuntime::g_runtime->mainThreadState->CR); 26 | printf("XER: %08llX\n", XRuntime::g_runtime->mainThreadState->XER); 27 | 28 | printf("\n--- RR ---\n"); 29 | for (size_t i = 0; i < 32; i++) 30 | { 31 | printf("R[%i]: %016llX\n", i, XRuntime::g_runtime->mainThreadState->RR[i]); 32 | } 33 | printf("\n--- FR ---\n"); 34 | for (size_t i = 0; i < 32; i++) 35 | { 36 | printf("FR[%i]: %016llX\n", i, XRuntime::g_runtime->mainThreadState->FR[i]); 37 | } 38 | break; 39 | } 40 | } 41 | 42 | return TRUE; 43 | } -------------------------------------------------------------------------------- /llvm360/Runtime/src/pch.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" -------------------------------------------------------------------------------- /llvm360/Runtime/src/pch.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef PCH_H 3 | #define PCH_H 4 | #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers 5 | // Windows Header Files 6 | #include 7 | 8 | 9 | // exports 10 | #include "Runtime/Xen/XenUtils.h" 11 | #include "Runtime/Xen/XboxKrnl_Entry.h" 12 | #include "Runtime/Xen/Xam_Entry.h" 13 | 14 | #include "Runtime/Runtime.h" 15 | #include "pch.h" 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | 22 | 23 | #endif //PCH_H --------------------------------------------------------------------------------