]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - gdb/i386-nto-tdep.c
2012-02-02 Pedro Alves <palves@redhat.com>
[thirdparty/binutils-gdb.git] / gdb / i386-nto-tdep.c
CommitLineData
911bc6ee 1/* Target-dependent code for QNX Neutrino x86.
1b883d35 2
0b302171 3 Copyright (C) 2003-2004, 2007-2012 Free Software Foundation, Inc.
1b883d35
KW
4
5 Contributed by QNX Software Systems Ltd.
6
7 This file is part of GDB.
8
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
a9762ec7 11 the Free Software Foundation; either version 3 of the License, or
1b883d35
KW
12 (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
a9762ec7 20 along with this program. If not, see <http://www.gnu.org/licenses/>. */
1b883d35 21
1b883d35
KW
22#include "defs.h"
23#include "frame.h"
17ca283a 24#include "osabi.h"
1b883d35 25#include "regcache.h"
17ca283a
MK
26#include "target.h"
27
28#include "gdb_assert.h"
29#include "gdb_string.h"
30
1b883d35 31#include "i386-tdep.h"
1b883d35 32#include "i387-tdep.h"
17ca283a 33#include "nto-tdep.h"
59215afb 34#include "solib.h"
17ca283a 35#include "solib-svr4.h"
1b883d35
KW
36
37#ifndef X86_CPU_FXSR
38#define X86_CPU_FXSR (1L << 12)
39#endif
40
41/* Why 13? Look in our /usr/include/x86/context.h header at the
42 x86_cpu_registers structure and you'll see an 'exx' junk register
43 that is just filler. Don't ask me, ask the kernel guys. */
44#define NUM_GPREGS 13
45
3d171c85
MK
46/* Mapping between the general-purpose registers in `struct xxx'
47 format and GDB's register cache layout. */
48
49/* From <x86/context.h>. */
50static int i386nto_gregset_reg_offset[] =
51{
52 7 * 4, /* %eax */
53 6 * 4, /* %ecx */
54 5 * 4, /* %edx */
55 4 * 4, /* %ebx */
56 11 * 4, /* %esp */
57 2 * 4, /* %epb */
58 1 * 4, /* %esi */
59 0 * 4, /* %edi */
60 8 * 4, /* %eip */
61 10 * 4, /* %eflags */
62 9 * 4, /* %cs */
63 12 * 4, /* %ss */
64 -1 /* filler */
1b883d35
KW
65};
66
3d171c85
MK
67/* Given a GDB register number REGNUM, return the offset into
68 Neutrino's register structure or -1 if the register is unknown. */
d737fd7f 69
1b883d35 70static int
3d171c85 71nto_reg_offset (int regnum)
1b883d35 72{
3d171c85
MK
73 if (regnum >= 0 && regnum < ARRAY_SIZE (i386nto_gregset_reg_offset))
74 return i386nto_gregset_reg_offset[regnum];
75
76 return -1;
1b883d35
KW
77}
78
79static void
468e3d51 80i386nto_supply_gregset (struct regcache *regcache, char *gpregs)
1b883d35 81{
875f8d0e
UW
82 struct gdbarch *gdbarch = get_regcache_arch (regcache);
83 struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
1b883d35 84
3d171c85 85 if(tdep->gregset == NULL)
875f8d0e 86 tdep->gregset = regset_alloc (gdbarch, i386_supply_gregset,
3d171c85
MK
87 i386_collect_gregset);
88
89 gdb_assert (tdep->gregset_reg_offset == i386nto_gregset_reg_offset);
468e3d51 90 tdep->gregset->supply_regset (tdep->gregset, regcache, -1,
3d171c85 91 gpregs, NUM_GPREGS * 4);
1b883d35
KW
92}
93
94static void
468e3d51 95i386nto_supply_fpregset (struct regcache *regcache, char *fpregs)
1b883d35
KW
96{
97 if (nto_cpuinfo_valid && nto_cpuinfo_flags | X86_CPU_FXSR)
468e3d51 98 i387_supply_fxsave (regcache, -1, fpregs);
1b883d35 99 else
468e3d51 100 i387_supply_fsave (regcache, -1, fpregs);
1b883d35
KW
101}
102
103static void
468e3d51 104i386nto_supply_regset (struct regcache *regcache, int regset, char *data)
1b883d35
KW
105{
106 switch (regset)
107 {
3d171c85 108 case NTO_REG_GENERAL:
468e3d51 109 i386nto_supply_gregset (regcache, data);
1b883d35
KW
110 break;
111 case NTO_REG_FLOAT:
468e3d51 112 i386nto_supply_fpregset (regcache, data);
1b883d35
KW
113 break;
114 }
115}
116
117static int
118i386nto_regset_id (int regno)
119{
120 if (regno == -1)
121 return NTO_REG_END;
f6792ef4 122 else if (regno < I386_NUM_GREGS)
1b883d35 123 return NTO_REG_GENERAL;
90884b2b 124 else if (regno < I386_NUM_GREGS + I387_NUM_REGS)
1b883d35 125 return NTO_REG_FLOAT;
dbfb31a4
AR
126 else if (regno < I386_SSE_NUM_REGS)
127 return NTO_REG_FLOAT; /* We store xmm registers in fxsave_area. */
1b883d35
KW
128
129 return -1; /* Error. */
130}
131
132static int
60441ab9
UW
133i386nto_register_area (struct gdbarch *gdbarch,
134 int regno, int regset, unsigned *off)
1b883d35 135{
dbfb31a4 136 struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
1b883d35
KW
137 int len;
138
139 *off = 0;
140 if (regset == NTO_REG_GENERAL)
141 {
142 if (regno == -1)
143 return NUM_GPREGS * 4;
144
145 *off = nto_reg_offset (regno);
146 if (*off == -1)
147 return 0;
148 return 4;
149 }
150 else if (regset == NTO_REG_FLOAT)
151 {
dbfb31a4
AR
152 unsigned off_adjust, regsize, regset_size, regno_base;
153 /* The following are flags indicating number in our fxsave_area. */
154 int first_four = (regno >= I387_FCTRL_REGNUM (tdep)
155 && regno <= I387_FISEG_REGNUM (tdep));
156 int second_four = (regno > I387_FISEG_REGNUM (tdep)
157 && regno <= I387_FOP_REGNUM (tdep));
158 int st_reg = (regno >= I387_ST0_REGNUM (tdep)
159 && regno < I387_ST0_REGNUM (tdep) + 8);
160 int xmm_reg = (regno >= I387_XMM0_REGNUM (tdep)
161 && regno < I387_MXCSR_REGNUM (tdep));
1b883d35
KW
162
163 if (nto_cpuinfo_valid && nto_cpuinfo_flags | X86_CPU_FXSR)
164 {
165 off_adjust = 32;
166 regsize = 16;
167 regset_size = 512;
dbfb31a4
AR
168 /* fxsave_area structure. */
169 if (first_four)
170 {
171 /* fpu_control_word, fpu_status_word, fpu_tag_word, fpu_operand
172 registers. */
173 regsize = 2; /* Two bytes each. */
174 off_adjust = 0;
175 regno_base = I387_FCTRL_REGNUM (tdep);
176 }
177 else if (second_four)
178 {
179 /* fpu_ip, fpu_cs, fpu_op, fpu_ds registers. */
180 regsize = 4;
181 off_adjust = 8;
182 regno_base = I387_FISEG_REGNUM (tdep) + 1;
183 }
184 else if (st_reg)
185 {
186 /* ST registers. */
187 regsize = 16;
188 off_adjust = 32;
189 regno_base = I387_ST0_REGNUM (tdep);
190 }
191 else if (xmm_reg)
192 {
193 /* XMM registers. */
194 regsize = 16;
195 off_adjust = 160;
196 regno_base = I387_XMM0_REGNUM (tdep);
197 }
198 else if (regno == I387_MXCSR_REGNUM (tdep))
199 {
200 regsize = 4;
201 off_adjust = 24;
202 regno_base = I387_MXCSR_REGNUM (tdep);
203 }
204 else
205 {
206 /* Whole regset. */
207 gdb_assert (regno == -1);
208 off_adjust = 0;
209 regno_base = 0;
210 regsize = regset_size;
211 }
1b883d35
KW
212 }
213 else
214 {
dbfb31a4
AR
215 regset_size = 108;
216 /* fsave_area structure. */
217 if (first_four || second_four)
218 {
219 /* fpu_control_word, ... , fpu_ds registers. */
220 regsize = 4;
221 off_adjust = 0;
222 regno_base = I387_FCTRL_REGNUM (tdep);
223 }
224 else if (st_reg)
225 {
226 /* One of ST registers. */
227 regsize = 10;
228 off_adjust = 7 * 4;
229 regno_base = I387_ST0_REGNUM (tdep);
230 }
231 else
232 {
233 /* Whole regset. */
234 gdb_assert (regno == -1);
235 off_adjust = 0;
236 regno_base = 0;
237 regsize = regset_size;
238 }
1b883d35
KW
239 }
240
dbfb31a4
AR
241 if (regno != -1)
242 *off = off_adjust + (regno - regno_base) * regsize;
243 else
244 *off = 0;
245 return regsize;
1b883d35
KW
246 }
247 return -1;
248}
249
250static int
468e3d51 251i386nto_regset_fill (const struct regcache *regcache, int regset, char *data)
1b883d35
KW
252{
253 if (regset == NTO_REG_GENERAL)
254 {
255 int regno;
256
257 for (regno = 0; regno < NUM_GPREGS; regno++)
258 {
259 int offset = nto_reg_offset (regno);
260 if (offset != -1)
468e3d51 261 regcache_raw_collect (regcache, regno, data + offset);
1b883d35
KW
262 }
263 }
264 else if (regset == NTO_REG_FLOAT)
265 {
266 if (nto_cpuinfo_valid && nto_cpuinfo_flags | X86_CPU_FXSR)
468e3d51 267 i387_collect_fxsave (regcache, -1, data);
1b883d35 268 else
468e3d51 269 i387_collect_fsave (regcache, -1, data);
1b883d35
KW
270 }
271 else
272 return -1;
273
274 return 0;
275}
276
10458914
DJ
277/* Return whether THIS_FRAME corresponds to a QNX Neutrino sigtramp
278 routine. */
911bc6ee 279
1b883d35 280static int
10458914 281i386nto_sigtramp_p (struct frame_info *this_frame)
1b883d35 282{
10458914 283 CORE_ADDR pc = get_frame_pc (this_frame);
911bc6ee
MK
284 char *name;
285
286 find_pc_partial_function (pc, &name, NULL, NULL);
1b883d35
KW
287 return name && strcmp ("__signalstub", name) == 0;
288}
289
10458914
DJ
290/* Assuming THIS_FRAME is a QNX Neutrino sigtramp routine, return the
291 address of the associated sigcontext structure. */
acd5c798 292
1b883d35 293static CORE_ADDR
10458914 294i386nto_sigcontext_addr (struct frame_info *this_frame)
1b883d35 295{
e17a4113
UW
296 struct gdbarch *gdbarch = get_frame_arch (this_frame);
297 enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
acd5c798 298 char buf[4];
19a934d8 299 CORE_ADDR ptrctx;
acd5c798 300
19a934d8
AR
301 /* We store __ucontext_t addr in EDI register. */
302 get_frame_register (this_frame, I386_EDI_REGNUM, buf);
e17a4113 303 ptrctx = extract_unsigned_integer (buf, 4, byte_order);
19a934d8 304 ptrctx += 24 /* Context pointer is at this offset. */;
1b883d35 305
19a934d8 306 return ptrctx;
1b883d35
KW
307}
308
309static void
47979a4b 310init_i386nto_ops (void)
1b883d35 311{
80b1849c
AR
312 nto_regset_id = i386nto_regset_id;
313 nto_supply_gregset = i386nto_supply_gregset;
314 nto_supply_fpregset = i386nto_supply_fpregset;
315 nto_supply_altregset = nto_dummy_supply_regset;
316 nto_supply_regset = i386nto_supply_regset;
317 nto_register_area = i386nto_register_area;
318 nto_regset_fill = i386nto_regset_fill;
319 nto_fetch_link_map_offsets =
17ca283a 320 svr4_ilp32_fetch_link_map_offsets;
1b883d35
KW
321}
322
323static void
324i386nto_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
325{
326 struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
59215afb 327 static struct target_so_ops nto_svr4_so_ops;
1b883d35 328
d737fd7f
KW
329 /* Deal with our strange signals. */
330 nto_initialize_signals ();
331
1b883d35
KW
332 /* NTO uses ELF. */
333 i386_elf_init_abi (info, gdbarch);
334
71bd6bd4 335 /* Neutrino rewinds to look more normal. Need to override the i386
d3efc286 336 default which is [unfortunately] to decrement the PC. */
1b883d35
KW
337 set_gdbarch_decr_pc_after_break (gdbarch, 0);
338
3d171c85
MK
339 tdep->gregset_reg_offset = i386nto_gregset_reg_offset;
340 tdep->gregset_num_regs = ARRAY_SIZE (i386nto_gregset_reg_offset);
341 tdep->sizeof_gregset = NUM_GPREGS * 4;
342
911bc6ee 343 tdep->sigtramp_p = i386nto_sigtramp_p;
1b883d35 344 tdep->sigcontext_addr = i386nto_sigcontext_addr;
19a934d8
AR
345 tdep->sc_reg_offset = i386nto_gregset_reg_offset;
346 tdep->sc_num_regs = ARRAY_SIZE (i386nto_gregset_reg_offset);
1b883d35
KW
347
348 /* Setjmp()'s return PC saved in EDX (5). */
349 tdep->jb_pc_offset = 20; /* 5x32 bit ints in. */
350
17ca283a
MK
351 set_solib_svr4_fetch_link_map_offsets
352 (gdbarch, svr4_ilp32_fetch_link_map_offsets);
1b883d35 353
59215afb
UW
354 /* Initialize this lazily, to avoid an initialization order
355 dependency on solib-svr4.c's _initialize routine. */
356 if (nto_svr4_so_ops.in_dynsym_resolve_code == NULL)
357 {
358 nto_svr4_so_ops = svr4_so_ops;
359
360 /* Our loader handles solib relocations differently than svr4. */
361 nto_svr4_so_ops.relocate_section_addresses
362 = nto_relocate_section_addresses;
1b883d35 363
59215afb
UW
364 /* Supply a nice function to find our solibs. */
365 nto_svr4_so_ops.find_and_open_solib
366 = nto_find_and_open_solib;
1b883d35 367
59215afb
UW
368 /* Our linker code is in libc. */
369 nto_svr4_so_ops.in_dynsym_resolve_code
370 = nto_in_dynsym_resolve_code;
371 }
372 set_solib_ops (gdbarch, &nto_svr4_so_ops);
1b883d35
KW
373}
374
63807e1d
PA
375/* Provide a prototype to silence -Wmissing-prototypes. */
376extern initialize_file_ftype _initialize_i386nto_tdep;
377
1b883d35
KW
378void
379_initialize_i386nto_tdep (void)
380{
d737fd7f 381 init_i386nto_ops ();
1b883d35
KW
382 gdbarch_register_osabi (bfd_arch_i386, 0, GDB_OSABI_QNXNTO,
383 i386nto_init_abi);
d737fd7f
KW
384 gdbarch_register_osabi_sniffer (bfd_arch_i386, bfd_target_elf_flavour,
385 nto_elf_osabi_sniffer);
1b883d35 386}