1 /* Xtensa GNU/Linux native support. 2 3 Copyright (C) 2007-2016 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 "frame.h" 22 #include "inferior.h" 23 #include "gdbcore.h" 24 #include "regcache.h" 25 #include "target.h" 26 #include "linux-nat.h" 27 #include <sys/types.h> 28 #include <signal.h> 29 #include <sys/user.h> 30 #include <sys/ioctl.h> 31 #include "gdb_wait.h" 32 #include <fcntl.h> 33 #include <sys/procfs.h> 34 #include "nat/gdb_ptrace.h" 35 #include <asm/ptrace.h> 36 37 #include "gregset.h" 38 #include "xtensa-tdep.h" 39 40 /* Defines ps_err_e, struct ps_prochandle. */ 41 #include "gdb_proc_service.h" 42 43 /* Extended register set depends on hardware configs. 44 Keeping these definitions separately allows to introduce 45 hardware-specific overlays. */ 46 #include "xtensa-xtregs.c" 47 48 void 49 fill_gregset (const struct regcache *regcache, 50 gdb_gregset_t *gregsetp, int regnum) 51 { 52 int i; 53 xtensa_elf_gregset_t *regs = (xtensa_elf_gregset_t *) gregsetp; 54 struct gdbarch *gdbarch = get_regcache_arch (regcache); 55 56 if (regnum == gdbarch_pc_regnum (gdbarch) || regnum == -1) 57 regcache_raw_collect (regcache, gdbarch_pc_regnum (gdbarch), ®s->pc); 58 if (regnum == gdbarch_ps_regnum (gdbarch) || regnum == -1) 59 regcache_raw_collect (regcache, gdbarch_ps_regnum (gdbarch), ®s->ps); 60 61 if (regnum == gdbarch_tdep (gdbarch)->wb_regnum || regnum == -1) 62 regcache_raw_collect (regcache, 63 gdbarch_tdep (gdbarch)->wb_regnum, 64 ®s->windowbase); 65 if (regnum == gdbarch_tdep (gdbarch)->ws_regnum || regnum == -1) 66 regcache_raw_collect (regcache, 67 gdbarch_tdep (gdbarch)->ws_regnum, 68 ®s->windowstart); 69 if (regnum == gdbarch_tdep (gdbarch)->lbeg_regnum || regnum == -1) 70 regcache_raw_collect (regcache, 71 gdbarch_tdep (gdbarch)->lbeg_regnum, 72 ®s->lbeg); 73 if (regnum == gdbarch_tdep (gdbarch)->lend_regnum || regnum == -1) 74 regcache_raw_collect (regcache, 75 gdbarch_tdep (gdbarch)->lend_regnum, 76 ®s->lend); 77 if (regnum == gdbarch_tdep (gdbarch)->lcount_regnum || regnum == -1) 78 regcache_raw_collect (regcache, 79 gdbarch_tdep (gdbarch)->lcount_regnum, 80 ®s->lcount); 81 if (regnum == gdbarch_tdep (gdbarch)->sar_regnum || regnum == -1) 82 regcache_raw_collect (regcache, 83 gdbarch_tdep (gdbarch)->sar_regnum, 84 ®s->sar); 85 if (regnum >=gdbarch_tdep (gdbarch)->ar_base 86 && regnum < gdbarch_tdep (gdbarch)->ar_base 87 + gdbarch_tdep (gdbarch)->num_aregs) 88 regcache_raw_collect (regcache,regnum, 89 ®s->ar[regnum - gdbarch_tdep (gdbarch)->ar_base]); 90 else if (regnum == -1) 91 { 92 for (i = 0; i < gdbarch_tdep (gdbarch)->num_aregs; ++i) 93 regcache_raw_collect (regcache, 94 gdbarch_tdep (gdbarch)->ar_base + i, 95 ®s->ar[i]); 96 } 97 } 98 99 static void 100 supply_gregset_reg (struct regcache *regcache, 101 const gdb_gregset_t *gregsetp, int regnum) 102 { 103 int i; 104 xtensa_elf_gregset_t *regs = (xtensa_elf_gregset_t *) gregsetp; 105 106 struct gdbarch *gdbarch = get_regcache_arch (regcache); 107 108 if (regnum == gdbarch_pc_regnum (gdbarch) || regnum == -1) 109 regcache_raw_supply (regcache, gdbarch_pc_regnum (gdbarch), ®s->pc); 110 if (regnum == gdbarch_ps_regnum (gdbarch) || regnum == -1) 111 regcache_raw_supply (regcache, gdbarch_ps_regnum (gdbarch), ®s->ps); 112 113 if (regnum == gdbarch_tdep (gdbarch)->wb_regnum || regnum == -1) 114 regcache_raw_supply (regcache, 115 gdbarch_tdep (gdbarch)->wb_regnum, 116 ®s->windowbase); 117 if (regnum == gdbarch_tdep (gdbarch)->ws_regnum || regnum == -1) 118 regcache_raw_supply (regcache, 119 gdbarch_tdep (gdbarch)->ws_regnum, 120 ®s->windowstart); 121 if (regnum == gdbarch_tdep (gdbarch)->lbeg_regnum || regnum == -1) 122 regcache_raw_supply (regcache, 123 gdbarch_tdep (gdbarch)->lbeg_regnum, 124 ®s->lbeg); 125 if (regnum == gdbarch_tdep (gdbarch)->lend_regnum || regnum == -1) 126 regcache_raw_supply (regcache, 127 gdbarch_tdep (gdbarch)->lend_regnum, 128 ®s->lend); 129 if (regnum == gdbarch_tdep (gdbarch)->lcount_regnum || regnum == -1) 130 regcache_raw_supply (regcache, 131 gdbarch_tdep (gdbarch)->lcount_regnum, 132 ®s->lcount); 133 if (regnum == gdbarch_tdep (gdbarch)->sar_regnum || regnum == -1) 134 regcache_raw_supply (regcache, 135 gdbarch_tdep (gdbarch)->sar_regnum, 136 ®s->sar); 137 if (regnum >=gdbarch_tdep (gdbarch)->ar_base 138 && regnum < gdbarch_tdep (gdbarch)->ar_base 139 + gdbarch_tdep (gdbarch)->num_aregs) 140 regcache_raw_supply (regcache,regnum, 141 ®s->ar[regnum - gdbarch_tdep (gdbarch)->ar_base]); 142 else if (regnum == -1) 143 { 144 for (i = 0; i < gdbarch_tdep (gdbarch)->num_aregs; ++i) 145 regcache_raw_supply (regcache, 146 gdbarch_tdep (gdbarch)->ar_base + i, 147 ®s->ar[i]); 148 } 149 } 150 151 void 152 supply_gregset (struct regcache *regcache, const gdb_gregset_t *gregsetp) 153 { 154 supply_gregset_reg (regcache, gregsetp, -1); 155 } 156 157 void 158 fill_fpregset (const struct regcache *regcache, 159 gdb_fpregset_t *fpregsetp, int regnum) 160 { 161 return; 162 } 163 164 void 165 supply_fpregset (struct regcache *regcache, 166 const gdb_fpregset_t *fpregsetp) 167 { 168 return; 169 } 170 171 /* Fetch greg-register(s) from process/thread TID 172 and store value(s) in GDB's register array. */ 173 174 static void 175 fetch_gregs (struct regcache *regcache, int regnum) 176 { 177 int tid = ptid_get_lwp (inferior_ptid); 178 const gdb_gregset_t regs; 179 int areg; 180 181 if (ptrace (PTRACE_GETREGS, tid, 0, (long) ®s) < 0) 182 { 183 perror_with_name (_("Couldn't get registers")); 184 return; 185 } 186 187 supply_gregset_reg (regcache, ®s, regnum); 188 } 189 190 /* Store greg-register(s) in GDB's register 191 array into the process/thread specified by TID. */ 192 193 static void 194 store_gregs (struct regcache *regcache, int regnum) 195 { 196 int tid = ptid_get_lwp (inferior_ptid); 197 gdb_gregset_t regs; 198 int areg; 199 200 if (ptrace (PTRACE_GETREGS, tid, 0, (long) ®s) < 0) 201 { 202 perror_with_name (_("Couldn't get registers")); 203 return; 204 } 205 206 fill_gregset (regcache, ®s, regnum); 207 208 if (ptrace (PTRACE_SETREGS, tid, 0, (long) ®s) < 0) 209 { 210 perror_with_name (_("Couldn't write registers")); 211 return; 212 } 213 } 214 215 static int xtreg_lo; 216 static int xtreg_high; 217 218 /* Fetch/Store Xtensa TIE registers. Xtensa GNU/Linux PTRACE 219 interface provides special requests for this. */ 220 221 static void 222 fetch_xtregs (struct regcache *regcache, int regnum) 223 { 224 int tid = ptid_get_lwp (inferior_ptid); 225 const xtensa_regtable_t *ptr; 226 char xtregs [XTENSA_ELF_XTREG_SIZE]; 227 228 if (ptrace (PTRACE_GETXTREGS, tid, 0, (long)&xtregs) < 0) 229 perror_with_name (_("Couldn't get extended registers")); 230 231 for (ptr = xtensa_regmap_table; ptr->name; ptr++) 232 if (regnum == ptr->gdb_regnum || regnum == -1) 233 regcache_raw_supply (regcache, ptr->gdb_regnum, 234 xtregs + ptr->ptrace_offset); 235 } 236 237 static void 238 store_xtregs (struct regcache *regcache, int regnum) 239 { 240 int tid = ptid_get_lwp (inferior_ptid); 241 const xtensa_regtable_t *ptr; 242 char xtregs [XTENSA_ELF_XTREG_SIZE]; 243 244 if (ptrace (PTRACE_GETXTREGS, tid, 0, (long)&xtregs) < 0) 245 perror_with_name (_("Couldn't get extended registers")); 246 247 for (ptr = xtensa_regmap_table; ptr->name; ptr++) 248 if (regnum == ptr->gdb_regnum || regnum == -1) 249 regcache_raw_collect (regcache, ptr->gdb_regnum, 250 xtregs + ptr->ptrace_offset); 251 252 if (ptrace (PTRACE_SETXTREGS, tid, 0, (long)&xtregs) < 0) 253 perror_with_name (_("Couldn't write extended registers")); 254 } 255 256 static void 257 xtensa_linux_fetch_inferior_registers (struct target_ops *ops, 258 struct regcache *regcache, int regnum) 259 { 260 if (regnum == -1) 261 { 262 fetch_gregs (regcache, regnum); 263 fetch_xtregs (regcache, regnum); 264 } 265 else if ((regnum < xtreg_lo) || (regnum > xtreg_high)) 266 fetch_gregs (regcache, regnum); 267 else 268 fetch_xtregs (regcache, regnum); 269 } 270 271 static void 272 xtensa_linux_store_inferior_registers (struct target_ops *ops, 273 struct regcache *regcache, int regnum) 274 { 275 if (regnum == -1) 276 { 277 store_gregs (regcache, regnum); 278 store_xtregs (regcache, regnum); 279 } 280 else if ((regnum < xtreg_lo) || (regnum > xtreg_high)) 281 store_gregs (regcache, regnum); 282 else 283 store_xtregs (regcache, regnum); 284 } 285 286 /* Called by libthread_db. */ 287 288 ps_err_e 289 ps_get_thread_area (struct ps_prochandle *ph, 290 lwpid_t lwpid, int idx, void **base) 291 { 292 xtensa_elf_gregset_t regs; 293 294 if (ptrace (PTRACE_GETREGS, lwpid, NULL, ®s) != 0) 295 return PS_ERR; 296 297 /* IDX is the bias from the thread pointer to the beginning of the 298 thread descriptor. It has to be subtracted due to implementation 299 quirks in libthread_db. */ 300 *base = (void *) ((char *) regs.threadptr - idx); 301 302 return PS_OK; 303 } 304 305 void _initialize_xtensa_linux_nat (void); 306 307 void 308 _initialize_xtensa_linux_nat (void) 309 { 310 struct target_ops *t; 311 const xtensa_regtable_t *ptr; 312 313 /* Calculate the number range for extended registers. */ 314 xtreg_lo = 1000000000; 315 xtreg_high = -1; 316 for (ptr = xtensa_regmap_table; ptr->name; ptr++) 317 { 318 if (ptr->gdb_regnum < xtreg_lo) 319 xtreg_lo = ptr->gdb_regnum; 320 if (ptr->gdb_regnum > xtreg_high) 321 xtreg_high = ptr->gdb_regnum; 322 } 323 324 /* Fill in the generic GNU/Linux methods. */ 325 t = linux_target (); 326 327 /* Add our register access methods. */ 328 t->to_fetch_registers = xtensa_linux_fetch_inferior_registers; 329 t->to_store_registers = xtensa_linux_store_inferior_registers; 330 331 linux_nat_add_target (t); 332 } 333