bool ThreadHandler::HandleExceptionOccurred(ExceptionOccurredEvent* event) { char buffer[256]; get_debug_exception_string(event->Exception(), buffer, sizeof(buffer)); return _HandleThreadStopped(NULL, THREAD_STOPPED_EXCEPTION, buffer); }
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; }