コード例 #1
0
ファイル: ThreadHandler.cpp プロジェクト: MaddTheSane/haiku
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;
}
コード例 #2
0
status_t
BreakpointManager::_UpdateBreakpointInstallation(Breakpoint* breakpoint)
{
	bool shouldBeInstalled = breakpoint->ShouldBeInstalled();

	TRACE_CONTROL("BreakpointManager::_UpdateBreakpointInstallation(%p): "
		"should be installed: %d, is installed: %d\n", breakpoint,
		shouldBeInstalled, breakpoint->IsInstalled());

	if (shouldBeInstalled == breakpoint->IsInstalled())
		return B_OK;

	if (shouldBeInstalled) {
		// install
		status_t error = fDebuggerInterface->InstallBreakpoint(
			breakpoint->Address());
		if (error != B_OK)
			return error;

		TRACE_CONTROL("BREAKPOINT at %#llx installed: %s\n",
			breakpoint->Address(), strerror(error));

		breakpoint->SetInstalled(true);
	} else {
		// uninstall
		fDebuggerInterface->UninstallBreakpoint(breakpoint->Address());

		TRACE_CONTROL("BREAKPOINT at %#llx uninstalled\n",
			breakpoint->Address());

		breakpoint->SetInstalled(false);
	}

	return B_OK;
}
コード例 #3
0
ファイル: ThreadHandler.cpp プロジェクト: mmadia/haiku-1
bool
ThreadHandler::_HandleSingleStepStep(CpuState* cpuState)
{
    TRACE_CONTROL("ThreadHandler::_HandleSingleStepStep(): ip: %llx\n",
                  cpuState->InstructionPointer());

    switch (fStepMode) {
    case STEP_INTO:
    {
        // We continue stepping as long as we're in the statement.
        if (fStepStatement->ContainsAddress(cpuState->InstructionPointer())) {
            _SingleStepThread(cpuState->InstructionPointer());
            return true;
        }
        return false;
    }

    case STEP_OVER:
    {
        // If we have stepped out of the statement, we're done.
        if (!fStepStatement->ContainsAddress(cpuState->InstructionPointer()))
            return false;
        return _DoStepOver(cpuState);
    }

    case STEP_OUT:
    // We never single-step in this case.
    default:
        return false;
    }
}
コード例 #4
0
bool
ThreadHandler::_HandleSingleStepStep(CpuState* cpuState)
{
	TRACE_CONTROL("ThreadHandler::_HandleSingleStepStep(): ip: %llx\n",
		cpuState->InstructionPointer());

	switch (fStepMode) {
		case STEP_INTO:
		{
			// We continue stepping as long as we're in the statement.
			if (fStepStatement->ContainsAddress(cpuState->InstructionPointer())) {
				_SingleStepThread(cpuState->InstructionPointer());
				return true;
			}

			StackTrace* stackTrace = fThread->GetStackTrace();
			BReference<StackTrace> stackTraceReference(stackTrace);

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

			if (stackTrace != NULL) {
				StackFrame* frame = stackTrace->FrameAt(0);
				Image* image = frame->GetImage();
				ImageDebugInfo* info = NULL;
				if (GetImageDebugInfo(image, info) != B_OK)
					return false;

				BReference<ImageDebugInfo>(info, true);
				if (info->GetAddressSectionType(
						cpuState->InstructionPointer())
						== ADDRESS_SECTION_TYPE_PLT) {
					_SingleStepThread(cpuState->InstructionPointer());
					return true;
				}
			}
			return false;
		}

		case STEP_OVER:
		{
			// If we have stepped out of the statement, we're done.
			if (!fStepStatement->ContainsAddress(cpuState->InstructionPointer()))
				return false;
			return _DoStepOver(cpuState);
		}

		case STEP_OUT:
			// We never single-step in this case.
		default:
			return false;
	}
}
コード例 #5
0
void
TeamDebugger::_HandleClearUserBreakpoint(target_addr_t address)
{
	TRACE_CONTROL("TeamDebugger::_HandleClearUserBreakpoint(%#llx)\n", address);

	AutoLocker< ::Team> locker(fTeam);

	Breakpoint* breakpoint = fTeam->BreakpointAtAddress(address);
	if (breakpoint == NULL || breakpoint->FirstUserBreakpoint() == NULL)
		return;
	UserBreakpoint* userBreakpoint
		= breakpoint->FirstUserBreakpoint()->GetUserBreakpoint();
	BReference<UserBreakpoint> userBreakpointReference(userBreakpoint);

	locker.Unlock();

	_HandleClearUserBreakpoint(userBreakpoint);
}
コード例 #6
0
void
TeamDebugger::_HandleInspectAddress(target_addr_t address,
	TeamMemoryBlock::Listener* listener)
{
	TRACE_CONTROL("TeamDebugger::_HandleInspectAddress(%" B_PRIx64 ", %p)\n",
		address, listener);

	TeamMemoryBlock* memoryBlock = fMemoryBlockManager
		->GetMemoryBlock(address);

	if (memoryBlock == NULL) {
		_NotifyUser("Inspect Address", "Failed to allocate memory block");
		return;
	}

	if (!memoryBlock->HasListener(listener))
		memoryBlock->AddListener(listener);

	if (!memoryBlock->IsValid()) {
		AutoLocker< ::Team> teamLocker(fTeam);

		TeamMemory* memory = fTeam->GetTeamMemory();
		// schedule the job
		status_t result;
		if ((result = fWorker->ScheduleJob(
			new(std::nothrow) RetrieveMemoryBlockJob(fTeam, memory,
				memoryBlock),
			this)) != B_OK) {
			memoryBlock->ReleaseReference();
			_NotifyUser("Inspect Address", "Failed to retrieve memory data: %s",
				strerror(result));
		}
	} else
		memoryBlock->NotifyDataRetrieved();

}
コード例 #7
0
ファイル: ThreadHandler.cpp プロジェクト: MaddTheSane/haiku
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;
	}
}
コード例 #8
0
ファイル: ThreadHandler.cpp プロジェクト: MaddTheSane/haiku
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();
	}
}
コード例 #9
0
status_t
BreakpointManager::InstallUserBreakpoint(UserBreakpoint* userBreakpoint,
	bool enabled)
{
	TRACE_CONTROL("BreakpointManager::InstallUserBreakpoint(%p, %d)\n",
		userBreakpoint, enabled);

	AutoLocker<BLocker> installLocker(fLock);
	AutoLocker<Team> teamLocker(fTeam);

	bool oldEnabled = userBreakpoint->IsEnabled();
	if (userBreakpoint->IsValid() && enabled == oldEnabled) {
		TRACE_CONTROL("  user breakpoint already valid and with same enabled "
			"state\n");
		return B_OK;
	}

	// get/create the breakpoints for all instances
	TRACE_CONTROL("  creating breakpoints for breakpoint instances\n");

	status_t error = B_OK;
	for (int32 i = 0;
		UserBreakpointInstance* instance = userBreakpoint->InstanceAt(i); i++) {

		TRACE_CONTROL("    breakpoint instance %p\n", instance);

		if (instance->GetBreakpoint() != NULL) {
			TRACE_CONTROL("    -> already has breakpoint\n");
			continue;
		}

		target_addr_t address = instance->Address();
		Breakpoint* breakpoint = fTeam->BreakpointAtAddress(address);
		if (breakpoint == NULL) {
			TRACE_CONTROL("    -> no breakpoint at that address yet\n");

			Image* image = fTeam->ImageByAddress(address);
			if (image == NULL) {
				TRACE_CONTROL("    -> no image at that address\n");
				error = B_BAD_ADDRESS;
				break;
			}

			breakpoint = new(std::nothrow) Breakpoint(image, address);
			if (breakpoint == NULL || !fTeam->AddBreakpoint(breakpoint)) {
				delete breakpoint;
				error = B_NO_MEMORY;
				break;
			}
		}

		TRACE_CONTROL("    -> adding instance to breakpoint %p\n", breakpoint);

		breakpoint->AddUserBreakpoint(instance);
		instance->SetBreakpoint(breakpoint);
	}

	// If everything looks good so far mark the user breakpoint according to
	// its new state.
	if (error == B_OK)
		userBreakpoint->SetEnabled(enabled);

	// notify user breakpoint listeners
	if (error == B_OK)
		fTeam->NotifyUserBreakpointChanged(userBreakpoint);

	teamLocker.Unlock();

	// install/uninstall the breakpoints as needed
	TRACE_CONTROL("  updating breakpoints\n");

	if (error == B_OK) {
		for (int32 i = 0;
			UserBreakpointInstance* instance = userBreakpoint->InstanceAt(i);
			i++) {
			TRACE_CONTROL("    breakpoint instance %p\n", instance);

			error = _UpdateBreakpointInstallation(instance->GetBreakpoint());
			if (error != B_OK)
				break;
		}
	}

	if (error == B_OK) {
		TRACE_CONTROL("  success, marking user breakpoint valid\n");

		// everything went fine -- mark the user breakpoint valid
		if (!userBreakpoint->IsValid()) {
			teamLocker.Lock();
			userBreakpoint->SetValid(true);
			userBreakpoint->AcquireReference();
			fTeam->AddUserBreakpoint(userBreakpoint);
			fTeam->NotifyUserBreakpointChanged(userBreakpoint);
				// notify again -- the breakpoint hadn't been added before
			teamLocker.Unlock();
		}
	} else {
		// something went wrong -- revert the situation
		TRACE_CONTROL("  error, reverting\n");

		teamLocker.Lock();
		userBreakpoint->SetEnabled(oldEnabled);
		teamLocker.Unlock();

		if (!oldEnabled || !userBreakpoint->IsValid()) {
			for (int32 i = 0;  UserBreakpointInstance* instance
					= userBreakpoint->InstanceAt(i);
				i++) {
				Breakpoint* breakpoint = instance->GetBreakpoint();
				if (breakpoint == NULL)
					continue;

				if (!userBreakpoint->IsValid()) {
					instance->SetBreakpoint(NULL);
					breakpoint->RemoveUserBreakpoint(instance);
				}

				_UpdateBreakpointInstallation(breakpoint);

				teamLocker.Lock();

				if (breakpoint->IsUnused())
					fTeam->RemoveBreakpoint(breakpoint);
				teamLocker.Unlock();
			}

			teamLocker.Lock();
			fTeam->NotifyUserBreakpointChanged(userBreakpoint);
			teamLocker.Unlock();
		}
	}

	installLocker.Unlock();

	return error;
}
コード例 #10
0
ファイル: ThreadHandler.cpp プロジェクト: mmadia/haiku-1
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();
    }
}
コード例 #11
0
void
TeamDebugger::_HandleSetUserBreakpoint(target_addr_t address, bool enabled)
{
	TRACE_CONTROL("TeamDebugger::_HandleSetUserBreakpoint(%#llx, %d)\n",
		address, enabled);

	// check whether there already is a breakpoint
	AutoLocker< ::Team> locker(fTeam);

	Breakpoint* breakpoint = fTeam->BreakpointAtAddress(address);
	UserBreakpoint* userBreakpoint = NULL;
	if (breakpoint != NULL && breakpoint->FirstUserBreakpoint() != NULL)
		userBreakpoint = breakpoint->FirstUserBreakpoint()->GetUserBreakpoint();
	BReference<UserBreakpoint> userBreakpointReference(userBreakpoint);

	if (userBreakpoint == NULL) {
		TRACE_CONTROL("  no breakpoint yet\n");

		// get the function at the address
		Image* image = fTeam->ImageByAddress(address);

		TRACE_CONTROL("  image: %p\n", image);

		if (image == NULL)
			return;
		ImageDebugInfo* imageDebugInfo = image->GetImageDebugInfo();

		TRACE_CONTROL("  image debug info: %p\n", imageDebugInfo);

		if (imageDebugInfo == NULL)
			return;
			// TODO: Handle this case by loading the debug info, if possible!
		FunctionInstance* functionInstance
			= imageDebugInfo->FunctionAtAddress(address);

		TRACE_CONTROL("  function instance: %p\n", functionInstance);

		if (functionInstance == NULL)
			return;
		Function* function = functionInstance->GetFunction();

		TRACE_CONTROL("  function: %p\n", function);

		// get the source location for the address
		FunctionDebugInfo* functionDebugInfo
			= functionInstance->GetFunctionDebugInfo();
		SourceLocation sourceLocation;
		Statement* breakpointStatement = NULL;
		if (functionDebugInfo->GetSpecificImageDebugInfo()->GetStatement(
				functionDebugInfo, address, breakpointStatement) != B_OK) {
			return;
		}

		sourceLocation = breakpointStatement->StartSourceLocation();
		breakpointStatement->ReleaseReference();

		target_addr_t relativeAddress = address - functionInstance->Address();

		TRACE_CONTROL("  relative address: %#llx, source location: "
			"(%ld, %ld)\n", relativeAddress, sourceLocation.Line(),
			sourceLocation.Column());

		// get function id
		FunctionID* functionID = functionInstance->GetFunctionID();
		if (functionID == NULL)
			return;
		BReference<FunctionID> functionIDReference(functionID, true);

		// create the user breakpoint
		userBreakpoint = new(std::nothrow) UserBreakpoint(
			UserBreakpointLocation(functionID, function->SourceFile(),
				sourceLocation, relativeAddress));
		if (userBreakpoint == NULL)
			return;
		userBreakpointReference.SetTo(userBreakpoint, true);

		TRACE_CONTROL("  created user breakpoint: %p\n", userBreakpoint);

		// iterate through all function instances and create
		// UserBreakpointInstances
		for (FunctionInstanceList::ConstIterator it
					= function->Instances().GetIterator();
				FunctionInstance* instance = it.Next();) {
			TRACE_CONTROL("  function instance %p: range: %#llx - %#llx\n",
				instance, instance->Address(),
				instance->Address() + instance->Size());

			// get the breakpoint address for the instance
			target_addr_t instanceAddress = 0;
			if (instance == functionInstance) {
				instanceAddress = address;
			} else if (functionInstance->SourceFile() != NULL) {
				// We have a source file, so get the address for the source
				// location.
				Statement* statement = NULL;
				functionDebugInfo = instance->GetFunctionDebugInfo();
				functionDebugInfo->GetSpecificImageDebugInfo()
					->GetStatementAtSourceLocation(functionDebugInfo,
						sourceLocation, statement);
				if (statement != NULL) {
					instanceAddress = statement->CoveringAddressRange().Start();
						// TODO: What about BreakpointAllowed()?
					statement->ReleaseReference();
				}
			}

			TRACE_CONTROL("    breakpoint address using source info: %llx\n",
				instanceAddress);

			if (instanceAddress == 0) {
				// No source file (or we failed getting the statement), so try
				// to use the same relative address.
				if (relativeAddress > instance->Size())
					continue;
				instanceAddress = instance->Address() + relativeAddress;
			}

			TRACE_CONTROL("    final breakpoint address: %llx\n",
				instanceAddress);

			UserBreakpointInstance* breakpointInstance = new(std::nothrow)
				UserBreakpointInstance(userBreakpoint, instanceAddress);
			if (breakpointInstance == NULL
				|| !userBreakpoint->AddInstance(breakpointInstance)) {
				delete breakpointInstance;
				return;
			}

			TRACE_CONTROL("  breakpoint instance: %p\n", breakpointInstance);
		}
	}

	locker.Unlock();

	_HandleSetUserBreakpoint(userBreakpoint, enabled);
}