def sub_80E72C8_fix_extra_vars_0x74_read(opcode_params, funcstate, src_file, fileline): if opcode_params[0] == "r0" and opcode_params[1] == "r5": funcstate.regs["r0"].set_new_reg( analyzer.RegisterInfo(datatypes.BattleObject().wrap(), fileline)) return False return True
def sub_80103F8_hack_battle_obj_null(opcode_params, funcstate, src_file, fileline): if opcode_params[0] != "r7": return True funcstate.regs["r7"].set_new_reg( analyzer.RegisterInfo(datatypes.BattleObject().wrap(), fileline)) return False
def hack_battle_state_field_0x80_object_read(opcode_params, funcstate, src_file, fileline): if opcode_params[0] == "r7" and opcode_params[1] == "r4": funcstate.regs["r7"].set_new_reg( analyzer.RegisterInfo(datatypes.BattleObject().wrap(), fileline)) return False return True
def check_sub_802EF74_tst(opcode_params, funcstate, src_file, fileline): if opcode_params[0] == "r7": funcstate.regs["r7"].set_new_reg( analyzer.RegisterInfo(datatypes.BattleObject().wrap(), fileline)) return False return True
def check_stored_functions(opcode_params, funcstate, src_file, fileline): if opcode_params.startswith("nullsub"): return False elif opcode_params not in analyzer.template_functions: return True return_values = analyzer.template_functions[opcode_params] for return_value in return_values: funcstate.regs[return_value.regname].set_new_reg(analyzer.RegisterInfo(return_value.datatype().wrap(), fileline)) fileline_msg("Called stored function \"%s\"." % opcode_params, fileline) return False
def sub_80E1566_fix_sub_80E1670_return_value(opcode_params, funcstate, src_file, fileline): funcstate.regs["r0"].set_new_reg( analyzer.RegisterInfo(datatypes.BattleObject().wrap(), fileline)) return True
def sub_80DCA38_fix_uninitialized_stack_read(opcode_params, funcstate, src_file, fileline): if opcode_params[1] == "r6": funcstate.regs["r6"].set_new_reg( analyzer.RegisterInfo(datatypes.Primitive().wrap(), fileline)) return True
def sub_80BC670_set_r0_battle_object(opcode_params, funcstate, src_file, fileline): funcstate.regs["r0"].set_new_reg( analyzer.RegisterInfo(datatypes.BattleObject().wrap(), fileline)) return True
def object_get_panel_region_set_correct_return_value(opcode_params, funcstate, src_file, fileline): funcstate.regs["r0"].set_new_reg( analyzer.RegisterInfo(datatypes.Primitive().wrap(), fileline)) return True
def check_bl_sub_80BC3B8(opcode_params, funcstate, src_file, fileline): if opcode_params == "sub_80BC3B8": funcstate.regs["r0"].set_new_reg( analyzer.RegisterInfo(datatypes.BattleObject().wrap(), fileline)) return True
def sub_8109D08_bx_callback_fix(opcode_params, funcstate, src_file, fileline): funcstate.regs["r1"].set_new_reg( analyzer.RegisterInfo( datatypes.ROMPointer([syms["sub_810A21A"], syms["sub_810A254"]], syms["off_810A2B0"]).wrap(), fileline)) return True
def check_sub_8013892_push_r7(opcode_params, funcstate, src_file, fileline): if opcode_params == "{r7}": funcstate.regs["r4"].set_new_reg( analyzer.RegisterInfo(datatypes.AIData().wrap(), fileline)) return True
def check_sub_80127C0(opcode_params, funcstate, src_file, fileline): funcstate.regs["r6"].set_new_reg( analyzer.RegisterInfo(datatypes.Primitive(Size.BYTE).wrap(), fileline)) funcstate.regs["r4"].set_new_reg( analyzer.RegisterInfo(datatypes.Primitive().wrap(), fileline)) return False
def check_loc_800EA38(opcode_params, funcstate, src_file, fileline): funcstate.regs["r3"].set_new_reg( analyzer.RegisterInfo( datatypes.Primitive(Size.BYTE, 0x8c).wrap(), fileline)) return True
def run_analyzer_common(src_file, funcstate, function_start_time): function_total_time = 0 return_lr = funcstate.regs["lr"].data base_stack_offset = funcstate.regs["sp"].data.ref.offset function_name = funcstate.function.name function_filename = funcstate.function.filename #function_tree = collections.OrderedDict() debug_print("funcstart: base stack offset: %s, function: %s (%s:%s)" % (base_stack_offset, function_name, function_filename, funcstate.function.line_num + 1)) return_regs = None return_pc = None return_stack = None funcstate.regs["pc"].set_new_reg( RegisterInfo( datatypes.ProgramCounter(src_file.filename, src_file.line_num).wrap(), FileLine(src_file.filename, src_file.line_num))) add_function_specific_callbacks(funcstate.function.value) while True: debug_print("start src_file: %s:%s" % (src_file.filename, src_file.line_num + 1)) for line in src_file: #if funcstate.function.value == 0x80BE8AE: # sub_80BE8AE # debug_print("cur src_file: %s:%s" % (src_file.filename, src_file.line_num + 1)) if not line.startswith("\t"): split_line = line.split(":", 1) # if we're currently in an unconditional branch, don't read opcodes until we find the label if funcstate.uncond_branch != "": if funcstate.uncond_branch != split_line[0]: continue funcstate.uncond_branch = "" funcstate.found_labels[split_line[0]] = FileLine( src_file.filename, src_file.line_num) if len(split_line) > 1: line = split_line[1] else: continue if line.strip() == "": continue elif funcstate.uncond_branch != "": continue funcstate.regs["pc"].data.ref.line_num = src_file.line_num pc_fileline = funcstate.regs["pc"][-1].fileline fileline = FileLine(src_file.filename, src_file.line_num) analyze_source.global_fileline = fileline if opcodes.read_opcode(line, funcstate, src_file, fileline): new_pc_fileline = funcstate.regs["pc"][-1].fileline if new_pc_fileline.line_num != pc_fileline.line_num or new_pc_fileline.filename != pc_fileline.filename: sp_datatype_ref = funcstate.regs["sp"].data.ref pc_datatype_ref = funcstate.regs["pc"].data.ref try: possible_syms = pc_datatype_ref.possible_syms except AttributeError: # need to fundamentally rethink how to parse variable callbacks, for now just hope that they don't do anything significant fileline_msg( "VariableCallbackWarning: Skipped bad callback of type \"%s\"!" % type(pc_datatype_ref).__name__, fileline) funcstate.regs["r0"].set_new_reg( analyzer.RegisterInfo( datatypes.UnknownDataType().wrap(), fileline)) funcstate.regs["r1"].set_new_reg( analyzer.RegisterInfo( datatypes.UnknownDataType().wrap(), fileline)) funcstate.regs["r2"].set_new_reg( analyzer.RegisterInfo( datatypes.UnknownDataType().wrap(), fileline)) funcstate.regs["r3"].set_new_reg( analyzer.RegisterInfo( datatypes.UnknownDataType().wrap(), fileline)) possible_syms = None if possible_syms is not None: if len(possible_syms) > 1: #debug_print("sp offset: %s" % sp_datatype_ref.offset) if sp_datatype_ref.offset == base_stack_offset: fileline_error( "Tried performing jumptable at base stack offset!", fileline) remove_function_specific_callbacks( funcstate.function.value) jumptable_already_executed = pc_datatype_ref.original_sym.value in already_executed_jumptables debug_print("Jumptable found: name: %s" % pc_datatype_ref.original_sym.name) #if funcstate.function.value == 0x801B9E6: # sub_801B9E6, runs jumptables # dumb_hack_please_remove_function_memory = datatypes.Struct.dumb_hack_basic_struct_fields[datatypes.AIData][0xc8][Size.WORD].memory # dumb_hack_please_remove_function_memory.function = None # dumb_hack_please_remove_function_memory.dumb_hack_please_remove_in_sub_801B9E6 = True already_executed_jumptables.add( pc_datatype_ref.original_sym.value) for sym in possible_syms: if sym.type != "F": fileline_msg( "BadFunctionDefinitionWarning: Tried executing jumptable non-function symbol \"%s\"!" % sym.name, fileline) if sym.name not in problem_functions: debug_print( "Start of jumptable function called from \"%s\" (%s:%s)" % (function_name, src_file.filename, src_file.line_num + 1)) function_total_time += time.time( ) - function_start_time #subroutine_return_regs, function_tree["!" + sym.name] = run_analyzer_from_sym(sym, funcstate.regs, time.time()) subroutine_return_regs = run_analyzer_from_sym( sym, funcstate.regs, time.time()) function_start_time = time.time() debug_print( "End of jumptable function called from \"%s\" (%s:%s)" % (function_name, src_file.filename, src_file.line_num + 1)) if jumptable_already_executed: break else: debug_print( "Skipped problem function \"%s\" called from \"%s\" (%s:%s)" % (sym.name, function_name, src_file.filename, src_file.line_num + 1)) #if funcstate.function.value == 0x801B9E6: # sub_801B9E6 # dumb_hack_please_remove_function_memory.dumb_hack_please_remove_in_sub_801B9E6 = False add_function_specific_callbacks( funcstate.function.value) elif len(possible_syms) == 1: if sp_datatype_ref.offset == base_stack_offset: # returning from function if return_lr.ref.filename == pc_datatype_ref.filename and return_lr.ref.line_num == pc_datatype_ref.line_num: if return_regs is None: # just use first return regs found for now return_regs = funcstate.regs return_stack = datatypes.Stack.datatypes break # not returning from function, then this is a noreturn bx or something similar # I think this only happens when performing an interwork return else: fileline_error( "Tried performing noreturn branch!", fileline) else: if possible_syms[0].type != "F": fileline_msg( "BadFunctionDefinitionWarning: Tried executing regular non-function symbol \"%s\"!" % possible_syms[0].name, fileline) debug_print( "Start of regular function called from \"%s\" (%s:%s)" % (function_name, src_file.filename, src_file.line_num + 1)) remove_function_specific_callbacks( funcstate.function.value) function_total_time = time.time( ) - function_start_time #subroutine_return_regs, function_tree[possible_syms[0].name] = run_analyzer_from_sym(possible_syms[0], funcstate.regs, time.time()) subroutine_return_regs = run_analyzer_from_sym( possible_syms[0], funcstate.regs, time.time()) function_start_time = time.time() debug_print( "End of regular function called from \"%s\" (%s:%s)" % (function_name, src_file.filename, src_file.line_num + 1)) add_function_specific_callbacks( funcstate.function.value) #debug_print("return regs: %s" % subroutine_return_regs) else: fileline_error( "Tried executing function but there was none!", fileline) funcstate.set_registers(subroutine_return_regs) src_file.line_num = funcstate.regs[ "pc"].data.ref.line_num - 1 elif funcstate.uncond_branch != "": debug_print("uncond branch: %s" % funcstate.uncond_branch) if funcstate.uncond_branch in funcstate.found_labels: # TODO: potential for loop detection here funcstate.uncond_branch = "" break elif funcstate.uncond_branch in syms: if src_file.filename != syms[ funcstate.uncond_branch].filename: global_fileline_error( "Unconditional branch jumps to other file!") src_file.line_num = syms[ funcstate.uncond_branch].line_num - 1 else: stripped_line = line.strip() if stripped_line.startswith( "thumb_func") or stripped_line.startswith( ".align 1, 0"): continue fileline_error("Unknown directive \"%s\"!" % stripped_line, fileline) else: global_fileline_error("Reached end of file while parsing!") # don't attempt to run any conditional branches if this function already had its conditional branches executed # unless the function is forced to run all paths each time if function_name in function_trackers and return_regs is not None and funcstate.function.value not in force_all_paths_functions: break # sub_801AF44 if funcstate.function.value == 0x801AF44 and "loc_801B18E" in funcstate.found_labels: break # now check if we have any conditional labels left for cond_branch_info in funcstate.cond_branches: if cond_branch_info.branch_name not in funcstate.found_labels: #debug_print("found labels: %s\nbranch name: %s" % (funcstate.found_labels, cond_branch_info.branch_name)) funcstate.set_registers(cond_branch_info.registers) src_file.line_num = parser.find_label_line_num( cond_branch_info.branch_name, funcstate) datatypes.Stack.datatypes = cond_branch_info.stack break else: if return_regs is not None: #debug_print("about to return regs: %s" % return_regs) # return_regs["pc"].append(RegisterInfo(copy.deepcopy(return_pc), fileline)) break else: fileline_error("Did not find a return point in function!", fileline) remove_function_specific_callbacks(funcstate.function.value) if funcstate.function.value == 0x8019892: # object_createCollisionData return_regs = funcstate.regs datatypes.Stack.datatypes = return_stack debug_print("funcend: base stack offset: %s, function: %s (%s:%s)" % (base_stack_offset, function_name, function_filename, funcstate.function.line_num + 1)) if function_name in function_trackers: function_trackers[function_name].count += 1 function_total_time += time.time() - function_start_time function_trackers[function_name].time += function_total_time else: function_total_time += time.time() - function_start_time function_trackers[function_name] = FunctionTracker(function_total_time) #return (return_regs, function_tree) return return_regs
def chatbox_8041964_skip_flag_call(opcode_params, funcstate, src_file, fileline): if opcode_params == "TestEventFlagRange": funcstate.regs["r0"].set_new_reg(analyzer.RegisterInfo(datatypes.Primitive().wrap(), fileline)) return True