Commit | Line | Data |
---|---|---|
d0722149 DE |
1 | /* GNU/Linux/x86-64 specific low level interface, for the remote server |
2 | for GDB. | |
3 | Copyright (C) 2002, 2004, 2005, 2006, 2007, 2008, 2009 | |
4 | Free Software Foundation, Inc. | |
5 | ||
6 | This file is part of GDB. | |
7 | ||
8 | This program is free software; you can redistribute it and/or modify | |
9 | it under the terms of the GNU General Public License as published by | |
10 | the Free Software Foundation; either version 3 of the License, or | |
11 | (at your option) any later version. | |
12 | ||
13 | This program is distributed in the hope that it will be useful, | |
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | GNU General Public License for more details. | |
17 | ||
18 | You should have received a copy of the GNU General Public License | |
19 | along with this program. If not, see <http://www.gnu.org/licenses/>. */ | |
20 | ||
d0722149 DE |
21 | #include <signal.h> |
22 | #include "server.h" | |
23 | #include "linux-low.h" | |
24 | #include "i387-fp.h" | |
25 | ||
26 | #include "gdb_proc_service.h" | |
27 | ||
28 | /* NOTE: gdb_proc_service.h may include linux/elf.h. | |
29 | We need Elf32_Phdr. If we don't get linux/elf.h we could include | |
30 | elf.h like linux-ppc-low.c does. */ | |
31 | ||
32 | /* Defined in auto-generated file reg-i386-linux.c. */ | |
33 | void init_registers_i386_linux (void); | |
34 | /* Defined in auto-generated file reg-x86-64-linux.c. */ | |
35 | void init_registers_x86_64_linux (void); | |
36 | ||
37 | #include <sys/reg.h> | |
38 | #include <sys/procfs.h> | |
39 | #include <sys/ptrace.h> | |
40 | ||
41 | #ifndef PTRACE_GET_THREAD_AREA | |
42 | #define PTRACE_GET_THREAD_AREA 25 | |
43 | #endif | |
44 | ||
45 | /* This definition comes from prctl.h, but some kernels may not have it. */ | |
46 | #ifndef PTRACE_ARCH_PRCTL | |
47 | #define PTRACE_ARCH_PRCTL 30 | |
48 | #endif | |
49 | ||
50 | /* The following definitions come from prctl.h, but may be absent | |
51 | for certain configurations. */ | |
52 | #ifndef ARCH_GET_FS | |
53 | #define ARCH_SET_GS 0x1001 | |
54 | #define ARCH_SET_FS 0x1002 | |
55 | #define ARCH_GET_FS 0x1003 | |
56 | #define ARCH_GET_GS 0x1004 | |
57 | #endif | |
58 | ||
59 | #ifdef __x86_64__ | |
60 | ||
61 | /* Mapping between the general-purpose registers in `struct user' | |
62 | format and GDB's register array layout. | |
63 | Note that the transfer layout uses 64-bit regs. */ | |
64 | static /*const*/ int i386_regmap[] = | |
65 | { | |
66 | RAX * 8, RCX * 8, RDX * 8, RBX * 8, | |
67 | RSP * 8, RBP * 8, RSI * 8, RDI * 8, | |
68 | RIP * 8, EFLAGS * 8, CS * 8, SS * 8, | |
69 | DS * 8, ES * 8, FS * 8, GS * 8 | |
70 | }; | |
71 | ||
72 | #define I386_NUM_REGS (sizeof (i386_regmap) / sizeof (i386_regmap[0])) | |
73 | ||
74 | /* So code below doesn't have to care, i386 or amd64. */ | |
75 | #define ORIG_EAX ORIG_RAX | |
76 | ||
77 | static const int x86_64_regmap[] = | |
78 | { | |
79 | RAX * 8, RBX * 8, RCX * 8, RDX * 8, | |
80 | RSI * 8, RDI * 8, RBP * 8, RSP * 8, | |
81 | R8 * 8, R9 * 8, R10 * 8, R11 * 8, | |
82 | R12 * 8, R13 * 8, R14 * 8, R15 * 8, | |
83 | RIP * 8, EFLAGS * 8, CS * 8, SS * 8, | |
84 | DS * 8, ES * 8, FS * 8, GS * 8, | |
85 | -1, -1, -1, -1, -1, -1, -1, -1, | |
86 | -1, -1, -1, -1, -1, -1, -1, -1, | |
87 | -1, -1, -1, -1, -1, -1, -1, -1, | |
88 | -1, -1, -1, -1, -1, -1, -1, -1, -1, | |
89 | ORIG_RAX * 8 | |
90 | }; | |
91 | ||
92 | #define X86_64_NUM_REGS (sizeof (x86_64_regmap) / sizeof (x86_64_regmap[0])) | |
93 | ||
94 | #else /* ! __x86_64__ */ | |
95 | ||
96 | /* Mapping between the general-purpose registers in `struct user' | |
97 | format and GDB's register array layout. */ | |
98 | static /*const*/ int i386_regmap[] = | |
99 | { | |
100 | EAX * 4, ECX * 4, EDX * 4, EBX * 4, | |
101 | UESP * 4, EBP * 4, ESI * 4, EDI * 4, | |
102 | EIP * 4, EFL * 4, CS * 4, SS * 4, | |
103 | DS * 4, ES * 4, FS * 4, GS * 4 | |
104 | }; | |
105 | ||
106 | #define I386_NUM_REGS (sizeof (i386_regmap) / sizeof (i386_regmap[0])) | |
107 | ||
108 | #endif | |
109 | \f | |
110 | /* Called by libthread_db. */ | |
111 | ||
112 | ps_err_e | |
113 | ps_get_thread_area (const struct ps_prochandle *ph, | |
114 | lwpid_t lwpid, int idx, void **base) | |
115 | { | |
116 | #ifdef __x86_64__ | |
117 | int use_64bit = register_size (0) == 8; | |
118 | ||
119 | if (use_64bit) | |
120 | { | |
121 | switch (idx) | |
122 | { | |
123 | case FS: | |
124 | if (ptrace (PTRACE_ARCH_PRCTL, lwpid, base, ARCH_GET_FS) == 0) | |
125 | return PS_OK; | |
126 | break; | |
127 | case GS: | |
128 | if (ptrace (PTRACE_ARCH_PRCTL, lwpid, base, ARCH_GET_GS) == 0) | |
129 | return PS_OK; | |
130 | break; | |
131 | default: | |
132 | return PS_BADADDR; | |
133 | } | |
134 | return PS_ERR; | |
135 | } | |
136 | #endif | |
137 | ||
138 | { | |
139 | unsigned int desc[4]; | |
140 | ||
141 | if (ptrace (PTRACE_GET_THREAD_AREA, lwpid, | |
142 | (void *) (intptr_t) idx, (unsigned long) &desc) < 0) | |
143 | return PS_ERR; | |
144 | ||
145 | *(int *)base = desc[1]; | |
146 | return PS_OK; | |
147 | } | |
148 | } | |
149 | \f | |
150 | static int | |
151 | i386_cannot_store_register (int regno) | |
152 | { | |
153 | return regno >= I386_NUM_REGS; | |
154 | } | |
155 | ||
156 | static int | |
157 | i386_cannot_fetch_register (int regno) | |
158 | { | |
159 | return regno >= I386_NUM_REGS; | |
160 | } | |
161 | ||
162 | static void | |
163 | x86_fill_gregset (void *buf) | |
164 | { | |
165 | int i; | |
166 | ||
167 | #ifdef __x86_64__ | |
168 | if (register_size (0) == 8) | |
169 | { | |
170 | for (i = 0; i < X86_64_NUM_REGS; i++) | |
171 | if (x86_64_regmap[i] != -1) | |
172 | collect_register (i, ((char *) buf) + x86_64_regmap[i]); | |
173 | return; | |
174 | } | |
175 | #endif | |
176 | ||
177 | for (i = 0; i < I386_NUM_REGS; i++) | |
178 | collect_register (i, ((char *) buf) + i386_regmap[i]); | |
179 | ||
180 | collect_register_by_name ("orig_eax", ((char *) buf) + ORIG_EAX * 4); | |
181 | } | |
182 | ||
183 | static void | |
184 | x86_store_gregset (const void *buf) | |
185 | { | |
186 | int i; | |
187 | ||
188 | #ifdef __x86_64__ | |
189 | if (register_size (0) == 8) | |
190 | { | |
191 | for (i = 0; i < X86_64_NUM_REGS; i++) | |
192 | if (x86_64_regmap[i] != -1) | |
193 | supply_register (i, ((char *) buf) + x86_64_regmap[i]); | |
194 | return; | |
195 | } | |
196 | #endif | |
197 | ||
198 | for (i = 0; i < I386_NUM_REGS; i++) | |
199 | supply_register (i, ((char *) buf) + i386_regmap[i]); | |
200 | ||
201 | supply_register_by_name ("orig_eax", ((char *) buf) + ORIG_EAX * 4); | |
202 | } | |
203 | ||
204 | static void | |
205 | x86_fill_fpregset (void *buf) | |
206 | { | |
207 | #ifdef __x86_64__ | |
208 | i387_cache_to_fxsave (buf); | |
209 | #else | |
210 | i387_cache_to_fsave (buf); | |
211 | #endif | |
212 | } | |
213 | ||
214 | static void | |
215 | x86_store_fpregset (const void *buf) | |
216 | { | |
217 | #ifdef __x86_64__ | |
218 | i387_fxsave_to_cache (buf); | |
219 | #else | |
220 | i387_fsave_to_cache (buf); | |
221 | #endif | |
222 | } | |
223 | ||
224 | #ifndef __x86_64__ | |
225 | ||
226 | static void | |
227 | x86_fill_fpxregset (void *buf) | |
228 | { | |
229 | i387_cache_to_fxsave (buf); | |
230 | } | |
231 | ||
232 | static void | |
233 | x86_store_fpxregset (const void *buf) | |
234 | { | |
235 | i387_fxsave_to_cache (buf); | |
236 | } | |
237 | ||
238 | #endif | |
239 | ||
240 | /* ??? The non-biarch i386 case stores all the i387 regs twice. | |
241 | Once in i387_.*fsave.* and once in i387_.*fxsave.*. | |
242 | This is, presumably, to handle the case where PTRACE_[GS]ETFPXREGS | |
243 | doesn't work. IWBN to avoid the duplication in the case where it | |
244 | does work. Maybe the arch_setup routine could check whether it works | |
245 | and update target_regsets accordingly, maybe by moving target_regsets | |
246 | to linux_target_ops and set the right one there, rather than having to | |
247 | modify the target_regsets global. */ | |
248 | ||
249 | struct regset_info target_regsets[] = | |
250 | { | |
251 | #ifdef HAVE_PTRACE_GETREGS | |
252 | { PTRACE_GETREGS, PTRACE_SETREGS, sizeof (elf_gregset_t), | |
253 | GENERAL_REGS, | |
254 | x86_fill_gregset, x86_store_gregset }, | |
255 | # ifndef __x86_64__ | |
256 | # ifdef HAVE_PTRACE_GETFPXREGS | |
257 | { PTRACE_GETFPXREGS, PTRACE_SETFPXREGS, sizeof (elf_fpxregset_t), | |
258 | EXTENDED_REGS, | |
259 | x86_fill_fpxregset, x86_store_fpxregset }, | |
260 | # endif | |
261 | # endif | |
262 | { PTRACE_GETFPREGS, PTRACE_SETFPREGS, sizeof (elf_fpregset_t), | |
263 | FP_REGS, | |
264 | x86_fill_fpregset, x86_store_fpregset }, | |
265 | #endif /* HAVE_PTRACE_GETREGS */ | |
266 | { 0, 0, -1, -1, NULL, NULL } | |
267 | }; | |
268 | ||
269 | static CORE_ADDR | |
270 | x86_get_pc (void) | |
271 | { | |
272 | int use_64bit = register_size (0) == 8; | |
273 | ||
274 | if (use_64bit) | |
275 | { | |
276 | unsigned long pc; | |
277 | collect_register_by_name ("rip", &pc); | |
278 | return (CORE_ADDR) pc; | |
279 | } | |
280 | else | |
281 | { | |
282 | unsigned int pc; | |
283 | collect_register_by_name ("eip", &pc); | |
284 | return (CORE_ADDR) pc; | |
285 | } | |
286 | } | |
287 | ||
288 | static void | |
289 | x86_set_pc (CORE_ADDR pc) | |
290 | { | |
291 | int use_64bit = register_size (0) == 8; | |
292 | ||
293 | if (use_64bit) | |
294 | { | |
295 | unsigned long newpc = pc; | |
296 | supply_register_by_name ("rip", &newpc); | |
297 | } | |
298 | else | |
299 | { | |
300 | unsigned int newpc = pc; | |
301 | supply_register_by_name ("eip", &newpc); | |
302 | } | |
303 | } | |
304 | \f | |
305 | static const unsigned char x86_breakpoint[] = { 0xCC }; | |
306 | #define x86_breakpoint_len 1 | |
307 | ||
308 | static int | |
309 | x86_breakpoint_at (CORE_ADDR pc) | |
310 | { | |
311 | unsigned char c; | |
312 | ||
313 | read_inferior_memory (pc, &c, 1); | |
314 | if (c == 0xCC) | |
315 | return 1; | |
316 | ||
317 | return 0; | |
318 | } | |
319 | \f | |
320 | /* When GDBSERVER is built as a 64-bit application on linux, the | |
321 | PTRACE_GETSIGINFO data is always presented in 64-bit layout. Since | |
322 | debugging a 32-bit inferior with a 64-bit GDBSERVER should look the same | |
323 | as debugging it with a 32-bit GDBSERVER, we do the 32-bit <-> 64-bit | |
324 | conversion in-place ourselves. */ | |
325 | ||
326 | /* These types below (compat_*) define a siginfo type that is layout | |
327 | compatible with the siginfo type exported by the 32-bit userspace | |
328 | support. */ | |
329 | ||
330 | #ifdef __x86_64__ | |
331 | ||
332 | typedef int compat_int_t; | |
333 | typedef unsigned int compat_uptr_t; | |
334 | ||
335 | typedef int compat_time_t; | |
336 | typedef int compat_timer_t; | |
337 | typedef int compat_clock_t; | |
338 | ||
339 | struct compat_timeval | |
340 | { | |
341 | compat_time_t tv_sec; | |
342 | int tv_usec; | |
343 | }; | |
344 | ||
345 | typedef union compat_sigval | |
346 | { | |
347 | compat_int_t sival_int; | |
348 | compat_uptr_t sival_ptr; | |
349 | } compat_sigval_t; | |
350 | ||
351 | typedef struct compat_siginfo | |
352 | { | |
353 | int si_signo; | |
354 | int si_errno; | |
355 | int si_code; | |
356 | ||
357 | union | |
358 | { | |
359 | int _pad[((128 / sizeof (int)) - 3)]; | |
360 | ||
361 | /* kill() */ | |
362 | struct | |
363 | { | |
364 | unsigned int _pid; | |
365 | unsigned int _uid; | |
366 | } _kill; | |
367 | ||
368 | /* POSIX.1b timers */ | |
369 | struct | |
370 | { | |
371 | compat_timer_t _tid; | |
372 | int _overrun; | |
373 | compat_sigval_t _sigval; | |
374 | } _timer; | |
375 | ||
376 | /* POSIX.1b signals */ | |
377 | struct | |
378 | { | |
379 | unsigned int _pid; | |
380 | unsigned int _uid; | |
381 | compat_sigval_t _sigval; | |
382 | } _rt; | |
383 | ||
384 | /* SIGCHLD */ | |
385 | struct | |
386 | { | |
387 | unsigned int _pid; | |
388 | unsigned int _uid; | |
389 | int _status; | |
390 | compat_clock_t _utime; | |
391 | compat_clock_t _stime; | |
392 | } _sigchld; | |
393 | ||
394 | /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */ | |
395 | struct | |
396 | { | |
397 | unsigned int _addr; | |
398 | } _sigfault; | |
399 | ||
400 | /* SIGPOLL */ | |
401 | struct | |
402 | { | |
403 | int _band; | |
404 | int _fd; | |
405 | } _sigpoll; | |
406 | } _sifields; | |
407 | } compat_siginfo_t; | |
408 | ||
409 | #define cpt_si_pid _sifields._kill._pid | |
410 | #define cpt_si_uid _sifields._kill._uid | |
411 | #define cpt_si_timerid _sifields._timer._tid | |
412 | #define cpt_si_overrun _sifields._timer._overrun | |
413 | #define cpt_si_status _sifields._sigchld._status | |
414 | #define cpt_si_utime _sifields._sigchld._utime | |
415 | #define cpt_si_stime _sifields._sigchld._stime | |
416 | #define cpt_si_ptr _sifields._rt._sigval.sival_ptr | |
417 | #define cpt_si_addr _sifields._sigfault._addr | |
418 | #define cpt_si_band _sifields._sigpoll._band | |
419 | #define cpt_si_fd _sifields._sigpoll._fd | |
420 | ||
421 | /* glibc at least up to 2.3.2 doesn't have si_timerid, si_overrun. | |
422 | In their place is si_timer1,si_timer2. */ | |
423 | #ifndef si_timerid | |
424 | #define si_timerid si_timer1 | |
425 | #endif | |
426 | #ifndef si_overrun | |
427 | #define si_overrun si_timer2 | |
428 | #endif | |
429 | ||
430 | static void | |
431 | compat_siginfo_from_siginfo (compat_siginfo_t *to, siginfo_t *from) | |
432 | { | |
433 | memset (to, 0, sizeof (*to)); | |
434 | ||
435 | to->si_signo = from->si_signo; | |
436 | to->si_errno = from->si_errno; | |
437 | to->si_code = from->si_code; | |
438 | ||
439 | if (to->si_code < 0) | |
440 | { | |
441 | to->cpt_si_ptr = (intptr_t) from->si_ptr; | |
442 | } | |
443 | else if (to->si_code == SI_USER) | |
444 | { | |
445 | to->cpt_si_pid = from->si_pid; | |
446 | to->cpt_si_uid = from->si_uid; | |
447 | } | |
448 | else if (to->si_code == SI_TIMER) | |
449 | { | |
450 | to->cpt_si_timerid = from->si_timerid; | |
451 | to->cpt_si_overrun = from->si_overrun; | |
452 | to->cpt_si_ptr = (intptr_t) from->si_ptr; | |
453 | } | |
454 | else | |
455 | { | |
456 | switch (to->si_signo) | |
457 | { | |
458 | case SIGCHLD: | |
459 | to->cpt_si_pid = from->si_pid; | |
460 | to->cpt_si_uid = from->si_uid; | |
461 | to->cpt_si_status = from->si_status; | |
462 | to->cpt_si_utime = from->si_utime; | |
463 | to->cpt_si_stime = from->si_stime; | |
464 | break; | |
465 | case SIGILL: | |
466 | case SIGFPE: | |
467 | case SIGSEGV: | |
468 | case SIGBUS: | |
469 | to->cpt_si_addr = (intptr_t) from->si_addr; | |
470 | break; | |
471 | case SIGPOLL: | |
472 | to->cpt_si_band = from->si_band; | |
473 | to->cpt_si_fd = from->si_fd; | |
474 | break; | |
475 | default: | |
476 | to->cpt_si_pid = from->si_pid; | |
477 | to->cpt_si_uid = from->si_uid; | |
478 | to->cpt_si_ptr = (intptr_t) from->si_ptr; | |
479 | break; | |
480 | } | |
481 | } | |
482 | } | |
483 | ||
484 | static void | |
485 | siginfo_from_compat_siginfo (siginfo_t *to, compat_siginfo_t *from) | |
486 | { | |
487 | memset (to, 0, sizeof (*to)); | |
488 | ||
489 | to->si_signo = from->si_signo; | |
490 | to->si_errno = from->si_errno; | |
491 | to->si_code = from->si_code; | |
492 | ||
493 | if (to->si_code < 0) | |
494 | { | |
495 | to->si_ptr = (void *) (intptr_t) from->cpt_si_ptr; | |
496 | } | |
497 | else if (to->si_code == SI_USER) | |
498 | { | |
499 | to->si_pid = from->cpt_si_pid; | |
500 | to->si_uid = from->cpt_si_uid; | |
501 | } | |
502 | else if (to->si_code == SI_TIMER) | |
503 | { | |
504 | to->si_timerid = from->cpt_si_timerid; | |
505 | to->si_overrun = from->cpt_si_overrun; | |
506 | to->si_ptr = (void *) (intptr_t) from->cpt_si_ptr; | |
507 | } | |
508 | else | |
509 | { | |
510 | switch (to->si_signo) | |
511 | { | |
512 | case SIGCHLD: | |
513 | to->si_pid = from->cpt_si_pid; | |
514 | to->si_uid = from->cpt_si_uid; | |
515 | to->si_status = from->cpt_si_status; | |
516 | to->si_utime = from->cpt_si_utime; | |
517 | to->si_stime = from->cpt_si_stime; | |
518 | break; | |
519 | case SIGILL: | |
520 | case SIGFPE: | |
521 | case SIGSEGV: | |
522 | case SIGBUS: | |
523 | to->si_addr = (void *) (intptr_t) from->cpt_si_addr; | |
524 | break; | |
525 | case SIGPOLL: | |
526 | to->si_band = from->cpt_si_band; | |
527 | to->si_fd = from->cpt_si_fd; | |
528 | break; | |
529 | default: | |
530 | to->si_pid = from->cpt_si_pid; | |
531 | to->si_uid = from->cpt_si_uid; | |
532 | to->si_ptr = (void* ) (intptr_t) from->cpt_si_ptr; | |
533 | break; | |
534 | } | |
535 | } | |
536 | } | |
537 | ||
538 | #endif /* __x86_64__ */ | |
539 | ||
540 | /* Convert a native/host siginfo object, into/from the siginfo in the | |
541 | layout of the inferiors' architecture. Returns true if any | |
542 | conversion was done; false otherwise. If DIRECTION is 1, then copy | |
543 | from INF to NATIVE. If DIRECTION is 0, copy from NATIVE to | |
544 | INF. */ | |
545 | ||
546 | static int | |
547 | x86_siginfo_fixup (struct siginfo *native, void *inf, int direction) | |
548 | { | |
549 | #ifdef __x86_64__ | |
550 | /* Is the inferior 32-bit? If so, then fixup the siginfo object. */ | |
551 | if (register_size (0) == 4) | |
552 | { | |
9f1036c1 DE |
553 | if (sizeof (struct siginfo) != sizeof (compat_siginfo_t)) |
554 | fatal ("unexpected difference in siginfo"); | |
d0722149 DE |
555 | |
556 | if (direction == 0) | |
557 | compat_siginfo_from_siginfo ((struct compat_siginfo *) inf, native); | |
558 | else | |
559 | siginfo_from_compat_siginfo (native, (struct compat_siginfo *) inf); | |
560 | ||
561 | return 1; | |
562 | } | |
563 | #endif | |
564 | ||
565 | return 0; | |
566 | } | |
567 | \f | |
9f1036c1 | 568 | /* Initialize gdbserver for the architecture of the inferior. */ |
d0722149 DE |
569 | |
570 | static void | |
571 | x86_arch_setup (void) | |
572 | { | |
573 | #ifdef __x86_64__ | |
574 | int pid = pid_of (get_thread_lwp (current_inferior)); | |
575 | char *file = linux_child_pid_to_exec_file (pid); | |
576 | int use_64bit = elf_64_file_p (file); | |
577 | ||
578 | free (file); | |
579 | ||
580 | if (use_64bit < 0) | |
581 | { | |
582 | /* This can only happen if /proc/<pid>/exe is unreadable, | |
583 | but "that can't happen" if we've gotten this far. | |
584 | Fall through and assume this is a 32-bit program. */ | |
585 | } | |
586 | else if (use_64bit) | |
587 | { | |
588 | init_registers_x86_64_linux (); | |
589 | ||
590 | /* Amd64 doesn't have HAVE_LINUX_USRREGS. */ | |
591 | the_low_target.num_regs = -1; | |
592 | the_low_target.regmap = NULL; | |
593 | the_low_target.cannot_fetch_register = NULL; | |
594 | the_low_target.cannot_store_register = NULL; | |
595 | ||
596 | /* Amd64 has 16 xmm regs. */ | |
597 | num_xmm_registers = 16; | |
598 | ||
599 | return; | |
600 | } | |
601 | #endif | |
602 | ||
603 | /* Ok we have a 32-bit inferior. */ | |
604 | ||
605 | init_registers_i386_linux (); | |
606 | ||
607 | the_low_target.num_regs = I386_NUM_REGS; | |
608 | the_low_target.regmap = i386_regmap; | |
609 | the_low_target.cannot_fetch_register = i386_cannot_fetch_register; | |
610 | the_low_target.cannot_store_register = i386_cannot_store_register; | |
611 | ||
612 | /* I386 has 8 xmm regs. */ | |
613 | num_xmm_registers = 8; | |
614 | } | |
615 | ||
616 | /* This is initialized assuming an amd64 target. | |
617 | x86_arch_setup will correct it for i386 or amd64 targets. */ | |
618 | ||
619 | struct linux_target_ops the_low_target = | |
620 | { | |
621 | x86_arch_setup, | |
622 | -1, | |
623 | NULL, | |
624 | NULL, | |
625 | NULL, | |
626 | x86_get_pc, | |
627 | x86_set_pc, | |
628 | x86_breakpoint, | |
629 | x86_breakpoint_len, | |
630 | NULL, | |
631 | 1, | |
632 | x86_breakpoint_at, | |
633 | NULL, | |
634 | NULL, | |
635 | NULL, | |
636 | NULL, | |
637 | /* collect_ptrace_register/supply_ptrace_register are not needed in the | |
638 | native i386 case (no registers smaller than an xfer unit), and are not | |
639 | used in the biarch case (HAVE_LINUX_USRREGS is not defined). */ | |
640 | NULL, | |
641 | NULL, | |
642 | /* need to fix up i386 siginfo if host is amd64 */ | |
643 | x86_siginfo_fixup, | |
644 | }; |