Beispiel #1
0
bool
ThreadHandler::HandleExceptionOccurred(ExceptionOccurredEvent* event)
{
	char buffer[256];
	get_debug_exception_string(event->Exception(), buffer, sizeof(buffer));
	return _HandleThreadStopped(NULL, THREAD_STOPPED_EXCEPTION, buffer);
}
Beispiel #2
0
static ptid_t
haiku_child_wait_internal (team_debug_info *teamDebugInfo, ptid_t ptid,
	struct target_waitstatus *ourstatus, bool *ignore, bool *selectThread)
{
	team_id teamID = ptid_get_pid(ptid);
	team_id threadID = ptid_get_tid(ptid);
	debug_event *event = NULL;
	ptid_t retval = pid_to_ptid(-1);
	struct thread_debug_info *thread;
	int pendingSignal = -1;
	pending_signal_status pendingSignalStatus = SIGNAL_FAKED;
	int reprocessEvent = -1;

	*selectThread = false;

	if (teamID < 0 || threadID == 0)
		threadID = -1;

	// if we're waiting for any thread, search the thread list for already
	// stopped threads (needed for reprocessing events)
	if (threadID < 0) {
		for (thread = teamDebugInfo->threads; thread; thread = thread->next) {
			if (thread->stopped) {
				threadID = thread->thread;
				break;
			}
		}
	}

	// check, if the thread exists and is already stopped
	if (threadID >= 0
		&& (thread = haiku_find_thread(teamDebugInfo, threadID)) != NULL
		&& thread->stopped) {
		// remove the event that stopped the thread from the thread (we will
		// add it again, if it shall not be ignored)
		event = thread->last_event;
		thread->last_event = NULL;
		thread->stopped = false;
		reprocessEvent = thread->reprocess_event;

		TRACE(("haiku_child_wait_internal(): thread %ld already stopped. "
			"re-digesting the last event (%p).\n", threadID, event));
	} else {
		// prepare closure for finding interesting events
		thread_event_closure threadEventClosure;
		threadEventClosure.context = teamDebugInfo;
		threadEventClosure.thread = threadID;
		threadEventClosure.event = NULL;

		// find the first interesting queued event
		threadEventClosure.event = haiku_find_next_debug_event(
			&teamDebugInfo->events, haiku_thread_event_predicate,
			&threadEventClosure);

		// read all events pending on the port
		haiku_read_pending_debug_events(teamDebugInfo,
			(threadEventClosure.event == NULL), haiku_thread_event_predicate,
			&threadEventClosure);

		// get the event of interest
		event = haiku_remove_debug_event(&teamDebugInfo->events,
			threadEventClosure.event);

		if (!event) {
			TRACE(("haiku_child_wait_internal(): got no event!\n"));
			return retval;
		}

		TRACE(("haiku_child_wait_internal(): got event: %u, thread: %ld, "
			"team: %ld, nub port: %ld\n", event->message,
			event->data.origin.thread, event->data.origin.team,
			event->data.origin.nub_port));
	}

	if (event->data.origin.team != teamDebugInfo->team) {
		// Spurious debug message. Doesn't concern our team. Ignore.
		xfree(event);
		return retval;
	}

	retval = ptid_build(event->data.origin.team, 0, event->data.origin.thread);

	*ignore = false;

	switch (event->message) {
		case B_DEBUGGER_MESSAGE_DEBUGGER_CALL:
		{
			// print the debugger message
			char debuggerMessage[1024];
			ssize_t bytesRead = debug_read_string(&teamDebugInfo->context,
				event->data.debugger_call.message, debuggerMessage,
				sizeof(debuggerMessage));
			if (bytesRead > 0) {
				printf_unfiltered ("Thread %ld called debugger(): %s\n",
					event->data.origin.thread, debuggerMessage);
			} else {
				printf_unfiltered ("Thread %ld called debugger(), but failed"
					"to get the debugger message.\n",
					event->data.origin.thread);
			}

			// fall through...
		}
		case B_DEBUGGER_MESSAGE_THREAD_DEBUGGED:
		case B_DEBUGGER_MESSAGE_BREAKPOINT_HIT:
		case B_DEBUGGER_MESSAGE_WATCHPOINT_HIT:
		case B_DEBUGGER_MESSAGE_SINGLE_STEP:
			ourstatus->kind = TARGET_WAITKIND_STOPPED;
			ourstatus->value.sig = TARGET_SIGNAL_TRAP;
			pendingSignal = SIGTRAP;
			pendingSignalStatus = SIGNAL_FAKED;
			break;

		case B_DEBUGGER_MESSAGE_PRE_SYSCALL:
			ourstatus->kind = TARGET_WAITKIND_SYSCALL_ENTRY;
			ourstatus->value.syscall_id = event->data.pre_syscall.syscall;
			break;

		case B_DEBUGGER_MESSAGE_POST_SYSCALL:
			ourstatus->kind = TARGET_WAITKIND_SYSCALL_RETURN;
			ourstatus->value.syscall_id = event->data.post_syscall.syscall;
			break;

		case B_DEBUGGER_MESSAGE_SIGNAL_RECEIVED:
			pendingSignal = event->data.signal_received.signal;
			pendingSignalStatus = SIGNAL_ARRIVED;
			ourstatus->kind = TARGET_WAITKIND_STOPPED;
			ourstatus->value.sig = haiku_to_target_signal(pendingSignal);
			break;

		case B_DEBUGGER_MESSAGE_EXCEPTION_OCCURRED:
		{
			// print the exception message
			char exception[1024];
			get_debug_exception_string(event->data.exception_occurred.exception,
				exception, sizeof(exception));
			printf_unfiltered ("Thread %ld caused an exception: %s\n",
				event->data.origin.thread, exception);

			pendingSignal = event->data.exception_occurred.signal;
			pendingSignalStatus = SIGNAL_WILL_ARRIVE;
			ourstatus->kind = TARGET_WAITKIND_STOPPED;
			ourstatus->value.sig = haiku_to_target_signal(pendingSignal);
			break;
		}

		case B_DEBUGGER_MESSAGE_TEAM_CREATED:
			// ignore
			*ignore = true;
			break;

		case B_DEBUGGER_MESSAGE_TEAM_DELETED:
			ourstatus->kind = TARGET_WAITKIND_EXITED;
			ourstatus->value.integer = 0;
				// TODO: Extend the debugger interface?
			break;

		case B_DEBUGGER_MESSAGE_THREAD_CREATED:
		{
			// internal bookkeeping only
			thread_id newThread = event->data.thread_created.new_thread;
			if (newThread != teamDebugInfo->nub_thread)
				haiku_add_thread(teamDebugInfo, newThread);
			*ignore = true;
			break;
		}

		case B_DEBUGGER_MESSAGE_THREAD_DELETED:
			// internal bookkeeping
			haiku_remove_thread(teamDebugInfo,
				event->data.thread_deleted.origin.thread);
			*ignore = true;

			// TODO: What if this is the current thread?
			break;

		case B_DEBUGGER_MESSAGE_IMAGE_CREATED:
			if (reprocessEvent < 0) {
				// first time we see the event: update our image list
//				haiku_add_image(teamDebugInfo,
//					&event->data.image_created.info);
haiku_cleanup_image_list(teamDebugInfo);
haiku_init_image_list(teamDebugInfo);
// TODO: We don't get events when images have been removed in preparation of
// an exec*() yet.
			}

			ourstatus->kind = TARGET_WAITKIND_LOADED;
			ourstatus->value.integer = 0;
			if (event->data.image_created.info.type == B_APP_IMAGE) {
				// An app image has been loaded, i.e. the application is now
				// fully loaded. We need to send a TARGET_WAITKIND_LOADED
				// first, so that GDB's shared object list is updated correctly.
				// But we also need to send an TARGET_WAITKIND_EXECD event.
				// We use the reprocessEvent mechanism here.

				if (reprocessEvent == 2) {
					// the second time the event is processed: send the `exec'
					// event
					if (inferior_ignoring_startup_exec_events > 0) {
						// we shall not send an exec event, so we skip that
						// and send the `trap' immediately
TRACE(("haiku_child_wait_internal(): ignoring exec (%d)\n",
inferior_ignoring_startup_exec_events));
						inferior_ignoring_startup_exec_events--;
						reprocessEvent = 1;
					}
				}

				if (reprocessEvent < 0) {
TRACE(("haiku_child_wait_internal(): B_APP_IMAGE created, reprocess < 0\n"));
					// the first time the event is processed: send the
					// `loaded' event
					reprocessEvent = 2;
				} else if (reprocessEvent == 2) {
TRACE(("haiku_child_wait_internal(): B_APP_IMAGE created, reprocess -> exec\n"));
					// the second time the event is processed: send the `exec'
					// event
					ourstatus->kind = TARGET_WAITKIND_EXECD;
					ourstatus->value.execd_pathname
						= event->data.image_created.info.name;

					reprocessEvent = 1;
				} else if (reprocessEvent <= 1) {
					// the third time the event is processed: send the `trap'
					// event
					ourstatus->kind = TARGET_WAITKIND_STOPPED;
					ourstatus->value.sig = TARGET_SIGNAL_TRAP;
					pendingSignal = SIGTRAP;
					pendingSignalStatus = SIGNAL_FAKED;

					reprocessEvent = 0;
				}
			}

			// re_enable_breakpoints_in_shlibs ();
				// TODO: Needed?
			break;

		case B_DEBUGGER_MESSAGE_IMAGE_DELETED:
			haiku_remove_image(teamDebugInfo,
				event->data.image_deleted.info.id);

			// send TARGET_WAITKIND_LOADED here too, it causes the shared
			// object list to be updated
			ourstatus->kind = TARGET_WAITKIND_LOADED;
			ourstatus->value.integer = 0;
			break;

		case B_DEBUGGER_MESSAGE_HANDED_OVER:
		{
TRACE(("haiku_child_wait_internal(): B_DEBUGGER_MESSAGE_HANDED_OVER: causing "
"thread: %ld\n", event->data.handed_over.causing_thread));
			// The debugged team has been handed over to us by another debugger
			// (likely the debug server). This event also tells us, which
			// thread has caused the original debugger to be installed (if any).
			// So, if we're not looking for any particular thread, select that
			// thread.
			if (threadID < 0 && event->data.handed_over.causing_thread >= 0) {
				*selectThread = true;
				retval = ptid_build(event->data.origin.team, 0,
					event->data.handed_over.causing_thread);
			}
			*ignore = true;
		}

		default:
			// unknown message, ignore
			*ignore = true;
			break;
	}

	// make the event the thread's last event or delete it
	if (!*ignore && event->data.origin.thread >= 0) {
		struct thread_debug_info *thread = haiku_find_thread(teamDebugInfo,
			event->data.origin.thread);
		if (thread->last_event)
			xfree(thread->last_event);
			thread->last_event = event;
			thread->stopped = true;
			thread->signal = pendingSignal;
			thread->signal_status = pendingSignalStatus;
			thread->reprocess_event
				= (reprocessEvent >= 0 ? reprocessEvent : 0);
	} else {
		xfree(event);

		// continue the thread
		if (event->data.origin.thread >= 0) {
			haiku_continue_thread(teamDebugInfo, event->data.origin.thread,
				B_THREAD_DEBUG_HANDLE_EVENT, false);
		}

//		*ignore = true;
// TODO: This should indeed not be needed. It definitely eats the
// `team deleted' events.
	}

	return retval;
}