1/* Native-dependent code for PA-RISC HP-UX. 2 3 Copyright (C) 2004, 2005, 2007 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 "defs.h" 21#include "inferior.h" 22#include "regcache.h" 23#include "target.h" 24 25#include "gdb_assert.h" 26#include <sys/ptrace.h> 27#include <machine/save_state.h> 28 29#ifdef HAVE_TTRACE 30#include <sys/ttrace.h> 31#endif 32 33#include "hppa-tdep.h" 34#include "inf-ptrace.h" 35#include "inf-ttrace.h" 36 37/* Non-zero if we should pretend not to be a runnable target. */ 38int child_suppress_run = 0; 39 40/* Return the offset of register REGNUM within `struct save_state'. 41 The offset returns depends on the flags in the "flags" register and 42 the register size (32-bit or 64-bit). These are taken from 43 REGCACHE. */ 44 45LONGEST 46hppa_hpux_save_state_offset (struct regcache *regcache, int regnum) 47{ 48 LONGEST offset; 49 50 if (regnum == HPPA_FLAGS_REGNUM) 51 return ssoff (ss_flags); 52 53 if (HPPA_R0_REGNUM < regnum && regnum < HPPA_FP0_REGNUM) 54 { 55 struct gdbarch *arch = get_regcache_arch (regcache); 56 size_t size = register_size (arch, HPPA_R1_REGNUM); 57 ULONGEST flags; 58 59 gdb_assert (size == 4 || size == 8); 60 61 regcache_cooked_read_unsigned (regcache, HPPA_FLAGS_REGNUM, &flags); 62 if (flags & SS_WIDEREGS) 63 offset = ssoff (ss_wide) + (8 - size) + (regnum - HPPA_R0_REGNUM) * 8; 64 else 65 offset = ssoff (ss_narrow) + (regnum - HPPA_R1_REGNUM) * 4; 66 } 67 else 68 { 69 struct gdbarch *arch = get_regcache_arch (regcache); 70 size_t size = register_size (arch, HPPA_FP0_REGNUM); 71 72 gdb_assert (size == 4 || size == 8); 73 gdb_assert (regnum >= HPPA_FP0_REGNUM); 74 offset = ssoff(ss_fpblock) + (regnum - HPPA_FP0_REGNUM) * size; 75 } 76 77 gdb_assert (offset < sizeof (save_state_t)); 78 return offset; 79} 80 81/* Just in case a future version of PA-RISC HP-UX won't have ptrace(2) 82 at all. */ 83#ifndef PTRACE_TYPE_RET 84#define PTRACE_TYPE_RET void 85#endif 86 87static void 88hppa_hpux_fetch_register (struct regcache *regcache, int regnum) 89{ 90 CORE_ADDR addr; 91 size_t size; 92 PTRACE_TYPE_RET *buf; 93 pid_t pid; 94 int i; 95 96 pid = ptid_get_pid (inferior_ptid); 97 98 /* This isn't really an address, but ptrace thinks of it as one. */ 99 addr = hppa_hpux_save_state_offset (regcache, regnum); 100 size = register_size (current_gdbarch, regnum); 101 102 gdb_assert (size == 4 || size == 8); 103 buf = alloca (size); 104 105#ifdef HAVE_TTRACE 106 { 107 lwpid_t lwp = ptid_get_lwp (inferior_ptid); 108 109 if (ttrace (TT_LWP_RUREGS, pid, lwp, addr, size, (uintptr_t)buf) == -1) 110 error (_("Couldn't read register %s (#%d): %s"), 111 gdbarch_register_name (current_gdbarch, regnum), 112 regnum, safe_strerror (errno)); 113 } 114#else 115 { 116 int i; 117 118 /* Read the register contents from the inferior a chuck at the time. */ 119 for (i = 0; i < size / sizeof (PTRACE_TYPE_RET); i++) 120 { 121 errno = 0; 122 buf[i] = ptrace (PT_RUREGS, pid, (PTRACE_TYPE_ARG3) addr, 0, 0); 123 if (errno != 0) 124 error (_("Couldn't read register %s (#%d): %s"), 125 gdbarch_register_name (current_gdbarch, regnum), 126 regnum, safe_strerror (errno)); 127 128 addr += sizeof (PTRACE_TYPE_RET); 129 } 130 } 131#endif 132 133 /* Take care with the "flags" register. It's stored as an `int' in 134 `struct save_state', even for 64-bit code. */ 135 if (regnum == HPPA_FLAGS_REGNUM && size == 8) 136 { 137 ULONGEST flags = extract_unsigned_integer ((gdb_byte *)buf, 4); 138 store_unsigned_integer ((gdb_byte *)buf, 8, flags); 139 } 140 141 regcache_raw_supply (regcache, regnum, buf); 142} 143 144static void 145hppa_hpux_fetch_inferior_registers (struct regcache *regcache, int regnum) 146{ 147 if (regnum == -1) 148 for (regnum = 0; regnum < gdbarch_num_regs (current_gdbarch); regnum++) 149 hppa_hpux_fetch_register (regcache, regnum); 150 else 151 hppa_hpux_fetch_register (regcache, regnum); 152} 153 154/* Store register REGNUM into the inferior. */ 155 156static void 157hppa_hpux_store_register (struct regcache *regcache, int regnum) 158{ 159 CORE_ADDR addr; 160 size_t size; 161 PTRACE_TYPE_RET *buf; 162 pid_t pid; 163 164 pid = ptid_get_pid (inferior_ptid); 165 166 /* This isn't really an address, but ptrace thinks of it as one. */ 167 addr = hppa_hpux_save_state_offset (regcache, regnum); 168 size = register_size (current_gdbarch, regnum); 169 170 gdb_assert (size == 4 || size == 8); 171 buf = alloca (size); 172 173 regcache_raw_collect (regcache, regnum, buf); 174 175 /* Take care with the "flags" register. It's stored as an `int' in 176 `struct save_state', even for 64-bit code. */ 177 if (regnum == HPPA_FLAGS_REGNUM && size == 8) 178 { 179 ULONGEST flags = extract_unsigned_integer ((gdb_byte *)buf, 8); 180 store_unsigned_integer ((gdb_byte *)buf, 4, flags); 181 size = 4; 182 } 183 184#ifdef HAVE_TTRACE 185 { 186 lwpid_t lwp = ptid_get_lwp (inferior_ptid); 187 188 if (ttrace (TT_LWP_WUREGS, pid, lwp, addr, size, (uintptr_t)buf) == -1) 189 error (_("Couldn't write register %s (#%d): %s"), 190 gdbarch_register_name (current_gdbarch, regnum), 191 regnum, safe_strerror (errno)); 192 } 193#else 194 { 195 int i; 196 197 /* Write the register contents into the inferior a chunk at the time. */ 198 for (i = 0; i < size / sizeof (PTRACE_TYPE_RET); i++) 199 { 200 errno = 0; 201 ptrace (PT_WUREGS, pid, (PTRACE_TYPE_ARG3) addr, buf[i], 0); 202 if (errno != 0) 203 error (_("Couldn't write register %s (#%d): %s"), 204 gdbarch_register_name (current_gdbarch, regnum), 205 regnum, safe_strerror (errno)); 206 207 addr += sizeof (PTRACE_TYPE_RET); 208 } 209 } 210#endif 211} 212 213/* Store register REGNUM back into the inferior. If REGNUM is -1, do 214 this for all registers (including the floating point registers). */ 215 216static void 217hppa_hpux_store_inferior_registers (struct regcache *regcache, int regnum) 218{ 219 if (regnum == -1) 220 for (regnum = 0; regnum < gdbarch_num_regs (current_gdbarch); regnum++) 221 hppa_hpux_store_register (regcache, regnum); 222 else 223 hppa_hpux_store_register (regcache, regnum); 224} 225 226static int 227hppa_hpux_child_can_run (void) 228{ 229 /* This variable is controlled by modules that layer their own 230 process structure atop that provided here. The code in 231 hpux-thread.c does this to support the HP-UX user-mode DCE 232 threads. */ 233 return !child_suppress_run; 234} 235 236 237/* Prevent warning from -Wmissing-prototypes. */ 238void _initialize_hppa_hpux_nat (void); 239 240void 241_initialize_hppa_hpux_nat (void) 242{ 243 struct target_ops *t; 244 245#ifdef HAVE_TTRACE 246 t = inf_ttrace_target (); 247#else 248 t = inf_ptrace_target (); 249#endif 250 251 t->to_fetch_registers = hppa_hpux_fetch_inferior_registers; 252 t->to_store_registers = hppa_hpux_store_inferior_registers; 253 t->to_can_run = hppa_hpux_child_can_run; 254 255 add_target (t); 256} 257