Home | History | Annotate | Line # | Download | only in gdb
      1 /* Native-dependent code for modern i386 BSD's.
      2 
      3    Copyright (C) 2000-2024 Free Software Foundation, Inc.
      4 
      5    This file is part of GDB.
      6 
      7    This program is free software; you can redistribute it and/or modify
      8    it under the terms of the GNU General Public License as published by
      9    the Free Software Foundation; either version 3 of the License, or
     10    (at your option) any later version.
     11 
     12    This program is distributed in the hope that it will be useful,
     13    but WITHOUT ANY WARRANTY; without even the implied warranty of
     14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15    GNU General Public License for more details.
     16 
     17    You should have received a copy of the GNU General Public License
     18    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
     19 
     20 #include "inferior.h"
     21 #include "regcache.h"
     22 
     23 #include <signal.h>
     24 #include <sys/types.h>
     25 #include <sys/ptrace.h>
     26 #include <machine/reg.h>
     27 #include <machine/frame.h>
     28 
     29 #include "i386-tdep.h"
     30 #include "i387-tdep.h"
     31 #include "x86-bsd-nat.h"
     32 #include "i386-bsd-nat.h"
     33 #include "inf-ptrace.h"
     34 
     35 
     37 static PTRACE_TYPE_RET
     38 gdb_ptrace (PTRACE_TYPE_ARG1 request, ptid_t ptid, PTRACE_TYPE_ARG3 addr,
     39 	    PTRACE_TYPE_ARG4 data)
     40 {
     41 #ifdef __NetBSD__
     42   gdb_assert (data == 0);
     43   /* Support for NetBSD threads: unlike other ptrace implementations in this
     44      file, NetBSD requires that we pass both the pid and lwp.  */
     45   return ptrace (request, ptid.pid (), addr, ptid.lwp ());
     46 #else
     47   pid_t pid = get_ptrace_pid (ptid);
     48   return ptrace (request, pid, addr, data);
     49 #endif
     50 }
     51 
     52 /* In older BSD versions we cannot get at some of the segment
     53    registers.  FreeBSD for example didn't support the %fs and %gs
     54    registers until the 3.0 release.  We have autoconf checks for their
     55    presence, and deal gracefully with their absence.  */
     56 
     57 /* Offset in `struct reg' where MEMBER is stored.  */
     58 #define REG_OFFSET(member) offsetof (struct reg, member)
     59 
     60 /* At i386bsd_reg_offset[REGNUM] you'll find the offset in `struct
     61    reg' where the GDB register REGNUM is stored.  Unsupported
     62    registers are marked with `-1'.  */
     63 static int i386bsd_r_reg_offset[] =
     64 {
     65   REG_OFFSET (r_eax),
     66   REG_OFFSET (r_ecx),
     67   REG_OFFSET (r_edx),
     68   REG_OFFSET (r_ebx),
     69   REG_OFFSET (r_esp),
     70   REG_OFFSET (r_ebp),
     71   REG_OFFSET (r_esi),
     72   REG_OFFSET (r_edi),
     73   REG_OFFSET (r_eip),
     74   REG_OFFSET (r_eflags),
     75   REG_OFFSET (r_cs),
     76   REG_OFFSET (r_ss),
     77   REG_OFFSET (r_ds),
     78   REG_OFFSET (r_es),
     79 #ifdef HAVE_STRUCT_REG_R_FS
     80   REG_OFFSET (r_fs),
     81 #else
     82   -1,
     83 #endif
     84 #ifdef HAVE_STRUCT_REG_R_GS
     85   REG_OFFSET (r_gs)
     86 #else
     87   -1
     88 #endif
     89 };
     90 
     91 /* Macro to determine if a register is fetched with PT_GETREGS.  */
     92 #define GETREGS_SUPPLIES(regnum) \
     93   ((0 <= (regnum) && (regnum) <= 15))
     94 
     95 /* Set to 1 if the kernel supports PT_GETXMMREGS.  Initialized to -1
     96    so that we try PT_GETXMMREGS the first time around.  */
     97 static int have_ptrace_xmmregs = -1;
     98 
     99 
    101 /* Supply the general-purpose registers in GREGS, to REGCACHE.  */
    102 
    103 static void
    104 i386bsd_supply_gregset (struct regcache *regcache, const void *gregs)
    105 {
    106   const char *regs = (const char *) gregs;
    107   int regnum;
    108 
    109   for (regnum = 0; regnum < ARRAY_SIZE (i386bsd_r_reg_offset); regnum++)
    110     {
    111       int offset = i386bsd_r_reg_offset[regnum];
    112 
    113       if (offset != -1)
    114 	regcache->raw_supply (regnum, regs + offset);
    115     }
    116 }
    117 
    118 /* Collect register REGNUM from REGCACHE and store its contents in
    119    GREGS.  If REGNUM is -1, collect and store all appropriate
    120    registers.  */
    121 
    122 static void
    123 i386bsd_collect_gregset (const struct regcache *regcache,
    124 			 void *gregs, int regnum)
    125 {
    126   char *regs = (char *) gregs;
    127   int i;
    128 
    129   for (i = 0; i < ARRAY_SIZE (i386bsd_r_reg_offset); i++)
    130     {
    131       if (regnum == -1 || regnum == i)
    132 	{
    133 	  int offset = i386bsd_r_reg_offset[i];
    134 
    135 	  if (offset != -1)
    136 	    regcache->raw_collect (i, regs + offset);
    137 	}
    138     }
    139 }
    140 
    141 /* Fetch register REGNUM from the inferior.  If REGNUM is -1, do this
    142    for all registers (including the floating point registers).  */
    143 
    144 void
    145 i386bsd_fetch_inferior_registers (struct regcache *regcache, int regnum)
    146 {
    147   ptid_t ptid = regcache->ptid ();
    148 
    149   if (regnum == -1 || GETREGS_SUPPLIES (regnum))
    150     {
    151       struct reg regs;
    152 
    153       if (gdb_ptrace (PT_GETREGS, ptid, (PTRACE_TYPE_ARG3) &regs, 0) == -1)
    154 	perror_with_name (_("Couldn't get registers"));
    155 
    156       i386bsd_supply_gregset (regcache, &regs);
    157       if (regnum != -1)
    158 	return;
    159     }
    160 
    161   if (regnum == -1 || regnum >= I386_ST0_REGNUM)
    162     {
    163       struct fpreg fpregs;
    164       char xmmregs[512];
    165 
    166       if (have_ptrace_xmmregs != 0
    167 	  && gdb_ptrace(PT_GETXMMREGS, ptid,
    168 			(PTRACE_TYPE_ARG3) xmmregs, 0) == 0)
    169 	{
    170 	  have_ptrace_xmmregs = 1;
    171 	  i387_supply_fxsave (regcache, -1, xmmregs);
    172 	}
    173       else
    174 	{
    175 	  have_ptrace_xmmregs = 0;
    176 	  if (gdb_ptrace (PT_GETFPREGS, ptid,
    177 			  (PTRACE_TYPE_ARG3) &fpregs, 0) == -1)
    178 	    perror_with_name (_("Couldn't get floating point status"));
    179 
    180 	  i387_supply_fsave (regcache, -1, &fpregs);
    181 	}
    182     }
    183 }
    184 
    185 /* Store register REGNUM back into the inferior.  If REGNUM is -1, do
    186    this for all registers (including the floating point registers).  */
    187 
    188 void
    189 i386bsd_store_inferior_registers (struct regcache *regcache, int regnum)
    190 {
    191   ptid_t ptid = regcache->ptid ();
    192 
    193   if (regnum == -1 || GETREGS_SUPPLIES (regnum))
    194     {
    195       struct reg regs;
    196 
    197       if (gdb_ptrace (PT_GETREGS, ptid, (PTRACE_TYPE_ARG3) &regs, 0) == -1)
    198 	perror_with_name (_("Couldn't get registers"));
    199 
    200       i386bsd_collect_gregset (regcache, &regs, regnum);
    201 
    202       if (gdb_ptrace (PT_SETREGS, ptid, (PTRACE_TYPE_ARG3) &regs, 0) == -1)
    203 	perror_with_name (_("Couldn't write registers"));
    204 
    205       if (regnum != -1)
    206 	return;
    207     }
    208 
    209   if (regnum == -1 || regnum >= I386_ST0_REGNUM)
    210     {
    211       struct fpreg fpregs;
    212       char xmmregs[512];
    213 
    214       if (have_ptrace_xmmregs != 0
    215 	  && gdb_ptrace(PT_GETXMMREGS, ptid,
    216 			(PTRACE_TYPE_ARG3) xmmregs, 0) == 0)
    217 	{
    218 	  have_ptrace_xmmregs = 1;
    219 
    220 	  i387_collect_fxsave (regcache, regnum, xmmregs);
    221 
    222 	  if (gdb_ptrace (PT_SETXMMREGS, ptid,
    223 			  (PTRACE_TYPE_ARG3) xmmregs, 0) == -1)
    224 	    perror_with_name (_("Couldn't write XMM registers"));
    225 	}
    226       else
    227 	{
    228 	  have_ptrace_xmmregs = 0;
    229 	  if (gdb_ptrace (PT_GETFPREGS, ptid,
    230 			  (PTRACE_TYPE_ARG3) &fpregs, 0) == -1)
    231 	    perror_with_name (_("Couldn't get floating point status"));
    232 
    233 	  i387_collect_fsave (regcache, regnum, &fpregs);
    234 
    235 	  if (gdb_ptrace (PT_SETFPREGS, ptid,
    236 			  (PTRACE_TYPE_ARG3) &fpregs, 0) == -1)
    237 	    perror_with_name (_("Couldn't write floating point status"));
    238 	}
    239     }
    240 }
    241 
    242 void _initialize_i386bsd_nat ();
    243 void
    244 _initialize_i386bsd_nat ()
    245 {
    246   /* To support the recognition of signal handlers, i386-bsd-tdep.c
    247      hardcodes some constants.  Inclusion of this file means that we
    248      are compiling a native debugger, which means that we can use the
    249      system header files and sysctl(3) to get at the relevant
    250      information.  */
    251 
    252 #if defined (OpenBSD)
    253 #define SC_REG_OFFSET i386obsd_sc_reg_offset
    254 #endif
    255 
    256 #ifdef SC_REG_OFFSET
    257 
    258   /* We only check the program counter, stack pointer and frame
    259      pointer since these members of `struct sigcontext' are essential
    260      for providing backtraces.  More checks could be added, but would
    261      involve adding configure checks for the appropriate structure
    262      members, since older BSD's don't provide all of them.  */
    263 
    264 #define SC_PC_OFFSET SC_REG_OFFSET[I386_EIP_REGNUM]
    265 #define SC_SP_OFFSET SC_REG_OFFSET[I386_ESP_REGNUM]
    266 #define SC_FP_OFFSET SC_REG_OFFSET[I386_EBP_REGNUM]
    267 
    268   /* Override the default value for the offset of the program counter
    269      in the sigcontext structure.  */
    270   int offset = offsetof (struct sigcontext, sc_pc);
    271 
    272   if (SC_PC_OFFSET != offset)
    273     {
    274       warning (_("\
    275 offsetof (struct sigcontext, sc_pc) yields %d instead of %d.\n\
    276 Please report this to <bug-gdb (at) gnu.org>."),
    277 	       offset, SC_PC_OFFSET);
    278     }
    279 
    280   SC_PC_OFFSET = offset;
    281 
    282   /* Likewise for the stack pointer.  */
    283   offset = offsetof (struct sigcontext, sc_sp);
    284 
    285   if (SC_SP_OFFSET != offset)
    286     {
    287       warning (_("\
    288 offsetof (struct sigcontext, sc_sp) yields %d instead of %d.\n\
    289 Please report this to <bug-gdb (at) gnu.org>."),
    290 	       offset, SC_SP_OFFSET);
    291     }
    292 
    293   SC_SP_OFFSET = offset;
    294 
    295   /* And the frame pointer.  */
    296   offset = offsetof (struct sigcontext, sc_fp);
    297 
    298   if (SC_FP_OFFSET != offset)
    299     {
    300       warning (_("\
    301 offsetof (struct sigcontext, sc_fp) yields %d instead of %d.\n\
    302 Please report this to <bug-gdb (at) gnu.org>."),
    303 	       offset, SC_FP_OFFSET);
    304     }
    305 
    306   SC_FP_OFFSET = offset;
    307 
    308 #endif /* SC_REG_OFFSET */
    309 }
    310