1130803Smarcel/* S390 native-dependent code for GDB, the GNU debugger. 2130803Smarcel Copyright 2001, 2003 Free Software Foundation, Inc 3130803Smarcel 4130803Smarcel Contributed by D.J. Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com) 5130803Smarcel for IBM Deutschland Entwicklung GmbH, IBM Corporation. 6130803Smarcel 7130803Smarcel This file is part of GDB. 8130803Smarcel 9130803Smarcel This program is free software; you can redistribute it and/or modify 10130803Smarcel it under the terms of the GNU General Public License as published by 11130803Smarcel the Free Software Foundation; either version 2 of the License, or 12130803Smarcel (at your option) any later version. 13130803Smarcel 14130803Smarcel This program is distributed in the hope that it will be useful, 15130803Smarcel but WITHOUT ANY WARRANTY; without even the implied warranty of 16130803Smarcel MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17130803Smarcel GNU General Public License for more details. 18130803Smarcel 19130803Smarcel You should have received a copy of the GNU General Public License 20130803Smarcel along with this program; if not, write to the Free Software 21130803Smarcel Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 22130803Smarcel 02111-1307, USA. */ 23130803Smarcel 24130803Smarcel#include "defs.h" 25130803Smarcel#include "tm.h" 26130803Smarcel#include "regcache.h" 27130803Smarcel#include "inferior.h" 28130803Smarcel 29130803Smarcel#include "s390-tdep.h" 30130803Smarcel 31130803Smarcel#include <asm/ptrace.h> 32130803Smarcel#include <sys/ptrace.h> 33130803Smarcel#include <asm/types.h> 34130803Smarcel#include <sys/procfs.h> 35130803Smarcel#include <sys/user.h> 36130803Smarcel#include <sys/ucontext.h> 37130803Smarcel 38130803Smarcel 39130803Smarcel/* Map registers to gregset/ptrace offsets. 40130803Smarcel These arrays are defined in s390-tdep.c. */ 41130803Smarcel 42130803Smarcel#ifdef __s390x__ 43130803Smarcel#define regmap_gregset s390x_regmap_gregset 44130803Smarcel#else 45130803Smarcel#define regmap_gregset s390_regmap_gregset 46130803Smarcel#endif 47130803Smarcel 48130803Smarcel#define regmap_fpregset s390_regmap_fpregset 49130803Smarcel 50130803Smarcel/* When debugging a 32-bit executable running under a 64-bit kernel, 51130803Smarcel we have to fix up the 64-bit registers we get from the kernel 52130803Smarcel to make them look like 32-bit registers. */ 53130803Smarcel#ifdef __s390x__ 54130803Smarcel#define SUBOFF(i) \ 55130803Smarcel ((TARGET_PTR_BIT == 32 \ 56130803Smarcel && ((i) == S390_PSWA_REGNUM \ 57130803Smarcel || ((i) >= S390_R0_REGNUM && (i) <= S390_R15_REGNUM)))? 4 : 0) 58130803Smarcel#else 59130803Smarcel#define SUBOFF(i) 0 60130803Smarcel#endif 61130803Smarcel 62130803Smarcel 63130803Smarcel/* Fill GDB's register array with the general-purpose register values 64130803Smarcel in *REGP. */ 65130803Smarcelvoid 66130803Smarcelsupply_gregset (gregset_t *regp) 67130803Smarcel{ 68130803Smarcel int i; 69130803Smarcel for (i = 0; i < S390_NUM_REGS; i++) 70130803Smarcel if (regmap_gregset[i] != -1) 71130803Smarcel regcache_raw_supply (current_regcache, i, 72130803Smarcel (char *)regp + regmap_gregset[i] + SUBOFF (i)); 73130803Smarcel} 74130803Smarcel 75130803Smarcel/* Fill register REGNO (if it is a general-purpose register) in 76130803Smarcel *REGP with the value in GDB's register array. If REGNO is -1, 77130803Smarcel do this for all registers. */ 78130803Smarcelvoid 79130803Smarcelfill_gregset (gregset_t *regp, int regno) 80130803Smarcel{ 81130803Smarcel int i; 82130803Smarcel for (i = 0; i < S390_NUM_REGS; i++) 83130803Smarcel if (regmap_gregset[i] != -1) 84130803Smarcel if (regno == -1 || regno == i) 85130803Smarcel regcache_raw_collect (current_regcache, i, 86130803Smarcel (char *)regp + regmap_gregset[i] + SUBOFF (i)); 87130803Smarcel} 88130803Smarcel 89130803Smarcel/* Fill GDB's register array with the floating-point register values 90130803Smarcel in *REGP. */ 91130803Smarcelvoid 92130803Smarcelsupply_fpregset (fpregset_t *regp) 93130803Smarcel{ 94130803Smarcel int i; 95130803Smarcel for (i = 0; i < S390_NUM_REGS; i++) 96130803Smarcel if (regmap_fpregset[i] != -1) 97130803Smarcel regcache_raw_supply (current_regcache, i, 98130803Smarcel ((char *)regp) + regmap_fpregset[i]); 99130803Smarcel} 100130803Smarcel 101130803Smarcel/* Fill register REGNO (if it is a general-purpose register) in 102130803Smarcel *REGP with the value in GDB's register array. If REGNO is -1, 103130803Smarcel do this for all registers. */ 104130803Smarcelvoid 105130803Smarcelfill_fpregset (fpregset_t *regp, int regno) 106130803Smarcel{ 107130803Smarcel int i; 108130803Smarcel for (i = 0; i < S390_NUM_REGS; i++) 109130803Smarcel if (regmap_fpregset[i] != -1) 110130803Smarcel if (regno == -1 || regno == i) 111130803Smarcel regcache_raw_collect (current_regcache, i, 112130803Smarcel ((char *)regp) + regmap_fpregset[i]); 113130803Smarcel} 114130803Smarcel 115130803Smarcel/* Find the TID for the current inferior thread to use with ptrace. */ 116130803Smarcelstatic int 117130803Smarcels390_inferior_tid (void) 118130803Smarcel{ 119130803Smarcel /* GNU/Linux LWP ID's are process ID's. */ 120130803Smarcel int tid = TIDGET (inferior_ptid); 121130803Smarcel if (tid == 0) 122130803Smarcel tid = PIDGET (inferior_ptid); /* Not a threaded program. */ 123130803Smarcel 124130803Smarcel return tid; 125130803Smarcel} 126130803Smarcel 127130803Smarcel/* Fetch all general-purpose registers from process/thread TID and 128130803Smarcel store their values in GDB's register cache. */ 129130803Smarcelstatic void 130130803Smarcelfetch_regs (int tid) 131130803Smarcel{ 132130803Smarcel gregset_t regs; 133130803Smarcel ptrace_area parea; 134130803Smarcel 135130803Smarcel parea.len = sizeof (regs); 136130803Smarcel parea.process_addr = (addr_t) ®s; 137130803Smarcel parea.kernel_addr = offsetof (struct user_regs_struct, psw); 138130803Smarcel if (ptrace (PTRACE_PEEKUSR_AREA, tid, (long) &parea) < 0) 139130803Smarcel perror_with_name ("Couldn't get registers"); 140130803Smarcel 141130803Smarcel supply_gregset (®s); 142130803Smarcel} 143130803Smarcel 144130803Smarcel/* Store all valid general-purpose registers in GDB's register cache 145130803Smarcel into the process/thread specified by TID. */ 146130803Smarcelstatic void 147130803Smarcelstore_regs (int tid, int regnum) 148130803Smarcel{ 149130803Smarcel gregset_t regs; 150130803Smarcel ptrace_area parea; 151130803Smarcel 152130803Smarcel parea.len = sizeof (regs); 153130803Smarcel parea.process_addr = (addr_t) ®s; 154130803Smarcel parea.kernel_addr = offsetof (struct user_regs_struct, psw); 155130803Smarcel if (ptrace (PTRACE_PEEKUSR_AREA, tid, (long) &parea) < 0) 156130803Smarcel perror_with_name ("Couldn't get registers"); 157130803Smarcel 158130803Smarcel fill_gregset (®s, regnum); 159130803Smarcel 160130803Smarcel if (ptrace (PTRACE_POKEUSR_AREA, tid, (long) &parea) < 0) 161130803Smarcel perror_with_name ("Couldn't write registers"); 162130803Smarcel} 163130803Smarcel 164130803Smarcel/* Fetch all floating-point registers from process/thread TID and store 165130803Smarcel their values in GDB's register cache. */ 166130803Smarcelstatic void 167130803Smarcelfetch_fpregs (int tid) 168130803Smarcel{ 169130803Smarcel fpregset_t fpregs; 170130803Smarcel ptrace_area parea; 171130803Smarcel 172130803Smarcel parea.len = sizeof (fpregs); 173130803Smarcel parea.process_addr = (addr_t) &fpregs; 174130803Smarcel parea.kernel_addr = offsetof (struct user_regs_struct, fp_regs); 175130803Smarcel if (ptrace (PTRACE_PEEKUSR_AREA, tid, (long) &parea) < 0) 176130803Smarcel perror_with_name ("Couldn't get floating point status"); 177130803Smarcel 178130803Smarcel supply_fpregset (&fpregs); 179130803Smarcel} 180130803Smarcel 181130803Smarcel/* Store all valid floating-point registers in GDB's register cache 182130803Smarcel into the process/thread specified by TID. */ 183130803Smarcelstatic void 184130803Smarcelstore_fpregs (int tid, int regnum) 185130803Smarcel{ 186130803Smarcel fpregset_t fpregs; 187130803Smarcel ptrace_area parea; 188130803Smarcel 189130803Smarcel parea.len = sizeof (fpregs); 190130803Smarcel parea.process_addr = (addr_t) &fpregs; 191130803Smarcel parea.kernel_addr = offsetof (struct user_regs_struct, fp_regs); 192130803Smarcel if (ptrace (PTRACE_PEEKUSR_AREA, tid, (long) &parea) < 0) 193130803Smarcel perror_with_name ("Couldn't get floating point status"); 194130803Smarcel 195130803Smarcel fill_fpregset (&fpregs, regnum); 196130803Smarcel 197130803Smarcel if (ptrace (PTRACE_POKEUSR_AREA, tid, (long) &parea) < 0) 198130803Smarcel perror_with_name ("Couldn't write floating point status"); 199130803Smarcel} 200130803Smarcel 201130803Smarcel/* Fetch register REGNUM from the child process. If REGNUM is -1, do 202130803Smarcel this for all registers. */ 203130803Smarcelvoid 204130803Smarcelfetch_inferior_registers (int regnum) 205130803Smarcel{ 206130803Smarcel int tid = s390_inferior_tid (); 207130803Smarcel 208130803Smarcel if (regnum == -1 209130803Smarcel || (regnum < S390_NUM_REGS && regmap_gregset[regnum] != -1)) 210130803Smarcel fetch_regs (tid); 211130803Smarcel 212130803Smarcel if (regnum == -1 213130803Smarcel || (regnum < S390_NUM_REGS && regmap_fpregset[regnum] != -1)) 214130803Smarcel fetch_fpregs (tid); 215130803Smarcel} 216130803Smarcel 217130803Smarcel/* Store register REGNUM back into the child process. If REGNUM is 218130803Smarcel -1, do this for all registers. */ 219130803Smarcelvoid 220130803Smarcelstore_inferior_registers (int regnum) 221130803Smarcel{ 222130803Smarcel int tid = s390_inferior_tid (); 223130803Smarcel 224130803Smarcel if (regnum == -1 225130803Smarcel || (regnum < S390_NUM_REGS && regmap_gregset[regnum] != -1)) 226130803Smarcel store_regs (tid, regnum); 227130803Smarcel 228130803Smarcel if (regnum == -1 229130803Smarcel || (regnum < S390_NUM_REGS && regmap_fpregset[regnum] != -1)) 230130803Smarcel store_fpregs (tid, regnum); 231130803Smarcel} 232130803Smarcel 233130803Smarcel 234130803Smarcel/* Hardware-assisted watchpoint handling. */ 235130803Smarcel 236130803Smarcel/* We maintain a list of all currently active watchpoints in order 237130803Smarcel to properly handle watchpoint removal. 238130803Smarcel 239130803Smarcel The only thing we actually need is the total address space area 240130803Smarcel spanned by the watchpoints. */ 241130803Smarcel 242130803Smarcelstruct watch_area 243130803Smarcel{ 244130803Smarcel struct watch_area *next; 245130803Smarcel CORE_ADDR lo_addr; 246130803Smarcel CORE_ADDR hi_addr; 247130803Smarcel}; 248130803Smarcel 249130803Smarcelstatic struct watch_area *watch_base = NULL; 250130803Smarcel 251130803Smarcelint 252130803Smarcels390_stopped_by_watchpoint (void) 253130803Smarcel{ 254130803Smarcel per_lowcore_bits per_lowcore; 255130803Smarcel ptrace_area parea; 256130803Smarcel 257130803Smarcel /* Speed up common case. */ 258130803Smarcel if (!watch_base) 259130803Smarcel return 0; 260130803Smarcel 261130803Smarcel parea.len = sizeof (per_lowcore); 262130803Smarcel parea.process_addr = (addr_t) & per_lowcore; 263130803Smarcel parea.kernel_addr = offsetof (struct user_regs_struct, per_info.lowcore); 264130803Smarcel if (ptrace (PTRACE_PEEKUSR_AREA, s390_inferior_tid (), &parea) < 0) 265130803Smarcel perror_with_name ("Couldn't retrieve watchpoint status"); 266130803Smarcel 267130803Smarcel return per_lowcore.perc_storage_alteration == 1 268130803Smarcel && per_lowcore.perc_store_real_address == 0; 269130803Smarcel} 270130803Smarcel 271130803Smarcelstatic void 272130803Smarcels390_fix_watch_points (void) 273130803Smarcel{ 274130803Smarcel int tid = s390_inferior_tid (); 275130803Smarcel 276130803Smarcel per_struct per_info; 277130803Smarcel ptrace_area parea; 278130803Smarcel 279130803Smarcel CORE_ADDR watch_lo_addr = (CORE_ADDR)-1, watch_hi_addr = 0; 280130803Smarcel struct watch_area *area; 281130803Smarcel 282130803Smarcel for (area = watch_base; area; area = area->next) 283130803Smarcel { 284130803Smarcel watch_lo_addr = min (watch_lo_addr, area->lo_addr); 285130803Smarcel watch_hi_addr = max (watch_hi_addr, area->hi_addr); 286130803Smarcel } 287130803Smarcel 288130803Smarcel parea.len = sizeof (per_info); 289130803Smarcel parea.process_addr = (addr_t) & per_info; 290130803Smarcel parea.kernel_addr = offsetof (struct user_regs_struct, per_info); 291130803Smarcel if (ptrace (PTRACE_PEEKUSR_AREA, tid, &parea) < 0) 292130803Smarcel perror_with_name ("Couldn't retrieve watchpoint status"); 293130803Smarcel 294130803Smarcel if (watch_base) 295130803Smarcel { 296130803Smarcel per_info.control_regs.bits.em_storage_alteration = 1; 297130803Smarcel per_info.control_regs.bits.storage_alt_space_ctl = 1; 298130803Smarcel } 299130803Smarcel else 300130803Smarcel { 301130803Smarcel per_info.control_regs.bits.em_storage_alteration = 0; 302130803Smarcel per_info.control_regs.bits.storage_alt_space_ctl = 0; 303130803Smarcel } 304130803Smarcel per_info.starting_addr = watch_lo_addr; 305130803Smarcel per_info.ending_addr = watch_hi_addr; 306130803Smarcel 307130803Smarcel if (ptrace (PTRACE_POKEUSR_AREA, tid, &parea) < 0) 308130803Smarcel perror_with_name ("Couldn't modify watchpoint status"); 309130803Smarcel} 310130803Smarcel 311130803Smarcelint 312130803Smarcels390_insert_watchpoint (CORE_ADDR addr, int len) 313130803Smarcel{ 314130803Smarcel struct watch_area *area = xmalloc (sizeof (struct watch_area)); 315130803Smarcel if (!area) 316130803Smarcel return -1; 317130803Smarcel 318130803Smarcel area->lo_addr = addr; 319130803Smarcel area->hi_addr = addr + len - 1; 320130803Smarcel 321130803Smarcel area->next = watch_base; 322130803Smarcel watch_base = area; 323130803Smarcel 324130803Smarcel s390_fix_watch_points (); 325130803Smarcel return 0; 326130803Smarcel} 327130803Smarcel 328130803Smarcelint 329130803Smarcels390_remove_watchpoint (CORE_ADDR addr, int len) 330130803Smarcel{ 331130803Smarcel struct watch_area *area, **parea; 332130803Smarcel 333130803Smarcel for (parea = &watch_base; *parea; parea = &(*parea)->next) 334130803Smarcel if ((*parea)->lo_addr == addr 335130803Smarcel && (*parea)->hi_addr == addr + len - 1) 336130803Smarcel break; 337130803Smarcel 338130803Smarcel if (!*parea) 339130803Smarcel { 340130803Smarcel fprintf_unfiltered (gdb_stderr, 341130803Smarcel "Attempt to remove nonexistent watchpoint.\n"); 342130803Smarcel return -1; 343130803Smarcel } 344130803Smarcel 345130803Smarcel area = *parea; 346130803Smarcel *parea = area->next; 347130803Smarcel xfree (area); 348130803Smarcel 349130803Smarcel s390_fix_watch_points (); 350130803Smarcel return 0; 351130803Smarcel} 352130803Smarcel 353130803Smarcel 354130803Smarcelint 355130803Smarcelkernel_u_size (void) 356130803Smarcel{ 357130803Smarcel return sizeof (struct user); 358130803Smarcel} 359130803Smarcel 360