1130803Smarcel/* Thread management interface, for the remote server for GDB. 2130803Smarcel Copyright 2002 3130803Smarcel Free Software Foundation, Inc. 4130803Smarcel 5130803Smarcel Contributed by MontaVista Software. 6130803Smarcel 7130803Smarcel This file is part of GDB. 8130803Smarcel 9130803Smarcel This program is free software; you can redistribute it and/or modify 10130803Smarcel it under the terms of the GNU General Public License as published by 11130803Smarcel the Free Software Foundation; either version 2 of the License, or 12130803Smarcel (at your option) any later version. 13130803Smarcel 14130803Smarcel This program is distributed in the hope that it will be useful, 15130803Smarcel but WITHOUT ANY WARRANTY; without even the implied warranty of 16130803Smarcel MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17130803Smarcel GNU General Public License for more details. 18130803Smarcel 19130803Smarcel You should have received a copy of the GNU General Public License 20130803Smarcel along with this program; if not, write to the Free Software 21130803Smarcel Foundation, Inc., 59 Temple Place - Suite 330, 22130803Smarcel Boston, MA 02111-1307, USA. */ 23130803Smarcel 24130803Smarcel#include "server.h" 25130803Smarcel 26130803Smarcel#include "linux-low.h" 27130803Smarcel 28130803Smarcelextern int debug_threads; 29130803Smarcel 30130803Smarcel#ifdef HAVE_THREAD_DB_H 31130803Smarcel#include <thread_db.h> 32130803Smarcel#endif 33130803Smarcel 34130803Smarcel/* Correct for all GNU/Linux targets (for quite some time). */ 35130803Smarcel#define GDB_GREGSET_T elf_gregset_t 36130803Smarcel#define GDB_FPREGSET_T elf_fpregset_t 37130803Smarcel 38130803Smarcel#ifndef HAVE_ELF_FPREGSET_T 39130803Smarcel/* Make sure we have said types. Not all platforms bring in <linux/elf.h> 40130803Smarcel via <sys/procfs.h>. */ 41130803Smarcel#ifdef HAVE_LINUX_ELF_H 42130803Smarcel#include <linux/elf.h> 43130803Smarcel#endif 44130803Smarcel#endif 45130803Smarcel 46130803Smarcel#include "../gdb_proc_service.h" 47130803Smarcel 48130803Smarcel/* Structure that identifies the child process for the 49130803Smarcel <proc_service.h> interface. */ 50130803Smarcelstatic struct ps_prochandle proc_handle; 51130803Smarcel 52130803Smarcel/* Connection to the libthread_db library. */ 53130803Smarcelstatic td_thragent_t *thread_agent; 54130803Smarcel 55130803Smarcelstatic int find_new_threads_callback (const td_thrhandle_t *th_p, void *data); 56130803Smarcel 57130803Smarcelstatic char * 58130803Smarcelthread_db_err_str (td_err_e err) 59130803Smarcel{ 60130803Smarcel static char buf[64]; 61130803Smarcel 62130803Smarcel switch (err) 63130803Smarcel { 64130803Smarcel case TD_OK: 65130803Smarcel return "generic 'call succeeded'"; 66130803Smarcel case TD_ERR: 67130803Smarcel return "generic error"; 68130803Smarcel case TD_NOTHR: 69130803Smarcel return "no thread to satisfy query"; 70130803Smarcel case TD_NOSV: 71130803Smarcel return "no sync handle to satisfy query"; 72130803Smarcel case TD_NOLWP: 73130803Smarcel return "no LWP to satisfy query"; 74130803Smarcel case TD_BADPH: 75130803Smarcel return "invalid process handle"; 76130803Smarcel case TD_BADTH: 77130803Smarcel return "invalid thread handle"; 78130803Smarcel case TD_BADSH: 79130803Smarcel return "invalid synchronization handle"; 80130803Smarcel case TD_BADTA: 81130803Smarcel return "invalid thread agent"; 82130803Smarcel case TD_BADKEY: 83130803Smarcel return "invalid key"; 84130803Smarcel case TD_NOMSG: 85130803Smarcel return "no event message for getmsg"; 86130803Smarcel case TD_NOFPREGS: 87130803Smarcel return "FPU register set not available"; 88130803Smarcel case TD_NOLIBTHREAD: 89130803Smarcel return "application not linked with libthread"; 90130803Smarcel case TD_NOEVENT: 91130803Smarcel return "requested event is not supported"; 92130803Smarcel case TD_NOCAPAB: 93130803Smarcel return "capability not available"; 94130803Smarcel case TD_DBERR: 95130803Smarcel return "debugger service failed"; 96130803Smarcel case TD_NOAPLIC: 97130803Smarcel return "operation not applicable to"; 98130803Smarcel case TD_NOTSD: 99130803Smarcel return "no thread-specific data for this thread"; 100130803Smarcel case TD_MALLOC: 101130803Smarcel return "malloc failed"; 102130803Smarcel case TD_PARTIALREG: 103130803Smarcel return "only part of register set was written/read"; 104130803Smarcel case TD_NOXREGS: 105130803Smarcel return "X register set not available for this thread"; 106130803Smarcel default: 107130803Smarcel snprintf (buf, sizeof (buf), "unknown thread_db error '%d'", err); 108130803Smarcel return buf; 109130803Smarcel } 110130803Smarcel} 111130803Smarcel 112130803Smarcel#if 0 113130803Smarcelstatic char * 114130803Smarcelthread_db_state_str (td_thr_state_e state) 115130803Smarcel{ 116130803Smarcel static char buf[64]; 117130803Smarcel 118130803Smarcel switch (state) 119130803Smarcel { 120130803Smarcel case TD_THR_STOPPED: 121130803Smarcel return "stopped by debugger"; 122130803Smarcel case TD_THR_RUN: 123130803Smarcel return "runnable"; 124130803Smarcel case TD_THR_ACTIVE: 125130803Smarcel return "active"; 126130803Smarcel case TD_THR_ZOMBIE: 127130803Smarcel return "zombie"; 128130803Smarcel case TD_THR_SLEEP: 129130803Smarcel return "sleeping"; 130130803Smarcel case TD_THR_STOPPED_ASLEEP: 131130803Smarcel return "stopped by debugger AND blocked"; 132130803Smarcel default: 133130803Smarcel snprintf (buf, sizeof (buf), "unknown thread_db state %d", state); 134130803Smarcel return buf; 135130803Smarcel } 136130803Smarcel} 137130803Smarcel#endif 138130803Smarcel 139130803Smarcelstatic void 140130803Smarcelthread_db_create_event (CORE_ADDR where) 141130803Smarcel{ 142130803Smarcel td_event_msg_t msg; 143130803Smarcel td_err_e err; 144130803Smarcel struct inferior_linux_data *tdata; 145130803Smarcel 146130803Smarcel if (debug_threads) 147130803Smarcel fprintf (stderr, "Thread creation event.\n"); 148130803Smarcel 149130803Smarcel tdata = inferior_target_data (current_inferior); 150130803Smarcel 151130803Smarcel /* FIXME: This assumes we don't get another event. 152130803Smarcel In the LinuxThreads implementation, this is safe, 153130803Smarcel because all events come from the manager thread 154130803Smarcel (except for its own creation, of course). */ 155130803Smarcel err = td_ta_event_getmsg (thread_agent, &msg); 156130803Smarcel if (err != TD_OK) 157130803Smarcel fprintf (stderr, "thread getmsg err: %s\n", 158130803Smarcel thread_db_err_str (err)); 159130803Smarcel 160130803Smarcel /* msg.event == TD_EVENT_CREATE */ 161130803Smarcel 162130803Smarcel find_new_threads_callback (msg.th_p, NULL); 163130803Smarcel} 164130803Smarcel 165130803Smarcel#if 0 166130803Smarcelstatic void 167130803Smarcelthread_db_death_event (CORE_ADDR where) 168130803Smarcel{ 169130803Smarcel if (debug_threads) 170130803Smarcel fprintf (stderr, "Thread death event.\n"); 171130803Smarcel} 172130803Smarcel#endif 173130803Smarcel 174130803Smarcelstatic int 175130803Smarcelthread_db_enable_reporting () 176130803Smarcel{ 177130803Smarcel td_thr_events_t events; 178130803Smarcel td_notify_t notify; 179130803Smarcel td_err_e err; 180130803Smarcel 181130803Smarcel /* Set the process wide mask saying which events we're interested in. */ 182130803Smarcel td_event_emptyset (&events); 183130803Smarcel td_event_addset (&events, TD_CREATE); 184130803Smarcel 185130803Smarcel#if 0 186130803Smarcel /* This is reported to be broken in glibc 2.1.3. A different approach 187130803Smarcel will be necessary to support that. */ 188130803Smarcel td_event_addset (&events, TD_DEATH); 189130803Smarcel#endif 190130803Smarcel 191130803Smarcel err = td_ta_set_event (thread_agent, &events); 192130803Smarcel if (err != TD_OK) 193130803Smarcel { 194130803Smarcel warning ("Unable to set global thread event mask: %s", 195130803Smarcel thread_db_err_str (err)); 196130803Smarcel return 0; 197130803Smarcel } 198130803Smarcel 199130803Smarcel /* Get address for thread creation breakpoint. */ 200130803Smarcel err = td_ta_event_addr (thread_agent, TD_CREATE, ¬ify); 201130803Smarcel if (err != TD_OK) 202130803Smarcel { 203130803Smarcel warning ("Unable to get location for thread creation breakpoint: %s", 204130803Smarcel thread_db_err_str (err)); 205130803Smarcel return 0; 206130803Smarcel } 207130803Smarcel set_breakpoint_at ((CORE_ADDR) (unsigned long) notify.u.bptaddr, 208130803Smarcel thread_db_create_event); 209130803Smarcel 210130803Smarcel#if 0 211130803Smarcel /* Don't concern ourselves with reported thread deaths, only 212130803Smarcel with actual thread deaths (via wait). */ 213130803Smarcel 214130803Smarcel /* Get address for thread death breakpoint. */ 215130803Smarcel err = td_ta_event_addr (thread_agent, TD_DEATH, ¬ify); 216130803Smarcel if (err != TD_OK) 217130803Smarcel { 218130803Smarcel warning ("Unable to get location for thread death breakpoint: %s", 219130803Smarcel thread_db_err_str (err)); 220130803Smarcel return; 221130803Smarcel } 222130803Smarcel set_breakpoint_at ((CORE_ADDR) (unsigned long) notify.u.bptaddr, 223130803Smarcel thread_db_death_event); 224130803Smarcel#endif 225130803Smarcel 226130803Smarcel return 1; 227130803Smarcel} 228130803Smarcel 229130803Smarcelstatic void 230130803Smarcelmaybe_attach_thread (const td_thrhandle_t *th_p, td_thrinfo_t *ti_p) 231130803Smarcel{ 232130803Smarcel td_err_e err; 233130803Smarcel struct thread_info *inferior; 234130803Smarcel struct process_info *process; 235130803Smarcel 236130803Smarcel /* If we are attaching to our first thread, things are a little 237130803Smarcel different. */ 238130803Smarcel if (all_threads.head == all_threads.tail) 239130803Smarcel { 240130803Smarcel inferior = (struct thread_info *) all_threads.head; 241130803Smarcel process = get_thread_process (inferior); 242130803Smarcel if (process->thread_known == 0) 243130803Smarcel { 244130803Smarcel /* Switch to indexing the threads list by TID. */ 245130803Smarcel change_inferior_id (&all_threads, ti_p->ti_tid); 246130803Smarcel goto found; 247130803Smarcel } 248130803Smarcel } 249130803Smarcel 250130803Smarcel inferior = (struct thread_info *) find_inferior_id (&all_threads, 251130803Smarcel ti_p->ti_tid); 252130803Smarcel if (inferior != NULL) 253130803Smarcel return; 254130803Smarcel 255130803Smarcel if (debug_threads) 256130803Smarcel fprintf (stderr, "Attaching to thread %ld (LWP %d)\n", 257130803Smarcel ti_p->ti_tid, ti_p->ti_lid); 258130803Smarcel linux_attach_lwp (ti_p->ti_lid, ti_p->ti_tid); 259130803Smarcel inferior = (struct thread_info *) find_inferior_id (&all_threads, 260130803Smarcel ti_p->ti_tid); 261130803Smarcel if (inferior == NULL) 262130803Smarcel { 263130803Smarcel warning ("Could not attach to thread %ld (LWP %d)\n", 264130803Smarcel ti_p->ti_tid, ti_p->ti_lid); 265130803Smarcel return; 266130803Smarcel } 267130803Smarcel 268130803Smarcel process = inferior_target_data (inferior); 269130803Smarcel 270130803Smarcelfound: 271130803Smarcel new_thread_notify (ti_p->ti_tid); 272130803Smarcel 273130803Smarcel process->tid = ti_p->ti_tid; 274130803Smarcel process->lwpid = ti_p->ti_lid; 275130803Smarcel 276130803Smarcel process->thread_known = 1; 277130803Smarcel err = td_thr_event_enable (th_p, 1); 278130803Smarcel if (err != TD_OK) 279130803Smarcel error ("Cannot enable thread event reporting for %d: %s", 280130803Smarcel ti_p->ti_lid, thread_db_err_str (err)); 281130803Smarcel} 282130803Smarcel 283130803Smarcelstatic int 284130803Smarcelfind_new_threads_callback (const td_thrhandle_t *th_p, void *data) 285130803Smarcel{ 286130803Smarcel td_thrinfo_t ti; 287130803Smarcel td_err_e err; 288130803Smarcel 289130803Smarcel err = td_thr_get_info (th_p, &ti); 290130803Smarcel if (err != TD_OK) 291130803Smarcel error ("Cannot get thread info: %s", thread_db_err_str (err)); 292130803Smarcel 293130803Smarcel /* Check for zombies. */ 294130803Smarcel if (ti.ti_state == TD_THR_UNKNOWN || ti.ti_state == TD_THR_ZOMBIE) 295130803Smarcel return 0; 296130803Smarcel 297130803Smarcel maybe_attach_thread (th_p, &ti); 298130803Smarcel 299130803Smarcel return 0; 300130803Smarcel} 301130803Smarcel 302130803Smarcelstatic void 303130803Smarcelthread_db_find_new_threads (void) 304130803Smarcel{ 305130803Smarcel td_err_e err; 306130803Smarcel 307130803Smarcel /* Iterate over all user-space threads to discover new threads. */ 308130803Smarcel err = td_ta_thr_iter (thread_agent, find_new_threads_callback, NULL, 309130803Smarcel TD_THR_ANY_STATE, TD_THR_LOWEST_PRIORITY, 310130803Smarcel TD_SIGNO_MASK, TD_THR_ANY_USER_FLAGS); 311130803Smarcel if (err != TD_OK) 312130803Smarcel error ("Cannot find new threads: %s", thread_db_err_str (err)); 313130803Smarcel} 314130803Smarcel 315130803Smarcelint 316130803Smarcelthread_db_init () 317130803Smarcel{ 318130803Smarcel int err; 319130803Smarcel 320130803Smarcel proc_handle.pid = ((struct inferior_list_entry *)current_inferior)->id; 321130803Smarcel 322130803Smarcel err = td_ta_new (&proc_handle, &thread_agent); 323130803Smarcel switch (err) 324130803Smarcel { 325130803Smarcel case TD_NOLIBTHREAD: 326130803Smarcel /* No thread library was detected. */ 327130803Smarcel return 0; 328130803Smarcel 329130803Smarcel case TD_OK: 330130803Smarcel /* The thread library was detected. */ 331130803Smarcel 332130803Smarcel if (thread_db_enable_reporting () == 0) 333130803Smarcel return 0; 334130803Smarcel thread_db_find_new_threads (); 335130803Smarcel return 1; 336130803Smarcel 337130803Smarcel default: 338130803Smarcel warning ("error initializing thread_db library."); 339130803Smarcel } 340130803Smarcel 341130803Smarcel return 0; 342130803Smarcel} 343