Example #1
0
bool
ThreadHandler::_DoStepOver(CpuState* cpuState)
{
	TRACE_CONTROL("ThreadHandler::_DoStepOver()\n");

	// The basic strategy is to single-step out of the statement like for
	// "step into", only we have to avoid stepping into subroutines. Hence we
	// check whether the current instruction is a subroutine call. If not, we
	// just single-step, otherwise we set a breakpoint after the instruction.
	InstructionInfo info;
	if (fDebuggerInterface->GetArchitecture()->GetInstructionInfo(
			cpuState->InstructionPointer(), info, cpuState) != B_OK) {
		TRACE_CONTROL("  failed to get instruction info\n");
		return false;
	}

	if (info.Type() != INSTRUCTION_TYPE_SUBROUTINE_CALL) {
		_SingleStepThread(cpuState->InstructionPointer());

		TRACE_CONTROL("  not a subroutine call\n");
		return true;
	}

	TRACE_CONTROL("  subroutine call -- installing breakpoint at address "
		"%#" B_PRIx64 "\n", info.Address() + info.Size());

	if (_InstallTemporaryBreakpoint(info.Address() + info.Size()) != B_OK)
		return false;

	fSteppedOverFunctionAddress = info.TargetAddress();

	_RunThread(cpuState->InstructionPointer());
	return true;
}
Example #2
0
bool
ThreadHandler::_HandleBreakpointHitStep(CpuState* cpuState)
{
	// in any case uninstall the temporary breakpoint
	_UninstallTemporaryBreakpoint();

	switch (fStepMode) {
		case STEP_OVER:
		{
			StackTrace* stackTrace = fThread->GetStackTrace();
			BReference<StackTrace> stackTraceReference(stackTrace);

			if (stackTrace == NULL && cpuState != NULL) {
				if (fDebuggerInterface->GetArchitecture()->CreateStackTrace(
						fThread->GetTeam(), this, cpuState, stackTrace, NULL,
						1, false, false) == B_OK) {
					stackTraceReference.SetTo(stackTrace, true);
				}
			}
			if (stackTrace != NULL) {
				StackFrame* frame = stackTrace->FrameAt(0);
				// If we're not in the same frame we started in,
				// keep executing.
				if (frame != NULL && fPreviousFrameAddress
						!= frame->FrameAddress()) {
					status_t error = _InstallTemporaryBreakpoint(
						cpuState->InstructionPointer());
					if (error != B_OK)
						_StepFallback();
					else
						_RunThread(cpuState->InstructionPointer());
					return true;
				}
			}

			if (fPreviousFrameAddress != 0 && fSteppedOverFunctionAddress
					!= cpuState->InstructionPointer()) {
				TRACE_CONTROL("STEP_OVER: called function address %#" B_PRIx64
					", previous frame address: %#" B_PRIx64 ", frame address: %#"
					B_PRIx64 ", adding return info\n", fSteppedOverFunctionAddress,
					fPreviousFrameAddress, stackTrace->FrameAt(0)->FrameAddress());
				ReturnValueInfo* returnInfo = new(std::nothrow) ReturnValueInfo(
					fSteppedOverFunctionAddress, cpuState);
				if (returnInfo == NULL)
					return false;

				BReference<ReturnValueInfo> returnInfoReference(returnInfo, true);

				if (fThread->AddReturnValueInfo(returnInfo) != B_OK)
					return false;

				returnInfoReference.Detach();
				fSteppedOverFunctionAddress = 0;
			}

			// If we're still in the statement, we continue single-stepping,
			// otherwise we're done.
			if (fStepStatement->ContainsAddress(
					cpuState->InstructionPointer())) {
				if (!_DoStepOver(cpuState))
					_StepFallback();
				return true;
			}
			fPreviousFrameAddress = 0;
			return false;
		}

		case STEP_INTO:
			// Should never happen -- we don't set a breakpoint in this case.
			return false;

		case STEP_OUT:
		{
			// That's the return address, so we're done in theory,
			// unless we're a recursive function. Check if we've actually
			// exited the previous stack frame or not
			if (!_HasExitedFrame(cpuState->StackFramePointer())) {
				status_t error = _InstallTemporaryBreakpoint(
					cpuState->InstructionPointer());
				if (error != B_OK)
					_StepFallback();
				else
					_RunThread(cpuState->InstructionPointer());
				return true;
			}

			if (fPreviousFrameAddress == 0)
				return false;

			TRACE_CONTROL("ThreadHandler::_HandleBreakpointHitStep() - "
				"frame pointer 0x%#" B_PRIx64 ", previous: 0x%#" B_PRIx64
				" - step out adding return value\n", cpuState
					->StackFramePointer(), fPreviousFrameAddress);
			ReturnValueInfo* info = new(std::nothrow) ReturnValueInfo(
				fPreviousInstructionPointer, cpuState);
			if (info == NULL)
				return false;
			BReference<ReturnValueInfo> infoReference(info, true);
			if (fThread->AddReturnValueInfo(info) != B_OK)
				return false;

			infoReference.Detach();
			fPreviousFrameAddress = 0;
		}

		default:
			return false;
	}
}
Example #3
0
void
ThreadHandler::HandleThreadAction(uint32 action, target_addr_t address)
{
	AutoLocker<Team> locker(fThread->GetTeam());

	if (fThread->State() == THREAD_STATE_UNKNOWN)
		return;

	// When stop is requested, thread must be running, otherwise stopped.
	if (action == MSG_THREAD_STOP
			? fThread->State() != THREAD_STATE_RUNNING
			: fThread->State() != THREAD_STATE_STOPPED) {
		return;
	}

	// When stepping we need a stack trace. Save it before unsetting the state.
	CpuState* cpuState = fThread->GetCpuState();
	StackTrace* stackTrace = fThread->GetStackTrace();
	BReference<CpuState> cpuStateReference(cpuState);
	BReference<StackTrace> stackTraceReference(stackTrace);

	if (action == MSG_THREAD_SET_ADDRESS) {
		_HandleSetAddress(cpuState, address);
		return;
	}

	// When continuing the thread update thread state before actually issuing
	// the command, since we need to unlock.
	if (action != MSG_THREAD_STOP) {
		_SetThreadState(THREAD_STATE_RUNNING, NULL, THREAD_STOPPED_UNKNOWN,
			BString());
	}

	locker.Unlock();

	switch (action) {
		case MSG_THREAD_RUN:
			fStepMode = address != 0 ? STEP_UNTIL : STEP_NONE;
			if (address != 0)
				_InstallTemporaryBreakpoint(address);
			_RunThread(0);
			return;
		case MSG_THREAD_STOP:
			fStepMode = STEP_NONE;
			if (fDebuggerInterface->StopThread(ThreadID()) == B_OK)
				fThread->SetStopRequestPending();
			return;
		case MSG_THREAD_STEP_OVER:
		case MSG_THREAD_STEP_INTO:
		case MSG_THREAD_STEP_OUT:
			break;
	}

	TRACE_CONTROL("ThreadHandler::HandleThreadAction(MSG_THREAD_STEP_*)\n");

	// We want to step. We need a stack trace for that purpose. If we don't
	// have one yet, get it. Start with the CPU state.
	if (stackTrace == NULL && cpuState == NULL) {
		if (fDebuggerInterface->GetCpuState(fThread->ID(), cpuState) == B_OK)
			cpuStateReference.SetTo(cpuState, true);
	}

	if (stackTrace == NULL && cpuState != NULL) {
		if (fDebuggerInterface->GetArchitecture()->CreateStackTrace(
				fThread->GetTeam(), this, cpuState, stackTrace, NULL, 1,
				false, false) == B_OK) {
			stackTraceReference.SetTo(stackTrace, true);
		}
	}

	if (stackTrace == NULL || stackTrace->CountFrames() == 0) {
		_StepFallback();
		return;
	}

	StackFrame* frame = stackTrace->FrameAt(0);

	TRACE_CONTROL("  ip: %#" B_PRIx64 "\n", frame->InstructionPointer());

	target_addr_t frameIP = frame->GetCpuState()->InstructionPointer();
	// When the thread is in a syscall, do the same for all step kinds: Stop it
	// when it returns by means of a breakpoint.
	if (frame->Type() == STACK_FRAME_TYPE_SYSCALL) {
		// set a breakpoint at the CPU state's instruction pointer (points to
		// the return address, unlike the stack frame's instruction pointer)
// TODO: This is doesn't work correctly anymore. When stepping over a "syscall"
// instruction the thread is stopped twice. The after the first step the PC is
// incorrectly shown at the "syscall" instruction. Then we step again and are
// stopped at the temporary breakpoint after the "syscall" instruction. There
// are two problems. The first one is that we don't (cannot?) discriminate
// between the thread being in a syscall (like in a blocking syscall) and the
// thread having been stopped (or singled-stepped) at the end of the syscall.
// The second issue is that the temporary breakpoint is probably not necessary
// anymore, since single-stepping over "syscall" instructions should just work
// as expected.
		status_t error = _InstallTemporaryBreakpoint(frameIP);
		if (error != B_OK) {
			_StepFallback();
			return;
		}

		fStepMode = STEP_OUT;
		_RunThread(frameIP);
		return;
	}

	// For "step out" just set a temporary breakpoint on the return address.
	if (action == MSG_THREAD_STEP_OUT) {
		status_t error = _InstallTemporaryBreakpoint(frame->ReturnAddress());
		if (error != B_OK) {
			_StepFallback();
			return;
		}
		fPreviousInstructionPointer = frameIP;
		fPreviousFrameAddress = frame->FrameAddress();
		fStepMode = STEP_OUT;
		_RunThread(frameIP);
		return;
	}

	// For "step in" and "step over" we also need the source code statement at
	// the current instruction pointer.
	fStepStatement = _GetStatementAtInstructionPointer(frame);
	if (fStepStatement == NULL) {
		_StepFallback();
		return;
	}

	TRACE_CONTROL("  statement: %#" B_PRIx64 " - %#" B_PRIx64 "\n",
		fStepStatement->CoveringAddressRange().Start(),
		fStepStatement->CoveringAddressRange().End());

	if (action == MSG_THREAD_STEP_INTO) {
		// step into
		fStepMode = STEP_INTO;
		_SingleStepThread(frameIP);
	} else {
		fPreviousFrameAddress = frame->FrameAddress();
		// step over
		fStepMode = STEP_OVER;
		if (!_DoStepOver(frame->GetCpuState()))
			_StepFallback();
	}
}
bool
ThreadHandler::_HandleBreakpointHitStep(CpuState* cpuState)
{
	// in any case uninstall the temporary breakpoint
	_UninstallTemporaryBreakpoint();

	switch (fStepMode) {
		case STEP_OVER:
		{
			StackTrace* stackTrace = fThread->GetStackTrace();
			BReference<StackTrace> stackTraceReference(stackTrace);

			if (stackTrace == NULL && cpuState != NULL) {
				if (fDebuggerInterface->GetArchitecture()->CreateStackTrace(
						fThread->GetTeam(), this, cpuState, stackTrace, 0, 1,
						false, false) == B_OK) {
					stackTraceReference.SetTo(stackTrace, true);
				}
			}
			if (stackTrace != NULL) {
				StackFrame* frame = stackTrace->FrameAt(0);
				// If we're not in the same frame we started in,
				// keep executing.
				if (frame != NULL && fPreviousFrameAddress
						!= frame->FrameAddress()) {
					status_t error = _InstallTemporaryBreakpoint(
						cpuState->InstructionPointer());
					if (error != B_OK)
						_StepFallback();
					else
						_RunThread(cpuState->InstructionPointer());
					return true;
				}
			}

			// If we're still in the statement, we continue single-stepping,
			// otherwise we're done.
			if (fStepStatement->ContainsAddress(
					cpuState->InstructionPointer())) {
				if (!_DoStepOver(cpuState))
					_StepFallback();
				return true;
			}
			fPreviousFrameAddress = 0;
			return false;
		}

		case STEP_INTO:
			// Should never happen -- we don't set a breakpoint in this case.
			return false;

		case STEP_OUT:
		{
			// That's the return address, so we're done in theory,
			// unless we're a recursive function. Check if we've actually
			// exited the previous stack frame or not.
			fThread->SetExecutedSubroutine(cpuState->InstructionPointer());
			target_addr_t framePointer = cpuState->StackFramePointer();
			bool hasExitedFrame = fDebuggerInterface->GetArchitecture()
				->StackGrowthDirection() == STACK_GROWTH_DIRECTION_POSITIVE
					? framePointer < fPreviousFrameAddress
					: framePointer > fPreviousFrameAddress;

			if (!hasExitedFrame) {
				status_t error = _InstallTemporaryBreakpoint(
					cpuState->InstructionPointer());
				if (error != B_OK)
					_StepFallback();
				else
					_RunThread(cpuState->InstructionPointer());
				return true;
			}
			fPreviousFrameAddress = 0;
		}

		default:
			return false;
	}
}
Example #5
0
void
ThreadHandler::HandleThreadAction(uint32 action)
{
    AutoLocker<Team> locker(fThread->GetTeam());

    if (fThread->State() == THREAD_STATE_UNKNOWN)
        return;

    // When stop is requested, thread must be running, otherwise stopped.
    if (action == MSG_THREAD_STOP
            ? fThread->State() != THREAD_STATE_RUNNING
            : fThread->State() != THREAD_STATE_STOPPED) {
        return;
    }

    // When stepping we need a stack trace. Save it before unsetting the state.
    CpuState* cpuState = fThread->GetCpuState();
    StackTrace* stackTrace = fThread->GetStackTrace();
    Reference<CpuState> cpuStateReference(cpuState);
    Reference<StackTrace> stackTraceReference(stackTrace);

    // When continuing the thread update thread state before actually issuing
    // the command, since we need to unlock.
    if (action != MSG_THREAD_STOP) {
        _SetThreadState(THREAD_STATE_RUNNING, NULL, THREAD_STOPPED_UNKNOWN,
                        BString());
    }

    locker.Unlock();

    switch (action) {
    case MSG_THREAD_RUN:
        fStepMode = STEP_NONE;
        _RunThread(0);
        return;
    case MSG_THREAD_STOP:
        fStepMode = STEP_NONE;
        fDebuggerInterface->StopThread(ThreadID());
        return;
    case MSG_THREAD_STEP_OVER:
    case MSG_THREAD_STEP_INTO:
    case MSG_THREAD_STEP_OUT:
        break;
    }

    TRACE_CONTROL("ThreadHandler::HandleThreadAction(MSG_THREAD_STEP_*)\n");

    // We want to step. We need a stack trace for that purpose. If we don't
    // have one yet, get it. Start with the CPU state.
    if (stackTrace == NULL && cpuState == NULL) {
        if (fDebuggerInterface->GetCpuState(fThread->ID(), cpuState) == B_OK)
            cpuStateReference.SetTo(cpuState, true);
    }

    if (stackTrace == NULL && cpuState != NULL) {
        if (fDebuggerInterface->GetArchitecture()->CreateStackTrace(
                    fThread->GetTeam(), this, cpuState, stackTrace) == B_OK) {
            stackTraceReference.SetTo(stackTrace, true);
        }
    }

    if (stackTrace == NULL || stackTrace->CountFrames() == 0) {
        _StepFallback();
        return;
    }

    StackFrame* frame = stackTrace->FrameAt(0);

    TRACE_CONTROL("  ip: %#llx\n", frame->InstructionPointer());

    // When the thread is in a syscall, do the same for all step kinds: Stop it
    // when it return by means of a breakpoint.
    if (frame->Type() == STACK_FRAME_TYPE_SYSCALL) {
        // set a breakpoint at the CPU state's instruction pointer (points to
        // the return address, unlike the stack frame's instruction pointer)
        status_t error = _InstallTemporaryBreakpoint(
                             frame->GetCpuState()->InstructionPointer());
        if (error != B_OK) {
            _StepFallback();
            return;
        }

        fStepMode = STEP_OUT;
        _RunThread(frame->GetCpuState()->InstructionPointer());
        return;
    }

    // For "step out" just set a temporary breakpoint on the return address.
    if (action == MSG_THREAD_STEP_OUT) {
// TODO: That's OK in principle, but needs additional work with recursive
// functions. We need to store some information that allows us to determine
// whether we've actually stepped out of the current frame when we have hit
// the breakpoint.
        status_t error = _InstallTemporaryBreakpoint(frame->ReturnAddress());
        if (error != B_OK) {
            _StepFallback();
            return;
        }

        fStepMode = STEP_OUT;
        _RunThread(frame->GetCpuState()->InstructionPointer());
        return;
    }

    // For "step in" and "step over" we also need the source code statement at
    // the current instruction pointer.
    fStepStatement = _GetStatementAtInstructionPointer(frame);
    if (fStepStatement == NULL) {
        _StepFallback();
        return;
    }

    TRACE_CONTROL("  statement: %#llx - %#llx\n",
                  fStepStatement->CoveringAddressRange().Start(),
                  fStepStatement->CoveringAddressRange().End());

    if (action == MSG_THREAD_STEP_INTO) {
        // step into
        fStepMode = STEP_INTO;
        _SingleStepThread(frame->GetCpuState()->InstructionPointer());
    } else {
        // step over
        fStepMode = STEP_OVER;
        if (!_DoStepOver(frame->GetCpuState()))
            _StepFallback();
    }
}
Example #6
0
void CImageManager::_BeginPrefetch () {
	_RunThread(THREAD_PREFETCH);
}
Example #7
0
void CImageManager::_BeginLoad () {
	_RunThread(THREAD_LOAD);
}