1/*
2 * Copyright 2005-2016, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Copyright 2015, Rene Gollent, rene@gollent.com.
4 * Distributed under the terms of the MIT License.
5 */
6
7
8#include <errno.h>
9#include <signal.h>
10#include <stdlib.h>
11#include <stdio.h>
12#include <string.h>
13
14#include <algorithm>
15
16#include <arch/debug.h>
17#include <arch/user_debugger.h>
18#include <core_dump.h>
19#include <cpu.h>
20#include <debugger.h>
21#include <kernel.h>
22#include <KernelExport.h>
23#include <kscheduler.h>
24#include <ksignal.h>
25#include <ksyscalls.h>
26#include <port.h>
27#include <sem.h>
28#include <team.h>
29#include <thread.h>
30#include <thread_types.h>
31#include <user_debugger.h>
32#include <vm/vm.h>
33#include <vm/vm_types.h>
34
35#include <AutoDeleter.h>
36#include <util/AutoLock.h>
37#include <util/ThreadAutoLock.h>
38
39#include "BreakpointManager.h"
40
41
42//#define TRACE_USER_DEBUGGER
43#ifdef TRACE_USER_DEBUGGER
44#	define TRACE(x) dprintf x
45#else
46#	define TRACE(x) ;
47#endif
48
49
50// TODO: Since the introduction of team_debug_info::debugger_changed_condition
51// there's some potential for simplifications. E.g. clear_team_debug_info() and
52// destroy_team_debug_info() are now only used in nub_thread_cleanup() (plus
53// arch_clear_team_debug_info() in install_team_debugger_init_debug_infos()).
54
55
56static port_id sDefaultDebuggerPort = -1;
57	// accessed atomically
58
59static timer sProfilingTimers[SMP_MAX_CPUS];
60	// a profiling timer for each CPU -- used when a profiled thread is running
61	// on that CPU
62
63
64static void schedule_profiling_timer(Thread* thread, bigtime_t interval);
65static int32 profiling_event(timer* unused);
66static status_t ensure_debugger_installed();
67static void get_team_debug_info(team_debug_info &teamDebugInfo);
68
69
70static inline status_t
71kill_interruptable_write_port(port_id port, int32 code, const void *buffer,
72	size_t bufferSize)
73{
74	return write_port_etc(port, code, buffer, bufferSize, B_KILL_CAN_INTERRUPT,
75		0);
76}
77
78
79static status_t
80debugger_write(port_id port, int32 code, const void *buffer, size_t bufferSize,
81	bool dontWait)
82{
83	TRACE(("debugger_write(): thread: %" B_PRId32 ", team %" B_PRId32 ", "
84		"port: %" B_PRId32 ", code: %" B_PRIx32 ", message: %p, size: %lu, "
85		"dontWait: %d\n", thread_get_current_thread()->id,
86		thread_get_current_thread()->team->id, port, code, buffer, bufferSize,
87		dontWait));
88
89	status_t error = B_OK;
90
91	// get the team debug info
92	team_debug_info teamDebugInfo;
93	get_team_debug_info(teamDebugInfo);
94	sem_id writeLock = teamDebugInfo.debugger_write_lock;
95
96	// get the write lock
97	TRACE(("debugger_write(): acquiring write lock...\n"));
98	error = acquire_sem_etc(writeLock, 1,
99		dontWait ? (uint32)B_RELATIVE_TIMEOUT : (uint32)B_KILL_CAN_INTERRUPT, 0);
100	if (error != B_OK) {
101		TRACE(("debugger_write() done1: %" B_PRIx32 "\n", error));
102		return error;
103	}
104
105	// re-get the team debug info
106	get_team_debug_info(teamDebugInfo);
107
108	if (teamDebugInfo.debugger_port != port
109		|| (teamDebugInfo.flags & B_TEAM_DEBUG_DEBUGGER_HANDOVER)) {
110		// The debugger has changed in the meantime or we are about to be
111		// handed over to a new debugger. In either case we don't send the
112		// message.
113		TRACE(("debugger_write(): %s\n",
114			(teamDebugInfo.debugger_port != port ? "debugger port changed"
115				: "handover flag set")));
116	} else {
117		TRACE(("debugger_write(): writing to port...\n"));
118
119		error = write_port_etc(port, code, buffer, bufferSize,
120			dontWait ? (uint32)B_RELATIVE_TIMEOUT : (uint32)B_KILL_CAN_INTERRUPT, 0);
121	}
122
123	// release the write lock
124	release_sem(writeLock);
125
126	TRACE(("debugger_write() done: %" B_PRIx32 "\n", error));
127
128	return error;
129}
130
131
132/*!	Updates the thread::flags field according to what user debugger flags are
133	set for the thread.
134	Interrupts must be disabled and the thread's debug info lock must be held.
135*/
136static void
137update_thread_user_debug_flag(Thread* thread)
138{
139	if ((atomic_get(&thread->debug_info.flags) & B_THREAD_DEBUG_STOP) != 0)
140		atomic_or(&thread->flags, THREAD_FLAGS_DEBUG_THREAD);
141	else
142		atomic_and(&thread->flags, ~THREAD_FLAGS_DEBUG_THREAD);
143}
144
145
146/*!	Updates the thread::flags THREAD_FLAGS_BREAKPOINTS_DEFINED bit of the
147	given thread.
148	Interrupts must be disabled and the thread debug info lock must be held.
149*/
150static void
151update_thread_breakpoints_flag(Thread* thread)
152{
153	Team* team = thread->team;
154
155	if (arch_has_breakpoints(&team->debug_info.arch_info))
156		atomic_or(&thread->flags, THREAD_FLAGS_BREAKPOINTS_DEFINED);
157	else
158		atomic_and(&thread->flags, ~THREAD_FLAGS_BREAKPOINTS_DEFINED);
159}
160
161
162/*!	Updates the Thread::flags THREAD_FLAGS_BREAKPOINTS_DEFINED bit of all
163	threads of the current team.
164*/
165static void
166update_threads_breakpoints_flag()
167{
168	Team* team = thread_get_current_thread()->team;
169
170	TeamLocker teamLocker(team);
171
172	Thread* thread = team->thread_list;
173
174	if (arch_has_breakpoints(&team->debug_info.arch_info)) {
175		for (; thread != NULL; thread = thread->team_next)
176			atomic_or(&thread->flags, THREAD_FLAGS_BREAKPOINTS_DEFINED);
177	} else {
178		for (; thread != NULL; thread = thread->team_next)
179			atomic_and(&thread->flags, ~THREAD_FLAGS_BREAKPOINTS_DEFINED);
180	}
181}
182
183
184/*!	Updates the thread::flags B_TEAM_DEBUG_DEBUGGER_INSTALLED bit of the
185	given thread, which must be the current thread.
186*/
187static void
188update_thread_debugger_installed_flag(Thread* thread)
189{
190	Team* team = thread->team;
191
192	if (atomic_get(&team->debug_info.flags) & B_TEAM_DEBUG_DEBUGGER_INSTALLED)
193		atomic_or(&thread->flags, THREAD_FLAGS_DEBUGGER_INSTALLED);
194	else
195		atomic_and(&thread->flags, ~THREAD_FLAGS_DEBUGGER_INSTALLED);
196}
197
198
199/*!	Updates the thread::flags THREAD_FLAGS_DEBUGGER_INSTALLED bit of all
200	threads of the given team.
201	The team's lock must be held.
202*/
203static void
204update_threads_debugger_installed_flag(Team* team)
205{
206	Thread* thread = team->thread_list;
207
208	if (atomic_get(&team->debug_info.flags) & B_TEAM_DEBUG_DEBUGGER_INSTALLED) {
209		for (; thread != NULL; thread = thread->team_next)
210			atomic_or(&thread->flags, THREAD_FLAGS_DEBUGGER_INSTALLED);
211	} else {
212		for (; thread != NULL; thread = thread->team_next)
213			atomic_and(&thread->flags, ~THREAD_FLAGS_DEBUGGER_INSTALLED);
214	}
215}
216
217
218/**
219 *	For the first initialization the function must be called with \a initLock
220 *	set to \c true. If it would be possible that another thread accesses the
221 *	structure at the same time, `lock' must be held when calling the function.
222 */
223void
224clear_team_debug_info(struct team_debug_info *info, bool initLock)
225{
226	if (info) {
227		arch_clear_team_debug_info(&info->arch_info);
228		atomic_set(&info->flags, B_TEAM_DEBUG_DEFAULT_FLAGS);
229		info->debugger_team = -1;
230		info->debugger_port = -1;
231		info->nub_thread = -1;
232		info->nub_port = -1;
233		info->debugger_write_lock = -1;
234		info->causing_thread = -1;
235		info->image_event = 0;
236		info->breakpoint_manager = NULL;
237
238		if (initLock) {
239			B_INITIALIZE_SPINLOCK(&info->lock);
240			info->debugger_changed_condition = NULL;
241		}
242	}
243}
244
245/**
246 *  `lock' must not be held nor may interrupts be disabled.
247 *  \a info must not be a member of a team struct (or the team struct must no
248 *  longer be accessible, i.e. the team should already be removed).
249 *
250 *	In case the team is still accessible, the procedure is:
251 *	1. get `lock'
252 *	2. copy the team debug info on stack
253 *	3. call clear_team_debug_info() on the team debug info
254 *	4. release `lock'
255 *	5. call destroy_team_debug_info() on the copied team debug info
256 */
257static void
258destroy_team_debug_info(struct team_debug_info *info)
259{
260	if (info) {
261		arch_destroy_team_debug_info(&info->arch_info);
262
263		// delete the breakpoint manager
264		delete info->breakpoint_manager ;
265		info->breakpoint_manager = NULL;
266
267		// delete the debugger port write lock
268		if (info->debugger_write_lock >= 0) {
269			delete_sem(info->debugger_write_lock);
270			info->debugger_write_lock = -1;
271		}
272
273		// delete the nub port
274		if (info->nub_port >= 0) {
275			set_port_owner(info->nub_port, B_CURRENT_TEAM);
276			delete_port(info->nub_port);
277			info->nub_port = -1;
278		}
279
280		// wait for the nub thread
281		if (info->nub_thread >= 0) {
282			if (info->nub_thread != thread_get_current_thread()->id) {
283				int32 result;
284				wait_for_thread(info->nub_thread, &result);
285			}
286
287			info->nub_thread = -1;
288		}
289
290		atomic_set(&info->flags, 0);
291		info->debugger_team = -1;
292		info->debugger_port = -1;
293		info->causing_thread = -1;
294		info->image_event = -1;
295	}
296}
297
298
299void
300init_thread_debug_info(struct thread_debug_info *info)
301{
302	if (info) {
303		B_INITIALIZE_SPINLOCK(&info->lock);
304		arch_clear_thread_debug_info(&info->arch_info);
305		info->flags = B_THREAD_DEBUG_DEFAULT_FLAGS;
306		info->debug_port = -1;
307		info->ignore_signals = 0;
308		info->ignore_signals_once = 0;
309		info->profile.sample_area = -1;
310		info->profile.samples = NULL;
311		info->profile.buffer_full = false;
312		info->profile.installed_timer = NULL;
313	}
314}
315
316
317/*!	Clears the debug info for the current thread.
318	Invoked with thread debug info lock being held.
319*/
320void
321clear_thread_debug_info(struct thread_debug_info *info, bool dying)
322{
323	if (info) {
324		// cancel profiling timer
325		if (info->profile.installed_timer != NULL) {
326			cancel_timer(info->profile.installed_timer);
327			info->profile.installed_timer = NULL;
328		}
329
330		arch_clear_thread_debug_info(&info->arch_info);
331		atomic_set(&info->flags,
332			B_THREAD_DEBUG_DEFAULT_FLAGS | (dying ? B_THREAD_DEBUG_DYING : 0));
333		info->debug_port = -1;
334		info->ignore_signals = 0;
335		info->ignore_signals_once = 0;
336		info->profile.sample_area = -1;
337		info->profile.samples = NULL;
338		info->profile.buffer_full = false;
339	}
340}
341
342
343void
344destroy_thread_debug_info(struct thread_debug_info *info)
345{
346	if (info) {
347		area_id sampleArea = info->profile.sample_area;
348		if (sampleArea >= 0) {
349			area_info areaInfo;
350			if (get_area_info(sampleArea, &areaInfo) == B_OK) {
351				unlock_memory(areaInfo.address, areaInfo.size, B_READ_DEVICE);
352				delete_area(sampleArea);
353			}
354		}
355
356		arch_destroy_thread_debug_info(&info->arch_info);
357
358		if (info->debug_port >= 0) {
359			delete_port(info->debug_port);
360			info->debug_port = -1;
361		}
362
363		info->ignore_signals = 0;
364		info->ignore_signals_once = 0;
365
366		atomic_set(&info->flags, 0);
367	}
368}
369
370
371static status_t
372prepare_debugger_change(team_id teamID, ConditionVariable& condition,
373	Team*& team)
374{
375	// We look up the team by ID, even in case of the current team, so we can be
376	// sure, that the team is not already dying.
377	if (teamID == B_CURRENT_TEAM)
378		teamID = thread_get_current_thread()->team->id;
379
380	while (true) {
381		// get the team
382		team = Team::GetAndLock(teamID);
383		if (team == NULL)
384			return B_BAD_TEAM_ID;
385		BReference<Team> teamReference(team, true);
386		TeamLocker teamLocker(team, true);
387
388		// don't allow messing with the kernel team
389		if (team == team_get_kernel_team())
390			return B_NOT_ALLOWED;
391
392		// check whether the condition is already set
393		InterruptsSpinLocker debugInfoLocker(team->debug_info.lock);
394
395		if (team->debug_info.debugger_changed_condition == NULL) {
396			// nobody there yet -- set our condition variable and be done
397			team->debug_info.debugger_changed_condition = &condition;
398			return B_OK;
399		}
400
401		// we'll have to wait
402		ConditionVariableEntry entry;
403		team->debug_info.debugger_changed_condition->Add(&entry);
404
405		debugInfoLocker.Unlock();
406		teamLocker.Unlock();
407
408		entry.Wait();
409	}
410}
411
412
413static void
414prepare_debugger_change(Team* team, ConditionVariable& condition)
415{
416	while (true) {
417		// check whether the condition is already set
418		InterruptsSpinLocker debugInfoLocker(team->debug_info.lock);
419
420		if (team->debug_info.debugger_changed_condition == NULL) {
421			// nobody there yet -- set our condition variable and be done
422			team->debug_info.debugger_changed_condition = &condition;
423			return;
424		}
425
426		// we'll have to wait
427		ConditionVariableEntry entry;
428		team->debug_info.debugger_changed_condition->Add(&entry);
429
430		debugInfoLocker.Unlock();
431
432		entry.Wait();
433	}
434}
435
436
437static void
438finish_debugger_change(Team* team)
439{
440	// unset our condition variable and notify all threads waiting on it
441	InterruptsSpinLocker debugInfoLocker(team->debug_info.lock);
442
443	ConditionVariable* condition = team->debug_info.debugger_changed_condition;
444	team->debug_info.debugger_changed_condition = NULL;
445
446	condition->NotifyAll();
447}
448
449
450void
451user_debug_prepare_for_exec()
452{
453	Thread *thread = thread_get_current_thread();
454	Team *team = thread->team;
455
456	// If a debugger is installed for the team and the thread debug stuff
457	// initialized, change the ownership of the debug port for the thread
458	// to the kernel team, since exec_team() deletes all ports owned by this
459	// team. We change the ownership back later.
460	if (atomic_get(&team->debug_info.flags) & B_TEAM_DEBUG_DEBUGGER_INSTALLED) {
461		// get the port
462		port_id debugPort = -1;
463
464		InterruptsSpinLocker threadDebugInfoLocker(thread->debug_info.lock);
465
466		if ((thread->debug_info.flags & B_THREAD_DEBUG_INITIALIZED) != 0)
467			debugPort = thread->debug_info.debug_port;
468
469		threadDebugInfoLocker.Unlock();
470
471		// set the new port ownership
472		if (debugPort >= 0)
473			set_port_owner(debugPort, team_get_kernel_team_id());
474	}
475}
476
477
478void
479user_debug_finish_after_exec()
480{
481	Thread *thread = thread_get_current_thread();
482	Team *team = thread->team;
483
484	// If a debugger is installed for the team and the thread debug stuff
485	// initialized for this thread, change the ownership of its debug port
486	// back to this team.
487	if (atomic_get(&team->debug_info.flags) & B_TEAM_DEBUG_DEBUGGER_INSTALLED) {
488		// get the port
489		port_id debugPort = -1;
490
491		InterruptsSpinLocker threadDebugInfoLocker(thread->debug_info.lock);
492
493		if (thread->debug_info.flags & B_THREAD_DEBUG_INITIALIZED)
494			debugPort = thread->debug_info.debug_port;
495
496		threadDebugInfoLocker.Unlock();
497
498		// set the new port ownership
499		if (debugPort >= 0)
500			set_port_owner(debugPort, team->id);
501	}
502}
503
504
505void
506init_user_debug()
507{
508	#ifdef ARCH_INIT_USER_DEBUG
509		ARCH_INIT_USER_DEBUG();
510	#endif
511}
512
513
514static void
515get_team_debug_info(team_debug_info &teamDebugInfo)
516{
517	Thread *thread = thread_get_current_thread();
518
519	cpu_status state = disable_interrupts();
520	GRAB_TEAM_DEBUG_INFO_LOCK(thread->team->debug_info);
521
522	memcpy(&teamDebugInfo, &thread->team->debug_info, sizeof(team_debug_info));
523
524	RELEASE_TEAM_DEBUG_INFO_LOCK(thread->team->debug_info);
525	restore_interrupts(state);
526}
527
528
529static status_t
530thread_hit_debug_event_internal(debug_debugger_message event,
531	const void *message, int32 size, bool requireDebugger, bool &restart)
532{
533	restart = false;
534	Thread *thread = thread_get_current_thread();
535
536	TRACE(("thread_hit_debug_event(): thread: %" B_PRId32 ", event: %" B_PRIu32
537		", message: %p, size: %" B_PRId32 "\n", thread->id, (uint32)event,
538		message, size));
539
540	// check, if there's a debug port already
541	bool setPort = !(atomic_get(&thread->debug_info.flags)
542		& B_THREAD_DEBUG_INITIALIZED);
543
544	// create a port, if there is none yet
545	port_id port = -1;
546	if (setPort) {
547		char nameBuffer[128];
548		snprintf(nameBuffer, sizeof(nameBuffer), "nub to thread %" B_PRId32,
549			thread->id);
550
551		port = create_port(1, nameBuffer);
552		if (port < 0) {
553			dprintf("thread_hit_debug_event(): Failed to create debug port: "
554				"%s\n", strerror(port));
555			return port;
556		}
557	}
558
559	// check the debug info structures once more: get the debugger port, set
560	// the thread's debug port, and update the thread's debug flags
561	port_id deletePort = port;
562	port_id debuggerPort = -1;
563	port_id nubPort = -1;
564	status_t error = B_OK;
565	cpu_status state = disable_interrupts();
566	GRAB_TEAM_DEBUG_INFO_LOCK(thread->team->debug_info);
567	SpinLocker threadDebugInfoLocker(thread->debug_info.lock);
568
569	uint32 threadFlags = thread->debug_info.flags;
570	threadFlags &= ~B_THREAD_DEBUG_STOP;
571	bool debuggerInstalled
572		= (thread->team->debug_info.flags & B_TEAM_DEBUG_DEBUGGER_INSTALLED);
573	if (thread->id == thread->team->debug_info.nub_thread) {
574		// Ugh, we're the nub thread. We shouldn't be here.
575		TRACE(("thread_hit_debug_event(): Misdirected nub thread: %" B_PRId32
576			"\n", thread->id));
577
578		error = B_ERROR;
579	} else if (debuggerInstalled || !requireDebugger) {
580		if (debuggerInstalled) {
581			debuggerPort = thread->team->debug_info.debugger_port;
582			nubPort = thread->team->debug_info.nub_port;
583		}
584
585		if (setPort) {
586			if (threadFlags & B_THREAD_DEBUG_INITIALIZED) {
587				// someone created a port for us (the port we've created will
588				// be deleted below)
589				port = thread->debug_info.debug_port;
590			} else {
591				thread->debug_info.debug_port = port;
592				deletePort = -1;	// keep the port
593				threadFlags |= B_THREAD_DEBUG_INITIALIZED;
594			}
595		} else {
596			if (threadFlags & B_THREAD_DEBUG_INITIALIZED) {
597				port = thread->debug_info.debug_port;
598			} else {
599				// someone deleted our port
600				error = B_ERROR;
601			}
602		}
603	} else
604		error = B_ERROR;
605
606	// update the flags
607	if (error == B_OK)
608		threadFlags |= B_THREAD_DEBUG_STOPPED;
609	atomic_set(&thread->debug_info.flags, threadFlags);
610
611	update_thread_user_debug_flag(thread);
612
613	threadDebugInfoLocker.Unlock();
614	RELEASE_TEAM_DEBUG_INFO_LOCK(thread->team->debug_info);
615	restore_interrupts(state);
616
617	// delete the superfluous port
618	if (deletePort >= 0)
619		delete_port(deletePort);
620
621	if (error != B_OK) {
622		TRACE(("thread_hit_debug_event() error: thread: %" B_PRId32 ", error: "
623			"%" B_PRIx32 "\n", thread->id, error));
624		return error;
625	}
626
627	// send a message to the debugger port
628	if (debuggerInstalled) {
629		// update the message's origin info first
630		debug_origin *origin = (debug_origin *)message;
631		origin->thread = thread->id;
632		origin->team = thread->team->id;
633		origin->nub_port = nubPort;
634
635		TRACE(("thread_hit_debug_event(): thread: %" B_PRId32 ", sending "
636			"message to debugger port %" B_PRId32 "\n", thread->id,
637			debuggerPort));
638
639		error = debugger_write(debuggerPort, event, message, size, false);
640	}
641
642	status_t result = B_THREAD_DEBUG_HANDLE_EVENT;
643	bool singleStep = false;
644
645	if (error == B_OK) {
646		bool done = false;
647		while (!done) {
648			// read a command from the debug port
649			int32 command;
650			debugged_thread_message_data commandMessage;
651			ssize_t commandMessageSize = read_port_etc(port, &command,
652				&commandMessage, sizeof(commandMessage), B_KILL_CAN_INTERRUPT,
653				0);
654
655			if (commandMessageSize < 0) {
656				error = commandMessageSize;
657				TRACE(("thread_hit_debug_event(): thread: %" B_PRId32 ", failed "
658					"to receive message from port %" B_PRId32 ": %" B_PRIx32 "\n",
659					thread->id, port, error));
660				break;
661			}
662
663			switch (command) {
664				case B_DEBUGGED_THREAD_MESSAGE_CONTINUE:
665					TRACE(("thread_hit_debug_event(): thread: %" B_PRId32 ": "
666						"B_DEBUGGED_THREAD_MESSAGE_CONTINUE\n",
667						thread->id));
668					result = commandMessage.continue_thread.handle_event;
669
670					singleStep = commandMessage.continue_thread.single_step;
671					done = true;
672					break;
673
674				case B_DEBUGGED_THREAD_SET_CPU_STATE:
675				{
676					TRACE(("thread_hit_debug_event(): thread: %" B_PRId32 ": "
677						"B_DEBUGGED_THREAD_SET_CPU_STATE\n",
678						thread->id));
679					arch_set_debug_cpu_state(
680						&commandMessage.set_cpu_state.cpu_state);
681
682					break;
683				}
684
685				case B_DEBUGGED_THREAD_GET_CPU_STATE:
686				{
687					port_id replyPort = commandMessage.get_cpu_state.reply_port;
688
689					// prepare the message
690					debug_nub_get_cpu_state_reply replyMessage;
691					replyMessage.error = B_OK;
692					replyMessage.message = event;
693					arch_get_debug_cpu_state(&replyMessage.cpu_state);
694
695					// send it
696					error = kill_interruptable_write_port(replyPort, event,
697						&replyMessage, sizeof(replyMessage));
698
699					break;
700				}
701
702				case B_DEBUGGED_THREAD_DEBUGGER_CHANGED:
703				{
704					// Check, if the debugger really changed, i.e. is different
705					// than the one we know.
706					team_debug_info teamDebugInfo;
707					get_team_debug_info(teamDebugInfo);
708
709					if (teamDebugInfo.flags & B_TEAM_DEBUG_DEBUGGER_INSTALLED) {
710						if (!debuggerInstalled
711							|| teamDebugInfo.debugger_port != debuggerPort) {
712							// debugger was installed or has changed: restart
713							// this function
714							restart = true;
715							done = true;
716						}
717					} else {
718						if (debuggerInstalled) {
719							// debugger is gone: continue the thread normally
720							done = true;
721						}
722					}
723
724					break;
725				}
726			}
727		}
728	} else {
729		TRACE(("thread_hit_debug_event(): thread: %" B_PRId32 ", failed to send "
730			"message to debugger port %" B_PRId32 ": %" B_PRIx32 "\n",
731			thread->id, debuggerPort, error));
732	}
733
734	// update the thread debug info
735	bool destroyThreadInfo = false;
736	thread_debug_info threadDebugInfo;
737
738	state = disable_interrupts();
739	threadDebugInfoLocker.Lock();
740
741	// check, if the team is still being debugged
742	int32 teamDebugFlags = atomic_get(&thread->team->debug_info.flags);
743	if (teamDebugFlags & B_TEAM_DEBUG_DEBUGGER_INSTALLED) {
744		// update the single-step flag
745		if (singleStep) {
746			atomic_or(&thread->debug_info.flags,
747				B_THREAD_DEBUG_SINGLE_STEP);
748			atomic_or(&thread->flags, THREAD_FLAGS_SINGLE_STEP);
749		} else {
750			atomic_and(&thread->debug_info.flags,
751				~(int32)B_THREAD_DEBUG_SINGLE_STEP);
752		}
753
754		// unset the "stopped" state
755		atomic_and(&thread->debug_info.flags, ~B_THREAD_DEBUG_STOPPED);
756
757		update_thread_user_debug_flag(thread);
758
759	} else {
760		// the debugger is gone: cleanup our info completely
761		threadDebugInfo = thread->debug_info;
762		clear_thread_debug_info(&thread->debug_info, false);
763		destroyThreadInfo = true;
764	}
765
766	threadDebugInfoLocker.Unlock();
767	restore_interrupts(state);
768
769	// enable/disable single stepping
770	arch_update_thread_single_step();
771
772	if (destroyThreadInfo)
773		destroy_thread_debug_info(&threadDebugInfo);
774
775	return (error == B_OK ? result : error);
776}
777
778
779static status_t
780thread_hit_debug_event(debug_debugger_message event, const void *message,
781	int32 size, bool requireDebugger)
782{
783	status_t result;
784	bool restart;
785	do {
786		restart = false;
787		result = thread_hit_debug_event_internal(event, message, size,
788			requireDebugger, restart);
789	} while (result >= 0 && restart);
790
791	// Prepare to continue -- we install a debugger change condition, so no one
792	// will change the debugger while we're playing with the breakpoint manager.
793	// TODO: Maybe better use ref-counting and a flag in the breakpoint manager.
794	Team* team = thread_get_current_thread()->team;
795	ConditionVariable debugChangeCondition;
796	debugChangeCondition.Init(team, "debug change condition");
797	prepare_debugger_change(team, debugChangeCondition);
798
799	if (team->debug_info.breakpoint_manager != NULL) {
800		bool isSyscall;
801		void* pc = arch_debug_get_interrupt_pc(&isSyscall);
802		if (pc != NULL && !isSyscall)
803			team->debug_info.breakpoint_manager->PrepareToContinue(pc);
804	}
805
806	finish_debugger_change(team);
807
808	return result;
809}
810
811
812static status_t
813thread_hit_serious_debug_event(debug_debugger_message event,
814	const void *message, int32 messageSize)
815{
816	// ensure that a debugger is installed for this team
817	status_t error = ensure_debugger_installed();
818	if (error != B_OK) {
819		Thread *thread = thread_get_current_thread();
820		dprintf("thread_hit_serious_debug_event(): Failed to install debugger: "
821			"thread: %" B_PRId32 " (%s): %s\n", thread->id, thread->name,
822			strerror(error));
823		return error;
824	}
825
826	// enter the debug loop
827	return thread_hit_debug_event(event, message, messageSize, true);
828}
829
830
831void
832user_debug_pre_syscall(uint32 syscall, void *args)
833{
834	// check whether a debugger is installed
835	Thread *thread = thread_get_current_thread();
836	int32 teamDebugFlags = atomic_get(&thread->team->debug_info.flags);
837	if (!(teamDebugFlags & B_TEAM_DEBUG_DEBUGGER_INSTALLED))
838		return;
839
840	// check whether pre-syscall tracing is enabled for team or thread
841	int32 threadDebugFlags = atomic_get(&thread->debug_info.flags);
842	if (!(teamDebugFlags & B_TEAM_DEBUG_PRE_SYSCALL)
843			&& !(threadDebugFlags & B_THREAD_DEBUG_PRE_SYSCALL)) {
844		return;
845	}
846
847	// prepare the message
848	debug_pre_syscall message;
849	message.syscall = syscall;
850
851	// copy the syscall args
852	if (syscall < (uint32)kSyscallCount) {
853		if (kSyscallInfos[syscall].parameter_size > 0)
854			memcpy(message.args, args, kSyscallInfos[syscall].parameter_size);
855	}
856
857	thread_hit_debug_event(B_DEBUGGER_MESSAGE_PRE_SYSCALL, &message,
858		sizeof(message), true);
859}
860
861
862void
863user_debug_post_syscall(uint32 syscall, void *args, uint64 returnValue,
864	bigtime_t startTime)
865{
866	// check whether a debugger is installed
867	Thread *thread = thread_get_current_thread();
868	int32 teamDebugFlags = atomic_get(&thread->team->debug_info.flags);
869	if (!(teamDebugFlags & B_TEAM_DEBUG_DEBUGGER_INSTALLED))
870		return;
871
872	// check whether post-syscall tracing is enabled for team or thread
873	int32 threadDebugFlags = atomic_get(&thread->debug_info.flags);
874	if (!(teamDebugFlags & B_TEAM_DEBUG_POST_SYSCALL)
875			&& !(threadDebugFlags & B_THREAD_DEBUG_POST_SYSCALL)) {
876		return;
877	}
878
879	// prepare the message
880	debug_post_syscall message;
881	message.start_time = startTime;
882	message.end_time = system_time();
883	message.return_value = returnValue;
884	message.syscall = syscall;
885
886	// copy the syscall args
887	if (syscall < (uint32)kSyscallCount) {
888		if (kSyscallInfos[syscall].parameter_size > 0)
889			memcpy(message.args, args, kSyscallInfos[syscall].parameter_size);
890	}
891
892	thread_hit_debug_event(B_DEBUGGER_MESSAGE_POST_SYSCALL, &message,
893		sizeof(message), true);
894}
895
896
897/**	\brief To be called when an unhandled processor exception (error/fault)
898 *		   occurred.
899 *	\param exception The debug_why_stopped value identifying the kind of fault.
900 *	\param signal The signal corresponding to the exception.
901 *	\return \c true, if the caller shall continue normally, i.e. usually send
902 *			a deadly signal. \c false, if the debugger insists to continue the
903 *			program (e.g. because it has solved the removed the cause of the
904 *			problem).
905 */
906bool
907user_debug_exception_occurred(debug_exception_type exception, int signal)
908{
909	// First check whether there's a signal handler installed for the signal.
910	// If so, we don't want to install a debugger for the team. We always send
911	// the signal instead. An already installed debugger will be notified, if
912	// it has requested notifications of signal.
913	struct sigaction signalAction;
914	if (sigaction(signal, NULL, &signalAction) == 0
915		&& signalAction.sa_handler != SIG_DFL) {
916		return true;
917	}
918
919	// prepare the message
920	debug_exception_occurred message;
921	message.exception = exception;
922	message.signal = signal;
923
924	status_t result = thread_hit_serious_debug_event(
925		B_DEBUGGER_MESSAGE_EXCEPTION_OCCURRED, &message, sizeof(message));
926	return (result != B_THREAD_DEBUG_IGNORE_EVENT);
927}
928
929
930bool
931user_debug_handle_signal(int signal, struct sigaction *handler, siginfo_t *info,
932	bool deadly)
933{
934	// check, if a debugger is installed and is interested in signals
935	Thread *thread = thread_get_current_thread();
936	int32 teamDebugFlags = atomic_get(&thread->team->debug_info.flags);
937	if (~teamDebugFlags
938		& (B_TEAM_DEBUG_DEBUGGER_INSTALLED | B_TEAM_DEBUG_SIGNALS)) {
939		return true;
940	}
941
942	// prepare the message
943	debug_signal_received message;
944	message.signal = signal;
945	message.handler = *handler;
946	message.info = *info;
947	message.deadly = deadly;
948
949	status_t result = thread_hit_debug_event(B_DEBUGGER_MESSAGE_SIGNAL_RECEIVED,
950		&message, sizeof(message), true);
951	return (result != B_THREAD_DEBUG_IGNORE_EVENT);
952}
953
954
955void
956user_debug_stop_thread()
957{
958	// check whether this is actually an emulated single-step notification
959	Thread* thread = thread_get_current_thread();
960	InterruptsSpinLocker threadDebugInfoLocker(thread->debug_info.lock);
961
962	bool singleStepped = false;
963	if ((atomic_and(&thread->debug_info.flags,
964				~B_THREAD_DEBUG_NOTIFY_SINGLE_STEP)
965			& B_THREAD_DEBUG_NOTIFY_SINGLE_STEP) != 0) {
966		singleStepped = true;
967	}
968
969	threadDebugInfoLocker.Unlock();
970
971	if (singleStepped) {
972		user_debug_single_stepped();
973	} else {
974		debug_thread_debugged message;
975		thread_hit_serious_debug_event(B_DEBUGGER_MESSAGE_THREAD_DEBUGGED,
976			&message, sizeof(message));
977	}
978}
979
980
981void
982user_debug_team_created(team_id teamID)
983{
984	// check, if a debugger is installed and is interested in team creation
985	// events
986	Thread *thread = thread_get_current_thread();
987	int32 teamDebugFlags = atomic_get(&thread->team->debug_info.flags);
988	if (~teamDebugFlags
989		& (B_TEAM_DEBUG_DEBUGGER_INSTALLED | B_TEAM_DEBUG_TEAM_CREATION)) {
990		return;
991	}
992
993	// prepare the message
994	debug_team_created message;
995	message.new_team = teamID;
996
997	thread_hit_debug_event(B_DEBUGGER_MESSAGE_TEAM_CREATED, &message,
998		sizeof(message), true);
999}
1000
1001
1002void
1003user_debug_team_deleted(team_id teamID, port_id debuggerPort)
1004{
1005	if (debuggerPort >= 0) {
1006		TRACE(("user_debug_team_deleted(team: %" B_PRId32 ", debugger port: "
1007			"%" B_PRId32 ")\n", teamID, debuggerPort));
1008
1009		debug_team_deleted message;
1010		message.origin.thread = -1;
1011		message.origin.team = teamID;
1012		message.origin.nub_port = -1;
1013		write_port_etc(debuggerPort, B_DEBUGGER_MESSAGE_TEAM_DELETED, &message,
1014			sizeof(message), B_RELATIVE_TIMEOUT, 0);
1015	}
1016}
1017
1018
1019void
1020user_debug_team_exec()
1021{
1022	// check, if a debugger is installed and is interested in team creation
1023	// events
1024	Thread *thread = thread_get_current_thread();
1025	int32 teamDebugFlags = atomic_get(&thread->team->debug_info.flags);
1026	if (~teamDebugFlags
1027		& (B_TEAM_DEBUG_DEBUGGER_INSTALLED | B_TEAM_DEBUG_TEAM_CREATION)) {
1028		return;
1029	}
1030
1031	// prepare the message
1032	debug_team_exec message;
1033	message.image_event = atomic_add(&thread->team->debug_info.image_event, 1)
1034		+ 1;
1035
1036	thread_hit_debug_event(B_DEBUGGER_MESSAGE_TEAM_EXEC, &message,
1037		sizeof(message), true);
1038}
1039
1040
1041/*!	Called by a new userland thread to update the debugging related flags of
1042	\c Thread::flags before the thread first enters userland.
1043	\param thread The calling thread.
1044*/
1045void
1046user_debug_update_new_thread_flags(Thread* thread)
1047{
1048	// lock it and update it's flags
1049	InterruptsSpinLocker threadDebugInfoLocker(thread->debug_info.lock);
1050
1051	update_thread_user_debug_flag(thread);
1052	update_thread_breakpoints_flag(thread);
1053	update_thread_debugger_installed_flag(thread);
1054}
1055
1056
1057void
1058user_debug_thread_created(thread_id threadID)
1059{
1060	// check, if a debugger is installed and is interested in thread events
1061	Thread *thread = thread_get_current_thread();
1062	int32 teamDebugFlags = atomic_get(&thread->team->debug_info.flags);
1063	if (~teamDebugFlags
1064		& (B_TEAM_DEBUG_DEBUGGER_INSTALLED | B_TEAM_DEBUG_THREADS)) {
1065		return;
1066	}
1067
1068	// prepare the message
1069	debug_thread_created message;
1070	message.new_thread = threadID;
1071
1072	thread_hit_debug_event(B_DEBUGGER_MESSAGE_THREAD_CREATED, &message,
1073		sizeof(message), true);
1074}
1075
1076
1077void
1078user_debug_thread_deleted(team_id teamID, thread_id threadID)
1079{
1080	// Things are a bit complicated here, since this thread no longer belongs to
1081	// the debugged team (but to the kernel). So we can't use debugger_write().
1082
1083	// get the team debug flags and debugger port
1084	Team* team = Team::Get(teamID);
1085	if (team == NULL)
1086		return;
1087	BReference<Team> teamReference(team, true);
1088
1089	InterruptsSpinLocker debugInfoLocker(team->debug_info.lock);
1090
1091	int32 teamDebugFlags = atomic_get(&team->debug_info.flags);
1092	port_id debuggerPort = team->debug_info.debugger_port;
1093	sem_id writeLock = team->debug_info.debugger_write_lock;
1094
1095	debugInfoLocker.Unlock();
1096
1097	// check, if a debugger is installed and is interested in thread events
1098	if (~teamDebugFlags
1099		& (B_TEAM_DEBUG_DEBUGGER_INSTALLED | B_TEAM_DEBUG_THREADS)) {
1100		return;
1101	}
1102
1103	// acquire the debugger write lock
1104	status_t error = acquire_sem_etc(writeLock, 1, B_KILL_CAN_INTERRUPT, 0);
1105	if (error != B_OK)
1106		return;
1107
1108	// re-get the team debug info -- we need to check whether anything changed
1109	debugInfoLocker.Lock();
1110
1111	teamDebugFlags = atomic_get(&team->debug_info.flags);
1112	port_id newDebuggerPort = team->debug_info.debugger_port;
1113
1114	debugInfoLocker.Unlock();
1115
1116	// Send the message only if the debugger hasn't changed in the meantime or
1117	// the team is about to be handed over.
1118	if (newDebuggerPort == debuggerPort
1119		|| (teamDebugFlags & B_TEAM_DEBUG_DEBUGGER_HANDOVER) == 0) {
1120		debug_thread_deleted message;
1121		message.origin.thread = threadID;
1122		message.origin.team = teamID;
1123		message.origin.nub_port = -1;
1124
1125		write_port_etc(debuggerPort, B_DEBUGGER_MESSAGE_THREAD_DELETED,
1126			&message, sizeof(message), B_KILL_CAN_INTERRUPT, 0);
1127	}
1128
1129	// release the debugger write lock
1130	release_sem(writeLock);
1131}
1132
1133
1134/*!	Called for a thread that is about to die, cleaning up all user debug
1135	facilities installed for the thread.
1136	\param thread The current thread, the one that is going to die.
1137*/
1138void
1139user_debug_thread_exiting(Thread* thread)
1140{
1141	// thread is the current thread, so using team is safe
1142	Team* team = thread->team;
1143
1144	InterruptsLocker interruptsLocker;
1145
1146	GRAB_TEAM_DEBUG_INFO_LOCK(team->debug_info);
1147
1148	int32 teamDebugFlags = atomic_get(&team->debug_info.flags);
1149	port_id debuggerPort = team->debug_info.debugger_port;
1150
1151	RELEASE_TEAM_DEBUG_INFO_LOCK(team->debug_info);
1152
1153	// check, if a debugger is installed
1154	if ((teamDebugFlags & B_TEAM_DEBUG_DEBUGGER_INSTALLED) == 0
1155		|| debuggerPort < 0) {
1156		return;
1157	}
1158
1159	// detach the profile info and mark the thread dying
1160	SpinLocker threadDebugInfoLocker(thread->debug_info.lock);
1161
1162	thread_debug_info& threadDebugInfo = thread->debug_info;
1163	if (threadDebugInfo.profile.samples == NULL)
1164		return;
1165
1166	area_id sampleArea = threadDebugInfo.profile.sample_area;
1167	int32 sampleCount = threadDebugInfo.profile.sample_count;
1168	int32 droppedTicks = threadDebugInfo.profile.dropped_ticks;
1169	int32 stackDepth = threadDebugInfo.profile.stack_depth;
1170	bool variableStackDepth = threadDebugInfo.profile.variable_stack_depth;
1171	int32 imageEvent = threadDebugInfo.profile.image_event;
1172	threadDebugInfo.profile.sample_area = -1;
1173	threadDebugInfo.profile.samples = NULL;
1174	threadDebugInfo.profile.buffer_full = false;
1175
1176	atomic_or(&threadDebugInfo.flags, B_THREAD_DEBUG_DYING);
1177
1178	threadDebugInfoLocker.Unlock();
1179	interruptsLocker.Unlock();
1180
1181	// notify the debugger
1182	debug_profiler_update message;
1183	message.origin.thread = thread->id;
1184	message.origin.team = thread->team->id;
1185	message.origin.nub_port = -1;	// asynchronous message
1186	message.sample_count = sampleCount;
1187	message.dropped_ticks = droppedTicks;
1188	message.stack_depth = stackDepth;
1189	message.variable_stack_depth = variableStackDepth;
1190	message.image_event = imageEvent;
1191	message.stopped = true;
1192	debugger_write(debuggerPort, B_DEBUGGER_MESSAGE_PROFILER_UPDATE,
1193		&message, sizeof(message), false);
1194
1195	if (sampleArea >= 0) {
1196		area_info areaInfo;
1197		if (get_area_info(sampleArea, &areaInfo) == B_OK) {
1198			unlock_memory(areaInfo.address, areaInfo.size, B_READ_DEVICE);
1199			delete_area(sampleArea);
1200		}
1201	}
1202}
1203
1204
1205void
1206user_debug_image_created(const image_info *imageInfo)
1207{
1208	// check, if a debugger is installed and is interested in image events
1209	Thread *thread = thread_get_current_thread();
1210	int32 teamDebugFlags = atomic_get(&thread->team->debug_info.flags);
1211	if (~teamDebugFlags
1212		& (B_TEAM_DEBUG_DEBUGGER_INSTALLED | B_TEAM_DEBUG_IMAGES)) {
1213		return;
1214	}
1215
1216	// prepare the message
1217	debug_image_created message;
1218	memcpy(&message.info, imageInfo, sizeof(image_info));
1219	message.image_event = atomic_add(&thread->team->debug_info.image_event, 1)
1220		+ 1;
1221
1222	thread_hit_debug_event(B_DEBUGGER_MESSAGE_IMAGE_CREATED, &message,
1223		sizeof(message), true);
1224}
1225
1226
1227void
1228user_debug_image_deleted(const image_info *imageInfo)
1229{
1230	// check, if a debugger is installed and is interested in image events
1231	Thread *thread = thread_get_current_thread();
1232	int32 teamDebugFlags = atomic_get(&thread->team->debug_info.flags);
1233	if (~teamDebugFlags
1234		& (B_TEAM_DEBUG_DEBUGGER_INSTALLED | B_TEAM_DEBUG_IMAGES)) {
1235		return;
1236	}
1237
1238	// prepare the message
1239	debug_image_deleted message;
1240	memcpy(&message.info, imageInfo, sizeof(image_info));
1241	message.image_event = atomic_add(&thread->team->debug_info.image_event, 1)
1242		+ 1;
1243
1244	thread_hit_debug_event(B_DEBUGGER_MESSAGE_IMAGE_DELETED, &message,
1245		sizeof(message), true);
1246}
1247
1248
1249void
1250user_debug_breakpoint_hit(bool software)
1251{
1252	// prepare the message
1253	debug_breakpoint_hit message;
1254	arch_get_debug_cpu_state(&message.cpu_state);
1255
1256	thread_hit_serious_debug_event(B_DEBUGGER_MESSAGE_BREAKPOINT_HIT, &message,
1257		sizeof(message));
1258}
1259
1260
1261void
1262user_debug_watchpoint_hit()
1263{
1264	// prepare the message
1265	debug_watchpoint_hit message;
1266	arch_get_debug_cpu_state(&message.cpu_state);
1267
1268	thread_hit_serious_debug_event(B_DEBUGGER_MESSAGE_WATCHPOINT_HIT, &message,
1269		sizeof(message));
1270}
1271
1272
1273void
1274user_debug_single_stepped()
1275{
1276	// clear the single-step thread flag
1277	Thread* thread = thread_get_current_thread();
1278	atomic_and(&thread->flags, ~(int32)THREAD_FLAGS_SINGLE_STEP);
1279
1280	// prepare the message
1281	debug_single_step message;
1282	arch_get_debug_cpu_state(&message.cpu_state);
1283
1284	thread_hit_serious_debug_event(B_DEBUGGER_MESSAGE_SINGLE_STEP, &message,
1285		sizeof(message));
1286}
1287
1288
1289/*!	Schedules the profiling timer for the current thread.
1290	The caller must hold the thread's debug info lock.
1291	\param thread The current thread.
1292	\param interval The time after which the timer should fire.
1293*/
1294static void
1295schedule_profiling_timer(Thread* thread, bigtime_t interval)
1296{
1297	struct timer* timer = &sProfilingTimers[thread->cpu->cpu_num];
1298	thread->debug_info.profile.installed_timer = timer;
1299	thread->debug_info.profile.timer_end = system_time() + interval;
1300	add_timer(timer, &profiling_event, interval, B_ONE_SHOT_RELATIVE_TIMER);
1301}
1302
1303
1304/*!	Samples the current thread's instruction pointer/stack trace.
1305	The caller must hold the current thread's debug info lock.
1306	\param flushBuffer Return parameter: Set to \c true when the sampling
1307		buffer must be flushed.
1308*/
1309static bool
1310profiling_do_sample(bool& flushBuffer)
1311{
1312	Thread* thread = thread_get_current_thread();
1313	thread_debug_info& debugInfo = thread->debug_info;
1314
1315	if (debugInfo.profile.samples == NULL)
1316		return false;
1317
1318	// Check, whether the buffer is full or an image event occurred since the
1319	// last sample was taken.
1320	int32 maxSamples = debugInfo.profile.max_samples;
1321	int32 sampleCount = debugInfo.profile.sample_count;
1322	int32 stackDepth = debugInfo.profile.stack_depth;
1323	int32 imageEvent = thread->team->debug_info.image_event;
1324	if (debugInfo.profile.sample_count > 0) {
1325		if (debugInfo.profile.last_image_event < imageEvent
1326			&& debugInfo.profile.variable_stack_depth
1327			&& sampleCount + 2 <= maxSamples) {
1328			// an image event occurred, but we use variable stack depth and
1329			// have enough room in the buffer to indicate an image event
1330			addr_t* event = debugInfo.profile.samples + sampleCount;
1331			event[0] = B_DEBUG_PROFILE_IMAGE_EVENT;
1332			event[1] = imageEvent;
1333			sampleCount += 2;
1334			debugInfo.profile.sample_count = sampleCount;
1335			debugInfo.profile.last_image_event = imageEvent;
1336		}
1337
1338		if (debugInfo.profile.last_image_event < imageEvent
1339			|| debugInfo.profile.flush_threshold - sampleCount < stackDepth) {
1340			if (!IS_KERNEL_ADDRESS(arch_debug_get_interrupt_pc(NULL))) {
1341				flushBuffer = true;
1342				return true;
1343			}
1344
1345			// We can't flush the buffer now, since we interrupted a kernel
1346			// function. If the buffer is not full yet, we add the samples,
1347			// otherwise we have to drop them.
1348			if (maxSamples - sampleCount < stackDepth) {
1349				debugInfo.profile.dropped_ticks++;
1350				return true;
1351			}
1352		}
1353	} else {
1354		// first sample -- set the image event
1355		debugInfo.profile.image_event = imageEvent;
1356		debugInfo.profile.last_image_event = imageEvent;
1357	}
1358
1359	// get the samples
1360	addr_t* returnAddresses = debugInfo.profile.samples
1361		+ debugInfo.profile.sample_count;
1362	if (debugInfo.profile.variable_stack_depth) {
1363		// variable sample count per hit
1364		*returnAddresses = arch_debug_get_stack_trace(returnAddresses + 1,
1365			stackDepth - 1, 1, 0, STACK_TRACE_KERNEL | STACK_TRACE_USER);
1366
1367		debugInfo.profile.sample_count += *returnAddresses + 1;
1368	} else {
1369		// fixed sample count per hit
1370		if (stackDepth > 1) {
1371			int32 count = arch_debug_get_stack_trace(returnAddresses,
1372				stackDepth, 1, 0, STACK_TRACE_KERNEL | STACK_TRACE_USER);
1373
1374			for (int32 i = count; i < stackDepth; i++)
1375				returnAddresses[i] = 0;
1376		} else
1377			*returnAddresses = (addr_t)arch_debug_get_interrupt_pc(NULL);
1378
1379		debugInfo.profile.sample_count += stackDepth;
1380	}
1381
1382	return true;
1383}
1384
1385
1386static void
1387profiling_buffer_full(void*)
1388{
1389	// It is undefined whether the function is called with interrupts enabled
1390	// or disabled. We are allowed to enable interrupts, though. First make
1391	// sure interrupts are disabled.
1392	disable_interrupts();
1393
1394	Thread* thread = thread_get_current_thread();
1395	thread_debug_info& debugInfo = thread->debug_info;
1396
1397	SpinLocker threadDebugInfoLocker(debugInfo.lock);
1398
1399	if (debugInfo.profile.samples != NULL && debugInfo.profile.buffer_full) {
1400		int32 sampleCount = debugInfo.profile.sample_count;
1401		int32 droppedTicks = debugInfo.profile.dropped_ticks;
1402		int32 stackDepth = debugInfo.profile.stack_depth;
1403		bool variableStackDepth = debugInfo.profile.variable_stack_depth;
1404		int32 imageEvent = debugInfo.profile.image_event;
1405
1406		// notify the debugger
1407		debugInfo.profile.sample_count = 0;
1408		debugInfo.profile.dropped_ticks = 0;
1409
1410		threadDebugInfoLocker.Unlock();
1411		enable_interrupts();
1412
1413		// prepare the message
1414		debug_profiler_update message;
1415		message.sample_count = sampleCount;
1416		message.dropped_ticks = droppedTicks;
1417		message.stack_depth = stackDepth;
1418		message.variable_stack_depth = variableStackDepth;
1419		message.image_event = imageEvent;
1420		message.stopped = false;
1421
1422		thread_hit_debug_event(B_DEBUGGER_MESSAGE_PROFILER_UPDATE, &message,
1423			sizeof(message), false);
1424
1425		disable_interrupts();
1426		threadDebugInfoLocker.Lock();
1427
1428		// do the sampling and reschedule timer, if still profiling this thread
1429		bool flushBuffer;
1430		if (profiling_do_sample(flushBuffer)) {
1431			debugInfo.profile.buffer_full = false;
1432			schedule_profiling_timer(thread, debugInfo.profile.interval);
1433		}
1434	}
1435
1436	threadDebugInfoLocker.Unlock();
1437	enable_interrupts();
1438}
1439
1440
1441/*!	Profiling timer event callback.
1442	Called with interrupts disabled.
1443*/
1444static int32
1445profiling_event(timer* /*unused*/)
1446{
1447	Thread* thread = thread_get_current_thread();
1448	thread_debug_info& debugInfo = thread->debug_info;
1449
1450	SpinLocker threadDebugInfoLocker(debugInfo.lock);
1451
1452	bool flushBuffer = false;
1453	if (profiling_do_sample(flushBuffer)) {
1454		if (flushBuffer) {
1455			// The sample buffer needs to be flushed; we'll have to notify the
1456			// debugger. We can't do that right here. Instead we set a post
1457			// interrupt callback doing that for us, and don't reschedule the
1458			// timer yet.
1459			thread->post_interrupt_callback = profiling_buffer_full;
1460			debugInfo.profile.installed_timer = NULL;
1461			debugInfo.profile.buffer_full = true;
1462		} else
1463			schedule_profiling_timer(thread, debugInfo.profile.interval);
1464	} else
1465		debugInfo.profile.installed_timer = NULL;
1466
1467	return B_HANDLED_INTERRUPT;
1468}
1469
1470
1471/*!	Called by the scheduler when a debugged thread has been unscheduled.
1472	The scheduler lock is being held.
1473*/
1474void
1475user_debug_thread_unscheduled(Thread* thread)
1476{
1477	SpinLocker threadDebugInfoLocker(thread->debug_info.lock);
1478
1479	// if running, cancel the profiling timer
1480	struct timer* timer = thread->debug_info.profile.installed_timer;
1481	if (timer != NULL) {
1482		// track remaining time
1483		bigtime_t left = thread->debug_info.profile.timer_end - system_time();
1484		thread->debug_info.profile.interval_left = max_c(left, 0);
1485		thread->debug_info.profile.installed_timer = NULL;
1486
1487		// cancel timer
1488		threadDebugInfoLocker.Unlock();
1489			// not necessary, but doesn't harm and reduces contention
1490		cancel_timer(timer);
1491			// since invoked on the same CPU, this will not possibly wait for
1492			// an already called timer hook
1493	}
1494}
1495
1496
1497/*!	Called by the scheduler when a debugged thread has been scheduled.
1498	The scheduler lock is being held.
1499*/
1500void
1501user_debug_thread_scheduled(Thread* thread)
1502{
1503	SpinLocker threadDebugInfoLocker(thread->debug_info.lock);
1504
1505	if (thread->debug_info.profile.samples != NULL
1506		&& !thread->debug_info.profile.buffer_full) {
1507		// install profiling timer
1508		schedule_profiling_timer(thread,
1509			thread->debug_info.profile.interval_left);
1510	}
1511}
1512
1513
1514/*!	\brief Called by the debug nub thread of a team to broadcast a message to
1515		all threads of the team that are initialized for debugging (and
1516		thus have a debug port).
1517*/
1518static void
1519broadcast_debugged_thread_message(Thread *nubThread, int32 code,
1520	const void *message, int32 size)
1521{
1522	// iterate through the threads
1523	thread_info threadInfo;
1524	int32 cookie = 0;
1525	while (get_next_thread_info(nubThread->team->id, &cookie, &threadInfo)
1526			== B_OK) {
1527		// get the thread and lock it
1528		Thread* thread = Thread::GetAndLock(threadInfo.thread);
1529		if (thread == NULL)
1530			continue;
1531
1532		BReference<Thread> threadReference(thread, true);
1533		ThreadLocker threadLocker(thread, true);
1534
1535		// get the thread's debug port
1536		InterruptsSpinLocker threadDebugInfoLocker(thread->debug_info.lock);
1537
1538		port_id threadDebugPort = -1;
1539		if (thread && thread != nubThread && thread->team == nubThread->team
1540			&& (thread->debug_info.flags & B_THREAD_DEBUG_INITIALIZED) != 0
1541			&& (thread->debug_info.flags & B_THREAD_DEBUG_STOPPED) != 0) {
1542			threadDebugPort = thread->debug_info.debug_port;
1543		}
1544
1545		threadDebugInfoLocker.Unlock();
1546		threadLocker.Unlock();
1547
1548		// send the message to the thread
1549		if (threadDebugPort >= 0) {
1550			status_t error = kill_interruptable_write_port(threadDebugPort,
1551				code, message, size);
1552			if (error != B_OK) {
1553				TRACE(("broadcast_debugged_thread_message(): Failed to send "
1554					"message to thread %" B_PRId32 ": %" B_PRIx32 "\n",
1555					thread->id, error));
1556			}
1557		}
1558	}
1559}
1560
1561
1562static void
1563nub_thread_cleanup(Thread *nubThread)
1564{
1565	TRACE(("nub_thread_cleanup(%" B_PRId32 "): debugger port: %" B_PRId32 "\n",
1566		nubThread->id, nubThread->team->debug_info.debugger_port));
1567
1568	ConditionVariable debugChangeCondition;
1569	debugChangeCondition.Init(nubThread->team, "debug change condition");
1570	prepare_debugger_change(nubThread->team, debugChangeCondition);
1571
1572	team_debug_info teamDebugInfo;
1573	bool destroyDebugInfo = false;
1574
1575	TeamLocker teamLocker(nubThread->team);
1576		// required by update_threads_debugger_installed_flag()
1577
1578	cpu_status state = disable_interrupts();
1579	GRAB_TEAM_DEBUG_INFO_LOCK(nubThread->team->debug_info);
1580
1581	team_debug_info &info = nubThread->team->debug_info;
1582	if (info.flags & B_TEAM_DEBUG_DEBUGGER_INSTALLED
1583		&& info.nub_thread == nubThread->id) {
1584		teamDebugInfo = info;
1585		clear_team_debug_info(&info, false);
1586		destroyDebugInfo = true;
1587	}
1588
1589	// update the thread::flags fields
1590	update_threads_debugger_installed_flag(nubThread->team);
1591
1592	RELEASE_TEAM_DEBUG_INFO_LOCK(nubThread->team->debug_info);
1593	restore_interrupts(state);
1594
1595	teamLocker.Unlock();
1596
1597	if (destroyDebugInfo)
1598		teamDebugInfo.breakpoint_manager->RemoveAllBreakpoints();
1599
1600	finish_debugger_change(nubThread->team);
1601
1602	if (destroyDebugInfo)
1603		destroy_team_debug_info(&teamDebugInfo);
1604
1605	// notify all threads that the debugger is gone
1606	broadcast_debugged_thread_message(nubThread,
1607		B_DEBUGGED_THREAD_DEBUGGER_CHANGED, NULL, 0);
1608}
1609
1610
1611/**	\brief Debug nub thread helper function that returns the debug port of
1612 *		   a thread of the same team.
1613 */
1614static status_t
1615debug_nub_thread_get_thread_debug_port(Thread *nubThread,
1616	thread_id threadID, port_id &threadDebugPort)
1617{
1618	threadDebugPort = -1;
1619
1620	// get the thread
1621	Thread* thread = Thread::GetAndLock(threadID);
1622	if (thread == NULL)
1623		return B_BAD_THREAD_ID;
1624	BReference<Thread> threadReference(thread, true);
1625	ThreadLocker threadLocker(thread, true);
1626
1627	// get the debug port
1628	InterruptsSpinLocker threadDebugInfoLocker(thread->debug_info.lock);
1629
1630	if (thread->team != nubThread->team)
1631		return B_BAD_VALUE;
1632	if ((thread->debug_info.flags & B_THREAD_DEBUG_STOPPED) == 0)
1633		return B_BAD_THREAD_STATE;
1634
1635	threadDebugPort = thread->debug_info.debug_port;
1636
1637	threadDebugInfoLocker.Unlock();
1638
1639	if (threadDebugPort < 0)
1640		return B_ERROR;
1641
1642	return B_OK;
1643}
1644
1645
1646static status_t
1647debug_nub_thread(void *)
1648{
1649	Thread *nubThread = thread_get_current_thread();
1650
1651	// check, if we're still the current nub thread and get our port
1652	cpu_status state = disable_interrupts();
1653	GRAB_TEAM_DEBUG_INFO_LOCK(nubThread->team->debug_info);
1654
1655	if (nubThread->team->debug_info.nub_thread != nubThread->id) {
1656		RELEASE_TEAM_DEBUG_INFO_LOCK(nubThread->team->debug_info);
1657		restore_interrupts(state);
1658		return 0;
1659	}
1660
1661	port_id port = nubThread->team->debug_info.nub_port;
1662	sem_id writeLock = nubThread->team->debug_info.debugger_write_lock;
1663	BreakpointManager* breakpointManager
1664		= nubThread->team->debug_info.breakpoint_manager;
1665
1666	RELEASE_TEAM_DEBUG_INFO_LOCK(nubThread->team->debug_info);
1667	restore_interrupts(state);
1668
1669	TRACE(("debug_nub_thread() thread: %" B_PRId32 ", team %" B_PRId32 ", nub "
1670		"port: %" B_PRId32 "\n", nubThread->id, nubThread->team->id, port));
1671
1672	// notify all threads that a debugger has been installed
1673	broadcast_debugged_thread_message(nubThread,
1674		B_DEBUGGED_THREAD_DEBUGGER_CHANGED, NULL, 0);
1675
1676	// command processing loop
1677	while (true) {
1678		int32 command;
1679		debug_nub_message_data message;
1680		ssize_t messageSize = read_port_etc(port, &command, &message,
1681			sizeof(message), B_KILL_CAN_INTERRUPT, 0);
1682
1683		if (messageSize < 0) {
1684			// The port is no longer valid or we were interrupted by a kill
1685			// signal: If we are still listed in the team's debug info as nub
1686			// thread, we need to update that.
1687			nub_thread_cleanup(nubThread);
1688
1689			TRACE(("nub thread %" B_PRId32 ": terminating: %lx\n",
1690				nubThread->id, messageSize));
1691
1692			return messageSize;
1693		}
1694
1695		bool sendReply = false;
1696		union {
1697			debug_nub_read_memory_reply			read_memory;
1698			debug_nub_write_memory_reply		write_memory;
1699			debug_nub_get_cpu_state_reply		get_cpu_state;
1700			debug_nub_set_breakpoint_reply		set_breakpoint;
1701			debug_nub_set_watchpoint_reply		set_watchpoint;
1702			debug_nub_get_signal_masks_reply	get_signal_masks;
1703			debug_nub_get_signal_handler_reply	get_signal_handler;
1704			debug_nub_start_profiler_reply		start_profiler;
1705			debug_profiler_update				profiler_update;
1706			debug_nub_write_core_file_reply		write_core_file;
1707		} reply;
1708		int32 replySize = 0;
1709		port_id replyPort = -1;
1710
1711		// process the command
1712		switch (command) {
1713			case B_DEBUG_MESSAGE_READ_MEMORY:
1714			{
1715				// get the parameters
1716				replyPort = message.read_memory.reply_port;
1717				void *address = message.read_memory.address;
1718				int32 size = message.read_memory.size;
1719				status_t result = B_OK;
1720
1721				// check the parameters
1722				if (!BreakpointManager::CanAccessAddress(address, false))
1723					result = B_BAD_ADDRESS;
1724				else if (size <= 0 || size > B_MAX_READ_WRITE_MEMORY_SIZE)
1725					result = B_BAD_VALUE;
1726
1727				// read the memory
1728				size_t bytesRead = 0;
1729				if (result == B_OK) {
1730					result = breakpointManager->ReadMemory(address,
1731						reply.read_memory.data, size, bytesRead);
1732				}
1733				reply.read_memory.error = result;
1734
1735				TRACE(("nub thread %" B_PRId32 ": B_DEBUG_MESSAGE_READ_MEMORY: "
1736					"reply port: %" B_PRId32 ", address: %p, size: %" B_PRId32
1737					", result: %" B_PRIx32 ", read: %ld\n", nubThread->id,
1738					replyPort, address, size, result, bytesRead));
1739
1740				// send only as much data as necessary
1741				reply.read_memory.size = bytesRead;
1742				replySize = reply.read_memory.data + bytesRead - (char*)&reply;
1743				sendReply = true;
1744				break;
1745			}
1746
1747			case B_DEBUG_MESSAGE_WRITE_MEMORY:
1748			{
1749				// get the parameters
1750				replyPort = message.write_memory.reply_port;
1751				void *address = message.write_memory.address;
1752				int32 size = message.write_memory.size;
1753				const char *data = message.write_memory.data;
1754				int32 realSize = (char*)&message + messageSize - data;
1755				status_t result = B_OK;
1756
1757				// check the parameters
1758				if (!BreakpointManager::CanAccessAddress(address, true))
1759					result = B_BAD_ADDRESS;
1760				else if (size <= 0 || size > realSize)
1761					result = B_BAD_VALUE;
1762
1763				// write the memory
1764				size_t bytesWritten = 0;
1765				if (result == B_OK) {
1766					result = breakpointManager->WriteMemory(address, data, size,
1767						bytesWritten);
1768				}
1769				reply.write_memory.error = result;
1770
1771				TRACE(("nub thread %" B_PRId32 ": B_DEBUG_MESSAGE_WRITE_MEMORY: "
1772					"reply port: %" B_PRId32 ", address: %p, size: %" B_PRId32
1773					", result: %" B_PRIx32 ", written: %ld\n", nubThread->id,
1774					replyPort, address, size, result, bytesWritten));
1775
1776				reply.write_memory.size = bytesWritten;
1777				sendReply = true;
1778				replySize = sizeof(debug_nub_write_memory_reply);
1779				break;
1780			}
1781
1782			case B_DEBUG_MESSAGE_SET_TEAM_FLAGS:
1783			{
1784				// get the parameters
1785				int32 flags = message.set_team_flags.flags
1786					& B_TEAM_DEBUG_USER_FLAG_MASK;
1787
1788				TRACE(("nub thread %" B_PRId32 ": B_DEBUG_MESSAGE_SET_TEAM_FLAGS"
1789					": flags: %" B_PRIx32 "\n", nubThread->id, flags));
1790
1791				Team *team = thread_get_current_thread()->team;
1792
1793				// set the flags
1794				cpu_status state = disable_interrupts();
1795				GRAB_TEAM_DEBUG_INFO_LOCK(team->debug_info);
1796
1797				flags |= team->debug_info.flags & B_TEAM_DEBUG_KERNEL_FLAG_MASK;
1798				atomic_set(&team->debug_info.flags, flags);
1799
1800				RELEASE_TEAM_DEBUG_INFO_LOCK(team->debug_info);
1801				restore_interrupts(state);
1802
1803				break;
1804			}
1805
1806			case B_DEBUG_MESSAGE_SET_THREAD_FLAGS:
1807			{
1808				// get the parameters
1809				thread_id threadID = message.set_thread_flags.thread;
1810				int32 flags = message.set_thread_flags.flags
1811					& B_THREAD_DEBUG_USER_FLAG_MASK;
1812
1813				TRACE(("nub thread %" B_PRId32 ": B_DEBUG_MESSAGE_SET_THREAD_FLAGS"
1814					": thread: %" B_PRId32 ", flags: %" B_PRIx32 "\n",
1815					nubThread->id, threadID, flags));
1816
1817				// set the flags
1818				Thread* thread = Thread::GetAndLock(threadID);
1819				if (thread == NULL)
1820					break;
1821				BReference<Thread> threadReference(thread, true);
1822				ThreadLocker threadLocker(thread, true);
1823
1824				InterruptsSpinLocker threadDebugInfoLocker(
1825					thread->debug_info.lock);
1826
1827				if (thread->team == thread_get_current_thread()->team) {
1828					flags |= thread->debug_info.flags
1829						& B_THREAD_DEBUG_KERNEL_FLAG_MASK;
1830					atomic_set(&thread->debug_info.flags, flags);
1831				}
1832
1833				break;
1834			}
1835
1836			case B_DEBUG_MESSAGE_CONTINUE_THREAD:
1837			{
1838				// get the parameters
1839				thread_id threadID;
1840				uint32 handleEvent;
1841				bool singleStep;
1842
1843				threadID = message.continue_thread.thread;
1844				handleEvent = message.continue_thread.handle_event;
1845				singleStep = message.continue_thread.single_step;
1846
1847				TRACE(("nub thread %" B_PRId32 ": B_DEBUG_MESSAGE_CONTINUE_THREAD"
1848					": thread: %" B_PRId32 ", handle event: %" B_PRIu32 ", "
1849					"single step: %d\n", nubThread->id, threadID, handleEvent,
1850					singleStep));
1851
1852				// find the thread and get its debug port
1853				port_id threadDebugPort = -1;
1854				status_t result = debug_nub_thread_get_thread_debug_port(
1855					nubThread, threadID, threadDebugPort);
1856
1857				// send a message to the debugged thread
1858				if (result == B_OK) {
1859					debugged_thread_continue commandMessage;
1860					commandMessage.handle_event = handleEvent;
1861					commandMessage.single_step = singleStep;
1862
1863					result = write_port(threadDebugPort,
1864						B_DEBUGGED_THREAD_MESSAGE_CONTINUE,
1865						&commandMessage, sizeof(commandMessage));
1866				} else if (result == B_BAD_THREAD_STATE) {
1867					Thread* thread = Thread::GetAndLock(threadID);
1868					if (thread == NULL)
1869						break;
1870
1871					BReference<Thread> threadReference(thread, true);
1872					ThreadLocker threadLocker(thread, true);
1873					if (thread->state == B_THREAD_SUSPENDED) {
1874						threadLocker.Unlock();
1875						resume_thread(threadID);
1876						break;
1877					}
1878				}
1879
1880				break;
1881			}
1882
1883			case B_DEBUG_MESSAGE_SET_CPU_STATE:
1884			{
1885				// get the parameters
1886				thread_id threadID = message.set_cpu_state.thread;
1887				const debug_cpu_state &cpuState
1888					= message.set_cpu_state.cpu_state;
1889
1890				TRACE(("nub thread %" B_PRId32 ": B_DEBUG_MESSAGE_SET_CPU_STATE"
1891					": thread: %" B_PRId32 "\n", nubThread->id, threadID));
1892
1893				// find the thread and get its debug port
1894				port_id threadDebugPort = -1;
1895				status_t result = debug_nub_thread_get_thread_debug_port(
1896					nubThread, threadID, threadDebugPort);
1897
1898				// send a message to the debugged thread
1899				if (result == B_OK) {
1900					debugged_thread_set_cpu_state commandMessage;
1901					memcpy(&commandMessage.cpu_state, &cpuState,
1902						sizeof(debug_cpu_state));
1903					write_port(threadDebugPort,
1904						B_DEBUGGED_THREAD_SET_CPU_STATE,
1905						&commandMessage, sizeof(commandMessage));
1906				}
1907
1908				break;
1909			}
1910
1911			case B_DEBUG_MESSAGE_GET_CPU_STATE:
1912			{
1913				// get the parameters
1914				thread_id threadID = message.get_cpu_state.thread;
1915				replyPort = message.get_cpu_state.reply_port;
1916
1917				TRACE(("nub thread %" B_PRId32 ": B_DEBUG_MESSAGE_GET_CPU_STATE"
1918					": thread: %" B_PRId32 "\n", nubThread->id, threadID));
1919
1920				// find the thread and get its debug port
1921				port_id threadDebugPort = -1;
1922				status_t result = debug_nub_thread_get_thread_debug_port(
1923					nubThread, threadID, threadDebugPort);
1924
1925				// send a message to the debugged thread
1926				if (threadDebugPort >= 0) {
1927					debugged_thread_get_cpu_state commandMessage;
1928					commandMessage.reply_port = replyPort;
1929					result = write_port(threadDebugPort,
1930						B_DEBUGGED_THREAD_GET_CPU_STATE, &commandMessage,
1931						sizeof(commandMessage));
1932				}
1933
1934				// send a reply to the debugger in case of error
1935				if (result != B_OK) {
1936					reply.get_cpu_state.error = result;
1937					sendReply = true;
1938					replySize = sizeof(reply.get_cpu_state);
1939				}
1940
1941				break;
1942			}
1943
1944			case B_DEBUG_MESSAGE_SET_BREAKPOINT:
1945			{
1946				// get the parameters
1947				replyPort = message.set_breakpoint.reply_port;
1948				void *address = message.set_breakpoint.address;
1949
1950				TRACE(("nub thread %" B_PRId32 ": B_DEBUG_MESSAGE_SET_BREAKPOINT"
1951					": address: %p\n", nubThread->id, address));
1952
1953				// check the address
1954				status_t result = B_OK;
1955				if (address == NULL
1956					|| !BreakpointManager::CanAccessAddress(address, false)) {
1957					result = B_BAD_ADDRESS;
1958				}
1959
1960				// set the breakpoint
1961				if (result == B_OK)
1962					result = breakpointManager->InstallBreakpoint(address);
1963
1964				if (result == B_OK)
1965					update_threads_breakpoints_flag();
1966
1967				// prepare the reply
1968				reply.set_breakpoint.error = result;
1969				replySize = sizeof(reply.set_breakpoint);
1970				sendReply = true;
1971
1972				break;
1973			}
1974
1975			case B_DEBUG_MESSAGE_CLEAR_BREAKPOINT:
1976			{
1977				// get the parameters
1978				void *address = message.clear_breakpoint.address;
1979
1980				TRACE(("nub thread %" B_PRId32 ": B_DEBUG_MESSAGE_CLEAR_BREAKPOINT"
1981					": address: %p\n", nubThread->id, address));
1982
1983				// check the address
1984				status_t result = B_OK;
1985				if (address == NULL
1986					|| !BreakpointManager::CanAccessAddress(address, false)) {
1987					result = B_BAD_ADDRESS;
1988				}
1989
1990				// clear the breakpoint
1991				if (result == B_OK)
1992					result = breakpointManager->UninstallBreakpoint(address);
1993
1994				if (result == B_OK)
1995					update_threads_breakpoints_flag();
1996
1997				break;
1998			}
1999
2000			case B_DEBUG_MESSAGE_SET_WATCHPOINT:
2001			{
2002				// get the parameters
2003				replyPort = message.set_watchpoint.reply_port;
2004				void *address = message.set_watchpoint.address;
2005				uint32 type = message.set_watchpoint.type;
2006				int32 length = message.set_watchpoint.length;
2007
2008				TRACE(("nub thread %" B_PRId32 ": B_DEBUG_MESSAGE_SET_WATCHPOINT"
2009					": address: %p, type: %" B_PRIu32 ", length: %" B_PRId32 "\n",
2010					nubThread->id, address, type, length));
2011
2012				// check the address and size
2013				status_t result = B_OK;
2014				if (address == NULL
2015					|| !BreakpointManager::CanAccessAddress(address, false)) {
2016					result = B_BAD_ADDRESS;
2017				}
2018				if (length < 0)
2019					result = B_BAD_VALUE;
2020
2021				// set the watchpoint
2022				if (result == B_OK) {
2023					result = breakpointManager->InstallWatchpoint(address, type,
2024						length);
2025				}
2026
2027				if (result == B_OK)
2028					update_threads_breakpoints_flag();
2029
2030				// prepare the reply
2031				reply.set_watchpoint.error = result;
2032				replySize = sizeof(reply.set_watchpoint);
2033				sendReply = true;
2034
2035				break;
2036			}
2037
2038			case B_DEBUG_MESSAGE_CLEAR_WATCHPOINT:
2039			{
2040				// get the parameters
2041				void *address = message.clear_watchpoint.address;
2042
2043				TRACE(("nub thread %" B_PRId32 ": B_DEBUG_MESSAGE_CLEAR_WATCHPOINT"
2044					": address: %p\n", nubThread->id, address));
2045
2046				// check the address
2047				status_t result = B_OK;
2048				if (address == NULL
2049					|| !BreakpointManager::CanAccessAddress(address, false)) {
2050					result = B_BAD_ADDRESS;
2051				}
2052
2053				// clear the watchpoint
2054				if (result == B_OK)
2055					result = breakpointManager->UninstallWatchpoint(address);
2056
2057				if (result == B_OK)
2058					update_threads_breakpoints_flag();
2059
2060				break;
2061			}
2062
2063			case B_DEBUG_MESSAGE_SET_SIGNAL_MASKS:
2064			{
2065				// get the parameters
2066				thread_id threadID = message.set_signal_masks.thread;
2067				uint64 ignore = message.set_signal_masks.ignore_mask;
2068				uint64 ignoreOnce = message.set_signal_masks.ignore_once_mask;
2069				uint32 ignoreOp = message.set_signal_masks.ignore_op;
2070				uint32 ignoreOnceOp = message.set_signal_masks.ignore_once_op;
2071
2072				TRACE(("nub thread %" B_PRId32 ": B_DEBUG_MESSAGE_SET_SIGNAL_MASKS"
2073					": thread: %" B_PRId32 ", ignore: %" B_PRIx64 " (op: %"
2074					B_PRIu32 "), ignore once: %" B_PRIx64 " (op: %" B_PRIu32
2075					")\n", nubThread->id, threadID, ignore, ignoreOp,
2076					ignoreOnce, ignoreOnceOp));
2077
2078				// set the masks
2079				Thread* thread = Thread::GetAndLock(threadID);
2080				if (thread == NULL)
2081					break;
2082				BReference<Thread> threadReference(thread, true);
2083				ThreadLocker threadLocker(thread, true);
2084
2085				InterruptsSpinLocker threadDebugInfoLocker(
2086					thread->debug_info.lock);
2087
2088				if (thread->team == thread_get_current_thread()->team) {
2089					thread_debug_info &threadDebugInfo = thread->debug_info;
2090					// set ignore mask
2091					switch (ignoreOp) {
2092						case B_DEBUG_SIGNAL_MASK_AND:
2093							threadDebugInfo.ignore_signals &= ignore;
2094							break;
2095						case B_DEBUG_SIGNAL_MASK_OR:
2096							threadDebugInfo.ignore_signals |= ignore;
2097							break;
2098						case B_DEBUG_SIGNAL_MASK_SET:
2099							threadDebugInfo.ignore_signals = ignore;
2100							break;
2101					}
2102
2103					// set ignore once mask
2104					switch (ignoreOnceOp) {
2105						case B_DEBUG_SIGNAL_MASK_AND:
2106							threadDebugInfo.ignore_signals_once &= ignoreOnce;
2107							break;
2108						case B_DEBUG_SIGNAL_MASK_OR:
2109							threadDebugInfo.ignore_signals_once |= ignoreOnce;
2110							break;
2111						case B_DEBUG_SIGNAL_MASK_SET:
2112							threadDebugInfo.ignore_signals_once = ignoreOnce;
2113							break;
2114					}
2115				}
2116
2117				break;
2118			}
2119
2120			case B_DEBUG_MESSAGE_GET_SIGNAL_MASKS:
2121			{
2122				// get the parameters
2123				replyPort = message.get_signal_masks.reply_port;
2124				thread_id threadID = message.get_signal_masks.thread;
2125				status_t result = B_OK;
2126
2127				// get the masks
2128				uint64 ignore = 0;
2129				uint64 ignoreOnce = 0;
2130
2131				Thread* thread = Thread::GetAndLock(threadID);
2132				if (thread != NULL) {
2133					BReference<Thread> threadReference(thread, true);
2134					ThreadLocker threadLocker(thread, true);
2135
2136					InterruptsSpinLocker threadDebugInfoLocker(
2137						thread->debug_info.lock);
2138
2139					ignore = thread->debug_info.ignore_signals;
2140					ignoreOnce = thread->debug_info.ignore_signals_once;
2141				} else
2142					result = B_BAD_THREAD_ID;
2143
2144				TRACE(("nub thread %" B_PRId32 ": B_DEBUG_MESSAGE_GET_SIGNAL_MASKS"
2145					": reply port: %" B_PRId32 ", thread: %" B_PRId32 ", "
2146					"ignore: %" B_PRIx64 ", ignore once: %" B_PRIx64 ", result: "
2147					"%" B_PRIx32 "\n", nubThread->id, replyPort, threadID,
2148					ignore, ignoreOnce, result));
2149
2150				// prepare the message
2151				reply.get_signal_masks.error = result;
2152				reply.get_signal_masks.ignore_mask = ignore;
2153				reply.get_signal_masks.ignore_once_mask = ignoreOnce;
2154				replySize = sizeof(reply.get_signal_masks);
2155				sendReply = true;
2156				break;
2157			}
2158
2159			case B_DEBUG_MESSAGE_SET_SIGNAL_HANDLER:
2160			{
2161				// get the parameters
2162				int signal = message.set_signal_handler.signal;
2163				struct sigaction &handler = message.set_signal_handler.handler;
2164
2165				TRACE(("nub thread %" B_PRId32 ": B_DEBUG_MESSAGE_SET_SIGNAL_HANDLER"
2166					": signal: %d, handler: %p\n", nubThread->id, signal,
2167					handler.sa_handler));
2168
2169				// set the handler
2170				sigaction(signal, &handler, NULL);
2171
2172				break;
2173			}
2174
2175			case B_DEBUG_MESSAGE_GET_SIGNAL_HANDLER:
2176			{
2177				// get the parameters
2178				replyPort = message.get_signal_handler.reply_port;
2179				int signal = message.get_signal_handler.signal;
2180				status_t result = B_OK;
2181
2182				// get the handler
2183				if (sigaction(signal, NULL, &reply.get_signal_handler.handler)
2184						!= 0) {
2185					result = errno;
2186				}
2187
2188				TRACE(("nub thread %" B_PRId32 ": B_DEBUG_MESSAGE_GET_SIGNAL_HANDLER"
2189					": reply port: %" B_PRId32 ", signal: %d, handler: %p\n",
2190					nubThread->id, replyPort, signal,
2191					reply.get_signal_handler.handler.sa_handler));
2192
2193				// prepare the message
2194				reply.get_signal_handler.error = result;
2195				replySize = sizeof(reply.get_signal_handler);
2196				sendReply = true;
2197				break;
2198			}
2199
2200			case B_DEBUG_MESSAGE_PREPARE_HANDOVER:
2201			{
2202				TRACE(("nub thread %" B_PRId32 ": B_DEBUG_MESSAGE_PREPARE_HANDOVER"
2203					"\n", nubThread->id));
2204
2205				Team *team = nubThread->team;
2206
2207				// Acquire the debugger write lock. As soon as we have it and
2208				// have set the B_TEAM_DEBUG_DEBUGGER_HANDOVER flag, no thread
2209				// will write anything to the debugger port anymore.
2210				status_t result = acquire_sem_etc(writeLock, 1,
2211					B_KILL_CAN_INTERRUPT, 0);
2212				if (result == B_OK) {
2213					// set the respective team debug flag
2214					cpu_status state = disable_interrupts();
2215					GRAB_TEAM_DEBUG_INFO_LOCK(team->debug_info);
2216
2217					atomic_or(&team->debug_info.flags,
2218						B_TEAM_DEBUG_DEBUGGER_HANDOVER);
2219					BreakpointManager* breakpointManager
2220						= team->debug_info.breakpoint_manager;
2221
2222					RELEASE_TEAM_DEBUG_INFO_LOCK(team->debug_info);
2223					restore_interrupts(state);
2224
2225					// remove all installed breakpoints
2226					breakpointManager->RemoveAllBreakpoints();
2227
2228					release_sem(writeLock);
2229				} else {
2230					// We probably got a SIGKILL. If so, we will terminate when
2231					// reading the next message fails.
2232				}
2233
2234				break;
2235			}
2236
2237			case B_DEBUG_MESSAGE_HANDED_OVER:
2238			{
2239				// notify all threads that the debugger has changed
2240				broadcast_debugged_thread_message(nubThread,
2241					B_DEBUGGED_THREAD_DEBUGGER_CHANGED, NULL, 0);
2242
2243				break;
2244			}
2245
2246			case B_DEBUG_START_PROFILER:
2247			{
2248				// get the parameters
2249				thread_id threadID = message.start_profiler.thread;
2250				replyPort = message.start_profiler.reply_port;
2251				area_id sampleArea = message.start_profiler.sample_area;
2252				int32 stackDepth = message.start_profiler.stack_depth;
2253				bool variableStackDepth
2254					= message.start_profiler.variable_stack_depth;
2255				bigtime_t interval = max_c(message.start_profiler.interval,
2256					B_DEBUG_MIN_PROFILE_INTERVAL);
2257				status_t result = B_OK;
2258
2259				TRACE(("nub thread %" B_PRId32 ": B_DEBUG_START_PROFILER: "
2260					"thread: %" B_PRId32 ", sample area: %" B_PRId32 "\n",
2261					nubThread->id, threadID, sampleArea));
2262
2263				if (stackDepth < 1)
2264					stackDepth = 1;
2265				else if (stackDepth > B_DEBUG_STACK_TRACE_DEPTH)
2266					stackDepth = B_DEBUG_STACK_TRACE_DEPTH;
2267
2268				// provision for an extra entry per hit (for the number of
2269				// samples), if variable stack depth
2270				if (variableStackDepth)
2271					stackDepth++;
2272
2273				// clone the sample area
2274				area_info areaInfo;
2275				if (result == B_OK)
2276					result = get_area_info(sampleArea, &areaInfo);
2277
2278				area_id clonedSampleArea = -1;
2279				void* samples = NULL;
2280				if (result == B_OK) {
2281					clonedSampleArea = clone_area("profiling samples", &samples,
2282						B_ANY_KERNEL_ADDRESS,
2283						B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA,
2284						sampleArea);
2285					if (clonedSampleArea >= 0) {
2286						// we need the memory locked
2287						result = lock_memory(samples, areaInfo.size,
2288							B_READ_DEVICE);
2289						if (result != B_OK) {
2290							delete_area(clonedSampleArea);
2291							clonedSampleArea = -1;
2292						}
2293					} else
2294						result = clonedSampleArea;
2295				}
2296
2297				// get the thread and set the profile info
2298				int32 imageEvent = nubThread->team->debug_info.image_event;
2299				if (result == B_OK) {
2300					Thread* thread = Thread::GetAndLock(threadID);
2301					BReference<Thread> threadReference(thread, true);
2302					ThreadLocker threadLocker(thread, true);
2303
2304					if (thread != NULL && thread->team == nubThread->team) {
2305						thread_debug_info &threadDebugInfo = thread->debug_info;
2306
2307						InterruptsSpinLocker threadDebugInfoLocker(
2308							threadDebugInfo.lock);
2309
2310						if (threadDebugInfo.profile.samples == NULL) {
2311							threadDebugInfo.profile.interval = interval;
2312							threadDebugInfo.profile.sample_area
2313								= clonedSampleArea;
2314							threadDebugInfo.profile.samples = (addr_t*)samples;
2315							threadDebugInfo.profile.max_samples
2316								= areaInfo.size / sizeof(addr_t);
2317							threadDebugInfo.profile.flush_threshold
2318								= threadDebugInfo.profile.max_samples
2319									* B_DEBUG_PROFILE_BUFFER_FLUSH_THRESHOLD
2320									/ 100;
2321							threadDebugInfo.profile.sample_count = 0;
2322							threadDebugInfo.profile.dropped_ticks = 0;
2323							threadDebugInfo.profile.stack_depth = stackDepth;
2324							threadDebugInfo.profile.variable_stack_depth
2325								= variableStackDepth;
2326							threadDebugInfo.profile.buffer_full = false;
2327							threadDebugInfo.profile.interval_left = interval;
2328							threadDebugInfo.profile.installed_timer = NULL;
2329							threadDebugInfo.profile.image_event = imageEvent;
2330							threadDebugInfo.profile.last_image_event
2331								= imageEvent;
2332						} else
2333							result = B_BAD_VALUE;
2334					} else
2335						result = B_BAD_THREAD_ID;
2336				}
2337
2338				// on error unlock and delete the sample area
2339				if (result != B_OK) {
2340					if (clonedSampleArea >= 0) {
2341						unlock_memory(samples, areaInfo.size, B_READ_DEVICE);
2342						delete_area(clonedSampleArea);
2343					}
2344				}
2345
2346				// send a reply to the debugger
2347				reply.start_profiler.error = result;
2348				reply.start_profiler.interval = interval;
2349				reply.start_profiler.image_event = imageEvent;
2350				sendReply = true;
2351				replySize = sizeof(reply.start_profiler);
2352
2353				break;
2354			}
2355
2356			case B_DEBUG_STOP_PROFILER:
2357			{
2358				// get the parameters
2359				thread_id threadID = message.stop_profiler.thread;
2360				replyPort = message.stop_profiler.reply_port;
2361				status_t result = B_OK;
2362
2363				TRACE(("nub thread %" B_PRId32 ": B_DEBUG_STOP_PROFILER: "
2364					"thread: %" B_PRId32 "\n", nubThread->id, threadID));
2365
2366				area_id sampleArea = -1;
2367				addr_t* samples = NULL;
2368				int32 sampleCount = 0;
2369				int32 stackDepth = 0;
2370				bool variableStackDepth = false;
2371				int32 imageEvent = 0;
2372				int32 droppedTicks = 0;
2373
2374				// get the thread and detach the profile info
2375				Thread* thread = Thread::GetAndLock(threadID);
2376				BReference<Thread> threadReference(thread, true);
2377				ThreadLocker threadLocker(thread, true);
2378
2379				if (thread && thread->team == nubThread->team) {
2380					thread_debug_info &threadDebugInfo = thread->debug_info;
2381
2382					InterruptsSpinLocker threadDebugInfoLocker(
2383						threadDebugInfo.lock);
2384
2385					if (threadDebugInfo.profile.samples != NULL) {
2386						sampleArea = threadDebugInfo.profile.sample_area;
2387						samples = threadDebugInfo.profile.samples;
2388						sampleCount = threadDebugInfo.profile.sample_count;
2389						droppedTicks = threadDebugInfo.profile.dropped_ticks;
2390						stackDepth = threadDebugInfo.profile.stack_depth;
2391						variableStackDepth
2392							= threadDebugInfo.profile.variable_stack_depth;
2393						imageEvent = threadDebugInfo.profile.image_event;
2394						threadDebugInfo.profile.sample_area = -1;
2395						threadDebugInfo.profile.samples = NULL;
2396						threadDebugInfo.profile.buffer_full = false;
2397						threadDebugInfo.profile.dropped_ticks = 0;
2398					} else
2399						result = B_BAD_VALUE;
2400				} else
2401					result = B_BAD_THREAD_ID;
2402
2403				threadLocker.Unlock();
2404
2405				// prepare the reply
2406				if (result == B_OK) {
2407					reply.profiler_update.origin.thread = threadID;
2408					reply.profiler_update.image_event = imageEvent;
2409					reply.profiler_update.stack_depth = stackDepth;
2410					reply.profiler_update.variable_stack_depth
2411						= variableStackDepth;
2412					reply.profiler_update.sample_count = sampleCount;
2413					reply.profiler_update.dropped_ticks = droppedTicks;
2414					reply.profiler_update.stopped = true;
2415				} else
2416					reply.profiler_update.origin.thread = result;
2417
2418				replySize = sizeof(debug_profiler_update);
2419				sendReply = true;
2420
2421				if (sampleArea >= 0) {
2422					area_info areaInfo;
2423					if (get_area_info(sampleArea, &areaInfo) == B_OK) {
2424						unlock_memory(samples, areaInfo.size, B_READ_DEVICE);
2425						delete_area(sampleArea);
2426					}
2427				}
2428
2429				break;
2430			}
2431
2432			case B_DEBUG_WRITE_CORE_FILE:
2433			{
2434				// get the parameters
2435				replyPort = message.write_core_file.reply_port;
2436				char* path = message.write_core_file.path;
2437				path[sizeof(message.write_core_file.path) - 1] = '\0';
2438
2439				TRACE(("nub thread %" B_PRId32 ": B_DEBUG_WRITE_CORE_FILE"
2440					": path: %s\n", nubThread->id, path));
2441
2442				// write the core file
2443				status_t result = core_dump_write_core_file(path, false);
2444
2445				// prepare the reply
2446				reply.write_core_file.error = result;
2447				replySize = sizeof(reply.write_core_file);
2448				sendReply = true;
2449
2450				break;
2451			}
2452		}
2453
2454		// send the reply, if necessary
2455		if (sendReply) {
2456			status_t error = kill_interruptable_write_port(replyPort, command,
2457				&reply, replySize);
2458
2459			if (error != B_OK) {
2460				// The debugger port is either not longer existing or we got
2461				// interrupted by a kill signal. In either case we terminate.
2462				TRACE(("nub thread %" B_PRId32 ": failed to send reply to port "
2463					"%" B_PRId32 ": %s\n", nubThread->id, replyPort,
2464					strerror(error)));
2465
2466				nub_thread_cleanup(nubThread);
2467				return error;
2468			}
2469		}
2470	}
2471}
2472
2473
2474/**	\brief Helper function for install_team_debugger(), that sets up the team
2475		   and thread debug infos.
2476
2477	The caller must hold the team's lock as well as the team debug info lock.
2478
2479	The function also clears the arch specific team and thread debug infos
2480	(including among other things formerly set break/watchpoints).
2481 */
2482static void
2483install_team_debugger_init_debug_infos(Team *team, team_id debuggerTeam,
2484	port_id debuggerPort, port_id nubPort, thread_id nubThread,
2485	sem_id debuggerPortWriteLock, thread_id causingThread)
2486{
2487	atomic_set(&team->debug_info.flags,
2488		B_TEAM_DEBUG_DEFAULT_FLAGS | B_TEAM_DEBUG_DEBUGGER_INSTALLED);
2489	team->debug_info.nub_port = nubPort;
2490	team->debug_info.nub_thread = nubThread;
2491	team->debug_info.debugger_team = debuggerTeam;
2492	team->debug_info.debugger_port = debuggerPort;
2493	team->debug_info.debugger_write_lock = debuggerPortWriteLock;
2494	team->debug_info.causing_thread = causingThread;
2495
2496	arch_clear_team_debug_info(&team->debug_info.arch_info);
2497
2498	// set the user debug flags and signal masks of all threads to the default
2499	for (Thread *thread = team->thread_list; thread;
2500			thread = thread->team_next) {
2501		SpinLocker threadDebugInfoLocker(thread->debug_info.lock);
2502
2503		if (thread->id == nubThread) {
2504			atomic_set(&thread->debug_info.flags, B_THREAD_DEBUG_NUB_THREAD);
2505		} else {
2506			int32 flags = thread->debug_info.flags
2507				& ~B_THREAD_DEBUG_USER_FLAG_MASK;
2508			atomic_set(&thread->debug_info.flags,
2509				flags | B_THREAD_DEBUG_DEFAULT_FLAGS);
2510			thread->debug_info.ignore_signals = 0;
2511			thread->debug_info.ignore_signals_once = 0;
2512
2513			arch_clear_thread_debug_info(&thread->debug_info.arch_info);
2514		}
2515	}
2516
2517	// update the thread::flags fields
2518	update_threads_debugger_installed_flag(team);
2519}
2520
2521
2522static port_id
2523install_team_debugger(team_id teamID, port_id debuggerPort,
2524	thread_id causingThread, bool useDefault, bool dontReplace)
2525{
2526	TRACE(("install_team_debugger(team: %" B_PRId32 ", port: %" B_PRId32 ", "
2527		"default: %d, dontReplace: %d)\n", teamID, debuggerPort, useDefault,
2528		dontReplace));
2529
2530	if (useDefault)
2531		debuggerPort = atomic_get(&sDefaultDebuggerPort);
2532
2533	// get the debugger team
2534	port_info debuggerPortInfo;
2535	status_t error = get_port_info(debuggerPort, &debuggerPortInfo);
2536	if (error != B_OK) {
2537		TRACE(("install_team_debugger(): Failed to get debugger port info: "
2538			"%" B_PRIx32 "\n", error));
2539		return error;
2540	}
2541	team_id debuggerTeam = debuggerPortInfo.team;
2542
2543	// Check the debugger team: It must neither be the kernel team nor the
2544	// debugged team.
2545	if (debuggerTeam == team_get_kernel_team_id() || debuggerTeam == teamID) {
2546		TRACE(("install_team_debugger(): Can't debug kernel or debugger team. "
2547			"debugger: %" B_PRId32 ", debugged: %" B_PRId32 "\n", debuggerTeam,
2548			teamID));
2549		return B_NOT_ALLOWED;
2550	}
2551
2552	// get the team
2553	Team* team;
2554	ConditionVariable debugChangeCondition;
2555	debugChangeCondition.Init(NULL, "debug change condition");
2556	error = prepare_debugger_change(teamID, debugChangeCondition, team);
2557	if (error != B_OK)
2558		return error;
2559
2560	// get the real team ID
2561	teamID = team->id;
2562
2563	// check, if a debugger is already installed
2564
2565	bool done = false;
2566	port_id result = B_ERROR;
2567	bool handOver = false;
2568	port_id oldDebuggerPort = -1;
2569	port_id nubPort = -1;
2570
2571	TeamLocker teamLocker(team);
2572	cpu_status state = disable_interrupts();
2573	GRAB_TEAM_DEBUG_INFO_LOCK(team->debug_info);
2574
2575	int32 teamDebugFlags = team->debug_info.flags;
2576
2577	if (teamDebugFlags & B_TEAM_DEBUG_DEBUGGER_INSTALLED) {
2578		// There's already a debugger installed.
2579		if (teamDebugFlags & B_TEAM_DEBUG_DEBUGGER_HANDOVER) {
2580			if (dontReplace) {
2581				// We're fine with already having a debugger.
2582				error = B_OK;
2583				done = true;
2584				result = team->debug_info.nub_port;
2585			} else {
2586				// a handover to another debugger is requested
2587				// Set the handing-over flag -- we'll clear both flags after
2588				// having sent the handed-over message to the new debugger.
2589				atomic_or(&team->debug_info.flags,
2590					B_TEAM_DEBUG_DEBUGGER_HANDING_OVER);
2591
2592				oldDebuggerPort = team->debug_info.debugger_port;
2593				result = nubPort = team->debug_info.nub_port;
2594				if (causingThread < 0)
2595					causingThread = team->debug_info.causing_thread;
2596
2597				// set the new debugger
2598				install_team_debugger_init_debug_infos(team, debuggerTeam,
2599					debuggerPort, nubPort, team->debug_info.nub_thread,
2600					team->debug_info.debugger_write_lock, causingThread);
2601
2602				handOver = true;
2603				done = true;
2604			}
2605		} else {
2606			// there's already a debugger installed
2607			error = (dontReplace ? B_OK : B_BAD_VALUE);
2608			done = true;
2609			result = team->debug_info.nub_port;
2610		}
2611	} else if ((teamDebugFlags & B_TEAM_DEBUG_DEBUGGER_DISABLED) != 0
2612		&& useDefault) {
2613		// No debugger yet, disable_debugger() had been invoked, and we
2614		// would install the default debugger. Just fail.
2615		error = B_BAD_VALUE;
2616	}
2617
2618	RELEASE_TEAM_DEBUG_INFO_LOCK(team->debug_info);
2619	restore_interrupts(state);
2620	teamLocker.Unlock();
2621
2622	if (handOver && set_port_owner(nubPort, debuggerTeam) != B_OK) {
2623		// The old debugger must just have died. Just proceed as
2624		// if there was no debugger installed. We may still be too
2625		// early, in which case we'll fail, but this race condition
2626		// should be unbelievably rare and relatively harmless.
2627		handOver = false;
2628		done = false;
2629	}
2630
2631	if (handOver) {
2632		// prepare the handed-over message
2633		debug_handed_over notification;
2634		notification.origin.thread = -1;
2635		notification.origin.team = teamID;
2636		notification.origin.nub_port = nubPort;
2637		notification.debugger = debuggerTeam;
2638		notification.debugger_port = debuggerPort;
2639		notification.causing_thread = causingThread;
2640
2641		// notify the new debugger
2642		error = write_port_etc(debuggerPort,
2643			B_DEBUGGER_MESSAGE_HANDED_OVER, &notification,
2644			sizeof(notification), B_RELATIVE_TIMEOUT, 0);
2645		if (error != B_OK) {
2646			dprintf("install_team_debugger(): Failed to send message to new "
2647				"debugger: %s\n", strerror(error));
2648		}
2649
2650		// clear the handed-over and handing-over flags
2651		state = disable_interrupts();
2652		GRAB_TEAM_DEBUG_INFO_LOCK(team->debug_info);
2653
2654		atomic_and(&team->debug_info.flags,
2655			~(B_TEAM_DEBUG_DEBUGGER_HANDOVER
2656				| B_TEAM_DEBUG_DEBUGGER_HANDING_OVER));
2657
2658		RELEASE_TEAM_DEBUG_INFO_LOCK(team->debug_info);
2659		restore_interrupts(state);
2660
2661		finish_debugger_change(team);
2662
2663		// notify the nub thread
2664		kill_interruptable_write_port(nubPort, B_DEBUG_MESSAGE_HANDED_OVER,
2665			NULL, 0);
2666
2667		// notify the old debugger
2668		error = write_port_etc(oldDebuggerPort,
2669			B_DEBUGGER_MESSAGE_HANDED_OVER, &notification,
2670			sizeof(notification), B_RELATIVE_TIMEOUT, 0);
2671		if (error != B_OK) {
2672			TRACE(("install_team_debugger(): Failed to send message to old "
2673				"debugger: %s\n", strerror(error)));
2674		}
2675
2676		TRACE(("install_team_debugger() done: handed over to debugger: team: "
2677			"%" B_PRId32 ", port: %" B_PRId32 "\n", debuggerTeam,
2678			debuggerPort));
2679
2680		return result;
2681	}
2682
2683	if (done || error != B_OK) {
2684		TRACE(("install_team_debugger() done1: %" B_PRId32 "\n",
2685			(error == B_OK ? result : error)));
2686		finish_debugger_change(team);
2687		return (error == B_OK ? result : error);
2688	}
2689
2690	// create the debugger write lock semaphore
2691	char nameBuffer[B_OS_NAME_LENGTH];
2692	snprintf(nameBuffer, sizeof(nameBuffer), "team %" B_PRId32 " debugger port "
2693		"write", teamID);
2694	sem_id debuggerWriteLock = create_sem(1, nameBuffer);
2695	if (debuggerWriteLock < 0)
2696		error = debuggerWriteLock;
2697
2698	// create the nub port
2699	snprintf(nameBuffer, sizeof(nameBuffer), "team %" B_PRId32 " debug", teamID);
2700	if (error == B_OK) {
2701		nubPort = create_port(1, nameBuffer);
2702		if (nubPort < 0)
2703			error = nubPort;
2704		else
2705			result = nubPort;
2706	}
2707
2708	// make the debugger team the port owner; thus we know, if the debugger is
2709	// gone and can cleanup
2710	if (error == B_OK)
2711		error = set_port_owner(nubPort, debuggerTeam);
2712
2713	// create the breakpoint manager
2714	BreakpointManager* breakpointManager = NULL;
2715	if (error == B_OK) {
2716		breakpointManager = new(std::nothrow) BreakpointManager;
2717		if (breakpointManager != NULL)
2718			error = breakpointManager->Init();
2719		else
2720			error = B_NO_MEMORY;
2721	}
2722
2723	// spawn the nub thread
2724	thread_id nubThread = -1;
2725	if (error == B_OK) {
2726		snprintf(nameBuffer, sizeof(nameBuffer), "team %" B_PRId32 " debug task",
2727			teamID);
2728		nubThread = spawn_kernel_thread_etc(debug_nub_thread, nameBuffer,
2729			B_NORMAL_PRIORITY, NULL, teamID);
2730		if (nubThread < 0)
2731			error = nubThread;
2732	}
2733
2734	// now adjust the debug info accordingly
2735	if (error == B_OK) {
2736		TeamLocker teamLocker(team);
2737		state = disable_interrupts();
2738		GRAB_TEAM_DEBUG_INFO_LOCK(team->debug_info);
2739
2740		team->debug_info.breakpoint_manager = breakpointManager;
2741		install_team_debugger_init_debug_infos(team, debuggerTeam,
2742			debuggerPort, nubPort, nubThread, debuggerWriteLock,
2743			causingThread);
2744
2745		RELEASE_TEAM_DEBUG_INFO_LOCK(team->debug_info);
2746		restore_interrupts(state);
2747	}
2748
2749	finish_debugger_change(team);
2750
2751	// if everything went fine, resume the nub thread, otherwise clean up
2752	if (error == B_OK) {
2753		resume_thread(nubThread);
2754	} else {
2755		// delete port and terminate thread
2756		if (nubPort >= 0) {
2757			set_port_owner(nubPort, B_CURRENT_TEAM);
2758			delete_port(nubPort);
2759		}
2760		if (nubThread >= 0) {
2761			int32 result;
2762			wait_for_thread(nubThread, &result);
2763		}
2764
2765		delete breakpointManager;
2766	}
2767
2768	TRACE(("install_team_debugger() done2: %" B_PRId32 "\n",
2769		(error == B_OK ? result : error)));
2770	return (error == B_OK ? result : error);
2771}
2772
2773
2774static status_t
2775ensure_debugger_installed()
2776{
2777	port_id port = install_team_debugger(B_CURRENT_TEAM, -1,
2778		thread_get_current_thread_id(), true, true);
2779	return port >= 0 ? B_OK : port;
2780}
2781
2782
2783// #pragma mark -
2784
2785
2786void
2787_user_debugger(const char *userMessage)
2788{
2789	// install the default debugger, if there is none yet
2790	status_t error = ensure_debugger_installed();
2791	if (error != B_OK) {
2792		// time to commit suicide
2793		char buffer[128];
2794		ssize_t length = user_strlcpy(buffer, userMessage, sizeof(buffer));
2795		if (length >= 0) {
2796			dprintf("_user_debugger(): Failed to install debugger. Message is: "
2797				"`%s'\n", buffer);
2798		} else {
2799			dprintf("_user_debugger(): Failed to install debugger. Message is: "
2800				"%p (%s)\n", userMessage, strerror(length));
2801		}
2802		_user_exit_team(1);
2803	}
2804
2805	// prepare the message
2806	debug_debugger_call message;
2807	message.message = (void*)userMessage;
2808
2809	thread_hit_debug_event(B_DEBUGGER_MESSAGE_DEBUGGER_CALL, &message,
2810		sizeof(message), true);
2811}
2812
2813
2814int
2815_user_disable_debugger(int state)
2816{
2817	Team *team = thread_get_current_thread()->team;
2818
2819	TRACE(("_user_disable_debugger(%d): team: %" B_PRId32 "\n", state,
2820		team->id));
2821
2822	cpu_status cpuState = disable_interrupts();
2823	GRAB_TEAM_DEBUG_INFO_LOCK(team->debug_info);
2824
2825	int32 oldFlags;
2826	if (state) {
2827		oldFlags = atomic_or(&team->debug_info.flags,
2828			B_TEAM_DEBUG_DEBUGGER_DISABLED);
2829	} else {
2830		oldFlags = atomic_and(&team->debug_info.flags,
2831			~B_TEAM_DEBUG_DEBUGGER_DISABLED);
2832	}
2833
2834	RELEASE_TEAM_DEBUG_INFO_LOCK(team->debug_info);
2835	restore_interrupts(cpuState);
2836
2837	// TODO: Check, if the return value is really the old state.
2838	return !(oldFlags & B_TEAM_DEBUG_DEBUGGER_DISABLED);
2839}
2840
2841
2842status_t
2843_user_install_default_debugger(port_id debuggerPort)
2844{
2845	// Do not allow non-root processes to install a default debugger.
2846	if (geteuid() != 0)
2847		return B_PERMISSION_DENIED;
2848
2849	// if supplied, check whether the port is a valid port
2850	if (debuggerPort >= 0) {
2851		port_info portInfo;
2852		status_t error = get_port_info(debuggerPort, &portInfo);
2853		if (error != B_OK)
2854			return error;
2855
2856		// the debugger team must not be the kernel team
2857		if (portInfo.team == team_get_kernel_team_id())
2858			return B_NOT_ALLOWED;
2859	}
2860
2861	atomic_set(&sDefaultDebuggerPort, debuggerPort);
2862
2863	return B_OK;
2864}
2865
2866
2867port_id
2868_user_install_team_debugger(team_id teamID, port_id debuggerPort)
2869{
2870	if (geteuid() != 0 && team_geteuid(teamID) != geteuid())
2871		return B_PERMISSION_DENIED;
2872
2873	return install_team_debugger(teamID, debuggerPort, -1, false, false);
2874}
2875
2876
2877status_t
2878_user_remove_team_debugger(team_id teamID)
2879{
2880	Team* team;
2881	ConditionVariable debugChangeCondition;
2882	debugChangeCondition.Init(NULL, "debug change condition");
2883	status_t error = prepare_debugger_change(teamID, debugChangeCondition,
2884		team);
2885	if (error != B_OK)
2886		return error;
2887
2888	InterruptsSpinLocker debugInfoLocker(team->debug_info.lock);
2889
2890	thread_id nubThread = -1;
2891	port_id nubPort = -1;
2892
2893	if (team->debug_info.flags & B_TEAM_DEBUG_DEBUGGER_INSTALLED) {
2894		// there's a debugger installed
2895		nubThread = team->debug_info.nub_thread;
2896		nubPort = team->debug_info.nub_port;
2897	} else {
2898		// no debugger installed
2899		error = B_BAD_VALUE;
2900	}
2901
2902	debugInfoLocker.Unlock();
2903
2904	// Delete the nub port -- this will cause the nub thread to terminate and
2905	// remove the debugger.
2906	if (nubPort >= 0)
2907		delete_port(nubPort);
2908
2909	finish_debugger_change(team);
2910
2911	// wait for the nub thread
2912	if (nubThread >= 0)
2913		wait_for_thread(nubThread, NULL);
2914
2915	return error;
2916}
2917
2918
2919status_t
2920_user_debug_thread(thread_id threadID)
2921{
2922	TRACE(("[%" B_PRId32 "] _user_debug_thread(%" B_PRId32 ")\n",
2923		find_thread(NULL), threadID));
2924
2925	// get the thread
2926	Thread* thread = Thread::GetAndLock(threadID);
2927	if (thread == NULL)
2928		return B_BAD_THREAD_ID;
2929	BReference<Thread> threadReference(thread, true);
2930	ThreadLocker threadLocker(thread, true);
2931
2932	// we can't debug the kernel team
2933	if (thread->team == team_get_kernel_team())
2934		return B_NOT_ALLOWED;
2935
2936	InterruptsLocker interruptsLocker;
2937	SpinLocker threadDebugInfoLocker(thread->debug_info.lock);
2938
2939	// If the thread is already dying, it's too late to debug it.
2940	if ((thread->debug_info.flags & B_THREAD_DEBUG_DYING) != 0)
2941		return B_BAD_THREAD_ID;
2942
2943	// don't debug the nub thread
2944	if ((thread->debug_info.flags & B_THREAD_DEBUG_NUB_THREAD) != 0)
2945		return B_NOT_ALLOWED;
2946
2947	// already marked stopped or being told to stop?
2948	if ((thread->debug_info.flags
2949			& (B_THREAD_DEBUG_STOPPED | B_THREAD_DEBUG_STOP)) != 0) {
2950		return B_OK;
2951	}
2952
2953	// set the flag that tells the thread to stop as soon as possible
2954	atomic_or(&thread->debug_info.flags, B_THREAD_DEBUG_STOP);
2955
2956	update_thread_user_debug_flag(thread);
2957
2958	// send the thread a SIGNAL_DEBUG_THREAD, so it is interrupted (or
2959	// continued)
2960	threadDebugInfoLocker.Unlock();
2961	ReadSpinLocker teamLocker(thread->team_lock);
2962	SpinLocker locker(thread->team->signal_lock);
2963
2964	send_signal_to_thread_locked(thread, SIGNAL_DEBUG_THREAD, NULL, 0);
2965
2966	return B_OK;
2967}
2968
2969
2970void
2971_user_wait_for_debugger(void)
2972{
2973	debug_thread_debugged message = {};
2974	thread_hit_debug_event(B_DEBUGGER_MESSAGE_THREAD_DEBUGGED, &message,
2975		sizeof(message), false);
2976}
2977
2978
2979status_t
2980_user_set_debugger_breakpoint(void *address, uint32 type, int32 length,
2981	bool watchpoint)
2982{
2983	// check the address and size
2984	if (address == NULL || !BreakpointManager::CanAccessAddress(address, false))
2985		return B_BAD_ADDRESS;
2986	if (watchpoint && length < 0)
2987		return B_BAD_VALUE;
2988
2989	// check whether a debugger is installed already
2990	team_debug_info teamDebugInfo;
2991	get_team_debug_info(teamDebugInfo);
2992	if (teamDebugInfo.flags & B_TEAM_DEBUG_DEBUGGER_INSTALLED)
2993		return B_BAD_VALUE;
2994
2995	// We can't help it, here's a small but relatively harmless race condition,
2996	// since a debugger could be installed in the meantime. The worst case is
2997	// that we install a break/watchpoint the debugger doesn't know about.
2998
2999	// set the break/watchpoint
3000	status_t result;
3001	if (watchpoint)
3002		result = arch_set_watchpoint(address, type, length);
3003	else
3004		result = arch_set_breakpoint(address);
3005
3006	if (result == B_OK)
3007		update_threads_breakpoints_flag();
3008
3009	return result;
3010}
3011
3012
3013status_t
3014_user_clear_debugger_breakpoint(void *address, bool watchpoint)
3015{
3016	// check the address
3017	if (address == NULL || !BreakpointManager::CanAccessAddress(address, false))
3018		return B_BAD_ADDRESS;
3019
3020	// check whether a debugger is installed already
3021	team_debug_info teamDebugInfo;
3022	get_team_debug_info(teamDebugInfo);
3023	if (teamDebugInfo.flags & B_TEAM_DEBUG_DEBUGGER_INSTALLED)
3024		return B_BAD_VALUE;
3025
3026	// We can't help it, here's a small but relatively harmless race condition,
3027	// since a debugger could be installed in the meantime. The worst case is
3028	// that we clear a break/watchpoint the debugger has just installed.
3029
3030	// clear the break/watchpoint
3031	status_t result;
3032	if (watchpoint)
3033		result = arch_clear_watchpoint(address);
3034	else
3035		result = arch_clear_breakpoint(address);
3036
3037	if (result == B_OK)
3038		update_threads_breakpoints_flag();
3039
3040	return result;
3041}
3042