1 /* Xtensa GNU/Linux native support. 2 3 Copyright (C) 2007-2023 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 "gdbsupport/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 class xtensa_linux_nat_target final : public linux_nat_target 49 { 50 public: 51 /* Add our register access methods. */ 52 void fetch_registers (struct regcache *, int) override; 53 void store_registers (struct regcache *, int) override; 54 }; 55 56 static xtensa_linux_nat_target the_xtensa_linux_nat_target; 57 58 void 59 fill_gregset (const struct regcache *regcache, 60 gdb_gregset_t *gregsetp, int regnum) 61 { 62 int i; 63 xtensa_elf_gregset_t *regs = (xtensa_elf_gregset_t *) gregsetp; 64 struct gdbarch *gdbarch = regcache->arch (); 65 xtensa_gdbarch_tdep *tdep = gdbarch_tdep<xtensa_gdbarch_tdep> (gdbarch); 66 67 if (regnum == gdbarch_pc_regnum (gdbarch) || regnum == -1) 68 regcache->raw_collect (gdbarch_pc_regnum (gdbarch), ®s->pc); 69 if (regnum == gdbarch_ps_regnum (gdbarch) || regnum == -1) 70 regcache->raw_collect (gdbarch_ps_regnum (gdbarch), ®s->ps); 71 72 if (regnum == tdep->wb_regnum || regnum == -1) 73 regcache->raw_collect (tdep->wb_regnum, 74 ®s->windowbase); 75 if (regnum == tdep->ws_regnum || regnum == -1) 76 regcache->raw_collect (tdep->ws_regnum, 77 ®s->windowstart); 78 if (regnum == tdep->lbeg_regnum || regnum == -1) 79 regcache->raw_collect (tdep->lbeg_regnum, 80 ®s->lbeg); 81 if (regnum == tdep->lend_regnum || regnum == -1) 82 regcache->raw_collect (tdep->lend_regnum, 83 ®s->lend); 84 if (regnum == tdep->lcount_regnum || regnum == -1) 85 regcache->raw_collect (tdep->lcount_regnum, 86 ®s->lcount); 87 if (regnum == tdep->sar_regnum || regnum == -1) 88 regcache->raw_collect (tdep->sar_regnum, 89 ®s->sar); 90 if (regnum == tdep->threadptr_regnum || regnum == -1) 91 regcache->raw_collect (tdep->threadptr_regnum, 92 ®s->threadptr); 93 if (regnum >=tdep->ar_base 94 && regnum < tdep->ar_base 95 + tdep->num_aregs) 96 regcache->raw_collect (regnum, 97 ®s->ar[regnum - tdep->ar_base]); 98 else if (regnum == -1) 99 { 100 for (i = 0; i < tdep->num_aregs; ++i) 101 regcache->raw_collect (tdep->ar_base + i, 102 ®s->ar[i]); 103 } 104 if (regnum >= tdep->a0_base 105 && regnum < tdep->a0_base + C0_NREGS) 106 regcache->raw_collect (regnum, 107 ®s->ar[(4 * regs->windowbase + regnum 108 - tdep->a0_base) 109 % tdep->num_aregs]); 110 else if (regnum == -1) 111 { 112 for (i = 0; i < C0_NREGS; ++i) 113 regcache->raw_collect (tdep->a0_base + i, 114 (®s->ar[(4 * regs->windowbase + i) 115 % tdep->num_aregs])); 116 } 117 } 118 119 static void 120 supply_gregset_reg (struct regcache *regcache, 121 const gdb_gregset_t *gregsetp, int regnum) 122 { 123 int i; 124 xtensa_elf_gregset_t *regs = (xtensa_elf_gregset_t *) gregsetp; 125 126 struct gdbarch *gdbarch = regcache->arch (); 127 xtensa_gdbarch_tdep *tdep = gdbarch_tdep<xtensa_gdbarch_tdep> (gdbarch); 128 129 if (regnum == gdbarch_pc_regnum (gdbarch) || regnum == -1) 130 regcache->raw_supply (gdbarch_pc_regnum (gdbarch), ®s->pc); 131 if (regnum == gdbarch_ps_regnum (gdbarch) || regnum == -1) 132 regcache->raw_supply (gdbarch_ps_regnum (gdbarch), ®s->ps); 133 134 if (regnum == tdep->wb_regnum || regnum == -1) 135 regcache->raw_supply (tdep->wb_regnum, 136 ®s->windowbase); 137 if (regnum == tdep->ws_regnum || regnum == -1) 138 regcache->raw_supply (tdep->ws_regnum, 139 ®s->windowstart); 140 if (regnum == tdep->lbeg_regnum || regnum == -1) 141 regcache->raw_supply (tdep->lbeg_regnum, 142 ®s->lbeg); 143 if (regnum == tdep->lend_regnum || regnum == -1) 144 regcache->raw_supply (tdep->lend_regnum, 145 ®s->lend); 146 if (regnum == tdep->lcount_regnum || regnum == -1) 147 regcache->raw_supply (tdep->lcount_regnum, 148 ®s->lcount); 149 if (regnum == tdep->sar_regnum || regnum == -1) 150 regcache->raw_supply (tdep->sar_regnum, 151 ®s->sar); 152 if (regnum == tdep->threadptr_regnum || regnum == -1) 153 regcache->raw_supply (tdep->threadptr_regnum, 154 ®s->threadptr); 155 if (regnum >=tdep->ar_base 156 && regnum < tdep->ar_base 157 + tdep->num_aregs) 158 regcache->raw_supply (regnum, 159 ®s->ar[regnum - tdep->ar_base]); 160 else if (regnum == -1) 161 { 162 for (i = 0; i < tdep->num_aregs; ++i) 163 regcache->raw_supply (tdep->ar_base + i, 164 ®s->ar[i]); 165 } 166 if (regnum >= tdep->a0_base 167 && regnum < tdep->a0_base + C0_NREGS) 168 regcache->raw_supply (regnum, 169 ®s->ar[(4 * regs->windowbase + regnum 170 - tdep->a0_base) 171 % tdep->num_aregs]); 172 else if (regnum == -1) 173 { 174 for (i = 0; i < C0_NREGS; ++i) 175 regcache->raw_supply (tdep->a0_base + i, 176 ®s->ar[(4 * regs->windowbase + i) 177 % tdep->num_aregs]); 178 } 179 } 180 181 void 182 supply_gregset (struct regcache *regcache, const gdb_gregset_t *gregsetp) 183 { 184 supply_gregset_reg (regcache, gregsetp, -1); 185 } 186 187 void 188 fill_fpregset (const struct regcache *regcache, 189 gdb_fpregset_t *fpregsetp, int regnum) 190 { 191 return; 192 } 193 194 void 195 supply_fpregset (struct regcache *regcache, 196 const gdb_fpregset_t *fpregsetp) 197 { 198 return; 199 } 200 201 /* Fetch greg-register(s) from process/thread TID 202 and store value(s) in GDB's register array. */ 203 204 static void 205 fetch_gregs (struct regcache *regcache, int regnum) 206 { 207 int tid = regcache->ptid ().lwp (); 208 gdb_gregset_t regs; 209 210 if (ptrace (PTRACE_GETREGS, tid, 0, (long) ®s) < 0) 211 { 212 perror_with_name (_("Couldn't get registers")); 213 return; 214 } 215 216 supply_gregset_reg (regcache, ®s, regnum); 217 } 218 219 /* Store greg-register(s) in GDB's register 220 array into the process/thread specified by TID. */ 221 222 static void 223 store_gregs (struct regcache *regcache, int regnum) 224 { 225 int tid = regcache->ptid ().lwp (); 226 gdb_gregset_t regs; 227 228 if (ptrace (PTRACE_GETREGS, tid, 0, (long) ®s) < 0) 229 { 230 perror_with_name (_("Couldn't get registers")); 231 return; 232 } 233 234 fill_gregset (regcache, ®s, regnum); 235 236 if (ptrace (PTRACE_SETREGS, tid, 0, (long) ®s) < 0) 237 { 238 perror_with_name (_("Couldn't write registers")); 239 return; 240 } 241 } 242 243 static int xtreg_lo; 244 static int xtreg_high; 245 246 /* Fetch/Store Xtensa TIE registers. Xtensa GNU/Linux PTRACE 247 interface provides special requests for this. */ 248 249 static void 250 fetch_xtregs (struct regcache *regcache, int regnum) 251 { 252 int tid = regcache->ptid ().lwp (); 253 const xtensa_regtable_t *ptr; 254 char xtregs [XTENSA_ELF_XTREG_SIZE]; 255 256 if (ptrace (PTRACE_GETXTREGS, tid, 0, (long)&xtregs) < 0) 257 perror_with_name (_("Couldn't get extended registers")); 258 259 for (ptr = xtensa_regmap_table; ptr->name; ptr++) 260 if (regnum == ptr->gdb_regnum || regnum == -1) 261 regcache->raw_supply (ptr->gdb_regnum, xtregs + ptr->ptrace_offset); 262 } 263 264 static void 265 store_xtregs (struct regcache *regcache, int regnum) 266 { 267 int tid = regcache->ptid ().lwp (); 268 const xtensa_regtable_t *ptr; 269 char xtregs [XTENSA_ELF_XTREG_SIZE]; 270 271 if (ptrace (PTRACE_GETXTREGS, tid, 0, (long)&xtregs) < 0) 272 perror_with_name (_("Couldn't get extended registers")); 273 274 for (ptr = xtensa_regmap_table; ptr->name; ptr++) 275 if (regnum == ptr->gdb_regnum || regnum == -1) 276 regcache->raw_collect (ptr->gdb_regnum, xtregs + ptr->ptrace_offset); 277 278 if (ptrace (PTRACE_SETXTREGS, tid, 0, (long)&xtregs) < 0) 279 perror_with_name (_("Couldn't write extended registers")); 280 } 281 282 void 283 xtensa_linux_nat_target::fetch_registers (struct regcache *regcache, 284 int regnum) 285 { 286 if (regnum == -1) 287 { 288 fetch_gregs (regcache, regnum); 289 fetch_xtregs (regcache, regnum); 290 } 291 else if ((regnum < xtreg_lo) || (regnum > xtreg_high)) 292 fetch_gregs (regcache, regnum); 293 else 294 fetch_xtregs (regcache, regnum); 295 } 296 297 void 298 xtensa_linux_nat_target::store_registers (struct regcache *regcache, 299 int regnum) 300 { 301 if (regnum == -1) 302 { 303 store_gregs (regcache, regnum); 304 store_xtregs (regcache, regnum); 305 } 306 else if ((regnum < xtreg_lo) || (regnum > xtreg_high)) 307 store_gregs (regcache, regnum); 308 else 309 store_xtregs (regcache, regnum); 310 } 311 312 /* Called by libthread_db. */ 313 314 ps_err_e 315 ps_get_thread_area (struct ps_prochandle *ph, 316 lwpid_t lwpid, int idx, void **base) 317 { 318 xtensa_elf_gregset_t regs; 319 320 if (ptrace (PTRACE_GETREGS, lwpid, NULL, ®s) != 0) 321 return PS_ERR; 322 323 /* IDX is the bias from the thread pointer to the beginning of the 324 thread descriptor. It has to be subtracted due to implementation 325 quirks in libthread_db. */ 326 *base = (void *) ((char *) regs.threadptr - idx); 327 328 return PS_OK; 329 } 330 331 void _initialize_xtensa_linux_nat (); 332 void 333 _initialize_xtensa_linux_nat () 334 { 335 const xtensa_regtable_t *ptr; 336 337 /* Calculate the number range for extended registers. */ 338 xtreg_lo = 1000000000; 339 xtreg_high = -1; 340 for (ptr = xtensa_regmap_table; ptr->name; ptr++) 341 { 342 if (ptr->gdb_regnum < xtreg_lo) 343 xtreg_lo = ptr->gdb_regnum; 344 if (ptr->gdb_regnum > xtreg_high) 345 xtreg_high = ptr->gdb_regnum; 346 } 347 348 linux_target = &the_xtensa_linux_nat_target; 349 add_inf_child_target (&the_xtensa_linux_nat_target); 350 } 351