Index: gdb/amd64-obsd-tdep.c --- gdb/amd64-obsd-tdep.c.orig +++ gdb/amd64-obsd-tdep.c @@ -39,8 +39,44 @@ /* Support for signal handlers. */ /* Default page size. */ -static const int amd64obsd_page_size = 4096; +static const CORE_ADDR amd64obsd_page_size = 4096; +/* Offset & instructions for sigreturn(2). */ + +#define SIGRETURN_INSN_LEN 9 + +struct amd64obsd_sigreturn_info_t { + int offset; + gdb_byte sigreturn[SIGRETURN_INSN_LEN]; +}; + +static const amd64obsd_sigreturn_info_t + amd64obsd_sigreturn_info[] = { + /* OpenBSD 7.4 */ + { 13, { 0x48, 0xc7, 0xc0, + 0x67, 0x00, 0x00, 0x00, /* movq $SYS_sigreturn, %rax */ + 0x0f, 0x05 } }, /* syscall */ + /* OpenBSD 6.4 */ + { 9, { 0x48, 0xc7, 0xc0, + 0x67, 0x00, 0x00, 0x00, /* movq $SYS_sigreturn, %rax */ + 0x0f, 0x05 } }, /* syscall */ + /* OpenBSD 5.1 */ + { 6, { 0x48, 0xc7, 0xc0, + 0x67, 0x00, 0x00, 0x00, /* movq $SYS_sigreturn, %rax */ + 0x0f, 0x05 } }, /* syscall */ + { 7, { 0x48, 0xc7, 0xc0, + 0x67, 0x00, 0x00, 0x00, /* movq $SYS_sigreturn, %rax */ + 0x0f, 0x05 } }, /* syscall */ + /* OpenBSD 5.0 */ + { 6, { 0x48, 0xc7, 0xc0, + 0x67, 0x00, 0x00, 0x00, /* movq $SYS_sigreturn, %rax */ + 0xcd, 0x80 } }, /* int $0x80 */ + { 7, { 0x48, 0xc7, 0xc0, + 0x67, 0x00, 0x00, 0x00, /* movq $SYS_sigreturn, %rax */ + 0xcd, 0x80 } }, /* int $0x80 */ + { -1, {} } +}; + /* Return whether THIS_FRAME corresponds to an OpenBSD sigtramp routine. */ @@ -49,20 +85,8 @@ amd64obsd_sigtramp_p (struct frame_info *this_frame) { CORE_ADDR pc = get_frame_pc (this_frame); CORE_ADDR start_pc = (pc & ~(amd64obsd_page_size - 1)); - const gdb_byte osigreturn[] = - { - 0x48, 0xc7, 0xc0, - 0x67, 0x00, 0x00, 0x00, /* movq $SYS_sigreturn, %rax */ - 0xcd, 0x80 /* int $0x80 */ - }; - const gdb_byte sigreturn[] = - { - 0x48, 0xc7, 0xc0, - 0x67, 0x00, 0x00, 0x00, /* movq $SYS_sigreturn, %rax */ - 0x0f, 0x05 /* syscall */ - }; - size_t buflen = (sizeof sigreturn) + 1; - gdb_byte *buf; + const amd64obsd_sigreturn_info_t *info; + gdb_byte buf[SIGRETURN_INSN_LEN]; const char *name; /* If the function has a valid symbol name, it isn't a @@ -76,22 +100,21 @@ amd64obsd_sigtramp_p (struct frame_info *this_frame) if (find_pc_section (pc) != NULL) return 0; - /* If we can't read the instructions at START_PC, return zero. */ - buf = (gdb_byte *) alloca ((sizeof sigreturn) + 1); - if (!safe_frame_unwind_memory (this_frame, start_pc + 6, buf, buflen)) - return 0; + for (info = amd64obsd_sigreturn_info; info->offset != -1; info++) + { + /* If we can't read the instructions, return zero. */ + if (!safe_frame_unwind_memory (this_frame, + start_pc + info->offset, buf, sizeof buf)) + continue; - /* Check for sigreturn(2). Depending on how the assembler encoded - the `movq %rsp, %rdi' instruction, the code starts at offset 6 or - 7. OpenBSD 5.0 and later use the `syscall' instruction. Older - versions use `int $0x80'. Check for both. */ - if (memcmp (buf, sigreturn, sizeof sigreturn) - && memcmp (buf + 1, sigreturn, sizeof sigreturn) - && memcmp (buf, osigreturn, sizeof osigreturn) - && memcmp (buf + 1, osigreturn, sizeof osigreturn)) - return 0; + /* Check for sigreturn(2). */ + if (memcmp (buf, info->sigreturn, sizeof buf)) + continue; - return 1; + return 1; + } + + return 0; } /* Assuming THIS_FRAME is for a BSD sigtramp routine, return the @@ -101,7 +124,10 @@ static CORE_ADDR amd64obsd_sigcontext_addr (struct frame_info *this_frame) { CORE_ADDR pc = get_frame_pc (this_frame); + CORE_ADDR start_pc = (pc & ~(amd64obsd_page_size - 1)); ULONGEST offset = (pc & (amd64obsd_page_size - 1)); + const amd64obsd_sigreturn_info_t *info; + gdb_byte buf[SIGRETURN_INSN_LEN]; /* The %rsp register points at `struct sigcontext' upon entry of a signal trampoline. The relevant part of the trampoline is @@ -115,10 +141,22 @@ amd64obsd_sigcontext_addr (struct frame_info *this_fra (see /usr/src/sys/arch/amd64/amd64/locore.S). The `pushq' instruction clobbers %rsp, but its value is saved in `%rdi'. */ - if (offset > 5) - return get_frame_register_unsigned (this_frame, AMD64_RDI_REGNUM); - else - return get_frame_register_unsigned (this_frame, AMD64_RSP_REGNUM); + for (info = amd64obsd_sigreturn_info; info->offset != -1; info++) + { + /* If we can't read the instructions, return %rsp. */ + if (!safe_frame_unwind_memory (this_frame, + start_pc + info->offset, buf, sizeof buf)) + continue; + + /* Check for sigreturn(2). */ + if (memcmp (buf, info->sigreturn, sizeof buf)) + continue; + + if (offset > info->offset - 4 && offset < info->offset + 9) + return get_frame_register_unsigned (this_frame, AMD64_RDI_REGNUM); + } + + return get_frame_register_unsigned (this_frame, AMD64_RSP_REGNUM); } /* OpenBSD 3.5 or later. */