xref: /netbsd-src/external/gpl3/gdb.old/dist/gdb/i386-gnu-tdep.c (revision 6881a4007f077b54e5f51159c52b9b25f57deb0d)
1699b0f92Schristos /* Target-dependent code for the GNU Hurd.
2*6881a400Schristos    Copyright (C) 2002-2023 Free Software Foundation, Inc.
3699b0f92Schristos 
4699b0f92Schristos    This file is part of GDB.
5699b0f92Schristos 
6699b0f92Schristos    This program is free software; you can redistribute it and/or modify
7699b0f92Schristos    it under the terms of the GNU General Public License as published by
8699b0f92Schristos    the Free Software Foundation; either version 3 of the License, or
9699b0f92Schristos    (at your option) any later version.
10699b0f92Schristos 
11699b0f92Schristos    This program is distributed in the hope that it will be useful,
12699b0f92Schristos    but WITHOUT ANY WARRANTY; without even the implied warranty of
13699b0f92Schristos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14699b0f92Schristos    GNU General Public License for more details.
15699b0f92Schristos 
16699b0f92Schristos    You should have received a copy of the GNU General Public License
17699b0f92Schristos    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
18699b0f92Schristos 
19699b0f92Schristos #include "defs.h"
207d62b00eSchristos #include "gdbcore.h"
21699b0f92Schristos #include "osabi.h"
22699b0f92Schristos #include "solib-svr4.h"
23699b0f92Schristos 
24699b0f92Schristos #include "i386-tdep.h"
25699b0f92Schristos 
267d62b00eSchristos /* Recognizing signal handler frames.  */
277d62b00eSchristos 
287d62b00eSchristos /* When the GNU/Hurd libc calls a signal handler, the return address points
297d62b00eSchristos    inside the trampoline assembly snippet.
307d62b00eSchristos 
317d62b00eSchristos    If the trampoline function name can not be identified, we resort to reading
327d62b00eSchristos    memory from the process in order to identify it.  */
337d62b00eSchristos 
347d62b00eSchristos static const gdb_byte gnu_sigtramp_code[] =
357d62b00eSchristos {
367d62b00eSchristos /* rpc_wait_trampoline: */
377d62b00eSchristos   0xb8, 0xe7, 0xff, 0xff, 0xff,			/* mov    $-25,%eax */
387d62b00eSchristos   0x9a, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00,	/* lcall  $7,$0 */
397d62b00eSchristos   0x89, 0x01,					/* movl   %eax, (%ecx) */
407d62b00eSchristos   0x89, 0xdc,					/* movl   %ebx, %esp */
417d62b00eSchristos 
427d62b00eSchristos /* trampoline: */
437d62b00eSchristos   0xff, 0xd2,					/* call   *%edx */
447d62b00eSchristos /* RA HERE */
457d62b00eSchristos   0x83, 0xc4, 0x0c,				/* addl   $12, %esp */
467d62b00eSchristos   0xc3,						/* ret */
477d62b00eSchristos 
487d62b00eSchristos /* firewall: */
497d62b00eSchristos   0xf4,						/* hlt */
507d62b00eSchristos };
517d62b00eSchristos 
527d62b00eSchristos #define GNU_SIGTRAMP_LEN (sizeof gnu_sigtramp_code)
537d62b00eSchristos #define GNU_SIGTRAMP_TAIL 5			/* length of tail after RA */
547d62b00eSchristos 
557d62b00eSchristos /* If THIS_FRAME is a sigtramp routine, return the address of the
567d62b00eSchristos    start of the routine.  Otherwise, return 0.  */
577d62b00eSchristos 
587d62b00eSchristos static CORE_ADDR
59*6881a400Schristos i386_gnu_sigtramp_start (frame_info_ptr this_frame)
607d62b00eSchristos {
617d62b00eSchristos   CORE_ADDR pc = get_frame_pc (this_frame);
627d62b00eSchristos   gdb_byte buf[GNU_SIGTRAMP_LEN];
637d62b00eSchristos 
647d62b00eSchristos   if (!safe_frame_unwind_memory (this_frame,
657d62b00eSchristos 				 pc + GNU_SIGTRAMP_TAIL - GNU_SIGTRAMP_LEN,
66*6881a400Schristos 				 buf))
677d62b00eSchristos     return 0;
687d62b00eSchristos 
697d62b00eSchristos   if (memcmp (buf, gnu_sigtramp_code, GNU_SIGTRAMP_LEN) != 0)
707d62b00eSchristos     return 0;
717d62b00eSchristos 
727d62b00eSchristos   return pc;
737d62b00eSchristos }
747d62b00eSchristos 
757d62b00eSchristos /* Return whether THIS_FRAME corresponds to a GNU/Linux sigtramp
767d62b00eSchristos    routine.  */
777d62b00eSchristos 
787d62b00eSchristos static int
79*6881a400Schristos i386_gnu_sigtramp_p (frame_info_ptr this_frame)
807d62b00eSchristos {
817d62b00eSchristos   CORE_ADDR pc = get_frame_pc (this_frame);
827d62b00eSchristos   const char *name;
837d62b00eSchristos 
847d62b00eSchristos   find_pc_partial_function (pc, &name, NULL, NULL);
857d62b00eSchristos 
867d62b00eSchristos   /* If we have a NAME, we can check for the trampoline function */
877d62b00eSchristos   if (name != NULL && strcmp (name, "trampoline") == 0)
887d62b00eSchristos     return 1;
897d62b00eSchristos 
907d62b00eSchristos   return i386_gnu_sigtramp_start (this_frame) != 0;
917d62b00eSchristos }
927d62b00eSchristos 
937d62b00eSchristos /* Offset to sc_i386_thread_state in sigcontext, from <bits/sigcontext.h>.  */
947d62b00eSchristos #define I386_GNU_SIGCONTEXT_THREAD_STATE_OFFSET 20
957d62b00eSchristos 
967d62b00eSchristos /* Assuming THIS_FRAME is a GNU/Linux sigtramp routine, return the
977d62b00eSchristos    address of the associated sigcontext structure.  */
987d62b00eSchristos 
997d62b00eSchristos static CORE_ADDR
100*6881a400Schristos i386_gnu_sigcontext_addr (frame_info_ptr this_frame)
1017d62b00eSchristos {
1027d62b00eSchristos   struct gdbarch *gdbarch = get_frame_arch (this_frame);
1037d62b00eSchristos   enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
1047d62b00eSchristos   CORE_ADDR pc;
1057d62b00eSchristos   CORE_ADDR sp;
1067d62b00eSchristos   gdb_byte buf[4];
1077d62b00eSchristos 
1087d62b00eSchristos   get_frame_register (this_frame, I386_ESP_REGNUM, buf);
1097d62b00eSchristos   sp = extract_unsigned_integer (buf, 4, byte_order);
1107d62b00eSchristos 
1117d62b00eSchristos   pc = i386_gnu_sigtramp_start (this_frame);
1127d62b00eSchristos   if (pc)
1137d62b00eSchristos     {
1147d62b00eSchristos       CORE_ADDR sigcontext_addr;
1157d62b00eSchristos 
1167d62b00eSchristos       /* The sigcontext structure address is passed as the third argument to
1177d62b00eSchristos 	 the signal handler. */
1187d62b00eSchristos       read_memory (sp + 8, buf, 4);
1197d62b00eSchristos       sigcontext_addr = extract_unsigned_integer (buf, 4, byte_order);
1207d62b00eSchristos       return sigcontext_addr + I386_GNU_SIGCONTEXT_THREAD_STATE_OFFSET;
1217d62b00eSchristos     }
1227d62b00eSchristos 
1237d62b00eSchristos   error (_("Couldn't recognize signal trampoline."));
1247d62b00eSchristos   return 0;
1257d62b00eSchristos }
1267d62b00eSchristos 
1277d62b00eSchristos /* Mapping between the general-purpose registers in `struct
1287d62b00eSchristos    sigcontext' format (starting at sc_i386_thread_state)
1297d62b00eSchristos    and GDB's register cache layout.  */
1307d62b00eSchristos 
1317d62b00eSchristos /* From <bits/sigcontext.h>.  */
1327d62b00eSchristos static int i386_gnu_sc_reg_offset[] =
1337d62b00eSchristos {
1347d62b00eSchristos   11 * 4,			/* %eax */
1357d62b00eSchristos   10 * 4,			/* %ecx */
1367d62b00eSchristos   9 * 4,			/* %edx */
1377d62b00eSchristos   8 * 4,			/* %ebx */
1387d62b00eSchristos   7 * 4,			/* %esp */
1397d62b00eSchristos   6 * 4,			/* %ebp */
1407d62b00eSchristos   5 * 4,			/* %esi */
1417d62b00eSchristos   4 * 4,			/* %edi */
1427d62b00eSchristos   12 * 4,			/* %eip */
1437d62b00eSchristos   14 * 4,			/* %eflags */
1447d62b00eSchristos   13 * 4,			/* %cs */
1457d62b00eSchristos   16 * 4,			/* %ss */
1467d62b00eSchristos   3 * 4,			/* %ds */
1477d62b00eSchristos   2 * 4,			/* %es */
1487d62b00eSchristos   1 * 4,			/* %fs */
1497d62b00eSchristos   0 * 4				/* %gs */
1507d62b00eSchristos };
1517d62b00eSchristos 
152699b0f92Schristos /* From <sys/ucontext.h>.  */
153699b0f92Schristos static int i386gnu_gregset_reg_offset[] =
154699b0f92Schristos {
155699b0f92Schristos   11 * 4,		/* %eax */
156699b0f92Schristos   10 * 4,		/* %ecx */
157699b0f92Schristos   9 * 4,		/* %edx */
158699b0f92Schristos   8 * 4,		/* %ebx */
159699b0f92Schristos   17 * 4,		/* %uesp */
160699b0f92Schristos   6 * 4,		/* %ebp */
161699b0f92Schristos   5 * 4,		/* %esi */
162699b0f92Schristos   4 * 4,		/* %edi */
163699b0f92Schristos   14 * 4,		/* %eip */
164699b0f92Schristos   16 * 4,		/* %efl */
165699b0f92Schristos   15 * 4,		/* %cs */
166699b0f92Schristos   18 * 4,		/* %ss */
167699b0f92Schristos   3 * 4,		/* %ds */
168699b0f92Schristos   2 * 4,		/* %es */
169699b0f92Schristos   1 * 4,		/* %fs */
170699b0f92Schristos   0 * 4,		/* %gs */
171699b0f92Schristos };
172699b0f92Schristos 
173699b0f92Schristos static void
174699b0f92Schristos i386gnu_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
175699b0f92Schristos {
176*6881a400Schristos   i386_gdbarch_tdep *tdep = gdbarch_tdep<i386_gdbarch_tdep> (gdbarch);
177699b0f92Schristos 
178699b0f92Schristos   /* GNU uses ELF.  */
179699b0f92Schristos   i386_elf_init_abi (info, gdbarch);
180699b0f92Schristos 
181699b0f92Schristos   set_solib_svr4_fetch_link_map_offsets
182699b0f92Schristos     (gdbarch, svr4_ilp32_fetch_link_map_offsets);
183699b0f92Schristos 
184699b0f92Schristos   tdep->gregset_reg_offset = i386gnu_gregset_reg_offset;
185699b0f92Schristos   tdep->gregset_num_regs = ARRAY_SIZE (i386gnu_gregset_reg_offset);
186699b0f92Schristos   tdep->sizeof_gregset = 19 * 4;
187699b0f92Schristos 
188699b0f92Schristos   tdep->jb_pc_offset = 20;	/* From <bits/setjmp.h>.  */
1897d62b00eSchristos 
1907d62b00eSchristos   tdep->sigtramp_p = i386_gnu_sigtramp_p;
1917d62b00eSchristos   tdep->sigcontext_addr = i386_gnu_sigcontext_addr;
1927d62b00eSchristos   tdep->sc_reg_offset = i386_gnu_sc_reg_offset;
1937d62b00eSchristos   tdep->sc_num_regs = ARRAY_SIZE (i386_gnu_sc_reg_offset);
194699b0f92Schristos }
195699b0f92Schristos 
1967d62b00eSchristos void _initialize_i386gnu_tdep ();
197699b0f92Schristos void
1987d62b00eSchristos _initialize_i386gnu_tdep ()
199699b0f92Schristos {
200699b0f92Schristos   gdbarch_register_osabi (bfd_arch_i386, 0, GDB_OSABI_HURD, i386gnu_init_abi);
201699b0f92Schristos }
202