]>
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 ([email protected]). | |
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 ([email protected]). */ | |
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 | |
cb747ec5 DE |
135 | CORE_ADDR |
136 | sparc64_extract_struct_value_address (regbuf) | |
137 | char regbuf[REGISTER_BYTES]; | |
138 | { | |
139 | CORE_ADDR addr; | |
140 | ||
141 | /* FIXME: We assume a non-leaf function. */ | |
142 | addr = read_register (I0_REGNUM); | |
143 | return addr; | |
144 | } | |
145 | ||
cb747ec5 DE |
146 | /* Check instruction at ADDR to see if it is an annulled branch or other |
147 | instruction whose npc isn't pc+4 (eg: trap, done, retry). | |
148 | All other instructions will go to NPC or will trap. | |
149 | Set *TARGET if we find a candidate branch; set to zero if not. */ | |
150 | ||
151 | branch_type | |
152 | isbranch (instruction, addr, target) | |
153 | long instruction; | |
154 | CORE_ADDR addr, *target; | |
155 | { | |
156 | branch_type val = not_branch; | |
157 | long int offset; /* Must be signed for sign-extend. */ | |
158 | union | |
159 | { | |
160 | unsigned long int code; | |
161 | struct | |
162 | { | |
163 | unsigned int op:2; | |
164 | unsigned int a:1; | |
165 | unsigned int cond:4; | |
166 | unsigned int op2:3; | |
167 | unsigned int disp22:22; | |
168 | } b; | |
169 | struct | |
170 | { | |
171 | unsigned int op:2; | |
172 | unsigned int a:1; | |
173 | unsigned int cond:4; | |
174 | unsigned int op2:3; | |
175 | unsigned int cc:2; | |
176 | unsigned int p:1; | |
177 | unsigned int disp19:19; | |
178 | } bp; | |
179 | struct | |
180 | { | |
181 | unsigned int op:2; | |
182 | unsigned int a:1; | |
183 | unsigned int zero:1; | |
184 | unsigned int rcond:3; | |
185 | unsigned int op2:3; | |
186 | unsigned int disp16hi:2; | |
187 | unsigned int p:1; | |
188 | unsigned int rs1:5; | |
189 | unsigned int disp16lo:14; | |
190 | } bpr; | |
191 | struct | |
192 | { | |
193 | unsigned int op:2; | |
194 | unsigned int fcn:5; | |
195 | unsigned int op3:6; | |
196 | unsigned int reserved:19; | |
197 | } dr; | |
198 | } insn; | |
199 | ||
200 | *target = 0; | |
201 | insn.code = instruction; | |
202 | ||
203 | if (insn.b.op == 0 | |
204 | && (insn.b.op2 == 1 || insn.b.op2 == 2 || insn.b.op2 ==3 | |
205 | || insn.b.op2 == 5 || insn.b.op2 == 6)) | |
206 | { | |
207 | if (insn.b.cond == 8) | |
208 | val = insn.b.a ? baa : ba; | |
209 | else | |
210 | val = insn.b.a ? bicca : bicc; | |
211 | switch (insn.b.op2) | |
212 | { | |
213 | case 1: /* bpcc */ | |
214 | offset = 4 * ((int) (insn.bp.disp19 << 13) >> 13); | |
215 | break; | |
216 | case 2: /* bicc */ | |
217 | offset = 4 * ((int) (insn.b.disp22 << 10) >> 10); | |
218 | break; | |
219 | case 3: /* bpr */ | |
220 | offset = 4 * ((int) ((insn.bpr.disp16hi << 10) | |
221 | || (insn.bpr.disp16lo << 18)) >> 13); | |
222 | break; | |
223 | case 5: /* fbpfcc */ | |
224 | offset = 4 * ((int) (insn.bp.disp19 << 13) >> 13); | |
225 | break; | |
226 | case 6: /* fbfcc */ | |
227 | offset = 4 * ((int) (insn.b.disp22 << 10) >> 10); | |
228 | break; | |
229 | } | |
230 | *target = addr + offset; | |
231 | } | |
232 | else if (insn.dr.op == 2 && insn.dr.op3 == 62) | |
233 | { | |
234 | if (insn.dr.fcn == 0) | |
235 | { | |
236 | /* done */ | |
237 | *target = read_register (TNPC_REGNUM); | |
238 | val = done_retry; | |
239 | } | |
240 | else if (insn.dr.fcn == 1) | |
241 | { | |
242 | /* retry */ | |
243 | *target = read_register (TPC_REGNUM); | |
244 | val = done_retry; | |
245 | } | |
246 | } | |
247 | ||
248 | return val; | |
249 | } | |
250 | ||
b562a186 DE |
251 | /* PRINT_REGISTER_HOOK routine. |
252 | Pretty print various registers. */ | |
253 | ||
254 | static void | |
255 | dump_ccreg (reg, val) | |
256 | char *reg; | |
257 | int val; | |
258 | { | |
259 | printf ("%s:%s,%s,%s,%s", reg, | |
260 | val & 8 ? "N" : "NN", | |
261 | val & 4 ? "Z" : "NZ", | |
262 | val & 2 ? "O" : "NO", | |
263 | val & 1 ? "C" : "NC" | |
264 | ); | |
265 | } | |
266 | ||
267 | void | |
268 | sparc_print_register_hook (regno) | |
269 | int regno; | |
270 | { | |
271 | if (((unsigned) (regno) - FP0_REGNUM < FP_MAX_REGNUM - FP0_REGNUM) | |
272 | && ((regno) & 1) == 0) | |
273 | { | |
274 | char doublereg[8]; /* two float regs */ | |
275 | if (!read_relative_register_raw_bytes ((regno), doublereg)) | |
276 | { | |
277 | printf("\t"); | |
278 | print_floating (doublereg, builtin_type_double, stdout); | |
279 | } | |
280 | } | |
281 | else if ((regno) == CCR_REGNUM) | |
282 | { | |
283 | int ccr = read_register (CCR_REGNUM); | |
284 | printf("\t"); | |
285 | dump_ccreg ("xcc", ccr >> 4); | |
286 | printf(", "); | |
287 | dump_ccreg ("icc", ccr & 15); | |
288 | } | |
289 | } | |
290 | ||
cb747ec5 DE |
291 | /* We try to support 32 bit and 64 bit pointers. |
292 | We are called when the Shade target is selected by shadeif.c. */ | |
293 | ||
294 | int target_ptr_bit = 64; /* default */ | |
295 | ||
296 | void | |
297 | set_target_ptr_bit(ptr_bit) | |
298 | int ptr_bit; | |
299 | { | |
300 | target_ptr_bit = ptr_bit; | |
301 | } |