1 /* Xtensa GNU/Linux native support.
3 Copyright (C) 2007-2024 Free Software Foundation, Inc.
5 This file is part of GDB.
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.
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.
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/>. */
25 #include "linux-nat.h"
26 #include <sys/types.h>
29 #include <sys/ioctl.h>
30 #include "gdbsupport/gdb_wait.h"
32 #include <sys/procfs.h>
33 #include "nat/gdb_ptrace.h"
34 #include <asm/ptrace.h>
37 #include "xtensa-tdep.h"
39 /* Defines ps_err_e, struct ps_prochandle. */
40 #include "gdb_proc_service.h"
42 /* Extended register set depends on hardware configs.
43 Keeping these definitions separately allows to introduce
44 hardware-specific overlays. */
45 #include "xtensa-xtregs.c"
47 class xtensa_linux_nat_target final
: public linux_nat_target
50 /* Add our register access methods. */
51 void fetch_registers (struct regcache
*, int) override
;
52 void store_registers (struct regcache
*, int) override
;
55 static xtensa_linux_nat_target the_xtensa_linux_nat_target
;
58 fill_gregset (const struct regcache
*regcache
,
59 gdb_gregset_t
*gregsetp
, int regnum
)
62 xtensa_elf_gregset_t
*regs
= (xtensa_elf_gregset_t
*) gregsetp
;
63 struct gdbarch
*gdbarch
= regcache
->arch ();
64 xtensa_gdbarch_tdep
*tdep
= gdbarch_tdep
<xtensa_gdbarch_tdep
> (gdbarch
);
66 if (regnum
== gdbarch_pc_regnum (gdbarch
) || regnum
== -1)
67 regcache
->raw_collect (gdbarch_pc_regnum (gdbarch
), ®s
->pc
);
68 if (regnum
== gdbarch_ps_regnum (gdbarch
) || regnum
== -1)
69 regcache
->raw_collect (gdbarch_ps_regnum (gdbarch
), ®s
->ps
);
71 if (regnum
== tdep
->wb_regnum
|| regnum
== -1)
72 regcache
->raw_collect (tdep
->wb_regnum
,
74 if (regnum
== tdep
->ws_regnum
|| regnum
== -1)
75 regcache
->raw_collect (tdep
->ws_regnum
,
77 if (regnum
== tdep
->lbeg_regnum
|| regnum
== -1)
78 regcache
->raw_collect (tdep
->lbeg_regnum
,
80 if (regnum
== tdep
->lend_regnum
|| regnum
== -1)
81 regcache
->raw_collect (tdep
->lend_regnum
,
83 if (regnum
== tdep
->lcount_regnum
|| regnum
== -1)
84 regcache
->raw_collect (tdep
->lcount_regnum
,
86 if (regnum
== tdep
->sar_regnum
|| regnum
== -1)
87 regcache
->raw_collect (tdep
->sar_regnum
,
89 if (regnum
== tdep
->threadptr_regnum
|| regnum
== -1)
90 regcache
->raw_collect (tdep
->threadptr_regnum
,
92 if (regnum
>=tdep
->ar_base
93 && regnum
< tdep
->ar_base
95 regcache
->raw_collect (regnum
,
96 ®s
->ar
[regnum
- tdep
->ar_base
]);
97 else if (regnum
== -1)
99 for (i
= 0; i
< tdep
->num_aregs
; ++i
)
100 regcache
->raw_collect (tdep
->ar_base
+ i
,
103 if (regnum
>= tdep
->a0_base
104 && regnum
< tdep
->a0_base
+ C0_NREGS
)
105 regcache
->raw_collect (regnum
,
106 ®s
->ar
[(4 * regs
->windowbase
+ regnum
109 else if (regnum
== -1)
111 for (i
= 0; i
< C0_NREGS
; ++i
)
112 regcache
->raw_collect (tdep
->a0_base
+ i
,
113 (®s
->ar
[(4 * regs
->windowbase
+ i
)
114 % tdep
->num_aregs
]));
119 supply_gregset_reg (struct regcache
*regcache
,
120 const gdb_gregset_t
*gregsetp
, int regnum
)
123 xtensa_elf_gregset_t
*regs
= (xtensa_elf_gregset_t
*) gregsetp
;
125 struct gdbarch
*gdbarch
= regcache
->arch ();
126 xtensa_gdbarch_tdep
*tdep
= gdbarch_tdep
<xtensa_gdbarch_tdep
> (gdbarch
);
128 if (regnum
== gdbarch_pc_regnum (gdbarch
) || regnum
== -1)
129 regcache
->raw_supply (gdbarch_pc_regnum (gdbarch
), ®s
->pc
);
130 if (regnum
== gdbarch_ps_regnum (gdbarch
) || regnum
== -1)
131 regcache
->raw_supply (gdbarch_ps_regnum (gdbarch
), ®s
->ps
);
133 if (regnum
== tdep
->wb_regnum
|| regnum
== -1)
134 regcache
->raw_supply (tdep
->wb_regnum
,
136 if (regnum
== tdep
->ws_regnum
|| regnum
== -1)
137 regcache
->raw_supply (tdep
->ws_regnum
,
139 if (regnum
== tdep
->lbeg_regnum
|| regnum
== -1)
140 regcache
->raw_supply (tdep
->lbeg_regnum
,
142 if (regnum
== tdep
->lend_regnum
|| regnum
== -1)
143 regcache
->raw_supply (tdep
->lend_regnum
,
145 if (regnum
== tdep
->lcount_regnum
|| regnum
== -1)
146 regcache
->raw_supply (tdep
->lcount_regnum
,
148 if (regnum
== tdep
->sar_regnum
|| regnum
== -1)
149 regcache
->raw_supply (tdep
->sar_regnum
,
151 if (regnum
== tdep
->threadptr_regnum
|| regnum
== -1)
152 regcache
->raw_supply (tdep
->threadptr_regnum
,
154 if (regnum
>=tdep
->ar_base
155 && regnum
< tdep
->ar_base
157 regcache
->raw_supply (regnum
,
158 ®s
->ar
[regnum
- tdep
->ar_base
]);
159 else if (regnum
== -1)
161 for (i
= 0; i
< tdep
->num_aregs
; ++i
)
162 regcache
->raw_supply (tdep
->ar_base
+ i
,
165 if (regnum
>= tdep
->a0_base
166 && regnum
< tdep
->a0_base
+ C0_NREGS
)
167 regcache
->raw_supply (regnum
,
168 ®s
->ar
[(4 * regs
->windowbase
+ regnum
171 else if (regnum
== -1)
173 for (i
= 0; i
< C0_NREGS
; ++i
)
174 regcache
->raw_supply (tdep
->a0_base
+ i
,
175 ®s
->ar
[(4 * regs
->windowbase
+ i
)
181 supply_gregset (struct regcache
*regcache
, const gdb_gregset_t
*gregsetp
)
183 supply_gregset_reg (regcache
, gregsetp
, -1);
187 fill_fpregset (const struct regcache
*regcache
,
188 gdb_fpregset_t
*fpregsetp
, int regnum
)
194 supply_fpregset (struct regcache
*regcache
,
195 const gdb_fpregset_t
*fpregsetp
)
200 /* Fetch greg-register(s) from process/thread TID
201 and store value(s) in GDB's register array. */
204 fetch_gregs (struct regcache
*regcache
, int regnum
)
206 int tid
= regcache
->ptid ().lwp ();
209 if (ptrace (PTRACE_GETREGS
, tid
, 0, (long) ®s
) < 0)
211 perror_with_name (_("Couldn't get registers"));
215 supply_gregset_reg (regcache
, ®s
, regnum
);
218 /* Store greg-register(s) in GDB's register
219 array into the process/thread specified by TID. */
222 store_gregs (struct regcache
*regcache
, int regnum
)
224 int tid
= regcache
->ptid ().lwp ();
227 if (ptrace (PTRACE_GETREGS
, tid
, 0, (long) ®s
) < 0)
229 perror_with_name (_("Couldn't get registers"));
233 fill_gregset (regcache
, ®s
, regnum
);
235 if (ptrace (PTRACE_SETREGS
, tid
, 0, (long) ®s
) < 0)
237 perror_with_name (_("Couldn't write registers"));
243 static int xtreg_high
;
245 /* Fetch/Store Xtensa TIE registers. Xtensa GNU/Linux PTRACE
246 interface provides special requests for this. */
249 fetch_xtregs (struct regcache
*regcache
, int regnum
)
251 int tid
= regcache
->ptid ().lwp ();
252 const xtensa_regtable_t
*ptr
;
253 char xtregs
[XTENSA_ELF_XTREG_SIZE
];
255 if (ptrace (PTRACE_GETXTREGS
, tid
, 0, (long)&xtregs
) < 0)
256 perror_with_name (_("Couldn't get extended registers"));
258 for (ptr
= xtensa_regmap_table
; ptr
->name
; ptr
++)
259 if (regnum
== ptr
->gdb_regnum
|| regnum
== -1)
260 regcache
->raw_supply (ptr
->gdb_regnum
, xtregs
+ ptr
->ptrace_offset
);
264 store_xtregs (struct regcache
*regcache
, int regnum
)
266 int tid
= regcache
->ptid ().lwp ();
267 const xtensa_regtable_t
*ptr
;
268 char xtregs
[XTENSA_ELF_XTREG_SIZE
];
270 if (ptrace (PTRACE_GETXTREGS
, tid
, 0, (long)&xtregs
) < 0)
271 perror_with_name (_("Couldn't get extended registers"));
273 for (ptr
= xtensa_regmap_table
; ptr
->name
; ptr
++)
274 if (regnum
== ptr
->gdb_regnum
|| regnum
== -1)
275 regcache
->raw_collect (ptr
->gdb_regnum
, xtregs
+ ptr
->ptrace_offset
);
277 if (ptrace (PTRACE_SETXTREGS
, tid
, 0, (long)&xtregs
) < 0)
278 perror_with_name (_("Couldn't write extended registers"));
282 xtensa_linux_nat_target::fetch_registers (struct regcache
*regcache
,
287 fetch_gregs (regcache
, regnum
);
288 fetch_xtregs (regcache
, regnum
);
290 else if ((regnum
< xtreg_lo
) || (regnum
> xtreg_high
))
291 fetch_gregs (regcache
, regnum
);
293 fetch_xtregs (regcache
, regnum
);
297 xtensa_linux_nat_target::store_registers (struct regcache
*regcache
,
302 store_gregs (regcache
, regnum
);
303 store_xtregs (regcache
, regnum
);
305 else if ((regnum
< xtreg_lo
) || (regnum
> xtreg_high
))
306 store_gregs (regcache
, regnum
);
308 store_xtregs (regcache
, regnum
);
311 /* Called by libthread_db. */
314 ps_get_thread_area (struct ps_prochandle
*ph
,
315 lwpid_t lwpid
, int idx
, void **base
)
317 xtensa_elf_gregset_t regs
;
319 if (ptrace (PTRACE_GETREGS
, lwpid
, NULL
, ®s
) != 0)
322 /* IDX is the bias from the thread pointer to the beginning of the
323 thread descriptor. It has to be subtracted due to implementation
324 quirks in libthread_db. */
325 *base
= (void *) ((char *) regs
.threadptr
- idx
);
330 void _initialize_xtensa_linux_nat ();
332 _initialize_xtensa_linux_nat ()
334 const xtensa_regtable_t
*ptr
;
336 /* Calculate the number range for extended registers. */
337 xtreg_lo
= 1000000000;
339 for (ptr
= xtensa_regmap_table
; ptr
->name
; ptr
++)
341 if (ptr
->gdb_regnum
< xtreg_lo
)
342 xtreg_lo
= ptr
->gdb_regnum
;
343 if (ptr
->gdb_regnum
> xtreg_high
)
344 xtreg_high
= ptr
->gdb_regnum
;
347 linux_target
= &the_xtensa_linux_nat_target
;
348 add_inf_child_target (&the_xtensa_linux_nat_target
);