rem: TRACE(("nub thread %ld: B_DEBUG_MESSAGE_WRITE_MEMORY: " "reply port: %ld, address: %p, size: %ld\n", nubThread->id, replyPort, address, size));
context: debug_nub_thread(void *){	struct thread *nubThread = thread_get_current_thread();	// check, if we're still the current nub thread and get our port	cpu_status state = disable_interrupts();	GRAB_TEAM_DEBUG_INFO_LOCK(nubThread->team->debug_info);	if (nubThread->team->debug_info.nub_thread != nubThread->id)		return 0;	port_id port = nubThread->team->debug_info.nub_port;	sem_id writeLock = nubThread->team->debug_info.debugger_write_lock;	RELEASE_TEAM_DEBUG_INFO_LOCK(nubThread->team->debug_info);	restore_interrupts(state);	TRACE(("debug_nub_thread() thread: %ld, team %ld, nub port: %ld\n",		nubThread->id, nubThread->team->id, port));	// notify all threads that a debugger has been installed	broadcast_debugged_thread_message(nubThread,		B_DEBUGGED_THREAD_DEBUGGER_CHANGED, NULL, 0);	// command processing loop	while (true) {		int32 command;		debug_nub_message_data message;		ssize_t messageSize = kill_interruptable_read_port(port, &command,			&message, sizeof(message));		if (messageSize < 0) {			// The port is not longer valid or we were interrupted by a kill			// signal: If we are still listed in the team's debug info as nub			// thread, we need to update that.			nub_thread_cleanup(nubThread);			TRACE(("nub thread %ld: terminating: %lx\n", nubThread->id,				messageSize));			return messageSize;		}		bool sendReply = false;		union {			debug_nub_read_memory_reply			read_memory;			debug_nub_write_memory_reply		write_memory;			debug_nub_get_cpu_state_reply		get_cpu_state;			debug_nub_set_breakpoint_reply		set_breakpoint;			debug_nub_set_watchpoint_reply		set_watchpoint;			debug_nub_get_signal_masks_reply	get_signal_masks;			debug_nub_get_signal_handler_reply	get_signal_handler;			debug_nub_prepare_handover_reply	prepare_handover;		} reply;		int32 replySize = 0;		port_id replyPort = -1;		// process the command		switch (command) {			case B_DEBUG_MESSAGE_READ_MEMORY:			{				// get the parameters				replyPort = message.read_memory.reply_port;				void *address = message.read_memory.address;				int32 size = message.read_memory.size;				status_t result = B_OK;				// check the parameters				if (!IS_USER_ADDRESS(address))					result = B_BAD_ADDRESS;				else if (size <= 0 || size > B_MAX_READ_WRITE_MEMORY_SIZE)					result = B_BAD_VALUE;				// read the memory				int32 bytesRead = 0;				if (result == B_OK) {					result = read_user_memory(address, reply.read_memory.data,						size, bytesRead);				}				reply.read_memory.error = result;				TRACE(("nub thread %ld: B_DEBUG_MESSAGE_READ_MEMORY: "					"reply port: %ld, address: %p, size: %ld, result: %lx\n",					nubThread->id, replyPort, address, size, result));				// send only as much data as necessary				reply.read_memory.size = bytesRead;				replySize = reply.read_memory.data + bytesRead - (char*)&reply;				sendReply = true;				break;			}			case B_DEBUG_MESSAGE_WRITE_MEMORY:			{				// get the parameters				replyPort = message.write_memory.reply_port;				void *address = message.write_memory.address;				int32 size = message.write_memory.size;				const char *data = message.write_memory.data;				int32 realSize = (char*)&message + messageSize - data;				status_t result = B_OK;				TRACE(("nub thread %ld: B_DEBUG_MESSAGE_WRITE_MEMORY: "					"reply port: %ld, address: %p, size: %ld\n", nubThread->id,					replyPort, address, size));				// check the parameters				if (!IS_USER_ADDRESS(address))					result = B_BAD_ADDRESS;				else if (size <= 0 || size > realSize)					result = B_BAD_VALUE;				// write the memory				if (result == B_OK)					result = user_memcpy(address, data, size);				reply.write_memory.error = result;				sendReply = true;				replySize = sizeof(debug_nub_write_memory_reply);				break;			}			case B_DEBUG_MESSAGE_SET_TEAM_FLAGS:			{				// get the parameters				int32 flags = message.set_team_flags.flags					& B_TEAM_DEBUG_USER_FLAG_MASK;				TRACE(("nub thread %ld: B_DEBUG_MESSAGE_SET_TEAM_FLAGS: "					"flags: %lx\n", nubThread->id, flags));				struct team *team = thread_get_current_thread()->team;				// set the flags				cpu_status state = disable_interrupts();				GRAB_TEAM_DEBUG_INFO_LOCK(team->debug_info);				flags |= team->debug_info.flags & B_TEAM_DEBUG_KERNEL_FLAG_MASK;				atomic_set(&team->debug_info.flags, flags);				RELEASE_TEAM_DEBUG_INFO_LOCK(team->debug_info);				restore_interrupts(state);				break;			}			case B_DEBUG_MESSAGE_SET_THREAD_FLAGS:			{				// get the parameters				thread_id threadID = message.set_thread_flags.thread;				int32 flags = message.set_thread_flags.flags					& B_THREAD_DEBUG_USER_FLAG_MASK;				TRACE(("nub thread %ld: B_DEBUG_MESSAGE_SET_THREAD_FLAGS: "					"thread: %ld, flags: %lx\n", nubThread->id, threadID,					flags));				// set the flags				cpu_status state = disable_interrupts();				GRAB_THREAD_LOCK();				struct thread *thread					= thread_get_thread_struct_locked(threadID);				if (thread					&& thread->team == thread_get_current_thread()->team) {					flags |= thread->debug_info.flags						& B_THREAD_DEBUG_KERNEL_FLAG_MASK;					atomic_set(&thread->debug_info.flags, flags);				}				RELEASE_THREAD_LOCK();				restore_interrupts(state);				break;			}			case B_DEBUG_MESSAGE_CONTINUE_THREAD:			{				// get the parameters				thread_id threadID;				uint32 handleEvent;				bool singleStep;				threadID = message.continue_thread.thread;				handleEvent = message.continue_thread.handle_event;				singleStep = message.continue_thread.single_step;				TRACE(("nub thread %ld: B_DEBUG_MESSAGE_CONTINUE_THREAD: "					"thread: %ld, handle event: %lu, single step: %d\n",					nubThread->id, threadID, handleEvent, singleStep));				// find the thread and get its debug port				port_id threadDebugPort = -1;				status_t result = debug_nub_thread_get_thread_debug_port(					nubThread, threadID, threadDebugPort);				// send a message to the debugged thread				if (result == B_OK) {					debugged_thread_continue commandMessage;					commandMessage.handle_event = handleEvent;					commandMessage.single_step = singleStep;					result = write_port(threadDebugPort,						B_DEBUGGED_THREAD_MESSAGE_CONTINUE,						&commandMessage, sizeof(commandMessage));				}				break;			}			case B_DEBUG_MESSAGE_SET_CPU_STATE:			{				// get the parameters				thread_id threadID = message.set_cpu_state.thread;				const debug_cpu_state &cpuState					= message.set_cpu_state.cpu_state;				TRACE(("nub thread %ld: B_DEBUG_MESSAGE_SET_CPU_STATE: "					"thread: %ld\n", nubThread->id, threadID));				// find the thread and get its debug port				port_id threadDebugPort = -1;				status_t result = debug_nub_thread_get_thread_debug_port(					nubThread, threadID, threadDebugPort);				// send a message to the debugged thread				if (result == B_OK) {					debugged_thread_set_cpu_state commandMessage;					memcpy(&commandMessage.cpu_state, &cpuState,						sizeof(debug_cpu_state));					write_port(threadDebugPort,						B_DEBUGGED_THREAD_SET_CPU_STATE,						&commandMessage, sizeof(commandMessage));				}				break;			}			case B_DEBUG_MESSAGE_GET_CPU_STATE:			{				// get the parameters				thread_id threadID = message.get_cpu_state.thread;				replyPort = message.get_cpu_state.reply_port;				TRACE(("nub thread %ld: B_DEBUG_MESSAGE_GET_CPU_STATE: "					"thread: %ld\n", nubThread->id, threadID));				// find the thread and get its debug port				port_id threadDebugPort = -1;				status_t result = debug_nub_thread_get_thread_debug_port(					nubThread, threadID, threadDebugPort);				// send a message to the debugged thread				if (threadDebugPort >= 0) {					debugged_thread_get_cpu_state commandMessage;					commandMessage.reply_port = replyPort;					result = write_port(threadDebugPort,						B_DEBUGGED_THREAD_GET_CPU_STATE, &commandMessage,						sizeof(commandMessage));				}				// send a reply to the debugger in case of error				if (result != B_OK) {					reply.get_cpu_state.error = result;					sendReply = true;					replySize = sizeof(reply.get_cpu_state);				}				break;			}			case B_DEBUG_MESSAGE_SET_BREAKPOINT:			{				// get the parameters				replyPort = message.set_breakpoint.reply_port;				void *address = message.set_breakpoint.address;				TRACE(("nub thread %ld: B_DEBUG_MESSAGE_SET_BREAKPOINT: "					"address: %p\n", nubThread->id, address));				// check the address				status_t result = B_OK;				if (address == NULL || !IS_USER_ADDRESS(address))					result = B_BAD_ADDRESS;				// set the breakpoint				if (result == B_OK)					result = arch_set_breakpoint(address);				// prepare the reply				reply.set_breakpoint.error = result;				replySize = sizeof(reply.set_breakpoint);				sendReply = true;				break;			}						case B_DEBUG_MESSAGE_CLEAR_BREAKPOINT:			{				// get the parameters				void *address = message.clear_breakpoint.address;				TRACE(("nub thread %ld: B_DEBUG_MESSAGE_CLEAR_BREAKPOINT: "					"address: %p\n", nubThread->id, address));				// check the address				status_t result = B_OK;				if (address == NULL || !IS_USER_ADDRESS(address))					result = B_BAD_ADDRESS;				// clear the breakpoint				if (result == B_OK)					result = arch_clear_breakpoint(address);				break;			}			case B_DEBUG_MESSAGE_SET_WATCHPOINT:			{				// get the parameters				replyPort = message.set_watchpoint.reply_port;				void *address = message.set_watchpoint.address;				uint32 type = message.set_watchpoint.type;				int32 length = message.set_watchpoint.length;				TRACE(("nub thread %ld: B_DEBUG_MESSAGE_SET_WATCHPOINT: "					"address: %p, type: %lu, length: %ld\n", nubThread->id,					address, type, length));				// check the address and size				status_t result = B_OK;				if (address == NULL || !IS_USER_ADDRESS(address))					result = B_BAD_ADDRESS;				if (length < 0)					result = B_BAD_VALUE;				// set the watchpoint				if (result == B_OK)					result = arch_set_watchpoint(address, type, length);				// prepare the reply				reply.set_watchpoint.error = result;				replySize = sizeof(reply.set_watchpoint);				sendReply = true;				break;			}			case B_DEBUG_MESSAGE_CLEAR_WATCHPOINT:			{				// get the parameters				void *address = message.clear_watchpoint.address;				TRACE(("nub thread %ld: B_DEBUG_MESSAGE_CLEAR_WATCHPOINT: "					"address: %p\n", nubThread->id, address));				// check the address				status_t result = B_OK;				if (address == NULL || !IS_USER_ADDRESS(address))					result = B_BAD_ADDRESS;				// clear the watchpoint				if (result == B_OK)					result = arch_clear_watchpoint(address);				break;			}			case B_DEBUG_MESSAGE_SET_SIGNAL_MASKS:			{				// get the parameters				thread_id threadID = message.set_signal_masks.thread;				uint64 ignore = message.set_signal_masks.ignore_mask;				uint64 ignoreOnce = message.set_signal_masks.ignore_once_mask;				uint32 ignoreOp = message.set_signal_masks.ignore_op;				uint32 ignoreOnceOp = message.set_signal_masks.ignore_once_op;				TRACE(("nub thread %ld: B_DEBUG_MESSAGE_SET_SIGNAL_MASKS: "					"thread: %ld, ignore: %llx (op: %lu), ignore once: %llx "					"(op: %lu)\n", nubThread->id, threadID, ignore,						ignoreOp, ignoreOnce, ignoreOnceOp));				// set the masks				cpu_status state = disable_interrupts();				GRAB_THREAD_LOCK();				struct thread *thread					= thread_get_thread_struct_locked(threadID);				if (thread					&& thread->team == thread_get_current_thread()->team) {					thread_debug_info &threadDebugInfo = thread->debug_info;					// set ignore mask					switch (ignoreOp) {						case B_DEBUG_SIGNAL_MASK_AND:							threadDebugInfo.ignore_signals &= ignore;							break;						case B_DEBUG_SIGNAL_MASK_OR:							threadDebugInfo.ignore_signals |= ignore;							break;						case B_DEBUG_SIGNAL_MASK_SET:							threadDebugInfo.ignore_signals = ignore;							break;					}					// set ignore once mask					switch (ignoreOnceOp) {						case B_DEBUG_SIGNAL_MASK_AND:							threadDebugInfo.ignore_signals_once &= ignoreOnce;							break;						case B_DEBUG_SIGNAL_MASK_OR:							threadDebugInfo.ignore_signals_once |= ignoreOnce;							break;						case B_DEBUG_SIGNAL_MASK_SET:							threadDebugInfo.ignore_signals_once = ignoreOnce;							break;					}				}				RELEASE_THREAD_LOCK();				restore_interrupts(state);				break;			}			case B_DEBUG_MESSAGE_GET_SIGNAL_MASKS:			{				// get the parameters				replyPort = message.get_signal_masks.reply_port;				thread_id threadID = message.get_signal_masks.thread;				status_t result = B_OK;				// get the masks				uint64 ignore = 0;				uint64 ignoreOnce = 0;								cpu_status state = disable_interrupts();				GRAB_THREAD_LOCK();				struct thread *thread					= thread_get_thread_struct_locked(threadID);				if (thread) {					ignore = thread->debug_info.ignore_signals;					ignoreOnce = thread->debug_info.ignore_signals_once;				} else					result = B_BAD_THREAD_ID;				RELEASE_THREAD_LOCK();				restore_interrupts(state);				TRACE(("nub thread %ld: B_DEBUG_MESSAGE_GET_SIGNAL_MASKS: "					"reply port: %ld, thread: %ld, ignore: %llx, "					"ignore once: %llx, result: %lx\n", nubThread->id,					replyPort, threadID, ignore, ignoreOnce, result));				// prepare the message				reply.get_signal_masks.error = result;				reply.get_signal_masks.ignore_mask = ignore;				reply.get_signal_masks.ignore_once_mask = ignoreOnce;				replySize = sizeof(reply.get_signal_masks);				sendReply = true;				break;			}			case B_DEBUG_MESSAGE_SET_SIGNAL_HANDLER:			{				// get the parameters				thread_id threadID = message.set_signal_handler.thread;				int signal = message.set_signal_handler.signal;				struct sigaction &handler = message.set_signal_handler.handler;				TRACE(("nub thread %ld: B_DEBUG_MESSAGE_SET_SIGNAL_HANDLER: "					"thread: %ld, signal: %d, handler: %p\n", nubThread->id,					threadID, signal, handler.sa_handler));				// check, if the thread exists and is ours				cpu_status state = disable_interrupts();				GRAB_THREAD_LOCK();				struct thread *thread					= thread_get_thread_struct_locked(threadID);				if (thread					&& thread->team != thread_get_current_thread()->team) {					thread = NULL;				}				RELEASE_THREAD_LOCK();				restore_interrupts(state);				// set the handler				if (thread)					sigaction_etc(threadID, signal, &handler, NULL);				break;			}			case B_DEBUG_MESSAGE_GET_SIGNAL_HANDLER:			{				// get the parameters				replyPort = message.get_signal_handler.reply_port;				thread_id threadID = message.get_signal_handler.thread;				int signal = message.get_signal_handler.signal;				status_t result = B_OK;				// check, if the thread exists and is ours				cpu_status state = disable_interrupts();				GRAB_THREAD_LOCK();				struct thread *thread					= thread_get_thread_struct_locked(threadID);				if (thread) {					if (thread->team != thread_get_current_thread()->team)						result = B_BAD_VALUE;				} else					result = B_BAD_THREAD_ID;				RELEASE_THREAD_LOCK();				restore_interrupts(state);				// get the handler				if (result == B_OK) {					result = sigaction_etc(threadID, signal, NULL,						&reply.get_signal_handler.handler);				}				TRACE(("nub thread %ld: B_DEBUG_MESSAGE_GET_SIGNAL_HANDLER: "					"reply port: %ld, thread: %ld, signal: %d, "					"handler: %p\n", nubThread->id, replyPort,					threadID, signal,					reply.get_signal_handler.handler.sa_handler));				// prepare the message				reply.get_signal_handler.error = result;				replySize = sizeof(reply.get_signal_handler);				sendReply = true;				break;			}			case B_DEBUG_MESSAGE_PREPARE_HANDOVER:			{				TRACE(("nub thread %ld: B_DEBUG_MESSAGE_PREPARE_HANDOVER\n",					nubThread->id));				struct team *team = nubThread->team;				// Acquire the debugger write lock. As soon as we have it and				// have set the B_TEAM_DEBUG_DEBUGGER_HANDOVER flag, no thread				// will write anything to the debugger port anymore.				status_t result = acquire_sem_etc(writeLock, 1,					B_KILL_CAN_INTERRUPT, 0);				if (result == B_OK) {					// set the respective team debug flag					cpu_status state = disable_interrupts();					GRAB_TEAM_DEBUG_INFO_LOCK(team->debug_info);					atomic_or(&team->debug_info.flags,						B_TEAM_DEBUG_DEBUGGER_HANDOVER);					RELEASE_TEAM_DEBUG_INFO_LOCK(team->debug_info);					restore_interrupts(state);					release_sem(writeLock);				} else {					// We probably got a SIGKILL. If so, we will terminate when					// sending the reply fails.				}					// prepare the reply				reply.prepare_handover.error = result;				replySize = sizeof(reply.prepare_handover);				sendReply = true;				break;			}			case B_DEBUG_MESSAGE_HANDED_OVER:			{				// notify all threads that the debugger has changed				broadcast_debugged_thread_message(nubThread,					B_DEBUGGED_THREAD_DEBUGGER_CHANGED, NULL, 0);				break;			}		}		// send the reply, if necessary		if (sendReply) {			status_t error = kill_interruptable_write_port(replyPort, command,				&reply, replySize);			if (error != B_OK) {				// The debugger port is either not longer existing or we got				// interrupted by a kill signal. In either case we terminate.				nub_thread_cleanup(nubThread);				return error;			}		}	}}