]>
Commit | Line | Data |
---|---|---|
dd3b648e RP |
1 | /* Definitions to target GDB on an ISI Optimum V (3.05) under 4.3bsd. |
2 | Copyright (C) 1987, 1989 Free Software Foundation, Inc. | |
3 | ||
4 | This file is part of GDB. | |
5 | ||
99a7de40 | 6 | This program is free software; you can redistribute it and/or modify |
dd3b648e | 7 | it under the terms of the GNU General Public License as published by |
99a7de40 JG |
8 | the Free Software Foundation; either version 2 of the License, or |
9 | (at your option) any later version. | |
dd3b648e | 10 | |
99a7de40 | 11 | This program is distributed in the hope that it will be useful, |
dd3b648e RP |
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | GNU General Public License for more details. | |
15 | ||
16 | You should have received a copy of the GNU General Public License | |
99a7de40 JG |
17 | along with this program; if not, write to the Free Software |
18 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ | |
dd3b648e RP |
19 | |
20 | /* This has not been tested on ISI's running BSD 4.2, but it will probably | |
21 | work. */ | |
22 | ||
23 | /* Define this if the C compiler puts an underscore at the front | |
24 | of external names before giving them to the linker. */ | |
25 | ||
26 | #define NAMES_HAVE_UNDERSCORE | |
27 | ||
28 | /* Debugger information will be in DBX format. */ | |
29 | ||
30 | #define READ_DBX_FORMAT | |
31 | ||
32 | /*#define STACK_END_ADDR 0x10000000*/ | |
33 | #define STACK_END_ADDR 0xfffe000 | |
34 | ||
35 | /* Data segment starts at etext rounded up to DATAROUND in {N,Z}MAGIC files */ | |
36 | ||
37 | #define DATAROUND 0x20000 | |
38 | #define N_DATADDR(hdr) (hdr.a_magic != OMAGIC ? \ | |
39 | (hdr.a_text + DATAROUND) & ~(DATAROUND-1) : hdr.a_text) | |
40 | ||
41 | /* Text segment starts at sizeof (struct exec) in {N,Z}MAGIC files */ | |
42 | ||
43 | #define N_TXTADDR(hdr) (hdr.a_magic != OMAGIC ? sizeof (struct exec) : 0) | |
44 | ||
45 | /* Amount PC must be decremented by after a breakpoint. | |
46 | This is often the number of bytes in BREAKPOINT | |
47 | but not always. | |
48 | On the ISI, the kernel resets the pc to the trap instr */ | |
49 | ||
50 | #define DECR_PC_AFTER_BREAK 0 | |
51 | ||
52 | \f | |
53 | /* Return number of args passed to a frame. | |
54 | Can return -1, meaning no way to tell. */ | |
55 | ||
56 | #define FRAME_NUM_ARGS(val, fi) \ | |
57 | { register CORE_ADDR pc = FRAME_SAVED_PC (fi); \ | |
58 | register int insn = 0177777 & read_memory_integer (pc, 2); \ | |
59 | val = 0; \ | |
60 | if (insn == 0047757 || insn == 0157374) /* lea W(sp),sp or addaw #W,sp */ \ | |
61 | val = read_memory_integer (pc + 2, 2); \ | |
62 | else if ((insn & 0170777) == 0050217 /* addql #N, sp */ \ | |
63 | || (insn & 0170777) == 0050117) /* addqw */ \ | |
64 | { val = (insn >> 9) & 7; if (val == 0) val = 8; } \ | |
65 | else if (insn == 0157774) /* addal #WW, sp */ \ | |
66 | val = read_memory_integer (pc + 2, 4); \ | |
67 | val >>= 2; } | |
68 | ||
69 | /* Put here the code to store, into a struct frame_saved_regs, | |
70 | the addresses of the saved registers of frame described by FRAME_INFO. | |
71 | This includes special registers such as pc and fp saved in special | |
72 | ways in the stack frame. sp is even more special: | |
73 | the address we return for it IS the sp for the next frame. */ | |
74 | ||
75 | #define FRAME_FIND_SAVED_REGS(frame_info, frame_saved_regs) \ | |
76 | { register int regnum; \ | |
77 | register int regmask; \ | |
78 | register CORE_ADDR next_addr; \ | |
79 | register CORE_ADDR pc; \ | |
80 | register int insn; \ | |
81 | register int offset; \ | |
82 | bzero (&frame_saved_regs, sizeof frame_saved_regs); \ | |
83 | if ((frame_info)->pc >= (frame_info)->frame - CALL_DUMMY_LENGTH - FP_REGNUM*4 - 8*12 - 4 \ | |
84 | && (frame_info)->pc <= (frame_info)->frame) \ | |
85 | { next_addr = (frame_info)->frame; \ | |
86 | pc = (frame_info)->frame - CALL_DUMMY_LENGTH - FP_REGNUM * 4 - 8*12 - 4; }\ | |
87 | else \ | |
88 | { pc = get_pc_function_start ((frame_info)->pc); \ | |
89 | /* Verify we have a link a6 instruction next, \ | |
90 | or a branch followed by a link a6 instruction; \ | |
91 | if not we lose. If we win, find the address above the saved \ | |
92 | regs using the amount of storage from the link instruction. */\ | |
93 | retry: \ | |
94 | insn = read_memory_integer (pc, 2); \ | |
95 | if (insn == 044016) \ | |
96 | next_addr = (frame_info)->frame - read_memory_integer (pc += 2, 4), pc+=4; \ | |
97 | else if (insn == 047126) \ | |
98 | next_addr = (frame_info)->frame - read_memory_integer (pc += 2, 2), pc+=2; \ | |
99 | else if ((insn & 0177400) == 060000) /* bra insn */ \ | |
100 | { offset = insn & 0377; \ | |
101 | pc += 2; /* advance past bra */ \ | |
102 | if (offset == 0) /* bra #word */ \ | |
103 | offset = read_memory_integer (pc, 2), pc += 2; \ | |
104 | else if (offset == 0377) /* bra #long */ \ | |
105 | offset = read_memory_integer (pc, 4), pc += 4; \ | |
106 | pc += offset; \ | |
107 | goto retry; \ | |
108 | } else goto lose; \ | |
109 | /* If have an addal #-n, sp next, adjust next_addr. */ \ | |
110 | if ((0177777 & read_memory_integer (pc, 2)) == 0157774) \ | |
111 | next_addr += read_memory_integer (pc += 2, 4), pc += 4; \ | |
112 | } \ | |
113 | /* next should be a moveml to (sp) or -(sp) or a movl r,-(sp) */ \ | |
114 | insn = read_memory_integer (pc, 2), pc += 2; \ | |
115 | regmask = read_memory_integer (pc, 2); \ | |
116 | if ((insn & 0177760) == 022700) /* movl rn, (sp) */ \ | |
117 | (frame_saved_regs).regs[(insn&7) + ((insn&010)?8:0)] = next_addr; \ | |
118 | else if ((insn & 0177760) == 024700) /* movl rn, -(sp) */ \ | |
119 | (frame_saved_regs).regs[(insn&7) + ((insn&010)?8:0)] = next_addr-=4; \ | |
120 | else if (insn == 0044327) /* moveml mask, (sp) */ \ | |
121 | { pc += 2; \ | |
122 | /* Regmask's low bit is for register 0, the first written */ \ | |
123 | next_addr -= 4; \ | |
124 | for (regnum = 0; regnum < 16; regnum++, regmask >>= 1) \ | |
125 | if (regmask & 1) \ | |
126 | (frame_saved_regs).regs[regnum] = (next_addr += 4); \ | |
127 | } else if (insn == 0044347) /* moveml mask, -(sp) */ \ | |
128 | { pc += 2; \ | |
129 | /* Regmask's low bit is for register 15, the first pushed */ \ | |
130 | for (regnum = 15; regnum >= 0; regnum--, regmask >>= 1) \ | |
131 | if (regmask & 1) \ | |
132 | (frame_saved_regs).regs[regnum] = (next_addr -= 4); } \ | |
133 | /* clrw -(sp); movw ccr,-(sp) may follow. */ \ | |
134 | if (read_memory_integer (pc, 2) == 041147 \ | |
135 | && read_memory_integer (pc+2, 2) == 042347) \ | |
136 | (frame_saved_regs).regs[PS_REGNUM] = (next_addr -= 4); \ | |
137 | lose: ; \ | |
138 | (frame_saved_regs).regs[SP_REGNUM] = (frame_info)->frame + 8; \ | |
139 | (frame_saved_regs).regs[FP_REGNUM] = (frame_info)->frame; \ | |
140 | (frame_saved_regs).regs[PC_REGNUM] = (frame_info)->frame + 4; \ | |
141 | } | |
142 | \f | |
143 | /* Things needed for making the inferior call functions. */ | |
144 | ||
145 | /* Push an empty stack frame, to record the current PC, etc. */ | |
146 | ||
147 | #define PUSH_DUMMY_FRAME \ | |
148 | { register CORE_ADDR sp = read_register (SP_REGNUM); \ | |
149 | register int regnum; \ | |
150 | char raw_buffer[12]; \ | |
151 | sp = push_word (sp, read_register (PC_REGNUM)); \ | |
152 | sp = push_word (sp, read_register (FP_REGNUM)); \ | |
153 | write_register (FP_REGNUM, sp); \ | |
154 | for (regnum = FP0_REGNUM + 7; regnum >= FP0_REGNUM; regnum--) \ | |
155 | { read_register_bytes (REGISTER_BYTE (regnum), raw_buffer, 12); \ | |
156 | sp = push_bytes (sp, raw_buffer, 12); } \ | |
157 | for (regnum = FP_REGNUM - 1; regnum >= 0; regnum--) \ | |
158 | sp = push_word (sp, read_register (regnum)); \ | |
159 | sp = push_word (sp, read_register (PS_REGNUM)); \ | |
160 | write_register (SP_REGNUM, sp); } | |
161 | ||
162 | /* Discard from the stack the innermost frame, restoring all registers. */ | |
163 | ||
164 | #define POP_FRAME \ | |
165 | { register FRAME frame = get_current_frame (); \ | |
166 | register CORE_ADDR fp; \ | |
167 | register int regnum; \ | |
168 | struct frame_saved_regs fsr; \ | |
169 | struct frame_info *fi; \ | |
170 | char raw_buffer[12]; \ | |
171 | fi = get_frame_info (frame); \ | |
172 | fp = fi->frame; \ | |
173 | get_frame_saved_regs (fi, &fsr); \ | |
174 | for (regnum = FP0_REGNUM + 7; regnum >= FP0_REGNUM; regnum--) \ | |
175 | if (fsr.regs[regnum]) \ | |
176 | { read_memory (fsr.regs[regnum], raw_buffer, 12); \ | |
177 | write_register_bytes (REGISTER_BYTE (regnum), raw_buffer, 12); }\ | |
178 | for (regnum = FP_REGNUM - 1; regnum >= 0; regnum--) \ | |
179 | if (fsr.regs[regnum]) \ | |
180 | write_register (regnum, read_memory_integer (fsr.regs[regnum], 4)); \ | |
181 | if (fsr.regs[PS_REGNUM]) \ | |
182 | write_register (PS_REGNUM, read_memory_integer (fsr.regs[PS_REGNUM], 4)); \ | |
183 | write_register (FP_REGNUM, read_memory_integer (fp, 4)); \ | |
184 | write_register (PC_REGNUM, read_memory_integer (fp + 4, 4)); \ | |
185 | write_register (SP_REGNUM, fp + 8); \ | |
186 | flush_cached_frames (); \ | |
187 | set_current_frame ( create_new_frame (read_register (FP_REGNUM), \ | |
188 | read_pc ())); } | |
189 | ||
190 | /* This sequence of words is the instructions | |
191 | fmovem #<f0-f7>,-(sp) | |
192 | moveml 0xfffc,-(sp) | |
193 | clrw -(sp) | |
194 | movew ccr,-(sp) | |
195 | /..* The arguments are pushed at this point by GDB; | |
196 | no code is needed in the dummy for this. | |
197 | The CALL_DUMMY_START_OFFSET gives the position of | |
198 | the following jsr instruction. *../ | |
199 | jsr @#32323232 | |
200 | addl #69696969,sp | |
201 | bpt | |
202 | nop | |
203 | Note this is 24 bytes. | |
204 | We actually start executing at the jsr, since the pushing of the | |
205 | registers is done by PUSH_DUMMY_FRAME. If this were real code, | |
206 | the arguments for the function called by the jsr would be pushed | |
207 | between the moveml and the jsr, and we could allow it to execute through. | |
208 | But the arguments have to be pushed by GDB after the PUSH_DUMMY_FRAME is done, | |
209 | and we cannot allow the moveml to push the registers again lest they be | |
210 | taken for the arguments. */ | |
211 | ||
212 | #define CALL_DUMMY {0xf227e0ff, 0x48e7fffc, 0x426742e7, 0x4eb93232, 0x3232dffc, 0x69696969, 0x4e4f4e71} | |
213 | ||
214 | #define CALL_DUMMY_LENGTH 28 | |
215 | ||
216 | #define CALL_DUMMY_START_OFFSET 12 | |
217 | ||
218 | /* Insert the specified number of args and function address | |
219 | into a call sequence of the above form stored at DUMMYNAME. */ | |
220 | ||
221 | #define FIX_CALL_DUMMY(dummyname, pc, fun, nargs, args, type, gcc_p) \ | |
222 | { *(int *)((char *) dummyname + 20) = nargs * 4; \ | |
223 | *(int *)((char *) dummyname + 14) = fun; } | |
224 | \f | |
225 | #define HAVE_68881 1 | |
226 | ||
227 | #include "tm-68k.h" |