1/* Thread management interface, for the remote server for GDB. 2 Copyright 2002 3 Free Software Foundation, Inc. 4 5 Contributed by MontaVista Software. 6 7 This file is part of GDB. 8 9 This program is free software; you can redistribute it and/or modify 10 it under the terms of the GNU General Public License as published by 11 the Free Software Foundation; either version 2 of the License, or 12 (at your option) any later version. 13 14 This program is distributed in the hope that it will be useful, 15 but WITHOUT ANY WARRANTY; without even the implied warranty of 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 GNU General Public License for more details. 18 19 You should have received a copy of the GNU General Public License 20 along with this program; if not, write to the Free Software 21 Foundation, Inc., 59 Temple Place - Suite 330, 22 Boston, MA 02111-1307, USA. */ 23 24#include "server.h" 25 26#include "linux-low.h" 27 28extern int debug_threads; 29 30#ifdef HAVE_THREAD_DB_H 31#include <thread_db.h> 32#endif 33 34/* Correct for all GNU/Linux targets (for quite some time). */ 35#define GDB_GREGSET_T elf_gregset_t 36#define GDB_FPREGSET_T elf_fpregset_t 37 38#ifndef HAVE_ELF_FPREGSET_T 39/* Make sure we have said types. Not all platforms bring in <linux/elf.h> 40 via <sys/procfs.h>. */ 41#ifdef HAVE_LINUX_ELF_H 42#include <linux/elf.h> 43#endif 44#endif 45 46#include "../gdb_proc_service.h" 47 48/* Structure that identifies the child process for the 49 <proc_service.h> interface. */ 50static struct ps_prochandle proc_handle; 51 52/* Connection to the libthread_db library. */ 53static td_thragent_t *thread_agent; 54 55static int find_new_threads_callback (const td_thrhandle_t *th_p, void *data); 56 57static char * 58thread_db_err_str (td_err_e err) 59{ 60 static char buf[64]; 61 62 switch (err) 63 { 64 case TD_OK: 65 return "generic 'call succeeded'"; 66 case TD_ERR: 67 return "generic error"; 68 case TD_NOTHR: 69 return "no thread to satisfy query"; 70 case TD_NOSV: 71 return "no sync handle to satisfy query"; 72 case TD_NOLWP: 73 return "no LWP to satisfy query"; 74 case TD_BADPH: 75 return "invalid process handle"; 76 case TD_BADTH: 77 return "invalid thread handle"; 78 case TD_BADSH: 79 return "invalid synchronization handle"; 80 case TD_BADTA: 81 return "invalid thread agent"; 82 case TD_BADKEY: 83 return "invalid key"; 84 case TD_NOMSG: 85 return "no event message for getmsg"; 86 case TD_NOFPREGS: 87 return "FPU register set not available"; 88 case TD_NOLIBTHREAD: 89 return "application not linked with libthread"; 90 case TD_NOEVENT: 91 return "requested event is not supported"; 92 case TD_NOCAPAB: 93 return "capability not available"; 94 case TD_DBERR: 95 return "debugger service failed"; 96 case TD_NOAPLIC: 97 return "operation not applicable to"; 98 case TD_NOTSD: 99 return "no thread-specific data for this thread"; 100 case TD_MALLOC: 101 return "malloc failed"; 102 case TD_PARTIALREG: 103 return "only part of register set was written/read"; 104 case TD_NOXREGS: 105 return "X register set not available for this thread"; 106 default: 107 snprintf (buf, sizeof (buf), "unknown thread_db error '%d'", err); 108 return buf; 109 } 110} 111 112#if 0 113static char * 114thread_db_state_str (td_thr_state_e state) 115{ 116 static char buf[64]; 117 118 switch (state) 119 { 120 case TD_THR_STOPPED: 121 return "stopped by debugger"; 122 case TD_THR_RUN: 123 return "runnable"; 124 case TD_THR_ACTIVE: 125 return "active"; 126 case TD_THR_ZOMBIE: 127 return "zombie"; 128 case TD_THR_SLEEP: 129 return "sleeping"; 130 case TD_THR_STOPPED_ASLEEP: 131 return "stopped by debugger AND blocked"; 132 default: 133 snprintf (buf, sizeof (buf), "unknown thread_db state %d", state); 134 return buf; 135 } 136} 137#endif 138 139static void 140thread_db_create_event (CORE_ADDR where) 141{ 142 td_event_msg_t msg; 143 td_err_e err; 144 struct inferior_linux_data *tdata; 145 146 if (debug_threads) 147 fprintf (stderr, "Thread creation event.\n"); 148 149 tdata = inferior_target_data (current_inferior); 150 151 /* FIXME: This assumes we don't get another event. 152 In the LinuxThreads implementation, this is safe, 153 because all events come from the manager thread 154 (except for its own creation, of course). */ 155 err = td_ta_event_getmsg (thread_agent, &msg); 156 if (err != TD_OK) 157 fprintf (stderr, "thread getmsg err: %s\n", 158 thread_db_err_str (err)); 159 160 /* msg.event == TD_EVENT_CREATE */ 161 162 find_new_threads_callback (msg.th_p, NULL); 163} 164 165#if 0 166static void 167thread_db_death_event (CORE_ADDR where) 168{ 169 if (debug_threads) 170 fprintf (stderr, "Thread death event.\n"); 171} 172#endif 173 174static int 175thread_db_enable_reporting () 176{ 177 td_thr_events_t events; 178 td_notify_t notify; 179 td_err_e err; 180 181 /* Set the process wide mask saying which events we're interested in. */ 182 td_event_emptyset (&events); 183 td_event_addset (&events, TD_CREATE); 184 185#if 0 186 /* This is reported to be broken in glibc 2.1.3. A different approach 187 will be necessary to support that. */ 188 td_event_addset (&events, TD_DEATH); 189#endif 190 191 err = td_ta_set_event (thread_agent, &events); 192 if (err != TD_OK) 193 { 194 warning ("Unable to set global thread event mask: %s", 195 thread_db_err_str (err)); 196 return 0; 197 } 198 199 /* Get address for thread creation breakpoint. */ 200 err = td_ta_event_addr (thread_agent, TD_CREATE, ¬ify); 201 if (err != TD_OK) 202 { 203 warning ("Unable to get location for thread creation breakpoint: %s", 204 thread_db_err_str (err)); 205 return 0; 206 } 207 set_breakpoint_at ((CORE_ADDR) (unsigned long) notify.u.bptaddr, 208 thread_db_create_event); 209 210#if 0 211 /* Don't concern ourselves with reported thread deaths, only 212 with actual thread deaths (via wait). */ 213 214 /* Get address for thread death breakpoint. */ 215 err = td_ta_event_addr (thread_agent, TD_DEATH, ¬ify); 216 if (err != TD_OK) 217 { 218 warning ("Unable to get location for thread death breakpoint: %s", 219 thread_db_err_str (err)); 220 return; 221 } 222 set_breakpoint_at ((CORE_ADDR) (unsigned long) notify.u.bptaddr, 223 thread_db_death_event); 224#endif 225 226 return 1; 227} 228 229static void 230maybe_attach_thread (const td_thrhandle_t *th_p, td_thrinfo_t *ti_p) 231{ 232 td_err_e err; 233 struct thread_info *inferior; 234 struct process_info *process; 235 236 /* If we are attaching to our first thread, things are a little 237 different. */ 238 if (all_threads.head == all_threads.tail) 239 { 240 inferior = (struct thread_info *) all_threads.head; 241 process = get_thread_process (inferior); 242 if (process->thread_known == 0) 243 { 244 /* Switch to indexing the threads list by TID. */ 245 change_inferior_id (&all_threads, ti_p->ti_tid); 246 goto found; 247 } 248 } 249 250 inferior = (struct thread_info *) find_inferior_id (&all_threads, 251 ti_p->ti_tid); 252 if (inferior != NULL) 253 return; 254 255 if (debug_threads) 256 fprintf (stderr, "Attaching to thread %ld (LWP %d)\n", 257 ti_p->ti_tid, ti_p->ti_lid); 258 linux_attach_lwp (ti_p->ti_lid, ti_p->ti_tid); 259 inferior = (struct thread_info *) find_inferior_id (&all_threads, 260 ti_p->ti_tid); 261 if (inferior == NULL) 262 { 263 warning ("Could not attach to thread %ld (LWP %d)\n", 264 ti_p->ti_tid, ti_p->ti_lid); 265 return; 266 } 267 268 process = inferior_target_data (inferior); 269 270found: 271 new_thread_notify (ti_p->ti_tid); 272 273 process->tid = ti_p->ti_tid; 274 process->lwpid = ti_p->ti_lid; 275 276 process->thread_known = 1; 277 err = td_thr_event_enable (th_p, 1); 278 if (err != TD_OK) 279 error ("Cannot enable thread event reporting for %d: %s", 280 ti_p->ti_lid, thread_db_err_str (err)); 281} 282 283static int 284find_new_threads_callback (const td_thrhandle_t *th_p, void *data) 285{ 286 td_thrinfo_t ti; 287 td_err_e err; 288 289 err = td_thr_get_info (th_p, &ti); 290 if (err != TD_OK) 291 error ("Cannot get thread info: %s", thread_db_err_str (err)); 292 293 /* Check for zombies. */ 294 if (ti.ti_state == TD_THR_UNKNOWN || ti.ti_state == TD_THR_ZOMBIE) 295 return 0; 296 297 maybe_attach_thread (th_p, &ti); 298 299 return 0; 300} 301 302static void 303thread_db_find_new_threads (void) 304{ 305 td_err_e err; 306 307 /* Iterate over all user-space threads to discover new threads. */ 308 err = td_ta_thr_iter (thread_agent, find_new_threads_callback, NULL, 309 TD_THR_ANY_STATE, TD_THR_LOWEST_PRIORITY, 310 TD_SIGNO_MASK, TD_THR_ANY_USER_FLAGS); 311 if (err != TD_OK) 312 error ("Cannot find new threads: %s", thread_db_err_str (err)); 313} 314 315int 316thread_db_init () 317{ 318 int err; 319 320 proc_handle.pid = ((struct inferior_list_entry *)current_inferior)->id; 321 322 err = td_ta_new (&proc_handle, &thread_agent); 323 switch (err) 324 { 325 case TD_NOLIBTHREAD: 326 /* No thread library was detected. */ 327 return 0; 328 329 case TD_OK: 330 /* The thread library was detected. */ 331 332 if (thread_db_enable_reporting () == 0) 333 return 0; 334 thread_db_find_new_threads (); 335 return 1; 336 337 default: 338 warning ("error initializing thread_db library."); 339 } 340 341 return 0; 342} 343