//-------------------------------------------------------------------------- // returns true: multithreaded application has been detected bool linux_debmod_t::tdb_new(int pid) { if ( ta == NULL ) { #ifdef LDEB msg("checking pid %d with thread_db\n", pid); #endif prochandle.pid = pid; td_err_e err = td_ta_new(&prochandle, &ta); // the call might fail the first time if libc is not loaded yet // so don't show misleading message to the user // COMPLAIN_IF_FAILED("td_ta_new", err); if ( err != TD_OK ) { ta = NULL; return false; } td_thrhandle_t th; err = td_ta_map_lwp2thr(ta, pid, &th); COMPLAIN_IF_FAILED("td_ta_map_lwp2thr", err); if ( err != TD_OK ) return false; err = td_thr_event_enable(&th, TD_CREATE); DIE_IF_FAILED("td_thr_event_enable(TD_CREATE)", err); err = td_thr_event_enable(&th, TD_DEATH); DIE_IF_FAILED("td_thr_event_enable(TD_DEATH)", err); // set breakpoints for thread birth/death td_thr_events_t events; td_event_emptyset(&events); td_event_addset(&events, TD_CREATE); td_event_addset(&events, TD_DEATH); err = td_ta_set_event(ta, &events); DIE_IF_FAILED("td_ta_set_event", err); tdb_enable_event(TD_CREATE, &birth_bpt); tdb_enable_event(TD_DEATH, &death_bpt); #ifdef LDEB msg("thread support has been detected, birth_bpt=%a death_bpt=%a\n", birth_bpt.bpt_addr, death_bpt.bpt_addr); #endif /* // hack: enable thread_td debug. later: it turned out to be useless debug print. td_log(); uchar *ptr = (uchar *)td_log; QASSERT(ptr[0] == 0xFF && ptr[1] == 0x25); ptr = **(uchar***)(ptr+2); ptr += 0x7158 - 0x1120; *ptr = 1; // enable */ tdb_update_threads(); } return true; }
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)); }
//-------------------------------------------------------------------------- void linux_debmod_t::new_thread(thrinfo_t *info) { int tid = info->ti_lid; threads_t::iterator p = threads.find(tid); if ( p == threads.end() ) // not found { #ifdef LDEB msg("thread %d is new\n", tid); ::display_thrinfo(*info); #endif td_err_e err; td_thr_events_t events; td_event_emptyset(&events); td_event_addset(&events, TD_CREATE); td_event_addset(&events, TD_DEATH); td_event_addset(&events, TD_CATCHSIG); err = td_thr_set_event(info->th_p, &events); DIE_IF_FAILED("td_thr_set_event", err); err = td_thr_event_enable(info->th_p, 1); COMPLAIN_IF_FAILED("td_thr_event_enable", err); if ( err != TD_OK ) { #ifdef LDEB msg("%d: thread dead already? not adding to list.\n", tid); #endif return; } sigset_t set; sigemptyset(&set); sigaddset(&set, SIGSTOP); td_thr_setsigpending(info->th_p, 1, &set); debug_event_t ev; ev.eid = THREAD_START; ev.pid = process_handle; ev.tid = tid; ev.ea = (ea_t)info->ti_startfunc; ev.handled = true; add_thread(tid); // attach to the thread and make is ready for debugging qptrace(PTRACE_ATTACH, tid, 0, 0); int status; int tid2 = waitpid(tid, &status, __WCLONE); // (must succeed) consume SIGSTOP QASSERT(tid2 != -1 && WIFSTOPPED(status) && WSTOPSIG(status) == SIGSTOP); get_thread(tid)->waiting_sigstop = false; enqueue_event(ev, IN_FRONT); } get_thread(tid)->thr = info->th_p; }
static int update_threads_cb(const td_thrhandle_t *th_p, void *data) { thrinfovec_t &newlist = *(thrinfovec_t *)data; thrinfo_t ti; td_err_e err = td_thr_get_info(th_p, &ti); DIE_IF_FAILED("td_thr_get_info", err); if ( ti.ti_state == TD_THR_UNKNOWN || ti.ti_state == TD_THR_ZOMBIE ) return 0; if ( ti.ti_tid != 0 ) { td_thr_events_t events; td_event_emptyset(&events); td_event_addset(&events, TD_CREATE); td_event_addset(&events, TD_DEATH); // td_event_addset(&events, TD_CATCHSIG); err = td_thr_set_event(th_p, &events); DIE_IF_FAILED("td_thr_set_event", err); err = td_thr_event_enable(th_p, 1); DIE_IF_FAILED("td_thr_event_enable", err); sigset_t set; sigemptyset(&set); sigaddset(&set, SIGSTOP); td_thr_setsigpending(th_p, 1, &set); } ti.th_p = th_p; #ifdef LDEB msg("update_threads_cb: got thread %d\n", ti.ti_lid); //td_thr_get_info(th_p, &ti); //display_thrinfo(ti); #endif newlist.push_back(ti); return 0; }