Home | History | Annotate | Line # | Download | only in gdb
i386-netbsd-tdep.c revision 1.1.1.2
      1 /* Target-dependent code for NetBSD/i386.
      2 
      3    Copyright (C) 1988-2024 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 "arch-utils.h"
     21 #include "frame.h"
     22 #include "gdbcore.h"
     23 #include "regcache.h"
     24 #include "regset.h"
     25 #include "osabi.h"
     26 #include "symtab.h"
     27 #include "trad-frame.h"
     28 #include "tramp-frame.h"
     29 #include "frame-unwind.h"
     30 
     31 #include "i386-tdep.h"
     32 #include "i387-tdep.h"
     33 #include "netbsd-tdep.h"
     34 #include "solib-svr4.h"
     35 
     36 /* From <machine/reg.h>.  */
     37 static int i386nbsd_r_reg_offset[] =
     38 {
     39   0 * 4,			/* %eax */
     40   1 * 4,			/* %ecx */
     41   2 * 4,			/* %edx */
     42   3 * 4,			/* %ebx */
     43   4 * 4,			/* %esp */
     44   5 * 4,			/* %ebp */
     45   6 * 4,			/* %esi */
     46   7 * 4,			/* %edi */
     47   8 * 4,			/* %eip */
     48   9 * 4,			/* %eflags */
     49   10 * 4,			/* %cs */
     50   11 * 4,			/* %ss */
     51   12 * 4,			/* %ds */
     52   13 * 4,			/* %es */
     53   14 * 4,			/* %fs */
     54   15 * 4			/* %gs */
     55 };
     56 
     57 /* From <machine/signal.h>.  */
     58 static int i386nbsd_sc_reg_offset[] =
     59 {
     60   10 * 4,			/* %eax */
     61   9 * 4,			/* %ecx */
     62   8 * 4,			/* %edx */
     63   7 * 4,			/* %ebx */
     64   14 * 4,			/* %esp */
     65   6 * 4,			/* %ebp */
     66   5 * 4,			/* %esi */
     67   4 * 4,			/* %edi */
     68   11 * 4,			/* %eip */
     69   13 * 4,			/* %eflags */
     70   12 * 4,			/* %cs */
     71   15 * 4,			/* %ss */
     72   3 * 4,			/* %ds */
     73   2 * 4,			/* %es */
     74   1 * 4,			/* %fs */
     75   0 * 4				/* %gs */
     76 };
     77 
     78 /* From <machine/mcontext.h>.  */
     79 static int i386nbsd_mc_reg_offset[] =
     80 {
     81   11 * 4,			/* %eax */
     82   10 * 4,			/* %ecx */
     83   9 * 4,			/* %edx */
     84   8 * 4,			/* %ebx */
     85   7 * 4,			/* %esp */
     86   6 * 4,			/* %ebp */
     87   5 * 4,			/* %esi */
     88   4 * 4,			/* %edi */
     89   14 * 4,			/* %eip */
     90   16 * 4,			/* %eflags */
     91   15 * 4,			/* %cs */
     92   18 * 4,			/* %ss */
     93   3 * 4,			/* %ds */
     94   2 * 4,			/* %es */
     95   1 * 4,			/* %fs */
     96   0 * 4				/* %gs */
     97 };
     98 
     99 static void i386nbsd_sigtramp_cache_init (const struct tramp_frame *,
    100 					  const frame_info_ptr &,
    101 					  struct trad_frame_cache *,
    102 					  CORE_ADDR);
    103 
    104 static const struct tramp_frame i386nbsd_sigtramp_sc16 =
    105 {
    106   SIGTRAMP_FRAME,
    107   1,
    108   {
    109    /* leal  0x10(%esp), %eax */
    110    { 0x8d, ULONGEST_MAX },
    111    { 0x44, ULONGEST_MAX },
    112    { 0x24, ULONGEST_MAX },
    113    { 0x10, ULONGEST_MAX },
    114 
    115    /* pushl %eax */
    116    { 0x50, ULONGEST_MAX },
    117 
    118    /* pushl %eax */
    119    { 0x50, ULONGEST_MAX },
    120 
    121    /* movl  $0x127, %eax		# __sigreturn14 */
    122    { 0xb8, ULONGEST_MAX },
    123    { 0x27, ULONGEST_MAX },
    124    {0x01, ULONGEST_MAX },
    125    {0x00, ULONGEST_MAX },
    126    {0x00, ULONGEST_MAX },
    127 
    128    /* int   $0x80 */
    129    { 0xcd, ULONGEST_MAX },
    130    { 0x80, ULONGEST_MAX},
    131 
    132    /* movl  $0x1, %eax		# exit */
    133    { 0xb8, ULONGEST_MAX },
    134    { 0x01, ULONGEST_MAX },
    135    {0x00, ULONGEST_MAX },
    136    {0x00, ULONGEST_MAX },
    137    {0x00, ULONGEST_MAX },
    138 
    139    /* int   $0x80 */
    140    { 0xcd, ULONGEST_MAX },
    141    { 0x80, ULONGEST_MAX},
    142 
    143    { TRAMP_SENTINEL_INSN, ULONGEST_MAX }
    144   },
    145   i386nbsd_sigtramp_cache_init
    146 };
    147 
    148 static const struct tramp_frame i386nbsd_sigtramp_sc2 =
    149 {
    150   SIGTRAMP_FRAME,
    151   1,
    152   {
    153    /* leal  0x0c(%esp), %eax */
    154    { 0x8d, ULONGEST_MAX },
    155    { 0x44, ULONGEST_MAX },
    156    { 0x24, ULONGEST_MAX },
    157    { 0x0c, ULONGEST_MAX },
    158    /* movl  %eax, 0x4(%esp) */
    159    { 0x89, ULONGEST_MAX },
    160    { 0x44, ULONGEST_MAX },
    161    { 0x24, ULONGEST_MAX },
    162    { 0x04, ULONGEST_MAX },
    163    /* movl  $0x127, %eax		# __sigreturn14 */
    164    { 0xb8, ULONGEST_MAX },
    165    { 0x27, ULONGEST_MAX },
    166    {0x01, ULONGEST_MAX },
    167    {0x00, ULONGEST_MAX },
    168    {0x00, ULONGEST_MAX },
    169    /* int   $0x80 */
    170    { 0xcd, ULONGEST_MAX },
    171    { 0x80, ULONGEST_MAX},
    172    /* movl  %eax, 0x4(%esp) */
    173    { 0x89, ULONGEST_MAX },
    174    { 0x44, ULONGEST_MAX },
    175    { 0x24, ULONGEST_MAX },
    176    { 0x04, ULONGEST_MAX },
    177    /* movl  $0x1, %eax */
    178    { 0xb8, ULONGEST_MAX },
    179    { 0x01, ULONGEST_MAX },
    180    {0x00, ULONGEST_MAX },
    181    {0x00, ULONGEST_MAX },
    182    {0x00, ULONGEST_MAX },
    183    /* int   $0x80 */
    184    { 0xcd, ULONGEST_MAX },
    185    { 0x80, ULONGEST_MAX},
    186    { TRAMP_SENTINEL_INSN, ULONGEST_MAX }
    187   },
    188   i386nbsd_sigtramp_cache_init
    189 };
    190 
    191 static const struct tramp_frame i386nbsd_sigtramp_si2 =
    192 {
    193   SIGTRAMP_FRAME,
    194   1,
    195   {
    196    /* movl  8(%esp),%eax */
    197    { 0x8b, ULONGEST_MAX },
    198    { 0x44, ULONGEST_MAX },
    199    { 0x24, ULONGEST_MAX },
    200    { 0x08, ULONGEST_MAX },
    201    /* movl  %eax, 0x4(%esp) */
    202    { 0x89, ULONGEST_MAX },
    203    { 0x44, ULONGEST_MAX },
    204    { 0x24, ULONGEST_MAX },
    205    { 0x04, ULONGEST_MAX },
    206    /* movl  $0x134, %eax            # setcontext */
    207    { 0xb8, ULONGEST_MAX },
    208    { 0x34, ULONGEST_MAX },
    209    { 0x01, ULONGEST_MAX },
    210    { 0x00, ULONGEST_MAX },
    211    { 0x00, ULONGEST_MAX },
    212    /* int   $0x80 */
    213    { 0xcd, ULONGEST_MAX },
    214    { 0x80, ULONGEST_MAX },
    215    /* movl  %eax, 0x4(%esp) */
    216    { 0x89, ULONGEST_MAX },
    217    { 0x44, ULONGEST_MAX },
    218    { 0x24, ULONGEST_MAX },
    219    { 0x04, ULONGEST_MAX },
    220    /* movl  $0x1, %eax */
    221    { 0xb8, ULONGEST_MAX },
    222    { 0x01, ULONGEST_MAX },
    223    { 0x00, ULONGEST_MAX },
    224    { 0x00, ULONGEST_MAX },
    225    { 0x00, ULONGEST_MAX },
    226    /* int   $0x80 */
    227    { 0xcd, ULONGEST_MAX },
    228    { 0x80, ULONGEST_MAX },
    229    { TRAMP_SENTINEL_INSN, ULONGEST_MAX }
    230   },
    231   i386nbsd_sigtramp_cache_init
    232 };
    233 
    234 static const struct tramp_frame i386nbsd_sigtramp_si31 =
    235 {
    236   SIGTRAMP_FRAME,
    237   1,
    238   {
    239    /* leal  0x8c(%esp), %eax */
    240    { 0x8d, ULONGEST_MAX },
    241    { 0x84, ULONGEST_MAX },
    242    { 0x24, ULONGEST_MAX },
    243    { 0x8c, ULONGEST_MAX },
    244    { 0x00, ULONGEST_MAX },
    245    { 0x00, ULONGEST_MAX },
    246    { 0x00, ULONGEST_MAX },
    247    /* movl  %eax, 0x4(%esp) */
    248    { 0x89, ULONGEST_MAX },
    249    { 0x44, ULONGEST_MAX },
    250    { 0x24, ULONGEST_MAX },
    251    { 0x04, ULONGEST_MAX },
    252    /* movl  $0x134, %eax            # setcontext */
    253    { 0xb8, ULONGEST_MAX },
    254    { 0x34, ULONGEST_MAX },
    255    { 0x01, ULONGEST_MAX },
    256    { 0x00, ULONGEST_MAX },
    257    { 0x00, ULONGEST_MAX },
    258    /* int   $0x80 */
    259    { 0xcd, ULONGEST_MAX },
    260    { 0x80, ULONGEST_MAX},
    261    /* movl  %eax, 0x4(%esp) */
    262    { 0x89, ULONGEST_MAX },
    263    { 0x44, ULONGEST_MAX },
    264    { 0x24, ULONGEST_MAX },
    265    { 0x04, ULONGEST_MAX },
    266    /* movl  $0x1, %eax */
    267    { 0xb8, ULONGEST_MAX },
    268    { 0x01, ULONGEST_MAX },
    269    {0x00, ULONGEST_MAX },
    270    {0x00, ULONGEST_MAX },
    271    {0x00, ULONGEST_MAX },
    272    /* int   $0x80 */
    273    { 0xcd, ULONGEST_MAX },
    274    { 0x80, ULONGEST_MAX},
    275    { TRAMP_SENTINEL_INSN, ULONGEST_MAX }
    276   },
    277   i386nbsd_sigtramp_cache_init
    278 };
    279 
    280 static const struct tramp_frame i386nbsd_sigtramp_si4 =
    281 {
    282   SIGTRAMP_FRAME,
    283   1,
    284   {
    285    /* leal  0x8c(%esp), %eax */
    286    { 0x8d, ULONGEST_MAX },
    287    { 0x84, ULONGEST_MAX },
    288    { 0x24, ULONGEST_MAX },
    289    { 0x8c, ULONGEST_MAX },
    290    { 0x00, ULONGEST_MAX },
    291    { 0x00, ULONGEST_MAX },
    292    { 0x00, ULONGEST_MAX },
    293    /* movl  %eax, 0x4(%esp) */
    294    { 0x89, ULONGEST_MAX },
    295    { 0x44, ULONGEST_MAX },
    296    { 0x24, ULONGEST_MAX },
    297    { 0x04, ULONGEST_MAX },
    298    /* movl  $0x134, %eax            # setcontext */
    299    { 0xb8, ULONGEST_MAX },
    300    { 0x34, ULONGEST_MAX },
    301    { 0x01, ULONGEST_MAX },
    302    { 0x00, ULONGEST_MAX },
    303    { 0x00, ULONGEST_MAX },
    304    /* int   $0x80 */
    305    { 0xcd, ULONGEST_MAX },
    306    { 0x80, ULONGEST_MAX},
    307    /* movl   $0xffffffff,0x4(%esp) */
    308    { 0xc7, ULONGEST_MAX },
    309    { 0x44, ULONGEST_MAX },
    310    { 0x24, ULONGEST_MAX },
    311    { 0x04, ULONGEST_MAX },
    312    { 0xff, ULONGEST_MAX },
    313    { 0xff, ULONGEST_MAX },
    314    { 0xff, ULONGEST_MAX },
    315    { 0xff, ULONGEST_MAX },
    316    /* movl  $0x1, %eax */
    317    { 0xb8, ULONGEST_MAX },
    318    { 0x01, ULONGEST_MAX },
    319    {0x00, ULONGEST_MAX },
    320    {0x00, ULONGEST_MAX },
    321    {0x00, ULONGEST_MAX },
    322    /* int   $0x80 */
    323    { 0xcd, ULONGEST_MAX },
    324    { 0x80, ULONGEST_MAX},
    325    { TRAMP_SENTINEL_INSN, ULONGEST_MAX }
    326   },
    327   i386nbsd_sigtramp_cache_init
    328 };
    329 
    330 static void
    331 i386nbsd_sigtramp_cache_init (const struct tramp_frame *self,
    332 			      const frame_info_ptr &this_frame,
    333 			      struct trad_frame_cache *this_cache,
    334 			      CORE_ADDR func)
    335 {
    336   struct gdbarch *gdbarch = get_frame_arch (this_frame);
    337   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
    338   CORE_ADDR sp = get_frame_register_unsigned (this_frame, I386_ESP_REGNUM);
    339   CORE_ADDR base;
    340   int *reg_offset;
    341   int num_regs;
    342   int i;
    343 
    344   if (self == &i386nbsd_sigtramp_sc16 || self == &i386nbsd_sigtramp_sc2)
    345     {
    346       reg_offset = i386nbsd_sc_reg_offset;
    347       num_regs = ARRAY_SIZE (i386nbsd_sc_reg_offset);
    348 
    349       /* Read in the sigcontext address.  */
    350       base = read_memory_unsigned_integer (sp + 8, 4, byte_order);
    351     }
    352   else
    353     {
    354       reg_offset = i386nbsd_mc_reg_offset;
    355       num_regs = ARRAY_SIZE (i386nbsd_mc_reg_offset);
    356 
    357       /* Read in the ucontext address.  */
    358       base = read_memory_unsigned_integer (sp + 8, 4, byte_order);
    359       /* offsetof(ucontext_t, uc_mcontext) == 36 */
    360       base += 36;
    361     }
    362 
    363   for (i = 0; i < num_regs; i++)
    364     if (reg_offset[i] != -1)
    365       trad_frame_set_reg_addr (this_cache, i, base + reg_offset[i]);
    366 
    367   /* Construct the frame ID using the function start.  */
    368   trad_frame_set_id (this_cache, frame_id_build (sp, func));
    369 }
    370 
    371 
    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 (const 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 (const 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 			    const 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