]>
Commit | Line | Data |
---|---|---|
1 | /* PPC GNU/Linux native support. | |
2 | Copyright 1988, 1989, 1991, 1992, 1994, 1996, 2000, 2001, 2002 | |
3 | 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 2 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, write to the Free Software | |
19 | Foundation, Inc., 59 Temple Place - Suite 330, | |
20 | Boston, MA 02111-1307, USA. */ | |
21 | ||
22 | #include "defs.h" | |
23 | #include "gdb_string.h" | |
24 | #include "frame.h" | |
25 | #include "inferior.h" | |
26 | #include "gdbcore.h" | |
27 | #include "regcache.h" | |
28 | ||
29 | #include <sys/types.h> | |
30 | #include <sys/param.h> | |
31 | #include <signal.h> | |
32 | #include <sys/user.h> | |
33 | #include <sys/ioctl.h> | |
34 | #include <sys/wait.h> | |
35 | #include <fcntl.h> | |
36 | #include <sys/procfs.h> | |
37 | #include <sys/ptrace.h> | |
38 | ||
39 | /* Prototypes for supply_gregset etc. */ | |
40 | #include "gregset.h" | |
41 | #include "ppc-tdep.h" | |
42 | ||
43 | #ifndef PT_READ_U | |
44 | #define PT_READ_U PTRACE_PEEKUSR | |
45 | #endif | |
46 | #ifndef PT_WRITE_U | |
47 | #define PT_WRITE_U PTRACE_POKEUSR | |
48 | #endif | |
49 | ||
50 | /* Default the type of the ptrace transfer to int. */ | |
51 | #ifndef PTRACE_XFER_TYPE | |
52 | #define PTRACE_XFER_TYPE int | |
53 | #endif | |
54 | ||
55 | /* Glibc's headers don't define PTRACE_GETVRREGS so we cannot use a | |
56 | configure time check. Some older glibc's (for instance 2.2.1) | |
57 | don't have a specific powerpc version of ptrace.h, and fall back on | |
58 | a generic one. In such cases, sys/ptrace.h defines | |
59 | PTRACE_GETFPXREGS and PTRACE_SETFPXREGS to the same numbers that | |
60 | ppc kernel's asm/ptrace.h defines PTRACE_GETVRREGS and | |
61 | PTRACE_SETVRREGS to be. This also makes a configury check pretty | |
62 | much useless. */ | |
63 | ||
64 | /* These definitions should really come from the glibc header files, | |
65 | but Glibc doesn't know about the vrregs yet. */ | |
66 | #ifndef PTRACE_GETVRREGS | |
67 | #define PTRACE_GETVRREGS 18 | |
68 | #define PTRACE_SETVRREGS 19 | |
69 | #endif | |
70 | ||
71 | /* This oddity is because the Linux kernel defines elf_vrregset_t as | |
72 | an array of 33 16 bytes long elements. I.e. it leaves out vrsave. | |
73 | However the PTRACE_GETVRREGS and PTRACE_SETVRREGS requests return | |
74 | the vrsave as an extra 4 bytes at the end. I opted for creating a | |
75 | flat array of chars, so that it is easier to manipulate for gdb. | |
76 | ||
77 | There are 32 vector registers 16 bytes longs, plus a VSCR register | |
78 | which is only 4 bytes long, but is fetched as a 16 bytes | |
79 | quantity. Up to here we have the elf_vrregset_t structure. | |
80 | Appended to this there is space for the VRSAVE register: 4 bytes. | |
81 | Even though this vrsave register is not included in the regset | |
82 | typedef, it is handled by the ptrace requests. | |
83 | ||
84 | Note that GNU/Linux doesn't support little endian PPC hardware, | |
85 | therefore the offset at which the real value of the VSCR register | |
86 | is located will be always 12 bytes. | |
87 | ||
88 | The layout is like this (where x is the actual value of the vscr reg): */ | |
89 | ||
90 | /* *INDENT-OFF* */ | |
91 | /* | |
92 | |.|.|.|.|.....|.|.|.|.||.|.|.|x||.| | |
93 | <-------> <-------><-------><-> | |
94 | VR0 VR31 VSCR VRSAVE | |
95 | */ | |
96 | /* *INDENT-ON* */ | |
97 | ||
98 | #define SIZEOF_VRREGS 33*16+4 | |
99 | ||
100 | typedef char gdb_vrregset_t[SIZEOF_VRREGS]; | |
101 | ||
102 | /* For runtime check of ptrace support for VRREGS. */ | |
103 | int have_ptrace_getvrregs = 1; | |
104 | ||
105 | int | |
106 | kernel_u_size (void) | |
107 | { | |
108 | return (sizeof (struct user)); | |
109 | } | |
110 | ||
111 | /* *INDENT-OFF* */ | |
112 | /* registers layout, as presented by the ptrace interface: | |
113 | PT_R0, PT_R1, PT_R2, PT_R3, PT_R4, PT_R5, PT_R6, PT_R7, | |
114 | PT_R8, PT_R9, PT_R10, PT_R11, PT_R12, PT_R13, PT_R14, PT_R15, | |
115 | PT_R16, PT_R17, PT_R18, PT_R19, PT_R20, PT_R21, PT_R22, PT_R23, | |
116 | PT_R24, PT_R25, PT_R26, PT_R27, PT_R28, PT_R29, PT_R30, PT_R31, | |
117 | PT_FPR0, PT_FPR0 + 2, PT_FPR0 + 4, PT_FPR0 + 6, PT_FPR0 + 8, PT_FPR0 + 10, PT_FPR0 + 12, PT_FPR0 + 14, | |
118 | PT_FPR0 + 16, PT_FPR0 + 18, PT_FPR0 + 20, PT_FPR0 + 22, PT_FPR0 + 24, PT_FPR0 + 26, PT_FPR0 + 28, PT_FPR0 + 30, | |
119 | PT_FPR0 + 32, PT_FPR0 + 34, PT_FPR0 + 36, PT_FPR0 + 38, PT_FPR0 + 40, PT_FPR0 + 42, PT_FPR0 + 44, PT_FPR0 + 46, | |
120 | PT_FPR0 + 48, PT_FPR0 + 50, PT_FPR0 + 52, PT_FPR0 + 54, PT_FPR0 + 56, PT_FPR0 + 58, PT_FPR0 + 60, PT_FPR0 + 62, | |
121 | PT_NIP, PT_MSR, PT_CCR, PT_LNK, PT_CTR, PT_XER, PT_MQ */ | |
122 | /* *INDENT_ON * */ | |
123 | ||
124 | static int | |
125 | ppc_register_u_addr (int regno) | |
126 | { | |
127 | int u_addr = -1; | |
128 | struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch); | |
129 | ||
130 | /* General purpose registers occupy 1 slot each in the buffer */ | |
131 | if (regno >= tdep->ppc_gp0_regnum && regno <= tdep->ppc_gplast_regnum ) | |
132 | u_addr = ((PT_R0 + regno) * 4); | |
133 | ||
134 | /* Floating point regs: 2 slots each */ | |
135 | if (regno >= FP0_REGNUM && regno <= FPLAST_REGNUM) | |
136 | u_addr = ((PT_FPR0 + (regno - FP0_REGNUM) * 2) * 4); | |
137 | ||
138 | /* UISA special purpose registers: 1 slot each */ | |
139 | if (regno == PC_REGNUM) | |
140 | u_addr = PT_NIP * 4; | |
141 | if (regno == tdep->ppc_lr_regnum) | |
142 | u_addr = PT_LNK * 4; | |
143 | if (regno == tdep->ppc_cr_regnum) | |
144 | u_addr = PT_CCR * 4; | |
145 | if (regno == tdep->ppc_xer_regnum) | |
146 | u_addr = PT_XER * 4; | |
147 | if (regno == tdep->ppc_ctr_regnum) | |
148 | u_addr = PT_CTR * 4; | |
149 | if (regno == tdep->ppc_mq_regnum) | |
150 | u_addr = PT_MQ * 4; | |
151 | if (regno == tdep->ppc_ps_regnum) | |
152 | u_addr = PT_MSR * 4; | |
153 | if (regno == tdep->ppc_fpscr_regnum) | |
154 | u_addr = PT_FPSCR * 4; | |
155 | ||
156 | return u_addr; | |
157 | } | |
158 | ||
159 | static int | |
160 | ppc_ptrace_cannot_fetch_store_register (int regno) | |
161 | { | |
162 | return (ppc_register_u_addr (regno) == -1); | |
163 | } | |
164 | ||
165 | /* The Linux kernel ptrace interface for AltiVec registers uses the | |
166 | registers set mechanism, as opposed to the interface for all the | |
167 | other registers, that stores/fetches each register individually. */ | |
168 | static void | |
169 | fetch_altivec_register (int tid, int regno) | |
170 | { | |
171 | int ret; | |
172 | int offset = 0; | |
173 | gdb_vrregset_t regs; | |
174 | struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch); | |
175 | int vrregsize = REGISTER_RAW_SIZE (tdep->ppc_vr0_regnum); | |
176 | ||
177 | ret = ptrace (PTRACE_GETVRREGS, tid, 0, ®s); | |
178 | if (ret < 0) | |
179 | { | |
180 | if (errno == EIO) | |
181 | { | |
182 | have_ptrace_getvrregs = 0; | |
183 | return; | |
184 | } | |
185 | perror_with_name ("Unable to fetch AltiVec register"); | |
186 | } | |
187 | ||
188 | /* VSCR is fetched as a 16 bytes quantity, but it is really 4 bytes | |
189 | long on the hardware. We deal only with the lower 4 bytes of the | |
190 | vector. VRSAVE is at the end of the array in a 4 bytes slot, so | |
191 | there is no need to define an offset for it. */ | |
192 | if (regno == (tdep->ppc_vrsave_regnum - 1)) | |
193 | offset = vrregsize - REGISTER_RAW_SIZE (tdep->ppc_vrsave_regnum); | |
194 | ||
195 | supply_register (regno, | |
196 | regs + (regno - tdep->ppc_vr0_regnum) * vrregsize + offset); | |
197 | } | |
198 | ||
199 | static void | |
200 | fetch_register (int tid, int regno) | |
201 | { | |
202 | /* This isn't really an address. But ptrace thinks of it as one. */ | |
203 | char mess[128]; /* For messages */ | |
204 | register int i; | |
205 | unsigned int offset; /* Offset of registers within the u area. */ | |
206 | char *buf = alloca (MAX_REGISTER_RAW_SIZE); | |
207 | CORE_ADDR regaddr = ppc_register_u_addr (regno); | |
208 | ||
209 | if (altivec_register_p (regno)) | |
210 | { | |
211 | /* If this is the first time through, or if it is not the first | |
212 | time through, and we have comfirmed that there is kernel | |
213 | support for such a ptrace request, then go and fetch the | |
214 | register. */ | |
215 | if (have_ptrace_getvrregs) | |
216 | { | |
217 | fetch_altivec_register (tid, regno); | |
218 | return; | |
219 | } | |
220 | /* If we have discovered that there is no ptrace support for | |
221 | AltiVec registers, fall through and return zeroes, because | |
222 | regaddr will be -1 in this case. */ | |
223 | } | |
224 | ||
225 | if (regaddr == -1) | |
226 | { | |
227 | memset (buf, '\0', REGISTER_RAW_SIZE (regno)); /* Supply zeroes */ | |
228 | supply_register (regno, buf); | |
229 | return; | |
230 | } | |
231 | ||
232 | for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof (PTRACE_XFER_TYPE)) | |
233 | { | |
234 | errno = 0; | |
235 | *(PTRACE_XFER_TYPE *) & buf[i] = ptrace (PT_READ_U, tid, | |
236 | (PTRACE_ARG3_TYPE) regaddr, 0); | |
237 | regaddr += sizeof (PTRACE_XFER_TYPE); | |
238 | if (errno != 0) | |
239 | { | |
240 | sprintf (mess, "reading register %s (#%d)", | |
241 | REGISTER_NAME (regno), regno); | |
242 | perror_with_name (mess); | |
243 | } | |
244 | } | |
245 | supply_register (regno, buf); | |
246 | } | |
247 | ||
248 | static void | |
249 | supply_vrregset (gdb_vrregset_t *vrregsetp) | |
250 | { | |
251 | int i; | |
252 | struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch); | |
253 | int num_of_vrregs = tdep->ppc_vrsave_regnum - tdep->ppc_vr0_regnum + 1; | |
254 | int vrregsize = REGISTER_RAW_SIZE (tdep->ppc_vr0_regnum); | |
255 | int offset = vrregsize - REGISTER_RAW_SIZE (tdep->ppc_vrsave_regnum); | |
256 | ||
257 | for (i = 0; i < num_of_vrregs; i++) | |
258 | { | |
259 | /* The last 2 registers of this set are only 32 bit long, not | |
260 | 128. However an offset is necessary only for VSCR because it | |
261 | occupies a whole vector, while VRSAVE occupies a full 4 bytes | |
262 | slot. */ | |
263 | if (i == (num_of_vrregs - 2)) | |
264 | supply_register (tdep->ppc_vr0_regnum + i, | |
265 | *vrregsetp + i * vrregsize + offset); | |
266 | else | |
267 | supply_register (tdep->ppc_vr0_regnum + i, *vrregsetp + i * vrregsize); | |
268 | } | |
269 | } | |
270 | ||
271 | static void | |
272 | fetch_altivec_registers (int tid) | |
273 | { | |
274 | int ret; | |
275 | gdb_vrregset_t regs; | |
276 | ||
277 | ret = ptrace (PTRACE_GETVRREGS, tid, 0, ®s); | |
278 | if (ret < 0) | |
279 | { | |
280 | if (errno == EIO) | |
281 | { | |
282 | have_ptrace_getvrregs = 0; | |
283 | return; | |
284 | } | |
285 | perror_with_name ("Unable to fetch AltiVec registers"); | |
286 | } | |
287 | supply_vrregset (®s); | |
288 | } | |
289 | ||
290 | static void | |
291 | fetch_ppc_registers (int tid) | |
292 | { | |
293 | int i; | |
294 | struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch); | |
295 | ||
296 | for (i = 0; i <= tdep->ppc_fpscr_regnum; i++) | |
297 | fetch_register (tid, i); | |
298 | if (tdep->ppc_mq_regnum != -1) | |
299 | fetch_register (tid, tdep->ppc_mq_regnum); | |
300 | if (have_ptrace_getvrregs) | |
301 | if (tdep->ppc_vr0_regnum != -1 && tdep->ppc_vrsave_regnum != -1) | |
302 | fetch_altivec_registers (tid); | |
303 | } | |
304 | ||
305 | /* Fetch registers from the child process. Fetch all registers if | |
306 | regno == -1, otherwise fetch all general registers or all floating | |
307 | point registers depending upon the value of regno. */ | |
308 | void | |
309 | fetch_inferior_registers (int regno) | |
310 | { | |
311 | /* Overload thread id onto process id */ | |
312 | int tid = TIDGET (inferior_ptid); | |
313 | ||
314 | /* No thread id, just use process id */ | |
315 | if (tid == 0) | |
316 | tid = PIDGET (inferior_ptid); | |
317 | ||
318 | if (regno == -1) | |
319 | fetch_ppc_registers (tid); | |
320 | else | |
321 | fetch_register (tid, regno); | |
322 | } | |
323 | ||
324 | /* Store one register. */ | |
325 | static void | |
326 | store_altivec_register (int tid, int regno) | |
327 | { | |
328 | int ret; | |
329 | int offset = 0; | |
330 | gdb_vrregset_t regs; | |
331 | struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch); | |
332 | int vrregsize = REGISTER_RAW_SIZE (tdep->ppc_vr0_regnum); | |
333 | ||
334 | ret = ptrace (PTRACE_GETVRREGS, tid, 0, ®s); | |
335 | if (ret < 0) | |
336 | { | |
337 | if (errno == EIO) | |
338 | { | |
339 | have_ptrace_getvrregs = 0; | |
340 | return; | |
341 | } | |
342 | perror_with_name ("Unable to fetch AltiVec register"); | |
343 | } | |
344 | ||
345 | /* VSCR is fetched as a 16 bytes quantity, but it is really 4 bytes | |
346 | long on the hardware. */ | |
347 | if (regno == (tdep->ppc_vrsave_regnum - 1)) | |
348 | offset = vrregsize - REGISTER_RAW_SIZE (tdep->ppc_vrsave_regnum); | |
349 | ||
350 | regcache_collect (regno, | |
351 | regs + (regno - tdep->ppc_vr0_regnum) * vrregsize + offset); | |
352 | ||
353 | ret = ptrace (PTRACE_SETVRREGS, tid, 0, ®s); | |
354 | if (ret < 0) | |
355 | perror_with_name ("Unable to store AltiVec register"); | |
356 | } | |
357 | ||
358 | static void | |
359 | store_register (int tid, int regno) | |
360 | { | |
361 | /* This isn't really an address. But ptrace thinks of it as one. */ | |
362 | CORE_ADDR regaddr = ppc_register_u_addr (regno); | |
363 | char mess[128]; /* For messages */ | |
364 | register int i; | |
365 | unsigned int offset; /* Offset of registers within the u area. */ | |
366 | char *buf = alloca (MAX_REGISTER_RAW_SIZE); | |
367 | ||
368 | if (altivec_register_p (regno)) | |
369 | { | |
370 | store_altivec_register (tid, regno); | |
371 | return; | |
372 | } | |
373 | ||
374 | if (regaddr == -1) | |
375 | return; | |
376 | ||
377 | regcache_collect (regno, buf); | |
378 | for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof (PTRACE_XFER_TYPE)) | |
379 | { | |
380 | errno = 0; | |
381 | ptrace (PT_WRITE_U, tid, (PTRACE_ARG3_TYPE) regaddr, | |
382 | *(PTRACE_XFER_TYPE *) & buf[i]); | |
383 | regaddr += sizeof (PTRACE_XFER_TYPE); | |
384 | ||
385 | if (errno == EIO | |
386 | && regno == gdbarch_tdep (current_gdbarch)->ppc_fpscr_regnum) | |
387 | { | |
388 | /* Some older kernel versions don't allow fpscr to be written. */ | |
389 | continue; | |
390 | } | |
391 | ||
392 | if (errno != 0) | |
393 | { | |
394 | sprintf (mess, "writing register %s (#%d)", | |
395 | REGISTER_NAME (regno), regno); | |
396 | perror_with_name (mess); | |
397 | } | |
398 | } | |
399 | } | |
400 | ||
401 | static void | |
402 | fill_vrregset (gdb_vrregset_t *vrregsetp) | |
403 | { | |
404 | int i; | |
405 | struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch); | |
406 | int num_of_vrregs = tdep->ppc_vrsave_regnum - tdep->ppc_vr0_regnum + 1; | |
407 | int vrregsize = REGISTER_RAW_SIZE (tdep->ppc_vr0_regnum); | |
408 | int offset = vrregsize - REGISTER_RAW_SIZE (tdep->ppc_vrsave_regnum); | |
409 | ||
410 | for (i = 0; i < num_of_vrregs; i++) | |
411 | { | |
412 | /* The last 2 registers of this set are only 32 bit long, not | |
413 | 128, but only VSCR is fetched as a 16 bytes quantity. */ | |
414 | if (i == (num_of_vrregs - 2)) | |
415 | regcache_collect (tdep->ppc_vr0_regnum + i, | |
416 | *vrregsetp + i * vrregsize + offset); | |
417 | else | |
418 | regcache_collect (tdep->ppc_vr0_regnum + i, *vrregsetp + i * vrregsize); | |
419 | } | |
420 | } | |
421 | ||
422 | static void | |
423 | store_altivec_registers (int tid) | |
424 | { | |
425 | int ret; | |
426 | gdb_vrregset_t regs; | |
427 | ||
428 | ret = ptrace (PTRACE_GETVRREGS, tid, 0, (int) ®s); | |
429 | if (ret < 0) | |
430 | { | |
431 | if (errno == EIO) | |
432 | { | |
433 | have_ptrace_getvrregs = 0; | |
434 | return; | |
435 | } | |
436 | perror_with_name ("Couldn't get AltiVec registers"); | |
437 | } | |
438 | ||
439 | fill_vrregset (®s); | |
440 | ||
441 | if (ptrace (PTRACE_SETVRREGS, tid, 0, (int) ®s) < 0) | |
442 | perror_with_name ("Couldn't write AltiVec registers"); | |
443 | } | |
444 | ||
445 | static void | |
446 | store_ppc_registers (int tid) | |
447 | { | |
448 | int i; | |
449 | struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch); | |
450 | ||
451 | for (i = 0; i <= tdep->ppc_fpscr_regnum; i++) | |
452 | store_register (tid, i); | |
453 | if (tdep->ppc_mq_regnum != -1) | |
454 | store_register (tid, tdep->ppc_mq_regnum); | |
455 | if (have_ptrace_getvrregs) | |
456 | if (tdep->ppc_vr0_regnum != -1 && tdep->ppc_vrsave_regnum != -1) | |
457 | store_altivec_registers (tid); | |
458 | } | |
459 | ||
460 | void | |
461 | store_inferior_registers (int regno) | |
462 | { | |
463 | /* Overload thread id onto process id */ | |
464 | int tid = TIDGET (inferior_ptid); | |
465 | ||
466 | /* No thread id, just use process id */ | |
467 | if (tid == 0) | |
468 | tid = PIDGET (inferior_ptid); | |
469 | ||
470 | if (regno >= 0) | |
471 | store_register (tid, regno); | |
472 | else | |
473 | store_ppc_registers (tid); | |
474 | } | |
475 | ||
476 | void | |
477 | supply_gregset (gdb_gregset_t *gregsetp) | |
478 | { | |
479 | ppc_linux_supply_gregset ((char *) gregsetp); | |
480 | } | |
481 | ||
482 | void | |
483 | fill_gregset (gdb_gregset_t *gregsetp, int regno) | |
484 | { | |
485 | int regi; | |
486 | elf_greg_t *regp = (elf_greg_t *) gregsetp; | |
487 | struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch); | |
488 | ||
489 | for (regi = 0; regi < 32; regi++) | |
490 | { | |
491 | if ((regno == -1) || regno == regi) | |
492 | regcache_collect (regi, regp + PT_R0 + regi); | |
493 | } | |
494 | ||
495 | if ((regno == -1) || regno == PC_REGNUM) | |
496 | regcache_collect (PC_REGNUM, regp + PT_NIP); | |
497 | if ((regno == -1) || regno == tdep->ppc_lr_regnum) | |
498 | regcache_collect (tdep->ppc_lr_regnum, regp + PT_LNK); | |
499 | if ((regno == -1) || regno == tdep->ppc_cr_regnum) | |
500 | regcache_collect (tdep->ppc_cr_regnum, regp + PT_CCR); | |
501 | if ((regno == -1) || regno == tdep->ppc_xer_regnum) | |
502 | regcache_collect (tdep->ppc_xer_regnum, regp + PT_XER); | |
503 | if ((regno == -1) || regno == tdep->ppc_ctr_regnum) | |
504 | regcache_collect (tdep->ppc_ctr_regnum, regp + PT_CTR); | |
505 | if (((regno == -1) || regno == tdep->ppc_mq_regnum) | |
506 | && (tdep->ppc_mq_regnum != -1)) | |
507 | regcache_collect (tdep->ppc_mq_regnum, regp + PT_MQ); | |
508 | if ((regno == -1) || regno == tdep->ppc_ps_regnum) | |
509 | regcache_collect (tdep->ppc_ps_regnum, regp + PT_MSR); | |
510 | } | |
511 | ||
512 | void | |
513 | supply_fpregset (gdb_fpregset_t * fpregsetp) | |
514 | { | |
515 | ppc_linux_supply_fpregset ((char *) fpregsetp); | |
516 | } | |
517 | ||
518 | /* Given a pointer to a floating point register set in /proc format | |
519 | (fpregset_t *), update the register specified by REGNO from gdb's | |
520 | idea of the current floating point register set. If REGNO is -1, | |
521 | update them all. */ | |
522 | void | |
523 | fill_fpregset (gdb_fpregset_t *fpregsetp, int regno) | |
524 | { | |
525 | int regi; | |
526 | struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch); | |
527 | ||
528 | for (regi = 0; regi < 32; regi++) | |
529 | { | |
530 | if ((regno == -1) || (regno == FP0_REGNUM + regi)) | |
531 | regcache_collect (FP0_REGNUM + regi, (char *) (*fpregsetp + regi)); | |
532 | } | |
533 | if ((regno == -1) || regno == tdep->ppc_fpscr_regnum) | |
534 | regcache_collect (tdep->ppc_fpscr_regnum, (char *) (*fpregsetp + regi)); | |
535 | } |