static td_err_e enable_thread_event (int event, CORE_ADDR *bp) { td_notify_t notify; td_err_e err; struct thread_db_info *info; info = get_thread_db_info (GET_PID (inferior_ptid)); /* Access an lwp we know is stopped. */ info->proc_handle.ptid = inferior_ptid; /* Get the breakpoint address for thread EVENT. */ err = info->td_ta_event_addr_p (info->thread_agent, event, ¬ify); if (err != TD_OK) return err; /* Set up the breakpoint. */ gdb_assert (exec_bfd); (*bp) = (gdbarch_convert_from_func_ptr_addr (target_gdbarch, /* Do proper sign extension for the target. */ (bfd_get_sign_extend_vma (exec_bfd) > 0 ? (CORE_ADDR) (intptr_t) notify.u.bptaddr : (CORE_ADDR) (uintptr_t) notify.u.bptaddr), ¤t_target)); create_thread_event_breakpoint (target_gdbarch, *bp); return TD_OK; }
/* Attach to lwp PTID, doing whatever else is required to have this LWP under the debugger's control --- e.g., enabling event reporting. Returns true on success. */ int thread_db_attach_lwp (ptid_t ptid) { td_thrhandle_t th; td_thrinfo_t ti; td_err_e err; struct thread_db_info *info; info = get_thread_db_info (GET_PID (ptid)); if (info == NULL) return 0; /* This ptid comes from linux-nat.c, which should always fill in the LWP. */ gdb_assert (GET_LWP (ptid) != 0); /* Access an lwp we know is stopped. */ info->proc_handle.ptid = ptid; /* If we have only looked at the first thread before libpthread was initialized, we may not know its thread ID yet. Make sure we do before we add another thread to the list. */ if (!have_threads (ptid)) thread_db_find_new_threads_1 (ptid); err = info->td_ta_map_lwp2thr_p (info->thread_agent, GET_LWP (ptid), &th); if (err != TD_OK) /* Cannot find user-level thread. */ return 0; err = info->td_thr_get_info_p (&th, &ti); if (err != TD_OK) { warning (_("Cannot get thread info: %s"), thread_db_err_str (err)); return 0; } attach_thread (ptid, &th, &ti); return 1; }
static ptid_t thread_from_lwp (ptid_t ptid) { td_thrhandle_t th; td_err_e err; ptid_t thread_ptid; struct thread_db_info *info; struct thread_get_info_inout io = {0}; /* This ptid comes from linux-nat.c, which should always fill in the LWP. */ gdb_assert (GET_LWP (ptid) != 0); info = get_thread_db_info (GET_PID (ptid)); /* Access an lwp we know is stopped. */ info->proc_handle.ptid = ptid; err = info->td_ta_map_lwp2thr_p (info->thread_agent, GET_LWP (ptid), &th); if (err != TD_OK) error (_("Cannot find user-level thread for LWP %ld: %s"), GET_LWP (ptid), thread_db_err_str (err)); /* Fetch the thread info. If we get back TD_THR_ZOMBIE, then the event thread has already died. If another gdb interface has called thread_alive() previously, the thread won't be found on the thread list anymore. In that case, we don't want to process this ptid anymore to avoid the possibility of later treating it as a newly discovered thread id that we should add to the list. Thus, we return a -1 ptid which is also how the thread list marks a dead thread. */ io.thread_db_info = info; io.thread_info = NULL; if (thread_get_info_callback (&th, &io) == TD_THR_ZOMBIE && io.thread_info == NULL) return minus_one_ptid; gdb_assert (ptid_get_tid (ptid) == 0); return ptid; }
static void enable_thread_event_reporting (void) { td_thr_events_t events; td_err_e err; #ifdef HAVE_GNU_LIBC_VERSION_H const char *libc_version; int libc_major, libc_minor; #endif struct thread_db_info *info; info = get_thread_db_info (GET_PID (inferior_ptid)); /* We cannot use the thread event reporting facility if these functions aren't available. */ if (info->td_ta_event_addr_p == NULL || info->td_ta_set_event_p == NULL || info->td_ta_event_getmsg_p == NULL || info->td_thr_event_enable_p == NULL) return; /* Set the process wide mask saying which events we're interested in. */ td_event_emptyset (&events); td_event_addset (&events, TD_CREATE); #ifdef HAVE_GNU_LIBC_VERSION_H /* The event reporting facility is broken for TD_DEATH events in glibc 2.1.3, so don't enable it if we have glibc but a lower version. */ libc_version = gnu_get_libc_version (); if (sscanf (libc_version, "%d.%d", &libc_major, &libc_minor) == 2 && (libc_major > 2 || (libc_major == 2 && libc_minor > 1))) #endif td_event_addset (&events, TD_DEATH); err = info->td_ta_set_event_p (info->thread_agent, &events); if (err != TD_OK) { warning (_("Unable to set global thread event mask: %s"), thread_db_err_str (err)); return; } /* Delete previous thread event breakpoints, if any. */ remove_thread_event_breakpoints (); info->td_create_bp_addr = 0; info->td_death_bp_addr = 0; /* Set up the thread creation event. */ err = enable_thread_event (TD_CREATE, &info->td_create_bp_addr); if (err != TD_OK) { warning (_("Unable to get location for thread creation breakpoint: %s"), thread_db_err_str (err)); return; } /* Set up the thread death event. */ err = enable_thread_event (TD_DEATH, &info->td_death_bp_addr); if (err != TD_OK) { warning (_("Unable to get location for thread death breakpoint: %s"), thread_db_err_str (err)); return; } }