def hook__ground_start(self, address, size): if not self.overlay11_loaded(): return self._print("Ground Start") threadsafe_gtk_nonblocking(lambda: self.reset()) ground_engine_lock.acquire() self._running = True ground_engine_lock.release() self._inform_ground_engine_start_cb()
def _do_sync(self): self._tables = [] self._current_table = 0 if self.rom_data: address_table_head = self.rom_data.binaries['arm9.bin'].symbols['MemoryAllocTable'].begin_absolute accessor = self.emu_thread.emu.memory.unsigned for x in range(accessor.read_long(address_table_head)): address_table = address_table_head+0x20+0x4*x self._tables.append(self._read_table(accessor.read_long(address_table))) threadsafe_gtk_nonblocking(self._do_sync_gtk)
def _do_sync(self): for var in self.rom_data.script_data.game_variables: var_values = [] for offset in range(0, var.nbvalues): if not var.is_local: _, val = GameVariable.read(self.emu_thread.emu.memory, self.rom_data, var.id, offset) var_values.append(val) self._variable_cache[self.rom_data.script_data. game_variables__by_id[var.id]] = var_values threadsafe_gtk_nonblocking(self._do_sync_gtk)
def hook__variable_set_with_offset(self, address: int, size: int): if self._boost: return var_id = self.emu_thread.emu.memory.register_arm9.r1 if var_id >= 0x400: return var_offset = self.emu_thread.emu.memory.register_arm9.r2 value_raw = self.emu_thread.emu.memory.register_arm9.r3 # TODO: Do we need to process the raw value...? self._variable_cache[self.rom_data.script_data.game_variables__by_id[ var_id]][var_offset] = value_raw threadsafe_gtk_nonblocking( partial(self.hook__variable_set_gtk, var_id, var_offset, value_raw))
def hook__ssb_load(self, address, size): if not self.overlay11_loaded(): return name = self.emu_thread.emu.memory.read_string( self.emu_thread.emu.memory.register_arm9.r1) load_for = self._load_ssb_for if self._load_ssb_for is not None else 0 self._print(f"SSB Load {name} for hanger {load_for}") self._load_ssb_for = None if load_for > MAX_SSB: warnings.warn( f"Ground Engine debugger: Invalid hanger ID for ssb: {load_for}" ) return threadsafe_gtk_nonblocking( lambda: self.ssb_file_manager.open_in_ground_engine(name)) self._loaded_ssb_files[load_for] = (SsbFileInRam(name, load_for))
def change_current_table(self, current_table): self._current_table = max(0, min(current_table, len(self._tables))) threadsafe_gtk_nonblocking(self._do_sync_gtk)
def _do_sync_local_vars(self, srs): for var in self._local_vars_specs: _, val = GameVariable.read(self.emu_thread.emu.memory, self._rom_data, var.id, 0, srs) self._local_vars_values.append(val) threadsafe_gtk_nonblocking(self._do_sync_gtk)
def print_callback(self, text: str): threadsafe_gtk_nonblocking(lambda: self._print_callback_fn(text))
def hook__set_debug_flag_2(self, address, size): flag_id = self.emu_thread.emu.memory.register_arm9.r0 value = self.emu_thread.emu.memory.register_arm9.r1 threadsafe_gtk_nonblocking( lambda: self.parent.set_check_debug_flag_2(flag_id, value))
def hook__breaking_point(self, address, size): """MAIN DEBUGGER HOOK. The emulator thread pauses here and publishes it's state via BreakpointState.""" if self._boost: return debugger_state_lock.acquire() srs = ScriptRuntimeStruct(self.emu_thread.emu.memory, self.rom_data, self.emu_thread.emu.memory.register_arm9.r6, self.ground_engine_state.unionall_load_addr) if self._log_operations: self.print_callback( f"> {srs.target_type.name}({srs.target_id}): {srs.current_opcode.name} @{srs.current_opcode_addr:0x}" ) if self.breakpoint_manager: if not self._breakpoints_disabled and self._breakpoints_disabled_for_tick != self.emu_thread.current_frame_id: debugger_state_lock.release() self._breakpoints_disabled_for_tick = -1 ssb = self.ground_engine_state.loaded_ssb_files[srs.hanger_ssb] if ssb is not None and ( self._breakpoint_force or self.breakpoint_manager.has( ssb.file_name, srs.current_opcode_addr_relative, srs.is_in_unionall, srs.script_target_type, srs.script_target_slot_id)): self.breakpoint_manager.reset_temporary() self._breakpoint_force = False state = BreakpointState(srs.hanger_ssb, srs) state.acquire() threadsafe_gtk_nonblocking( lambda: self.parent.break_pulled(state)) while not state.wait( 0.0005 ) and state.state == BreakpointStateType.STOPPED: # We haven't gotten the signal to resume yet, process pending events. self.emu_thread.run_one_pending_task() state.release() if state.state == BreakpointStateType.FAIL_HARD: # Ok, we won't pause again this tick. self._breakpoints_disabled_for_tick = self.emu_thread.current_frame_id elif state.state == BreakpointStateType.RESUME: # We just resume, this is easy :) pass elif state.state == BreakpointStateType.STEP_NEXT: # We force a break at the next run of this hook. self._breakpoint_force = True elif state.state == BreakpointStateType.STEP_INTO: # We break at whatever is executed next for the current script target. self.breakpoint_manager.add_temporary( srs.script_target_type, srs.script_target_slot_id) elif state.state == BreakpointStateType.STEP_OVER: # We break at the next opcode in the current script file self.breakpoint_manager.add_temporary( srs.script_target_type, srs.script_target_slot_id, is_in_unionall=srs.is_in_unionall) # If the current op is the last one (we will step out next) this will lead to issues. # We need to alternatively break at the current stack opcode (see STEP_OUT). if srs.has_call_stack: self.breakpoint_manager.add_temporary( srs.script_target_type, srs.script_target_slot_id, opcode_addr=srs. call_stack__current_opcode_addr_relative) elif state.state == BreakpointStateType.STEP_OUT: if srs.has_call_stack: # We break at the opcode address stored on the call stack position. self.breakpoint_manager.add_temporary( srs.script_target_type, srs.script_target_slot_id, opcode_addr=srs. call_stack__current_opcode_addr_relative) else: # We just resume pass elif state.state == BreakpointStateType.STEP_MANUAL: # We break at the requested opcode offset in the current hanger. self.breakpoint_manager.add_temporary( srs.script_target_type, srs.script_target_slot_id, is_in_unionall=srs.is_in_unionall, opcode_addr=state.manual_step_opcode_offset) else: debugger_state_lock.release() else: debugger_state_lock.release()