int thread_db_get_tls_address (struct thread_info *thread, CORE_ADDR offset, CORE_ADDR load_module, CORE_ADDR *address) { #if HAVE_TD_THR_TLS_GET_ADDR psaddr_t addr; td_err_e err; struct process_info *process; process = get_thread_process (thread); if (!process->thread_known) return TD_NOTHR; err = td_thr_tls_get_addr (&process->th, (psaddr_t) load_module, offset, &addr); if (err == TD_OK) { *address = (CORE_ADDR) addr; return 0; } else return err; #else return -1; #endif }
bool thread_db_thread_handle (ptid_t ptid, gdb_byte **handle, int *handle_len) { struct thread_db *thread_db; struct lwp_info *lwp; thread_info *thread = find_thread_ptid (ptid); if (thread == NULL) return false; thread_db = get_thread_process (thread)->priv->thread_db; if (thread_db == NULL) return false; lwp = get_thread_lwp (thread); if (!lwp->thread_known && !find_one_thread (thread->id)) return false; gdb_assert (lwp->thread_known); *handle = (gdb_byte *) &lwp->thread_handle; *handle_len = sizeof (lwp->thread_handle); return true; }
static void fbsd_detach_one_process (struct inferior_list_entry *entry) { struct thread_info *thread = (struct thread_info *) entry; struct process_info *process = get_thread_process (thread); ptrace (PT_DETACH, pid_of (process), 0, 0); }
struct process_info * current_process (void) { if (current_inferior == NULL) fatal ("Current inferior requested, but current_inferior is NULL\n"); return get_thread_process (current_inferior); }
static CORE_ADDR get_stop_pc (void) { CORE_ADDR stop_pc = (*the_low_target.get_pc) (); if (get_thread_process (current_inferior)->stepping) return stop_pc; else return stop_pc - the_low_target.decr_pc_after_break; }
static void maybe_attach_thread (const td_thrhandle_t *th_p, td_thrinfo_t *ti_p) { td_err_e err; struct thread_info *inferior; struct process_info *process; /* If we are attaching to our first thread, things are a little different. */ if (all_threads.head == all_threads.tail) { inferior = (struct thread_info *) all_threads.head; process = get_thread_process (inferior); if (process->thread_known == 0) { /* Switch to indexing the threads list by TID. */ change_inferior_id (&all_threads, ti_p->ti_tid); goto found; } } inferior = (struct thread_info *) find_inferior_id (&all_threads, ti_p->ti_tid); if (inferior != NULL) return; if (debug_threads) fprintf (stderr, "Attaching to thread %ld (LWP %d)\n", ti_p->ti_tid, ti_p->ti_lid); linux_attach_lwp (ti_p->ti_lid, ti_p->ti_tid); inferior = (struct thread_info *) find_inferior_id (&all_threads, ti_p->ti_tid); if (inferior == NULL) { warning ("Could not attach to thread %ld (LWP %d)\n", ti_p->ti_tid, ti_p->ti_lid); return; } process = inferior_target_data (inferior); found: new_thread_notify (ti_p->ti_tid); process->tid = ti_p->ti_tid; process->lwpid = ti_p->ti_lid; process->thread_known = 1; process->th = *th_p; err = td_thr_event_enable (th_p, 1); if (err != TD_OK) error ("Cannot enable thread event reporting for %d: %s", ti_p->ti_lid, thread_db_err_str (err)); }
static void linux_resume (int step, int signal) { struct process_info *process; process = get_thread_process (current_inferior); /* If the current process has a status pending, this signal will be enqueued and sent later. */ linux_resume_one_process (&process->head, step, signal); if (cont_thread == 0 || cont_thread == -1) for_each_inferior (&all_processes, linux_continue_one_process); }
static void linux_send_signal (int signum) { extern unsigned long signal_pid; if (cont_thread != 0 && cont_thread != -1) { struct process_info *process; process = get_thread_process (current_inferior); kill_lwp (process->lwpid, signum); } else kill_lwp (signal_pid, signum); }
static void fbsd_kill_one_process (struct inferior_list_entry *entry) { struct thread_info *thread = (struct thread_info *) entry; struct process_info *process = get_thread_process (thread); int wstat; do { ptrace (PT_KILL, pid_of (process), 0, 0); /* Make sure it died. The loop is most likely unnecessary. */ wstat = fbsd_wait_for_event (thread); } while (WIFSTOPPED (wstat)); }
static void fbsd_send_signal (int signum) { extern int signal_pid; if (cont_thread > 0) { struct process_info *process; process = get_thread_process (current_inferior); kill (process->lwpid, signum); } else kill (signal_pid, signum); }
/* This function is called once per thread. We look up the thread in RESUME_PTR, and mark the thread with a pointer to the appropriate resume request. This algorithm is O(threads * resume elements), but resume elements is small (and will remain small at least until GDB supports thread suspension). */ static void fbsd_set_resume_request (struct inferior_list_entry *entry) { struct process_info *process; struct thread_info *thread; int ndx; thread = (struct thread_info *) entry; process = get_thread_process (thread); ndx = 0; while (resume_ptr[ndx].thread != -1 && resume_ptr[ndx].thread != entry->id) ndx++; process->resume = &resume_ptr[ndx]; }
static void linux_kill (void) { struct thread_info *thread = (struct thread_info *) all_threads.head; struct process_info *process = get_thread_process (thread); int wstat; for_each_inferior (&all_threads, linux_kill_one_process); /* See the comment in linux_kill_one_process. We did not kill the first thread in the list, so do so now. */ do { ptrace (PTRACE_KILL, pid_of (process), 0, 0); /* Make sure it died. The loop is most likely unnecessary. */ wstat = linux_wait_for_event (thread); } while (WIFSTOPPED (wstat)); }
void thread_db_notice_clone (struct thread_info *parent_thr, ptid_t child_ptid) { process_info *parent_proc = get_thread_process (parent_thr); struct thread_db *thread_db = parent_proc->priv->thread_db; /* If the thread layer isn't initialized, return. It may just be that the program uses clone, but does not use libthread_db. */ if (thread_db == NULL || !thread_db->all_symbols_looked_up) return; /* find_one_thread calls into libthread_db which accesses memory via the current thread. Temporarily switch to a thread we know is stopped. */ scoped_restore restore_current_thread = make_scoped_restore (¤t_thread, parent_thr); if (!find_one_thread (child_ptid)) warning ("Cannot find thread after clone.\n"); }
struct regcache * get_thread_regcache (struct thread_info *thread, int fetch) { struct regcache *regcache; regcache = (struct regcache *) inferior_regcache_data (thread); /* Threads' regcaches are created lazily, because biarch targets add the main thread/lwp before seeing it stop for the first time, and it is only after the target sees the thread stop for the first time that the target has a chance of determining the process's architecture. IOW, when we first add the process's main thread we don't know which architecture/tdesc its regcache should have. */ if (regcache == NULL) { struct process_info *proc = get_thread_process (thread); gdb_assert (proc->tdesc != NULL); regcache = new_register_cache (proc->tdesc); set_inferior_regcache_data (thread, regcache); } if (fetch && regcache->registers_valid == 0) { struct thread_info *saved_thread = current_thread; current_thread = thread; /* Invalidate all registers, to prevent stale left-overs. */ memset (regcache->register_status, REG_UNAVAILABLE, regcache->tdesc->num_registers); fetch_inferior_registers (regcache, -1); current_thread = saved_thread; regcache->registers_valid = 1; } return regcache; }
static void fbsd_continue_one_thread (struct inferior_list_entry *entry) { struct process_info *process; struct thread_info *thread; int step; thread = (struct thread_info *) entry; process = get_thread_process (thread); if (process->resume->leave_stopped) return; if (process->resume->thread == -1) step = process->stepping || process->resume->step; else step = process->resume->step; fbsd_resume_one_process (&process->head, step, process->resume->sig); process->resume = NULL; }
static void linux_kill_one_process (struct inferior_list_entry *entry) { struct thread_info *thread = (struct thread_info *) entry; struct process_info *process = get_thread_process (thread); int wstat; /* We avoid killing the first thread here, because of a Linux kernel (at least 2.6.0-test7 through 2.6.8-rc4) bug; if we kill the parent before the children get a chance to be reaped, it will remain a zombie forever. */ if (entry == all_threads.head) return; do { ptrace (PTRACE_KILL, pid_of (process), 0, 0); /* Make sure it died. The loop is most likely unnecessary. */ wstat = linux_wait_for_event (thread); } while (WIFSTOPPED (wstat)); }
struct regcache * get_thread_regcache (struct thread_info *thread, int fetch) { struct regcache *regcache; regcache = (struct regcache *) inferior_regcache_data (thread); /* Threads' regcaches are created lazily, because biarch targets add the main thread/lwp before seeing it stop for the first time, and it is only after the target sees the thread stop for the first time that the target has a chance of determining the process's architecture. IOW, when we first add the process's main thread we don't know which architecture/tdesc its regcache should have. */ if (regcache == NULL) { struct process_info *proc = get_thread_process (thread); if (proc->tdesc == NULL) fatal ("no target description"); regcache = new_register_cache (proc->tdesc); set_inferior_regcache_data (thread, regcache); } if (fetch && regcache->registers_valid == 0) { struct thread_info *saved_inferior = current_inferior; current_inferior = thread; fetch_inferior_registers (regcache, -1); current_inferior = saved_inferior; regcache->registers_valid = 1; } return regcache; }
static void fbsd_queue_one_thread (struct inferior_list_entry *entry) { struct process_info *process; struct thread_info *thread; thread = (struct thread_info *) entry; process = get_thread_process (thread); if (process->resume->leave_stopped) return; /* If we have a new signal, enqueue the signal. */ if (process->resume->sig != 0) { struct pending_signals *p_sig; p_sig = malloc (sizeof (*p_sig)); p_sig->prev = process->pending_signals; p_sig->signal = process->resume->sig; process->pending_signals = p_sig; } process->resume = NULL; }
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; }
struct process_info * current_process (void) { gdb_assert (current_thread != NULL); return get_thread_process (current_thread); }
int thread_db_get_tls_address (struct thread_info *thread, CORE_ADDR offset, CORE_ADDR load_module, CORE_ADDR *address) { psaddr_t addr; td_err_e err; struct lwp_info *lwp; struct thread_info *saved_thread; struct process_info *proc; struct thread_db *thread_db; proc = get_thread_process (thread); thread_db = proc->priv->thread_db; /* If the thread layer is not (yet) initialized, fail. */ if (thread_db == NULL || !thread_db->all_symbols_looked_up) return TD_ERR; /* If td_thr_tls_get_addr is missing rather do not expect td_thr_tlsbase could work. */ if (thread_db->td_thr_tls_get_addr_p == NULL || (load_module == 0 && thread_db->td_thr_tlsbase_p == NULL)) return -1; lwp = get_thread_lwp (thread); if (!lwp->thread_known) find_one_thread (thread->entry.id); if (!lwp->thread_known) return TD_NOTHR; saved_thread = current_thread; current_thread = thread; if (load_module != 0) { /* Note the cast through uintptr_t: this interface only works if a target address fits in a psaddr_t, which is a host pointer. So a 32-bit debugger can not access 64-bit TLS through this. */ err = thread_db->td_thr_tls_get_addr_p (&lwp->th, (psaddr_t) (uintptr_t) load_module, offset, &addr); } else { /* This code path handles the case of -static -pthread executables: https://sourceware.org/ml/libc-help/2014-03/msg00024.html For older GNU libc r_debug.r_map is NULL. For GNU libc after PR libc/16831 due to GDB PR threads/16954 LOAD_MODULE is also NULL. The constant number 1 depends on GNU __libc_setup_tls initialization of l_tls_modid to 1. */ err = thread_db->td_thr_tlsbase_p (&lwp->th, 1, &addr); addr = (char *) addr + offset; } current_thread = saved_thread; if (err == TD_OK) { *address = (CORE_ADDR) (uintptr_t) addr; return 0; } else return err; }