GDB (API)
|
00001 /* Native-dependent code for PA-RISC HP-UX. 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 "inferior.h" 00022 #include "regcache.h" 00023 #include "target.h" 00024 00025 #include "gdb_assert.h" 00026 #include <sys/ptrace.h> 00027 #include <sys/utsname.h> 00028 #include <machine/save_state.h> 00029 00030 #ifdef HAVE_TTRACE 00031 #include <sys/ttrace.h> 00032 #endif 00033 00034 #include "hppa-tdep.h" 00035 #include "solib-som.h" 00036 #include "inf-ptrace.h" 00037 #include "inf-ttrace.h" 00038 00039 /* Return the offset of register REGNUM within `struct save_state'. 00040 The offset returns depends on the flags in the "flags" register and 00041 the register size (32-bit or 64-bit). These are taken from 00042 REGCACHE. */ 00043 00044 static LONGEST 00045 hppa_hpux_save_state_offset (struct regcache *regcache, int regnum) 00046 { 00047 LONGEST offset; 00048 00049 if (regnum == HPPA_FLAGS_REGNUM) 00050 return ssoff (ss_flags); 00051 00052 if (HPPA_R0_REGNUM < regnum && regnum < HPPA_FP0_REGNUM) 00053 { 00054 struct gdbarch *arch = get_regcache_arch (regcache); 00055 size_t size = register_size (arch, HPPA_R1_REGNUM); 00056 ULONGEST flags; 00057 00058 gdb_assert (size == 4 || size == 8); 00059 00060 regcache_cooked_read_unsigned (regcache, HPPA_FLAGS_REGNUM, &flags); 00061 if (flags & SS_WIDEREGS) 00062 offset = ssoff (ss_wide) + (8 - size) + (regnum - HPPA_R0_REGNUM) * 8; 00063 else 00064 offset = ssoff (ss_narrow) + (regnum - HPPA_R1_REGNUM) * 4; 00065 } 00066 else 00067 { 00068 struct gdbarch *arch = get_regcache_arch (regcache); 00069 size_t size = register_size (arch, HPPA_FP0_REGNUM); 00070 00071 gdb_assert (size == 4 || size == 8); 00072 gdb_assert (regnum >= HPPA_FP0_REGNUM); 00073 offset = ssoff(ss_fpblock) + (regnum - HPPA_FP0_REGNUM) * size; 00074 } 00075 00076 gdb_assert (offset < sizeof (save_state_t)); 00077 return offset; 00078 } 00079 00080 /* Just in case a future version of PA-RISC HP-UX won't have ptrace(2) 00081 at all. */ 00082 #ifndef PTRACE_TYPE_RET 00083 #define PTRACE_TYPE_RET void 00084 #endif 00085 00086 static void 00087 hppa_hpux_fetch_register (struct regcache *regcache, int regnum) 00088 { 00089 struct gdbarch *gdbarch = get_regcache_arch (regcache); 00090 enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); 00091 CORE_ADDR addr; 00092 size_t size; 00093 PTRACE_TYPE_RET *buf; 00094 pid_t pid; 00095 int i; 00096 00097 pid = ptid_get_pid (inferior_ptid); 00098 00099 /* This isn't really an address, but ptrace thinks of it as one. */ 00100 addr = hppa_hpux_save_state_offset (regcache, regnum); 00101 size = register_size (gdbarch, regnum); 00102 00103 gdb_assert (size == 4 || size == 8); 00104 buf = alloca (size); 00105 00106 #ifdef HAVE_TTRACE 00107 { 00108 lwpid_t lwp = ptid_get_lwp (inferior_ptid); 00109 00110 if (ttrace (TT_LWP_RUREGS, pid, lwp, addr, size, (uintptr_t)buf) == -1) 00111 error (_("Couldn't read register %s (#%d): %s"), 00112 gdbarch_register_name (gdbarch, regnum), 00113 regnum, safe_strerror (errno)); 00114 } 00115 #else 00116 { 00117 int i; 00118 00119 /* Read the register contents from the inferior a chuck at the time. */ 00120 for (i = 0; i < size / sizeof (PTRACE_TYPE_RET); i++) 00121 { 00122 errno = 0; 00123 buf[i] = ptrace (PT_RUREGS, pid, (PTRACE_TYPE_ARG3) addr, 0, 0); 00124 if (errno != 0) 00125 error (_("Couldn't read register %s (#%d): %s"), 00126 gdbarch_register_name (gdbarch, regnum), 00127 regnum, safe_strerror (errno)); 00128 00129 addr += sizeof (PTRACE_TYPE_RET); 00130 } 00131 } 00132 #endif 00133 00134 /* Take care with the "flags" register. It's stored as an `int' in 00135 `struct save_state', even for 64-bit code. */ 00136 if (regnum == HPPA_FLAGS_REGNUM && size == 8) 00137 { 00138 ULONGEST flags; 00139 flags = extract_unsigned_integer ((gdb_byte *)buf, 4, byte_order); 00140 store_unsigned_integer ((gdb_byte *)buf, 8, byte_order, flags); 00141 } 00142 00143 regcache_raw_supply (regcache, regnum, buf); 00144 } 00145 00146 static void 00147 hppa_hpux_fetch_inferior_registers (struct target_ops *ops, 00148 struct regcache *regcache, int regnum) 00149 { 00150 if (regnum == -1) 00151 for (regnum = 0; 00152 regnum < gdbarch_num_regs (get_regcache_arch (regcache)); 00153 regnum++) 00154 hppa_hpux_fetch_register (regcache, regnum); 00155 else 00156 hppa_hpux_fetch_register (regcache, regnum); 00157 } 00158 00159 /* Store register REGNUM into the inferior. */ 00160 00161 static void 00162 hppa_hpux_store_register (struct regcache *regcache, int regnum) 00163 { 00164 struct gdbarch *gdbarch = get_regcache_arch (regcache); 00165 enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); 00166 CORE_ADDR addr; 00167 size_t size; 00168 PTRACE_TYPE_RET *buf; 00169 pid_t pid; 00170 00171 pid = ptid_get_pid (inferior_ptid); 00172 00173 /* This isn't really an address, but ptrace thinks of it as one. */ 00174 addr = hppa_hpux_save_state_offset (regcache, regnum); 00175 size = register_size (gdbarch, regnum); 00176 00177 gdb_assert (size == 4 || size == 8); 00178 buf = alloca (size); 00179 00180 regcache_raw_collect (regcache, regnum, buf); 00181 00182 /* Take care with the "flags" register. It's stored as an `int' in 00183 `struct save_state', even for 64-bit code. */ 00184 if (regnum == HPPA_FLAGS_REGNUM && size == 8) 00185 { 00186 ULONGEST flags; 00187 flags = extract_unsigned_integer ((gdb_byte *)buf, 8, byte_order); 00188 store_unsigned_integer ((gdb_byte *)buf, 4, byte_order, flags); 00189 size = 4; 00190 } 00191 00192 #ifdef HAVE_TTRACE 00193 { 00194 lwpid_t lwp = ptid_get_lwp (inferior_ptid); 00195 00196 if (ttrace (TT_LWP_WUREGS, pid, lwp, addr, size, (uintptr_t)buf) == -1) 00197 error (_("Couldn't write register %s (#%d): %s"), 00198 gdbarch_register_name (gdbarch, regnum), 00199 regnum, safe_strerror (errno)); 00200 } 00201 #else 00202 { 00203 int i; 00204 00205 /* Write the register contents into the inferior a chunk at the time. */ 00206 for (i = 0; i < size / sizeof (PTRACE_TYPE_RET); i++) 00207 { 00208 errno = 0; 00209 ptrace (PT_WUREGS, pid, (PTRACE_TYPE_ARG3) addr, buf[i], 0); 00210 if (errno != 0) 00211 error (_("Couldn't write register %s (#%d): %s"), 00212 gdbarch_register_name (gdbarch, regnum), 00213 regnum, safe_strerror (errno)); 00214 00215 addr += sizeof (PTRACE_TYPE_RET); 00216 } 00217 } 00218 #endif 00219 } 00220 00221 /* Store register REGNUM back into the inferior. If REGNUM is -1, do 00222 this for all registers (including the floating point registers). */ 00223 00224 static void 00225 hppa_hpux_store_inferior_registers (struct target_ops *ops, 00226 struct regcache *regcache, int regnum) 00227 { 00228 if (regnum == -1) 00229 for (regnum = 0; 00230 regnum < gdbarch_num_regs (get_regcache_arch (regcache)); 00231 regnum++) 00232 hppa_hpux_store_register (regcache, regnum); 00233 else 00234 hppa_hpux_store_register (regcache, regnum); 00235 } 00236 00237 /* Set hpux_major_release variable to the value retrieved from a call to 00238 uname function. */ 00239 00240 static void 00241 set_hpux_major_release (void) 00242 { 00243 struct utsname x; 00244 char *p; 00245 00246 uname (&x); 00247 p = strchr (x.release, '.'); 00248 if (p) 00249 hpux_major_release = atoi (p + 1); 00250 } 00251 00252 00253 00254 /* Prevent warning from -Wmissing-prototypes. */ 00255 void _initialize_hppa_hpux_nat (void); 00256 00257 void 00258 _initialize_hppa_hpux_nat (void) 00259 { 00260 struct target_ops *t; 00261 00262 set_hpux_major_release (); 00263 00264 #ifdef HAVE_TTRACE 00265 t = inf_ttrace_target (); 00266 #else 00267 t = inf_ptrace_target (); 00268 #endif 00269 00270 t->to_fetch_registers = hppa_hpux_fetch_inferior_registers; 00271 t->to_store_registers = hppa_hpux_store_inferior_registers; 00272 00273 add_target (t); 00274 }