]>
Commit | Line | Data |
---|---|---|
c906108c | 1 | /* Target machine description for VxWorks on the 29k, for GDB, the GNU debugger. |
b6ba6518 | 2 | Copyright 1994, 1995, 1998, 1999, 2000 Free Software Foundation, Inc. |
c906108c SS |
3 | Contributed by Cygnus Support. |
4 | ||
c5aa993b | 5 | This file is part of GDB. |
c906108c | 6 | |
c5aa993b JM |
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. | |
c906108c | 11 | |
c5aa993b JM |
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. | |
c906108c | 16 | |
c5aa993b JM |
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., 59 Temple Place - Suite 330, | |
20 | Boston, MA 02111-1307, USA. */ | |
c906108c | 21 | |
f88e2c52 | 22 | #include "regcache.h" |
c906108c | 23 | #include "a29k/tm-a29k.h" |
cce74817 | 24 | #include "tm-vxworks.h" |
c906108c SS |
25 | |
26 | /* Number of registers in a ptrace_getregs call. */ | |
27 | ||
28 | #define VX_NUM_REGS (NUM_REGS) | |
29 | ||
30 | /* Number of registers in a ptrace_getfpregs call. */ | |
31 | ||
32 | /* #define VX_SIZE_FPREGS */ | |
33 | ||
34 | /* This is almost certainly the wrong place for this: */ | |
35 | #define LR2_REGNUM 34 | |
36 | \f | |
37 | ||
38 | /* Vxworks has its own CALL_DUMMY since it manages breakpoints in the kernel */ | |
39 | ||
40 | #undef CALL_DUMMY | |
41 | ||
42 | /* Replace the breakpoint instruction in the CALL_DUMMY with a nop. | |
43 | For Vxworks, the breakpoint is set and deleted by calls to | |
44 | CALL_DUMMY_BREAK_SET and CALL_DUMMY_BREAK_DELETE. */ | |
45 | ||
46 | #if TARGET_BYTE_ORDER == HOST_BYTE_ORDER | |
47 | #define CALL_DUMMY {0x0400870f,\ | |
48 | 0x36008200|(MSP_HW_REGNUM), \ | |
49 | 0x15000040|(MSP_HW_REGNUM<<8)|(MSP_HW_REGNUM<<16), \ | |
50 | 0x03ff80ff, 0x02ff80ff, 0xc8008080, 0x70400101, 0x70400101} | |
51 | #else /* Byte order differs. */ | |
52 | #define CALL_DUMMY {0x0f870004,\ | |
53 | 0x00820036|(MSP_HW_REGNUM << 24), \ | |
54 | 0x40000015|(MSP_HW_REGNUM<<8)|(MSP_HW_REGNUM<<16), \ | |
55 | 0xff80ff03, 0xff80ff02, 0x808000c8, 0x01014070, 0x01014070} | |
56 | #endif /* Byte order differs. */ | |
57 | ||
58 | ||
59 | /* For the basic CALL_DUMMY definitions, see "tm-29k.h." We use the | |
60 | same CALL_DUMMY code, but define FIX_CALL_DUMMY (and related macros) | |
61 | locally to handle remote debugging of VxWorks targets. The difference | |
62 | is in the setting and clearing of the breakpoint at the end of the | |
63 | CALL_DUMMY code fragment; under VxWorks, we can't simply insert a | |
64 | breakpoint instruction into the code, since that would interfere with | |
65 | the breakpoint management mechanism on the target. | |
66 | Note that CALL_DUMMY is a piece of code that is used to call any C function | |
67 | thru VxGDB */ | |
68 | ||
69 | /* The offset of the instruction within the CALL_DUMMY code where we | |
70 | want the inferior to stop after the function call has completed. | |
71 | call_function_by_hand () sets a breakpoint here (via CALL_DUMMY_BREAK_SET), | |
72 | which POP_FRAME later deletes (via CALL_DUMMY_BREAK_DELETE). */ | |
c5aa993b | 73 | |
c906108c | 74 | #define CALL_DUMMY_STOP_OFFSET (7 * 4) |
c5aa993b | 75 | |
c906108c SS |
76 | /* The offset of the first instruction of the CALL_DUMMY code fragment |
77 | relative to the frame pointer for a dummy frame. This is equal to | |
78 | the size of the CALL_DUMMY plus the arg_slop area size (see the diagram | |
79 | in "tm-29k.h"). */ | |
80 | /* PAD : the arg_slop area size doesn't appear to me to be useful since, the | |
81 | call dummy code no longer modify the msp. See below. This must be checked. */ | |
82 | ||
83 | #define CALL_DUMMY_OFFSET_IN_FRAME (CALL_DUMMY_LENGTH + 16 * 4) | |
84 | ||
85 | /* Insert the specified number of args and function address | |
86 | into a CALL_DUMMY sequence stored at DUMMYNAME, replace the third | |
87 | instruction (add msp, msp, 16*4) with a nop, and leave the final nop. | |
88 | We can't keep using a CALL_DUMMY that modify the msp since, for VxWorks, | |
89 | CALL_DUMMY is stored in the Memory Stack. Adding 16 words to the msp | |
90 | would then make possible for the inferior to overwrite the CALL_DUMMY code, | |
91 | thus creating a lot of trouble when exiting the inferior to come back in | |
92 | a CALL_DUMMY code that no longer exists... Furthermore, ESF are also stored | |
93 | from the msp in the memory stack. If msp is set higher than the dummy code, | |
94 | an ESF may clobber this code. */ | |
95 | ||
96 | #if TARGET_BYTE_ORDER == BIG_ENDIAN | |
97 | #define NOP_INSTR 0x70400101 | |
98 | #else /* Target is little endian */ | |
99 | #define NOP_INSTR 0x01014070 | |
100 | #endif | |
101 | ||
102 | #undef FIX_CALL_DUMMY | |
103 | #define FIX_CALL_DUMMY(dummyname, pc, fun, nargs, args, type, gcc_p) \ | |
104 | { \ | |
105 | *(int *)((char *)dummyname + 8) = NOP_INSTR; \ | |
106 | STUFF_I16((char *)dummyname + CONST_INSN, fun); \ | |
107 | STUFF_I16((char *)dummyname + CONST_INSN + 4, fun >> 16); \ | |
108 | } | |
109 | ||
110 | /* For VxWorks, CALL_DUMMY must be stored in the stack of the task that is | |
111 | being debugged and executed "in the context of" this task */ | |
112 | ||
113 | #undef CALL_DUMMY_LOCATION | |
114 | #define CALL_DUMMY_LOCATION ON_STACK | |
115 | ||
116 | /* Set or delete a breakpoint at the location within a CALL_DUMMY code | |
117 | fragment where we want the target program to stop after the function | |
118 | call is complete. CALL_DUMMY_ADDR is the address of the first | |
119 | instruction in the CALL_DUMMY. DUMMY_FRAME_ADDR is the value of the | |
120 | frame pointer in the dummy frame. | |
121 | ||
122 | NOTE: in the both of the following definitions, we take advantage of | |
c5aa993b JM |
123 | knowledge of the implementation of the target breakpoint operation, |
124 | in that we pass a null pointer as the second argument. It seems | |
125 | reasonable to assume that any target requiring the use of | |
126 | CALL_DUMMY_BREAK_{SET,DELETE} will not store the breakpoint | |
127 | shadow contents in GDB; in any case, this assumption is vaild | |
128 | for all VxWorks-related targets. */ | |
c906108c SS |
129 | |
130 | #define CALL_DUMMY_BREAK_SET(call_dummy_addr) \ | |
131 | target_insert_breakpoint ((call_dummy_addr) + CALL_DUMMY_STOP_OFFSET, \ | |
132 | (char *) 0) | |
133 | ||
134 | #define CALL_DUMMY_BREAK_DELETE(dummy_frame_addr) \ | |
135 | target_remove_breakpoint ((dummy_frame_addr) - (CALL_DUMMY_OFFSET_IN_FRAME \ | |
136 | - CALL_DUMMY_STOP_OFFSET), \ | |
137 | (char *) 0) | |
138 | ||
139 | /* Return nonzero if the pc is executing within a CALL_DUMMY frame. */ | |
140 | ||
141 | #define PC_IN_CALL_DUMMY(pc, sp, frame_address) \ | |
142 | ((pc) >= (sp) \ | |
143 | && (pc) <= (sp) + CALL_DUMMY_OFFSET_IN_FRAME + CALL_DUMMY_LENGTH) | |
144 | ||
145 | /* Defining this prevents us from trying to pass a structure-valued argument | |
146 | to a function called via the CALL_DUMMY mechanism. This is not handled | |
147 | properly in call_function_by_hand (), and the fix might require re-writing | |
148 | the CALL_DUMMY handling for all targets (at least, a clean solution | |
149 | would probably require this). Arguably, this should go in "tm-29k.h" | |
150 | rather than here. */ | |
c5aa993b | 151 | |
c906108c SS |
152 | #define STRUCT_VAL_ARGS_UNSUPPORTED |
153 | ||
154 | #define BKPT_OFFSET (7 * 4) | |
155 | #define BKPT_INSTR 0x72500101 | |
156 | ||
157 | #undef FIX_CALL_DUMMY | |
158 | #define FIX_CALL_DUMMY(dummyname, pc, fun, nargs, args, type, gcc_p) \ | |
159 | {\ | |
160 | STUFF_I16((char *)dummyname + CONST_INSN, fun);\ | |
161 | STUFF_I16((char *)dummyname + CONST_INSN + 4, fun >> 16);\ | |
162 | *(int *)((char *)dummyname + BKPT_OFFSET) = BKPT_INSTR;\ | |
163 | } | |
c906108c | 164 | \f |
c5aa993b | 165 | |
c906108c SS |
166 | /* Offsets into jmp_buf. They are derived from VxWorks' REG_SET struct |
167 | (see VxWorks' setjmp.h). Note that Sun2, Sun3 and SunOS4 and VxWorks have | |
168 | different REG_SET structs, hence different layouts for the jmp_buf struct. | |
169 | Only JB_PC is needed for getting the saved PC value. */ | |
170 | ||
c5aa993b | 171 | #define JB_ELEMENT_SIZE 4 /* size of each element in jmp_buf */ |
c906108c | 172 | #define JB_PC 3 /* offset of pc (pc1) in jmp_buf */ |
c5aa993b | 173 | |
c906108c SS |
174 | /* Figure out where the longjmp will land. We expect that we have just entered |
175 | longjmp and haven't yet setup the stack frame, so the args are still in the | |
176 | output regs. lr2 (LR2_REGNUM) points at the jmp_buf structure from which we | |
177 | extract the pc (JB_PC) that we will land at. The pc is copied into ADDR. | |
178 | This routine returns true on success */ | |
179 | ||
180 | #define GET_LONGJMP_TARGET(ADDR) get_longjmp_target(ADDR) | |
a14ed312 | 181 | extern int get_longjmp_target (CORE_ADDR *); |
c906108c SS |
182 | |
183 | /* VxWorks adjusts the PC after a breakpoint has been hit. */ | |
c5aa993b | 184 | |
c906108c SS |
185 | #undef DECR_PC_AFTER_BREAK |
186 | #define DECR_PC_AFTER_BREAK 0 | |
187 | ||
188 | /* Do whatever promotions are appropriate on a value being returned | |
189 | from a function. VAL is the user-supplied value, and FUNC_TYPE | |
190 | is the return type of the function if known, else 0. | |
c5aa993b | 191 | |
c906108c SS |
192 | For the Am29k, as far as I understand, if the function return type is known, |
193 | cast the value to that type; otherwise, ensure that integer return values | |
194 | fill all of gr96. | |
195 | ||
196 | This definition really belongs in "tm-29k.h", since it applies | |
197 | to most Am29K-based systems; but once moved into that file, it might | |
198 | need to be redefined for all Am29K-based targets that also redefine | |
199 | STORE_RETURN_VALUE. For now, to be safe, we define it here. */ | |
c5aa993b | 200 | |
c906108c SS |
201 | #define PROMOTE_RETURN_VALUE(val, func_type) \ |
202 | do { \ | |
203 | if (func_type) \ | |
204 | val = value_cast (func_type, val); \ | |
205 | if ((TYPE_CODE (VALUE_TYPE (val)) == TYPE_CODE_INT \ | |
206 | || TYPE_CODE (VALUE_TYPE (val)) == TYPE_CODE_ENUM) \ | |
207 | && TYPE_LENGTH (VALUE_TYPE (val)) < REGISTER_RAW_SIZE (0)) \ | |
208 | val = value_cast (builtin_type_int, val); \ | |
209 | } while (0) | |
210 | ||
a14ed312 | 211 | extern int vx29k_frame_chain_valid (CORE_ADDR, struct frame_info *); |
c906108c SS |
212 | #define FRAME_CHAIN_VALID(chain, thisframe) vx29k_frame_chain_valid (chain, thisframe) |
213 | ||
214 | extern CORE_ADDR frame_saved_call_site (); | |
215 | ||
216 | #undef PREPARE_TO_INIT_FRAME_INFO | |
217 | #define PREPARE_TO_INIT_FRAME_INFO(fci) do { \ | |
218 | long current_msp = read_register (MSP_REGNUM); \ | |
219 | if (PC_IN_CALL_DUMMY (fci->pc, current_msp, 0)) \ | |
220 | { \ | |
221 | fci->rsize = DUMMY_FRAME_RSIZE; \ | |
222 | fci->msize = 0; \ | |
223 | fci->saved_msp = \ | |
224 | read_register_stack_integer (fci->frame + DUMMY_FRAME_RSIZE - 4, 4); \ | |
225 | fci->flags |= (TRANSPARENT|MFP_USED); \ | |
226 | return; \ | |
227 | } \ | |
228 | } while (0) |