1/* i386-nto-tdep.c - i386 specific functionality for QNX Neutrino. 2 3 Copyright 2003 Free Software Foundation, Inc. 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 11 the Free Software Foundation; either version 2 of the License, or 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 20 along with this program; if not, write to the Free Software 21 Foundation, Inc., 59 Temple Place - Suite 330, 22 Boston, MA 02111-1307, USA. */ 23 24#include "gdb_string.h" 25#include "gdb_assert.h" 26#include "defs.h" 27#include "frame.h" 28#include "target.h" 29#include "regcache.h" 30#include "solib-svr4.h" 31#include "i386-tdep.h" 32#include "nto-tdep.h" 33#include "osabi.h" 34#include "i387-tdep.h" 35 36#ifndef X86_CPU_FXSR 37#define X86_CPU_FXSR (1L << 12) 38#endif 39 40/* Why 13? Look in our /usr/include/x86/context.h header at the 41 x86_cpu_registers structure and you'll see an 'exx' junk register 42 that is just filler. Don't ask me, ask the kernel guys. */ 43#define NUM_GPREGS 13 44 45/* Map a GDB register number to an offset in the reg structure. */ 46static int regmap[] = { 47 (7 * 4), /* eax */ 48 (6 * 4), /* ecx */ 49 (5 * 4), /* edx */ 50 (4 * 4), /* ebx */ 51 (11 * 4), /* esp */ 52 (2 * 4), /* epb */ 53 (1 * 4), /* esi */ 54 (0 * 4), /* edi */ 55 (8 * 4), /* eip */ 56 (10 * 4), /* eflags */ 57 (9 * 4), /* cs */ 58 (12 * 4), /* ss */ 59 (-1 * 4) /* filler */ 60}; 61 62/* Given a gdb regno, return the offset into Neutrino's register structure 63 or -1 if register is unknown. */ 64static int 65nto_reg_offset (int regno) 66{ 67 return (regno >= 0 && regno < NUM_GPREGS) ? regmap[regno] : -1; 68} 69 70static void 71i386nto_supply_gregset (char *gpregs) 72{ 73 unsigned regno; 74 int empty = 0; 75 76 for (regno = 0; regno < FP0_REGNUM; regno++) 77 { 78 int offset = nto_reg_offset (regno); 79 if (offset == -1) 80 supply_register (regno, (char *) &empty); 81 else 82 supply_register (regno, gpregs + offset); 83 } 84} 85 86static void 87i386nto_supply_fpregset (char *fpregs) 88{ 89 if (nto_cpuinfo_valid && nto_cpuinfo_flags | X86_CPU_FXSR) 90 i387_supply_fxsave (current_regcache, -1, fpregs); 91 else 92 i387_supply_fsave (current_regcache, -1, fpregs); 93} 94 95static void 96i386nto_supply_regset (int regset, char *data) 97{ 98 switch (regset) 99 { 100 case NTO_REG_GENERAL: /* QNX has different ordering of GP regs than GDB. */ 101 i386nto_supply_gregset (data); 102 break; 103 case NTO_REG_FLOAT: 104 i386nto_supply_fpregset (data); 105 break; 106 } 107} 108 109static int 110i386nto_regset_id (int regno) 111{ 112 if (regno == -1) 113 return NTO_REG_END; 114 else if (regno < FP0_REGNUM) 115 return NTO_REG_GENERAL; 116 else if (regno < FPC_REGNUM) 117 return NTO_REG_FLOAT; 118 119 return -1; /* Error. */ 120} 121 122static int 123i386nto_register_area (int regno, int regset, unsigned *off) 124{ 125 int len; 126 127 *off = 0; 128 if (regset == NTO_REG_GENERAL) 129 { 130 if (regno == -1) 131 return NUM_GPREGS * 4; 132 133 *off = nto_reg_offset (regno); 134 if (*off == -1) 135 return 0; 136 return 4; 137 } 138 else if (regset == NTO_REG_FLOAT) 139 { 140 unsigned off_adjust, regsize, regset_size; 141 142 if (nto_cpuinfo_valid && nto_cpuinfo_flags | X86_CPU_FXSR) 143 { 144 off_adjust = 32; 145 regsize = 16; 146 regset_size = 512; 147 } 148 else 149 { 150 off_adjust = 28; 151 regsize = 10; 152 regset_size = 128; 153 } 154 155 if (regno == -1) 156 return regset_size; 157 158 *off = (regno - FP0_REGNUM) * regsize + off_adjust; 159 return 10; 160 /* Why 10 instead of regsize? GDB only stores 10 bytes per FP 161 register so if we're sending a register back to the target, 162 we only want pdebug to write 10 bytes so as not to clobber 163 the reserved 6 bytes in the fxsave structure. */ 164 } 165 return -1; 166} 167 168static int 169i386nto_regset_fill (int regset, char *data) 170{ 171 if (regset == NTO_REG_GENERAL) 172 { 173 int regno; 174 175 for (regno = 0; regno < NUM_GPREGS; regno++) 176 { 177 int offset = nto_reg_offset (regno); 178 if (offset != -1) 179 regcache_collect (regno, data + offset); 180 } 181 } 182 else if (regset == NTO_REG_FLOAT) 183 { 184 if (nto_cpuinfo_valid && nto_cpuinfo_flags | X86_CPU_FXSR) 185 i387_fill_fxsave (data, -1); 186 else 187 i387_fill_fsave (data, -1); 188 } 189 else 190 return -1; 191 192 return 0; 193} 194 195static struct link_map_offsets * 196i386nto_svr4_fetch_link_map_offsets (void) 197{ 198 static struct link_map_offsets lmo; 199 static struct link_map_offsets *lmp = NULL; 200 201 if (lmp == NULL) 202 { 203 lmp = &lmo; 204 205 lmo.r_debug_size = 8; /* The actual size is 20 bytes, but 206 only 8 bytes are used. */ 207 lmo.r_map_offset = 4; 208 lmo.r_map_size = 4; 209 210 lmo.link_map_size = 20; /* The actual size is 552 bytes, but 211 only 20 bytes are used. */ 212 lmo.l_addr_offset = 0; 213 lmo.l_addr_size = 4; 214 215 lmo.l_name_offset = 4; 216 lmo.l_name_size = 4; 217 218 lmo.l_next_offset = 12; 219 lmo.l_next_size = 4; 220 221 lmo.l_prev_offset = 16; 222 lmo.l_prev_size = 4; 223 } 224 225 return lmp; 226} 227 228static int 229i386nto_pc_in_sigtramp (CORE_ADDR pc, char *name) 230{ 231 return name && strcmp ("__signalstub", name) == 0; 232} 233 234#define I386_NTO_SIGCONTEXT_OFFSET 136 235 236/* Assuming NEXT_FRAME is a frame following a QNX Neutrino sigtramp 237 routine, return the address of the associated sigcontext structure. */ 238 239static CORE_ADDR 240i386nto_sigcontext_addr (struct frame_info *next_frame) 241{ 242 char buf[4]; 243 CORE_ADDR sp; 244 245 frame_unwind_register (next_frame, SP_REGNUM, buf); 246 sp = extract_unsigned_integer (buf, 4); 247 248 return sp + I386_NTO_SIGCONTEXT_OFFSET; 249} 250 251static void 252init_i386nto_ops (void) 253{ 254 current_nto_target.nto_regset_id = i386nto_regset_id; 255 current_nto_target.nto_supply_gregset = i386nto_supply_gregset; 256 current_nto_target.nto_supply_fpregset = i386nto_supply_fpregset; 257 current_nto_target.nto_supply_altregset = nto_dummy_supply_regset; 258 current_nto_target.nto_supply_regset = i386nto_supply_regset; 259 current_nto_target.nto_register_area = i386nto_register_area; 260 current_nto_target.nto_regset_fill = i386nto_regset_fill; 261 current_nto_target.nto_fetch_link_map_offsets = 262 i386nto_svr4_fetch_link_map_offsets; 263} 264 265static void 266i386nto_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) 267{ 268 struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); 269 270 /* NTO uses ELF. */ 271 i386_elf_init_abi (info, gdbarch); 272 273 /* Neutrino rewinds to look more normal. Need to override the i386 274 default which is [unfortunately] to decrement the PC. */ 275 set_gdbarch_decr_pc_after_break (gdbarch, 0); 276 277 /* NTO has shared libraries. */ 278 set_gdbarch_in_solib_call_trampoline (gdbarch, in_plt_section); 279 set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target); 280 281 set_gdbarch_pc_in_sigtramp (gdbarch, i386nto_pc_in_sigtramp); 282 tdep->sigcontext_addr = i386nto_sigcontext_addr; 283 tdep->sc_pc_offset = 56; 284 tdep->sc_sp_offset = 68; 285 286 /* Setjmp()'s return PC saved in EDX (5). */ 287 tdep->jb_pc_offset = 20; /* 5x32 bit ints in. */ 288 289 set_solib_svr4_fetch_link_map_offsets (gdbarch, 290 i386nto_svr4_fetch_link_map_offsets); 291 292 /* Our loader handles solib relocations slightly differently than svr4. */ 293 TARGET_SO_RELOCATE_SECTION_ADDRESSES = nto_relocate_section_addresses; 294 295 /* Supply a nice function to find our solibs. */ 296 TARGET_SO_FIND_AND_OPEN_SOLIB = nto_find_and_open_solib; 297 298 init_i386nto_ops (); 299} 300 301void 302_initialize_i386nto_tdep (void) 303{ 304 gdbarch_register_osabi (bfd_arch_i386, 0, GDB_OSABI_QNXNTO, 305 i386nto_init_abi); 306} 307