This is the mail archive of the gdb-patches@sources.redhat.com mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

RFA: support libthread_db xregset functions


The comments in gregset.h have the story.

2003-11-24  Jim Blandy  <jimb@redhat.com>

	Allow targets to specify an extended register set, to be passed
	through libthread_db via its 'xregs' functions.
	* gregset.h (struct xregset_desc): New structure type.
	* gdbarch.sh (XREGSET_DESC): New gdbarch member.
	* gdbarch.c, gdbarch.h: Regenerated.
	* thread-db.c (td_thr_getxregsize_p, td_thr_getxregs_p,
	td_thr_setxregs_p): New variables.
	(thread_db_load): Initialize them.
	(warned_xregs_not_implemented): New variable.
	(thread_db_new_objfile): Clear it here.
	(thread_db_fetch_registers, thread_db_store_registers): Supply and
	fill the xregset, too, if the architecture says it has one, and
	libthread_db seems to be able to support it.
	* proc-service.c (ps_lgetxregsize, ps_lgetxregs, ps_lsetxregs):
	Fill in real implementations of these functions.
	
Index: gdb/gregset.h
===================================================================
RCS file: /cvs/src/src/gdb/gregset.h,v
retrieving revision 1.7
diff -c -r1.7 gregset.h
*** gdb/gregset.h	8 May 2002 23:29:11 -0000	1.7
--- gdb/gregset.h	24 Mar 2004 19:06:54 -0000
***************
*** 66,69 ****
--- 66,108 ----
  extern void fill_fpxregset (gdb_fpxregset_t *fpxregs, int regno);
  #endif
  
+ 
+ /* The libthread_db interface passes registers in and out using the same
+    structures that appear in core files: gregset_t and fpregset_t.
+    Whether reading or writing:
+    - GDB first moves data out of the regcache into a struct (using
+      fill_gregset or fill_fpregset),
+    - crosses the thread_db boundary (for writing, calls
+      td_thr_setregs; for reading, returns from td_thr_getregs), and
+    - moves the data from the struct back into the regcache (using
+      supply_gregset or supply_fpregset).
+ 
+    Now, some platforms define even more register sets; for example,
+    members of the PowerPC family supporting the Signal Processing
+    Extension ("SPE") have 'struct speregset'.  These need to be passed
+    back and forth across the thread_db boundary.  So we need fill_ and
+    supply_ functions for them, too.  And we need to know the size of
+    the structure, so we can clear it at the appropriate times.
+ 
+    An architecture that has such a register set should set its
+    XREGSET_FUNCS gdbarch member to a pointer to one of these
+    structures, which provides the necessary info for working with an
+    extended register set.  */
+ struct xregset_desc
+ {
+   /* The name of the register set this set of functions describes ---
+      for debugging, and for error messages.  */
+   const char *name;
+ 
+   /* The size of the register set.  */
+   size_t size;
+ 
+   /* Copy the values of all registers in XREGS into the regcache.  */
+   void (*supply) (void *xregs);
+ 
+   /* Copy the value of register REGNO from the regcache into XREGS.
+      If REGNO is -1, copy all the registers XREGS can hold.  */
+   void (*fill) (void *xregs, int regno);
+ };
+ 
  #endif
Index: gdb/gdbarch.sh
===================================================================
RCS file: /cvs/src/src/gdb/gdbarch.sh,v
retrieving revision 1.305
diff -c -r1.305 gdbarch.sh
*** gdb/gdbarch.sh	23 Mar 2004 15:16:41 -0000	1.305
--- gdb/gdbarch.sh	24 Mar 2004 19:06:54 -0000
***************
*** 761,766 ****
--- 761,768 ----
  # Fetch the pointer to the ith function argument.
  F::FETCH_POINTER_ARGUMENT:CORE_ADDR:fetch_pointer_argument:struct frame_info *frame, int argi, struct type *type:frame, argi, type
  
+ # See the definition of 'struct xregset_desc' in gregset.h.
+ v::XREGSET_DESC:struct xregset_desc *:xregset_desc:::::0::0:%p:current_gdbarch->xregset_desc
  # Return the appropriate register set for a core file section with
  # name SECT_NAME and size SECT_SIZE.
  M:::const struct regset *:regset_from_core_section:const char *sect_name, size_t sect_size:sect_name, sect_size
Index: gdb/gdbarch.c
===================================================================
RCS file: /cvs/src/src/gdb/gdbarch.c,v
retrieving revision 1.279
diff -c -r1.279 gdbarch.c
*** gdb/gdbarch.c	23 Mar 2004 15:16:39 -0000	1.279
--- gdb/gdbarch.c	24 Mar 2004 19:06:51 -0000
***************
*** 260,265 ****
--- 260,266 ----
    gdbarch_address_class_name_to_type_flags_ftype *address_class_name_to_type_flags;
    gdbarch_register_reggroup_p_ftype *register_reggroup_p;
    gdbarch_fetch_pointer_argument_ftype *fetch_pointer_argument;
+   struct xregset_desc * xregset_desc;
    gdbarch_regset_from_core_section_ftype *regset_from_core_section;
  };
  
***************
*** 427,432 ****
--- 428,434 ----
    0,  /* address_class_name_to_type_flags */
    default_register_reggroup_p,  /* register_reggroup_p */
    0,  /* fetch_pointer_argument */
+   0,  /* xregset_desc */
    0,  /* regset_from_core_section */
    /* startup_gdbarch() */
  };
***************
*** 735,740 ****
--- 737,743 ----
    /* Skip verify of address_class_name_to_type_flags, has predicate */
    /* Skip verify of register_reggroup_p, invalid_p == 0 */
    /* Skip verify of fetch_pointer_argument, has predicate */
+   /* Skip verify of xregset_desc, invalid_p == 0 */
    /* Skip verify of regset_from_core_section, has predicate */
    buf = ui_file_xstrdup (log, &dummy);
    make_cleanup (xfree, buf);
***************
*** 2446,2451 ****
--- 2449,2462 ----
                        (long) current_gdbarch->value_to_register
                        /*VALUE_TO_REGISTER ()*/);
  #endif
+ #ifdef XREGSET_DESC
+   fprintf_unfiltered (file,
+                       "gdbarch_dump: XREGSET_DESC # %s\n",
+                       XSTRING (XREGSET_DESC));
+   fprintf_unfiltered (file,
+                       "gdbarch_dump: XREGSET_DESC = %p\n",
+                       current_gdbarch->xregset_desc);
+ #endif
    if (current_gdbarch->dump_tdep != NULL)
      current_gdbarch->dump_tdep (current_gdbarch, file);
  }
***************
*** 5365,5370 ****
--- 5376,5398 ----
                                      gdbarch_fetch_pointer_argument_ftype fetch_pointer_argument)
  {
    gdbarch->fetch_pointer_argument = fetch_pointer_argument;
+ }
+ 
+ struct xregset_desc *
+ gdbarch_xregset_desc (struct gdbarch *gdbarch)
+ {
+   gdb_assert (gdbarch != NULL);
+   /* Skip verify of xregset_desc, invalid_p == 0 */
+   if (gdbarch_debug >= 2)
+     fprintf_unfiltered (gdb_stdlog, "gdbarch_xregset_desc called\n");
+   return gdbarch->xregset_desc;
+ }
+ 
+ void
+ set_gdbarch_xregset_desc (struct gdbarch *gdbarch,
+                           struct xregset_desc * xregset_desc)
+ {
+   gdbarch->xregset_desc = xregset_desc;
  }
  
  int
Index: gdb/gdbarch.h
===================================================================
RCS file: /cvs/src/src/gdb/gdbarch.h,v
retrieving revision 1.241
diff -c -r1.241 gdbarch.h
*** gdb/gdbarch.h	23 Mar 2004 15:16:40 -0000	1.241
--- gdb/gdbarch.h	24 Mar 2004 19:06:52 -0000
***************
*** 2332,2337 ****
--- 2332,2348 ----
  #define FETCH_POINTER_ARGUMENT(frame, argi, type) (gdbarch_fetch_pointer_argument (current_gdbarch, frame, argi, type))
  #endif
  
+ /* See the definition of 'struct xregset_desc' in gregset.h. */
+ 
+ extern struct xregset_desc * gdbarch_xregset_desc (struct gdbarch *gdbarch);
+ extern void set_gdbarch_xregset_desc (struct gdbarch *gdbarch, struct xregset_desc * xregset_desc);
+ #if (GDB_MULTI_ARCH > GDB_MULTI_ARCH_PARTIAL) && defined (XREGSET_DESC)
+ #error "Non multi-arch definition of XREGSET_DESC"
+ #endif
+ #if !defined (XREGSET_DESC)
+ #define XREGSET_DESC (gdbarch_xregset_desc (current_gdbarch))
+ #endif
+ 
  /* Return the appropriate register set for a core file section with
     name SECT_NAME and size SECT_SIZE. */
  
Index: gdb/proc-service.c
===================================================================
RCS file: /cvs/src/src/gdb/proc-service.c,v
retrieving revision 1.7
diff -c -r1.7 proc-service.c
*** gdb/proc-service.c	24 Feb 2002 22:31:19 -0000	1.7
--- gdb/proc-service.c	24 Mar 2004 19:06:55 -0000
***************
*** 131,147 ****
  ps_err_e
  ps_lgetxregsize (gdb_ps_prochandle_t ph, lwpid_t lwpid, int *xregsize)
  {
!   /* FIXME: Not supported yet.  */
    return PS_OK;
  }
  
  /* Get the extra state registers of LWP LWPID within the target
     process PH and store them in XREGSET.  */
- 
  ps_err_e
  ps_lgetxregs (gdb_ps_prochandle_t ph, lwpid_t lwpid, caddr_t xregset)
  {
!   /* FIXME: Not supported yet.  */
    return PS_OK;
  }
  
--- 131,163 ----
  ps_err_e
  ps_lgetxregsize (gdb_ps_prochandle_t ph, lwpid_t lwpid, int *xregsize)
  {
!   if (! XREGSET_DESC)
!     /* This architecture has no extra registers.  */
!     return PS_ERR;
! 
!   *xregsize = XREGSET_DESC->size;
    return PS_OK;
  }
  
+ 
  /* Get the extra state registers of LWP LWPID within the target
     process PH and store them in XREGSET.  */
  ps_err_e
  ps_lgetxregs (gdb_ps_prochandle_t ph, lwpid_t lwpid, caddr_t xregset)
  {
!   struct cleanup *old_chain = save_inferior_ptid ();
!   struct xregset_desc *desc = XREGSET_DESC;
! 
!   if (! desc)
!     /* This target has no extra registers.  */
!     return PS_OK;
! 
!   inferior_ptid = BUILD_LWP (lwpid, ph->pid);
! 
!   target_fetch_registers (-1);
!   desc->fill ((void *) xregset, -1);
! 
!   do_cleanups (old_chain);
    return PS_OK;
  }
  
***************
*** 151,157 ****
  ps_err_e
  ps_lsetxregs (gdb_ps_prochandle_t ph, lwpid_t lwpid, caddr_t xregset)
  {
!   /* FIXME: Not supported yet.  */
    return PS_OK;
  }
  
--- 167,186 ----
  ps_err_e
  ps_lsetxregs (gdb_ps_prochandle_t ph, lwpid_t lwpid, caddr_t xregset)
  {
!   struct cleanup *old_chain = save_inferior_ptid ();
!   struct xregset_desc *desc = XREGSET_DESC;
! 
!   if (! desc)
!     /* This architecture has no extended registers.  */
!     return PS_OK;
! 
!   inferior_ptid = BUILD_LWP (lwpid, ph->pid);
! 
!   /* FIXME: We should really make supply_gregset const-correct.  */
!   desc->supply ((void *) xregset);
!   target_store_registers (-1);
! 
!   do_cleanups (old_chain);
    return PS_OK;
  }
  
Index: gdb/thread-db.c
===================================================================
RCS file: /cvs/src/src/gdb/thread-db.c,v
retrieving revision 1.37
diff -c -r1.37 thread-db.c
*** gdb/thread-db.c	29 Feb 2004 02:39:47 -0000	1.37
--- gdb/thread-db.c	24 Mar 2004 19:06:56 -0000
***************
*** 101,114 ****
--- 101,120 ----
  static td_err_e (*td_thr_validate_p) (const td_thrhandle_t *th);
  static td_err_e (*td_thr_get_info_p) (const td_thrhandle_t *th,
  				      td_thrinfo_t *infop);
+ static td_err_e (*td_thr_getxregsize_p) (const td_thrhandle_t *__th,
+                                          int *__sizep);
  static td_err_e (*td_thr_getfpregs_p) (const td_thrhandle_t *th,
  				       gdb_prfpregset_t *regset);
  static td_err_e (*td_thr_getgregs_p) (const td_thrhandle_t *th,
  				      prgregset_t gregs);
+ static td_err_e (*td_thr_getxregs_p) (const td_thrhandle_t *__th,
+                                       void *__xregs);
  static td_err_e (*td_thr_setfpregs_p) (const td_thrhandle_t *th,
  				       const gdb_prfpregset_t *fpregs);
  static td_err_e (*td_thr_setgregs_p) (const td_thrhandle_t *th,
  				      prgregset_t gregs);
+ static td_err_e (*td_thr_setxregs_p) (const td_thrhandle_t *__th,
+                                       const void *__addr);
  static td_err_e (*td_thr_event_enable_p) (const td_thrhandle_t *th,
  					  int event);
  
***************
*** 126,131 ****
--- 132,145 ----
  /* Location of the thread death event breakpoint.  */
  static CORE_ADDR td_death_bp_addr;
  
+ /* On some architectures, there are additional regs beyond the gregset
+    and fpregset.  The libthread_db interface has functions to access
+    these, but on some versions of libthread_db they are not
+    implemented.  We want to warn the user about this, but not treat it
+    as a fatal error, since you can still access the other
+    registers.  */
+ static int warned_xregs_not_implemented;
+ 
  /* Prototypes for local functions.  */
  static void thread_db_find_new_threads (void);
  static void attach_thread (ptid_t ptid, const td_thrhandle_t *th_p,
***************
*** 431,436 ****
--- 445,454 ----
    if (td_thr_get_info_p == NULL)
      return 0;
  
+   td_thr_getxregsize_p = verbose_dlsym (handle, "td_thr_getxregsize");
+   if (td_thr_getxregsize_p == NULL)
+     return 0;
+ 
    td_thr_getfpregs_p = verbose_dlsym (handle, "td_thr_getfpregs");
    if (td_thr_getfpregs_p == NULL)
      return 0;
***************
*** 439,444 ****
--- 457,466 ----
    if (td_thr_getgregs_p == NULL)
      return 0;
  
+   td_thr_getxregs_p = verbose_dlsym (handle, "td_thr_getxregs");
+   if (td_thr_getxregs_p == NULL)
+     return 0;
+ 
    td_thr_setfpregs_p = verbose_dlsym (handle, "td_thr_setfpregs");
    if (td_thr_setfpregs_p == NULL)
      return 0;
***************
*** 447,452 ****
--- 469,478 ----
    if (td_thr_setgregs_p == NULL)
      return 0;
  
+   td_thr_setxregs_p = verbose_dlsym (handle, "td_thr_setxregs");
+   if (td_thr_setxregs_p == NULL)
+     return 0;
+ 
    /* Initialize the library.  */
    err = td_init_p ();
    if (err != TD_OK)
***************
*** 684,689 ****
--- 710,720 ----
        break;
      }
  
+   /* If the gdbarch says we have an extended register set, but we are
+      unable to access them via libthread_db, we want to issue one
+      warning each time we active libthread_db.  */
+   warned_xregs_not_implemented = 0;
+ 
  quit:
    if (target_new_objfile_chain)
      target_new_objfile_chain (objfile);
***************
*** 933,938 ****
--- 964,972 ----
    struct thread_info *thread_info;
    prgregset_t gregset;
    gdb_prfpregset_t fpregset;
+   void *xregset;
+   int fetched_xregs = 0;
+   struct xregset_desc *xregset_desc = XREGSET_DESC;
    td_err_e err;
  
    if (!is_thread (inferior_ptid))
***************
*** 945,950 ****
--- 979,989 ----
    thread_info = find_thread_pid (inferior_ptid);
    thread_db_map_id2thr (thread_info, 1);
  
+   if (xregset_desc)
+     xregset = alloca (xregset_desc->size);
+   else
+     xregset = 0;
+ 
    err = td_thr_getgregs_p (&thread_info->private->th, gregset);
    if (err != TD_OK)
      error ("Cannot fetch general-purpose registers for thread %ld: %s",
***************
*** 955,965 ****
--- 994,1033 ----
      error ("Cannot get floating-point registers for thread %ld: %s",
  	   (long) GET_THREAD (inferior_ptid), thread_db_err_str (err));
  
+   if (xregset_desc)
+     {
+       err = td_thr_getxregs_p (&thread_info->private->th, xregset);
+       switch (err)
+         {
+         case TD_OK:
+           fetched_xregs = 1;
+           break;
+ 
+         case TD_NOXREGS:
+           if (! warned_xregs_not_implemented)
+             {
+               warning ("thread debugging library is too old to access"
+                        " %s registers.",
+                        xregset_desc->name);
+               warned_xregs_not_implemented = 1;
+             }
+           break;
+ 
+         default:
+           error ("Cannot get %s registers for thread %ld: %s",
+                  xregset_desc->name,
+                  (long) GET_THREAD (inferior_ptid), thread_db_err_str (err));
+         }
+     }
+ 
    /* Note that we must call supply_gregset after calling the thread_db
       routines because the thread_db routines call ps_lgetgregs and
       friends which clobber GDB's register cache.  */
    supply_gregset ((gdb_gregset_t *) gregset);
    supply_fpregset (&fpregset);
+ 
+   if (fetched_xregs)
+     xregset_desc->supply (xregset);
  }
  
  static void
***************
*** 967,972 ****
--- 1035,1042 ----
  {
    prgregset_t gregset;
    gdb_prfpregset_t fpregset;
+   struct xregset_desc *xregset_desc = XREGSET_DESC;
+   void *xregset;
    td_err_e err;
    struct thread_info *thread_info;
  
***************
*** 991,996 ****
--- 1061,1073 ----
  
    fill_gregset ((gdb_gregset_t *) gregset, -1);
    fill_fpregset (&fpregset, -1);
+   if (xregset_desc)
+     {
+       xregset = alloca (xregset_desc->size);
+       xregset_desc->fill (xregset, -1);
+     }
+   else
+     xregset = 0;
  
    err = td_thr_setgregs_p (&thread_info->private->th, gregset);
    if (err != TD_OK)
***************
*** 1000,1005 ****
--- 1077,1100 ----
    if (err != TD_OK)
      error ("Cannot store floating-point registers  for thread %ld: %s",
  	   (long) GET_THREAD (inferior_ptid), thread_db_err_str (err));
+   if (xregset_desc)
+     {
+       err = td_thr_setxregs_p (&thread_info->private->th, xregset);
+       if (err == TD_NOXREGS)
+         {
+           if (! warned_xregs_not_implemented)
+             {
+               warning ("thread debugging library is too old to access"
+                        " %s registers.",
+                        xregset_desc->name);
+               warned_xregs_not_implemented = 1;
+             }
+         }
+       else if (err != TD_OK)
+         error ("Cannot store %s registers  for thread %ld: %s",
+                xregset_desc->name,
+                (long) GET_THREAD (inferior_ptid), thread_db_err_str (err));
+     }
  }
  
  static void


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]