X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gdb%2Fi386-gnu-tdep.c;h=b52a333ac162dcd90f0d7849734ceedef188391b;hb=5bb6e9dd7090cacb02bbe9f20d8b101a59a3bf99;hp=f178ae08678453367cac5f2985cb675797078e67;hpb=481695ed5f6e0a8a9c9c50bfac1cdd2b3151e6c9;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/i386-gnu-tdep.c b/gdb/i386-gnu-tdep.c index f178ae0867..b52a333ac1 100644 --- a/gdb/i386-gnu-tdep.c +++ b/gdb/i386-gnu-tdep.c @@ -1,5 +1,5 @@ /* Target-dependent code for the GNU Hurd. - Copyright (C) 2002-2017 Free Software Foundation, Inc. + Copyright (C) 2002-2020 Free Software Foundation, Inc. This file is part of GDB. @@ -17,11 +17,138 @@ along with this program. If not, see . */ #include "defs.h" +#include "gdbcore.h" #include "osabi.h" #include "solib-svr4.h" #include "i386-tdep.h" +/* Recognizing signal handler frames. */ + +/* When the GNU/Hurd libc calls a signal handler, the return address points + inside the trampoline assembly snippet. + + If the trampoline function name can not be identified, we resort to reading + memory from the process in order to identify it. */ + +static const gdb_byte gnu_sigtramp_code[] = +{ +/* rpc_wait_trampoline: */ + 0xb8, 0xe7, 0xff, 0xff, 0xff, /* mov $-25,%eax */ + 0x9a, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, /* lcall $7,$0 */ + 0x89, 0x01, /* movl %eax, (%ecx) */ + 0x89, 0xdc, /* movl %ebx, %esp */ + +/* trampoline: */ + 0xff, 0xd2, /* call *%edx */ +/* RA HERE */ + 0x83, 0xc4, 0x0c, /* addl $12, %esp */ + 0xc3, /* ret */ + +/* firewall: */ + 0xf4, /* hlt */ +}; + +#define GNU_SIGTRAMP_LEN (sizeof gnu_sigtramp_code) +#define GNU_SIGTRAMP_TAIL 5 /* length of tail after RA */ + +/* If THIS_FRAME is a sigtramp routine, return the address of the + start of the routine. Otherwise, return 0. */ + +static CORE_ADDR +i386_gnu_sigtramp_start (struct frame_info *this_frame) +{ + CORE_ADDR pc = get_frame_pc (this_frame); + gdb_byte buf[GNU_SIGTRAMP_LEN]; + + if (!safe_frame_unwind_memory (this_frame, + pc + GNU_SIGTRAMP_TAIL - GNU_SIGTRAMP_LEN, + buf, GNU_SIGTRAMP_LEN)) + return 0; + + if (memcmp (buf, gnu_sigtramp_code, GNU_SIGTRAMP_LEN) != 0) + return 0; + + return pc; +} + +/* Return whether THIS_FRAME corresponds to a GNU/Linux sigtramp + routine. */ + +static int +i386_gnu_sigtramp_p (struct frame_info *this_frame) +{ + CORE_ADDR pc = get_frame_pc (this_frame); + const char *name; + + find_pc_partial_function (pc, &name, NULL, NULL); + + /* If we have a NAME, we can check for the trampoline function */ + if (name != NULL && strcmp (name, "trampoline") == 0) + return 1; + + return i386_gnu_sigtramp_start (this_frame) != 0; +} + +/* Offset to sc_i386_thread_state in sigcontext, from . */ +#define I386_GNU_SIGCONTEXT_THREAD_STATE_OFFSET 20 + +/* Assuming THIS_FRAME is a GNU/Linux sigtramp routine, return the + address of the associated sigcontext structure. */ + +static CORE_ADDR +i386_gnu_sigcontext_addr (struct frame_info *this_frame) +{ + struct gdbarch *gdbarch = get_frame_arch (this_frame); + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); + CORE_ADDR pc; + CORE_ADDR sp; + gdb_byte buf[4]; + + get_frame_register (this_frame, I386_ESP_REGNUM, buf); + sp = extract_unsigned_integer (buf, 4, byte_order); + + pc = i386_gnu_sigtramp_start (this_frame); + if (pc) + { + CORE_ADDR sigcontext_addr; + + /* The sigcontext structure address is passed as the third argument to + the signal handler. */ + read_memory (sp + 8, buf, 4); + sigcontext_addr = extract_unsigned_integer (buf, 4, byte_order); + return sigcontext_addr + I386_GNU_SIGCONTEXT_THREAD_STATE_OFFSET; + } + + error (_("Couldn't recognize signal trampoline.")); + return 0; +} + +/* Mapping between the general-purpose registers in `struct + sigcontext' format (starting at sc_i386_thread_state) + and GDB's register cache layout. */ + +/* From . */ +static int i386_gnu_sc_reg_offset[] = +{ + 11 * 4, /* %eax */ + 10 * 4, /* %ecx */ + 9 * 4, /* %edx */ + 8 * 4, /* %ebx */ + 7 * 4, /* %esp */ + 6 * 4, /* %ebp */ + 5 * 4, /* %esi */ + 4 * 4, /* %edi */ + 12 * 4, /* %eip */ + 14 * 4, /* %eflags */ + 13 * 4, /* %cs */ + 16 * 4, /* %ss */ + 3 * 4, /* %ds */ + 2 * 4, /* %es */ + 1 * 4, /* %fs */ + 0 * 4 /* %gs */ +}; + /* From . */ static int i386gnu_gregset_reg_offset[] = { @@ -59,10 +186,16 @@ i386gnu_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) tdep->sizeof_gregset = 19 * 4; tdep->jb_pc_offset = 20; /* From . */ + + tdep->sigtramp_p = i386_gnu_sigtramp_p; + tdep->sigcontext_addr = i386_gnu_sigcontext_addr; + tdep->sc_reg_offset = i386_gnu_sc_reg_offset; + tdep->sc_num_regs = ARRAY_SIZE (i386_gnu_sc_reg_offset); } +void _initialize_i386gnu_tdep (); void -_initialize_i386gnu_tdep (void) +_initialize_i386gnu_tdep () { gdbarch_register_osabi (bfd_arch_i386, 0, GDB_OSABI_HURD, i386gnu_init_abi); }