X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gdb%2Famd64-linux-tdep.c;h=92f52655d57c9cb7bf443cde0d224656057b010a;hb=e17a4113357102b55cfa5b80557d590a46a43300;hp=9fa01739bc306775d9b6b7890f8893de25a49b3e;hpb=197e01b6dcd118b70ed3621b62b2ff3fa929d50f;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/amd64-linux-tdep.c b/gdb/amd64-linux-tdep.c index 9fa01739bc..92f52655d5 100644 --- a/gdb/amd64-linux-tdep.c +++ b/gdb/amd64-linux-tdep.c @@ -1,13 +1,14 @@ /* Target-dependent code for GNU/Linux x86-64. - Copyright (C) 2001, 2003, 2004, 2005 Free Software Foundation, Inc. + Copyright (C) 2001, 2003, 2004, 2005, 2006, 2007, 2008, 2009 + Free Software Foundation, Inc. Contributed by Jiri Smid, SuSE Labs. This file is part of GDB. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or + the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, @@ -16,16 +17,19 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. */ + along with this program. If not, see . */ #include "defs.h" +#include "arch-utils.h" #include "frame.h" #include "gdbcore.h" #include "regcache.h" #include "osabi.h" #include "symtab.h" +#include "gdbtypes.h" +#include "reggroups.h" +#include "amd64-linux-tdep.h" +#include "linux-tdep.h" #include "gdb_string.h" @@ -86,9 +90,9 @@ static const gdb_byte linux_sigtramp_code[] = the routine. Otherwise, return 0. */ static CORE_ADDR -amd64_linux_sigtramp_start (struct frame_info *next_frame) +amd64_linux_sigtramp_start (struct frame_info *this_frame) { - CORE_ADDR pc = frame_pc_unwind (next_frame); + CORE_ADDR pc = get_frame_pc (this_frame); gdb_byte buf[LINUX_SIGTRAMP_LEN]; /* We only recognize a signal trampoline if PC is at the start of @@ -98,7 +102,7 @@ amd64_linux_sigtramp_start (struct frame_info *next_frame) PC is not at the start of the instruction sequence, there will be a few trailing readable bytes on the stack. */ - if (!safe_frame_unwind_memory (next_frame, pc, buf, sizeof buf)) + if (!safe_frame_unwind_memory (this_frame, pc, buf, sizeof buf)) return 0; if (buf[0] != LINUX_SIGTRAMP_INSN0) @@ -107,7 +111,7 @@ amd64_linux_sigtramp_start (struct frame_info *next_frame) return 0; pc -= LINUX_SIGTRAMP_OFFSET1; - if (!safe_frame_unwind_memory (next_frame, pc, buf, sizeof buf)) + if (!safe_frame_unwind_memory (this_frame, pc, buf, sizeof buf)) return 0; } @@ -117,13 +121,13 @@ amd64_linux_sigtramp_start (struct frame_info *next_frame) return pc; } -/* Return whether the frame preceding NEXT_FRAME corresponds to a - GNU/Linux sigtramp routine. */ +/* Return whether THIS_FRAME corresponds to a GNU/Linux sigtramp + routine. */ static int -amd64_linux_sigtramp_p (struct frame_info *next_frame) +amd64_linux_sigtramp_p (struct frame_info *this_frame) { - CORE_ADDR pc = frame_pc_unwind (next_frame); + CORE_ADDR pc = get_frame_pc (this_frame); char *name; find_pc_partial_function (pc, &name, NULL, NULL); @@ -135,7 +139,7 @@ amd64_linux_sigtramp_p (struct frame_info *next_frame) __sigaction, or __libc_sigaction (all aliases to the same function). */ if (name == NULL || strstr (name, "sigaction") != NULL) - return (amd64_linux_sigtramp_start (next_frame) != 0); + return (amd64_linux_sigtramp_start (this_frame) != 0); return (strcmp ("__restore_rt", name) == 0); } @@ -143,17 +147,19 @@ amd64_linux_sigtramp_p (struct frame_info *next_frame) /* Offset to struct sigcontext in ucontext, from . */ #define AMD64_LINUX_UCONTEXT_SIGCONTEXT_OFFSET 40 -/* Assuming NEXT_FRAME is a frame following a GNU/Linux sigtramp - routine, return the address of the associated sigcontext structure. */ +/* Assuming THIS_FRAME is a GNU/Linux sigtramp routine, return the + address of the associated sigcontext structure. */ static CORE_ADDR -amd64_linux_sigcontext_addr (struct frame_info *next_frame) +amd64_linux_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 sp; gdb_byte buf[8]; - frame_unwind_register (next_frame, SP_REGNUM, buf); - sp = extract_unsigned_integer (buf, 8); + get_frame_register (this_frame, AMD64_RSP_REGNUM, buf); + sp = extract_unsigned_integer (buf, 8, byte_order); /* The sigcontext structure is part of the user context. A pointer to the user context is passed as the third argument to the signal @@ -199,6 +205,61 @@ static int amd64_linux_sc_reg_offset[] = -1 /* %gs */ }; +/* Replacement register functions which know about %orig_rax. */ + +static const char * +amd64_linux_register_name (struct gdbarch *gdbarch, int reg) +{ + if (reg == AMD64_LINUX_ORIG_RAX_REGNUM) + return "orig_rax"; + + return amd64_register_name (gdbarch, reg); +} + +static struct type * +amd64_linux_register_type (struct gdbarch *gdbarch, int reg) +{ + if (reg == AMD64_LINUX_ORIG_RAX_REGNUM) + return builtin_type (gdbarch)->builtin_int64; + + return amd64_register_type (gdbarch, reg); +} + +static int +amd64_linux_register_reggroup_p (struct gdbarch *gdbarch, int regnum, + struct reggroup *group) +{ + if (regnum == AMD64_LINUX_ORIG_RAX_REGNUM) + return (group == system_reggroup + || group == save_reggroup + || group == restore_reggroup); + return default_register_reggroup_p (gdbarch, regnum, group); +} + +/* Set the program counter for process PTID to PC. */ + +static void +amd64_linux_write_pc (struct regcache *regcache, CORE_ADDR pc) +{ + regcache_cooked_write_unsigned (regcache, AMD64_RIP_REGNUM, pc); + + /* We must be careful with modifying the program counter. If we + just interrupted a system call, the kernel might try to restart + it when we resume the inferior. On restarting the system call, + the kernel will try backing up the program counter even though it + no longer points at the system call. This typically results in a + SIGSEGV or SIGILL. We can prevent this by writing `-1' in the + "orig_rax" pseudo-register. + + Note that "orig_rax" is saved when setting up a dummy call frame. + This means that it is properly restored when that frame is + popped, and that the interrupted system call will be restarted + when we resume the inferior on return from a function call from + within GDB. In all other cases the system call will not be + restarted. */ + regcache_cooked_write_unsigned (regcache, AMD64_LINUX_ORIG_RAX_REGNUM, -1); +} + static void amd64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) { @@ -219,9 +280,27 @@ amd64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) set_solib_svr4_fetch_link_map_offsets (gdbarch, svr4_lp64_fetch_link_map_offsets); + /* Add the %orig_rax register used for syscall restarting. */ + set_gdbarch_write_pc (gdbarch, amd64_linux_write_pc); + set_gdbarch_num_regs (gdbarch, AMD64_LINUX_NUM_REGS); + set_gdbarch_register_name (gdbarch, amd64_linux_register_name); + set_gdbarch_register_type (gdbarch, amd64_linux_register_type); + set_gdbarch_register_reggroup_p (gdbarch, amd64_linux_register_reggroup_p); + /* Enable TLS support. */ set_gdbarch_fetch_tls_load_module_address (gdbarch, svr4_fetch_objfile_link_map); + + /* Displaced stepping. */ + set_gdbarch_displaced_step_copy_insn (gdbarch, + amd64_displaced_step_copy_insn); + set_gdbarch_displaced_step_fixup (gdbarch, amd64_displaced_step_fixup); + set_gdbarch_displaced_step_free_closure (gdbarch, + simple_displaced_step_free_closure); + set_gdbarch_displaced_step_location (gdbarch, + displaced_step_at_entry_point); + + set_gdbarch_get_siginfo_type (gdbarch, linux_get_siginfo_type); }