Commit | Line | Data |
---|---|---|
be9a2362 FF |
1 | /* Machine-dependent code which would otherwise be in inflow.c and core.c, |
2 | for GDB, the GNU debugger. | |
3 | Copyright (C) 1992 Free Software Foundation, Inc. | |
4 | This code is for the i860 cpu. | |
5 | Contributed by Peggy Fieland (pfieland@stratus.com) | |
6 | ||
7 | GDB is distributed in the hope that it will be useful, but WITHOUT ANY | |
8 | WARRANTY. No author or distributor accepts responsibility to anyone | |
9 | for the consequences of using it or for whether it serves any | |
10 | particular purpose or works at all, unless he says so in writing. | |
11 | Refer to the GDB General Public License for full details. | |
12 | ||
13 | Everyone is granted permission to copy, modify and redistribute GDB, | |
14 | but only under the conditions described in the GDB General Public | |
15 | License. A copy of this license is supposed to have been given to you | |
16 | along with GDB so you can know your rights and responsibilities. It | |
17 | should be in a file named COPYING. Among other things, the copyright | |
18 | notice and this notice must be preserved on all copies. | |
19 | ||
20 | In other words, go ahead and share GDB, but don't try to stop | |
21 | anyone else from sharing it farther. Help stamp out software hoarding! | |
22 | */ | |
23 | ||
24 | #include "defs.h" | |
25 | #include "tm-i860.h" | |
26 | #include "frame.h" | |
27 | #include "inferior.h" | |
28 | #include "obstack.h" | |
29 | #include "symtab.h" | |
30 | #include "value.h" | |
31 | ||
32 | #include "tm-i860.h" | |
33 | #include "i860-opcode.h" | |
34 | ||
35 | #include <stdio.h> | |
36 | #include "break.h" | |
37 | ||
38 | #ifdef notdef | |
39 | ||
40 | #include <sys/types.h> | |
41 | #include <sys/param.h> | |
42 | #include <sys/dir.h> | |
43 | ||
44 | #endif | |
45 | ||
46 | #include <signal.h> | |
47 | #include <sys/ioctl.h> | |
48 | #include <fcntl.h> | |
49 | ||
50 | /* #include <sys/reg.h> */ | |
51 | #include "i860_reg.h" | |
52 | ||
53 | #include <a.out.h> | |
54 | #include <sys/file.h> | |
55 | #include <sys/stat.h> | |
56 | #include <core.h> | |
57 | ||
58 | #include <sys/user.h> | |
59 | ||
60 | #include <elf.h> | |
61 | #include <sys/elftypes.h> | |
62 | #include <sys/elf_860.h> | |
63 | #include <libelf.h> | |
64 | ||
65 | ||
66 | int btdebug = 0; /* change value to 1 to enable debugging code */ | |
67 | ||
68 | #define BTDEBUG if (btdebug) btdebug_message | |
69 | ||
70 | #include <stdarg.h> | |
71 | ||
72 | int read_memory(); | |
73 | int write_memory(); | |
74 | ||
75 | btdebug_message(char *format, ...) | |
76 | { | |
77 | va_list arglist; | |
78 | va_start( arglist, format ); | |
79 | ||
80 | if( btdebug ) | |
81 | vfprintf (stderr, format, arglist ); | |
82 | va_end ( arglist ); | |
83 | } | |
84 | ||
85 | extern int errno; | |
86 | extern int attach_flag; | |
87 | ||
88 | ||
89 | /* This is used when GDB is exiting. It gives less chance of error.*/ | |
90 | ||
91 | ||
92 | /* Simulate single-step ptrace call for sun4. Code written by Gary | |
93 | Beihl (beihl@mcc.com). */ | |
94 | /* Modified for i860 by Jim Hanko (hanko@orc.olivetti.com) */ | |
95 | ||
96 | ||
97 | static struct breakpoint brk; | |
98 | typedef char binsn_quantum[sizeof break_insn]; | |
99 | static binsn_quantum break_mem[2]; | |
100 | ||
101 | /* Non-zero if we just simulated a single-step ptrace call. This is | |
102 | needed because we cannot remove the breakpoints in the inferior | |
103 | process until after the `wait' in `wait_for_inferior'. Used for | |
104 | i860. */ | |
105 | ||
106 | int one_stepped; | |
107 | void | |
108 | single_step (signal) | |
109 | int signal; | |
110 | { | |
111 | CORE_ADDR pc; | |
112 | branch_type place_brk(); | |
113 | ||
114 | pc = read_register (PC_REGNUM); | |
115 | ||
116 | if (!one_stepped) | |
117 | { | |
118 | brk.address = pc; | |
119 | place_brk (pc, SINGLE_STEP_MODE, &brk); | |
120 | brk.shadow_contents[0] = brk.shadow_contents[1] = 0; | |
121 | brk.shadow_contents[2] = brk.shadow_contents[3] = 0; | |
122 | ||
123 | if (brk.mode == DIM) | |
124 | { | |
125 | if ( brk.address1 ) | |
126 | { | |
127 | printf(" DIM1 ->"); | |
128 | printf(" %x : ", brk.act_addr[3]); | |
129 | print_insn( brk.act_addr[3], stdout); | |
130 | printf("\t -|- "); | |
131 | printf(" %x : ", brk.act_addr[2]); | |
132 | print_insn( brk.act_addr[2], stdout); | |
133 | printf("\n"); | |
134 | fflush(stdout); | |
135 | ||
136 | adj_read_memory (brk.act_addr[2], &brk.shadow_contents[2], 4); | |
137 | adj_write_memory (brk.act_addr[2], break_insn, 4); | |
138 | adj_read_memory (brk.act_addr[3], &brk.shadow_contents[3], 4); | |
139 | /* adj_write_memory (brk.act_addr[3], float_insn, 4); */ | |
140 | ||
141 | } | |
142 | if ( brk.address1) | |
143 | printf(" DIM2 ->"); | |
144 | else | |
145 | printf(" DIM1 ->"); | |
146 | ||
147 | printf(" %x : ", brk.act_addr[1]); | |
148 | print_insn( brk.act_addr[1], stdout); | |
149 | printf("\t -|- "); | |
150 | printf(" %x : ", brk.act_addr[0]); | |
151 | print_insn( brk.act_addr[0], stdout); | |
152 | printf("\n"); | |
153 | fflush(stdout); | |
154 | ||
155 | adj_read_memory (brk.act_addr[0], &brk.shadow_contents[0], 4); | |
156 | adj_write_memory (brk.act_addr[0], break_insn, 4); | |
157 | adj_read_memory (brk.act_addr[1], &brk.shadow_contents[1], 4); | |
158 | /* adj_write_memory (brk.act_addr[1], float_insn, 4); */ | |
159 | ||
160 | } | |
161 | else { | |
162 | if (brk.address1) | |
163 | { | |
164 | if (btdebug) | |
165 | { | |
166 | printf(" SIM1 ->"); | |
167 | printf(" %x : ", brk.act_addr[2]); | |
168 | print_insn( brk.act_addr[2], stdout); | |
169 | printf("\n"); | |
170 | fflush(stdout); | |
171 | } | |
172 | adj_read_memory (brk.act_addr[2], &brk.shadow_contents[2], 4); | |
173 | adj_write_memory (brk.act_addr[2], break_insn, 4); | |
174 | } | |
175 | if (btdebug) | |
176 | { | |
177 | if ( brk.address1) | |
178 | printf(" SIM2 ->"); | |
179 | else | |
180 | printf(" SIM1 ->"); | |
181 | ||
182 | printf(" %x : ", brk.act_addr[0]); | |
183 | print_insn( brk.act_addr[0], stdout); | |
184 | printf("\n"); | |
185 | fflush(stdout); | |
186 | } | |
187 | adj_read_memory (brk.act_addr[0], &brk.shadow_contents[0], 4); | |
188 | adj_write_memory (brk.act_addr[0], break_insn, 4); | |
189 | } | |
190 | ||
191 | /* Let it go */ | |
192 | one_stepped = 1; | |
193 | return; | |
194 | } | |
195 | else | |
196 | { | |
197 | /* Remove breakpoints */ | |
198 | if (brk.mode == DIM) | |
199 | { | |
200 | adj_write_memory (brk.act_addr[0], &brk.shadow_contents[0], 4); | |
201 | adj_write_memory (brk.act_addr[1], &brk.shadow_contents[1], 4); | |
202 | } else { | |
203 | adj_write_memory (brk.act_addr[0], &brk.shadow_contents[0], 4); | |
204 | } | |
205 | ||
206 | if (brk.address1) | |
207 | { | |
208 | if (brk.mode == DIM) | |
209 | { | |
210 | adj_write_memory (brk.act_addr[2], &brk.shadow_contents[2], 4); | |
211 | adj_write_memory (brk.act_addr[3], &brk.shadow_contents[3], 4); | |
212 | } else { | |
213 | adj_write_memory (brk.act_addr[2], &brk.shadow_contents[2], 4); | |
214 | } | |
215 | } | |
216 | one_stepped = 0; | |
217 | } | |
218 | } | |
219 | ||
220 | ||
221 | \f | |
222 | ||
223 | /* return nonzero if the routine containing pc has been | |
224 | * compiled with -g. We assume -g if the first instruction is | |
225 | * an addu|adds -X,sp and the second is st.l fp,XX(sp) | |
226 | * | |
227 | * based on skip_prologue(); | |
228 | */ | |
229 | ||
230 | g_routine(pc) | |
231 | CORE_ADDR pc; | |
232 | { | |
233 | long instr; | |
234 | int regno; | |
235 | CORE_ADDR top_pc; | |
236 | ||
237 | top_pc = get_pc_function_start(pc); | |
238 | if (top_pc) | |
239 | { | |
240 | instr = adj_read_memory_integer (top_pc); | |
241 | /* Recognize "addu|adds -X,sp,sp" insn. */ | |
242 | ||
243 | if ((instr & 0xEFFF0000) == 0x84420000) | |
244 | { | |
245 | top_pc += 4; | |
246 | instr = adj_read_memory_integer (top_pc); | |
247 | ||
248 | if( (instr & 0xFFE0F801) == 0x1C401801 ) /* st.l fp,X(sp) */ | |
249 | return(1); | |
250 | } | |
251 | } | |
252 | return(0); | |
253 | } | |
254 | ||
255 | ||
256 | /* Written for i860 by Jim Hanko (hanko@orc.olivetti.com) */ | |
257 | /* This code was based on SPARC code written by Gary Beihl (beihl@mcc.com), | |
258 | by Michael Tiemann (tiemann@corto.inria.fr). */ | |
259 | ||
260 | struct command_line *get_breakpoint_commands (); | |
261 | ||
262 | CORE_ADDR | |
263 | skip_prologue (pc) | |
264 | CORE_ADDR pc; | |
265 | { | |
266 | long instr; | |
267 | int regno; | |
268 | ||
269 | instr = adj_read_memory_integer (pc); | |
270 | ||
271 | /* Recognize "addu|adds -X,sp,sp" insn. */ | |
272 | if ((instr & 0xEFFF0000) == 0x84420000) | |
273 | { | |
274 | pc += 4; | |
275 | instr = adj_read_memory_integer (pc); | |
276 | } | |
277 | else | |
278 | return(pc); /* No frame! */ | |
279 | ||
280 | /* Recognize store of return addr and frame pointer into frame */ | |
281 | while (1) | |
282 | { | |
283 | if ((instr & 0xFFE0F801) == 0x1C400801 || /* st.l r1,X(sp) */ | |
284 | (instr & 0xFFE0F801) == 0x1C401801) /* st.l fp,X(sp) */ | |
285 | { | |
286 | pc += 4; | |
287 | instr = adj_read_memory_integer (pc); | |
288 | } | |
289 | else | |
290 | break; | |
291 | } | |
292 | ||
293 | /* Recognize "addu|adds X,sp,fp" insn. */ | |
294 | if ((instr & 0xEFFF0000) == 0x84430000) | |
295 | { | |
296 | pc += 4; | |
297 | instr = adj_read_memory_integer (pc); | |
298 | } | |
299 | ||
300 | /* Now recognize stores into the frame from the registers. */ | |
301 | ||
302 | while (1) | |
303 | { | |
304 | if ((instr & 0xFFA00003) == 0x1C200001 || /* st.l rn,X(fp|sp) */ | |
305 | (instr & 0xFFA00001) == 0x4C200000) /* fst.y fn,X(fp|sp) */ | |
306 | { | |
307 | regno = (instr >> 11) & 0x1f; | |
308 | if (regno == 0) /* source reg == 0? quit */ | |
309 | break; | |
310 | pc += 4; | |
311 | instr = adj_read_memory_integer (pc); | |
312 | } | |
313 | else | |
314 | break; | |
315 | } | |
316 | ||
317 | return(pc); | |
318 | } | |
319 | ||
320 | ||
321 | /* Set *nextpc to branch target if we find a branch. If it is not a branch, | |
322 | set it to the next instruction (addr + 4) */ | |
323 | ||
324 | ||
325 | branch_type | |
326 | isabranch (addr, nextpc) | |
327 | CORE_ADDR addr, *nextpc; | |
328 | { | |
329 | long instr; | |
330 | branch_type val = not_branch; | |
331 | long offset; /* Must be signed for sign-extend */ | |
332 | ||
333 | printf(" isabranch\n"); | |
334 | *nextpc = addr; | |
335 | instr = adj_read_memory_integer (addr); | |
336 | ||
337 | if ((instr & 0xE0000000) == 0x60000000 && /* CTRL format */ | |
338 | (instr & 0xF8000000) != 0x60000000) /* not pfld.y */ | |
339 | { | |
340 | if ((instr & 0xF8000000) == 0x68000000) /* br or call */ | |
341 | val = uncond_d; | |
342 | else if ((instr & 0xF4000000) == 0x74000000) /* bc.t or bnc.t */ | |
343 | val = cond_d; | |
344 | else if ((instr & 0xF4000000) == 0x70000000) /* bc or bnc */ | |
345 | val = cond; | |
346 | ||
347 | offset = (instr & 0x03ffffff); | |
348 | if (offset & 0x02000000) /* sign extend? */ | |
349 | offset |= 0xFC000000; | |
350 | *nextpc = addr + 4 + (offset << 2); | |
351 | } | |
352 | else if ((instr & 0xFC00003F) == 0x4C000002 || /* calli */ | |
353 | (instr & 0xFC000000) == 0x40000000) /* bri */ | |
354 | { | |
355 | val = uncond_d; | |
356 | offset = ((instr & 0x0000F800) >> 11); | |
357 | *nextpc = (read_register(offset) & 0xFFFFFFFC); | |
358 | } | |
359 | else if ((instr & 0xF0000000) == 0x50000000) /* bte or btne */ | |
360 | { | |
361 | val = cond; | |
362 | ||
363 | offset = SIGN_EXT16(((instr & 0x001F0000) >> 5) | (instr & 0x000007FF)); | |
364 | *nextpc = addr + 4 + (offset << 2); | |
365 | } | |
366 | else if ((instr & 0xFC000000) == 0xB4000000) /* bla */ | |
367 | { | |
368 | val = cond_d; | |
369 | ||
370 | offset = SIGN_EXT16(((instr & 0x001F0000) >> 5) | (instr & 0x000007FF)); | |
371 | *nextpc = addr + 4 + (offset << 2); | |
372 | } | |
373 | ||
374 | printf(" Final addr - %x\n", *nextpc); | |
375 | /*printf("isabranch ret: %d\n",val); */ | |
376 | return val; | |
377 | } | |
378 | ||
379 | /* set in call_function() [valops.c] to the address of the "call dummy" code | |
380 | so dummy frames can be easily recognized; also used in wait_for_inferior() | |
381 | [infrun.c]. When not used, it points into the ABI's 'reserved area' */ | |
382 | ||
383 | CORE_ADDR call_dummy_set = 0; /* true if dummy call being done */ | |
384 | CORE_ADDR call_dummy_start; /* address of call dummy code */ | |
385 | ||
386 | frame_find_saved_regs(frame_info, frame_saved_regs) | |
387 | struct frame_info *frame_info; | |
388 | struct frame_saved_regs *frame_saved_regs; | |
389 | { | |
390 | register CORE_ADDR pc; | |
391 | long instr, spdelta = 0, offset; | |
392 | int i, size, reg; | |
393 | int r1_off = -1, fp_off = -1; | |
394 | int framesize; | |
395 | ||
396 | bzero (frame_saved_regs, sizeof(*frame_saved_regs)); | |
397 | ||
398 | if (call_dummy_set && frame_info->pc >= call_dummy_start && | |
399 | frame_info->pc <= call_dummy_start + CALL_DUMMY_LENGTH) | |
400 | { | |
401 | /* DUMMY frame - all registers stored in order at fp; old sp is | |
402 | at fp + NUM_REGS*4 */ | |
403 | ||
404 | for (i = 1; i < NUM_REGS; i++) /* skip reg 0 */ | |
405 | if (i != SP_REGNUM && i != FP0_REGNUM && i != FP0_REGNUM + 1) | |
406 | frame_saved_regs->regs[i] = frame_info->frame + i*4; | |
407 | ||
408 | frame_saved_regs->regs[SP_REGNUM] = frame_info->frame + NUM_REGS*4; | |
409 | ||
410 | call_dummy_set = 0; | |
411 | return; | |
412 | } | |
413 | ||
414 | pc = get_pc_function_start (frame_info->pc); | |
415 | if (pc) | |
416 | { | |
417 | instr = adj_read_memory_integer (pc); | |
418 | /* Recognize "addu|adds -X,sp,sp" insn. */ | |
419 | if ((instr & 0xEFFF0000) == 0x84420000) | |
420 | { | |
421 | framesize = -SIGN_EXT16(instr & 0x0000FFFF); | |
422 | pc += 4; | |
423 | instr = adj_read_memory_integer (pc); | |
424 | } | |
425 | } | |
426 | else | |
427 | goto punt; /* No frame! */ | |
428 | ||
429 | /* Recognize store of return addr and frame pointer into frame */ | |
430 | while (1) | |
431 | { | |
432 | if ((instr & 0xFFE0F801) == 0x1C400801) /* st.l r1,X(sp) */ | |
433 | { | |
434 | r1_off = SIGN_EXT16(((instr&0x001F0000) >> 5) | (instr&0x000007FE)); | |
435 | pc += 4; | |
436 | instr = adj_read_memory_integer (pc); | |
437 | } | |
438 | else if ((instr & 0xFFE0F801) == 0x1C401801) /* st.l fp,X(sp) */ | |
439 | { | |
440 | fp_off = SIGN_EXT16(((instr&0x001F0000) >> 5) | (instr&0x000007FE)); | |
441 | pc += 4; | |
442 | instr = adj_read_memory_integer (pc); | |
443 | } | |
444 | else | |
445 | break; | |
446 | } | |
447 | ||
448 | /* Recognize "addu|adds X,sp,fp" insn. */ | |
449 | if ((instr & 0xEFFF0000) == 0x84430000) | |
450 | { | |
451 | spdelta = SIGN_EXT16(instr & 0x0000FFFF); | |
452 | pc += 4; | |
453 | instr = adj_read_memory_integer (pc); | |
454 | } | |
455 | ||
456 | /* Now recognize stores into the frame from the registers. */ | |
457 | ||
458 | while (1) | |
459 | { | |
460 | if ((instr & 0xFFC00003) == 0x1C400001) /* st.l rn,X(fp|sp) */ | |
461 | { | |
462 | offset = SIGN_EXT16(((instr&0x001F0000) >> 5) | (instr&0x000007FE)); | |
463 | reg = (instr >> 11) & 0x1F; | |
464 | if (reg == 0) | |
465 | break; | |
466 | if ((instr & 0x00200000) == 0) /* was this using sp? */ | |
467 | if (spdelta) /* and we know sp-fp delta */ | |
468 | offset -= spdelta; /* if so, adjust the offset */ | |
469 | else | |
470 | break; /* if not, give up */ | |
471 | ||
472 | ||
473 | /* Handle the case where the return address is stored after the fp | |
474 | is adjusted */ | |
475 | ||
476 | if (reg == 1) | |
477 | frame_saved_regs->regs[PC_REGNUM] = frame_info->frame + offset; | |
478 | else | |
479 | frame_saved_regs->regs[reg] = frame_info->frame + offset; | |
480 | ||
481 | pc += 4; | |
482 | instr = adj_read_memory_integer (pc); | |
483 | } | |
484 | else if ((instr & 0xFFC00001) == 0x2C400000) /* fst.y fn,X(fp|sp) */ | |
485 | { | |
486 | /* | |
487 | * The number of words in a floating store based on 3 LSB of instr | |
488 | */ | |
489 | static int fst_sizes[] = {2, 0, 1, 0, 4, 0, 1, 0}; | |
490 | ||
491 | size = fst_sizes[instr & 7]; | |
492 | reg = ((instr >> 16) & 0x1F) + FP0_REGNUM; | |
493 | if (reg == 0) | |
494 | break; | |
495 | ||
496 | if (size > 1) /* align the offset */ | |
497 | offset = SIGN_EXT16(instr & 0x0000FFF8); /* drop 3 bits */ | |
498 | else | |
499 | offset = SIGN_EXT16(instr & 0x0000FFFC); /* drop 2 bits */ | |
500 | ||
501 | if ((instr & 0x00200000) == 0) /* was this using sp? */ | |
502 | if (spdelta) /* and we know sp-fp delta */ | |
503 | offset -= spdelta; /* if so, adjust the offset */ | |
504 | else | |
505 | break; /* if not, give up */ | |
506 | ||
507 | for (i = 0; i < size; i++) | |
508 | { | |
509 | frame_saved_regs->regs[reg] = frame_info->frame + offset; | |
510 | ||
511 | offset += 4; | |
512 | reg++; | |
513 | } | |
514 | ||
515 | pc += 4; | |
516 | instr = adj_read_memory_integer (pc); | |
517 | } | |
518 | else | |
519 | break; | |
520 | } | |
521 | ||
522 | punt: ; | |
523 | if (framesize != 0 && spdelta != 0) | |
524 | frame_saved_regs->regs[SP_REGNUM] = frame_info->frame+(framesize-spdelta); | |
525 | else | |
526 | frame_saved_regs->regs[SP_REGNUM] = frame_info->frame + 8; | |
527 | ||
528 | if (spdelta && fp_off != -1) | |
529 | frame_saved_regs->regs[FP_REGNUM] = frame_info->frame - spdelta + fp_off; | |
530 | else | |
531 | frame_saved_regs->regs[FP_REGNUM] = frame_info->frame; | |
532 | ||
533 | if (spdelta && r1_off != -1) | |
534 | frame_saved_regs->regs[PC_REGNUM] = frame_info->frame - spdelta + r1_off; | |
535 | else | |
536 | frame_saved_regs->regs[PC_REGNUM] = frame_info->frame + 4; | |
537 | } | |
538 | ||
539 | /* return the stack offset where the fp register is stored */ | |
540 | find_fp_offset(pc) | |
541 | { | |
542 | int fp_off,i; | |
543 | long instr; | |
544 | ||
545 | /* look for the instruction and examine the offset */ | |
546 | ||
547 | for(i=4; i<16; i+=4){ | |
548 | instr = adj_read_memory_integer(pc+i); | |
549 | if( (instr & 0xFFE0F801) == 0x1C401801) { /* st.l fp,X(sp) */ | |
550 | ||
551 | fp_off = SIGN_EXT16(((instr&0x001F0000) >> 5) | | |
552 | (instr&0x000007FE)); | |
553 | return(fp_off); | |
554 | } | |
555 | } | |
556 | return(0); | |
557 | } | |
558 | ||
559 | /* return the stack offset where r1 (return linkage ) register is stored */ | |
560 | ||
561 | find_r1_offset(pc) | |
562 | { | |
563 | int r1_off,i; | |
564 | long instr; | |
565 | ||
566 | /* look for the instruction and examine the offset */ | |
567 | ||
568 | for(i=4; i<16; i+=4){ | |
569 | ||
570 | instr = adj_read_memory_integer(pc+i); | |
571 | if ((instr & 0xFFE0F801) == 0x1C400801) { /* st.l r1,X(sp) */ | |
572 | ||
573 | r1_off = SIGN_EXT16(((instr&0x001F0000) >> 5) | | |
574 | (instr&0x000007FE)); | |
575 | return(r1_off); | |
576 | } | |
577 | } | |
578 | return(-1); | |
579 | } | |
580 | ||
581 | ||
582 | /* dose routine starting at pc build a stack frame of any kind?? */ | |
583 | has_a_frame(pc) | |
584 | { | |
585 | if( skip_prologue(pc) != pc )return(1); | |
586 | else return(0); | |
587 | } | |
588 | ||
589 | /* get the frame pointer of the caller. | |
590 | * note that only routines that have been compiled with | |
591 | * -g have full (XX)fp style stack frames | |
592 | * if we are not returning to a non -g caller then we | |
593 | * return the sp at entry to us as it is the caller's | |
594 | * frame reference. | |
595 | */ | |
596 | ||
597 | frame_chain(thisframe) | |
598 | FRAME thisframe; | |
599 | { | |
600 | unsigned long fp, sp, pc; | |
601 | unsigned long func_start; | |
602 | long instr; | |
603 | int offset; | |
604 | unsigned long thisfp = thisframe->frame; | |
605 | ||
606 | /* get the frame pointer actually sp for a non -g | |
607 | * for the routine that called us routine | |
608 | */ | |
609 | ||
610 | BTDEBUG("FRAME_CHAIN(%x)\n",thisframe); | |
611 | ||
612 | if ( !read_memory_integer (thisframe->frame,4)) | |
613 | { | |
614 | return (0); | |
615 | } | |
616 | ||
617 | if( ! g_routine(thisframe->pc) ){ | |
618 | BTDEBUG( "non g at %x\n",thisframe->pc); | |
619 | caller_pc(thisframe->pc,thisframe->sp,&pc,&fp); | |
620 | BTDEBUG("caller_pc returned %x %x \n",pc,fp); | |
621 | return(fp); | |
622 | ||
623 | }/* else a -g routine */ | |
624 | ||
625 | ||
626 | fp = read_memory_integer (thisfp, 4); | |
627 | ||
628 | if (fp < thisfp || fp > STACK_END_ADDR) | |
629 | { | |
630 | /* handle the Metaware-type pseudo-frame */ | |
631 | ||
632 | func_start = get_pc_function_start(thisframe->pc); | |
633 | ||
634 | if (func_start) | |
635 | { | |
636 | ||
637 | instr = adj_read_memory_integer (func_start); | |
638 | /* Recognize "addu|adds -X,sp,sp" insn. */ | |
639 | if ((instr & 0xEFFF0000) == 0x84420000) | |
640 | offset = SIGN_EXT16(instr & 0x0000FFFF); | |
641 | ||
642 | } | |
643 | ||
644 | fp = 0; | |
645 | if (offset < 0) | |
646 | fp = thisfp - offset; | |
647 | } | |
648 | BTDEBUG("frame_chain returned %d\n",fp); | |
649 | return(fp); | |
650 | } | |
651 | ||
652 | /* get the pc and frame pointer (or sp ) | |
653 | * for the routine that called us | |
654 | * when we (this_pc) is not within a -g routine | |
655 | * if caller is non g we return sp for fp | |
656 | */ | |
657 | ||
658 | /* note this is written for Metaware version R2.1d compiler */ | |
659 | ||
660 | caller_pc(this_pc,this_sp,to_pc,to_fp) | |
661 | int * to_pc, *to_fp; | |
662 | unsigned long this_pc,this_sp; | |
663 | { | |
664 | unsigned long func_start; | |
665 | int sp_offset,offset; | |
666 | unsigned long sp,pc,fp,instr; | |
667 | ||
668 | BTDEBUG("caller_pc %x sp = %x\n",this_pc,this_sp); | |
669 | ||
670 | func_start = get_pc_function_start(this_pc); | |
671 | ||
672 | BTDEBUG("caller_pc func_start %x\n", func_start); | |
673 | ||
674 | if (func_start) | |
675 | { | |
676 | if( has_a_frame(func_start) ){ | |
677 | ||
678 | BTDEBUG("has_a_frame\n"); | |
679 | ||
680 | /* if our caller has a preamble and | |
681 | * declares space for a stack frame | |
682 | * then we must work to find our return address | |
683 | */ | |
684 | instr = adj_read_memory_integer (func_start); | |
685 | /* Recognize "addu|adds -X,sp,sp" insn. */ | |
686 | ||
687 | if ((instr & 0xEFFF0000) == 0x84420000) | |
688 | sp_offset=SIGN_EXT16(instr&0x0000FFFF); | |
689 | } | |
690 | else { printf("error frame_chain\n");return(0); } | |
691 | ||
692 | BTDEBUG("sp_offset = %d %x\n",sp_offset,sp_offset); | |
693 | ||
694 | offset = find_r1_offset(func_start); | |
695 | ||
696 | if( offset < 0 ){ | |
697 | printf("cant find return address for routine at %x\n", | |
698 | func_start); | |
699 | return(0); | |
700 | } | |
701 | pc = read_memory_integer(this_sp+offset,4); | |
702 | sp= this_sp - sp_offset; | |
703 | ||
704 | BTDEBUG("callers pc = %x sp = %x\n",pc,sp); | |
705 | ||
706 | /* our caller a -g routine ? | |
707 | * if he is we have to find his real fp | |
708 | * else provide the sp as his fp | |
709 | */ | |
710 | ||
711 | if( g_routine(pc) ){ | |
712 | ||
713 | BTDEBUG("caller_a_g\n"); | |
714 | ||
715 | if( ! (offset = find_fp_offset(func_start)) ) { | |
716 | printf("error fp_offset\n"); | |
717 | return(0); | |
718 | } | |
719 | BTDEBUG("offset = %x %d\n",offset,offset); | |
720 | ||
721 | fp = read_memory_integer(this_sp+offset,4); | |
722 | *to_pc = CLEAN_PC(pc); | |
723 | *to_fp = fp; | |
724 | return(1); | |
725 | }else | |
726 | *to_pc = CLEAN_PC(pc); | |
727 | *to_fp = sp; | |
728 | return(1); | |
729 | } else { | |
730 | /* pc = read_register(RP_REGNUM); */ | |
731 | pc = 0; | |
732 | BTDEBUG("read_register pc %x\n",pc); | |
733 | if( g_routine(pc) ){ | |
734 | ||
735 | *to_pc = CLEAN_PC(pc); | |
736 | *to_fp = read_register(FP_REGNUM); | |
737 | return(1); | |
738 | }else { | |
739 | *to_pc = CLEAN_PC(pc); | |
740 | *to_fp = this_sp; | |
741 | return(1); | |
742 | } | |
743 | } | |
744 | } | |
745 | ||
746 | int outside_startup_file(); | |
747 | ||
748 | /* get the PC of the caller */ | |
749 | frame_saved_pc(frame_struct) | |
750 | FRAME frame_struct; | |
751 | { | |
752 | unsigned long frame; | |
753 | unsigned long pc; | |
754 | unsigned long pc1; | |
755 | unsigned long sp; | |
756 | ||
757 | CORE_ADDR fp; | |
758 | ||
759 | CORE_ADDR rp; | |
760 | ||
761 | frame = frame_struct->frame; | |
762 | pc = frame_struct->pc; | |
763 | BTDEBUG("frame_saved_pc input: frame %x, pc %x, sp %x ", | |
764 | frame, pc, sp); | |
765 | ||
766 | /* First see if this is the current frame. If it is, return the value in r1, | |
767 | as it may not have been stored */ | |
768 | ||
769 | fp = read_register(FP_REGNUM); | |
770 | ||
771 | /* check to see if we are in an entry sequence, where the return pointer has not yet been stored */ | |
772 | if (fp == frame && no_stored_rp(pc)) | |
773 | { | |
774 | pc = read_register(RP_REGNUM); | |
775 | frame_struct->rp = pc; | |
776 | } | |
777 | else if( ! g_routine(pc) ) | |
778 | { | |
779 | caller_pc(pc,sp,&pc,&frame); | |
780 | } | |
781 | else | |
782 | { | |
783 | ||
784 | pc = read_memory_integer (frame + 4, 4); | |
785 | ||
786 | if (!outside_startup_file(pc)) | |
787 | { | |
788 | ||
789 | BTDEBUG("pc %x outside startup file \n",pc); | |
790 | ||
791 | pc1 = read_memory_integer (frame, 4); | |
792 | ||
793 | if (outside_startup_file(pc1)) | |
794 | pc = pc1; | |
795 | else | |
796 | pc = 0; | |
797 | } | |
798 | } | |
799 | BTDEBUG(" returning pc %x\n", CLEAN_PC(pc)); | |
800 | return(CLEAN_PC(pc)); | |
801 | ||
802 | } | |
803 | ||
804 | /* Pass arguments to a function in the inferior process - ABI compliant | |
805 | */ | |
806 | ||
807 | pass_function_arguments(args, nargs, struct_return) | |
808 | value *args; | |
809 | int nargs; | |
810 | int struct_return; | |
811 | { | |
812 | int ireg = (struct_return) ? 17 : 16; | |
813 | int freg = FP0_REGNUM + 8; | |
814 | int i; | |
815 | struct type *type; | |
816 | value arg; | |
817 | long tmp; | |
818 | value value_arg_coerce(); | |
819 | ||
820 | ||
821 | for (i = 0; i < nargs; i++) | |
822 | { | |
823 | arg = value_arg_coerce(args[i]); | |
824 | type = VALUE_TYPE(arg); | |
825 | if (type == builtin_type_double) | |
826 | { | |
827 | write_register_bytes(REGISTER_BYTE(freg), VALUE_CONTENTS(arg), 8); | |
828 | freg += 2; | |
829 | } | |
830 | else | |
831 | { | |
832 | bcopy(VALUE_CONTENTS(arg), &tmp, 4); | |
833 | write_register(ireg, tmp); | |
834 | ireg++; | |
835 | } | |
836 | } | |
837 | if (ireg >= 28 || freg >= FP0_REGNUM + 16) | |
838 | error("Too many arguments to function"); | |
839 | } | |
840 | ||
841 | ||
842 | #define SPACES " " | |
843 | #define P_SPACES " " | |
844 | #define BYTE 0xff | |
845 | ||
846 | int screen_lines=24; | |
847 | ||
848 | char *spec_reg[] = { | |
849 | "fsr", "db", "dirbase", "fir", "psr", "epsr", | |
850 | }; | |
851 | ||
852 | char *doro_reg[] = { | |
853 | "scp", "cbsp", "pt_cs", "intmsk", "intack", | |
854 | }; | |
855 | #define NREGS 32 | |
856 | ||
857 | ||
858 | get_reg(regno) | |
859 | { | |
860 | char raw_buffer[32]; | |
861 | int addr; | |
862 | int virtual_buffer; | |
863 | ||
864 | read_relative_register_raw_bytes (regno, raw_buffer); | |
865 | REGISTER_CONVERT_TO_VIRTUAL (addr, raw_buffer, &virtual_buffer); | |
866 | return(virtual_buffer); | |
867 | } | |
868 | ||
869 | int jhdebug = 0; | |
870 | /* | |
871 | ** Figure out address to place next breakpoint. Avoid tricky spots, | |
872 | ** ie. delayed instruction slots etc. | |
873 | ** Need to upgrade this later to allow delayed instruction breakpoints | |
874 | ** with fix-up work done AFTER breakpoint. | |
875 | ** Note that this routine DOES deal with dual instruction mode | |
876 | */ | |
877 | #define BIM 0x8008 | |
878 | ||
879 | branch_type | |
880 | place_brk (addr, mode, brk) | |
881 | CORE_ADDR addr; | |
882 | int mode; | |
883 | struct breakpoint *brk; | |
884 | { | |
885 | long nextadr, prevadr, instr; | |
886 | int val = not_branch; | |
887 | long offset; /* Must be signed for sign-extend */ | |
888 | extern char registers[]; | |
889 | prevadr = nextadr = 0; | |
890 | ||
891 | brk->address1 = 0; | |
892 | ||
893 | if (mode == SINGLE_STEP_MODE) | |
894 | { | |
895 | if (INDIM || ENDIM) | |
896 | { | |
897 | nextadr = brk->address = (addr + 8); | |
898 | instr = adj_read_memory_integer ((addr + 4)); | |
899 | brk->mode = DIM; | |
900 | } | |
901 | else | |
902 | { | |
903 | nextadr = brk->address = (addr + 4); | |
904 | instr = adj_read_memory_integer (addr); | |
905 | if (STDIM) | |
906 | brk->mode = DIM; | |
907 | else | |
908 | brk->mode = SIM; | |
909 | } | |
910 | ||
911 | ||
912 | /* | |
913 | ** For br/call one more sequential instruction gets executed and then we | |
914 | ** continue at the current addr + offset. We are definitely going to | |
915 | ** the dest. We are NOT allowed to place a breakpoint in the "delay" | |
916 | ** slot - (the next sequential instruction) so we only place 1 breakpoint | |
917 | ** at the destination. | |
918 | ** For the bc/bnc the next instruction executed is EITHER the next sequential | |
919 | ** or the destination of the branch, we therefore place 2 breakpoints one | |
920 | ** at each location. | |
921 | ** For the bc.t/bnc.t either 1 more sequential instruction is performed | |
922 | ** followed by a branch (like br/call) OR we skip the sequential | |
923 | ** instruction and keep going. We therefore place a breakpoint at the | |
924 | ** destination of the branch AND the second sequential instruction after | |
925 | ** the branch. Again a breakpoint is NOT allowed in the "delay slot" | |
926 | */ | |
927 | if ((instr & 0xE0000000) == 0x60000000 && /* CTRL format */ | |
928 | (instr & 0xF8000000) != 0x60000000) /* not pfld.y */ | |
929 | { | |
930 | if ((instr & 0xF8000000) == 0x68000000) /* br or call */ | |
931 | val = uncond_d; | |
932 | else if ((instr & 0xF4000000) == 0x74000000) /* bc.t/bnc.t */ | |
933 | val = cond_d; | |
934 | else if ((instr & 0xF4000000) == 0x70000000) /* bc or bnc */ | |
935 | val = cond; | |
936 | offset = (instr & 0x03ffffff); | |
937 | if (offset & 0x02000000) /*?sign extend*/ | |
938 | offset |= 0xFC000000; | |
939 | if (val == uncond_d) /* br/call*/ | |
940 | prevadr = 0; | |
941 | else if (val == cond_d) /* bc.t/bnc.t */ | |
942 | { | |
943 | if ((INDIM) && !(ENDIM)) | |
944 | prevadr = nextadr + 8; | |
945 | else | |
946 | prevadr = nextadr + 4; | |
947 | } else { /* bc /bnc */ | |
948 | if ((INDIM) && !(ENDIM)) | |
949 | prevadr = nextadr; | |
950 | else | |
951 | prevadr = nextadr; | |
952 | } | |
953 | nextadr += (offset << 2); | |
954 | } | |
955 | /* | |
956 | ** We treat the bri/calli the same way as the br/call case. | |
957 | */ | |
958 | else if ((instr & 0xFC00003F) == 0x4C000002 || /* calli */ | |
959 | (instr & 0xFC000000) == 0x40000000) /* bri */ | |
960 | { | |
961 | val = uncond_d; | |
962 | offset = ((instr & 0x0000F800) >> 11); | |
963 | nextadr = (read_register(offset + R0) & 0xFFFFFFFC); | |
964 | prevadr = 0; | |
965 | } | |
966 | /* | |
967 | ** We treat the bte/btne the same way as the bc/bnc case. | |
968 | */ | |
969 | else if ((instr & 0xF0000000) == 0x50000000) /* bte/btne */ | |
970 | { | |
971 | val = cond; | |
972 | offset = SIGN_EXT16(((instr & 0x001F0000) >> 5) | | |
973 | (instr & 0x000007FF)); | |
974 | if ((INDIM) && !(ENDIM)) | |
975 | prevadr = nextadr; | |
976 | else | |
977 | prevadr = nextadr; | |
978 | ||
979 | nextadr += (offset << 2); | |
980 | } | |
981 | /* | |
982 | ** We treat the bte/btne the same way as the bc/bnc case. | |
983 | ** With the caveat that the 2 breakpoints may turn out to be at the same | |
984 | ** address in which case we ignore one of them. | |
985 | */ | |
986 | else if ((instr & 0xFC000000) == 0xB4000000) /* bla */ | |
987 | { | |
988 | val = cond_d; | |
989 | offset = SIGN_EXT16(((instr & 0x001F0000) >> 5) | | |
990 | (instr & 0x000007FF)); | |
991 | if ((INDIM) && !(ENDIM)) | |
992 | { | |
993 | prevadr = nextadr + 8; | |
994 | } else { | |
995 | prevadr = nextadr + 4; | |
996 | } | |
997 | nextadr += (offset << 2); | |
998 | if (prevadr == nextadr) prevadr = 0; | |
999 | } | |
1000 | } else { | |
1001 | int adjust = 0; | |
1002 | ||
1003 | nextadr = addr; | |
1004 | ||
1005 | if (ISDIM(FOPADR(addr))) | |
1006 | { | |
1007 | if (ISDIM(FOPADR(nextadr-8))) | |
1008 | { | |
1009 | instr = adj_read_memory_integer(CORADR(addr-8)); | |
1010 | brk->mode = DIM; | |
1011 | } else { | |
1012 | instr = adj_read_memory_integer(addr-4); | |
1013 | brk->mode = RIM; | |
1014 | } | |
1015 | } else { | |
1016 | if (ISDIM(addr-4)) | |
1017 | { | |
1018 | instr = adj_read_memory_integer(addr-4); | |
1019 | brk->mode = BIM; | |
1020 | } else { | |
1021 | instr = adj_read_memory_integer (addr-4); | |
1022 | brk->mode = SIM; | |
1023 | } | |
1024 | } | |
1025 | ||
1026 | /* examine the PREVIOUS instruction to determine if we are in a branch delay | |
1027 | slot. If we are, dont set a break here -- set it on the previous instruction. | |
1028 | This code also accounts for dual instruction mode */ | |
1029 | if ((instr & 0xE0000000) == 0x60000000 && | |
1030 | (instr & 0xF8000000) != 0x60000000) /* not pfld.y */ | |
1031 | { | |
1032 | adjust++; | |
1033 | /* br /call */ | |
1034 | /* bc /bnc */ | |
1035 | /* bc.t /bnc.t*/ | |
1036 | if ((instr & 0xF8000000) == 0x68000000) /* br or call */ | |
1037 | printf(" Breakpoint adjusted to avoid br/call delay slot and multiple breakpoints\n"); | |
1038 | ||
1039 | if ((instr & 0xF4000000) == 0x74000000) /* bc.t or bnc.t */ | |
1040 | printf(" Breakpoint adjusted to avoid bc.t/bnc.t delay slot and multiple breakpoints\n"); | |
1041 | /* it IS really OK to set a break on the instruction AFTER the conditional branch | |
1042 | -- it DOESN't have a delay slot */ | |
1043 | if ((instr & 0xF4000000) == 0x70000000) /* bc / bnc */ | |
1044 | /* printf(" Breakpoint adjusted to avoid bc/bnc delay slot and multiple breakpoints\n"); */ | |
1045 | adjust = 0; | |
1046 | } else if | |
1047 | ((instr & 0xFC00003F) == 0x4C000002 || /* bri/ calli */ | |
1048 | (instr & 0xFC000000) == 0x40000000) | |
1049 | { | |
1050 | adjust++; | |
1051 | printf(" Breakpoint adjusted to avoid calli/bri delay slot and multiple breakpoints\n"); | |
1052 | } else if | |
1053 | ((instr & 0xF0000000) == 0x50000000) /* bte - btne */ | |
1054 | { | |
1055 | /* it's OK to set a break here -- we are NOT in aa branch delay slot */ | |
1056 | /* | |
1057 | adjust++; | |
1058 | printf(" Breakpoint adjusted to avoid bte/btne multiple breakpoints\n"); | |
1059 | */ | |
1060 | adjust = 0; | |
1061 | } else if | |
1062 | ((instr & 0xFC000000) == 0xB4000000) | |
1063 | { | |
1064 | adjust++; | |
1065 | printf(" Breakpoint adjusted to avoid bla delay slot and multiple breakpoints\n"); | |
1066 | } | |
1067 | if (adjust) | |
1068 | { | |
1069 | if (brk->mode == DIM) | |
1070 | { | |
1071 | nextadr -= 8; | |
1072 | nextadr = CORADR(nextadr); | |
1073 | } | |
1074 | else | |
1075 | nextadr -=4; | |
1076 | } | |
1077 | ||
1078 | } | |
1079 | ||
1080 | if (brk->mode == RIM) | |
1081 | brk->mode = DIM; | |
1082 | if (brk->mode == BIM) | |
1083 | brk->mode = SIM; | |
1084 | ||
1085 | if (nextadr) | |
1086 | { | |
1087 | if (brk->mode == DIM) | |
1088 | { | |
1089 | brk->act_addr[0] = CORADR(nextadr); | |
1090 | brk->act_addr[1] = FOPADR(nextadr); | |
1091 | } else { | |
1092 | brk->act_addr[0] = nextadr; | |
1093 | brk->act_addr[1] = 0; | |
1094 | } | |
1095 | } | |
1096 | ||
1097 | if (prevadr) | |
1098 | { | |
1099 | brk->address1 = prevadr; | |
1100 | if (brk->mode == DIM) | |
1101 | { | |
1102 | brk->act_addr[2] = CORADR(prevadr); | |
1103 | brk->act_addr[3] = FOPADR(prevadr); | |
1104 | } else { | |
1105 | brk->act_addr[2] = prevadr; | |
1106 | brk->act_addr[3] = 0; | |
1107 | } | |
1108 | } else { | |
1109 | brk->act_addr[2] = brk->act_addr[3] = 0; | |
1110 | } | |
1111 | return val; | |
1112 | } | |
1113 | ||
1114 | /* | |
1115 | ** Figure out whether we are in a delayed slot and if so then take necessary | |
1116 | ** action to resume properly - remember trap pre-empts instruction | |
1117 | */ | |
1118 | int | |
1119 | wasabranch (addr, nextpc, ss) | |
1120 | CORE_ADDR addr, *nextpc; | |
1121 | int ss; | |
1122 | { | |
1123 | long nextadr, instr; | |
1124 | int val = not_branch; | |
1125 | long offset; /* Must be signed for sign-extend */ | |
1126 | ||
1127 | if (ss) | |
1128 | { | |
1129 | if (INDIM) | |
1130 | { | |
1131 | nextadr = CORADR((int)(addr + 8)); | |
1132 | instr = adj_read_memory_integer (CORADR(addr)); | |
1133 | } | |
1134 | else | |
1135 | { | |
1136 | nextadr = addr + 4; | |
1137 | instr = adj_read_memory_integer (addr); | |
1138 | } | |
1139 | } else { | |
1140 | if (ISDIM(addr)) | |
1141 | { | |
1142 | nextadr = CORADR(addr); | |
1143 | instr = adj_read_memory_integer (nextadr); | |
1144 | } | |
1145 | else | |
1146 | { | |
1147 | nextadr = addr; | |
1148 | instr = adj_read_memory_integer (addr); | |
1149 | } | |
1150 | } | |
1151 | ||
1152 | ||
1153 | if ((instr & 0xE0000000) == 0x60000000 && /* CTRL format */ | |
1154 | (instr & 0xF8000000) != 0x60000000) /* not pfld.y */ | |
1155 | { | |
1156 | if ((instr & 0xF8000000) == 0x68000000) /* br or call */ | |
1157 | val = uncond_d; | |
1158 | else if ((instr & 0xF4000000) == 0x74000000) /* bc.t or bnc.t */ | |
1159 | val = cond_d; | |
1160 | else if ((instr & 0xF4000000) == 0x70000000) /* bc or bnc */ | |
1161 | val = cond; | |
1162 | ||
1163 | offset = (instr & 0x03ffffff); | |
1164 | if (offset & 0x02000000) /* sign extend? */ | |
1165 | offset |= 0xFC000000; | |
1166 | nextadr += (offset << 2); | |
1167 | } | |
1168 | else if ((instr & 0xFC00003F) == 0x4C000002 || /* calli */ | |
1169 | (instr & 0xFC000000) == 0x40000000) /* bri */ | |
1170 | { | |
1171 | if (ss) | |
1172 | { | |
1173 | val = uncond_d; | |
1174 | offset = ((instr & 0x0000F800) >> 11); | |
1175 | nextadr = (read_register(offset) & 0xFFFFFFFC); | |
1176 | } else { | |
1177 | val = uncond_d; | |
1178 | } | |
1179 | } | |
1180 | else if ((instr & 0xF0000000) == 0x50000000) /* bte or btne */ | |
1181 | { | |
1182 | val = cond; | |
1183 | ||
1184 | offset = SIGN_EXT16(((instr & 0x001F0000) >> 5) | (instr & 0x000007FF)); | |
1185 | nextadr += (offset << 2); | |
1186 | } | |
1187 | else if ((instr & 0xFC000000) == 0xB4000000) /* bla */ | |
1188 | { | |
1189 | val = cond_d; | |
1190 | ||
1191 | offset = SIGN_EXT16(((instr & 0x001F0000) >> 5) | (instr & 0x000007FF)); | |
1192 | nextadr += (offset << 2); | |
1193 | } | |
1194 | ||
1195 | *nextpc = nextadr; | |
1196 | return val; | |
1197 | } | |
1198 | ||
1199 | extern char registers[]; | |
1200 | ||
1201 | i860_do_registers_info(regnum,fpregs) | |
1202 | int regnum; | |
1203 | int fpregs; | |
1204 | { | |
1205 | register int i; | |
1206 | unsigned int val; | |
1207 | unsigned int j,k; | |
1208 | ||
1209 | if (regnum == -1) | |
1210 | printf_filtered ( | |
1211 | "Register Contents (relative to selected stack frame)\n\n"); | |
1212 | ||
1213 | if (regnum != -1) /* print one register */ | |
1214 | { | |
1215 | if ((regnum >=F0 ) && (regnum <= F31)) | |
1216 | bcopy (®isters[ADJ_FREG(regnum)<<2], &val, sizeof (long)); | |
1217 | else | |
1218 | bcopy (®isters[regnum<<2], &val, sizeof (long)); | |
1219 | printf("%-4s 0x%08x\t", reg_names[regnum], val); | |
1220 | printf("\n\t"); fflush(stdout); | |
1221 | } | |
1222 | else /* print all registers */ | |
1223 | { | |
1224 | ||
1225 | printf("\n Control/Status Registers :- \n\t"); | |
1226 | for (j=0; j<=DB; j++) | |
1227 | { | |
1228 | bcopy (®isters[j<<2], &val, sizeof (long)); | |
1229 | printf("%-4s 0x%08x\t", reg_names[j], val); | |
1230 | } | |
1231 | printf("\n\t"); fflush(stdout); | |
1232 | ||
1233 | /* EPSR */ | |
1234 | bcopy (®isters[EPSR<<2], &val, sizeof (long)); | |
1235 | printf("%-4s 0x%08x\t", reg_names[EPSR], val); | |
1236 | ||
1237 | /* FSR */ | |
1238 | bcopy (®isters[FSR<<2], &val, sizeof (long)); | |
1239 | printf("%-4s 0x%08x\t", reg_names[FSR], val); | |
1240 | ||
1241 | /* CCR */ | |
1242 | bcopy (®isters[CCR<<2], &val, sizeof (long)); | |
1243 | printf("%-4s 0x%08x\t", reg_names[CCR], val); | |
1244 | /* BEAR*/ | |
1245 | bcopy (®isters[BEAR<<2], &val, sizeof (long)); | |
1246 | printf("%-4s 0x%08x\t", reg_names[BEAR], val); | |
1247 | ||
1248 | ||
1249 | #ifdef JIM_ADD_PRIV | |
1250 | for (j=P0; j<=P3; j++) | |
1251 | { | |
1252 | bcopy (®isters[j<<2], &val, sizeof (long)); | |
1253 | printf("%-4s 0x%08x\t", reg_names[j], val); | |
1254 | } | |
1255 | #endif | |
1256 | ||
1257 | printf("\n Integer Registers :- \n\t"); | |
1258 | for (j=R0; j<=R31; j++) | |
1259 | { | |
1260 | if (j != IREGS && (j % 4 == 0)) | |
1261 | { | |
1262 | printf("\n\t"); fflush(stdout); | |
1263 | } | |
1264 | bcopy (®isters[j<<2], &val, sizeof (long)); | |
1265 | printf("%-4s 0x%08x\t", reg_names[j], val); | |
1266 | } | |
1267 | ||
1268 | printf("\n Floating Registers :- \n\t"); | |
1269 | for (j=F0; j<=F31; j++) | |
1270 | { | |
1271 | if (j != FREGS && (j % 4 == 0)) | |
1272 | { | |
1273 | printf("\n\t"); fflush(stdout); | |
1274 | } | |
1275 | bcopy (®isters[ADJ_FREG(j)<<2], &val, sizeof (long)); | |
1276 | printf("%-4s 0x%08x\t", reg_names[j], val); | |
1277 | } | |
1278 | ||
1279 | printf("\n Special Registers :- \n\t"); | |
1280 | for (j=SPC_KI; j<=SPC_MERGE; j+=2) | |
1281 | { | |
1282 | unsigned int valh; | |
1283 | if (j == SPC_T) | |
1284 | { | |
1285 | printf("\n\t"); fflush(stdout); | |
1286 | } | |
1287 | bcopy (®isters[j<<2], &val, sizeof (long)); | |
1288 | bcopy (®isters[(j+1)<<2], &valh, sizeof (long)); | |
1289 | printf("%-6s 0x%08x %08x\t", reg_names[j], val,valh); | |
1290 | } | |
1291 | ||
1292 | printf("\n Graphics Pipeline :- \n"); | |
1293 | { | |
1294 | unsigned int valh, val2,val3; | |
1295 | j = PSV_I1; | |
1296 | bcopy (®isters[j<<2], &val, sizeof (long)); | |
1297 | bcopy (®isters[(j+1)<<2], &valh, sizeof (long)); | |
1298 | printf("\t\t\t%-8s 0x%08x %08x \n", reg_names[j], val,valh); | |
1299 | } | |
1300 | ||
1301 | printf(" Memory Load Pipeline :- \n"); | |
1302 | for (j=PSV_L1; j<=PSV_L3; j+=4) | |
1303 | { | |
1304 | unsigned int valh, val2,val3; | |
1305 | bcopy (®isters[j<<2], &val, sizeof (long)); | |
1306 | bcopy (®isters[(j+1)<<2], &valh, sizeof (long)); | |
1307 | bcopy (®isters[(j+2)<<2], &val2, sizeof (long)); | |
1308 | bcopy (®isters[(j+3)<<2], &val3, sizeof (long)); | |
1309 | printf("\t\t%-8s 0x%08x %08x %08x %08x\n", reg_names[j], | |
1310 | val,valh,val2,val3); | |
1311 | } | |
1312 | ||
1313 | printf("\n Adder Pipeline :-\t\tMultiplier Pipeline :-\t\tFSR results :-\n"); | |
1314 | for (i=PSV_FSR1,j=PSV_A1,k=PSV_M1; j<=PSV_A3; i++,j+=2,k+=2) | |
1315 | { | |
1316 | unsigned int valh,val2,val3,val4; | |
1317 | bcopy (®isters[i<<2], &val4, sizeof (long)); | |
1318 | bcopy (®isters[j<<2], &val, sizeof (long)); | |
1319 | bcopy (®isters[(j+1)<<2], &valh, sizeof (long)); | |
1320 | bcopy (®isters[k<<2], &val2, sizeof (long)); | |
1321 | bcopy (®isters[(k+1)<<2], &val3, sizeof (long)); | |
1322 | printf(" %-4s 0x%08x %08x\t", reg_names[j], val,valh); | |
1323 | printf("%-4s 0x%08x %08x\t", reg_names[k], val2,val3); | |
1324 | printf("%-4s 0x%08x\n", reg_names[i], val4); | |
1325 | } | |
1326 | ||
1327 | } | |
1328 | ||
1329 | ||
1330 | } | |
1331 | ||
1332 | int has_stored_r1(CORE_ADDR prologue_start, CORE_ADDR prologue_end) | |
1333 | { | |
1334 | long instr; | |
1335 | CORE_ADDR addr; | |
1336 | ||
1337 | BTDEBUG("has_stored_r1, prologue_start %x, prologue_end %x\n", | |
1338 | prologue_start, prologue_end); | |
1339 | ||
1340 | for (addr = prologue_start; addr <= prologue_end; addr += 4) | |
1341 | { | |
1342 | ||
1343 | instr = adj_read_memory_integer (addr); | |
1344 | if ((instr & 0xFFE0F801) == 0x1C400801 /* st.l r1,X(sp) */ | |
1345 | || (instr & 0xFFE0F801) == 0x1C600801) /* st.l r1,X(fp) */ | |
1346 | return (1); | |
1347 | } | |
1348 | return 0; | |
1349 | } | |
1350 | ||
1351 | /* This function returns 1 if there is no stored r1, 0 otherwise. | |
1352 | The function returns 1 if the pc is in a function prologue, | |
1353 | or the function prologue didn't save the return pointer in | |
1354 | the stack frame, 0 otherwise */ | |
1355 | ||
1356 | int no_stored_rp(CORE_ADDR pc) | |
1357 | { | |
1358 | CORE_ADDR func_start, prologue_end; | |
1359 | ||
1360 | func_start = get_pc_function_start(pc); | |
1361 | if (func_start) | |
1362 | { | |
1363 | prologue_end = func_start; | |
1364 | SKIP_PROLOGUE(prologue_end); | |
1365 | if ( (pc >= func_start) && (pc <= prologue_end)) | |
1366 | { | |
1367 | BTDEBUG("no_stored_rp: pc %x is in prologue \n",pc); | |
1368 | return 1; | |
1369 | } | |
1370 | /* otherwise, see if the entry sequence stored the return pointer. | |
1371 | If it didn't, return 1 */ | |
1372 | /* Some procedures , at least, store the return pointer AFTER the prologue sequence! */ | |
1373 | if (!has_stored_r1(func_start, pc)) | |
1374 | { | |
1375 | BTDEBUG("no_stored_rp, for pc %x, prologue didn't store r1\n",pc); | |
1376 | return 1; | |
1377 | } | |
1378 | } | |
1379 | BTDEBUG("no_stored_rp for pc %x return pointer was stored \n", pc); | |
1380 | ||
1381 | return 0; | |
1382 | } | |
1383 | ||
1384 | /* The following set of routines was adapted from existing code previously | |
1385 | in an i860-specific version of breakpoint.c by Peggy Fieland | |
1386 | (Margaret_Fieland@vos.stratus.com) */ | |
1387 | unsigned int dbrkval, dbrkmod; | |
1388 | void i860_dbrk_breakpoint() | |
1389 | { | |
1390 | BTDEBUG("i860_dbrk_breakpoint was called , dbrkval %x\n", dbrkval); | |
1391 | ||
1392 | if (dbrkval) | |
1393 | { | |
1394 | *(int *)®isters[DB<<2] = dbrkval; | |
1395 | } | |
1396 | else | |
1397 | { | |
1398 | *(int *)®isters[DB<<2] = 0; | |
1399 | } | |
1400 | ||
1401 | *(int *)®isters[PSR<<2] &= ~3; | |
1402 | *(int *)®isters[PSR<<2] |= dbrkmod; | |
1403 | ||
1404 | store_inferior_registers(DB); | |
1405 | store_inferior_registers(PSR); | |
1406 | ||
1407 | } | |
1408 | ||
1409 | void | |
1410 | d_ro_break_command(arg) | |
1411 | char *arg; | |
1412 | { | |
1413 | dbrkval = strtoul(arg, NULL, 0); | |
1414 | dbrkmod = 0x01; | |
1415 | printf(" ro_dbreak - %x %x\n", dbrkval, dbrkmod); | |
1416 | } | |
1417 | ||
1418 | void | |
1419 | d_wo_break_command(arg) | |
1420 | char *arg; | |
1421 | { | |
1422 | dbrkval = strtoul(arg, NULL, 0); | |
1423 | dbrkmod = 0x02; | |
1424 | printf(" wo_dbreak - %x %x\n", dbrkval, dbrkmod); | |
1425 | } | |
1426 | ||
1427 | void | |
1428 | d_rw_break_command(arg) | |
1429 | char *arg; | |
1430 | { | |
1431 | dbrkval = strtoul(arg, NULL, 0); | |
1432 | dbrkmod = 0x03; | |
1433 | printf(" rw_dbreak - %x %x\n", dbrkval, dbrkmod); | |
1434 | } | |
1435 | ||
1436 | void | |
1437 | clear_dbreak() | |
1438 | { | |
1439 | dbrkval = 0; | |
1440 | dbrkmod = 0; | |
1441 | } | |
1442 | ||
1443 | void | |
1444 | i860_init_breakpoints() | |
1445 | { | |
1446 | dbrkval = dbrkmod = 0; | |
1447 | add_com ("dbro", class_breakpoint, d_ro_break_command, | |
1448 | "Set a data breakpoint READ ONLY, 32-bit data element."); | |
1449 | add_com ("dbwo", class_breakpoint, d_wo_break_command, | |
1450 | "Set a data breakpoint WRITE ONLY, 32-bit data element."); | |
1451 | add_com ("dbrw", class_breakpoint, d_rw_break_command, | |
1452 | "Set a data breakpoint READ/WRITE, 32-bit data element."); | |
1453 | add_com ("dclear", class_breakpoint, clear_dbreak, | |
1454 | "clear the current data breakpoint."); | |
1455 | add_com_alias ("dc", "dclear", class_breakpoint, 1); | |
1456 | ||
1457 | } | |
1458 | ||
1459 | int i860_insert_breakpoint(b) | |
1460 | struct breakpoint *b; | |
1461 | { | |
1462 | int val; | |
1463 | ||
1464 | place_brk( b->address, BREAK_MODE, b ); | |
1465 | if (b->mode == DIM) | |
1466 | { | |
1467 | ||
1468 | adj_read_memory (b->act_addr[0], &b->shadow_contents[0], 4); | |
1469 | val = adj_write_memory (b->act_addr[0], break_insn, 4); | |
1470 | if (val) return val; | |
1471 | adj_read_memory (b->act_addr[1], &b->shadow_contents[1], 4); | |
1472 | /* val = adj_write_memory (b->act_addr[1], float_insn, 4); */ | |
1473 | if (val) return val; | |
1474 | } | |
1475 | else | |
1476 | { | |
1477 | adj_read_memory (b->act_addr[0], &b->shadow_contents[0], 4); | |
1478 | val = adj_write_memory (b->act_addr[0], break_insn, 4); | |
1479 | } | |
1480 | if (b->address1) | |
1481 | { | |
1482 | if (b->mode == DIM) | |
1483 | { | |
1484 | ||
1485 | adj_read_memory (b->act_addr[2], &b->shadow_contents[2], 4); | |
1486 | val = adj_write_memory (b->act_addr[2], break_insn, 4); | |
1487 | if (val) return val; | |
1488 | adj_read_memory (b->act_addr[3], &b->shadow_contents[3], 4); | |
1489 | /* val = adj_write_memory (b->act_addr[3], float_insn, 4); */ | |
1490 | if (val) return val; | |
1491 | } | |
1492 | else | |
1493 | { | |
1494 | adj_read_memory (b->act_addr[2], &b->shadow_contents[0], 4); | |
1495 | val = adj_write_memory (b->act_addr[2], break_insn, 4); | |
1496 | } | |
1497 | } | |
1498 | if (val) | |
1499 | return val; | |
1500 | BTDEBUG("Inserted breakpoint at 0x%x, shadow 0x%x, 0x%x.\n", | |
1501 | b->address, b->shadow_contents[0], b->shadow_contents[1]); | |
1502 | b->inserted = 1; | |
1503 | return 0; | |
1504 | } | |
1505 | ||
1506 | int i860_remove_breakpoint(b) | |
1507 | struct breakpoint *b; | |
1508 | { | |
1509 | int val; | |
1510 | ||
1511 | if (b->inserted) | |
1512 | { | |
1513 | if (b->mode == DIM) | |
1514 | { | |
1515 | val =adj_write_memory (b->act_addr[0], &(b->shadow_contents[0]), 4); | |
1516 | val =adj_write_memory (b->act_addr[1], &(b->shadow_contents[1]), 4); | |
1517 | if (b->address1) | |
1518 | { | |
1519 | val =adj_write_memory (b->act_addr[2], &(b->shadow_contents[2]), 4); | |
1520 | val =adj_write_memory (b->act_addr[3], &(b->shadow_contents[3]), 4); | |
1521 | } | |
1522 | } | |
1523 | else | |
1524 | { | |
1525 | val =adj_write_memory (b->act_addr[0], b->shadow_contents, 4); | |
1526 | if (b->address1) | |
1527 | { | |
1528 | val =adj_write_memory (b->act_addr[2], b->shadow_contents, 4); | |
1529 | } | |
1530 | } | |
1531 | if (val) | |
1532 | return val; | |
1533 | b->inserted = 0; | |
1534 | BTDEBUG( "Removed breakpoint at 0x%x, shadow 0x%x, 0x%x.\n", | |
1535 | b->address, b->shadow_contents[0], b->shadow_contents[1]); | |
1536 | } | |
1537 | ||
1538 | return 0; | |
1539 | ||
1540 | ||
1541 | } | |
1542 | ||
1543 | ||
1544 | #ifdef USE_PROC_FS /* Target dependent support for /proc */ | |
1545 | ||
1546 | #include <sys/procfs.h> | |
1547 | ||
1548 | /* The following routines were added by Peggy Fieland (Margaret_Fieland@vos.stratus.com) | |
1549 | They were adapted from the m-68k versions of the routines .*/ | |
1550 | ||
1551 | /* Given a pointer to a floating point register set in /proc format | |
1552 | (fpregset_t *), unpack the register contents and supply them as gdb's | |
1553 | idea of the current floating point register values. */ | |
1554 | ||
1555 | void | |
1556 | supply_fpregset (fpregsetp) | |
1557 | fpregset_t *fpregsetp; | |
1558 | { | |
1559 | register int regno; | |
1560 | ||
1561 | BTDEBUG("supply_fregset called \n"); | |
1562 | ||
1563 | for (regno = F0 ; regno <= F31 ; regno++) | |
1564 | { | |
1565 | supply_register (regno, (char *) &(fpregsetp -> fpu.r_freg[regno-F0])); | |
1566 | } | |
1567 | } | |
1568 | ||
1569 | /* Given a pointer to a floating point register set in /proc format | |
1570 | (fpregset_t *), update the register specified by REGNO from gdb's idea | |
1571 | of the current floating point register set. If REGNO is -1, update | |
1572 | them all. */ | |
1573 | ||
1574 | void | |
1575 | fill_fpregset (fpregsetp, regno) | |
1576 | fpregset_t *fpregsetp; | |
1577 | int regno; | |
1578 | { | |
1579 | int regi; | |
1580 | char *to; | |
1581 | char *from; | |
1582 | extern char registers[]; | |
1583 | BTDEBUG("fill_fregset regno %d\n",regno); | |
1584 | ||
1585 | for (regi = F0 ; regi <= F31 ; regi++) | |
1586 | { | |
1587 | if ((regno == -1) || (regno == regi)) | |
1588 | { | |
1589 | from = (char *) ®isters[REGISTER_BYTE (regi)]; | |
1590 | to = (char *) &(fpregsetp -> fpu.r_freg[regi-F0]); | |
1591 | bcopy (from, to, REGISTER_RAW_SIZE (regno)); | |
1592 | } | |
1593 | } | |
1594 | } | |
1595 | ||
1596 | ||
1597 | /* Given a pointer to a general register set in /proc format (gregset_t *), | |
1598 | unpack the register contents and supply them as gdb's idea of the current | |
1599 | register values. */ | |
1600 | ||
1601 | void | |
1602 | supply_gregset (gregsetp) | |
1603 | gregset_t *gregsetp; | |
1604 | { | |
1605 | register int regno; | |
1606 | register greg_t *regp = (greg_t *) gregsetp; | |
1607 | ||
1608 | BTDEBUG("supply_gregset called \n"); | |
1609 | ||
1610 | for (regno = 0 ; regno <= R31 ; regno++) | |
1611 | { | |
1612 | supply_register (regno, (char *) (regp + regno)); | |
1613 | } | |
1614 | } | |
1615 | ||
1616 | void | |
1617 | fill_gregset (gregsetp, regno) | |
1618 | gregset_t *gregsetp; | |
1619 | int regno; | |
1620 | { | |
1621 | int regi; | |
1622 | extern char registers[]; | |
1623 | register greg_t *regp = (greg_t *) gregsetp; | |
1624 | BTDEBUG("fill_gregset regno %d \n",regno); | |
1625 | ||
1626 | for (regi = 0 ; regi <= R31 ; regi++) | |
1627 | { | |
1628 | if ((regno == -1) || (regno == regi)) | |
1629 | { | |
1630 | *(regp + regi) = *(int *) ®isters[REGISTER_BYTE (regi)]; | |
1631 | } | |
1632 | ||
1633 | } | |
1634 | } | |
1635 | #endif | |
1636 |