1/*
2 * Copyright 2009-2012, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Copyright 2010-2016, Rene Gollent, rene@gollent.com.
4 * Distributed under the terms of the MIT License.
5 */
6
7
8#include "ThreadHandler.h"
9
10#include <stdio.h>
11
12#include <new>
13
14#include <AutoDeleter.h>
15#include <AutoLocker.h>
16#include <Variant.h>
17
18#include "Architecture.h"
19#include "BreakpointManager.h"
20#include "CpuState.h"
21#include "DebugEvent.h"
22#include "DebuggerInterface.h"
23#include "ExpressionInfo.h"
24#include "FunctionInstance.h"
25#include "ImageDebugInfo.h"
26#include "InstructionInfo.h"
27#include "Jobs.h"
28#include "MessageCodes.h"
29#include "Register.h"
30#include "SignalDispositionTypes.h"
31#include "SourceCode.h"
32#include "SourceLanguage.h"
33#include "SpecificImageDebugInfo.h"
34#include "StackTrace.h"
35#include "Statement.h"
36#include "SyntheticPrimitiveType.h"
37#include "Team.h"
38#include "Tracing.h"
39#include "Value.h"
40#include "ValueLocation.h"
41#include "Worker.h"
42
43
44// step modes
45enum {
46	STEP_NONE,
47	STEP_OVER,
48	STEP_INTO,
49	STEP_OUT,
50	STEP_UNTIL
51};
52
53
54class ExpressionEvaluationListener : public ExpressionInfo::Listener {
55public:
56	ExpressionEvaluationListener(ThreadHandler* handler)
57	:
58	fHandler(handler)
59	{
60		fHandler->AcquireReference();
61	}
62
63	~ExpressionEvaluationListener()
64	{
65		fHandler->ReleaseReference();
66	}
67
68	virtual void ExpressionEvaluated(ExpressionInfo* info, status_t result,
69		ExpressionResult* value)
70	{
71		fHandler->_HandleBreakpointConditionEvaluated(value);
72	}
73
74private:
75	ThreadHandler* fHandler;
76};
77
78
79ThreadHandler::ThreadHandler(::Thread* thread, Worker* worker,
80	DebuggerInterface* debuggerInterface, JobListener* jobListener,
81	BreakpointManager* breakpointManager)
82	:
83	fThread(thread),
84	fWorker(worker),
85	fDebuggerInterface(debuggerInterface),
86	fJobListener(jobListener),
87	fBreakpointManager(breakpointManager),
88	fStepMode(STEP_NONE),
89	fStepStatement(NULL),
90	fBreakpointAddress(0),
91	fSteppedOverFunctionAddress(0),
92	fPreviousInstructionPointer(0),
93	fPreviousFrameAddress(0),
94	fSingleStepping(false),
95	fConditionWaitSem(-1),
96	fConditionResult(NULL)
97{
98	fDebuggerInterface->AcquireReference();
99}
100
101
102ThreadHandler::~ThreadHandler()
103{
104	_ClearContinuationState();
105	fDebuggerInterface->ReleaseReference();
106
107	if (fConditionWaitSem > 0)
108		delete_sem(fConditionWaitSem);
109}
110
111
112void
113ThreadHandler::Init()
114{
115	fWorker->ScheduleJob(new(std::nothrow) GetThreadStateJob(fDebuggerInterface,
116		fThread), fJobListener);
117	fConditionWaitSem = create_sem(0, "breakpoint condition waiter");
118}
119
120
121status_t
122ThreadHandler::SetBreakpointAndRun(target_addr_t address)
123{
124	status_t error = _InstallTemporaryBreakpoint(address);
125	if (error != B_OK)
126		return error;
127
128	fPreviousInstructionPointer = 0;
129	fDebuggerInterface->ContinueThread(ThreadID());
130
131	// Pretend "step out" mode, so that the temporary breakpoint hit will not
132	// be ignored.
133	fStepMode = STEP_OUT;
134	fSingleStepping = false;
135
136	return B_OK;
137}
138
139
140bool
141ThreadHandler::HandleThreadDebugged(ThreadDebuggedEvent* event,
142	const BString& stoppedReason)
143{
144	return _HandleThreadStopped(NULL, THREAD_STOPPED_DEBUGGED, stoppedReason);
145}
146
147
148bool
149ThreadHandler::HandleDebuggerCall(DebuggerCallEvent* event)
150{
151	BString message;
152	fDebuggerInterface->ReadMemoryString(event->Message(), 1024, message);
153	return _HandleThreadStopped(NULL, THREAD_STOPPED_DEBUGGER_CALL, message);
154}
155
156
157bool
158ThreadHandler::HandleBreakpointHit(BreakpointHitEvent* event)
159{
160	CpuState* cpuState = event->GetCpuState();
161	target_addr_t instructionPointer = cpuState->InstructionPointer();
162
163	TRACE_EVENTS("ThreadHandler::HandleBreakpointHit(): ip: %" B_PRIx64 "\n",
164		instructionPointer);
165
166	// check whether this is a temporary breakpoint we're waiting for
167	if (fBreakpointAddress != 0 && instructionPointer == fBreakpointAddress
168		&& fStepMode != STEP_NONE) {
169		if (fStepMode != STEP_UNTIL && _HandleBreakpointHitStep(cpuState))
170			return true;
171	} else {
172		// Might be a user breakpoint, but could as well be a temporary
173		// breakpoint of another thread.
174		AutoLocker<Team> locker(fThread->GetTeam());
175		Breakpoint* breakpoint = fThread->GetTeam()->BreakpointAtAddress(
176			cpuState->InstructionPointer());
177		bool continueThread = false;
178		if (breakpoint == NULL) {
179			// spurious breakpoint -- might be a temporary breakpoint, that has
180			// already been uninstalled
181			continueThread = true;
182		} else if (!breakpoint->HasEnabledUserBreakpoint()) {
183			// breakpoint of another thread or one that has been disabled in
184			// the meantime
185			continueThread = true;
186		}
187
188		if (continueThread) {
189			if (fSingleStepping) {
190				// We might have hit a just-installed software breakpoint and
191				// thus haven't stepped at all. Just try again.
192				if (fPreviousInstructionPointer == instructionPointer) {
193					fDebuggerInterface->SingleStepThread(ThreadID());
194					return true;
195				}
196
197				// That shouldn't happen. Try something reasonable anyway.
198				if (fStepMode != STEP_NONE) {
199					if (_HandleSingleStepStep(cpuState))
200						return true;
201				}
202			}
203
204			return false;
205		} else {
206			locker.Unlock();
207			if (_HandleBreakpointConditionIfNeeded(cpuState))
208				return true;
209
210			locker.Lock();
211		}
212	}
213
214	return _HandleThreadStopped(cpuState, THREAD_STOPPED_BREAKPOINT);
215}
216
217
218bool
219ThreadHandler::HandleWatchpointHit(WatchpointHitEvent* event)
220{
221	return _HandleThreadStopped(event->GetCpuState(),
222		THREAD_STOPPED_WATCHPOINT);
223}
224
225
226bool
227ThreadHandler::HandleSingleStep(SingleStepEvent* event)
228{
229	// Check whether we're stepping automatically.
230	if (fStepMode != STEP_NONE) {
231		if (_HandleSingleStepStep(event->GetCpuState()))
232			return true;
233	}
234
235	return _HandleThreadStopped(event->GetCpuState(),
236		THREAD_STOPPED_SINGLE_STEP);
237}
238
239
240bool
241ThreadHandler::HandleExceptionOccurred(ExceptionOccurredEvent* event)
242{
243	char buffer[256];
244	get_debug_exception_string(event->Exception(), buffer, sizeof(buffer));
245	return _HandleThreadStopped(NULL, THREAD_STOPPED_EXCEPTION, buffer);
246}
247
248
249bool
250ThreadHandler::HandleSignalReceived(SignalReceivedEvent* event)
251{
252	::Team* team = fThread->GetTeam();
253	AutoLocker<Team> locker(team);
254
255	const SignalInfo& info = event->GetSignalInfo();
256	int32 signal = info.Signal();
257	int32 disposition = team->SignalDispositionFor(signal);
258
259	switch (disposition) {
260		case SIGNAL_DISPOSITION_IGNORE:
261			return false;
262		case SIGNAL_DISPOSITION_STOP_AT_SIGNAL_HANDLER:
263		{
264			const struct sigaction& handlerInfo = info.Handler();
265			target_addr_t address = 0;
266			if ((handlerInfo.sa_flags & SA_SIGINFO) != 0)
267				address = (target_addr_t)handlerInfo.sa_sigaction;
268			else
269				address = (target_addr_t)handlerInfo.sa_handler;
270
271			if (address == (target_addr_t)SIG_DFL
272				|| address == (target_addr_t)SIG_IGN
273				|| address == (target_addr_t)SIG_HOLD) {
274				address = 0;
275			}
276
277			if (address != 0 && _InstallTemporaryBreakpoint(address) == B_OK
278				&& fDebuggerInterface->ContinueThread(ThreadID()) == B_OK) {
279				fStepMode = STEP_UNTIL;
280				return true;
281			}
282
283			// fall through if no handler or if we failed to
284			// set a breakpoint at the handler
285		}
286		case SIGNAL_DISPOSITION_STOP_AT_RECEIPT:
287		{
288			BString stopReason;
289			stopReason.SetToFormat("Received signal %" B_PRId32 " (%s)",
290				signal, strsignal(signal));
291			return _HandleThreadStopped(NULL, THREAD_STOPPED_DEBUGGED,
292				stopReason);
293		}
294		default:
295			break;
296	}
297
298	return false;
299}
300
301
302void
303ThreadHandler::HandleThreadAction(uint32 action, target_addr_t address)
304{
305	AutoLocker<Team> locker(fThread->GetTeam());
306
307	if (fThread->State() == THREAD_STATE_UNKNOWN)
308		return;
309
310	// When stop is requested, thread must be running, otherwise stopped.
311	if (action == MSG_THREAD_STOP
312			? fThread->State() != THREAD_STATE_RUNNING
313			: fThread->State() != THREAD_STATE_STOPPED) {
314		return;
315	}
316
317	// When stepping we need a stack trace. Save it before unsetting the state.
318	CpuState* cpuState = fThread->GetCpuState();
319	StackTrace* stackTrace = fThread->GetStackTrace();
320	BReference<CpuState> cpuStateReference(cpuState);
321	BReference<StackTrace> stackTraceReference(stackTrace);
322
323	if (action == MSG_THREAD_SET_ADDRESS) {
324		_HandleSetAddress(cpuState, address);
325		return;
326	}
327
328	// When continuing the thread update thread state before actually issuing
329	// the command, since we need to unlock.
330	if (action != MSG_THREAD_STOP) {
331		_SetThreadState(THREAD_STATE_RUNNING, NULL, THREAD_STOPPED_UNKNOWN,
332			BString());
333	}
334
335	locker.Unlock();
336
337	switch (action) {
338		case MSG_THREAD_RUN:
339			fStepMode = address != 0 ? STEP_UNTIL : STEP_NONE;
340			if (address != 0)
341				_InstallTemporaryBreakpoint(address);
342			_RunThread(0);
343			return;
344		case MSG_THREAD_STOP:
345			fStepMode = STEP_NONE;
346			if (fDebuggerInterface->StopThread(ThreadID()) == B_OK)
347				fThread->SetStopRequestPending();
348			return;
349		case MSG_THREAD_STEP_OVER:
350		case MSG_THREAD_STEP_INTO:
351		case MSG_THREAD_STEP_OUT:
352			break;
353	}
354
355	TRACE_CONTROL("ThreadHandler::HandleThreadAction(MSG_THREAD_STEP_*)\n");
356
357	// We want to step. We need a stack trace for that purpose. If we don't
358	// have one yet, get it. Start with the CPU state.
359	if (stackTrace == NULL && cpuState == NULL) {
360		if (fDebuggerInterface->GetCpuState(fThread->ID(), cpuState) == B_OK)
361			cpuStateReference.SetTo(cpuState, true);
362	}
363
364	if (stackTrace == NULL && cpuState != NULL) {
365		if (fDebuggerInterface->GetArchitecture()->CreateStackTrace(
366				fThread->GetTeam(), this, cpuState, stackTrace, NULL, 1,
367				false, false) == B_OK) {
368			stackTraceReference.SetTo(stackTrace, true);
369		}
370	}
371
372	if (stackTrace == NULL || stackTrace->CountFrames() == 0) {
373		_StepFallback();
374		return;
375	}
376
377	StackFrame* frame = stackTrace->FrameAt(0);
378
379	TRACE_CONTROL("  ip: %#" B_PRIx64 "\n", frame->InstructionPointer());
380
381	target_addr_t frameIP = frame->GetCpuState()->InstructionPointer();
382	// When the thread is in a syscall, do the same for all step kinds: Stop it
383	// when it returns by means of a breakpoint.
384	if (frame->Type() == STACK_FRAME_TYPE_SYSCALL) {
385		// set a breakpoint at the CPU state's instruction pointer (points to
386		// the return address, unlike the stack frame's instruction pointer)
387// TODO: This is doesn't work correctly anymore. When stepping over a "syscall"
388// instruction the thread is stopped twice. The after the first step the PC is
389// incorrectly shown at the "syscall" instruction. Then we step again and are
390// stopped at the temporary breakpoint after the "syscall" instruction. There
391// are two problems. The first one is that we don't (cannot?) discriminate
392// between the thread being in a syscall (like in a blocking syscall) and the
393// thread having been stopped (or singled-stepped) at the end of the syscall.
394// The second issue is that the temporary breakpoint is probably not necessary
395// anymore, since single-stepping over "syscall" instructions should just work
396// as expected.
397		status_t error = _InstallTemporaryBreakpoint(frameIP);
398		if (error != B_OK) {
399			_StepFallback();
400			return;
401		}
402
403		fStepMode = STEP_OUT;
404		_RunThread(frameIP);
405		return;
406	}
407
408	// For "step out" just set a temporary breakpoint on the return address.
409	if (action == MSG_THREAD_STEP_OUT) {
410		status_t error = _InstallTemporaryBreakpoint(frame->ReturnAddress());
411		if (error != B_OK) {
412			_StepFallback();
413			return;
414		}
415		fPreviousInstructionPointer = frameIP;
416		fPreviousFrameAddress = frame->FrameAddress();
417		fStepMode = STEP_OUT;
418		_RunThread(frameIP);
419		return;
420	}
421
422	// For "step in" and "step over" we also need the source code statement at
423	// the current instruction pointer.
424	fStepStatement = _GetStatementAtInstructionPointer(frame);
425	if (fStepStatement == NULL) {
426		_StepFallback();
427		return;
428	}
429
430	TRACE_CONTROL("  statement: %#" B_PRIx64 " - %#" B_PRIx64 "\n",
431		fStepStatement->CoveringAddressRange().Start(),
432		fStepStatement->CoveringAddressRange().End());
433
434	if (action == MSG_THREAD_STEP_INTO) {
435		// step into
436		fStepMode = STEP_INTO;
437		_SingleStepThread(frameIP);
438	} else {
439		fPreviousFrameAddress = frame->FrameAddress();
440		// step over
441		fStepMode = STEP_OVER;
442		if (!_DoStepOver(frame->GetCpuState()))
443			_StepFallback();
444	}
445}
446
447
448void
449ThreadHandler::HandleThreadStateChanged()
450{
451	AutoLocker<Team> locker(fThread->GetTeam());
452
453	// cancel jobs for this thread
454	fWorker->AbortJob(SimpleJobKey(fThread, JOB_TYPE_GET_CPU_STATE));
455	fWorker->AbortJob(SimpleJobKey(fThread, JOB_TYPE_GET_STACK_TRACE));
456
457	// If the thread is stopped and has no CPU state yet, schedule a job.
458	if (fThread->State() == THREAD_STATE_STOPPED
459			&& fThread->GetCpuState() == NULL) {
460		fWorker->ScheduleJob(
461			new(std::nothrow) GetCpuStateJob(fDebuggerInterface, fThread),
462			fJobListener);
463	}
464}
465
466
467void
468ThreadHandler::HandleCpuStateChanged()
469{
470	AutoLocker<Team> locker(fThread->GetTeam());
471
472	// cancel stack trace job for this thread
473	fWorker->AbortJob(SimpleJobKey(fThread, JOB_TYPE_GET_STACK_TRACE));
474
475	// If the thread has a CPU state, but no stack trace yet, schedule a job.
476	if (fThread->GetCpuState() != NULL && fThread->GetStackTrace() == NULL) {
477		fWorker->ScheduleJob(
478			new(std::nothrow) GetStackTraceJob(fDebuggerInterface,
479				fJobListener, fDebuggerInterface->GetArchitecture(),
480				fThread), fJobListener);
481	}
482}
483
484
485void
486ThreadHandler::HandleStackTraceChanged()
487{
488}
489
490
491status_t
492ThreadHandler::GetImageDebugInfo(Image* image, ImageDebugInfo*& _info)
493{
494	AutoLocker<Team> teamLocker(fThread->GetTeam());
495
496	if (image->GetImageDebugInfo() != NULL) {
497		_info = image->GetImageDebugInfo();
498		_info->AcquireReference();
499		return B_OK;
500	}
501
502	// Let's be lazy. If the image debug info has not been loaded yet, the user
503	// can't have seen any source code either.
504	return B_ENTRY_NOT_FOUND;
505}
506
507
508bool
509ThreadHandler::_HandleThreadStopped(CpuState* cpuState, uint32 stoppedReason,
510	const BString& stoppedReasonInfo)
511{
512	_ClearContinuationState();
513
514	AutoLocker<Team> locker(fThread->GetTeam());
515
516	_SetThreadState(THREAD_STATE_STOPPED, cpuState, stoppedReason,
517		stoppedReasonInfo);
518
519	return true;
520}
521
522
523bool
524ThreadHandler::_HandleSetAddress(CpuState* state, target_addr_t address)
525{
526	CpuState* newState = NULL;
527	if (state->Clone(newState) != B_OK)
528		return false;
529	BReference<CpuState> stateReference(newState, true);
530
531	newState->SetInstructionPointer(address);
532	if (fDebuggerInterface->SetCpuState(fThread->ID(), newState) != B_OK)
533		return false;
534
535	AutoLocker<Team> locker(fThread->GetTeam());
536	fThread->SetStackTrace(NULL);
537	fThread->SetCpuState(newState);
538
539	return true;
540}
541
542
543void
544ThreadHandler::_SetThreadState(uint32 state, CpuState* cpuState,
545	uint32 stoppedReason, const BString& stoppedReasonInfo)
546{
547	fThread->SetState(state, stoppedReason, stoppedReasonInfo);
548	fThread->SetCpuState(cpuState);
549}
550
551
552Statement*
553ThreadHandler::_GetStatementAtInstructionPointer(StackFrame* frame)
554{
555	AutoLocker<Team> locker(fThread->GetTeam());
556
557	FunctionInstance* functionInstance = frame->Function();
558	if (functionInstance == NULL)
559		return NULL;
560	FunctionDebugInfo* function = functionInstance->GetFunctionDebugInfo();
561
562	// If there's source code attached to the function, we can just get the
563	// statement.
564//	SourceCode* sourceCode = function->GetSourceCode();
565//	if (sourceCode != NULL) {
566//		Statement* statement = sourceCode->StatementAtAddress(
567//			frame->InstructionPointer());
568//		if (statement != NULL)
569//			statement->AcquireReference();
570//		return statement;
571//	}
572
573	locker.Unlock();
574
575	// We need to get the statement from the debug info of the function.
576	Statement* statement;
577	if (function->GetSpecificImageDebugInfo()->GetStatement(function,
578			frame->InstructionPointer(), statement) != B_OK) {
579		return NULL;
580	}
581
582	return statement;
583}
584
585
586void
587ThreadHandler::_StepFallback()
588{
589	fStepMode = STEP_NONE;
590	_SingleStepThread(0);
591}
592
593
594bool
595ThreadHandler::_DoStepOver(CpuState* cpuState)
596{
597	TRACE_CONTROL("ThreadHandler::_DoStepOver()\n");
598
599	// The basic strategy is to single-step out of the statement like for
600	// "step into", only we have to avoid stepping into subroutines. Hence we
601	// check whether the current instruction is a subroutine call. If not, we
602	// just single-step, otherwise we set a breakpoint after the instruction.
603	InstructionInfo info;
604	if (fDebuggerInterface->GetArchitecture()->GetInstructionInfo(
605			cpuState->InstructionPointer(), info, cpuState) != B_OK) {
606		TRACE_CONTROL("  failed to get instruction info\n");
607		return false;
608	}
609
610	if (info.Type() != INSTRUCTION_TYPE_SUBROUTINE_CALL) {
611		_SingleStepThread(cpuState->InstructionPointer());
612
613		TRACE_CONTROL("  not a subroutine call\n");
614		return true;
615	}
616
617	TRACE_CONTROL("  subroutine call -- installing breakpoint at address "
618		"%#" B_PRIx64 "\n", info.Address() + info.Size());
619
620	if (_InstallTemporaryBreakpoint(info.Address() + info.Size()) != B_OK)
621		return false;
622
623	fSteppedOverFunctionAddress = info.TargetAddress();
624
625	_RunThread(cpuState->InstructionPointer());
626	return true;
627}
628
629
630status_t
631ThreadHandler::_InstallTemporaryBreakpoint(target_addr_t address)
632{
633	_UninstallTemporaryBreakpoint();
634
635	status_t error = fBreakpointManager->InstallTemporaryBreakpoint(address,
636		this);
637	if (error != B_OK)
638		return error;
639
640	fBreakpointAddress = address;
641	return B_OK;
642}
643
644
645void
646ThreadHandler::_UninstallTemporaryBreakpoint()
647{
648	if (fBreakpointAddress == 0)
649		return;
650
651	fBreakpointManager->UninstallTemporaryBreakpoint(fBreakpointAddress, this);
652	fBreakpointAddress = 0;
653}
654
655
656void
657ThreadHandler::_ClearContinuationState()
658{
659	_UninstallTemporaryBreakpoint();
660
661	if (fStepStatement != NULL) {
662		fStepStatement->ReleaseReference();
663		fStepStatement = NULL;
664	}
665
666	fStepMode = STEP_NONE;
667	fSingleStepping = false;
668}
669
670
671void
672ThreadHandler::_RunThread(target_addr_t instructionPointer)
673{
674	fPreviousInstructionPointer = instructionPointer;
675	fDebuggerInterface->ContinueThread(ThreadID());
676	fSingleStepping = false;
677}
678
679
680void
681ThreadHandler::_SingleStepThread(target_addr_t instructionPointer)
682{
683	fPreviousInstructionPointer = instructionPointer;
684	fDebuggerInterface->SingleStepThread(ThreadID());
685	fSingleStepping = true;
686}
687
688
689bool
690ThreadHandler::_HandleBreakpointHitStep(CpuState* cpuState)
691{
692	// in any case uninstall the temporary breakpoint
693	_UninstallTemporaryBreakpoint();
694
695	switch (fStepMode) {
696		case STEP_OVER:
697		{
698			StackTrace* stackTrace = fThread->GetStackTrace();
699			BReference<StackTrace> stackTraceReference(stackTrace);
700
701			if (stackTrace == NULL && cpuState != NULL) {
702				if (fDebuggerInterface->GetArchitecture()->CreateStackTrace(
703						fThread->GetTeam(), this, cpuState, stackTrace, NULL,
704						1, false, false) == B_OK) {
705					stackTraceReference.SetTo(stackTrace, true);
706				}
707			}
708			if (stackTrace != NULL) {
709				StackFrame* frame = stackTrace->FrameAt(0);
710				// If we're not in the same frame we started in,
711				// keep executing.
712				if (frame != NULL && fPreviousFrameAddress
713						!= frame->FrameAddress()) {
714					status_t error = _InstallTemporaryBreakpoint(
715						cpuState->InstructionPointer());
716					if (error != B_OK)
717						_StepFallback();
718					else
719						_RunThread(cpuState->InstructionPointer());
720					return true;
721				}
722			}
723
724			if (fPreviousFrameAddress != 0 && fSteppedOverFunctionAddress != 0
725					&& fSteppedOverFunctionAddress != cpuState->InstructionPointer()) {
726				TRACE_CONTROL("STEP_OVER: called function address %#" B_PRIx64
727					", previous frame address: %#" B_PRIx64 ", frame address: %#"
728					B_PRIx64 ", adding return info\n", fSteppedOverFunctionAddress,
729					fPreviousFrameAddress, stackTrace->FrameAt(0)->FrameAddress());
730				ReturnValueInfo* returnInfo = new(std::nothrow) ReturnValueInfo(
731					fSteppedOverFunctionAddress, cpuState);
732				if (returnInfo == NULL)
733					return false;
734
735				BReference<ReturnValueInfo> returnInfoReference(returnInfo, true);
736
737				if (fThread->AddReturnValueInfo(returnInfo) != B_OK)
738					return false;
739
740				returnInfoReference.Detach();
741				fSteppedOverFunctionAddress = 0;
742			}
743
744			// If we're still in the statement, we continue single-stepping,
745			// otherwise we're done.
746			if (fStepStatement->ContainsAddress(
747					cpuState->InstructionPointer())) {
748				if (!_DoStepOver(cpuState))
749					_StepFallback();
750				return true;
751			}
752			fPreviousFrameAddress = 0;
753			return false;
754		}
755
756		case STEP_INTO:
757			// Should never happen -- we don't set a breakpoint in this case.
758			return false;
759
760		case STEP_OUT:
761		{
762			// That's the return address, so we're done in theory,
763			// unless we're a recursive function. Check if we've actually
764			// exited the previous stack frame or not
765			if (!_HasExitedFrame(cpuState->StackFramePointer())) {
766				status_t error = _InstallTemporaryBreakpoint(
767					cpuState->InstructionPointer());
768				if (error != B_OK)
769					_StepFallback();
770				else
771					_RunThread(cpuState->InstructionPointer());
772				return true;
773			}
774
775			if (fPreviousFrameAddress == 0)
776				return false;
777
778			TRACE_CONTROL("ThreadHandler::_HandleBreakpointHitStep() - "
779				"frame pointer 0x%#" B_PRIx64 ", previous: 0x%#" B_PRIx64
780				" - step out adding return value\n", cpuState
781					->StackFramePointer(), fPreviousFrameAddress);
782			ReturnValueInfo* info = new(std::nothrow) ReturnValueInfo(
783				fPreviousInstructionPointer, cpuState);
784			if (info == NULL)
785				return false;
786			BReference<ReturnValueInfo> infoReference(info, true);
787			if (fThread->AddReturnValueInfo(info) != B_OK)
788				return false;
789
790			infoReference.Detach();
791			fPreviousFrameAddress = 0;
792		}
793
794		default:
795			return false;
796	}
797}
798
799
800bool
801ThreadHandler::_HandleSingleStepStep(CpuState* cpuState)
802{
803	TRACE_CONTROL("ThreadHandler::_HandleSingleStepStep(): ip: %" B_PRIx64 "\n",
804		cpuState->InstructionPointer());
805
806	switch (fStepMode) {
807		case STEP_INTO:
808		{
809			// We continue stepping as long as we're in the statement.
810			if (fStepStatement->ContainsAddress(cpuState->InstructionPointer())) {
811				_SingleStepThread(cpuState->InstructionPointer());
812				return true;
813			}
814
815			StackTrace* stackTrace = fThread->GetStackTrace();
816			BReference<StackTrace> stackTraceReference(stackTrace);
817
818			if (stackTrace == NULL && cpuState != NULL) {
819				if (fDebuggerInterface->GetArchitecture()->CreateStackTrace(
820						fThread->GetTeam(), this, cpuState, stackTrace, NULL,
821						1, false, false) == B_OK) {
822					stackTraceReference.SetTo(stackTrace, true);
823				}
824			}
825
826			if (stackTrace != NULL) {
827				StackFrame* frame = stackTrace->FrameAt(0);
828				Image* image = frame->GetImage();
829				if (image == NULL)
830					return false;
831
832				ImageDebugInfo* info = NULL;
833				if (GetImageDebugInfo(image, info) != B_OK)
834					return false;
835
836				BReference<ImageDebugInfo>(info, true);
837				if (info->GetAddressSectionType(
838						cpuState->InstructionPointer())
839						== ADDRESS_SECTION_TYPE_PLT) {
840					_SingleStepThread(cpuState->InstructionPointer());
841					return true;
842				}
843			}
844			return false;
845		}
846
847		case STEP_OVER:
848		{
849			// If we have stepped out of the statement, we're done.
850			if (!fStepStatement->ContainsAddress(cpuState->InstructionPointer())) {
851				StackTrace* stackTrace = fThread->GetStackTrace();
852				BReference<StackTrace> stackTraceReference(stackTrace);
853				if (stackTrace == NULL && cpuState != NULL) {
854					if (fDebuggerInterface->GetArchitecture()->CreateStackTrace(
855							fThread->GetTeam(), this, cpuState, stackTrace,
856							NULL, 1, false, false) == B_OK) {
857						stackTraceReference.SetTo(stackTrace, true);
858					}
859				}
860
861
862				if (stackTrace != NULL) {
863					if (_HasExitedFrame(stackTrace->FrameAt(0)
864						->FrameAddress())) {
865						TRACE_CONTROL("ThreadHandler::_HandleSingleStepStep() "
866							" - adding return value for STEP_OVER\n");
867						ReturnValueInfo* info = new(std::nothrow)
868							ReturnValueInfo(fStepStatement
869								->CoveringAddressRange().Start(), cpuState);
870						if (info == NULL)
871							return false;
872						BReference<ReturnValueInfo> infoReference(info, true);
873						if (fThread->AddReturnValueInfo(info) != B_OK)
874							return false;
875
876						infoReference.Detach();
877					}
878				}
879				return false;
880			}
881			return _DoStepOver(cpuState);
882		}
883
884		case STEP_OUT:
885			// We never single-step in this case.
886		default:
887			return false;
888	}
889}
890
891
892bool
893ThreadHandler::_HandleBreakpointConditionIfNeeded(CpuState* cpuState)
894{
895	AutoLocker< ::Team> teamLocker(fThread->GetTeam());
896	Breakpoint* breakpoint = fThread->GetTeam()->BreakpointAtAddress(
897		cpuState->InstructionPointer());
898
899	if (breakpoint == NULL)
900		return false;
901
902	if (!breakpoint->HasEnabledUserBreakpoint())
903		return false;
904
905	const UserBreakpointInstanceList& breakpoints
906		= breakpoint->UserBreakpoints();
907
908	for (UserBreakpointInstanceList::ConstIterator it
909			= breakpoints.GetIterator(); it.HasNext();) {
910		UserBreakpoint* userBreakpoint = it.Next()->GetUserBreakpoint();
911		if (!userBreakpoint->IsValid())
912			continue;
913		if (!userBreakpoint->IsEnabled())
914			continue;
915		if (!userBreakpoint->HasCondition())
916			continue;
917
918		StackTrace* stackTrace = fThread->GetStackTrace();
919		BReference<StackTrace> stackTraceReference;
920		if (stackTrace == NULL) {
921			if (fDebuggerInterface->GetArchitecture()->CreateStackTrace(
922				fThread->GetTeam(), this, cpuState, stackTrace, NULL, 1,
923				false, true) == B_OK) {
924				stackTraceReference.SetTo(stackTrace, true);
925			} else
926				return false;
927		}
928
929		StackFrame* frame = stackTrace->FrameAt(0);
930		FunctionDebugInfo* info = frame->Function()->GetFunctionDebugInfo();
931		if (info == NULL)
932			return false;
933
934		SpecificImageDebugInfo* specificInfo
935			= info->GetSpecificImageDebugInfo();
936		if (specificInfo == NULL)
937			return false;
938
939		SourceLanguage* language;
940		if (specificInfo->GetSourceLanguage(info, language) != B_OK)
941			return false;
942
943		BReference<SourceLanguage> reference(language, true);
944		ExpressionEvaluationListener* listener
945			= new(std::nothrow) ExpressionEvaluationListener(this);
946		if (listener == NULL)
947			return false;
948
949		ExpressionInfo* expressionInfo = new(std::nothrow) ExpressionInfo(
950			userBreakpoint->Condition());
951
952		if (expressionInfo == NULL) {
953			delete listener;
954			return false;
955		}
956
957		BReference<ExpressionInfo> expressionReference(expressionInfo, true);
958
959		expressionInfo->AddListener(listener);
960
961		status_t error = fWorker->ScheduleJob(
962			new(std::nothrow) ExpressionEvaluationJob(fThread->GetTeam(),
963				fDebuggerInterface, language, expressionInfo, frame, fThread),
964			fJobListener);
965
966		BPrivate::ObjectDeleter<ExpressionEvaluationListener> deleter(
967			listener);
968		if (error == B_OK) {
969			teamLocker.Unlock();
970			do {
971				error = acquire_sem(fConditionWaitSem);
972			} while (error == B_INTERRUPTED);
973
974			teamLocker.Lock();
975
976			if (_CheckStopCondition()) {
977				if (fConditionResult != NULL) {
978					fConditionResult->ReleaseReference();
979					fConditionResult = NULL;
980				}
981				_SetThreadState(THREAD_STATE_STOPPED, cpuState,
982					THREAD_STOPPED_BREAKPOINT, BString());
983				return false;
984			} else {
985				fDebuggerInterface->ContinueThread(ThreadID());
986				return true;
987			}
988		}
989	}
990
991	return false;
992}
993
994
995void
996ThreadHandler::_HandleBreakpointConditionEvaluated(ExpressionResult* value)
997{
998	fConditionResult = value;
999	if (fConditionResult != NULL)
1000		fConditionResult->AcquireReference();
1001	release_sem(fConditionWaitSem);
1002}
1003
1004
1005bool
1006ThreadHandler::_CheckStopCondition()
1007{
1008	// if we we're unable to properly assess the expression result
1009	// in any way, fall back to behaving like an unconditional breakpoint.
1010	if (fConditionResult == NULL)
1011		return true;
1012
1013	if (fConditionResult->Kind() != EXPRESSION_RESULT_KIND_PRIMITIVE)
1014		return true;
1015
1016	BVariant value;
1017	if (!fConditionResult->PrimitiveValue()->ToVariant(value))
1018		return true;
1019
1020	return value.ToBool();
1021}
1022
1023
1024bool
1025ThreadHandler::_HasExitedFrame(target_addr_t framePointer) const
1026{
1027	return fDebuggerInterface->GetArchitecture()->StackGrowthDirection()
1028			== STACK_GROWTH_DIRECTION_POSITIVE
1029				? framePointer < fPreviousFrameAddress
1030				: framePointer > fPreviousFrameAddress;
1031}
1032