Commit | Line | Data |
---|---|---|
cb747ec5 DE |
1 | /* Target-dependent code for the SPARC 64 for GDB, the GNU debugger. |
2 | Copyright 1986, 1987, 1989, 1991, 1992, 1993 Free Software Foundation, Inc. | |
3 | Contributed by Doug Evans (dje@cygnus.com). | |
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., 675 Mass Ave, Cambridge, MA 02139, USA. */ | |
20 | ||
21 | #include "defs.h" | |
22 | #include "frame.h" | |
23 | #include "inferior.h" | |
24 | #include "obstack.h" | |
25 | #include "target.h" | |
26 | #include "ieee-float.h" | |
27 | ||
28 | /*#include "symfile.h" /* for objfiles.h */ | |
29 | /*#include "objfiles.h" /* for find_pc_section */ | |
30 | ||
31 | /* This file contains replacements and additions to sparc-tdep.c only. | |
32 | Some of this code has been written for a day when we can merge at least | |
33 | some of this with sparc-tdep.c. Macro TARGET_SPARC64 exists to allow some | |
34 | code to potentially be used by both. */ | |
35 | ||
36 | #define TARGET_SPARC64 1 /* later make a config parm or some such */ | |
37 | ||
38 | /* From infrun.c */ | |
39 | extern int stop_after_trap; | |
40 | ||
41 | /* Branches with prediction are treated like their non-predicting cousins. */ | |
42 | /* FIXME: What about floating point branches? */ | |
43 | ||
44 | typedef enum | |
45 | { | |
46 | Error, not_branch, bicc, bicca, ba, baa, ticc, ta, done_retry | |
47 | } branch_type; | |
48 | ||
49 | /* Simulate single-step ptrace call for sun4. Code written by Gary | |
50 | Beihl (beihl@mcc.com). */ | |
51 | ||
52 | /* npc4 and next_pc describe the situation at the time that the | |
53 | step-breakpoint was set, not necessary the current value of NPC_REGNUM. */ | |
54 | static CORE_ADDR next_pc, npc4, target; | |
55 | static int brknpc4, brktrg; | |
56 | typedef char binsn_quantum[BREAKPOINT_MAX]; | |
57 | static binsn_quantum break_mem[3]; | |
58 | ||
59 | /* Non-zero if we just simulated a single-step ptrace call. This is | |
60 | needed because we cannot remove the breakpoints in the inferior | |
61 | process until after the `wait' in `wait_for_inferior'. Used for | |
62 | sun4. */ | |
63 | ||
64 | int one_stepped; | |
65 | ||
66 | /* sparc64_single_step() is called just before we want to resume the inferior, | |
67 | if we want to single-step it but there is no hardware or kernel single-step | |
68 | support (as on all SPARCs). We find all the possible targets of the | |
69 | coming instruction and breakpoint them. | |
70 | ||
71 | single_step is also called just after the inferior stops. If we had | |
72 | set up a simulated single-step, we undo our damage. */ | |
73 | ||
74 | /* FIXME: When the code is releasable, sparc's single step could become this | |
75 | one, removing the duplication. */ | |
76 | ||
77 | void | |
78 | sparc64_single_step (ignore) | |
79 | int ignore; /* pid, but we don't need it */ | |
80 | { | |
81 | branch_type br, isbranch(); | |
82 | CORE_ADDR pc; | |
83 | long pc_instruction; | |
84 | ||
85 | if (!one_stepped) | |
86 | { | |
87 | /* Always set breakpoint for NPC. */ | |
88 | next_pc = read_register (NPC_REGNUM); | |
89 | npc4 = next_pc + 4; /* branch not taken */ | |
90 | ||
91 | target_insert_breakpoint (next_pc, break_mem[0]); | |
92 | /* printf ("set break at %x\n",next_pc); */ | |
93 | ||
94 | pc = read_register (PC_REGNUM); | |
95 | pc_instruction = read_memory_integer (pc, sizeof(pc_instruction)); | |
96 | br = isbranch (pc_instruction, pc, &target); | |
97 | brknpc4 = brktrg = 0; | |
98 | ||
99 | if (br == bicca) | |
100 | { | |
101 | /* Conditional annulled branch will either end up at | |
102 | npc (if taken) or at npc+4 (if not taken). | |
103 | Trap npc+4. */ | |
104 | brknpc4 = 1; | |
105 | target_insert_breakpoint (npc4, break_mem[1]); | |
106 | } | |
107 | else if ((br == baa && target != next_pc) | |
108 | || (TARGET_SPARC64 && br == done_retry)) | |
109 | { | |
110 | /* Unconditional annulled branch will always end up at | |
111 | the target. */ | |
112 | brktrg = 1; | |
113 | target_insert_breakpoint (target, break_mem[2]); | |
114 | } | |
115 | ||
116 | /* We are ready to let it go */ | |
117 | one_stepped = 1; | |
118 | return; | |
119 | } | |
120 | else | |
121 | { | |
122 | /* Remove breakpoints */ | |
123 | target_remove_breakpoint (next_pc, break_mem[0]); | |
124 | ||
125 | if (brknpc4) | |
126 | target_remove_breakpoint (npc4, break_mem[1]); | |
127 | ||
128 | if (brktrg) | |
129 | target_remove_breakpoint (target, break_mem[2]); | |
130 | ||
131 | one_stepped = 0; | |
132 | } | |
133 | } | |
134 | \f | |
135 | /* FIXME: sparc64_frame_chain() is temporary. sparc_frame_chain() can | |
136 | be fixed to support both of us. */ | |
137 | ||
138 | #define FRAME_SAVED_L0 0 /* Byte offset from SP */ | |
139 | #define FRAME_SAVED_I0 (8*REGISTER_RAW_SIZE (0)) /* Byte offset from SP */ | |
140 | ||
141 | CORE_ADDR | |
142 | sparc64_frame_chain (thisframe) | |
143 | FRAME thisframe; | |
144 | { | |
145 | REGISTER_TYPE retval; | |
146 | int err; | |
147 | CORE_ADDR addr; | |
148 | ||
149 | addr = thisframe->frame + FRAME_SAVED_I0 + | |
150 | REGISTER_RAW_SIZE (0) * (FP_REGNUM - I0_REGNUM); | |
151 | err = target_read_memory (addr, (char *) &retval, sizeof (REGISTER_TYPE)); | |
152 | if (err) | |
153 | return 0; | |
154 | SWAP_TARGET_AND_HOST (&retval, sizeof (retval)); | |
155 | return retval; | |
156 | } | |
157 | ||
158 | CORE_ADDR | |
159 | sparc64_extract_struct_value_address (regbuf) | |
160 | char regbuf[REGISTER_BYTES]; | |
161 | { | |
162 | CORE_ADDR addr; | |
163 | ||
164 | /* FIXME: We assume a non-leaf function. */ | |
165 | addr = read_register (I0_REGNUM); | |
166 | return addr; | |
167 | } | |
168 | ||
169 | /* Find the pc saved in frame FRAME. */ | |
170 | /* FIXME: This function can be removed when sparc_frame_saved_pc | |
171 | handles us too. */ | |
172 | ||
173 | CORE_ADDR | |
174 | sparc64_frame_saved_pc (frame) | |
175 | FRAME frame; | |
176 | { | |
177 | int err; | |
178 | REGISTER_TYPE retval; | |
179 | CORE_ADDR addr,prev_pc; | |
180 | ||
181 | if (get_current_frame () == frame) /* FIXME, debug check. Remove >=gdb-4.6 */ | |
182 | { | |
183 | if (read_register (SP_REGNUM) != frame->bottom) abort(); | |
184 | } | |
185 | ||
186 | addr = frame->bottom + FRAME_SAVED_I0 + | |
187 | REGISTER_RAW_SIZE (0) * (I7_REGNUM - I0_REGNUM); | |
188 | err = target_read_memory (addr, (char *) &retval, sizeof (REGISTER_TYPE)); | |
189 | if (err) | |
190 | return 0; | |
191 | SWAP_TARGET_AND_HOST (&retval, sizeof (retval)); | |
192 | ||
193 | /* CORE_ADDR isn't always the same size as REGISTER_TYPE, so convert. */ | |
194 | ||
195 | prev_pc = (CORE_ADDR) retval; | |
196 | return PC_ADJUST (prev_pc); | |
197 | } | |
198 | ||
199 | /* Check instruction at ADDR to see if it is an annulled branch or other | |
200 | instruction whose npc isn't pc+4 (eg: trap, done, retry). | |
201 | All other instructions will go to NPC or will trap. | |
202 | Set *TARGET if we find a candidate branch; set to zero if not. */ | |
203 | ||
204 | branch_type | |
205 | isbranch (instruction, addr, target) | |
206 | long instruction; | |
207 | CORE_ADDR addr, *target; | |
208 | { | |
209 | branch_type val = not_branch; | |
210 | long int offset; /* Must be signed for sign-extend. */ | |
211 | union | |
212 | { | |
213 | unsigned long int code; | |
214 | struct | |
215 | { | |
216 | unsigned int op:2; | |
217 | unsigned int a:1; | |
218 | unsigned int cond:4; | |
219 | unsigned int op2:3; | |
220 | unsigned int disp22:22; | |
221 | } b; | |
222 | struct | |
223 | { | |
224 | unsigned int op:2; | |
225 | unsigned int a:1; | |
226 | unsigned int cond:4; | |
227 | unsigned int op2:3; | |
228 | unsigned int cc:2; | |
229 | unsigned int p:1; | |
230 | unsigned int disp19:19; | |
231 | } bp; | |
232 | struct | |
233 | { | |
234 | unsigned int op:2; | |
235 | unsigned int a:1; | |
236 | unsigned int zero:1; | |
237 | unsigned int rcond:3; | |
238 | unsigned int op2:3; | |
239 | unsigned int disp16hi:2; | |
240 | unsigned int p:1; | |
241 | unsigned int rs1:5; | |
242 | unsigned int disp16lo:14; | |
243 | } bpr; | |
244 | struct | |
245 | { | |
246 | unsigned int op:2; | |
247 | unsigned int fcn:5; | |
248 | unsigned int op3:6; | |
249 | unsigned int reserved:19; | |
250 | } dr; | |
251 | } insn; | |
252 | ||
253 | *target = 0; | |
254 | insn.code = instruction; | |
255 | ||
256 | if (insn.b.op == 0 | |
257 | && (insn.b.op2 == 1 || insn.b.op2 == 2 || insn.b.op2 ==3 | |
258 | || insn.b.op2 == 5 || insn.b.op2 == 6)) | |
259 | { | |
260 | if (insn.b.cond == 8) | |
261 | val = insn.b.a ? baa : ba; | |
262 | else | |
263 | val = insn.b.a ? bicca : bicc; | |
264 | switch (insn.b.op2) | |
265 | { | |
266 | case 1: /* bpcc */ | |
267 | offset = 4 * ((int) (insn.bp.disp19 << 13) >> 13); | |
268 | break; | |
269 | case 2: /* bicc */ | |
270 | offset = 4 * ((int) (insn.b.disp22 << 10) >> 10); | |
271 | break; | |
272 | case 3: /* bpr */ | |
273 | offset = 4 * ((int) ((insn.bpr.disp16hi << 10) | |
274 | || (insn.bpr.disp16lo << 18)) >> 13); | |
275 | break; | |
276 | case 5: /* fbpfcc */ | |
277 | offset = 4 * ((int) (insn.bp.disp19 << 13) >> 13); | |
278 | break; | |
279 | case 6: /* fbfcc */ | |
280 | offset = 4 * ((int) (insn.b.disp22 << 10) >> 10); | |
281 | break; | |
282 | } | |
283 | *target = addr + offset; | |
284 | } | |
285 | else if (insn.dr.op == 2 && insn.dr.op3 == 62) | |
286 | { | |
287 | if (insn.dr.fcn == 0) | |
288 | { | |
289 | /* done */ | |
290 | *target = read_register (TNPC_REGNUM); | |
291 | val = done_retry; | |
292 | } | |
293 | else if (insn.dr.fcn == 1) | |
294 | { | |
295 | /* retry */ | |
296 | *target = read_register (TPC_REGNUM); | |
297 | val = done_retry; | |
298 | } | |
299 | } | |
300 | ||
301 | return val; | |
302 | } | |
303 | ||
304 | /* We try to support 32 bit and 64 bit pointers. | |
305 | We are called when the Shade target is selected by shadeif.c. */ | |
306 | ||
307 | int target_ptr_bit = 64; /* default */ | |
308 | ||
309 | void | |
310 | set_target_ptr_bit(ptr_bit) | |
311 | int ptr_bit; | |
312 | { | |
313 | target_ptr_bit = ptr_bit; | |
314 | } |