void unloaded_dll (const char *name, CORE_ADDR base_addr) { struct dll_info *dll; struct dll_info key_dll; /* Be careful not to put the key DLL in any list. */ key_dll.name = (char *) name; key_dll.base_addr = base_addr; dll = (void *) find_inferior (&all_dlls, match_dll, &key_dll); if (dll == NULL) /* For some inferiors we might get unloaded_dll events without having a corresponding loaded_dll. In that case, the dll cannot be found in ALL_DLL, and there is nothing further for us to do. This has been observed when running 32bit executables on Windows64 (i.e. through WOW64, the interface between the 32bits and 64bits worlds). In that case, the inferior always does some strange unloading of unnamed dll. */ return; else { /* DLL has been found so remove the entry and free associated resources. */ remove_inferior (&all_dlls, &dll->entry); free_one_dll (&dll->entry); dlls_changed = 1; } }
static void fbsd_resume (struct thread_resume *resume_info) { int pending_flag; /* Yes, the use of a global here is rather ugly. */ resume_ptr = resume_info; for_each_inferior (&all_threads, fbsd_set_resume_request); /* If there is a thread which would otherwise be resumed, which has a pending status, then don't resume any threads - we can just report the pending status. Make sure to queue any signals that would otherwise be sent. */ pending_flag = 0; find_inferior (&all_processes, resume_status_pending_p, &pending_flag); if (debug_threads) { if (pending_flag) fprintf (stderr, "Not resuming, pending status\n"); else fprintf (stderr, "Resuming, no pending status\n"); } if (pending_flag) for_each_inferior (&all_threads, fbsd_queue_one_thread); else { block_async_io (); enable_async_io (); for_each_inferior (&all_threads, fbsd_continue_one_thread); } }
void regcache_invalidate (void) { /* Only update the threads of the current process. */ int pid = ptid_get_pid (current_thread->entry.id); find_inferior (&all_threads, regcache_invalidate_one, &pid); }
static void x86_dr_low_set_control (unsigned long control) { /* Only update the threads of this process. */ int pid = pid_of (current_thread); find_inferior (&all_threads, update_debug_registers_callback, &pid); }
static void switch_to_process (struct process_info *proc) { int pid = pid_of (proc); current_thread = (struct thread_info *) find_inferior (&all_threads, any_thread_of, &pid); }
static void x86_dr_low_set_addr (int regnum, CORE_ADDR addr) { /* Only update the threads of this process. */ int pid = pid_of (current_thread); gdb_assert (DR_FIRSTADDR <= regnum && regnum <= DR_LASTADDR); find_inferior (&all_threads, update_debug_registers_callback, &pid); }
static BOOL child_continue (DWORD continue_status, int thread_id) { BOOL res; res = ContinueDebugEvent (current_event.dwProcessId, current_event.dwThreadId, continue_status); continue_status = 0; if (res) find_inferior (&all_threads, continue_one_thread, &thread_id); debug_registers_changed = 0; return res; }
void aarch64_notify_debug_reg_change (const struct aarch64_debug_reg_state *state, int is_watchpoint, unsigned int idx) { struct aarch64_dr_update_callback_param param; /* Only update the threads of this process. */ param.pid = pid_of (current_thread); param.is_watchpoint = is_watchpoint; param.idx = idx; find_inferior (&all_threads, debug_reg_change_callback, (void *) ¶m); }
static BOOL child_continue (DWORD continue_status, int thread_id) { /* The inferior will only continue after the ContinueDebugEvent call. */ find_inferior (&all_threads, continue_one_thread, &thread_id); faked_breakpoint = 0; if (!ContinueDebugEvent (current_event.dwProcessId, current_event.dwThreadId, continue_status)) return FALSE; return TRUE; }
int prepare_to_access_memory (void) { struct thread_search search; struct thread_info *thread; memset (&search, 0, sizeof (search)); search.current_gen_ptid = general_thread; prev_general_thread = general_thread; if (the_target->prepare_to_access_memory != NULL) { int res; res = the_target->prepare_to_access_memory (); if (res != 0) return res; } find_inferior (&all_threads, thread_search_callback, &search); /* Prefer a stopped thread. If none is found, try the current thread. Otherwise, take the first thread in the process. If none is found, undo the effects of target->prepare_to_access_memory() and return error. */ if (search.stopped != NULL) thread = search.stopped; else if (search.current != NULL) thread = search.current; else if (search.first != NULL) thread = search.first; else { done_accessing_memory (); return 1; } current_thread = thread; general_thread = ptid_of (thread); return 0; }
/* Remove hardware break-/watchpoint. */ static int arm_remove_point (enum raw_bkpt_type type, CORE_ADDR addr, int len, struct raw_breakpoint *bp) { struct process_info *proc = current_process (); struct arm_linux_hw_breakpoint p, *pts; int watch, i, count; watch = arm_linux_hw_point_initialize (type, addr, len, &p); if (watch < 0) { /* Unsupported. */ return -1; } if (watch) { count = arm_linux_get_hw_watchpoint_count (); pts = proc->priv->arch_private->wpts; } else { count = arm_linux_get_hw_breakpoint_count (); pts = proc->priv->arch_private->bpts; } for (i = 0; i < count; i++) if (arm_linux_hw_breakpoint_equal (&p, pts + i)) { struct update_registers_data data = { watch, i }; pts[i].control = arm_hwbp_control_disable (pts[i].control); find_inferior (&all_threads, update_registers_callback, &data); return 0; } /* No watchpoint matched. */ return -1; }
/* Insert hardware break-/watchpoint. */ static int arm_insert_point (enum raw_bkpt_type type, CORE_ADDR addr, int len, struct raw_breakpoint *bp) { struct process_info *proc = current_process (); struct arm_linux_hw_breakpoint p, *pts; int watch, i, count; watch = arm_linux_hw_point_initialize (type, addr, len, &p); if (watch < 0) { /* Unsupported. */ return watch == -1 ? 1 : -1; } if (watch) { count = arm_linux_get_hw_watchpoint_count (); pts = proc->priv->arch_private->wpts; } else { count = arm_linux_get_hw_breakpoint_count (); pts = proc->priv->arch_private->bpts; } for (i = 0; i < count; i++) if (!arm_hwbp_control_is_enabled (pts[i].control)) { struct update_registers_data data = { watch, i }; pts[i] = p; find_inferior (&all_threads, update_registers_callback, &data); return 0; } /* We're out of watchpoints. */ return -1; }
static int fbsd_wait_for_event (struct thread_info *child) { CORE_ADDR stop_pc; struct process_info *event_child; int wstat; /* Check for a process with a pending status. */ /* It is possible that the user changed the pending task's registers since it stopped. We correctly handle the change of PC if we hit a breakpoint (in check_removed_breakpoint); signals should be reported anyway. */ if (child == NULL) { event_child = (struct process_info *) find_inferior (&all_processes, status_pending_p, NULL); if (debug_threads && event_child) fprintf (stderr, "Got a pending child %d\n", event_child->lwpid); } else { event_child = get_thread_process (child); if (event_child->status_pending_p && check_removed_breakpoint (event_child)) event_child = NULL; } if (event_child != NULL) { if (event_child->status_pending_p) { if (debug_threads) fprintf (stderr, "Got an event from pending child %d (%04x)\n", event_child->lwpid, event_child->status_pending); wstat = event_child->status_pending; event_child->status_pending_p = 0; event_child->status_pending = 0; current_inferior = get_process_thread (event_child); return wstat; } } /* We only enter this loop if no process has a pending wait status. Thus any action taken in response to a wait status inside this loop is responding as soon as we detect the status, not after any pending events. */ while (1) { if (child == NULL) event_child = NULL; else event_child = get_thread_process (child); fbsd_wait_for_process (&event_child, &wstat); if (event_child == NULL) error ("event from unknown child"); current_inferior = (struct thread_info *) find_inferior_id (&all_threads, event_child->tid); if (using_threads) { /* Check for thread exit. */ if (! WIFSTOPPED (wstat)) { if (debug_threads) fprintf (stderr, "Thread %d (LWP %d) exiting\n", event_child->tid, event_child->head.id); /* If the last thread is exiting, just return. */ if (all_threads.head == all_threads.tail) return wstat; dead_thread_notify (event_child->tid); remove_inferior (&all_processes, &event_child->head); free (event_child); remove_thread (current_inferior); current_inferior = (struct thread_info *) all_threads.head; /* If we were waiting for this particular child to do something... well, it did something. */ if (child != NULL) return wstat; /* Wait for a more interesting event. */ continue; } if (WIFSTOPPED (wstat) && WSTOPSIG (wstat) == SIGSTOP && event_child->stop_expected) { if (debug_threads) fprintf (stderr, "Expected stop.\n"); event_child->stop_expected = 0; fbsd_resume_one_process (&event_child->head, event_child->stepping, 0); continue; } /* FIXME drow/2002-06-09: Get signal numbers from the inferior's thread library? */ if (WIFSTOPPED (wstat)) { if (debug_threads) fprintf (stderr, "Ignored signal %d for %d (LWP %d).\n", WSTOPSIG (wstat), event_child->tid, event_child->head.id); fbsd_resume_one_process (&event_child->head, event_child->stepping, WSTOPSIG (wstat)); continue; } } /* If this event was not handled above, and is not a SIGTRAP, report it. */ if (!WIFSTOPPED (wstat) || WSTOPSIG (wstat) != SIGTRAP) return wstat; /* If this target does not support breakpoints, we simply report the SIGTRAP; it's of no concern to us. */ if (the_low_target.get_pc == NULL) return wstat; stop_pc = get_stop_pc (); /* bp_reinsert will only be set if we were single-stepping. Notice that we will resume the process after hitting a gdbserver breakpoint; single-stepping to/over one is not supported (yet). */ if (event_child->bp_reinsert != 0) { if (debug_threads) fprintf (stderr, "Reinserted breakpoint.\n"); reinsert_breakpoint (event_child->bp_reinsert); event_child->bp_reinsert = 0; /* Clear the single-stepping flag and SIGTRAP as we resume. */ fbsd_resume_one_process (&event_child->head, 0, 0); continue; } if (debug_threads) fprintf (stderr, "Hit a (non-reinsert) breakpoint.\n"); if (check_breakpoints (stop_pc) != 0) { /* We hit one of our own breakpoints. We mark it as a pending breakpoint, so that check_removed_breakpoint () will do the PC adjustment for us at the appropriate time. */ event_child->pending_is_breakpoint = 1; event_child->pending_stop_pc = stop_pc; /* Now we need to put the breakpoint back. We continue in the event loop instead of simply replacing the breakpoint right away, in order to not lose signals sent to the thread that hit the breakpoint. Unfortunately this increases the window where another thread could sneak past the removed breakpoint. For the current use of server-side breakpoints (thread creation) this is acceptable; but it needs to be considered before this breakpoint mechanism can be used in more general ways. For some breakpoints it may be necessary to stop all other threads, but that should be avoided where possible. If breakpoint_reinsert_addr is NULL, that means that we can use PT_STEP on this platform. Uninsert the breakpoint, mark it for reinsertion, and single-step. Otherwise, call the target function to figure out where we need our temporary breakpoint, create it, and continue executing this process. */ if (the_low_target.breakpoint_reinsert_addr == NULL) { event_child->bp_reinsert = stop_pc; uninsert_breakpoint (stop_pc); fbsd_resume_one_process (&event_child->head, 1, 0); } else { reinsert_breakpoint_by_bp (stop_pc, (*the_low_target.breakpoint_reinsert_addr) ()); fbsd_resume_one_process (&event_child->head, 0, 0); } continue; } /* If we were single-stepping, we definitely want to report the SIGTRAP. The single-step operation has completed, so also clear the stepping flag; in general this does not matter, because the SIGTRAP will be reported to the client, which will give us a new action for this thread, but clear it for consistency anyway. It's safe to clear the stepping flag because the only consumer of get_stop_pc () after this point is check_removed_breakpoint, and pending_is_breakpoint is not set. It might be wiser to use a step_completed flag instead. */ if (event_child->stepping) { event_child->stepping = 0; return wstat; } /* A SIGTRAP that we can't explain. It may have been a breakpoint. Check if it is a breakpoint, and if so mark the process information accordingly. This will handle both the necessary fiddling with the PC on decr_pc_after_break targets and suppressing extra threads hitting a breakpoint if two hit it at once and then GDB removes it after the first is reported. Arguably it would be better to report multiple threads hitting breakpoints simultaneously, but the current remote protocol does not allow this. */ if ((*the_low_target.breakpoint_at) (stop_pc)) { event_child->pending_is_breakpoint = 1; event_child->pending_stop_pc = stop_pc; } return wstat; } /* NOTREACHED */ return 0; }
void regcache_invalidate_pid (int pid) { find_inferior (&all_threads, regcache_invalidate_one, &pid); }
int have_attached_inferiors_p (void) { return (find_inferior (&all_processes, attached_inferior_callback, NULL) != NULL); }
int have_started_inferiors_p (void) { return (find_inferior (&all_processes, started_inferior_callback, NULL) != NULL); }