i386-nbsd-tdep.c revision 1.1.1.2
1/* Target-dependent code for NetBSD/i386. 2 3 Copyright (C) 1988-2019 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 /* leal 0x10(%esp), %eax */ 115 { 0x8d, ULONGEST_MAX }, 116 { 0x44, ULONGEST_MAX }, 117 { 0x24, ULONGEST_MAX }, 118 { 0x10, ULONGEST_MAX }, 119 120 /* pushl %eax */ 121 { 0x50, ULONGEST_MAX }, 122 123 /* pushl %eax */ 124 { 0x50, ULONGEST_MAX }, 125 126 /* movl $0x127, %eax # __sigreturn14 */ 127 { 0xb8, ULONGEST_MAX }, 128 { 0x27, ULONGEST_MAX }, 129 {0x01, ULONGEST_MAX }, 130 {0x00, ULONGEST_MAX }, 131 {0x00, ULONGEST_MAX }, 132 133 /* int $0x80 */ 134 { 0xcd, ULONGEST_MAX }, 135 { 0x80, ULONGEST_MAX}, 136 137 /* movl $0x1, %eax # exit */ 138 { 0xb8, ULONGEST_MAX }, 139 { 0x01, ULONGEST_MAX }, 140 {0x00, ULONGEST_MAX }, 141 {0x00, ULONGEST_MAX }, 142 {0x00, ULONGEST_MAX }, 143 144 /* int $0x80 */ 145 { 0xcd, ULONGEST_MAX }, 146 { 0x80, ULONGEST_MAX}, 147 148 { TRAMP_SENTINEL_INSN, ULONGEST_MAX } 149 }, 150 i386nbsd_sigtramp_cache_init 151}; 152 153static const struct tramp_frame i386nbsd_sigtramp_sc2 = 154{ 155 SIGTRAMP_FRAME, 156 1, 157 { 158 /* leal 0x0c(%esp), %eax */ 159 { 0x8d, ULONGEST_MAX }, 160 { 0x44, ULONGEST_MAX }, 161 { 0x24, ULONGEST_MAX }, 162 { 0x0c, ULONGEST_MAX }, 163 /* movl %eax, 0x4(%esp) */ 164 { 0x89, ULONGEST_MAX }, 165 { 0x44, ULONGEST_MAX }, 166 { 0x24, ULONGEST_MAX }, 167 { 0x04, ULONGEST_MAX }, 168 /* movl $0x127, %eax # __sigreturn14 */ 169 { 0xb8, ULONGEST_MAX }, 170 { 0x27, ULONGEST_MAX }, 171 {0x01, ULONGEST_MAX }, 172 {0x00, ULONGEST_MAX }, 173 {0x00, ULONGEST_MAX }, 174 /* int $0x80 */ 175 { 0xcd, ULONGEST_MAX }, 176 { 0x80, ULONGEST_MAX}, 177 /* movl %eax, 0x4(%esp) */ 178 { 0x89, ULONGEST_MAX }, 179 { 0x44, ULONGEST_MAX }, 180 { 0x24, ULONGEST_MAX }, 181 { 0x04, ULONGEST_MAX }, 182 /* movl $0x1, %eax */ 183 { 0xb8, ULONGEST_MAX }, 184 { 0x01, ULONGEST_MAX }, 185 {0x00, ULONGEST_MAX }, 186 {0x00, ULONGEST_MAX }, 187 {0x00, ULONGEST_MAX }, 188 /* int $0x80 */ 189 { 0xcd, ULONGEST_MAX }, 190 { 0x80, ULONGEST_MAX}, 191 { TRAMP_SENTINEL_INSN, ULONGEST_MAX } 192 }, 193 i386nbsd_sigtramp_cache_init 194}; 195 196static const struct tramp_frame i386nbsd_sigtramp_si2 = 197{ 198 SIGTRAMP_FRAME, 199 1, 200 { 201 /* movl 8(%esp),%eax */ 202 { 0x8b, ULONGEST_MAX }, 203 { 0x44, ULONGEST_MAX }, 204 { 0x24, ULONGEST_MAX }, 205 { 0x08, ULONGEST_MAX }, 206 /* movl %eax, 0x4(%esp) */ 207 { 0x89, ULONGEST_MAX }, 208 { 0x44, ULONGEST_MAX }, 209 { 0x24, ULONGEST_MAX }, 210 { 0x04, ULONGEST_MAX }, 211 /* movl $0x134, %eax # setcontext */ 212 { 0xb8, ULONGEST_MAX }, 213 { 0x34, ULONGEST_MAX }, 214 { 0x01, ULONGEST_MAX }, 215 { 0x00, ULONGEST_MAX }, 216 { 0x00, ULONGEST_MAX }, 217 /* int $0x80 */ 218 { 0xcd, ULONGEST_MAX }, 219 { 0x80, ULONGEST_MAX }, 220 /* movl %eax, 0x4(%esp) */ 221 { 0x89, ULONGEST_MAX }, 222 { 0x44, ULONGEST_MAX }, 223 { 0x24, ULONGEST_MAX }, 224 { 0x04, ULONGEST_MAX }, 225 /* movl $0x1, %eax */ 226 { 0xb8, ULONGEST_MAX }, 227 { 0x01, ULONGEST_MAX }, 228 { 0x00, ULONGEST_MAX }, 229 { 0x00, ULONGEST_MAX }, 230 { 0x00, ULONGEST_MAX }, 231 /* int $0x80 */ 232 { 0xcd, ULONGEST_MAX }, 233 { 0x80, ULONGEST_MAX }, 234 { TRAMP_SENTINEL_INSN, ULONGEST_MAX } 235 }, 236 i386nbsd_sigtramp_cache_init 237}; 238 239static const struct tramp_frame i386nbsd_sigtramp_si31 = 240{ 241 SIGTRAMP_FRAME, 242 1, 243 { 244 /* leal 0x8c(%esp), %eax */ 245 { 0x8d, ULONGEST_MAX }, 246 { 0x84, ULONGEST_MAX }, 247 { 0x24, ULONGEST_MAX }, 248 { 0x8c, ULONGEST_MAX }, 249 { 0x00, ULONGEST_MAX }, 250 { 0x00, ULONGEST_MAX }, 251 { 0x00, ULONGEST_MAX }, 252 /* movl %eax, 0x4(%esp) */ 253 { 0x89, ULONGEST_MAX }, 254 { 0x44, ULONGEST_MAX }, 255 { 0x24, ULONGEST_MAX }, 256 { 0x04, ULONGEST_MAX }, 257 /* movl $0x134, %eax # setcontext */ 258 { 0xb8, ULONGEST_MAX }, 259 { 0x34, ULONGEST_MAX }, 260 { 0x01, ULONGEST_MAX }, 261 { 0x00, ULONGEST_MAX }, 262 { 0x00, ULONGEST_MAX }, 263 /* int $0x80 */ 264 { 0xcd, ULONGEST_MAX }, 265 { 0x80, ULONGEST_MAX}, 266 /* movl %eax, 0x4(%esp) */ 267 { 0x89, ULONGEST_MAX }, 268 { 0x44, ULONGEST_MAX }, 269 { 0x24, ULONGEST_MAX }, 270 { 0x04, ULONGEST_MAX }, 271 /* movl $0x1, %eax */ 272 { 0xb8, ULONGEST_MAX }, 273 { 0x01, ULONGEST_MAX }, 274 {0x00, ULONGEST_MAX }, 275 {0x00, ULONGEST_MAX }, 276 {0x00, ULONGEST_MAX }, 277 /* int $0x80 */ 278 { 0xcd, ULONGEST_MAX }, 279 { 0x80, ULONGEST_MAX}, 280 { TRAMP_SENTINEL_INSN, ULONGEST_MAX } 281 }, 282 i386nbsd_sigtramp_cache_init 283}; 284 285static const struct tramp_frame i386nbsd_sigtramp_si4 = 286{ 287 SIGTRAMP_FRAME, 288 1, 289 { 290 /* leal 0x8c(%esp), %eax */ 291 { 0x8d, ULONGEST_MAX }, 292 { 0x84, ULONGEST_MAX }, 293 { 0x24, ULONGEST_MAX }, 294 { 0x8c, ULONGEST_MAX }, 295 { 0x00, ULONGEST_MAX }, 296 { 0x00, ULONGEST_MAX }, 297 { 0x00, ULONGEST_MAX }, 298 /* movl %eax, 0x4(%esp) */ 299 { 0x89, ULONGEST_MAX }, 300 { 0x44, ULONGEST_MAX }, 301 { 0x24, ULONGEST_MAX }, 302 { 0x04, ULONGEST_MAX }, 303 /* movl $0x134, %eax # setcontext */ 304 { 0xb8, ULONGEST_MAX }, 305 { 0x34, ULONGEST_MAX }, 306 { 0x01, ULONGEST_MAX }, 307 { 0x00, ULONGEST_MAX }, 308 { 0x00, ULONGEST_MAX }, 309 /* int $0x80 */ 310 { 0xcd, ULONGEST_MAX }, 311 { 0x80, ULONGEST_MAX}, 312 /* movl $0xffffffff,0x4(%esp) */ 313 { 0xc7, ULONGEST_MAX }, 314 { 0x44, ULONGEST_MAX }, 315 { 0x24, ULONGEST_MAX }, 316 { 0x04, ULONGEST_MAX }, 317 { 0xff, ULONGEST_MAX }, 318 { 0xff, ULONGEST_MAX }, 319 { 0xff, ULONGEST_MAX }, 320 { 0xff, ULONGEST_MAX }, 321 /* movl $0x1, %eax */ 322 { 0xb8, ULONGEST_MAX }, 323 { 0x01, ULONGEST_MAX }, 324 {0x00, ULONGEST_MAX }, 325 {0x00, ULONGEST_MAX }, 326 {0x00, ULONGEST_MAX }, 327 /* int $0x80 */ 328 { 0xcd, ULONGEST_MAX }, 329 { 0x80, ULONGEST_MAX}, 330 { TRAMP_SENTINEL_INSN, ULONGEST_MAX } 331 }, 332 i386nbsd_sigtramp_cache_init 333}; 334 335static void 336i386nbsd_sigtramp_cache_init (const struct tramp_frame *self, 337 struct frame_info *this_frame, 338 struct trad_frame_cache *this_cache, 339 CORE_ADDR func) 340{ 341 struct gdbarch *gdbarch = get_frame_arch (this_frame); 342 enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); 343 CORE_ADDR sp = get_frame_register_unsigned (this_frame, I386_ESP_REGNUM); 344 CORE_ADDR base; 345 int *reg_offset; 346 int num_regs; 347 int i; 348 349 if (self == &i386nbsd_sigtramp_sc16 || self == &i386nbsd_sigtramp_sc2) 350 { 351 reg_offset = i386nbsd_sc_reg_offset; 352 num_regs = ARRAY_SIZE (i386nbsd_sc_reg_offset); 353 354 /* Read in the sigcontext address. */ 355 base = read_memory_unsigned_integer (sp + 8, 4, byte_order); 356 } 357 else 358 { 359 reg_offset = i386nbsd_mc_reg_offset; 360 num_regs = ARRAY_SIZE (i386nbsd_mc_reg_offset); 361 362 /* Read in the ucontext address. */ 363 base = read_memory_unsigned_integer (sp + 8, 4, byte_order); 364 /* offsetof(ucontext_t, uc_mcontext) == 36 */ 365 base += 36; 366 } 367 368 for (i = 0; i < num_regs; i++) 369 if (reg_offset[i] != -1) 370 trad_frame_set_reg_addr (this_cache, i, base + reg_offset[i]); 371 372 /* Construct the frame ID using the function start. */ 373 trad_frame_set_id (this_cache, frame_id_build (sp, func)); 374} 375 376 377/* From <machine/frame.h>. Note that %esp and %ess are only saved in 378 a trap frame when entering the kernel from user space. */ 379static int i386nbsd_tf_reg_offset[] = 380{ 381 10 * 4, /* %eax */ 382 9 * 4, /* %ecx */ 383 8 * 4, /* %edx */ 384 7 * 4, /* %ebx */ 385 -1, /* %esp */ 386 6 * 4, /* %ebp */ 387 5 * 4, /* %esi */ 388 4 * 4, /* %edi */ 389 13 * 4, /* %eip */ 390 15 * 4, /* %eflags */ 391 14 * 4, /* %cs */ 392 -1, /* %ss */ 393 3 * 4, /* %ds */ 394 2 * 4, /* %es */ 395 1 * 4, /* %fs */ 396 0 * 4 /* %gs */ 397}; 398 399static struct trad_frame_cache * 400i386nbsd_trapframe_cache(struct frame_info *this_frame, void **this_cache) 401{ 402 struct trad_frame_cache *cache; 403 CORE_ADDR func, sp, addr, tmp; 404 ULONGEST cs; 405 const char *name; 406 int i; 407 struct gdbarch *gdbarch = get_frame_arch (this_frame); 408 enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); 409 410 if (*this_cache) 411 return (struct trad_frame_cache *)*this_cache; 412 413 cache = trad_frame_cache_zalloc (this_frame); 414 *this_cache = cache; 415 416 func = get_frame_func (this_frame); 417 sp = get_frame_register_unsigned (this_frame, I386_ESP_REGNUM); 418 419 find_pc_partial_function (func, &name, NULL, NULL); 420 if (name && (strncmp (name, "Xintr", 5) == 0 || 421 strncmp (name, "Xhandle", 7) == 0)) 422 { 423 /* It's an interrupt frame. */ 424 tmp = read_memory_unsigned_integer (sp + 4, 4, byte_order); 425 if (tmp < 15) 426 { 427 /* Reasonable value for 'ppl': already on interrupt stack. */ 428 addr = sp + 8; 429 } 430 else 431 { 432 /* Switch to previous stack. */ 433 addr = tmp + 4; 434 } 435 } 436 else 437 { 438 /* It's a trap frame. */ 439 addr = sp + 4; 440 } 441 442 for (i = 0; i < ARRAY_SIZE (i386nbsd_tf_reg_offset); i++) 443 if (i386nbsd_tf_reg_offset[i] != -1) 444 trad_frame_set_reg_addr (cache, i, addr + i386nbsd_tf_reg_offset[i]); 445 446 /* Read %cs from trap frame. */ 447 addr += i386nbsd_tf_reg_offset[I386_CS_REGNUM]; 448 cs = read_memory_unsigned_integer (addr, 4, byte_order); 449 if ((cs & I386_SEL_RPL) == I386_SEL_UPL) 450 { 451 /* Trap from user space; terminate backtrace. */ 452 trad_frame_set_id (cache, outer_frame_id); 453 } 454 else 455 { 456 /* Construct the frame ID using the function start. */ 457 trad_frame_set_id (cache, frame_id_build (sp + 8, func)); 458 } 459 460 return cache; 461} 462 463static void 464i386nbsd_trapframe_this_id (struct frame_info *this_frame, 465 void **this_cache, struct frame_id *this_id) 466{ 467 struct trad_frame_cache *cache = 468 i386nbsd_trapframe_cache (this_frame, this_cache); 469 470 trad_frame_get_id (cache, this_id); 471} 472 473static struct value * 474i386nbsd_trapframe_prev_register (struct frame_info *this_frame, 475 void **this_cache, int regnum) 476{ 477 struct trad_frame_cache *cache = 478 i386nbsd_trapframe_cache (this_frame, this_cache); 479 480 return trad_frame_get_register (cache, this_frame, regnum); 481} 482 483static int 484i386nbsd_trapframe_sniffer (const struct frame_unwind *self, 485 struct frame_info *this_frame, 486 void **this_prologue_cache) 487{ 488 ULONGEST cs; 489 const char *name; 490 491 /* Check Current Privilege Level and bail out if we're not executing 492 in kernel space. */ 493 cs = get_frame_register_unsigned (this_frame, I386_CS_REGNUM); 494 if ((cs & I386_SEL_RPL) == I386_SEL_UPL) 495 return 0; 496 497 498 find_pc_partial_function (get_frame_pc (this_frame), &name, NULL, NULL); 499 return (name && ((strcmp (name, "alltraps") == 0) 500 || (strcmp (name, "calltrap") == 0) 501 || (strcmp (name, "syscall1") == 0) 502 || (strcmp (name, "Xdoreti") == 0) 503 || (strncmp (name, "Xintr", 5) == 0) 504 || (strncmp (name, "Xhandle", 7) == 0) 505 || (strncmp (name, "Xpreempt", 8) == 0) 506 || (strncmp (name, "Xrecurse", 8) == 0) 507 || (strncmp (name, "Xresume", 7) == 0) 508 || (strncmp (name, "Xsoft", 5) == 0) 509 || (strncmp (name, "Xstray", 6) == 0) 510 || (strncmp (name, "Xsyscall", 8) == 0) 511 || (strncmp (name, "Xtrap", 5) == 0) 512 )); 513} 514 515const struct frame_unwind i386nbsd_trapframe_unwind = { 516 /* FIXME: kettenis/20051219: This really is more like an interrupt 517 frame, but SIGTRAMP_FRAME would print <signal handler called>, 518 which really is not what we want here. */ 519 NORMAL_FRAME, 520 default_frame_unwind_stop_reason, 521 i386nbsd_trapframe_this_id, 522 i386nbsd_trapframe_prev_register, 523 NULL, 524 i386nbsd_trapframe_sniffer 525}; 526 527static void 528i386nbsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) 529{ 530 struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); 531 532 /* Obviously NetBSD is BSD-based. */ 533 i386bsd_init_abi (info, gdbarch); 534 535 /* NetBSD has a different `struct reg'. */ 536 tdep->gregset_reg_offset = i386nbsd_r_reg_offset; 537 tdep->gregset_num_regs = ARRAY_SIZE (i386nbsd_r_reg_offset); 538 tdep->sizeof_gregset = 16 * 4; 539 540 /* NetBSD uses -freg-struct-return by default. */ 541 tdep->struct_return = reg_struct_return; 542 543 /* NetBSD uses tramp_frame sniffers for signal trampolines. */ 544 tdep->sigcontext_addr= 0; 545 tdep->sigtramp_start = 0; 546 tdep->sigtramp_end = 0; 547 tdep->sigtramp_p = 0; 548 tdep->sc_reg_offset = 0; 549 tdep->sc_num_regs = 0; 550 551 tramp_frame_prepend_unwinder (gdbarch, &i386nbsd_sigtramp_sc16); 552 tramp_frame_prepend_unwinder (gdbarch, &i386nbsd_sigtramp_sc2); 553 tramp_frame_prepend_unwinder (gdbarch, &i386nbsd_sigtramp_si2); 554 tramp_frame_prepend_unwinder (gdbarch, &i386nbsd_sigtramp_si31); 555 tramp_frame_prepend_unwinder (gdbarch, &i386nbsd_sigtramp_si4); 556 557 /* Unwind kernel trap frames correctly. */ 558 frame_unwind_prepend_unwinder (gdbarch, &i386nbsd_trapframe_unwind); 559} 560 561/* NetBSD ELF. */ 562 563static void 564i386nbsdelf_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) 565{ 566 struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); 567 568 /* It's still NetBSD. */ 569 i386nbsd_init_abi (info, gdbarch); 570 571 /* But ELF-based. */ 572 i386_elf_init_abi (info, gdbarch); 573 574 /* NetBSD ELF uses SVR4-style shared libraries. */ 575 set_solib_svr4_fetch_link_map_offsets 576 (gdbarch, svr4_ilp32_fetch_link_map_offsets); 577 578 /* NetBSD ELF uses -fpcc-struct-return by default. */ 579 tdep->struct_return = pcc_struct_return; 580} 581 582void 583_initialize_i386nbsd_tdep (void) 584{ 585 gdbarch_register_osabi (bfd_arch_i386, 0, GDB_OSABI_NETBSD, 586 i386nbsdelf_init_abi); 587} 588