X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gdb%2Famd64-linux-tdep.c;h=7fe92d1eea0183f9cd63fc010cce3944c7319ec7;hb=8b4f3082d8f1f7605c6f89f12bc3a93da06845c5;hp=5032371724c1a8a342c338e239f987a2ac57898a;hpb=2c02bd729076b940958bccf68f1cc0b1ecf8403b;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/amd64-linux-tdep.c b/gdb/amd64-linux-tdep.c index 5032371724..7fe92d1eea 100644 --- a/gdb/amd64-linux-tdep.c +++ b/gdb/amd64-linux-tdep.c @@ -1,6 +1,6 @@ /* Target-dependent code for GNU/Linux x86-64. - Copyright (C) 2001, 2003-2012 Free Software Foundation, Inc. + Copyright (C) 2001-2013 Free Software Foundation, Inc. Contributed by Jiri Smid, SuSE Labs. This file is part of GDB. @@ -33,19 +33,23 @@ #include "linux-tdep.h" #include "i386-xstate.h" -#include "gdb_string.h" +#include #include "amd64-tdep.h" #include "solib-svr4.h" #include "xml-syscall.h" +#include "glibc-tdep.h" #include "features/i386/amd64-linux.c" #include "features/i386/amd64-avx-linux.c" +#include "features/i386/amd64-mpx-linux.c" +#include "features/i386/x32-linux.c" +#include "features/i386/x32-avx-linux.c" /* The syscall's XML filename for i386. */ #define XML_SYSCALL_FILENAME_AMD64 "syscalls/amd64-linux.xml" -#include "record.h" +#include "record-full.h" #include "linux-record.h" /* Supported register note sections. */ @@ -93,6 +97,8 @@ int amd64_linux_gregset_reg_offset[] = -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, /* MPX registers BND0 ... BND3. */ + -1, -1, /* MPX registers BNDCFGU and BNDSTATUS. */ 15 * 8 /* "orig_rax" */ }; @@ -104,7 +110,7 @@ int amd64_linux_gregset_reg_offset[] = #define LINUX_SIGTRAMP_INSN1 0x0f /* syscall */ #define LINUX_SIGTRAMP_OFFSET1 7 -static const gdb_byte linux_sigtramp_code[] = +static const gdb_byte amd64_linux_sigtramp_code[] = { /* mov $__NR_rt_sigreturn, %rax */ LINUX_SIGTRAMP_INSN0, 0xc7, 0xc0, 0x0f, 0x00, 0x00, 0x00, @@ -112,7 +118,15 @@ static const gdb_byte linux_sigtramp_code[] = LINUX_SIGTRAMP_INSN1, 0x05 }; -#define LINUX_SIGTRAMP_LEN (sizeof linux_sigtramp_code) +static const gdb_byte amd64_x32_linux_sigtramp_code[] = +{ + /* mov $__NR_rt_sigreturn, %rax. */ + LINUX_SIGTRAMP_INSN0, 0xc7, 0xc0, 0x01, 0x02, 0x00, 0x40, + /* syscall */ + LINUX_SIGTRAMP_INSN1, 0x05 +}; + +#define LINUX_SIGTRAMP_LEN (sizeof amd64_linux_sigtramp_code) /* If PC is in a sigtramp routine, return the address of the start of the routine. Otherwise, return 0. */ @@ -120,6 +134,8 @@ static const gdb_byte linux_sigtramp_code[] = static CORE_ADDR amd64_linux_sigtramp_start (struct frame_info *this_frame) { + struct gdbarch *gdbarch; + const gdb_byte *sigtramp_code; CORE_ADDR pc = get_frame_pc (this_frame); gdb_byte buf[LINUX_SIGTRAMP_LEN]; @@ -143,7 +159,12 @@ amd64_linux_sigtramp_start (struct frame_info *this_frame) return 0; } - if (memcmp (buf, linux_sigtramp_code, LINUX_SIGTRAMP_LEN) != 0) + gdbarch = get_frame_arch (this_frame); + if (gdbarch_ptr_bit (gdbarch) == 32) + sigtramp_code = amd64_x32_linux_sigtramp_code; + else + sigtramp_code = amd64_linux_sigtramp_code; + if (memcmp (buf, sigtramp_code, LINUX_SIGTRAMP_LEN) != 0) return 0; return pc; @@ -295,39 +316,39 @@ amd64_linux_write_pc (struct regcache *regcache, CORE_ADDR pc) static int amd64_all_but_ip_registers_record (struct regcache *regcache) { - if (record_arch_list_add_reg (regcache, AMD64_RAX_REGNUM)) + if (record_full_arch_list_add_reg (regcache, AMD64_RAX_REGNUM)) return -1; - if (record_arch_list_add_reg (regcache, AMD64_RCX_REGNUM)) + if (record_full_arch_list_add_reg (regcache, AMD64_RCX_REGNUM)) return -1; - if (record_arch_list_add_reg (regcache, AMD64_RDX_REGNUM)) + if (record_full_arch_list_add_reg (regcache, AMD64_RDX_REGNUM)) return -1; - if (record_arch_list_add_reg (regcache, AMD64_RBX_REGNUM)) + if (record_full_arch_list_add_reg (regcache, AMD64_RBX_REGNUM)) return -1; - if (record_arch_list_add_reg (regcache, AMD64_RSP_REGNUM)) + if (record_full_arch_list_add_reg (regcache, AMD64_RSP_REGNUM)) return -1; - if (record_arch_list_add_reg (regcache, AMD64_RBP_REGNUM)) + if (record_full_arch_list_add_reg (regcache, AMD64_RBP_REGNUM)) return -1; - if (record_arch_list_add_reg (regcache, AMD64_RSI_REGNUM)) + if (record_full_arch_list_add_reg (regcache, AMD64_RSI_REGNUM)) return -1; - if (record_arch_list_add_reg (regcache, AMD64_RDI_REGNUM)) + if (record_full_arch_list_add_reg (regcache, AMD64_RDI_REGNUM)) return -1; - if (record_arch_list_add_reg (regcache, AMD64_R8_REGNUM)) + if (record_full_arch_list_add_reg (regcache, AMD64_R8_REGNUM)) return -1; - if (record_arch_list_add_reg (regcache, AMD64_R9_REGNUM)) + if (record_full_arch_list_add_reg (regcache, AMD64_R9_REGNUM)) return -1; - if (record_arch_list_add_reg (regcache, AMD64_R10_REGNUM)) + if (record_full_arch_list_add_reg (regcache, AMD64_R10_REGNUM)) return -1; - if (record_arch_list_add_reg (regcache, AMD64_R11_REGNUM)) + if (record_full_arch_list_add_reg (regcache, AMD64_R11_REGNUM)) return -1; - if (record_arch_list_add_reg (regcache, AMD64_R12_REGNUM)) + if (record_full_arch_list_add_reg (regcache, AMD64_R12_REGNUM)) return -1; - if (record_arch_list_add_reg (regcache, AMD64_R13_REGNUM)) + if (record_full_arch_list_add_reg (regcache, AMD64_R13_REGNUM)) return -1; - if (record_arch_list_add_reg (regcache, AMD64_R14_REGNUM)) + if (record_full_arch_list_add_reg (regcache, AMD64_R14_REGNUM)) return -1; - if (record_arch_list_add_reg (regcache, AMD64_R15_REGNUM)) + if (record_full_arch_list_add_reg (regcache, AMD64_R15_REGNUM)) return -1; - if (record_arch_list_add_reg (regcache, AMD64_EFLAGS_REGNUM)) + if (record_full_arch_list_add_reg (regcache, AMD64_EFLAGS_REGNUM)) return -1; return 0; @@ -1146,7 +1167,7 @@ amd64_canonicalize_syscall (enum amd64_syscall syscall_number) /* Parse the arguments of current system call instruction and record the values of the registers and memory that will be changed into - "record_arch_list". This instruction is "syscall". + "record_full_arch_list". This instruction is "syscall". Return -1 if something wrong. */ @@ -1185,8 +1206,8 @@ amd64_linux_syscall_record (struct regcache *regcache) regcache_raw_read_unsigned (regcache, amd64_linux_record_tdep.arg2, &addr); - if (record_arch_list_add_mem (addr, - amd64_linux_record_tdep.size_ulong)) + if (record_full_arch_list_add_mem + (addr, amd64_linux_record_tdep.size_ulong)) return -1; } goto record_regs; @@ -1213,9 +1234,9 @@ amd64_linux_syscall_record (struct regcache *regcache) record_regs: /* Record the return value of the system call. */ - if (record_arch_list_add_reg (regcache, AMD64_RCX_REGNUM)) + if (record_full_arch_list_add_reg (regcache, AMD64_RCX_REGNUM)) return -1; - if (record_arch_list_add_reg (regcache, AMD64_R11_REGNUM)) + if (record_full_arch_list_add_reg (regcache, AMD64_R11_REGNUM)) return -1; return 0; @@ -1225,17 +1246,17 @@ amd64_linux_syscall_record (struct regcache *regcache) #define AMD64_LINUX_xstate 512 #define AMD64_LINUX_frame_size 560 -int +static int amd64_linux_record_signal (struct gdbarch *gdbarch, struct regcache *regcache, - enum target_signal signal) + enum gdb_signal signal) { ULONGEST rsp; if (amd64_all_but_ip_registers_record (regcache)) return -1; - if (record_arch_list_add_reg (regcache, AMD64_RIP_REGNUM)) + if (record_full_arch_list_add_reg (regcache, AMD64_RIP_REGNUM)) return -1; /* Record the change in the stack. */ @@ -1249,12 +1270,12 @@ amd64_linux_record_signal (struct gdbarch *gdbarch, /* This is for frame_size. sp -= sizeof (struct rt_sigframe); */ rsp -= AMD64_LINUX_frame_size; - if (record_arch_list_add_mem (rsp, AMD64_LINUX_redzone + if (record_full_arch_list_add_mem (rsp, AMD64_LINUX_redzone + AMD64_LINUX_xstate + AMD64_LINUX_frame_size)) return -1; - if (record_arch_list_add_end ()) + if (record_full_arch_list_add_end ()) return -1; return 0; @@ -1268,52 +1289,35 @@ amd64_linux_core_read_description (struct gdbarch *gdbarch, bfd *abfd) { /* Linux/x86-64. */ - uint64_t xcr0 = i386_linux_core_read_xcr0 (gdbarch, target, abfd); - switch ((xcr0 & I386_XSTATE_AVX_MASK)) + uint64_t xcr0 = i386_linux_core_read_xcr0 (abfd); + + switch (xcr0 & I386_XSTATE_ALL_MASK) { + case I386_XSTATE_MPX_MASK: + if (gdbarch_ptr_bit (gdbarch) == 32) + return tdesc_x32_avx_linux; /* No x32 MPX falling back to AVX. */ + else + return tdesc_amd64_mpx_linux; case I386_XSTATE_AVX_MASK: - return tdesc_amd64_avx_linux; + if (gdbarch_ptr_bit (gdbarch) == 32) + return tdesc_x32_avx_linux; + else + return tdesc_amd64_avx_linux; default: - return tdesc_amd64_linux; + if (gdbarch_ptr_bit (gdbarch) == 32) + return tdesc_x32_linux; + else + return tdesc_amd64_linux; } } static void -amd64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) +amd64_linux_init_abi_common(struct gdbarch_info info, struct gdbarch *gdbarch) { struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); - const struct target_desc *tdesc = info.target_desc; - struct tdesc_arch_data *tdesc_data = (void *) info.tdep_info; - const struct tdesc_feature *feature; - int valid_p; - - gdb_assert (tdesc_data); linux_init_abi (info, gdbarch); - tdep->gregset_reg_offset = amd64_linux_gregset_reg_offset; - tdep->gregset_num_regs = ARRAY_SIZE (amd64_linux_gregset_reg_offset); - tdep->sizeof_gregset = 27 * 8; - - amd64_init_abi (info, gdbarch); - - /* Reserve a number for orig_rax. */ - set_gdbarch_num_regs (gdbarch, AMD64_LINUX_NUM_REGS); - - if (! tdesc_has_registers (tdesc)) - tdesc = tdesc_amd64_linux; - tdep->tdesc = tdesc; - - feature = tdesc_find_feature (tdesc, "org.gnu.gdb.i386.linux"); - if (feature == NULL) - return; - - valid_p = tdesc_numbered_register (feature, tdesc_data, - AMD64_LINUX_ORIG_RAX_REGNUM, - "orig_rax"); - if (!valid_p) - return; - tdep->sigtramp_p = amd64_linux_sigtramp_p; tdep->sigcontext_addr = amd64_linux_sigcontext_addr; tdep->sc_reg_offset = amd64_linux_sc_reg_offset; @@ -1321,10 +1325,6 @@ amd64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) tdep->xsave_xcr0_offset = I386_LINUX_XSAVE_XCR0_OFFSET; - /* GNU/Linux uses SVR4-style shared libraries. */ - 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); @@ -1342,6 +1342,9 @@ amd64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) /* GNU/Linux uses SVR4-style shared libraries. */ set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target); + /* GNU/Linux uses the dynamic linker included in the GNU C Library. */ + set_gdbarch_skip_solib_resolver (gdbarch, glibc_skip_solib_resolver); + /* Install supported register note sections. */ set_gdbarch_core_regset_sections (gdbarch, amd64_linux_regset_sections); @@ -1531,6 +1534,88 @@ amd64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) tdep->i386_syscall_record = amd64_linux_syscall_record; } + +static void +amd64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) +{ + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + const struct target_desc *tdesc = info.target_desc; + struct tdesc_arch_data *tdesc_data = (void *) info.tdep_info; + const struct tdesc_feature *feature; + int valid_p; + + gdb_assert (tdesc_data); + + tdep->gregset_reg_offset = amd64_linux_gregset_reg_offset; + tdep->gregset_num_regs = ARRAY_SIZE (amd64_linux_gregset_reg_offset); + tdep->sizeof_gregset = 27 * 8; + + amd64_init_abi (info, gdbarch); + + /* Reserve a number for orig_rax. */ + set_gdbarch_num_regs (gdbarch, AMD64_LINUX_NUM_REGS); + + if (! tdesc_has_registers (tdesc)) + tdesc = tdesc_amd64_linux; + tdep->tdesc = tdesc; + + feature = tdesc_find_feature (tdesc, "org.gnu.gdb.i386.linux"); + if (feature == NULL) + return; + + valid_p = tdesc_numbered_register (feature, tdesc_data, + AMD64_LINUX_ORIG_RAX_REGNUM, + "orig_rax"); + if (!valid_p) + return; + + amd64_linux_init_abi_common (info, gdbarch); + + /* GNU/Linux uses SVR4-style shared libraries. */ + set_solib_svr4_fetch_link_map_offsets + (gdbarch, svr4_lp64_fetch_link_map_offsets); +} + +static void +amd64_x32_linux_init_abi(struct gdbarch_info info, struct gdbarch *gdbarch) +{ + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + const struct target_desc *tdesc = info.target_desc; + struct tdesc_arch_data *tdesc_data = (void *) info.tdep_info; + const struct tdesc_feature *feature; + int valid_p; + + gdb_assert (tdesc_data); + + tdep->gregset_reg_offset = amd64_linux_gregset_reg_offset; + tdep->gregset_num_regs = ARRAY_SIZE (amd64_linux_gregset_reg_offset); + tdep->sizeof_gregset = 27 * 8; + + amd64_x32_init_abi (info, gdbarch); + + /* Reserve a number for orig_rax. */ + set_gdbarch_num_regs (gdbarch, AMD64_LINUX_NUM_REGS); + + if (! tdesc_has_registers (tdesc)) + tdesc = tdesc_x32_linux; + tdep->tdesc = tdesc; + + feature = tdesc_find_feature (tdesc, "org.gnu.gdb.i386.linux"); + if (feature == NULL) + return; + + valid_p = tdesc_numbered_register (feature, tdesc_data, + AMD64_LINUX_ORIG_RAX_REGNUM, + "orig_rax"); + if (!valid_p) + return; + + amd64_linux_init_abi_common (info, gdbarch); + + /* GNU/Linux uses SVR4-style shared libraries. */ + set_solib_svr4_fetch_link_map_offsets + (gdbarch, svr4_ilp32_fetch_link_map_offsets); +} /* Provide a prototype to silence -Wmissing-prototypes. */ @@ -1541,8 +1626,13 @@ _initialize_amd64_linux_tdep (void) { gdbarch_register_osabi (bfd_arch_i386, bfd_mach_x86_64, GDB_OSABI_LINUX, amd64_linux_init_abi); + gdbarch_register_osabi (bfd_arch_i386, bfd_mach_x64_32, + GDB_OSABI_LINUX, amd64_x32_linux_init_abi); /* Initialize the Linux target description. */ initialize_tdesc_amd64_linux (); initialize_tdesc_amd64_avx_linux (); + initialize_tdesc_amd64_mpx_linux (); + initialize_tdesc_x32_linux (); + initialize_tdesc_x32_avx_linux (); }