X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gdb%2Fi386-linux-tdep.c;h=1a2e4f0a0124420c2e71591de39876b51a9cd00a;hb=4aa995e123f47a4aca553ae4ed4fdebe2d00e316;hp=9574c69302a08f8a0b8d914633c783a491de2f51;hpb=5cb2fe259cab194fd68b4d1e6736f7054b15790c;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/i386-linux-tdep.c b/gdb/i386-linux-tdep.c index 9574c69302..1a2e4f0a01 100644 --- a/gdb/i386-linux-tdep.c +++ b/gdb/i386-linux-tdep.c @@ -1,12 +1,13 @@ /* Target-dependent code for GNU/Linux i386. - Copyright 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc. + Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008, 2009 + Free Software Foundation, Inc. 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, @@ -15,9 +16,7 @@ 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., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. */ + along with this program. If not, see . */ #include "defs.h" #include "gdbcore.h" @@ -32,19 +31,32 @@ #include "i386-tdep.h" #include "i386-linux-tdep.h" +#include "linux-tdep.h" #include "glibc-tdep.h" #include "solib-svr4.h" +#include "symtab.h" +#include "arch-utils.h" +#include "regset.h" + +/* Supported register note sections. */ +static struct core_regset_section i386_linux_regset_sections[] = +{ + { ".reg", 144 }, + { ".reg2", 108 }, + { ".reg-xfp", 512 }, + { NULL, 0 } +}; /* Return the name of register REG. */ static const char * -i386_linux_register_name (int reg) +i386_linux_register_name (struct gdbarch *gdbarch, int reg) { /* Deal with the extra "orig_eax" pseudo register. */ if (reg == I386_LINUX_ORIG_EAX_REGNUM) return "orig_eax"; - return i386_register_name (reg); + return i386_register_name (gdbarch, reg); } /* Return non-zero, when the register is in the corresponding register @@ -106,7 +118,7 @@ i386_linux_register_reggroup_p (struct gdbarch *gdbarch, int regnum, #define LINUX_SIGTRAMP_INSN2 0xcd /* int */ #define LINUX_SIGTRAMP_OFFSET2 6 -static const unsigned char linux_sigtramp_code[] = +static const gdb_byte linux_sigtramp_code[] = { LINUX_SIGTRAMP_INSN0, /* pop %eax */ LINUX_SIGTRAMP_INSN1, 0x77, 0x00, 0x00, 0x00, /* mov $0x77, %eax */ @@ -115,14 +127,14 @@ static const unsigned char linux_sigtramp_code[] = #define LINUX_SIGTRAMP_LEN (sizeof linux_sigtramp_code) -/* If NEXT_FRAME unwinds into a sigtramp routine, return the address - of the start of the routine. Otherwise, return 0. */ +/* If THIS_FRAME is a sigtramp routine, return the address of the + start of the routine. Otherwise, return 0. */ static CORE_ADDR -i386_linux_sigtramp_start (struct frame_info *next_frame) +i386_linux_sigtramp_start (struct frame_info *this_frame) { - CORE_ADDR pc = frame_pc_unwind (next_frame); - unsigned char buf[LINUX_SIGTRAMP_LEN]; + 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 one of the three instructions. We optimize for finding the PC at @@ -131,7 +143,7 @@ i386_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, LINUX_SIGTRAMP_LEN)) + if (!safe_frame_unwind_memory (this_frame, pc, buf, LINUX_SIGTRAMP_LEN)) return 0; if (buf[0] != LINUX_SIGTRAMP_INSN0) @@ -152,7 +164,7 @@ i386_linux_sigtramp_start (struct frame_info *next_frame) pc -= adjust; - if (!safe_frame_unwind_memory (next_frame, pc, buf, LINUX_SIGTRAMP_LEN)) + if (!safe_frame_unwind_memory (this_frame, pc, buf, LINUX_SIGTRAMP_LEN)) return 0; } @@ -175,7 +187,7 @@ i386_linux_sigtramp_start (struct frame_info *next_frame) #define LINUX_RT_SIGTRAMP_INSN1 0xcd /* int */ #define LINUX_RT_SIGTRAMP_OFFSET1 5 -static const unsigned char linux_rt_sigtramp_code[] = +static const gdb_byte linux_rt_sigtramp_code[] = { LINUX_RT_SIGTRAMP_INSN0, 0xad, 0x00, 0x00, 0x00, /* mov $0xad, %eax */ LINUX_RT_SIGTRAMP_INSN1, 0x80 /* int $0x80 */ @@ -183,14 +195,14 @@ static const unsigned char linux_rt_sigtramp_code[] = #define LINUX_RT_SIGTRAMP_LEN (sizeof linux_rt_sigtramp_code) -/* If NEXT_FRAME unwinds into an RT sigtramp routine, return the - address of the start of the routine. Otherwise, return 0. */ +/* If THIS_FRAME is an RT sigtramp routine, return the address of the + start of the routine. Otherwise, return 0. */ static CORE_ADDR -i386_linux_rt_sigtramp_start (struct frame_info *next_frame) +i386_linux_rt_sigtramp_start (struct frame_info *this_frame) { - CORE_ADDR pc = frame_pc_unwind (next_frame); - unsigned char buf[LINUX_RT_SIGTRAMP_LEN]; + CORE_ADDR pc = get_frame_pc (this_frame); + gdb_byte buf[LINUX_RT_SIGTRAMP_LEN]; /* We only recognize a signal trampoline if PC is at the start of one of the two instructions. We optimize for finding the PC at @@ -199,7 +211,7 @@ i386_linux_rt_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, LINUX_RT_SIGTRAMP_LEN)) + if (!safe_frame_unwind_memory (this_frame, pc, buf, LINUX_RT_SIGTRAMP_LEN)) return 0; if (buf[0] != LINUX_RT_SIGTRAMP_INSN0) @@ -209,7 +221,7 @@ i386_linux_rt_sigtramp_start (struct frame_info *next_frame) pc -= LINUX_RT_SIGTRAMP_OFFSET1; - if (!safe_frame_unwind_memory (next_frame, pc, buf, + if (!safe_frame_unwind_memory (this_frame, pc, buf, LINUX_RT_SIGTRAMP_LEN)) return 0; } @@ -220,13 +232,13 @@ i386_linux_rt_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 -i386_linux_sigtramp_p (struct frame_info *next_frame) +i386_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); @@ -237,21 +249,21 @@ i386_linux_sigtramp_p (struct frame_info *next_frame) be part of the preceding function. This should always be sigaction, __sigaction, or __libc_sigaction (all aliases to the same function). */ if (name == NULL || strstr (name, "sigaction") != NULL) - return (i386_linux_sigtramp_start (next_frame) != 0 - || i386_linux_rt_sigtramp_start (next_frame) != 0); + return (i386_linux_sigtramp_start (this_frame) != 0 + || i386_linux_rt_sigtramp_start (this_frame) != 0); return (strcmp ("__restore", name) == 0 || strcmp ("__restore_rt", name) == 0); } -/* Return one if the unwound PC from NEXT_FRAME is in a signal trampoline - which may have DWARF-2 CFI. */ +/* Return one if the PC of THIS_FRAME is in a signal trampoline which + may have DWARF-2 CFI. */ static int i386_linux_dwarf_signal_frame_p (struct gdbarch *gdbarch, - struct frame_info *next_frame) + 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); @@ -268,20 +280,20 @@ i386_linux_dwarf_signal_frame_p (struct gdbarch *gdbarch, /* Offset to struct sigcontext in ucontext, from . */ #define I386_LINUX_UCONTEXT_SIGCONTEXT_OFFSET 20 -/* 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 -i386_linux_sigcontext_addr (struct frame_info *next_frame) +i386_linux_sigcontext_addr (struct frame_info *this_frame) { CORE_ADDR pc; CORE_ADDR sp; - char buf[4]; + gdb_byte buf[4]; - frame_unwind_register (next_frame, I386_ESP_REGNUM, buf); + get_frame_register (this_frame, I386_ESP_REGNUM, buf); sp = extract_unsigned_integer (buf, 4); - pc = i386_linux_sigtramp_start (next_frame); + pc = i386_linux_sigtramp_start (this_frame); if (pc) { /* The sigcontext structure lives on the stack, right after @@ -290,12 +302,12 @@ i386_linux_sigcontext_addr (struct frame_info *next_frame) pointer. Keep in mind that the first instruction of the sigtramp code is "pop %eax". If the PC is after this instruction, adjust the returned value accordingly. */ - if (pc == frame_pc_unwind (next_frame)) + if (pc == get_frame_pc (this_frame)) return sp + 4; return sp; } - pc = i386_linux_rt_sigtramp_start (next_frame); + pc = i386_linux_rt_sigtramp_start (this_frame); if (pc) { CORE_ADDR ucontext_addr; @@ -308,16 +320,16 @@ i386_linux_sigcontext_addr (struct frame_info *next_frame) return ucontext_addr + I386_LINUX_UCONTEXT_SIGCONTEXT_OFFSET; } - error ("Couldn't recognize signal trampoline."); + error (_("Couldn't recognize signal trampoline.")); return 0; } /* Set the program counter for process PTID to PC. */ static void -i386_linux_write_pc (CORE_ADDR pc, ptid_t ptid) +i386_linux_write_pc (struct regcache *regcache, CORE_ADDR pc) { - write_register_pid (I386_EIP_REGNUM, pc, ptid); + regcache_cooked_write_unsigned (regcache, I386_EIP_REGNUM, pc); /* We must be careful with modifying the program counter. If we just interrupted a system call, the kernel might try to restart @@ -333,7 +345,7 @@ i386_linux_write_pc (CORE_ADDR pc, ptid_t ptid) 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. */ - write_register_pid (I386_LINUX_ORIG_EAX_REGNUM, -1, ptid); + regcache_cooked_write_unsigned (regcache, I386_LINUX_ORIG_EAX_REGNUM, -1); } @@ -429,7 +441,12 @@ i386_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) tdep->sc_reg_offset = i386_linux_sc_reg_offset; tdep->sc_num_regs = ARRAY_SIZE (i386_linux_sc_reg_offset); + /* N_FUN symbols in shared libaries have 0 for their values and need + to be relocated. */ + set_gdbarch_sofun_address_maybe_missing (gdbarch, 1); + /* GNU/Linux uses SVR4-style shared libraries. */ + set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target); set_solib_svr4_fetch_link_map_offsets (gdbarch, svr4_ilp32_fetch_link_map_offsets); @@ -437,6 +454,24 @@ i386_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) set_gdbarch_skip_solib_resolver (gdbarch, glibc_skip_solib_resolver); dwarf2_frame_set_signal_frame_p (gdbarch, i386_linux_dwarf_signal_frame_p); + + /* Enable TLS support. */ + set_gdbarch_fetch_tls_load_module_address (gdbarch, + svr4_fetch_objfile_link_map); + + /* Install supported register note sections. */ + set_gdbarch_core_regset_sections (gdbarch, i386_linux_regset_sections); + + /* Displaced stepping. */ + set_gdbarch_displaced_step_copy_insn (gdbarch, + simple_displaced_step_copy_insn); + set_gdbarch_displaced_step_fixup (gdbarch, i386_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); } /* Provide a prototype to silence -Wmissing-prototypes. */