1*11efff7fSkettenis /* Functions specific to running GDB native on HPPA running GNU/Linux.
2*11efff7fSkettenis
3*11efff7fSkettenis Copyright 2004 Free Software Foundation, Inc.
4*11efff7fSkettenis
5*11efff7fSkettenis This file is part of GDB.
6*11efff7fSkettenis
7*11efff7fSkettenis This program is free software; you can redistribute it and/or modify
8*11efff7fSkettenis it under the terms of the GNU General Public License as published by
9*11efff7fSkettenis the Free Software Foundation; either version 2 of the License, or
10*11efff7fSkettenis (at your option) any later version.
11*11efff7fSkettenis
12*11efff7fSkettenis This program is distributed in the hope that it will be useful,
13*11efff7fSkettenis but WITHOUT ANY WARRANTY; without even the implied warranty of
14*11efff7fSkettenis MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15*11efff7fSkettenis GNU General Public License for more details.
16*11efff7fSkettenis
17*11efff7fSkettenis You should have received a copy of the GNU General Public License
18*11efff7fSkettenis along with this program; if not, write to the Free Software
19*11efff7fSkettenis Foundation, Inc., 59 Temple Place - Suite 330,
20*11efff7fSkettenis Boston, MA 02111-1307, USA. */
21*11efff7fSkettenis
22*11efff7fSkettenis #include "defs.h"
23*11efff7fSkettenis #include "gdbcore.h"
24*11efff7fSkettenis #include "regcache.h"
25*11efff7fSkettenis #include "gdb_string.h"
26*11efff7fSkettenis #include "inferior.h"
27*11efff7fSkettenis
28*11efff7fSkettenis #include <sys/procfs.h>
29*11efff7fSkettenis #include <sys/ptrace.h>
30*11efff7fSkettenis #include <linux/version.h>
31*11efff7fSkettenis
32*11efff7fSkettenis #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,43)
33*11efff7fSkettenis #include <asm/offset.h>
34*11efff7fSkettenis #else
35*11efff7fSkettenis #include <asm/offsets.h>
36*11efff7fSkettenis #endif
37*11efff7fSkettenis
38*11efff7fSkettenis #include "hppa-tdep.h"
39*11efff7fSkettenis
40*11efff7fSkettenis /* Prototypes for supply_gregset etc. */
41*11efff7fSkettenis #include "gregset.h"
42*11efff7fSkettenis
43*11efff7fSkettenis /* These must match the order of the register names.
44*11efff7fSkettenis
45*11efff7fSkettenis Some sort of lookup table is needed because the offsets associated
46*11efff7fSkettenis with the registers are all over the board. */
47*11efff7fSkettenis
48*11efff7fSkettenis static const int u_offsets[] =
49*11efff7fSkettenis {
50*11efff7fSkettenis /* general registers */
51*11efff7fSkettenis -1,
52*11efff7fSkettenis PT_GR1,
53*11efff7fSkettenis PT_GR2,
54*11efff7fSkettenis PT_GR3,
55*11efff7fSkettenis PT_GR4,
56*11efff7fSkettenis PT_GR5,
57*11efff7fSkettenis PT_GR6,
58*11efff7fSkettenis PT_GR7,
59*11efff7fSkettenis PT_GR8,
60*11efff7fSkettenis PT_GR9,
61*11efff7fSkettenis PT_GR10,
62*11efff7fSkettenis PT_GR11,
63*11efff7fSkettenis PT_GR12,
64*11efff7fSkettenis PT_GR13,
65*11efff7fSkettenis PT_GR14,
66*11efff7fSkettenis PT_GR15,
67*11efff7fSkettenis PT_GR16,
68*11efff7fSkettenis PT_GR17,
69*11efff7fSkettenis PT_GR18,
70*11efff7fSkettenis PT_GR19,
71*11efff7fSkettenis PT_GR20,
72*11efff7fSkettenis PT_GR21,
73*11efff7fSkettenis PT_GR22,
74*11efff7fSkettenis PT_GR23,
75*11efff7fSkettenis PT_GR24,
76*11efff7fSkettenis PT_GR25,
77*11efff7fSkettenis PT_GR26,
78*11efff7fSkettenis PT_GR27,
79*11efff7fSkettenis PT_GR28,
80*11efff7fSkettenis PT_GR29,
81*11efff7fSkettenis PT_GR30,
82*11efff7fSkettenis PT_GR31,
83*11efff7fSkettenis
84*11efff7fSkettenis PT_SAR,
85*11efff7fSkettenis PT_IAOQ0,
86*11efff7fSkettenis PT_IASQ0,
87*11efff7fSkettenis PT_IAOQ1,
88*11efff7fSkettenis PT_IASQ1,
89*11efff7fSkettenis -1, /* eiem */
90*11efff7fSkettenis PT_IIR,
91*11efff7fSkettenis PT_ISR,
92*11efff7fSkettenis PT_IOR,
93*11efff7fSkettenis PT_PSW,
94*11efff7fSkettenis -1, /* goto */
95*11efff7fSkettenis
96*11efff7fSkettenis PT_SR4,
97*11efff7fSkettenis PT_SR0,
98*11efff7fSkettenis PT_SR1,
99*11efff7fSkettenis PT_SR2,
100*11efff7fSkettenis PT_SR3,
101*11efff7fSkettenis PT_SR5,
102*11efff7fSkettenis PT_SR6,
103*11efff7fSkettenis PT_SR7,
104*11efff7fSkettenis
105*11efff7fSkettenis -1, /* cr0 */
106*11efff7fSkettenis -1, /* pid0 */
107*11efff7fSkettenis -1, /* pid1 */
108*11efff7fSkettenis -1, /* ccr */
109*11efff7fSkettenis -1, /* pid2 */
110*11efff7fSkettenis -1, /* pid3 */
111*11efff7fSkettenis -1, /* cr24 */
112*11efff7fSkettenis -1, /* cr25 */
113*11efff7fSkettenis -1, /* cr26 */
114*11efff7fSkettenis PT_CR27,
115*11efff7fSkettenis -1, /* cr28 */
116*11efff7fSkettenis -1, /* cr29 */
117*11efff7fSkettenis -1, /* cr30 */
118*11efff7fSkettenis
119*11efff7fSkettenis /* Floating point regs. */
120*11efff7fSkettenis PT_FR0, PT_FR0 + 4,
121*11efff7fSkettenis PT_FR1, PT_FR1 + 4,
122*11efff7fSkettenis PT_FR2, PT_FR2 + 4,
123*11efff7fSkettenis PT_FR3, PT_FR3 + 4,
124*11efff7fSkettenis PT_FR4, PT_FR4 + 4,
125*11efff7fSkettenis PT_FR5, PT_FR5 + 4,
126*11efff7fSkettenis PT_FR6, PT_FR6 + 4,
127*11efff7fSkettenis PT_FR7, PT_FR7 + 4,
128*11efff7fSkettenis PT_FR8, PT_FR8 + 4,
129*11efff7fSkettenis PT_FR9, PT_FR9 + 4,
130*11efff7fSkettenis PT_FR10, PT_FR10 + 4,
131*11efff7fSkettenis PT_FR11, PT_FR11 + 4,
132*11efff7fSkettenis PT_FR12, PT_FR12 + 4,
133*11efff7fSkettenis PT_FR13, PT_FR13 + 4,
134*11efff7fSkettenis PT_FR14, PT_FR14 + 4,
135*11efff7fSkettenis PT_FR15, PT_FR15 + 4,
136*11efff7fSkettenis PT_FR16, PT_FR16 + 4,
137*11efff7fSkettenis PT_FR17, PT_FR17 + 4,
138*11efff7fSkettenis PT_FR18, PT_FR18 + 4,
139*11efff7fSkettenis PT_FR19, PT_FR19 + 4,
140*11efff7fSkettenis PT_FR20, PT_FR20 + 4,
141*11efff7fSkettenis PT_FR21, PT_FR21 + 4,
142*11efff7fSkettenis PT_FR22, PT_FR22 + 4,
143*11efff7fSkettenis PT_FR23, PT_FR23 + 4,
144*11efff7fSkettenis PT_FR24, PT_FR24 + 4,
145*11efff7fSkettenis PT_FR25, PT_FR25 + 4,
146*11efff7fSkettenis PT_FR26, PT_FR26 + 4,
147*11efff7fSkettenis PT_FR27, PT_FR27 + 4,
148*11efff7fSkettenis PT_FR28, PT_FR28 + 4,
149*11efff7fSkettenis PT_FR29, PT_FR29 + 4,
150*11efff7fSkettenis PT_FR30, PT_FR30 + 4,
151*11efff7fSkettenis PT_FR31, PT_FR31 + 4,
152*11efff7fSkettenis };
153*11efff7fSkettenis
154*11efff7fSkettenis CORE_ADDR
register_addr(int regno,CORE_ADDR blockend)155*11efff7fSkettenis register_addr (int regno, CORE_ADDR blockend)
156*11efff7fSkettenis {
157*11efff7fSkettenis CORE_ADDR addr;
158*11efff7fSkettenis
159*11efff7fSkettenis if ((unsigned) regno >= NUM_REGS)
160*11efff7fSkettenis error ("Invalid register number %d.", regno);
161*11efff7fSkettenis
162*11efff7fSkettenis if (u_offsets[regno] == -1)
163*11efff7fSkettenis addr = 0;
164*11efff7fSkettenis else
165*11efff7fSkettenis {
166*11efff7fSkettenis addr = (CORE_ADDR) u_offsets[regno];
167*11efff7fSkettenis }
168*11efff7fSkettenis
169*11efff7fSkettenis return addr;
170*11efff7fSkettenis }
171*11efff7fSkettenis
172*11efff7fSkettenis /*
173*11efff7fSkettenis * Registers saved in a coredump:
174*11efff7fSkettenis * gr0..gr31
175*11efff7fSkettenis * sr0..sr7
176*11efff7fSkettenis * iaoq0..iaoq1
177*11efff7fSkettenis * iasq0..iasq1
178*11efff7fSkettenis * sar, iir, isr, ior, ipsw
179*11efff7fSkettenis * cr0, cr24..cr31
180*11efff7fSkettenis * cr8,9,12,13
181*11efff7fSkettenis * cr10, cr15
182*11efff7fSkettenis */
183*11efff7fSkettenis #define GR_REGNUM(_n) (HPPA_R0_REGNUM+_n)
184*11efff7fSkettenis #define TR_REGNUM(_n) (HPPA_TR0_REGNUM+_n)
185*11efff7fSkettenis static const int greg_map[] =
186*11efff7fSkettenis {
187*11efff7fSkettenis GR_REGNUM(0), GR_REGNUM(1), GR_REGNUM(2), GR_REGNUM(3),
188*11efff7fSkettenis GR_REGNUM(4), GR_REGNUM(5), GR_REGNUM(6), GR_REGNUM(7),
189*11efff7fSkettenis GR_REGNUM(8), GR_REGNUM(9), GR_REGNUM(10), GR_REGNUM(11),
190*11efff7fSkettenis GR_REGNUM(12), GR_REGNUM(13), GR_REGNUM(14), GR_REGNUM(15),
191*11efff7fSkettenis GR_REGNUM(16), GR_REGNUM(17), GR_REGNUM(18), GR_REGNUM(19),
192*11efff7fSkettenis GR_REGNUM(20), GR_REGNUM(21), GR_REGNUM(22), GR_REGNUM(23),
193*11efff7fSkettenis GR_REGNUM(24), GR_REGNUM(25), GR_REGNUM(26), GR_REGNUM(27),
194*11efff7fSkettenis GR_REGNUM(28), GR_REGNUM(29), GR_REGNUM(30), GR_REGNUM(31),
195*11efff7fSkettenis
196*11efff7fSkettenis HPPA_SR4_REGNUM+1, HPPA_SR4_REGNUM+2, HPPA_SR4_REGNUM+3, HPPA_SR4_REGNUM+4,
197*11efff7fSkettenis HPPA_SR4_REGNUM, HPPA_SR4_REGNUM+5, HPPA_SR4_REGNUM+6, HPPA_SR4_REGNUM+7,
198*11efff7fSkettenis
199*11efff7fSkettenis HPPA_PCOQ_HEAD_REGNUM, HPPA_PCOQ_TAIL_REGNUM,
200*11efff7fSkettenis HPPA_PCSQ_HEAD_REGNUM, HPPA_PCSQ_TAIL_REGNUM,
201*11efff7fSkettenis
202*11efff7fSkettenis HPPA_SAR_REGNUM, HPPA_IIR_REGNUM, HPPA_ISR_REGNUM, HPPA_IOR_REGNUM,
203*11efff7fSkettenis HPPA_IPSW_REGNUM, HPPA_RCR_REGNUM,
204*11efff7fSkettenis
205*11efff7fSkettenis TR_REGNUM(0), TR_REGNUM(1), TR_REGNUM(2), TR_REGNUM(3),
206*11efff7fSkettenis TR_REGNUM(4), TR_REGNUM(5), TR_REGNUM(6), TR_REGNUM(7),
207*11efff7fSkettenis
208*11efff7fSkettenis HPPA_PID0_REGNUM, HPPA_PID1_REGNUM, HPPA_PID2_REGNUM, HPPA_PID3_REGNUM,
209*11efff7fSkettenis HPPA_CCR_REGNUM, HPPA_EIEM_REGNUM,
210*11efff7fSkettenis };
211*11efff7fSkettenis
212*11efff7fSkettenis
213*11efff7fSkettenis
214*11efff7fSkettenis /* Fetch one register. */
215*11efff7fSkettenis
216*11efff7fSkettenis static void
fetch_register(int regno)217*11efff7fSkettenis fetch_register (int regno)
218*11efff7fSkettenis {
219*11efff7fSkettenis int tid;
220*11efff7fSkettenis int val;
221*11efff7fSkettenis
222*11efff7fSkettenis if (CANNOT_FETCH_REGISTER (regno))
223*11efff7fSkettenis {
224*11efff7fSkettenis regcache_raw_supply (current_regcache, regno, NULL);
225*11efff7fSkettenis return;
226*11efff7fSkettenis }
227*11efff7fSkettenis
228*11efff7fSkettenis /* GNU/Linux LWP ID's are process ID's. */
229*11efff7fSkettenis tid = TIDGET (inferior_ptid);
230*11efff7fSkettenis if (tid == 0)
231*11efff7fSkettenis tid = PIDGET (inferior_ptid); /* Not a threaded program. */
232*11efff7fSkettenis
233*11efff7fSkettenis errno = 0;
234*11efff7fSkettenis val = ptrace (PTRACE_PEEKUSER, tid, register_addr (regno, 0), 0);
235*11efff7fSkettenis if (errno != 0)
236*11efff7fSkettenis error ("Couldn't read register %s (#%d): %s.", REGISTER_NAME (regno),
237*11efff7fSkettenis regno, safe_strerror (errno));
238*11efff7fSkettenis
239*11efff7fSkettenis regcache_raw_supply (current_regcache, regno, &val);
240*11efff7fSkettenis }
241*11efff7fSkettenis
242*11efff7fSkettenis /* Store one register. */
243*11efff7fSkettenis
244*11efff7fSkettenis static void
store_register(int regno)245*11efff7fSkettenis store_register (int regno)
246*11efff7fSkettenis {
247*11efff7fSkettenis int tid;
248*11efff7fSkettenis int val;
249*11efff7fSkettenis
250*11efff7fSkettenis if (CANNOT_STORE_REGISTER (regno))
251*11efff7fSkettenis return;
252*11efff7fSkettenis
253*11efff7fSkettenis /* GNU/Linux LWP ID's are process ID's. */
254*11efff7fSkettenis tid = TIDGET (inferior_ptid);
255*11efff7fSkettenis if (tid == 0)
256*11efff7fSkettenis tid = PIDGET (inferior_ptid); /* Not a threaded program. */
257*11efff7fSkettenis
258*11efff7fSkettenis errno = 0;
259*11efff7fSkettenis regcache_raw_collect (current_regcache, regno, &val);
260*11efff7fSkettenis ptrace (PTRACE_POKEUSER, tid, register_addr (regno, 0), val);
261*11efff7fSkettenis if (errno != 0)
262*11efff7fSkettenis error ("Couldn't write register %s (#%d): %s.", REGISTER_NAME (regno),
263*11efff7fSkettenis regno, safe_strerror (errno));
264*11efff7fSkettenis }
265*11efff7fSkettenis
266*11efff7fSkettenis /* Fetch registers from the child process. Fetch all registers if
267*11efff7fSkettenis regno == -1, otherwise fetch all general registers or all floating
268*11efff7fSkettenis point registers depending upon the value of regno. */
269*11efff7fSkettenis
270*11efff7fSkettenis void
fetch_inferior_registers(int regno)271*11efff7fSkettenis fetch_inferior_registers (int regno)
272*11efff7fSkettenis {
273*11efff7fSkettenis if (-1 == regno)
274*11efff7fSkettenis {
275*11efff7fSkettenis for (regno = 0; regno < NUM_REGS; regno++)
276*11efff7fSkettenis fetch_register (regno);
277*11efff7fSkettenis }
278*11efff7fSkettenis else
279*11efff7fSkettenis {
280*11efff7fSkettenis fetch_register (regno);
281*11efff7fSkettenis }
282*11efff7fSkettenis }
283*11efff7fSkettenis
284*11efff7fSkettenis /* Store registers back into the inferior. Store all registers if
285*11efff7fSkettenis regno == -1, otherwise store all general registers or all floating
286*11efff7fSkettenis point registers depending upon the value of regno. */
287*11efff7fSkettenis
288*11efff7fSkettenis void
store_inferior_registers(int regno)289*11efff7fSkettenis store_inferior_registers (int regno)
290*11efff7fSkettenis {
291*11efff7fSkettenis if (-1 == regno)
292*11efff7fSkettenis {
293*11efff7fSkettenis for (regno = 0; regno < NUM_REGS; regno++)
294*11efff7fSkettenis store_register (regno);
295*11efff7fSkettenis }
296*11efff7fSkettenis else
297*11efff7fSkettenis {
298*11efff7fSkettenis store_register (regno);
299*11efff7fSkettenis }
300*11efff7fSkettenis }
301*11efff7fSkettenis
302*11efff7fSkettenis /* Fill GDB's register array with the general-purpose register values
303*11efff7fSkettenis in *gregsetp. */
304*11efff7fSkettenis
305*11efff7fSkettenis void
supply_gregset(gdb_gregset_t * gregsetp)306*11efff7fSkettenis supply_gregset (gdb_gregset_t *gregsetp)
307*11efff7fSkettenis {
308*11efff7fSkettenis int i;
309*11efff7fSkettenis greg_t *regp = (elf_greg_t *) gregsetp;
310*11efff7fSkettenis
311*11efff7fSkettenis for (i = 0; i < sizeof (greg_map) / sizeof (greg_map[0]); i++, regp++)
312*11efff7fSkettenis {
313*11efff7fSkettenis int regno = greg_map[i];
314*11efff7fSkettenis regcache_raw_supply (current_regcache, regno, regp);
315*11efff7fSkettenis }
316*11efff7fSkettenis }
317*11efff7fSkettenis
318*11efff7fSkettenis /* Fill register regno (if it is a general-purpose register) in
319*11efff7fSkettenis *gregsetp with the appropriate value from GDB's register array.
320*11efff7fSkettenis If regno is -1, do this for all registers. */
321*11efff7fSkettenis
322*11efff7fSkettenis void
fill_gregset(gdb_gregset_t * gregsetp,int regno)323*11efff7fSkettenis fill_gregset (gdb_gregset_t *gregsetp, int regno)
324*11efff7fSkettenis {
325*11efff7fSkettenis int i;
326*11efff7fSkettenis
327*11efff7fSkettenis for (i = 0; i < sizeof (greg_map) / sizeof (greg_map[0]); i++)
328*11efff7fSkettenis {
329*11efff7fSkettenis int mregno = greg_map[i];
330*11efff7fSkettenis
331*11efff7fSkettenis if (regno == -1 || regno == mregno)
332*11efff7fSkettenis {
333*11efff7fSkettenis regcache_raw_collect(current_regcache, mregno, &(*gregsetp)[i]);
334*11efff7fSkettenis }
335*11efff7fSkettenis }
336*11efff7fSkettenis }
337*11efff7fSkettenis
338*11efff7fSkettenis /* Given a pointer to a floating point register set in /proc format
339*11efff7fSkettenis (fpregset_t *), unpack the register contents and supply them as gdb's
340*11efff7fSkettenis idea of the current floating point register values. */
341*11efff7fSkettenis
342*11efff7fSkettenis void
supply_fpregset(gdb_fpregset_t * fpregsetp)343*11efff7fSkettenis supply_fpregset (gdb_fpregset_t *fpregsetp)
344*11efff7fSkettenis {
345*11efff7fSkettenis int regi;
346*11efff7fSkettenis char *from;
347*11efff7fSkettenis
348*11efff7fSkettenis for (regi = 0; regi <= 31; regi++)
349*11efff7fSkettenis {
350*11efff7fSkettenis from = (char *) &((*fpregsetp)[regi]);
351*11efff7fSkettenis regcache_raw_supply (current_regcache, 2*regi + HPPA_FP0_REGNUM, from);
352*11efff7fSkettenis regcache_raw_supply (current_regcache, 2*regi + HPPA_FP0_REGNUM + 1,
353*11efff7fSkettenis from + 4);
354*11efff7fSkettenis }
355*11efff7fSkettenis }
356*11efff7fSkettenis
357*11efff7fSkettenis /* Given a pointer to a floating point register set in /proc format
358*11efff7fSkettenis (fpregset_t *), update the register specified by REGNO from gdb's idea
359*11efff7fSkettenis of the current floating point register set. If REGNO is -1, update
360*11efff7fSkettenis them all. */
361*11efff7fSkettenis
362*11efff7fSkettenis void
fill_fpregset(gdb_fpregset_t * fpregsetp,int regno)363*11efff7fSkettenis fill_fpregset (gdb_fpregset_t *fpregsetp, int regno)
364*11efff7fSkettenis {
365*11efff7fSkettenis int i;
366*11efff7fSkettenis
367*11efff7fSkettenis for (i = HPPA_FP0_REGNUM; i < HPPA_FP0_REGNUM + 32 * 2; i++)
368*11efff7fSkettenis {
369*11efff7fSkettenis /* Gross. fpregset_t is double, registers[x] has single
370*11efff7fSkettenis precision reg. */
371*11efff7fSkettenis char *to = (char *) &((*fpregsetp)[(i - HPPA_FP0_REGNUM) / 2]);
372*11efff7fSkettenis if ((i - HPPA_FP0_REGNUM) & 1)
373*11efff7fSkettenis to += 4;
374*11efff7fSkettenis regcache_raw_collect (current_regcache, i, to);
375*11efff7fSkettenis }
376*11efff7fSkettenis }
377