gdb: add cmd_list_element::is_command_class_help
[deliverable/binutils-gdb.git] / gdb / sparc-nat.c
CommitLineData
386c036b 1/* Native-dependent code for SPARC.
2555fe1a 2
3666a048 3 Copyright (C) 2003-2021 Free Software Foundation, Inc.
c906108c 4
c5aa993b 5 This file is part of GDB.
c906108c 6
c5aa993b
JM
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
a9762ec7 9 the Free Software Foundation; either version 3 of the License, or
c5aa993b 10 (at your option) any later version.
c906108c 11
c5aa993b
JM
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.
c906108c 16
c5aa993b 17 You should have received a copy of the GNU General Public License
a9762ec7 18 along with this program. If not, see <http://www.gnu.org/licenses/>. */
c906108c
SS
19
20#include "defs.h"
21#include "inferior.h"
4e052eda 22#include "regcache.h"
baf92889 23#include "target.h"
c906108c
SS
24
25#include <signal.h>
26#include <sys/ptrace.h>
268a13a5 27#include "gdbsupport/gdb_wait.h"
386c036b 28#ifdef HAVE_MACHINE_REG_H
c906108c
SS
29#include <machine/reg.h>
30#endif
c906108c 31
386c036b
MK
32#include "sparc-tdep.h"
33#include "sparc-nat.h"
1b9445c2 34#include "inf-ptrace.h"
386c036b
MK
35
36/* With some trickery we can use the code in this file for most (if
37 not all) ptrace(2) based SPARC systems, which includes SunOS 4,
1a111ce3 38 GNU/Linux and the various SPARC BSD's.
386c036b
MK
39
40 First, we need a data structure for use with ptrace(2). SunOS has
41 `struct regs' and `struct fp_status' in <machine/reg.h>. BSD's
42 have `struct reg' and `struct fpreg' in <machine/reg.h>. GNU/Linux
43 has the same structures as SunOS 4, but they're in <asm/reg.h>,
44 which is a kernel header. As a general rule we avoid including
45 GNU/Linux kernel headers. Fortunately GNU/Linux has a `gregset_t'
46 and a `fpregset_t' that are equivalent to `struct regs' and `struct
47 fp_status' in <sys/ucontext.h>, which is automatically included by
48 <signal.h>. Settling on using the `gregset_t' and `fpregset_t'
49 typedefs, providing them for the other systems, therefore solves
50 the puzzle. */
51
52#ifdef HAVE_MACHINE_REG_H
53#ifdef HAVE_STRUCT_REG
54typedef struct reg gregset_t;
55typedef struct fpreg fpregset_t;
56#else
57typedef struct regs gregset_t;
58typedef struct fp_status fpregset_t;
59#endif
60#endif
61
62/* Second, we need to remap the BSD ptrace(2) requests to their SunOS
63 equivalents. GNU/Linux already follows SunOS here. */
c906108c 64
386c036b
MK
65#ifndef PTRACE_GETREGS
66#define PTRACE_GETREGS PT_GETREGS
67#endif
68
69#ifndef PTRACE_SETREGS
70#define PTRACE_SETREGS PT_SETREGS
71#endif
c906108c 72
386c036b
MK
73#ifndef PTRACE_GETFPREGS
74#define PTRACE_GETFPREGS PT_GETFPREGS
75#endif
76
77#ifndef PTRACE_SETFPREGS
78#define PTRACE_SETFPREGS PT_SETFPREGS
79#endif
80
1ff700c2 81static PTRACE_TYPE_RET
2108a63a
KR
82gdb_ptrace (PTRACE_TYPE_ARG1 request, ptid_t ptid, PTRACE_TYPE_ARG3 addr)
83{
84#ifdef __NetBSD__
85 /* Support for NetBSD threads: unlike other ptrace implementations in this
86 file, NetBSD requires that we pass both the pid and lwp. */
87 return ptrace (request, ptid.pid (), addr, ptid.lwp ());
88#else
89 pid_t pid = get_ptrace_pid (ptid);
90 return ptrace (request, pid, addr, 0);
91#endif
92}
93
386c036b 94/* Register set description. */
b4fd25c9
AA
95const struct sparc_gregmap *sparc_gregmap;
96const struct sparc_fpregmap *sparc_fpregmap;
97void (*sparc_supply_gregset) (const struct sparc_gregmap *,
386c036b 98 struct regcache *, int , const void *);
b4fd25c9 99void (*sparc_collect_gregset) (const struct sparc_gregmap *,
386c036b 100 const struct regcache *, int, void *);
b4fd25c9 101void (*sparc_supply_fpregset) (const struct sparc_fpregmap *,
db75c717 102 struct regcache *, int , const void *);
b4fd25c9 103void (*sparc_collect_fpregset) (const struct sparc_fpregmap *,
db75c717 104 const struct regcache *, int , void *);
ec22ec34
UW
105int (*sparc_gregset_supplies_p) (struct gdbarch *, int);
106int (*sparc_fpregset_supplies_p) (struct gdbarch *, int);
386c036b
MK
107
108/* Determine whether `gregset_t' contains register REGNUM. */
109
110int
ec22ec34 111sparc32_gregset_supplies_p (struct gdbarch *gdbarch, int regnum)
386c036b
MK
112{
113 /* Integer registers. */
114 if ((regnum >= SPARC_G1_REGNUM && regnum <= SPARC_G7_REGNUM)
115 || (regnum >= SPARC_O0_REGNUM && regnum <= SPARC_O7_REGNUM)
116 || (regnum >= SPARC_L0_REGNUM && regnum <= SPARC_L7_REGNUM)
117 || (regnum >= SPARC_I0_REGNUM && regnum <= SPARC_I7_REGNUM))
118 return 1;
119
120 /* Control registers. */
121 if (regnum == SPARC32_PC_REGNUM
122 || regnum == SPARC32_NPC_REGNUM
123 || regnum == SPARC32_PSR_REGNUM
124 || regnum == SPARC32_Y_REGNUM)
125 return 1;
126
127 return 0;
128}
129
130/* Determine whether `fpregset_t' contains register REGNUM. */
131
132int
ec22ec34 133sparc32_fpregset_supplies_p (struct gdbarch *gdbarch, int regnum)
386c036b
MK
134{
135 /* Floating-point registers. */
136 if (regnum >= SPARC_F0_REGNUM && regnum <= SPARC_F31_REGNUM)
137 return 1;
138
139 /* Control registers. */
140 if (regnum == SPARC32_FSR_REGNUM)
141 return 1;
142
143 return 0;
144}
145
146/* Fetch register REGNUM from the inferior. If REGNUM is -1, do this
147 for all registers (including the floating-point registers). */
c906108c
SS
148
149void
d1e93af6
SM
150sparc_fetch_inferior_registers (process_stratum_target *proc_target,
151 regcache *regcache, int regnum)
c906108c 152{
ac7936df 153 struct gdbarch *gdbarch = regcache->arch ();
2108a63a 154 ptid_t ptid = regcache->ptid ();
02ae7771 155
386c036b 156 if (regnum == SPARC_G0_REGNUM)
c906108c 157 {
22e74ef9
MK
158 gdb_byte zero[8] = { 0 };
159
73e1c03f 160 regcache->raw_supply (SPARC_G0_REGNUM, &zero);
386c036b 161 return;
c906108c
SS
162 }
163
ec22ec34 164 if (regnum == -1 || sparc_gregset_supplies_p (gdbarch, regnum))
c906108c 165 {
386c036b 166 gregset_t regs;
c906108c 167
2108a63a 168 if (gdb_ptrace (PTRACE_GETREGS, ptid, (PTRACE_TYPE_ARG3) &regs) == -1)
e2e0b3e5 169 perror_with_name (_("Couldn't get registers"));
386c036b 170
d1e93af6
SM
171 /* Deep down, sparc_supply_rwindow reads memory, so needs the global
172 thread context to be set. */
173 thread_info *thread = find_thread_ptid (proc_target, ptid);
174 scoped_restore_current_thread restore_thread;
175 switch_to_thread (thread);
176
b4fd25c9 177 sparc_supply_gregset (sparc_gregmap, regcache, -1, &regs);
386c036b
MK
178 if (regnum != -1)
179 return;
c906108c 180 }
386c036b 181
ec22ec34 182 if (regnum == -1 || sparc_fpregset_supplies_p (gdbarch, regnum))
c906108c 183 {
386c036b
MK
184 fpregset_t fpregs;
185
2108a63a 186 if (gdb_ptrace (PTRACE_GETFPREGS, ptid, (PTRACE_TYPE_ARG3) &fpregs) == -1)
e2e0b3e5 187 perror_with_name (_("Couldn't get floating point status"));
386c036b 188
b4fd25c9 189 sparc_supply_fpregset (sparc_fpregmap, regcache, -1, &fpregs);
c906108c
SS
190 }
191}
192
c906108c 193void
d1e93af6
SM
194sparc_store_inferior_registers (process_stratum_target *proc_target,
195 regcache *regcache, int regnum)
c906108c 196{
ac7936df 197 struct gdbarch *gdbarch = regcache->arch ();
2108a63a 198 ptid_t ptid = regcache->ptid ();
c906108c 199
ec22ec34 200 if (regnum == -1 || sparc_gregset_supplies_p (gdbarch, regnum))
e1925118 201 {
386c036b 202 gregset_t regs;
c906108c 203
2108a63a 204 if (gdb_ptrace (PTRACE_GETREGS, ptid, (PTRACE_TYPE_ARG3) &regs) == -1)
e2e0b3e5 205 perror_with_name (_("Couldn't get registers"));
c906108c 206
b4fd25c9 207 sparc_collect_gregset (sparc_gregmap, regcache, regnum, &regs);
c906108c 208
2108a63a 209 if (gdb_ptrace (PTRACE_SETREGS, ptid, (PTRACE_TYPE_ARG3) &regs) == -1)
e2e0b3e5 210 perror_with_name (_("Couldn't write registers"));
c5aa993b 211
386c036b
MK
212 /* Deal with the stack regs. */
213 if (regnum == -1 || regnum == SPARC_SP_REGNUM
214 || (regnum >= SPARC_L0_REGNUM && regnum <= SPARC_I7_REGNUM))
215 {
216 ULONGEST sp;
c906108c 217
386c036b 218 regcache_cooked_read_unsigned (regcache, SPARC_SP_REGNUM, &sp);
d1e93af6
SM
219
220 /* Deep down, sparc_collect_rwindow writes memory, so needs the global
221 thread context to be set. */
222 thread_info *thread = find_thread_ptid (proc_target, ptid);
223 scoped_restore_current_thread restore_thread;
224 switch_to_thread (thread);
225
386c036b
MK
226 sparc_collect_rwindow (regcache, sp, regnum);
227 }
c906108c 228
386c036b
MK
229 if (regnum != -1)
230 return;
c906108c 231 }
c906108c 232
ec22ec34 233 if (regnum == -1 || sparc_fpregset_supplies_p (gdbarch, regnum))
c5aa993b 234 {
386c036b 235 fpregset_t fpregs, saved_fpregs;
c906108c 236
2108a63a 237 if (gdb_ptrace (PTRACE_GETFPREGS, ptid, (PTRACE_TYPE_ARG3) &fpregs) == -1)
e2e0b3e5 238 perror_with_name (_("Couldn't get floating-point registers"));
c906108c 239
386c036b 240 memcpy (&saved_fpregs, &fpregs, sizeof (fpregs));
b4fd25c9 241 sparc_collect_fpregset (sparc_fpregmap, regcache, regnum, &fpregs);
c906108c 242
386c036b
MK
243 /* Writing the floating-point registers will fail on NetBSD with
244 EINVAL if the inferior process doesn't have an FPU state
245 (i.e. if it didn't use the FPU yet). Therefore we don't try
246 to write the registers if nothing changed. */
247 if (memcmp (&saved_fpregs, &fpregs, sizeof (fpregs)) != 0)
c5aa993b 248 {
2108a63a
KR
249 if (gdb_ptrace (PTRACE_SETFPREGS, ptid,
250 (PTRACE_TYPE_ARG3) &fpregs) == -1)
e2e0b3e5 251 perror_with_name (_("Couldn't write floating-point registers"));
c5aa993b 252 }
c906108c 253
386c036b
MK
254 if (regnum != -1)
255 return;
256 }
c906108c 257}
baf92889 258
c906108c 259\f
edcc890f
YQ
260/* Implement the to_xfer_partial target_ops method for
261 TARGET_OBJECT_WCOOKIE. Fetch StackGhost Per-Process XOR cookie. */
baf92889 262
f6ac5f3d 263enum target_xfer_status
cadc9cb8 264sparc_xfer_wcookie (enum target_object object,
961cb7b5 265 const char *annex, gdb_byte *readbuf,
9b409511
YQ
266 const gdb_byte *writebuf, ULONGEST offset, ULONGEST len,
267 ULONGEST *xfered_len)
baf92889
MK
268{
269 unsigned long wcookie = 0;
270 char *buf = (char *)&wcookie;
271
272 gdb_assert (object == TARGET_OBJECT_WCOOKIE);
273 gdb_assert (readbuf && writebuf == NULL);
274
2c9771d3 275 if (offset == sizeof (unsigned long))
9b409511 276 return TARGET_XFER_EOF; /* Signal EOF. */
2c9771d3 277 if (offset > sizeof (unsigned long))
2ed4b548 278 return TARGET_XFER_E_IO;
c5aa993b 279
baf92889
MK
280#ifdef PT_WCOOKIE
281 /* If PT_WCOOKIE is defined (by <sys/ptrace.h>), assume we're
282 running on an OpenBSD release that uses StackGhost (3.1 or
2c9771d3
MK
283 later). Since release 3.6, OpenBSD uses a fully randomized
284 cookie. */
645d6d10 285 {
e99b03dc 286 int pid = inferior_ptid.pid ();
645d6d10
MK
287
288 /* Sanity check. The proper type for a cookie is register_t, but
289 we can't assume that this type exists on all systems supported
290 by the code in this file. */
291 gdb_assert (sizeof (wcookie) == sizeof (register_t));
292
293 /* Fetch the cookie. */
49ec097f 294 if (ptrace (PT_WCOOKIE, pid, (PTRACE_TYPE_ARG3) &wcookie, 0) == -1)
645d6d10
MK
295 {
296 if (errno != EINVAL)
e2e0b3e5 297 perror_with_name (_("Couldn't get StackGhost cookie"));
645d6d10
MK
298
299 /* Although PT_WCOOKIE is defined on OpenBSD 3.1 and later,
300 the request wasn't implemented until after OpenBSD 3.4. If
301 the kernel doesn't support the PT_WCOOKIE request, assume
302 we're running on a kernel that uses non-randomized cookies. */
303 wcookie = 0x3;
304 }
305 }
baf92889
MK
306#endif /* PT_WCOOKIE */
307
308 if (len > sizeof (unsigned long) - offset)
309 len = sizeof (unsigned long) - offset;
310
311 memcpy (readbuf, buf + offset, len);
9b409511
YQ
312 *xfered_len = (ULONGEST) len;
313 return TARGET_XFER_OK;
baf92889 314}
1b9445c2 315\f
baf92889 316
6c265988 317void _initialize_sparc_nat ();
c906108c 318void
6c265988 319_initialize_sparc_nat ()
c906108c 320{
405feb71 321 /* Default to using SunOS 4 register sets. */
b4fd25c9
AA
322 if (sparc_gregmap == NULL)
323 sparc_gregmap = &sparc32_sunos4_gregmap;
324 if (sparc_fpregmap == NULL)
325 sparc_fpregmap = &sparc32_sunos4_fpregmap;
386c036b
MK
326 if (sparc_supply_gregset == NULL)
327 sparc_supply_gregset = sparc32_supply_gregset;
328 if (sparc_collect_gregset == NULL)
329 sparc_collect_gregset = sparc32_collect_gregset;
330 if (sparc_supply_fpregset == NULL)
331 sparc_supply_fpregset = sparc32_supply_fpregset;
332 if (sparc_collect_fpregset == NULL)
333 sparc_collect_fpregset = sparc32_collect_fpregset;
334 if (sparc_gregset_supplies_p == NULL)
335 sparc_gregset_supplies_p = sparc32_gregset_supplies_p;
336 if (sparc_fpregset_supplies_p == NULL)
337 sparc_fpregset_supplies_p = sparc32_fpregset_supplies_p;
c906108c 338}
This page took 2.218125 seconds and 4 git commands to generate.