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