示例#1
0
/**
 * Command: Step CPU, but proceed through subroutines
 * Does this by temporary conditional breakpoint
 */
static int DebugCpu_Next(int nArgc, char *psArgv[])
{
	char command[40];
	if (nArgc > 1)
	{
		int optype;
		if(strcmp(psArgv[1], "branch") == 0)
			optype = CALL_BRANCH;
		else if(strcmp(psArgv[1], "exception") == 0)
			optype = CALL_EXCEPTION;
		else if(strcmp(psArgv[1], "exreturn") == 0)
			optype = CALL_EXCRETURN;
		else if(strcmp(psArgv[1], "subcall") == 0)
			optype = CALL_SUBROUTINE;
		else if (strcmp(psArgv[1], "subreturn") == 0)
			optype = CALL_SUBRETURN;
		else if (strcmp(psArgv[1], "return") == 0)
			optype = CALL_SUBRETURN | CALL_EXCRETURN;
		else
		{
			fprintf(stderr, "Unrecognized opcode type given!\n");
			return DEBUGGER_CMDDONE;
		}
		sprintf(command, "CpuOpcodeType & $%x > 0 :once :quiet\n", optype);
	}
	else
	{
		Uint32 optype, nextpc;

		optype = DebugCpu_OpcodeType();
		/* can this instruction be stepped normally? */
		if (optype != CALL_SUBROUTINE && optype != CALL_EXCEPTION)
		{
			nCpuSteps = 1;
			return DEBUGGER_END;
		}

		nextpc = Disasm_GetNextPC(M68000_GetPC());
		sprintf(command, "pc=$%x :once :quiet\n", nextpc);
	}
	/* use breakpoint, not steps */
	if (BreakCond_Command(command, false))
	{
		nCpuSteps = 0;
		return DEBUGGER_END;
	}
	return DEBUGGER_CMDDONE;
}
示例#2
0
/**
 * If call tracking is enabled (there are symbols), collect
 * information about subroutine and other calls, and their costs.
 * 
 * Like with profile data, caller info checks need to be for previous
 * instruction, that's why "pc" argument for this function actually
 * needs to be previous PC.
 */
static void collect_calls(Uint32 pc, counters_t *counters)
{
	calltype_t flag;
	int idx, family;
	Uint32 prev_pc, caller_pc;

	family = cpu_profile.prev_family;
	cpu_profile.prev_family = OpcodeFamily;

	prev_pc = cpu_callinfo.prev_pc;
	cpu_callinfo.prev_pc = pc;
	caller_pc = PC_UNDEFINED;

	/* address is return address for last subroutine call? */
	if (unlikely(pc == cpu_callinfo.return_pc) && likely(cpu_callinfo.depth)) {

		flag = cpu_opcode_type(family, prev_pc, pc);
		/* previous address can be exception return (e.g. RTE) instead of RTS,
		 * if exception occurred right after returning from subroutine call.
		 */
		if (likely(flag == CALL_SUBRETURN || flag == CALL_EXCRETURN)) {
			caller_pc = Profile_CallEnd(&cpu_callinfo, counters);
		} else {
#if DEBUG
			/* although at return address, it didn't return yet,
			 * e.g. because there was a jsr or jump to return address
			 */
			Uint32 nextpc;
			fprintf(stderr, "WARNING: subroutine call returned 0x%x -> 0x%x, not through RTS!\n", prev_pc, pc);
			Disasm(stderr, prev_pc, &nextpc, 1);
#endif
		}
		/* next address might be another symbol, so need to fall through */
	}

	/* address is one which we're tracking? */
	idx = Symbols_GetCpuAddressIndex(pc);
	if (unlikely(idx >= 0)) {

		flag = cpu_opcode_type(family, prev_pc, pc);
		if (flag == CALL_SUBROUTINE || flag == CALL_EXCEPTION) {
			/* special HACK for for EmuTOS AES switcher which
			 * changes stack content to remove itself from call
			 * stack and uses RTS for subroutine *calls*, not
			 * for returning from them.
			 *
			 * It wouldn't be reliable to detect calls from it,
			 * so I'm making call *to* it show up as branch, to
			 * keep callstack depth correct.
			 */
			if (unlikely(pc == etos_switcher)) {
				flag = CALL_BRANCH;
			} else if (unlikely(prev_pc == PC_UNDEFINED)) {
				/* if first profiled instruction
				 * is subroutine call, it doesn't have
				 * valid prev_pc value stored
				 */
				cpu_callinfo.return_pc = PC_UNDEFINED;
				fprintf(stderr, "WARNING: previous PC from callinfo for 0x%d is undefined!\n", pc);
#if DEBUG
				skip_assert = true;
				DebugUI(REASON_CPU_EXCEPTION);
#endif
			} else {
				/* slow! */
				cpu_callinfo.return_pc = Disasm_GetNextPC(prev_pc);
			}
		} else if (caller_pc != PC_UNDEFINED) {
			/* returned from function to first instruction of another symbol:
			 *	0xf384	jsr some_function
			 *	other_symbol:
			 *	0f3x8a	some_instruction
			 * -> change return instruction address to
			 *    address of what did the returned call.
			 */
			prev_pc = caller_pc;
			assert(is_prev_instr(prev_pc, pc));
			flag = CALL_NEXT;
		}
		Profile_CallStart(idx, &cpu_callinfo, prev_pc, flag, pc, counters);
	}
}