GDB (API)
|
00001 /* Native-dependent code for OpenBSD/powerpc. 00002 00003 Copyright (C) 2004-2013 Free Software Foundation, Inc. 00004 00005 This file is part of GDB. 00006 00007 This program is free software; you can redistribute it and/or modify 00008 it under the terms of the GNU General Public License as published by 00009 the Free Software Foundation; either version 3 of the License, or 00010 (at your option) any later version. 00011 00012 This program is distributed in the hope that it will be useful, 00013 but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00015 GNU General Public License for more details. 00016 00017 You should have received a copy of the GNU General Public License 00018 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 00019 00020 #include "defs.h" 00021 #include "gdbcore.h" 00022 #include "inferior.h" 00023 #include "regcache.h" 00024 00025 #include "gdb_assert.h" 00026 #include <stddef.h> 00027 #include <sys/types.h> 00028 #include <sys/ptrace.h> 00029 #include <sys/signal.h> 00030 #include <machine/frame.h> 00031 #include <machine/pcb.h> 00032 #include <machine/reg.h> 00033 00034 #include "ppc-tdep.h" 00035 #include "ppcobsd-tdep.h" 00036 #include "inf-ptrace.h" 00037 #include "bsd-kvm.h" 00038 00039 /* OpenBSD/powerpc didn't have PT_GETFPREGS/PT_SETFPREGS until release 00040 4.0. On older releases the floating-point registers are handled by 00041 PT_GETREGS/PT_SETREGS, but fpscr wasn't available.. */ 00042 00043 #ifdef PT_GETFPREGS 00044 00045 /* Returns true if PT_GETFPREGS fetches this register. */ 00046 00047 static int 00048 getfpregs_supplies (struct gdbarch *gdbarch, int regnum) 00049 { 00050 struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); 00051 00052 /* FIXME: jimb/2004-05-05: Some PPC variants don't have floating 00053 point registers. Traditionally, GDB's register set has still 00054 listed the floating point registers for such machines, so this 00055 code is harmless. However, the new E500 port actually omits the 00056 floating point registers entirely from the register set --- they 00057 don't even have register numbers assigned to them. 00058 00059 It's not clear to me how best to update this code, so this assert 00060 will alert the first person to encounter the NetBSD/E500 00061 combination to the problem. */ 00062 gdb_assert (ppc_floating_point_unit_p (gdbarch)); 00063 00064 return ((regnum >= tdep->ppc_fp0_regnum 00065 && regnum < tdep->ppc_fp0_regnum + ppc_num_fprs) 00066 || regnum == tdep->ppc_fpscr_regnum); 00067 } 00068 00069 #endif /* PT_GETFPREGS */ 00070 00071 /* Fetch register REGNUM from the inferior. If REGNUM is -1, do this 00072 for all registers. */ 00073 00074 static void 00075 ppcobsd_fetch_registers (struct target_ops *ops, 00076 struct regcache *regcache, int regnum) 00077 { 00078 struct reg regs; 00079 00080 if (ptrace (PT_GETREGS, ptid_get_pid (inferior_ptid), 00081 (PTRACE_TYPE_ARG3) ®s, 0) == -1) 00082 perror_with_name (_("Couldn't get registers")); 00083 00084 ppc_supply_gregset (&ppcobsd_gregset, regcache, -1, 00085 ®s, sizeof regs); 00086 #ifndef PT_GETFPREGS 00087 ppc_supply_fpregset (&ppcobsd_gregset, regcache, -1, 00088 ®s, sizeof regs); 00089 #endif 00090 00091 #ifdef PT_GETFPREGS 00092 if (regnum == -1 00093 || getfpregs_supplies (get_regcache_arch (regcache), regnum)) 00094 { 00095 struct fpreg fpregs; 00096 00097 if (ptrace (PT_GETFPREGS, ptid_get_pid (inferior_ptid), 00098 (PTRACE_TYPE_ARG3) &fpregs, 0) == -1) 00099 perror_with_name (_("Couldn't get floating point status")); 00100 00101 ppc_supply_fpregset (&ppcobsd_fpregset, regcache, -1, 00102 &fpregs, sizeof fpregs); 00103 } 00104 #endif 00105 } 00106 00107 /* Store register REGNUM back into the inferior. If REGNUM is -1, do 00108 this for all registers. */ 00109 00110 static void 00111 ppcobsd_store_registers (struct target_ops *ops, 00112 struct regcache *regcache, int regnum) 00113 { 00114 struct reg regs; 00115 00116 if (ptrace (PT_GETREGS, ptid_get_pid (inferior_ptid), 00117 (PTRACE_TYPE_ARG3) ®s, 0) == -1) 00118 perror_with_name (_("Couldn't get registers")); 00119 00120 ppc_collect_gregset (&ppcobsd_gregset, regcache, 00121 regnum, ®s, sizeof regs); 00122 #ifndef PT_GETFPREGS 00123 ppc_collect_fpregset (&ppcobsd_gregset, regcache, 00124 regnum, ®s, sizeof regs); 00125 #endif 00126 00127 if (ptrace (PT_SETREGS, ptid_get_pid (inferior_ptid), 00128 (PTRACE_TYPE_ARG3) ®s, 0) == -1) 00129 perror_with_name (_("Couldn't write registers")); 00130 00131 #ifdef PT_GETFPREGS 00132 if (regnum == -1 00133 || getfpregs_supplies (get_regcache_arch (regcache), regnum)) 00134 { 00135 struct fpreg fpregs; 00136 00137 if (ptrace (PT_GETFPREGS, ptid_get_pid (inferior_ptid), 00138 (PTRACE_TYPE_ARG3) &fpregs, 0) == -1) 00139 perror_with_name (_("Couldn't get floating point status")); 00140 00141 ppc_collect_fpregset (&ppcobsd_fpregset, regcache, 00142 regnum, &fpregs, sizeof fpregs); 00143 00144 if (ptrace (PT_SETFPREGS, ptid_get_pid (inferior_ptid), 00145 (PTRACE_TYPE_ARG3) &fpregs, 0) == -1) 00146 perror_with_name (_("Couldn't write floating point status")); 00147 } 00148 #endif 00149 } 00150 00151 00152 static int 00153 ppcobsd_supply_pcb (struct regcache *regcache, struct pcb *pcb) 00154 { 00155 struct gdbarch *gdbarch = get_regcache_arch (regcache); 00156 struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); 00157 struct switchframe sf; 00158 struct callframe cf; 00159 int i, regnum; 00160 00161 /* The following is true for OpenBSD 3.7: 00162 00163 The pcb contains %r1 (the stack pointer) at the point of the 00164 context switch in cpu_switch(). At that point we have a stack 00165 frame as described by `struct switchframe', and below that a call 00166 frame as described by `struct callframe'. From this information 00167 we reconstruct the register state as it would look when we are in 00168 cpu_switch(). */ 00169 00170 /* The stack pointer shouldn't be zero. */ 00171 if (pcb->pcb_sp == 0) 00172 return 0; 00173 00174 read_memory (pcb->pcb_sp, (gdb_byte *)&sf, sizeof sf); 00175 regcache_raw_supply (regcache, gdbarch_sp_regnum (gdbarch), &sf.sp); 00176 regcache_raw_supply (regcache, tdep->ppc_cr_regnum, &sf.cr); 00177 regcache_raw_supply (regcache, tdep->ppc_gp0_regnum + 2, &sf.fixreg2); 00178 for (i = 0, regnum = tdep->ppc_gp0_regnum + 13; i < 19; i++, regnum++) 00179 regcache_raw_supply (regcache, regnum, &sf.fixreg[i]); 00180 00181 read_memory (sf.sp, (gdb_byte *)&cf, sizeof cf); 00182 regcache_raw_supply (regcache, gdbarch_pc_regnum (gdbarch), &cf.lr); 00183 regcache_raw_supply (regcache, tdep->ppc_gp0_regnum + 30, &cf.r30); 00184 regcache_raw_supply (regcache, tdep->ppc_gp0_regnum + 31, &cf.r31); 00185 00186 return 1; 00187 } 00188 00189 00190 /* Provide a prototype to silence -Wmissing-prototypes. */ 00191 void _initialize_ppcobsd_nat (void); 00192 00193 void 00194 _initialize_ppcobsd_nat (void) 00195 { 00196 struct target_ops *t; 00197 00198 /* Add in local overrides. */ 00199 t = inf_ptrace_target (); 00200 t->to_fetch_registers = ppcobsd_fetch_registers; 00201 t->to_store_registers = ppcobsd_store_registers; 00202 add_target (t); 00203 00204 /* General-purpose registers. */ 00205 ppcobsd_reg_offsets.r0_offset = offsetof (struct reg, gpr); 00206 ppcobsd_reg_offsets.gpr_size = 4; 00207 ppcobsd_reg_offsets.xr_size = 4; 00208 ppcobsd_reg_offsets.pc_offset = offsetof (struct reg, pc); 00209 ppcobsd_reg_offsets.ps_offset = offsetof (struct reg, ps); 00210 ppcobsd_reg_offsets.cr_offset = offsetof (struct reg, cnd); 00211 ppcobsd_reg_offsets.lr_offset = offsetof (struct reg, lr); 00212 ppcobsd_reg_offsets.ctr_offset = offsetof (struct reg, cnt); 00213 ppcobsd_reg_offsets.xer_offset = offsetof (struct reg, xer); 00214 ppcobsd_reg_offsets.mq_offset = offsetof (struct reg, mq); 00215 00216 /* Floating-point registers. */ 00217 ppcobsd_reg_offsets.f0_offset = offsetof (struct reg, fpr); 00218 ppcobsd_reg_offsets.fpscr_offset = -1; 00219 #ifdef PT_GETFPREGS 00220 ppcobsd_fpreg_offsets.f0_offset = offsetof (struct fpreg, fpr); 00221 ppcobsd_fpreg_offsets.fpscr_offset = offsetof (struct fpreg, fpscr); 00222 ppcobsd_fpreg_offsets.fpscr_size = 4; 00223 #endif 00224 00225 /* AltiVec registers. */ 00226 ppcobsd_reg_offsets.vr0_offset = offsetof (struct vreg, vreg); 00227 ppcobsd_reg_offsets.vscr_offset = offsetof (struct vreg, vscr); 00228 ppcobsd_reg_offsets.vrsave_offset = offsetof (struct vreg, vrsave); 00229 00230 /* Support debugging kernel virtual memory images. */ 00231 bsd_kvm_add_target (ppcobsd_supply_pcb); 00232 }