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" | |
cb747ec5 DE |
26 | |
27 | /*#include "symfile.h" /* for objfiles.h */ | |
28 | /*#include "objfiles.h" /* for find_pc_section */ | |
29 | ||
30 | /* This file contains replacements and additions to sparc-tdep.c only. | |
31 | Some of this code has been written for a day when we can merge at least | |
32 | some of this with sparc-tdep.c. Macro TARGET_SPARC64 exists to allow some | |
33 | code to potentially be used by both. */ | |
34 | ||
35 | #define TARGET_SPARC64 1 /* later make a config parm or some such */ | |
36 | ||
37 | /* From infrun.c */ | |
38 | extern int stop_after_trap; | |
39 | ||
40 | /* Branches with prediction are treated like their non-predicting cousins. */ | |
41 | /* FIXME: What about floating point branches? */ | |
42 | ||
43 | typedef enum | |
44 | { | |
45 | Error, not_branch, bicc, bicca, ba, baa, ticc, ta, done_retry | |
46 | } branch_type; | |
47 | ||
48 | /* Simulate single-step ptrace call for sun4. Code written by Gary | |
49 | Beihl (beihl@mcc.com). */ | |
50 | ||
51 | /* npc4 and next_pc describe the situation at the time that the | |
52 | step-breakpoint was set, not necessary the current value of NPC_REGNUM. */ | |
53 | static CORE_ADDR next_pc, npc4, target; | |
54 | static int brknpc4, brktrg; | |
55 | typedef char binsn_quantum[BREAKPOINT_MAX]; | |
56 | static binsn_quantum break_mem[3]; | |
57 | ||
58 | /* Non-zero if we just simulated a single-step ptrace call. This is | |
59 | needed because we cannot remove the breakpoints in the inferior | |
60 | process until after the `wait' in `wait_for_inferior'. Used for | |
61 | sun4. */ | |
62 | ||
63 | int one_stepped; | |
64 | ||
65 | /* sparc64_single_step() is called just before we want to resume the inferior, | |
66 | if we want to single-step it but there is no hardware or kernel single-step | |
67 | support (as on all SPARCs). We find all the possible targets of the | |
68 | coming instruction and breakpoint them. | |
69 | ||
70 | single_step is also called just after the inferior stops. If we had | |
71 | set up a simulated single-step, we undo our damage. */ | |
72 | ||
73 | /* FIXME: When the code is releasable, sparc's single step could become this | |
74 | one, removing the duplication. */ | |
75 | ||
76 | void | |
77 | sparc64_single_step (ignore) | |
78 | int ignore; /* pid, but we don't need it */ | |
79 | { | |
80 | branch_type br, isbranch(); | |
81 | CORE_ADDR pc; | |
82 | long pc_instruction; | |
83 | ||
84 | if (!one_stepped) | |
85 | { | |
86 | /* Always set breakpoint for NPC. */ | |
87 | next_pc = read_register (NPC_REGNUM); | |
88 | npc4 = next_pc + 4; /* branch not taken */ | |
89 | ||
90 | target_insert_breakpoint (next_pc, break_mem[0]); | |
199b2450 | 91 | /* printf_unfiltered ("set break at %x\n",next_pc); */ |
cb747ec5 DE |
92 | |
93 | pc = read_register (PC_REGNUM); | |
94 | pc_instruction = read_memory_integer (pc, sizeof(pc_instruction)); | |
95 | br = isbranch (pc_instruction, pc, &target); | |
96 | brknpc4 = brktrg = 0; | |
97 | ||
98 | if (br == bicca) | |
99 | { | |
100 | /* Conditional annulled branch will either end up at | |
101 | npc (if taken) or at npc+4 (if not taken). | |
102 | Trap npc+4. */ | |
103 | brknpc4 = 1; | |
104 | target_insert_breakpoint (npc4, break_mem[1]); | |
105 | } | |
106 | else if ((br == baa && target != next_pc) | |
107 | || (TARGET_SPARC64 && br == done_retry)) | |
108 | { | |
109 | /* Unconditional annulled branch will always end up at | |
110 | the target. */ | |
111 | brktrg = 1; | |
112 | target_insert_breakpoint (target, break_mem[2]); | |
113 | } | |
114 | ||
115 | /* We are ready to let it go */ | |
116 | one_stepped = 1; | |
117 | return; | |
118 | } | |
119 | else | |
120 | { | |
121 | /* Remove breakpoints */ | |
122 | target_remove_breakpoint (next_pc, break_mem[0]); | |
123 | ||
124 | if (brknpc4) | |
125 | target_remove_breakpoint (npc4, break_mem[1]); | |
126 | ||
127 | if (brktrg) | |
128 | target_remove_breakpoint (target, break_mem[2]); | |
129 | ||
130 | one_stepped = 0; | |
131 | } | |
132 | } | |
133 | \f | |
cb747ec5 DE |
134 | CORE_ADDR |
135 | sparc64_extract_struct_value_address (regbuf) | |
136 | char regbuf[REGISTER_BYTES]; | |
137 | { | |
138 | CORE_ADDR addr; | |
139 | ||
140 | /* FIXME: We assume a non-leaf function. */ | |
141 | addr = read_register (I0_REGNUM); | |
142 | return addr; | |
143 | } | |
144 | ||
cb747ec5 DE |
145 | /* Check instruction at ADDR to see if it is an annulled branch or other |
146 | instruction whose npc isn't pc+4 (eg: trap, done, retry). | |
147 | All other instructions will go to NPC or will trap. | |
148 | Set *TARGET if we find a candidate branch; set to zero if not. */ | |
149 | ||
150 | branch_type | |
151 | isbranch (instruction, addr, target) | |
152 | long instruction; | |
153 | CORE_ADDR addr, *target; | |
154 | { | |
155 | branch_type val = not_branch; | |
156 | long int offset; /* Must be signed for sign-extend. */ | |
157 | union | |
158 | { | |
159 | unsigned long int code; | |
160 | struct | |
161 | { | |
162 | unsigned int op:2; | |
163 | unsigned int a:1; | |
164 | unsigned int cond:4; | |
165 | unsigned int op2:3; | |
166 | unsigned int disp22:22; | |
167 | } b; | |
168 | struct | |
169 | { | |
170 | unsigned int op:2; | |
171 | unsigned int a:1; | |
172 | unsigned int cond:4; | |
173 | unsigned int op2:3; | |
174 | unsigned int cc:2; | |
175 | unsigned int p:1; | |
176 | unsigned int disp19:19; | |
177 | } bp; | |
178 | struct | |
179 | { | |
180 | unsigned int op:2; | |
181 | unsigned int a:1; | |
182 | unsigned int zero:1; | |
183 | unsigned int rcond:3; | |
184 | unsigned int op2:3; | |
185 | unsigned int disp16hi:2; | |
186 | unsigned int p:1; | |
187 | unsigned int rs1:5; | |
188 | unsigned int disp16lo:14; | |
189 | } bpr; | |
190 | struct | |
191 | { | |
192 | unsigned int op:2; | |
193 | unsigned int fcn:5; | |
194 | unsigned int op3:6; | |
195 | unsigned int reserved:19; | |
196 | } dr; | |
197 | } insn; | |
198 | ||
199 | *target = 0; | |
200 | insn.code = instruction; | |
201 | ||
202 | if (insn.b.op == 0 | |
203 | && (insn.b.op2 == 1 || insn.b.op2 == 2 || insn.b.op2 ==3 | |
204 | || insn.b.op2 == 5 || insn.b.op2 == 6)) | |
205 | { | |
206 | if (insn.b.cond == 8) | |
207 | val = insn.b.a ? baa : ba; | |
208 | else | |
209 | val = insn.b.a ? bicca : bicc; | |
210 | switch (insn.b.op2) | |
211 | { | |
212 | case 1: /* bpcc */ | |
213 | offset = 4 * ((int) (insn.bp.disp19 << 13) >> 13); | |
214 | break; | |
215 | case 2: /* bicc */ | |
216 | offset = 4 * ((int) (insn.b.disp22 << 10) >> 10); | |
217 | break; | |
218 | case 3: /* bpr */ | |
219 | offset = 4 * ((int) ((insn.bpr.disp16hi << 10) | |
220 | || (insn.bpr.disp16lo << 18)) >> 13); | |
221 | break; | |
222 | case 5: /* fbpfcc */ | |
223 | offset = 4 * ((int) (insn.bp.disp19 << 13) >> 13); | |
224 | break; | |
225 | case 6: /* fbfcc */ | |
226 | offset = 4 * ((int) (insn.b.disp22 << 10) >> 10); | |
227 | break; | |
228 | } | |
229 | *target = addr + offset; | |
230 | } | |
231 | else if (insn.dr.op == 2 && insn.dr.op3 == 62) | |
232 | { | |
233 | if (insn.dr.fcn == 0) | |
234 | { | |
235 | /* done */ | |
236 | *target = read_register (TNPC_REGNUM); | |
237 | val = done_retry; | |
238 | } | |
239 | else if (insn.dr.fcn == 1) | |
240 | { | |
241 | /* retry */ | |
242 | *target = read_register (TPC_REGNUM); | |
243 | val = done_retry; | |
244 | } | |
245 | } | |
246 | ||
247 | return val; | |
248 | } | |
249 | ||
b562a186 DE |
250 | /* PRINT_REGISTER_HOOK routine. |
251 | Pretty print various registers. */ | |
252 | ||
253 | static void | |
254 | dump_ccreg (reg, val) | |
255 | char *reg; | |
256 | int val; | |
257 | { | |
199b2450 | 258 | printf_unfiltered ("%s:%s,%s,%s,%s", reg, |
b562a186 DE |
259 | val & 8 ? "N" : "NN", |
260 | val & 4 ? "Z" : "NZ", | |
261 | val & 2 ? "O" : "NO", | |
262 | val & 1 ? "C" : "NC" | |
263 | ); | |
264 | } | |
265 | ||
266 | void | |
267 | sparc_print_register_hook (regno) | |
268 | int regno; | |
269 | { | |
270 | if (((unsigned) (regno) - FP0_REGNUM < FP_MAX_REGNUM - FP0_REGNUM) | |
271 | && ((regno) & 1) == 0) | |
272 | { | |
273 | char doublereg[8]; /* two float regs */ | |
274 | if (!read_relative_register_raw_bytes ((regno), doublereg)) | |
275 | { | |
199b2450 TL |
276 | printf_unfiltered("\t"); |
277 | print_floating (doublereg, builtin_type_double, gdb_stdout); | |
b562a186 DE |
278 | } |
279 | } | |
280 | else if ((regno) == CCR_REGNUM) | |
281 | { | |
282 | int ccr = read_register (CCR_REGNUM); | |
199b2450 | 283 | printf_unfiltered("\t"); |
b562a186 | 284 | dump_ccreg ("xcc", ccr >> 4); |
199b2450 | 285 | printf_unfiltered(", "); |
b562a186 DE |
286 | dump_ccreg ("icc", ccr & 15); |
287 | } | |
288 | } |