def assert_not_ambiguous(self): if self.is_absolute_addr() and (self & 0x80000000) == 0: raise InvalidOperationException( f"{self.value} is ambiguous: absolute, top bit not set") if self.is_relative_addr() and (self & 0x80000000) != 0: raise InvalidOperationException( f"{self.value} is ambiguous: relative, top bit set")
def apply_to_dol(self, dol: DolFile, linker: "Linker"): funcSize = linker._symbolSizes[self.address] funcEnd = self.address + (funcSize - 4) if funcSize < 4: raise InvalidOperationException("Queried function is too small") dol.seek(funcEnd) if read_uint32(dol) != 0x4E800020: raise InvalidOperationException("Function does not end in blr") instrLoc = self.address dol.seek(instrLoc) while instrLoc < funcEnd: insn = read_uint32(dol) if (insn & 0xFC00FFFF == 0x4C000020): raise InvalidOperationException( "Function contains a return partway through") instrLoc += 4 self.endAddress = funcEnd try: dol.resolve_address(self.address) dol.seek(self.endAddress.value) write_uint32(dol, self._generate_instruction()) return True except UnmappedAddressError: return False
def pack_gecko_codes(self) -> list: self.address.assert_absolute() if self.valueType == WriteCommand.Type.Pointer: self.value.assert_absolute() else: self.value.assert_value() if self.original is not None: raise NotImplementedError( "Conditional writes not yet supported for gecko") elif self.address >= 0x90000000: raise NotImplementedError( "MEM2 writes not yet supported for gecko") code = ((self.address.value & 0x1FFFFFF) << 32) | self.value.value if self.valueType == WriteCommand.Type.Value16: return list(code | (0x2000000 << 32)) elif self.valueType == WriteCommand.Type.Value32: return list(code | (0x4000000 << 32)) elif self.valueType == WriteCommand.Type.Pointer: return list(code | (0x4000000 << 32)) raise InvalidOperationException( f"Invalid command type {self.valueType} specified")
def pack_riivo(self) -> str: self.address.assert_absolute() if self.valueType == WriteCommand.Type.Pointer: self.value.assert_absolute() else: self.value.assert_value() if self.original is not None: self.original.assert_not_relative() if self.valueType == WriteCommand.Type.Value8: return f"<memory offset='0x{self.address:X8}' value='{self.value:X2}' original='{self.original:X2}' />" elif self.valueType == WriteCommand.Type.Value16: return f"<memory offset='0x{self.address:X8}' value='{self.value:X4}' original='{self.original:X4}' />" elif self.valueType == WriteCommand.Type.Value32: return f"<memory offset='0x{self.address:X8}' value='{self.value:X8}' original='{self.original:X8}' />" elif self.valueType == WriteCommand.Type.Pointer: return f"<memory offset='0x{self.address:X8}' value='{self.value:X8}' original='{self.original:X8}' />" else: if self.valueType == WriteCommand.Type.Value8: return f"<memory offset='0x{self.address:X8}' value='{self.value:X2}' />" elif self.valueType == WriteCommand.Type.Value16: return f"<memory offset='0x{self.address:X8}' value='{self.value:X4}' />" elif self.valueType == WriteCommand.Type.Value32: return f"<memory offset='0x{self.address:X8}' value='{self.value:X8}' />" elif self.valueType == WriteCommand.Type.Pointer: return f"<memory offset='0x{self.address:X8}' value='{self.value:X8}' />" raise InvalidOperationException( f"Invalid command type {self.valueType} specified")
def load_from_linker(self, linker: Linker): if self.codeSize > 0: raise InvalidOperationException( "This Kamek binary already has stuff in it") self.mapper = linker # Extract only code/data sections linker._memory.seek(linker.outputStart.value - linker.baseAddress.value) self.rawCode = BytesIO(linker._memory.read(linker.outputSize.value)) self.baseAddr = linker.baseAddress self.bssSize = linker.bssSize for _key in linker._symbolSizes: self.symbolSizes[_key] = linker._symbolSizes[_key] self.add_relocs_as_commands(linker._fixups) for cmd in linker._kamekHooks: self.apply_hook(cmd) self.apply_static_commands()
def add_relocs_as_commands(self, relocs: list): for rel in relocs: if rel.source in self.commands: raise InvalidOperationException( f"Duplicate commands for address {rel.source.value:X}") self.commands[rel.source] = RelocCommand(rel.source, rel.dest, rel.type)
def apply_to_dol(self, dol: DolFile): if self.baseAddr.type == KWord.Types.RELATIVE: raise InvalidOperationException( "Cannot pack a dynamically linked binary into a DOL") dol.append_section(TextSection(self.baseAddr.value, self.rawCode)) for _key in self.commands: self.commands[_key].apply_to_dol(dol, self.mapper)
def apply_hook(self, hookData): hook = KHook.create(hookData, self.mapper) for cmd in hook.commands: if cmd.address in self.commands: raise InvalidOperationException( f"Duplicate commands for address {cmd.address.value:X}") self.commands[cmd.address] = cmd self.hooks.append(hook)
def _kamek_use_reloc(self, _type: ELFFlags.Reloc, source: KWord, dest: KWord): if source < self.kamekStart or source >= self.kamekEnd: return False elif _type != ELFFlags.Reloc.R_PPC_ADDR32: raise InvalidOperationException( "Unsupported relocation type in the Kamek hook data section") self._kamekRelocs[source] = dest return True
def apply(self, f: "KamekBinary") -> bool: funcSize = f.get_symbol_size(self.address) funcEnd = self.address + (funcSize - 4) if funcSize < 4: raise InvalidOperationException("Queried function is too small") if f.read_u32(funcEnd) != 0x4E800020: raise InvalidOperationException("Function does not end in blr") instrLoc = self.address while instrLoc < funcEnd: insn = f.read_u32(instrLoc) if (insn & 0xFC00FFFF == 0x4C000020): raise InvalidOperationException( "Function contains a return partway through") instrLoc += 4 self.endAddress = funcEnd if self.is_equal_reloc_absolute() and f.contains(self.address): f.write_u32(self.endAddress.value, self._generate_instruction()) return True else: return False
def assert_not_absolute(self): if self.is_absolute_addr(): raise InvalidOperationException( f"KWord {self.value} must not be a absolute address in this context" )
def assert_not_relative(self): if self.is_relative_addr(): raise InvalidOperationException( f"KWord {self.value} must not be a relative address in this context" )
def assert_not_value(self): if self.is_value(): raise InvalidOperationException( f"KWord {self.value} must not be a value in this context")