Commit | Line | Data |
---|---|---|
42a4f53d | 1 | /* Copyright (C) 2010-2019 Free Software Foundation, Inc. |
fa1bd1e4 JB |
2 | |
3 | This file is part of GDB. | |
4 | ||
5 | This program is free software; you can redistribute it and/or modify | |
6 | it under the terms of the GNU General Public License as published by | |
7 | the Free Software Foundation; either version 3 of the License, or | |
8 | (at your option) any later version. | |
9 | ||
10 | This program is distributed in the hope that it will be useful, | |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | GNU General Public License for more details. | |
14 | ||
15 | You should have received a copy of the GNU General Public License | |
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. */ | |
17 | ||
18 | #include "server.h" | |
19 | #include "lynx-low.h" | |
fa1bd1e4 JB |
20 | #include <limits.h> |
21 | #include <sys/ptrace.h> | |
0747795c | 22 | #include "common/x86-xstate.h" |
22916b07 | 23 | #include "arch/i386.h" |
190852c8 | 24 | #include "x86-tdesc.h" |
fa1bd1e4 JB |
25 | |
26 | /* The following two typedefs are defined in a .h file which is not | |
27 | in the standard include path (/sys/include/family/x86/ucontext.h), | |
55271bf9 JB |
28 | so we just duplicate them here. |
29 | ||
30 | Unfortunately for us, the definition of this structure differs between | |
31 | LynxOS 5.x and LynxOS 178. Rather than duplicate the code, we use | |
32 | different definitions depending on the target. */ | |
33 | ||
34 | #ifdef VMOS_DEV | |
35 | #define LYNXOS_178 | |
36 | #endif | |
fa1bd1e4 JB |
37 | |
38 | /* General register context */ | |
39 | typedef struct usr_econtext { | |
40 | ||
41 | uint32_t uec_fault; | |
42 | uint32_t uec_es; | |
43 | uint32_t uec_ds; | |
44 | uint32_t uec_edi; | |
45 | uint32_t uec_esi; | |
46 | uint32_t uec_ebp; | |
47 | uint32_t uec_temp; | |
48 | uint32_t uec_ebx; | |
49 | uint32_t uec_edx; | |
50 | uint32_t uec_ecx; | |
51 | uint32_t uec_eax; | |
52 | uint32_t uec_inum; | |
53 | uint32_t uec_ecode; | |
54 | uint32_t uec_eip; | |
55 | uint32_t uec_cs; | |
56 | uint32_t uec_eflags; | |
57 | uint32_t uec_esp; | |
58 | uint32_t uec_ss; | |
59 | uint32_t uec_fs; | |
60 | uint32_t uec_gs; | |
61 | } usr_econtext_t; | |
62 | ||
55271bf9 JB |
63 | #if defined(LYNXOS_178) |
64 | ||
65 | /* Floating point register context */ | |
66 | typedef struct usr_fcontext { | |
67 | uint32_t ufc_control; | |
68 | uint32_t ufc_status; | |
69 | uint32_t ufc_tag; | |
70 | uint8_t *ufc_inst_off; | |
71 | uint32_t ufc_inst_sel; | |
72 | uint8_t *ufc_data_off; | |
73 | uint32_t ufc_data_sel; | |
74 | struct ufp387_real { | |
75 | uint16_t umant4; | |
76 | uint16_t umant3; | |
77 | uint16_t umant2; | |
78 | uint16_t umant1; | |
79 | uint16_t us_and_e; | |
80 | } ufc_reg[8]; | |
81 | } usr_fcontext_t; | |
82 | ||
83 | #else /* This is LynxOS 5.x. */ | |
84 | ||
fa1bd1e4 JB |
85 | /* Floating point and SIMD register context */ |
86 | typedef struct usr_fcontext { | |
87 | uint16_t ufc_control; | |
88 | uint16_t ufc_status; | |
89 | uint16_t ufc_tag; | |
90 | uint16_t ufc_opcode; | |
91 | uint8_t *ufc_inst_off; | |
92 | uint32_t ufc_inst_sel; | |
93 | uint8_t *ufc_data_off; | |
94 | uint32_t ufc_data_sel; | |
95 | uint32_t usse_mxcsr; | |
96 | uint32_t usse_mxcsr_mask; | |
97 | struct ufp387_real { | |
98 | uint16_t umant4; | |
99 | uint16_t umant3; | |
100 | uint16_t umant2; | |
101 | uint16_t umant1; | |
102 | uint16_t us_and_e; | |
103 | uint16_t ureserved_1; | |
104 | uint16_t ureserved_2; | |
105 | uint16_t ureserved_3; | |
106 | } ufc_reg[8]; | |
107 | struct uxmm_register { | |
108 | uint16_t uchunk_1; | |
109 | uint16_t uchunk_2; | |
110 | uint16_t uchunk_3; | |
111 | uint16_t uchunk_4; | |
112 | uint16_t uchunk_5; | |
113 | uint16_t uchunk_6; | |
114 | uint16_t uchunk_7; | |
115 | uint16_t uchunk_8; | |
116 | } uxmm_reg[8]; | |
117 | char ureserved[16][14]; | |
118 | } usr_fcontext_t; | |
119 | ||
55271bf9 JB |
120 | #endif |
121 | ||
fa1bd1e4 JB |
122 | /* The index of various registers inside the regcache. */ |
123 | ||
124 | enum lynx_i386_gdb_regnum | |
125 | { | |
126 | I386_EAX_REGNUM, | |
127 | I386_ECX_REGNUM, | |
128 | I386_EDX_REGNUM, | |
129 | I386_EBX_REGNUM, | |
130 | I386_ESP_REGNUM, | |
131 | I386_EBP_REGNUM, | |
132 | I386_ESI_REGNUM, | |
133 | I386_EDI_REGNUM, | |
134 | I386_EIP_REGNUM, | |
135 | I386_EFLAGS_REGNUM, | |
136 | I386_CS_REGNUM, | |
137 | I386_SS_REGNUM, | |
138 | I386_DS_REGNUM, | |
139 | I386_ES_REGNUM, | |
140 | I386_FS_REGNUM, | |
141 | I386_GS_REGNUM, | |
142 | I386_ST0_REGNUM, | |
143 | I386_FCTRL_REGNUM = I386_ST0_REGNUM + 8, | |
144 | I386_FSTAT_REGNUM, | |
145 | I386_FTAG_REGNUM, | |
146 | I386_FISEG_REGNUM, | |
147 | I386_FIOFF_REGNUM, | |
148 | I386_FOSEG_REGNUM, | |
149 | I386_FOOFF_REGNUM, | |
150 | I386_FOP_REGNUM, | |
151 | I386_XMM0_REGNUM = 32, | |
152 | I386_MXCSR_REGNUM = I386_XMM0_REGNUM + 8, | |
153 | I386_SENTINEL_REGUM | |
154 | }; | |
155 | ||
fa1bd1e4 JB |
156 | /* The fill_function for the general-purpose register set. */ |
157 | ||
158 | static void | |
159 | lynx_i386_fill_gregset (struct regcache *regcache, char *buf) | |
160 | { | |
161 | #define lynx_i386_collect_gp(regnum, fld) \ | |
162 | collect_register (regcache, regnum, \ | |
163 | buf + offsetof (usr_econtext_t, uec_##fld)) | |
164 | ||
165 | lynx_i386_collect_gp (I386_EAX_REGNUM, eax); | |
166 | lynx_i386_collect_gp (I386_ECX_REGNUM, ecx); | |
167 | lynx_i386_collect_gp (I386_EDX_REGNUM, edx); | |
168 | lynx_i386_collect_gp (I386_EBX_REGNUM, ebx); | |
169 | lynx_i386_collect_gp (I386_ESP_REGNUM, esp); | |
170 | lynx_i386_collect_gp (I386_EBP_REGNUM, ebp); | |
171 | lynx_i386_collect_gp (I386_ESI_REGNUM, esi); | |
172 | lynx_i386_collect_gp (I386_EDI_REGNUM, edi); | |
173 | lynx_i386_collect_gp (I386_EIP_REGNUM, eip); | |
174 | lynx_i386_collect_gp (I386_EFLAGS_REGNUM, eflags); | |
175 | lynx_i386_collect_gp (I386_CS_REGNUM, cs); | |
176 | lynx_i386_collect_gp (I386_SS_REGNUM, ss); | |
177 | lynx_i386_collect_gp (I386_DS_REGNUM, ds); | |
178 | lynx_i386_collect_gp (I386_ES_REGNUM, es); | |
179 | lynx_i386_collect_gp (I386_FS_REGNUM, fs); | |
180 | lynx_i386_collect_gp (I386_GS_REGNUM, gs); | |
181 | } | |
182 | ||
183 | /* The store_function for the general-purpose register set. */ | |
184 | ||
185 | static void | |
186 | lynx_i386_store_gregset (struct regcache *regcache, const char *buf) | |
187 | { | |
188 | #define lynx_i386_supply_gp(regnum, fld) \ | |
189 | supply_register (regcache, regnum, \ | |
190 | buf + offsetof (usr_econtext_t, uec_##fld)) | |
191 | ||
192 | lynx_i386_supply_gp (I386_EAX_REGNUM, eax); | |
193 | lynx_i386_supply_gp (I386_ECX_REGNUM, ecx); | |
194 | lynx_i386_supply_gp (I386_EDX_REGNUM, edx); | |
195 | lynx_i386_supply_gp (I386_EBX_REGNUM, ebx); | |
196 | lynx_i386_supply_gp (I386_ESP_REGNUM, esp); | |
197 | lynx_i386_supply_gp (I386_EBP_REGNUM, ebp); | |
198 | lynx_i386_supply_gp (I386_ESI_REGNUM, esi); | |
199 | lynx_i386_supply_gp (I386_EDI_REGNUM, edi); | |
200 | lynx_i386_supply_gp (I386_EIP_REGNUM, eip); | |
201 | lynx_i386_supply_gp (I386_EFLAGS_REGNUM, eflags); | |
202 | lynx_i386_supply_gp (I386_CS_REGNUM, cs); | |
203 | lynx_i386_supply_gp (I386_SS_REGNUM, ss); | |
204 | lynx_i386_supply_gp (I386_DS_REGNUM, ds); | |
205 | lynx_i386_supply_gp (I386_ES_REGNUM, es); | |
206 | lynx_i386_supply_gp (I386_FS_REGNUM, fs); | |
207 | lynx_i386_supply_gp (I386_GS_REGNUM, gs); | |
208 | } | |
209 | ||
210 | /* Extract the first 16 bits of register REGNUM in the REGCACHE, | |
211 | and store these 2 bytes at DEST. | |
212 | ||
213 | This is useful to collect certain 16bit registers which are known | |
214 | by GDBserver as 32bit registers (such as the Control Register | |
215 | for instance). */ | |
216 | ||
217 | static void | |
218 | collect_16bit_register (struct regcache *regcache, int regnum, char *dest) | |
219 | { | |
220 | gdb_byte word[4]; | |
221 | ||
222 | collect_register (regcache, regnum, word); | |
223 | memcpy (dest, word, 2); | |
224 | } | |
225 | ||
226 | /* The fill_function for the floating-point register set. */ | |
227 | ||
228 | static void | |
229 | lynx_i386_fill_fpregset (struct regcache *regcache, char *buf) | |
230 | { | |
231 | int i; | |
232 | ||
233 | /* Collect %st0 .. %st7. */ | |
234 | for (i = 0; i < 8; i++) | |
235 | collect_register (regcache, I386_ST0_REGNUM + i, | |
236 | buf + offsetof (usr_fcontext_t, ufc_reg) | |
237 | + i * sizeof (struct ufp387_real)); | |
238 | ||
239 | /* Collect the other FPU registers. */ | |
240 | collect_16bit_register (regcache, I386_FCTRL_REGNUM, | |
241 | buf + offsetof (usr_fcontext_t, ufc_control)); | |
242 | collect_16bit_register (regcache, I386_FSTAT_REGNUM, | |
243 | buf + offsetof (usr_fcontext_t, ufc_status)); | |
244 | collect_16bit_register (regcache, I386_FTAG_REGNUM, | |
245 | buf + offsetof (usr_fcontext_t, ufc_tag)); | |
246 | collect_register (regcache, I386_FISEG_REGNUM, | |
247 | buf + offsetof (usr_fcontext_t, ufc_inst_sel)); | |
248 | collect_register (regcache, I386_FIOFF_REGNUM, | |
249 | buf + offsetof (usr_fcontext_t, ufc_inst_off)); | |
250 | collect_register (regcache, I386_FOSEG_REGNUM, | |
251 | buf + offsetof (usr_fcontext_t, ufc_data_sel)); | |
252 | collect_register (regcache, I386_FOOFF_REGNUM, | |
253 | buf + offsetof (usr_fcontext_t, ufc_data_off)); | |
55271bf9 | 254 | #if !defined(LYNXOS_178) |
fa1bd1e4 JB |
255 | collect_16bit_register (regcache, I386_FOP_REGNUM, |
256 | buf + offsetof (usr_fcontext_t, ufc_opcode)); | |
257 | ||
258 | /* Collect the XMM registers. */ | |
259 | for (i = 0; i < 8; i++) | |
260 | collect_register (regcache, I386_XMM0_REGNUM + i, | |
261 | buf + offsetof (usr_fcontext_t, uxmm_reg) | |
262 | + i * sizeof (struct uxmm_register)); | |
263 | collect_register (regcache, I386_MXCSR_REGNUM, | |
264 | buf + offsetof (usr_fcontext_t, usse_mxcsr)); | |
55271bf9 | 265 | #endif |
fa1bd1e4 JB |
266 | } |
267 | ||
268 | /* This is the supply counterpart for collect_16bit_register: | |
269 | It extracts a 2byte value from BUF, and uses that value to | |
270 | set REGNUM's value in the regcache. | |
271 | ||
272 | This is useful to supply the value of certain 16bit registers | |
273 | which are known by GDBserver as 32bit registers (such as the Control | |
274 | Register for instance). */ | |
275 | ||
276 | static void | |
277 | supply_16bit_register (struct regcache *regcache, int regnum, const char *buf) | |
278 | { | |
279 | gdb_byte word[4]; | |
280 | ||
281 | memcpy (word, buf, 2); | |
282 | memset (word + 2, 0, 2); | |
283 | supply_register (regcache, regnum, word); | |
284 | } | |
285 | ||
286 | /* The store_function for the floating-point register set. */ | |
287 | ||
288 | static void | |
289 | lynx_i386_store_fpregset (struct regcache *regcache, const char *buf) | |
290 | { | |
291 | int i; | |
292 | ||
293 | /* Store the %st0 .. %st7 registers. */ | |
294 | for (i = 0; i < 8; i++) | |
295 | supply_register (regcache, I386_ST0_REGNUM + i, | |
296 | buf + offsetof (usr_fcontext_t, ufc_reg) | |
297 | + i * sizeof (struct ufp387_real)); | |
298 | ||
299 | /* Store the other FPU registers. */ | |
300 | supply_16bit_register (regcache, I386_FCTRL_REGNUM, | |
301 | buf + offsetof (usr_fcontext_t, ufc_control)); | |
302 | supply_16bit_register (regcache, I386_FSTAT_REGNUM, | |
303 | buf + offsetof (usr_fcontext_t, ufc_status)); | |
304 | supply_16bit_register (regcache, I386_FTAG_REGNUM, | |
305 | buf + offsetof (usr_fcontext_t, ufc_tag)); | |
306 | supply_register (regcache, I386_FISEG_REGNUM, | |
307 | buf + offsetof (usr_fcontext_t, ufc_inst_sel)); | |
308 | supply_register (regcache, I386_FIOFF_REGNUM, | |
309 | buf + offsetof (usr_fcontext_t, ufc_inst_off)); | |
310 | supply_register (regcache, I386_FOSEG_REGNUM, | |
311 | buf + offsetof (usr_fcontext_t, ufc_data_sel)); | |
312 | supply_register (regcache, I386_FOOFF_REGNUM, | |
313 | buf + offsetof (usr_fcontext_t, ufc_data_off)); | |
55271bf9 | 314 | #if !defined(LYNXOS_178) |
fa1bd1e4 JB |
315 | supply_16bit_register (regcache, I386_FOP_REGNUM, |
316 | buf + offsetof (usr_fcontext_t, ufc_opcode)); | |
317 | ||
318 | /* Store the XMM registers. */ | |
319 | for (i = 0; i < 8; i++) | |
320 | supply_register (regcache, I386_XMM0_REGNUM + i, | |
321 | buf + offsetof (usr_fcontext_t, uxmm_reg) | |
322 | + i * sizeof (struct uxmm_register)); | |
323 | supply_register (regcache, I386_MXCSR_REGNUM, | |
324 | buf + offsetof (usr_fcontext_t, usse_mxcsr)); | |
55271bf9 | 325 | #endif |
fa1bd1e4 JB |
326 | } |
327 | ||
328 | /* Implements the lynx_target_ops.arch_setup routine. */ | |
329 | ||
330 | static void | |
331 | lynx_i386_arch_setup (void) | |
332 | { | |
289a6840 | 333 | struct target_desc *tdesc |
1163a4b7 | 334 | = i386_create_target_description (X86_XSTATE_SSE_MASK, false, false); |
289a6840 | 335 | |
190852c8 | 336 | init_target_desc (tdesc, i386_expedite_regs); |
289a6840 SM |
337 | |
338 | lynx_tdesc = tdesc; | |
fa1bd1e4 JB |
339 | } |
340 | ||
341 | /* Description of all the x86-lynx register sets. */ | |
342 | ||
343 | struct lynx_regset_info lynx_target_regsets[] = { | |
344 | /* General Purpose Registers. */ | |
345 | {PTRACE_GETREGS, PTRACE_SETREGS, sizeof(usr_econtext_t), | |
346 | lynx_i386_fill_gregset, lynx_i386_store_gregset}, | |
347 | /* Floating Point Registers. */ | |
348 | { PTRACE_GETFPREGS, PTRACE_SETFPREGS, sizeof(usr_fcontext_t), | |
349 | lynx_i386_fill_fpregset, lynx_i386_store_fpregset }, | |
350 | /* End of list marker. */ | |
351 | {0, 0, -1, NULL, NULL } | |
352 | }; | |
353 | ||
354 | /* The lynx_target_ops vector for x86-lynx. */ | |
355 | ||
356 | struct lynx_target_ops the_low_target = { | |
357 | lynx_i386_arch_setup, | |
358 | }; |