GDB (API)
/home/stan/gdb/src/gdb/dec-thread.c
Go to the documentation of this file.
00001 /* Copyright (C) 2008-2013 Free Software Foundation, Inc.
00002 
00003    This file is part of GDB.
00004 
00005    This program is free software; you can redistribute it and/or modify
00006    it under the terms of the GNU General Public License as published by
00007    the Free Software Foundation; either version 3 of the License, or
00008    (at your option) any later version.
00009 
00010    This program is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013    GNU General Public License for more details.
00014 
00015    You should have received a copy of the GNU General Public License
00016    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
00017 
00018 #include "defs.h"
00019 #include "command.h"
00020 #include "gdbcmd.h"
00021 #include "target.h"
00022 #include "observer.h"
00023 #include <sys/procfs.h>
00024 #include "gregset.h"
00025 #include "regcache.h"
00026 #include "inferior.h"
00027 #include "gdbthread.h"
00028 
00029 #include <pthread_debug.h>
00030 
00031 /* Print debugging traces if set to non-zero.  */
00032 static int debug_dec_thread = 0;
00033 
00034 /* Non-zero if the dec-thread layer is active.  */
00035 static int dec_thread_active = 0;
00036 
00037 /* The pthread_debug context.  */
00038 pthreadDebugContext_t debug_context;
00039 
00040 /* The dec-thread target_ops structure.  */
00041 static struct target_ops dec_thread_ops;
00042 
00043 /* Print a debug trace if DEBUG_DEC_THREAD is set (its value is adjusted
00044    by the user using "set debug dec-thread ...").  */
00045 
00046 static void
00047 debug (char *format, ...)
00048 {
00049   if (debug_dec_thread)
00050     {
00051       va_list args;
00052 
00053       va_start (args, format);
00054       printf_unfiltered ("DEC Threads: ");
00055       vprintf_unfiltered (format, args);
00056       printf_unfiltered ("\n");
00057       va_end (args);
00058     }
00059 }
00060 
00061 /* pthread debug callbacks.  */
00062 
00063 static int
00064 suspend_clbk (void *caller_context)
00065 {
00066   return ESUCCESS;
00067 }
00068 
00069 static int
00070 resume_clbk (void *caller_context)
00071 {
00072   return ESUCCESS;
00073 } 
00074 
00075 static int
00076 hold_clbk (void *caller_context, pthreadDebugKId_t kernel_tid)
00077 { 
00078   return ESUCCESS;
00079 }
00080 
00081 static int
00082 unhold_clbk (void *caller_context, pthreadDebugKId_t kernel_tid)
00083 {
00084   return ESUCCESS;
00085 }
00086 
00087 static int
00088 read_clbk (void *caller_context, void *address, void *buffer,
00089            unsigned long size)
00090 {
00091   int status = target_read_memory ((CORE_ADDR) address, buffer, size);
00092 
00093   if (status != 0)
00094     return EINVAL;
00095 
00096   return ESUCCESS;
00097 }
00098 
00099 static int
00100 write_clbk (void *caller_context, void *address, void *buffer,
00101             unsigned long size)
00102 {
00103   int status = target_write_memory ((CORE_ADDR) address, buffer, size);
00104   
00105   if (status != 0)
00106     return EINVAL;
00107 
00108   return ESUCCESS;
00109 }
00110 
00111 /* Get integer regs.  */
00112 
00113 static int
00114 get_reg_clbk(void *caller_context, pthreadDebugGetRegRtn_t regs,
00115              pthreadDebugKId_t kernel_tid)
00116 {
00117   debug ("get_reg_clbk");
00118 
00119   /* Not sure that we actually need to do anything in this callback.  */
00120   return ESUCCESS;
00121 }
00122 
00123 /* Set integer regs.  */
00124 
00125 static int
00126 set_reg_clbk(void *caller_context, const pthreadDebugRegs_t *regs,
00127              pthreadDebugKId_t kernel_tid)
00128 {
00129   debug ("set_reg_clbk");
00130 
00131   /* Not sure that we actually need to do anything in this callback.  */
00132   return ESUCCESS;
00133 }
00134 
00135 static int
00136 output_clbk (void *caller_context, char *line)
00137 {
00138   printf_filtered ("%s\n", line);
00139   return ESUCCESS;
00140 }
00141 
00142 static int
00143 error_clbk (void *caller_context, char *line)
00144 {
00145   fprintf_filtered (gdb_stderr, "%s\n", line);
00146   return ESUCCESS;
00147 }
00148 
00149 /* Get floating-point regs.  */
00150 
00151 static int
00152 get_fpreg_clbk (void *caller_context, pthreadDebugFregs_p fregs,
00153                 pthreadDebugKId_t kernel_tid)
00154 {
00155   debug ("get_fpreg_clbk");
00156 
00157   /* Not sure that we actually need to do anything in this callback.  */
00158   return ESUCCESS;
00159 }
00160 
00161 /* Set floating-point regs.  */
00162 
00163 static int
00164 set_fpreg_clbk (void *caller_context, const pthreadDebugFregs_t *fregs,
00165                 pthreadDebugKId_t kernel_tid)
00166 {
00167   debug ("set_fpreg_clbk");
00168 
00169   /* Not sure that we actually need to do anything in this callback.  */
00170   return ESUCCESS;
00171 }
00172 
00173 static void *
00174 malloc_clbk (void *caller_context, size_t size)
00175 {
00176   return xmalloc (size);
00177 }
00178 
00179 static void
00180 free_clbk (void *caller_context, void *address)
00181 {
00182   xfree (address);
00183 }
00184 
00185 static int
00186 kthdinfo_clbk (pthreadDebugClient_t caller_context,
00187                pthreadDebugKId_t kernel_tid,
00188                pthreadDebugKThreadInfo_p thread_info)
00189 {
00190   return ENOTSUP;
00191 }
00192 
00193 static int
00194 speckthd_clbk (pthreadDebugClient_t caller_context,
00195                pthreadDebugSpecialType_t type,
00196                pthreadDebugKId_t *kernel_tid)
00197 {
00198   return ENOTSUP;
00199 }
00200 
00201 static pthreadDebugCallbacks_t debug_callbacks =
00202 {
00203   PTHREAD_DEBUG_VERSION,
00204   (pthreadDebugGetMemRtn_t) read_clbk,
00205   (pthreadDebugSetMemRtn_t) write_clbk,
00206   suspend_clbk,
00207   resume_clbk,
00208   kthdinfo_clbk,
00209   hold_clbk,
00210   unhold_clbk,
00211   (pthreadDebugGetFregRtn_t) get_fpreg_clbk,
00212   (pthreadDebugSetFregRtn_t) set_fpreg_clbk,
00213   (pthreadDebugGetRegRtn_t) get_reg_clbk,
00214   (pthreadDebugSetRegRtn_t) set_reg_clbk,
00215   (pthreadDebugOutputRtn_t) output_clbk,
00216   (pthreadDebugOutputRtn_t) error_clbk,
00217   malloc_clbk,
00218   free_clbk,
00219   speckthd_clbk
00220 };
00221 
00222 /* Activate thread support if appropriate.  Do nothing if thread
00223    support is already active.  */
00224 
00225 static void
00226 enable_dec_thread (void)
00227 {
00228   struct minimal_symbol *msym;
00229   void* caller_context;
00230   int status;
00231 
00232   /* If already active, nothing more to do.  */
00233   if (dec_thread_active)
00234     return;
00235 
00236   msym = lookup_minimal_symbol ("__pthread_dbg_symtable", NULL, NULL);
00237   if (msym == NULL)
00238     {
00239       debug ("enable_dec_thread: No __pthread_dbg_symtable");
00240       return;
00241     }
00242 
00243   status = pthreadDebugContextInit (&caller_context, &debug_callbacks,
00244                                     (void *) SYMBOL_VALUE_ADDRESS (msym),
00245                                     &debug_context);
00246   if (status != ESUCCESS)
00247     {
00248       debug ("enable_dec_thread: pthreadDebugContextInit -> %d",
00249              status);
00250       return;
00251     }
00252 
00253   push_target (&dec_thread_ops);
00254   dec_thread_active = 1;
00255 
00256   debug ("enable_dec_thread: Thread support enabled.");
00257 }
00258 
00259 /* Deactivate thread support.  Do nothing if thread support is
00260    already inactive.  */
00261 
00262 static void
00263 disable_dec_thread (void)
00264 {
00265   if (!dec_thread_active)
00266     return;
00267 
00268   pthreadDebugContextDestroy (debug_context);
00269   unpush_target (&dec_thread_ops);
00270   dec_thread_active = 0;
00271 }
00272 
00273 /* A structure that contains a thread ID and is associated
00274    pthreadDebugThreadInfo_t data.  */
00275 
00276 struct dec_thread_info
00277 {
00278   pthreadDebugId_t thread;
00279   pthreadDebugThreadInfo_t info;
00280 };
00281 typedef struct dec_thread_info dec_thread_info_s;
00282 
00283 /* The list of user threads.  */
00284 
00285 DEF_VEC_O (dec_thread_info_s);
00286 VEC(dec_thread_info_s) *dec_thread_list;
00287 
00288 /* Release the memory used by the given VECP thread list pointer.
00289    Then set *VECP to NULL.  */
00290 
00291 static void
00292 free_dec_thread_info_vec (VEC(dec_thread_info_s) **vecp)
00293 {
00294   int i;
00295   struct dec_thread_info *item;
00296   VEC(dec_thread_info_s) *vec = *vecp;
00297 
00298   for (i = 0; VEC_iterate (dec_thread_info_s, vec, i, item); i++)
00299      xfree (item);
00300   VEC_free (dec_thread_info_s, vec);
00301   *vecp = NULL;
00302 }
00303 
00304 /* Return a thread's ptid given its associated INFO.  */
00305 
00306 static ptid_t
00307 ptid_build_from_info (struct dec_thread_info info)
00308 {
00309   int pid = ptid_get_pid (inferior_ptid);
00310 
00311   return ptid_build (pid, 0, (long) info.thread);
00312 }
00313 
00314 /* Return non-zero if PTID is still alive.
00315 
00316    Assumes that DEC_THREAD_LIST is up to date.  */
00317 static int
00318 dec_thread_ptid_is_alive (ptid_t ptid)
00319 {
00320   pthreadDebugId_t tid = ptid_get_tid (ptid);
00321   int i;
00322   struct dec_thread_info *info;
00323 
00324   if (tid == 0)
00325     /* This is the thread corresponding to the process.  This ptid
00326        is always alive until the program exits.  */
00327     return 1;
00328 
00329   /* Search whether an entry with the same tid exists in the dec-thread
00330      list of threads.  If it does, then the thread is still alive.
00331      No match found means that the thread must be dead, now.  */
00332   for (i = 0; VEC_iterate (dec_thread_info_s, dec_thread_list, i, info); i++)
00333     if (info->thread == tid)
00334       return 1;
00335   return 0;
00336 }
00337 
00338 /* Recompute the list of user threads and store the result in
00339    DEC_THREAD_LIST.  */
00340 
00341 static void
00342 update_dec_thread_list (void)
00343 {
00344   pthreadDebugId_t thread;
00345   pthreadDebugThreadInfo_t info;
00346   int res;
00347 
00348   free_dec_thread_info_vec (&dec_thread_list);
00349   res = pthreadDebugThdSeqInit (debug_context, &thread);
00350   while (res == ESUCCESS)
00351     {
00352 
00353       res = pthreadDebugThdGetInfo (debug_context, thread, &info);
00354       if (res != ESUCCESS)
00355         warning (_("unable to get thread info, ignoring thread %ld"),
00356                    thread);
00357       else if (info.kind == PTHREAD_DEBUG_THD_KIND_INITIAL
00358                || info.kind == PTHREAD_DEBUG_THD_KIND_NORMAL)
00359         {
00360           struct dec_thread_info *item = 
00361             xmalloc (sizeof (struct dec_thread_info));
00362 
00363           item->thread = thread;
00364           item->info = info;
00365           VEC_safe_push (dec_thread_info_s, dec_thread_list, item);
00366         }
00367       res = pthreadDebugThdSeqNext (debug_context, &thread);
00368     }
00369   pthreadDebugThdSeqDestroy (debug_context);
00370 }
00371 
00372 /* A callback to count the number of threads known to GDB.  */
00373 
00374 static int
00375 dec_thread_count_gdb_threads (struct thread_info *ignored, void *context)
00376 {
00377   int *count = (int *) context;
00378 
00379   *count = *count + 1;
00380   return 0;
00381 }
00382 
00383 /* A callback that saves the given thread INFO at the end of an
00384    array.  The end of the array is given in the CONTEXT and is
00385    incremented once the info has been added.  */
00386 
00387 static int
00388 dec_thread_add_gdb_thread (struct thread_info *info, void *context)
00389 {
00390   struct thread_info ***listp = (struct thread_info ***) context;
00391   
00392   **listp = info;
00393   *listp = *listp + 1;
00394   return 0;
00395 }
00396 
00397 /* Implement the find_new_thread target_ops method.  */
00398 
00399 static void
00400 dec_thread_find_new_threads (struct target_ops *ops)
00401 {
00402   int i;
00403   struct dec_thread_info *info;
00404 
00405   update_dec_thread_list ();
00406   for (i = 0; VEC_iterate (dec_thread_info_s, dec_thread_list, i, info); i++)
00407     {
00408       ptid_t ptid = ptid_build_from_info (*info);
00409 
00410       if (!in_thread_list (ptid))
00411         add_thread (ptid);
00412     }
00413 }
00414 
00415 /* Resynchronize the list of threads known by GDB with the actual
00416    list of threads reported by libpthread_debug.  */
00417 
00418 static void
00419 resync_thread_list (struct target_ops *ops)
00420 {
00421   int i;
00422   int num_gdb_threads = 0;
00423   struct thread_info **gdb_thread_list;
00424   struct thread_info **next_thread_info;
00425 
00426   /* Add new threads.  */
00427   dec_thread_find_new_threads (ops);
00428 
00429   /* Remove threads that no longer exist.  To help with the search,
00430      we build an array of GDB threads, and then iterate over this
00431      array.  */
00432 
00433   iterate_over_threads (dec_thread_count_gdb_threads,
00434                         (void *) &num_gdb_threads);
00435   gdb_thread_list = alloca (num_gdb_threads * sizeof (struct thread_info *));
00436   next_thread_info = gdb_thread_list;
00437   iterate_over_threads (dec_thread_add_gdb_thread, (void *) &next_thread_info);
00438 
00439   for (i = 0; i < num_gdb_threads; i++)
00440     if (!dec_thread_ptid_is_alive (gdb_thread_list[i]->ptid))
00441       delete_thread (gdb_thread_list[i]->ptid);
00442 }
00443 
00444 /* The "to_detach" method of the dec_thread_ops.  */
00445 
00446 static void
00447 dec_thread_detach (struct target_ops *ops, char *args, int from_tty)
00448 {   
00449   struct target_ops *beneath = find_target_beneath (ops);
00450 
00451   debug ("dec_thread_detach");
00452 
00453   disable_dec_thread ();
00454   beneath->to_detach (beneath, args, from_tty);
00455 }
00456 
00457 /* Return the ptid of the thread that is currently active.  */
00458 
00459 static ptid_t
00460 get_active_ptid (void)
00461 {
00462   int i;
00463   struct dec_thread_info *info;
00464 
00465   for (i = 0; VEC_iterate (dec_thread_info_s, dec_thread_list, i, info);
00466        i++)
00467     if (info->info.state == PTHREAD_DEBUG_STATE_RUNNING)
00468       return ptid_build_from_info (*info);
00469 
00470   /* No active thread found.  This can happen when the program
00471      has just exited.  */
00472   return null_ptid;
00473 }
00474 
00475 /* The "to_wait" method of the dec_thread_ops.  */
00476 
00477 static ptid_t
00478 dec_thread_wait (struct target_ops *ops,
00479                  ptid_t ptid, struct target_waitstatus *status, int options)
00480 {
00481   ptid_t active_ptid;
00482   struct target_ops *beneath = find_target_beneath (ops);
00483 
00484   debug ("dec_thread_wait");
00485 
00486   ptid = beneath->to_wait (beneath, ptid, status, options);
00487 
00488   /* The ptid returned by the target beneath us is the ptid of the process.
00489      We need to find which thread is currently active and return its ptid.  */
00490   resync_thread_list (ops);
00491   active_ptid = get_active_ptid ();
00492   if (ptid_equal (active_ptid, null_ptid))
00493     return ptid;
00494   return active_ptid;
00495 }
00496 
00497 /* Fetch the general purpose and floating point registers for the given
00498    thread TID, and store the result in GREGSET and FPREGSET.  Return
00499    zero if successful.  */
00500 
00501 static int
00502 dec_thread_get_regsets (pthreadDebugId_t tid, gdb_gregset_t *gregset,
00503                         gdb_fpregset_t *fpregset)
00504 {
00505   int res;
00506   pthreadDebugRegs_t regs;
00507   pthreadDebugFregs_t fregs;
00508 
00509   res = pthreadDebugThdGetReg (debug_context, tid, &regs);
00510   if (res != ESUCCESS)
00511     {
00512       debug ("dec_thread_get_regsets: pthreadDebugThdGetReg -> %d", res);
00513       return -1;
00514     }
00515   memcpy (gregset->regs, &regs, sizeof (regs));
00516 
00517   res = pthreadDebugThdGetFreg (debug_context, tid, &fregs);
00518   if (res != ESUCCESS)
00519     {
00520       debug ("dec_thread_get_regsets: pthreadDebugThdGetFreg -> %d", res);
00521       return -1;
00522     }
00523   memcpy (fpregset->regs, &fregs, sizeof (fregs));
00524 
00525   return 0;
00526 }
00527 
00528 /* The "to_fetch_registers" method of the dec_thread_ops.
00529 
00530    Because the dec-thread debug API doesn't allow us to fetch
00531    only one register, we simply ignore regno and fetch+supply all
00532    registers.  */
00533 
00534 static void
00535 dec_thread_fetch_registers (struct target_ops *ops,
00536                             struct regcache *regcache, int regno)
00537 {
00538   pthreadDebugId_t tid = ptid_get_tid (inferior_ptid);
00539   gregset_t gregset;
00540   fpregset_t fpregset;
00541   int res;
00542 
00543   debug ("dec_thread_fetch_registers (tid=%ld, regno=%d)", tid, regno);
00544 
00545 
00546   if (tid == 0 || ptid_equal (inferior_ptid, get_active_ptid ()))
00547     {
00548       struct target_ops *beneath = find_target_beneath (ops);
00549 
00550       beneath->to_fetch_registers (beneath, regcache, regno);
00551       return;
00552     }
00553 
00554   res = dec_thread_get_regsets (tid, &gregset, &fpregset);
00555   if (res != 0)
00556     return;
00557 
00558   supply_gregset (regcache, &gregset);
00559   supply_fpregset (regcache, &fpregset);
00560 }
00561 
00562 /* Store the registers given in GREGSET and FPREGSET into the associated
00563    general purpose and floating point registers of thread TID.  Return
00564    zero if successful.  */
00565 
00566 static int
00567 dec_thread_set_regsets (pthreadDebugId_t tid, gdb_gregset_t gregset,
00568                         gdb_fpregset_t fpregset)
00569 {
00570   int res;
00571   pthreadDebugRegs_t regs;
00572   pthreadDebugFregs_t fregs;
00573 
00574   memcpy (&regs, gregset.regs, sizeof (regs));
00575   res = pthreadDebugThdSetReg (debug_context, tid, &regs);
00576   if (res != ESUCCESS)
00577     {
00578       debug ("dec_thread_set_regsets: pthreadDebugThdSetReg -> %d", res);
00579       return -1;
00580     }
00581 
00582   memcpy (&fregs, fpregset.regs, sizeof (fregs));
00583   res = pthreadDebugThdSetFreg (debug_context, tid, &fregs);
00584   if (res != ESUCCESS)
00585     {
00586       debug ("dec_thread_set_regsets: pthreadDebugThdSetFreg -> %d", res);
00587       return -1;
00588     }
00589 
00590   return 0;
00591 }
00592 
00593 /* The "to_store_registers" method of the dec_thread_ops.
00594 
00595    Because the dec-thread debug API doesn't allow us to store
00596    just one register, we store all the registers.  */
00597 
00598 static void
00599 dec_thread_store_registers (struct target_ops *ops,
00600                             struct regcache *regcache, int regno)
00601 {
00602   pthreadDebugId_t tid = ptid_get_tid (inferior_ptid);
00603   gregset_t gregset;
00604   fpregset_t fpregset;
00605   int res;
00606 
00607   debug ("dec_thread_store_registers (tid=%ld, regno=%d)", tid, regno);
00608 
00609   if (tid == 0 || ptid_equal (inferior_ptid, get_active_ptid ()))
00610     {
00611       struct target_ops *beneath = find_target_beneath (ops);
00612 
00613       beneath->to_store_registers (beneath, regcache, regno);
00614       return;
00615     }
00616 
00617   /* FIXME: brobecker/2008-05-28: I wonder if we could simply check
00618      in which register set the register is and then only store the
00619      registers for that register set, instead of storing both register
00620      sets.  */
00621   fill_gregset (regcache, &gregset, -1);
00622   fill_fpregset (regcache, &fpregset, -1);
00623   
00624   res = dec_thread_set_regsets (tid, gregset, fpregset);
00625   if (res != 0)
00626     warning (_("failed to store registers."));
00627 }
00628 
00629 /* The "to_mourn_inferior" method of the dec_thread_ops.  */
00630 
00631 static void
00632 dec_thread_mourn_inferior (struct target_ops *ops)
00633 {
00634   struct target_ops *beneath = find_target_beneath (ops);
00635 
00636   debug ("dec_thread_mourn_inferior");
00637 
00638   disable_dec_thread ();
00639   beneath->to_mourn_inferior (beneath);
00640 }
00641 
00642 /* The "to_thread_alive" method of the dec_thread_ops.  */
00643 static int
00644 dec_thread_thread_alive (struct target_ops *ops, ptid_t ptid)
00645 {
00646   debug ("dec_thread_thread_alive (tid=%ld)", ptid_get_tid (ptid));
00647 
00648   /* The thread list maintained by GDB is up to date, since we update
00649      it everytime we stop.   So check this list.  */
00650   return in_thread_list (ptid);
00651 }
00652 
00653 /* The "to_pid_to_str" method of the dec_thread_ops.  */
00654 
00655 static char *
00656 dec_thread_pid_to_str (struct target_ops *ops, ptid_t ptid)
00657 {
00658   static char *ret = NULL;
00659 
00660   if (ptid_get_tid (ptid) == 0)
00661     {
00662       struct target_ops *beneath = find_target_beneath (ops);
00663 
00664       return beneath->to_pid_to_str (beneath, ptid);
00665     }
00666 
00667   /* Free previous return value; a new one will be allocated by
00668      xstrprintf().  */
00669   xfree (ret);
00670 
00671   ret = xstrprintf (_("Thread %ld"), ptid_get_tid (ptid));
00672   return ret;
00673 }
00674 
00675 /* A "new-objfile" observer.  Used to activate/deactivate dec-thread
00676    support.  */
00677 
00678 static void
00679 dec_thread_new_objfile_observer (struct objfile *objfile)
00680 {
00681   if (objfile != NULL)
00682      enable_dec_thread ();
00683   else
00684      disable_dec_thread ();
00685 }
00686 
00687 /* The "to_get_ada_task_ptid" method of the dec_thread_ops.  */
00688 
00689 static ptid_t
00690 dec_thread_get_ada_task_ptid (long lwp, long thread)
00691 {
00692   int i;
00693   struct dec_thread_info *info;
00694 
00695   debug ("dec_thread_get_ada_task_ptid (lwp=0x%lx, thread=0x%lx)",
00696          lwp, thread);
00697 
00698   for (i = 0; VEC_iterate (dec_thread_info_s, dec_thread_list, i, info);
00699        i++)
00700     if (info->info.teb == (pthread_t) thread)
00701       return ptid_build_from_info (*info);
00702   
00703   warning (_("Could not find thread id from THREAD = 0x%lx"), thread);
00704   return inferior_ptid;
00705 }
00706 
00707 static void
00708 init_dec_thread_ops (void)
00709 {
00710   dec_thread_ops.to_shortname          = "dec-threads";
00711   dec_thread_ops.to_longname           = _("DEC threads support");
00712   dec_thread_ops.to_doc                = _("DEC threads support");
00713   dec_thread_ops.to_detach             = dec_thread_detach;
00714   dec_thread_ops.to_wait               = dec_thread_wait;
00715   dec_thread_ops.to_fetch_registers    = dec_thread_fetch_registers;
00716   dec_thread_ops.to_store_registers    = dec_thread_store_registers;
00717   dec_thread_ops.to_mourn_inferior     = dec_thread_mourn_inferior;
00718   dec_thread_ops.to_thread_alive       = dec_thread_thread_alive;
00719   dec_thread_ops.to_find_new_threads   = dec_thread_find_new_threads;
00720   dec_thread_ops.to_pid_to_str         = dec_thread_pid_to_str;
00721   dec_thread_ops.to_stratum            = thread_stratum;
00722   dec_thread_ops.to_get_ada_task_ptid  = dec_thread_get_ada_task_ptid;
00723   dec_thread_ops.to_magic              = OPS_MAGIC;
00724 }
00725 
00726 void
00727 _initialize_dec_thread (void)
00728 {
00729   init_dec_thread_ops ();
00730   complete_target_initialization (&dec_thread_ops);
00731 
00732   observer_attach_new_objfile (dec_thread_new_objfile_observer);
00733 
00734   add_setshow_boolean_cmd ("dec-thread", class_maintenance, &debug_dec_thread,
00735                             _("Set debugging of DEC threads module."),
00736                             _("Show debugging of DEC threads module."),
00737                             _("Enables debugging output (used to debug GDB)."),
00738                             NULL, NULL,
00739                             &setdebuglist, &showdebuglist);
00740 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines