void ScanForFunctions(u32 startAddr, u32 endAddr /*, std::vector<u32> knownEntries*/) { Function currentFunction = {startAddr}; u32 furthestBranch = 0; bool looking = false; bool end = false; bool isStraightLeaf=true; u32 addr; for (addr = startAddr; addr<=endAddr; addr+=4) { int n = symbolMap.GetSymbolNum(addr,ST_FUNCTION); if (n != -1) { addr = symbolMap.GetSymbolAddr(n) + symbolMap.GetSymbolSize(n); continue; } u32 op = Memory::Read_Instruction(addr); u32 target = GetBranchTarget(addr); if (target != INVALIDTARGET) { isStraightLeaf = false; if (target > furthestBranch) { furthestBranch = target; } } if (op == MIPS_MAKE_JR_RA()) { if (furthestBranch >= addr) { looking = true; addr+=4; } else { end = true; } } if (looking) { if (addr >= furthestBranch) { u32 sureTarget = GetSureBranchTarget(addr); if (sureTarget != INVALIDTARGET && sureTarget < addr) { end = true; } sureTarget = GetJumpTarget(addr); if (sureTarget != INVALIDTARGET && sureTarget < addr && ((op&0xFC000000)==0x08000000)) { end = true; } //end = true; } } if (end) { currentFunction.end = addr + 4; currentFunction.isStraightLeaf = isStraightLeaf; functions.push_back(currentFunction); furthestBranch = 0; addr += 4; looking = false; end = false; isStraightLeaf=true; currentFunction.start = addr+4; } } currentFunction.end = addr + 4; functions.push_back(currentFunction); for (vector<Function>::iterator iter = functions.begin(); iter!=functions.end(); iter++) { (*iter).size = ((*iter).end-(*iter).start+4); char temp[256]; sprintf(temp,"z_un_%08x",(*iter).start); symbolMap.AddSymbol(std::string(temp).c_str(), (*iter).start,(*iter).end-(*iter).start+4,ST_FUNCTION); } HashFunctions(); }
//************************************************************************************* // //************************************************************************************* CTraceRecorder::EUpdateTraceStatus CTraceRecorder::UpdateTrace( u32 address, bool branch_delay_slot, bool branch_taken, OpCode op_code, CFragment * p_fragment ) { DAEDALUS_ASSERT( mTracing, "We're not tracing" ); bool want_to_stop( p_fragment != NULL ); if( mTraceBuffer.size() > MAX_TRACE_LENGTH ) { DBGConsole_Msg(0, "Hit max trace size!"); want_to_stop = true; } // Terminate if the current instruction is in the fragment cache or the trace reaches a specified size if( want_to_stop && (mActiveBranchIdx == INVALID_IDX) ) { DAEDALUS_ASSERT( mActiveBranchIdx == INVALID_IDX, "Exiting trace while in the middle of handling branch!" ); // Stop immediately so we can be sure of linking up with fragment mTracing = false; mExpectedExitTraceAddress = address; return UTS_CREATE_FRAGMENT; } // // Figure out whether to terminate this trace after adding this instruction // bool stop_trace_on_exit( false ); // // We want to record the delay slot op for the active branch // if( mActiveBranchIdx != INVALID_IDX ) { DAEDALUS_ASSERT( mActiveBranchIdx < mBranchDetails.size(), "Branch index is out of bounds" ); mBranchDetails[ mActiveBranchIdx ].DelaySlotTraceIndex = mTraceBuffer.size(); if (mBranchDetails[ mActiveBranchIdx ].SpeedHack == SHACK_POSSIBLE) { if (op_code._u32 == 0) { mBranchDetails[ mActiveBranchIdx ].SpeedHack = SHACK_SKIPTOEVENT; } #ifndef DAEDALUS_SILENT else if (op_code.op == OP_ADDIU || op_code.op == OP_DADDI || op_code.op == OP_ADDI || op_code.op == OP_DADDIU) { // We don't handle COPYREG SPEEDHACKS mBranchDetails[ mActiveBranchIdx ].SpeedHack = SHACK_COPYREG; } #endif } mActiveBranchIdx = INVALID_IDX; } // If we had to terminate on the last branch (e.g. for an indirect jump) // or if we're jumping backwards, terminate the run when we exit if( mStopTraceAfterDelaySlot && branch_delay_slot ) { mStopTraceAfterDelaySlot = false; stop_trace_on_exit = true; } // // Update the expected trace exit address // We assume that if we'll exit on the next instruction (assuming this isn't a branch) // if( !branch_delay_slot ) { mExpectedExitTraceAddress = address + 4; } StaticAnalysis::RegisterUsage usage; StaticAnalysis::Analyse(op_code,usage); // // If this is a branch, we need to determine if it was taken or not. // We store a information about the 'off-trace' target. // If the branch was taken, we need to flip the condition of the // branch so that anything failing the test is directed off our trace // u32 branch_idx( INVALID_IDX ); ER4300BranchType branch_type( usage.BranchType ); if( branch_type != BT_NOT_BRANCH ) { SBranchDetails details; details.Likely = IsBranchTypeLikely( branch_type ); if( branch_type == BT_ERET ) { stop_trace_on_exit = true; details.Eret = true; details.Direct = false; details.TargetAddress = INDIRECT_EXIT_ADDRESS; mExpectedExitTraceAddress = details.TargetAddress; } else if( !IsConditionalBranch( branch_type ) ) { details.Direct = IsBranchTypeDirect( branch_type ); details.TargetAddress = gCPUState.TargetPC; details.ConditionalBranchTaken = true; mExpectedExitTraceAddress = details.TargetAddress; if (!details.Direct || gCPUState.TargetPC <= gCPUState.CurrentPC) { // all indirect call will stop the trace mStopTraceAfterDelaySlot = true; } if (details.Direct && gCPUState.TargetPC == gCPUState.CurrentPC) { details.SpeedHack = SHACK_POSSIBLE; } } else { // Must be conditional, direct DAEDALUS_ASSERT( IsBranchTypeDirect( branch_type ), "Not expecting an indirect branch here" ); if( branch_taken ) { // XXXXXX should be able to get this some other way? bool backwards( gCPUState.TargetPC <= gCPUState.CurrentPC ); if( backwards ) { mStopTraceAfterDelaySlot = true; } if (gCPUState.TargetPC == gCPUState.CurrentPC) { details.SpeedHack = SHACK_POSSIBLE; } } u32 branch_target_address( GetBranchTarget( address, op_code, branch_type ) ); u32 fallthrough_address( address + 8 ); u32 target_address; if( branch_taken ) { // We're following the branch. target_address = fallthrough_address; mExpectedExitTraceAddress = branch_target_address; } else { // We're not following the branch, and falling through. target_address = branch_target_address; mExpectedExitTraceAddress = fallthrough_address; } details.ConditionalBranchTaken = branch_taken; details.Direct = true; details.TargetAddress = target_address; } if( !details.Direct ) { mNeedIndirectExitMap = true; } mActiveBranchIdx = mBranchDetails.size(); branch_idx = mBranchDetails.size(); mBranchDetails.push_back( details ); } // Add this op to the trace buffer. STraceEntry entry = { address, op_code, usage, branch_idx, branch_delay_slot }; mTraceBuffer.push_back( entry ); if( stop_trace_on_exit ) { DAEDALUS_ASSERT( branch_type == BT_ERET || mActiveBranchIdx == INVALID_IDX, "Exiting trace while in the middle of handling branch!" ); mTracing = false; return UTS_CREATE_FRAGMENT; } return UTS_CONTINUE_TRACE; }