1 |
578 |
markom |
/* Target machine description for VxWorks on the 29k, for GDB, the GNU debugger.
|
2 |
|
|
Copyright 1994, 1995, 1998, 1999, 2000 Free Software Foundation, Inc.
|
3 |
|
|
Contributed by Cygnus Support.
|
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., 59 Temple Place - Suite 330,
|
20 |
|
|
Boston, MA 02111-1307, USA. */
|
21 |
|
|
|
22 |
|
|
#include "regcache.h"
|
23 |
|
|
#include "a29k/tm-a29k.h"
|
24 |
|
|
#include "tm-vxworks.h"
|
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 |
|
|
|
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). */
|
73 |
|
|
|
74 |
|
|
#define CALL_DUMMY_STOP_OFFSET (7 * 4)
|
75 |
|
|
|
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
|
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. */
|
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. */
|
151 |
|
|
|
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 |
|
|
}
|
164 |
|
|
|
165 |
|
|
|
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 |
|
|
|
171 |
|
|
#define JB_ELEMENT_SIZE 4 /* size of each element in jmp_buf */
|
172 |
|
|
#define JB_PC 3 /* offset of pc (pc1) in jmp_buf */
|
173 |
|
|
|
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)
|
181 |
|
|
extern int get_longjmp_target (CORE_ADDR *);
|
182 |
|
|
|
183 |
|
|
/* VxWorks adjusts the PC after a breakpoint has been hit. */
|
184 |
|
|
|
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.
|
191 |
|
|
|
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. */
|
200 |
|
|
|
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 |
|
|
|
211 |
|
|
extern int vx29k_frame_chain_valid (CORE_ADDR, struct frame_info *);
|
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)
|