i386-nbsd-tdep.c revision 1.1.1.1
1/* Target-dependent code for NetBSD/i386. 2 3 Copyright (C) 1988-2017 Free Software Foundation, Inc. 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 3 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, see <http://www.gnu.org/licenses/>. */ 19 20#include "defs.h" 21#include "arch-utils.h" 22#include "frame.h" 23#include "gdbcore.h" 24#include "regcache.h" 25#include "regset.h" 26#include "osabi.h" 27#include "symtab.h" 28#include "trad-frame.h" 29#include "tramp-frame.h" 30 31#include "i386-tdep.h" 32#include "i387-tdep.h" 33#include "nbsd-tdep.h" 34#include "solib-svr4.h" 35 36#include "elf-bfd.h" /* for header hack */ 37#include "trad-frame.h" /* signal trampoline/kernel frame support */ 38#include "frame-unwind.h" /* kernel frame support */ 39#include "tramp-frame.h" /* signal trampoline/kernel frame support */ 40 41/* From <machine/reg.h>. */ 42static int i386nbsd_r_reg_offset[] = 43{ 44 0 * 4, /* %eax */ 45 1 * 4, /* %ecx */ 46 2 * 4, /* %edx */ 47 3 * 4, /* %ebx */ 48 4 * 4, /* %esp */ 49 5 * 4, /* %ebp */ 50 6 * 4, /* %esi */ 51 7 * 4, /* %edi */ 52 8 * 4, /* %eip */ 53 9 * 4, /* %eflags */ 54 10 * 4, /* %cs */ 55 11 * 4, /* %ss */ 56 12 * 4, /* %ds */ 57 13 * 4, /* %es */ 58 14 * 4, /* %fs */ 59 15 * 4 /* %gs */ 60}; 61 62/* From <machine/signal.h>. */ 63int i386nbsd_sc_reg_offset[] = 64{ 65 10 * 4, /* %eax */ 66 9 * 4, /* %ecx */ 67 8 * 4, /* %edx */ 68 7 * 4, /* %ebx */ 69 14 * 4, /* %esp */ 70 6 * 4, /* %ebp */ 71 5 * 4, /* %esi */ 72 4 * 4, /* %edi */ 73 11 * 4, /* %eip */ 74 13 * 4, /* %eflags */ 75 12 * 4, /* %cs */ 76 15 * 4, /* %ss */ 77 3 * 4, /* %ds */ 78 2 * 4, /* %es */ 79 1 * 4, /* %fs */ 80 0 * 4 /* %gs */ 81}; 82 83/* From <machine/mcontext.h>. */ 84int i386nbsd_mc_reg_offset[] = 85{ 86 11 * 4, /* %eax */ 87 10 * 4, /* %ecx */ 88 9 * 4, /* %edx */ 89 8 * 4, /* %ebx */ 90 7 * 4, /* %esp */ 91 6 * 4, /* %ebp */ 92 5 * 4, /* %esi */ 93 4 * 4, /* %edi */ 94 14 * 4, /* %eip */ 95 16 * 4, /* %eflags */ 96 15 * 4, /* %cs */ 97 18 * 4, /* %ss */ 98 3 * 4, /* %ds */ 99 2 * 4, /* %es */ 100 1 * 4, /* %fs */ 101 0 * 4 /* %gs */ 102}; 103 104static void i386nbsd_sigtramp_cache_init (const struct tramp_frame *, 105 struct frame_info *, 106 struct trad_frame_cache *, 107 CORE_ADDR); 108 109static const struct tramp_frame i386nbsd_sigtramp_sc16 = 110{ 111 SIGTRAMP_FRAME, 112 1, 113 { 114 { 0x8d, -1 }, { 0x44, -1 }, { 0x24, -1 }, { 0x10, -1 }, 115 /* leal 0x10(%esp), %eax */ 116 { 0x50, -1 }, /* pushl %eax */ 117 { 0x50, -1 }, /* pushl %eax */ 118 { 0xb8, -1 }, { 0x27, -1 }, {0x01, -1 }, {0x00, -1 }, {0x00, -1 }, 119 /* movl $0x127, %eax # __sigreturn14 */ 120 { 0xcd, -1 }, { 0x80, -1}, 121 /* int $0x80 */ 122 { 0xb8, -1 }, { 0x01, -1 }, {0x00, -1 }, {0x00, -1 }, {0x00, -1 }, 123 /* movl $0x1, %eax # exit */ 124 { 0xcd, -1 }, { 0x80, -1}, 125 /* int $0x80 */ 126 { TRAMP_SENTINEL_INSN, -1 } 127 }, 128 i386nbsd_sigtramp_cache_init 129}; 130 131static const struct tramp_frame i386nbsd_sigtramp_sc2 = 132{ 133 SIGTRAMP_FRAME, 134 1, 135 { 136 { 0x8d, -1 }, { 0x44, -1 }, { 0x24, -1 }, { 0x0c, -1 }, 137 /* leal 0x0c(%esp), %eax */ 138 { 0x89, -1 }, { 0x44, -1 }, { 0x24, -1 }, { 0x04, -1 }, 139 /* movl %eax, 0x4(%esp) */ 140 { 0xb8, -1 }, { 0x27, -1 }, {0x01, -1 }, {0x00, -1 }, {0x00, -1 }, 141 /* movl $0x127, %eax # __sigreturn14 */ 142 { 0xcd, -1 }, { 0x80, -1}, 143 /* int $0x80 */ 144 { 0x89, -1 }, { 0x44, -1 }, { 0x24, -1 }, { 0x04, -1 }, 145 /* movl %eax, 0x4(%esp) */ 146 { 0xb8, -1 }, { 0x01, -1 }, {0x00, -1 }, {0x00, -1 }, {0x00, -1 }, 147 /* movl $0x1, %eax */ 148 { 0xcd, -1 }, { 0x80, -1}, 149 /* int $0x80 */ 150 { TRAMP_SENTINEL_INSN, -1 } 151 }, 152 i386nbsd_sigtramp_cache_init 153}; 154 155static const struct tramp_frame i386nbsd_sigtramp_si2 = 156{ 157 SIGTRAMP_FRAME, 158 1, 159 { 160 { 0x8b, -1 }, { 0x44, -1 }, { 0x24, -1 }, { 0x08, -1 }, 161 /* movl 8(%esp),%eax */ 162 { 0x89, -1 }, { 0x44, -1 }, { 0x24, -1 }, { 0x04, -1 }, 163 /* movl %eax, 0x4(%esp) */ 164 { 0xb8, -1 }, { 0x34, -1 }, { 0x01, -1 }, { 0x00, -1 }, { 0x00, -1 }, 165 /* movl $0x134, %eax # setcontext */ 166 { 0xcd, -1 }, { 0x80, -1 }, 167 /* int $0x80 */ 168 { 0x89, -1 }, { 0x44, -1 }, { 0x24, -1 }, { 0x04, -1 }, 169 /* movl %eax, 0x4(%esp) */ 170 { 0xb8, -1 }, { 0x01, -1 }, { 0x00, -1 }, { 0x00, -1 }, { 0x00, -1 }, 171 /* movl $0x1, %eax */ 172 { 0xcd, -1 }, { 0x80, -1 }, 173 /* int $0x80 */ 174 { TRAMP_SENTINEL_INSN, -1 } 175 }, 176 i386nbsd_sigtramp_cache_init 177}; 178 179static const struct tramp_frame i386nbsd_sigtramp_si31 = 180{ 181 SIGTRAMP_FRAME, 182 1, 183 { 184 { 0x8d, -1 }, { 0x84, -1 }, { 0x24, -1 }, 185 { 0x8c, -1 }, { 0x00, -1 }, { 0x00, -1 }, { 0x00, -1 }, 186 /* leal 0x8c(%esp), %eax */ 187 { 0x89, -1 }, { 0x44, -1 }, { 0x24, -1 }, { 0x04, -1 }, 188 /* movl %eax, 0x4(%esp) */ 189 { 0xb8, -1 }, { 0x34, -1 }, { 0x01, -1 }, { 0x00, -1 }, { 0x00, -1 }, 190 /* movl $0x134, %eax # setcontext */ 191 { 0xcd, -1 }, { 0x80, -1}, 192 /* int $0x80 */ 193 { 0x89, -1 }, { 0x44, -1 }, { 0x24, -1 }, { 0x04, -1 }, 194 /* movl %eax, 0x4(%esp) */ 195 { 0xb8, -1 }, { 0x01, -1 }, {0x00, -1 }, {0x00, -1 }, {0x00, -1 }, 196 /* movl $0x1, %eax */ 197 { 0xcd, -1 }, { 0x80, -1}, 198 /* int $0x80 */ 199 { TRAMP_SENTINEL_INSN, -1 } 200 }, 201 i386nbsd_sigtramp_cache_init 202}; 203 204static const struct tramp_frame i386nbsd_sigtramp_si4 = 205{ 206 SIGTRAMP_FRAME, 207 1, 208 { 209 { 0x8d, -1 }, { 0x84, -1 }, { 0x24, -1 }, 210 { 0x8c, -1 }, { 0x00, -1 }, { 0x00, -1 }, { 0x00, -1 }, 211 /* leal 0x8c(%esp), %eax */ 212 { 0x89, -1 }, { 0x44, -1 }, { 0x24, -1 }, { 0x04, -1 }, 213 /* movl %eax, 0x4(%esp) */ 214 { 0xb8, -1 }, { 0x34, -1 }, { 0x01, -1 }, { 0x00, -1 }, { 0x00, -1 }, 215 /* movl $0x134, %eax # setcontext */ 216 { 0xcd, -1 }, { 0x80, -1}, 217 /* int $0x80 */ 218 { 0xc7, -1 }, { 0x44, -1 }, { 0x24, -1 }, { 0x04, -1 }, 219 { 0xff, -1 }, { 0xff, -1 }, { 0xff, -1 }, { 0xff, -1 }, 220 /* movl $0xffffffff,0x4(%esp) */ 221 { 0xb8, -1 }, { 0x01, -1 }, {0x00, -1 }, {0x00, -1 }, {0x00, -1 }, 222 /* movl $0x1, %eax */ 223 { 0xcd, -1 }, { 0x80, -1}, 224 /* int $0x80 */ 225 { TRAMP_SENTINEL_INSN, -1 } 226 }, 227 i386nbsd_sigtramp_cache_init 228}; 229 230static void 231i386nbsd_sigtramp_cache_init (const struct tramp_frame *self, 232 struct frame_info *this_frame, 233 struct trad_frame_cache *this_cache, 234 CORE_ADDR func) 235{ 236 struct gdbarch *gdbarch = get_frame_arch (this_frame); 237 enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); 238 CORE_ADDR sp = get_frame_register_unsigned (this_frame, I386_ESP_REGNUM); 239 CORE_ADDR base; 240 int *reg_offset; 241 int num_regs; 242 int i; 243 244 if (self == &i386nbsd_sigtramp_sc16 || self == &i386nbsd_sigtramp_sc2) 245 { 246 reg_offset = i386nbsd_sc_reg_offset; 247 num_regs = ARRAY_SIZE (i386nbsd_sc_reg_offset); 248 249 /* Read in the sigcontext address. */ 250 base = read_memory_unsigned_integer (sp + 8, 4, byte_order); 251 } 252 else 253 { 254 reg_offset = i386nbsd_mc_reg_offset; 255 num_regs = ARRAY_SIZE (i386nbsd_mc_reg_offset); 256 257 /* Read in the ucontext address. */ 258 base = read_memory_unsigned_integer (sp + 8, 4, byte_order); 259 /* offsetof(ucontext_t, uc_mcontext) == 36 */ 260 base += 36; 261 } 262 263 for (i = 0; i < num_regs; i++) 264 if (reg_offset[i] != -1) 265 trad_frame_set_reg_addr (this_cache, i, base + reg_offset[i]); 266 267 /* Construct the frame ID using the function start. */ 268 trad_frame_set_id (this_cache, frame_id_build (sp, func)); 269} 270 271 272/* From <machine/frame.h>. Note that %esp and %ess are only saved in 273 a trap frame when entering the kernel from user space. */ 274static int i386nbsd_tf_reg_offset[] = 275{ 276 10 * 4, /* %eax */ 277 9 * 4, /* %ecx */ 278 8 * 4, /* %edx */ 279 7 * 4, /* %ebx */ 280 -1, /* %esp */ 281 6 * 4, /* %ebp */ 282 5 * 4, /* %esi */ 283 4 * 4, /* %edi */ 284 13 * 4, /* %eip */ 285 15 * 4, /* %eflags */ 286 14 * 4, /* %cs */ 287 -1, /* %ss */ 288 3 * 4, /* %ds */ 289 2 * 4, /* %es */ 290 1 * 4, /* %fs */ 291 0 * 4 /* %gs */ 292}; 293 294static struct trad_frame_cache * 295i386nbsd_trapframe_cache(struct frame_info *this_frame, void **this_cache) 296{ 297 struct trad_frame_cache *cache; 298 CORE_ADDR func, sp, addr, tmp; 299 ULONGEST cs; 300 const char *name; 301 int i; 302 struct gdbarch *gdbarch = get_frame_arch (this_frame); 303 enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); 304 305 if (*this_cache) 306 return (struct trad_frame_cache *)*this_cache; 307 308 cache = trad_frame_cache_zalloc (this_frame); 309 *this_cache = cache; 310 311 func = get_frame_func (this_frame); 312 sp = get_frame_register_unsigned (this_frame, I386_ESP_REGNUM); 313 314 find_pc_partial_function (func, &name, NULL, NULL); 315 if (name && (strncmp (name, "Xintr", 5) == 0 || 316 strncmp (name, "Xhandle", 7) == 0)) 317 { 318 /* It's an interrupt frame. */ 319 tmp = read_memory_unsigned_integer (sp + 4, 4, byte_order); 320 if (tmp < 15) 321 { 322 /* Reasonable value for 'ppl': already on interrupt stack. */ 323 addr = sp + 8; 324 } 325 else 326 { 327 /* Switch to previous stack. */ 328 addr = tmp + 4; 329 } 330 } 331 else 332 { 333 /* It's a trap frame. */ 334 addr = sp + 4; 335 } 336 337 for (i = 0; i < ARRAY_SIZE (i386nbsd_tf_reg_offset); i++) 338 if (i386nbsd_tf_reg_offset[i] != -1) 339 trad_frame_set_reg_addr (cache, i, addr + i386nbsd_tf_reg_offset[i]); 340 341 /* Read %cs from trap frame. */ 342 addr += i386nbsd_tf_reg_offset[I386_CS_REGNUM]; 343 cs = read_memory_unsigned_integer (addr, 4, byte_order); 344 if ((cs & I386_SEL_RPL) == I386_SEL_UPL) 345 { 346 /* Trap from user space; terminate backtrace. */ 347 trad_frame_set_id (cache, outer_frame_id); 348 } 349 else 350 { 351 /* Construct the frame ID using the function start. */ 352 trad_frame_set_id (cache, frame_id_build (sp + 8, func)); 353 } 354 355 return cache; 356} 357 358static void 359i386nbsd_trapframe_this_id (struct frame_info *this_frame, 360 void **this_cache, struct frame_id *this_id) 361{ 362 struct trad_frame_cache *cache = 363 i386nbsd_trapframe_cache (this_frame, this_cache); 364 365 trad_frame_get_id (cache, this_id); 366} 367 368static struct value * 369i386nbsd_trapframe_prev_register (struct frame_info *this_frame, 370 void **this_cache, int regnum) 371{ 372 struct trad_frame_cache *cache = 373 i386nbsd_trapframe_cache (this_frame, this_cache); 374 375 return trad_frame_get_register (cache, this_frame, regnum); 376} 377 378static int 379i386nbsd_trapframe_sniffer (const struct frame_unwind *self, 380 struct frame_info *this_frame, 381 void **this_prologue_cache) 382{ 383 ULONGEST cs; 384 const char *name; 385 386 /* Check Current Privilege Level and bail out if we're not executing 387 in kernel space. */ 388 cs = get_frame_register_unsigned (this_frame, I386_CS_REGNUM); 389 if ((cs & I386_SEL_RPL) == I386_SEL_UPL) 390 return 0; 391 392 393 find_pc_partial_function (get_frame_pc (this_frame), &name, NULL, NULL); 394 return (name && ((strcmp (name, "alltraps") == 0) 395 || (strcmp (name, "calltrap") == 0) 396 || (strcmp (name, "syscall1") == 0) 397 || (strcmp (name, "Xdoreti") == 0) 398 || (strncmp (name, "Xintr", 5) == 0) 399 || (strncmp (name, "Xhandle", 7) == 0) 400 || (strncmp (name, "Xpreempt", 8) == 0) 401 || (strncmp (name, "Xrecurse", 8) == 0) 402 || (strncmp (name, "Xresume", 7) == 0) 403 || (strncmp (name, "Xsoft", 5) == 0) 404 || (strncmp (name, "Xstray", 6) == 0) 405 || (strncmp (name, "Xsyscall", 8) == 0) 406 || (strncmp (name, "Xtrap", 5) == 0) 407 )); 408} 409 410const struct frame_unwind i386nbsd_trapframe_unwind = { 411 /* FIXME: kettenis/20051219: This really is more like an interrupt 412 frame, but SIGTRAMP_FRAME would print <signal handler called>, 413 which really is not what we want here. */ 414 NORMAL_FRAME, 415 default_frame_unwind_stop_reason, 416 i386nbsd_trapframe_this_id, 417 i386nbsd_trapframe_prev_register, 418 NULL, 419 i386nbsd_trapframe_sniffer 420}; 421 422static void 423i386nbsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) 424{ 425 struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); 426 427 /* Obviously NetBSD is BSD-based. */ 428 i386bsd_init_abi (info, gdbarch); 429 430 /* NetBSD has a different `struct reg'. */ 431 tdep->gregset_reg_offset = i386nbsd_r_reg_offset; 432 tdep->gregset_num_regs = ARRAY_SIZE (i386nbsd_r_reg_offset); 433 tdep->sizeof_gregset = 16 * 4; 434 435 /* NetBSD uses -freg-struct-return by default. */ 436 tdep->struct_return = reg_struct_return; 437 438 /* NetBSD uses tramp_frame sniffers for signal trampolines. */ 439 tdep->sigcontext_addr= 0; 440 tdep->sigtramp_start = 0; 441 tdep->sigtramp_end = 0; 442 tdep->sigtramp_p = 0; 443 tdep->sc_reg_offset = 0; 444 tdep->sc_num_regs = 0; 445 446 tramp_frame_prepend_unwinder (gdbarch, &i386nbsd_sigtramp_sc16); 447 tramp_frame_prepend_unwinder (gdbarch, &i386nbsd_sigtramp_sc2); 448 tramp_frame_prepend_unwinder (gdbarch, &i386nbsd_sigtramp_si2); 449 tramp_frame_prepend_unwinder (gdbarch, &i386nbsd_sigtramp_si31); 450 tramp_frame_prepend_unwinder (gdbarch, &i386nbsd_sigtramp_si4); 451 452 /* Unwind kernel trap frames correctly. */ 453 frame_unwind_prepend_unwinder (gdbarch, &i386nbsd_trapframe_unwind); 454} 455 456/* NetBSD ELF. */ 457 458static void 459i386nbsdelf_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) 460{ 461 struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); 462 463 /* It's still NetBSD. */ 464 i386nbsd_init_abi (info, gdbarch); 465 466 /* But ELF-based. */ 467 i386_elf_init_abi (info, gdbarch); 468 469 /* NetBSD ELF uses SVR4-style shared libraries. */ 470 set_solib_svr4_fetch_link_map_offsets 471 (gdbarch, svr4_ilp32_fetch_link_map_offsets); 472 473 /* NetBSD ELF uses -fpcc-struct-return by default. */ 474 tdep->struct_return = pcc_struct_return; 475} 476 477/* Provide a prototype to silence -Wmissing-prototypes. */ 478extern initialize_file_ftype _initialize_i386nbsd_tdep; 479 480 481void 482_initialize_i386nbsd_tdep (void) 483{ 484 gdbarch_register_osabi (bfd_arch_i386, 0, GDB_OSABI_NETBSD, 485 i386nbsdelf_init_abi); 486} 487