diff options
author | Mark Kettenis <kettenis@gnu.org> | 2003-05-31 08:15:38 +0000 |
---|---|---|
committer | Mark Kettenis <kettenis@gnu.org> | 2003-05-31 08:15:38 +0000 |
commit | c4f35dd8e1037d2a8e1aa11894cb67de96279bfa (patch) | |
tree | fde4b39a640ec5c24ade4ec9c302e2425b305aed /gdb/x86-64-linux-nat.c | |
parent | f2c822e386797796f5f0436c86d2d08baf61e22a (diff) | |
download | gdb-c4f35dd8e1037d2a8e1aa11894cb67de96279bfa.zip gdb-c4f35dd8e1037d2a8e1aa11894cb67de96279bfa.tar.gz gdb-c4f35dd8e1037d2a8e1aa11894cb67de96279bfa.tar.bz2 |
* x86-64-tdep.h (x86_64_num_regs, x86_64_num_gregs): Remove
variable declarations.
(x86_64_register_number, x86_64_register_name): Remove prototypes.
(x86_64_linux_frame_saved_pc, x86_64_linux+saved_pc_after_call,
x86_64_linux_in_sigtramp, x86_64_linux_frame_chain,
x86_64_init_frame_pc, x86_64_init_frame_pc,
x86_64_function_has_prologue): Remove prototypes.
(X86_64_NUM_GREGS): New define.
(x86_64_supply_fxsave, x86_64_fill_fxsave): New prototypes.
* x86-64-tdep.c: Don't include "dwarf2cfi.h". Include
"dummy_frame.h", "frame.h", "frame-base.h", "frame-unwind.h".
(RAX_REGNUM, RDX_REGNUM, RDI_REGNUM, EFLAGS_REGNUM, ST0_REGNUM,
XMM1_REGNUM): Remove defines.
(X86_64_RAX_REGNUM, X86_64_RDX_REGNUM, X86_64_RDI_REGNUM,
X86_64_RBP_REGNUM, X86_64_RSP_REGNUM, X86_64_RIP_REGNUM,
X86_64_EFLAGS_REGNUM, X86_64_ST0_REGNUM, X86_64_XMM0_REGNUM,
X86_64_XMM1_REGNUM): New defines.
(struct x86_64_register_info): Renamed from `struct
register_info'. Remove `size' member.
(x86_64_register_info_table): Remove variable.
(x86_64_register_info): New variable.
(X86_64_NUM_REGS): New define.
(X86_64_NUM_GREGS): Remove define.
(x86_64_num_regs, x86_64_num_gregs): Remove variables.
(x86_64_dwarf2gdb_regno_map, x86_64_dwarf2gdb_regno_map_length):
Remove variables.
(x86_54_dwarf2_reg_to_regnum): Remove function.
(x86_64_dwarf_regmap, x86_64_dwarf_regmap_len): New variables.
(x86_64_dwarf_reg_to_regnum): New function.
(x86_64_register_name): Rewrite.
(x86_64_register_raw_size): Remove function.
(x86_64_register_byte_table): Remove variable.
(x86_64_register_byte): Remove function.
(x86_64_register_virtual_type): Remove function.
(x86_64_register_type): New function.
(x86_64_register_convertible, x86_64_register_convert_to_virtual,
x86_64_register_convert_to_raw): Remove functions.
(x86_64_push_return_address, x86_64_pop_frame): Remove functon.
(x86_64_use_struct_convention): Make static. Adjust for renamed
defines.
(x86_64_frame_init_saved_regs): Remove function.
(x86_64_push_arguments): Make static. Change to accept a regcache
as argument.
(x86_64_store_return_value, x86_64_extract_return_value): Make
static. Rewrite based on i386 counterparts.
(x86_64_push_dummy_call): New function.
(X86_64_NUM_SAVED_REGS): New define.
(x86_64_register_number): Remove function.
(x86_64_store_struct_return): Remove function.
(x86_64_frameless_function_invocation,
x86_64_function_has_prologue): Remove functions.
(PROLOG_BUFSIZE): Remove define.
(struct x86_64_frame_cache): New structure.
(x86_64_alloc_frame_cache, x86_64_analyze_prologue,
x86_64_frame_cache, x86_64_frame_this_id,
x86_64_frame_prev_register, x86_64_frame_p,
x86_64_sigtramp_frame_cache, x86_64_sigtramp_frame_this_id,
x86_64_sigtramp_frame_prev_register, x86_sigtramp_frame_p): New
functions.
(x86_64_frame_unwind, x86_64_sigtramp_frame_unwind): New
variables.
(x86_64_skip_prologue): Rewrite in terms of
x86_64_analyze_prologue.
(x86_64_frame_base_address): New function.
(x86_64_frame_base): New variable.
(x86_64_save_dummy_frame_tos, x86_64_unwind_dummy_id): Rewrite.
(x86_64_init_abi): Set register_type and push_dummy_call. Don't
set deprecated_fp_regnum, deprecated_register_size,
deprecated_register_bytes, register_raw_size, register_byte,
register_virtual_type, register_convertiable,
register_convert_to_virtual, convert_to_raw,
deprecated_get_saved_register, deprecated_target_read_fp,
deprecated_push_arguments, deprecated_push_return_address,
deprecated_pop_frame, deprecated_store_struct_return,
deprecated_frame_init_saved_regs, deprecated_frame_chain,
frameless_function_invocation, deprecated_frame_saved_pc,
deprecated_saved_pc_after_call, frame_num_args, pc_in_sigtramp,
dwarf2_build_frame_info, deprecated_init_extra_frame_info,
deprecated_init_frame_pc and virtual_frame_pointer. Call
frame_unwind_append_predicate to register x86_64_sigtramp_frame_p
and x86_64_frame_p. Call frame_base_set_default to register
x86_64_frame_base.
(I387_FISEG_REGNUM, I387_FOSEG_REGNUM): New defines.
(x86_64_supply_fxsave, x86_64_fill_fxsave): New functions.
(_initialize_x86_64_tdep): Remove function.
* x86-64-linux-tdep.c: Don't include "dwarf2cfi.h".
(LINUX_SIGINFO_SIZE, LINUX_UCONTEXT_SIGCONTEXT_OFFSET,
LINUX_SIGCONTEXT_PC_OFFSET, LINUX_SIGCONTEXT_FP_OFFSET): Don't
define.
(X86_64_LINUX_UCONTEXT_SIGCONTEXT_OFFSET): Define.
(x86_64_linux_sigcontext_addr): Rewrite.
(x86_64_linux_sigtramp_saved_pc, x86_64_linux_saved_pc_after_call,
x86_64_linux_frame_saved_pc): Remove functions.
(x86_64_linux_pc_in_sigtramp): Renamed from
x86_64_linux_in_sigtramp. Try harder to recognize a signal
trampoline.
(x86_64_linux_frame_chain, x86_64_init_frame_pc):
Remove_functions.
(x86_64_linux_init_abi): Set pc_in_sigtramp. Initialize
TDEP->sigcontext_addr, TDEP->sc_pc_offset and TDEP->sc_sp_offset.
* x86-64-linux-nat.c: Sync with i386-linux-tdep.c.
(x86_64_regmap): Rename to regmap.
(GETREGS_SUPPLIES): Use X86_64_NUM_GREGS instead of
x86_64_num_gregs.
(supply_gregset, fill_gregset): Likewise. Use regmap instead of
x86_64_regmap.
(x86_64_fxsave_offset): Remove function.
(supply_fpregset): Simply call x86_64_supply_fxsave.
(fill_fpregset): Simply call x86_64_fill_fxsave.
(fetch_inferior_registers, store_inferior_registers): Avoid
asignment in if-statement.
(LINUX_SYSCALL_LEN, LINUX_SYSCALL_REGNUM, SYS_Sigreturn,
SYS_rt_sigreturn, LINUX_SIGCONTEXT_EFLAGS_OFFSET,
LINUX_UCONTEXT_SIGCONTEXT_OFFSET): Remove defines.
(fetch_core_registers): Remove function.
(linux_elf_core_fns): Remove.
(offsetoff): Don't define.
(_initialize_x86_64_linux_nat, kernel_u_size): Remove functions.
* config/i386/x86-64linux.mt (TDEPFILES): Add i386-linux-tdep.o.
* config/i386/x86-64linux.mh (NATDEPFILES): Remove core-aout.o,
add core-regset.o.
* config/i386/nm-x86-64linux.h: Use NM_X86_64_LINUX_H for
protection against multiple includes instead of NM_X86_64_h. Add
various comments. Include "config/nm-linux.h". Don't include
<signal.h>.
(REGISTER_U_ADDR, KERNEL_U_SIZE, U_REGS_OFFSET, KERN_U_ADDR,
GET_THREAD_SIGNALS): Remove defines.
(x86_64_register_u_addr, kernel_u_size,
lin_thread_get_thread_signals): Remove prototypes.
(PTRACE_ARG3_TYPE, PTRACE_XFER_TYPE): Define to `long'.
[HAVE_LINK_H]: Don't include "solib.h".
[HAVE_LINK_H] (SVR4_SHARED_LIBS): Remove define.
* config/i386/tm-x86-64linux.h: Fix comments.
* Makefile.in (x86-64-linux-nat.o, x86_64-linux-tdep.o,
x86-64-tdep.o): Update dependencies.
Diffstat (limited to 'gdb/x86-64-linux-nat.c')
-rw-r--r-- | gdb/x86-64-linux-nat.c | 342 |
1 files changed, 92 insertions, 250 deletions
diff --git a/gdb/x86-64-linux-nat.c b/gdb/x86-64-linux-nat.c index 044236c..1200b08 100644 --- a/gdb/x86-64-linux-nat.c +++ b/gdb/x86-64-linux-nat.c @@ -25,20 +25,30 @@ #include "inferior.h" #include "gdbcore.h" #include "regcache.h" + #include "gdb_assert.h" #include "gdb_string.h" -#include "x86-64-tdep.h" - #include <sys/ptrace.h> #include <sys/debugreg.h> #include <sys/syscall.h> #include <sys/procfs.h> #include <sys/reg.h> +/* Prototypes for supply_gregset etc. */ +#include "gregset.h" + +#include "x86-64-tdep.h" + +/* The register sets used in GNU/Linux ELF core-dumps are identical to + the register sets used by `ptrace'. The corresponding types are + `elf_gregset_t' for the general-purpose registers (with + `elf_greg_t' the type of a single GP register) and `elf_fpregset_t' + for the floating-point registers. + /* Mapping between the general-purpose registers in `struct user' format and GDB's register array layout. */ - -static int x86_64_regmap[] = { +static int regmap[] = +{ RAX, RBX, RCX, RDX, RSI, RDI, RBP, RSP, R8, R9, R10, R11, @@ -47,85 +57,12 @@ static int x86_64_regmap[] = { DS, ES, FS, GS }; -static unsigned long -x86_64_linux_dr_get (int regnum) -{ - int tid; - unsigned long value; - - /* FIXME: kettenis/2001-01-29: It's not clear what we should do with - multi-threaded processes here. For now, pretend there is just - one thread. */ - tid = PIDGET (inferior_ptid); - - /* FIXME: kettenis/2001-03-27: Calling perror_with_name if the - ptrace call fails breaks debugging remote targets. The correct - way to fix this is to add the hardware breakpoint and watchpoint - stuff to the target vectore. For now, just return zero if the - ptrace call fails. */ - errno = 0; - value = ptrace (PT_READ_U, tid, - offsetof (struct user, u_debugreg[regnum]), 0); - if (errno != 0) -#if 0 - perror_with_name ("Couldn't read debug register"); -#else - return 0; -#endif - - return value; -} - -static void -x86_64_linux_dr_set (int regnum, unsigned long value) -{ - int tid; - - /* FIXME: kettenis/2001-01-29: It's not clear what we should do with - multi-threaded processes here. For now, pretend there is just - one thread. */ - tid = PIDGET (inferior_ptid); - - errno = 0; - ptrace (PT_WRITE_U, tid, offsetof (struct user, u_debugreg[regnum]), value); - if (errno != 0) - perror_with_name ("Couldn't write debug register"); -} - -void -x86_64_linux_dr_set_control (unsigned long control) -{ - x86_64_linux_dr_set (DR_CONTROL, control); -} - -void -x86_64_linux_dr_set_addr (int regnum, CORE_ADDR addr) -{ - gdb_assert (regnum >= 0 && regnum <= DR_LASTADDR - DR_FIRSTADDR); - - x86_64_linux_dr_set (DR_FIRSTADDR + regnum, addr); -} - -void -x86_64_linux_dr_reset_addr (int regnum) -{ - gdb_assert (regnum >= 0 && regnum <= DR_LASTADDR - DR_FIRSTADDR); - - x86_64_linux_dr_set (DR_FIRSTADDR + regnum, 0L); -} - -unsigned long -x86_64_linux_dr_get_status (void) -{ - return x86_64_linux_dr_get (DR_STATUS); -} - - -/* The register sets used in GNU/Linux ELF core-dumps are identical to - the register sets used by `ptrace'. */ +/* Which ptrace request retrieves which registers? + These apply to the corresponding SET requests as well. */ #define GETREGS_SUPPLIES(regno) \ - (0 <= (regno) && (regno) < x86_64_num_gregs) + (0 <= (regno) && (regno) < X86_64_NUM_GREGS) + #define GETFPREGS_SUPPLIES(regno) \ (FP0_REGNUM <= (regno) && (regno) <= MXCSR_REGNUM) @@ -137,13 +74,13 @@ x86_64_linux_dr_get_status (void) in *GREGSETP. */ void -supply_gregset (elf_gregset_t * gregsetp) +supply_gregset (elf_gregset_t *gregsetp) { elf_greg_t *regp = (elf_greg_t *) gregsetp; int i; - for (i = 0; i < x86_64_num_gregs; i++) - supply_register (i, (char *) (regp + x86_64_regmap[i])); + for (i = 0; i < X86_64_NUM_GREGS; i++) + supply_register (i, regp + regmap[i]); } /* Fill register REGNO (if it is a general-purpose register) in @@ -151,14 +88,14 @@ supply_gregset (elf_gregset_t * gregsetp) do this for all registers. */ void -fill_gregset (elf_gregset_t * gregsetp, int regno) +fill_gregset (elf_gregset_t *gregsetp, int regno) { elf_greg_t *regp = (elf_greg_t *) gregsetp; int i; - for (i = 0; i < x86_64_num_gregs; i++) - if ((regno == -1 || regno == i)) - regcache_collect (i, (char *) (regp + x86_64_regmap[i])); + for (i = 0; i < X86_64_NUM_GREGS; i++) + if (regno == -1 || regno == i) + regcache_collect (i, regp + regmap[i]); } /* Fetch all general-purpose registers from process/thread TID and @@ -195,73 +132,23 @@ store_regs (int tid, int regno) /* Transfering floating-point registers between GDB, inferiors and cores. */ -static void * -x86_64_fxsave_offset (elf_fpregset_t * fxsave, int regnum) -{ - const char *reg_name; - int reg_index; - - gdb_assert (x86_64_num_gregs - 1 < regnum && regnum < x86_64_num_regs); - - reg_name = x86_64_register_name (regnum); - - if (reg_name[0] == 's' && reg_name[1] == 't') - { - reg_index = reg_name[2] - '0'; - return &fxsave->st_space[reg_index * 2]; - } - - if (reg_name[0] == 'x' && reg_name[1] == 'm' && reg_name[2] == 'm') - { - reg_index = reg_name[3] - '0'; - return &fxsave->xmm_space[reg_index * 4]; - } - - if (strcmp (reg_name, "mxcsr") == 0) - return &fxsave->mxcsr; - - return NULL; -} - /* Fill GDB's register array with the floating-point and SSE register - values in *FXSAVE. This function masks off any of the reserved - bits in *FXSAVE. */ + values in *FPREGSETP. */ void -supply_fpregset (elf_fpregset_t * fxsave) +supply_fpregset (elf_fpregset_t *fpregsetp) { - int i, reg_st0, reg_mxcsr; - - reg_st0 = x86_64_register_number ("st0"); - reg_mxcsr = x86_64_register_number ("mxcsr"); - - gdb_assert (reg_st0 > 0 && reg_mxcsr > reg_st0); - - for (i = reg_st0; i <= reg_mxcsr; i++) - supply_register (i, x86_64_fxsave_offset (fxsave, i)); + x86_64_supply_fxsave ((char *) fpregsetp); } /* Fill register REGNUM (if it is a floating-point or SSE register) in - *FXSAVE with the value in GDB's register array. If REGNUM is -1, do - this for all registers. This function doesn't touch any of the - reserved bits in *FXSAVE. */ + *FPREGSETP with the value in GDB's register array. If REGNUM is + -1, do this for all registers. */ void -fill_fpregset (elf_fpregset_t * fxsave, int regnum) +fill_fpregset (elf_fpregset_t *fpregsetp, int regnum) { - int i, last_regnum = MXCSR_REGNUM; - void *ptr; - - if (gdbarch_tdep (current_gdbarch)->num_xmm_regs == 0) - last_regnum = FOP_REGNUM; - - for (i = FP0_REGNUM; i <= last_regnum; i++) - if (regnum == -1 || regnum == i) - { - ptr = x86_64_fxsave_offset (fxsave, i); - if (ptr) - regcache_collect (i, ptr); - } + x86_64_fill_fxsave ((char *) fpregsetp, regnum); } /* Fetch all floating-point registers from process/thread TID and store @@ -308,8 +195,9 @@ fetch_inferior_registers (int regno) int tid; /* GNU/Linux LWP ID's are process ID's. */ - if ((tid = TIDGET (inferior_ptid)) == 0) - tid = PIDGET (inferior_ptid); /* Not a threaded program. */ + tid = TIDGET (inferior_ptid); + if (tid == 0) + tid = PIDGET (inferior_ptid); /* Not a threaded program. */ if (regno == -1) { @@ -335,16 +223,18 @@ fetch_inferior_registers (int regno) } /* Store register REGNO back into the child process. If REGNO is -1, - do this for all registers (including the floating point and SSE + do this for all registers (including the floating-point and SSE registers). */ + void store_inferior_registers (int regno) { int tid; /* GNU/Linux LWP ID's are process ID's. */ - if ((tid = TIDGET (inferior_ptid)) == 0) - tid = PIDGET (inferior_ptid); /* Not a threaded program. */ + tid = TIDGET (inferior_ptid); + if (tid == 0) + tid = PIDGET (inferior_ptid); /* Not a threaded program. */ if (regno == -1) { @@ -370,123 +260,75 @@ store_inferior_registers (int regno) } -static const unsigned char linux_syscall[] = { 0x0f, 0x05 }; - -#define LINUX_SYSCALL_LEN (sizeof linux_syscall) - -/* The system call number is stored in the %rax register. */ -#define LINUX_SYSCALL_REGNUM 0 /* %rax */ +static unsigned long +x86_64_linux_dr_get (int regnum) +{ + int tid; + unsigned long value; -/* We are specifically interested in the sigreturn and rt_sigreturn - system calls. */ + /* FIXME: kettenis/2001-01-29: It's not clear what we should do with + multi-threaded processes here. For now, pretend there is just + one thread. */ + tid = PIDGET (inferior_ptid); -#ifndef SYS_sigreturn -#define SYS_sigreturn __NR_sigreturn -#endif -#ifndef SYS_rt_sigreturn -#define SYS_rt_sigreturn __NR_rt_sigreturn + /* FIXME: kettenis/2001-03-27: Calling perror_with_name if the + ptrace call fails breaks debugging remote targets. The correct + way to fix this is to add the hardware breakpoint and watchpoint + stuff to the target vectore. For now, just return zero if the + ptrace call fails. */ + errno = 0; + value = ptrace (PT_READ_U, tid, + offsetof (struct user, u_debugreg[regnum]), 0); + if (errno != 0) +#if 0 + perror_with_name ("Couldn't read debug register"); +#else + return 0; #endif -/* Offset to saved processor flags, from <asm/sigcontext.h>. */ -#define LINUX_SIGCONTEXT_EFLAGS_OFFSET (152) -/* Offset to saved processor registers from <asm/ucontext.h> */ -#define LINUX_UCONTEXT_SIGCONTEXT_OFFSET (36) - -/* Interpreting register set info found in core files. */ -/* Provide registers to GDB from a core file. - - CORE_REG_SECT points to an array of bytes, which are the contents - of a `note' from a core file which BFD thinks might contain - register contents. CORE_REG_SIZE is its size. - - WHICH says which register set corelow suspects this is: - 0 --- the general-purpose register set, in elf_gregset_t format - 2 --- the floating-point register set, in elf_fpregset_t format - - REG_ADDR isn't used on GNU/Linux. */ + return value; +} static void -fetch_core_registers (char *core_reg_sect, unsigned core_reg_size, - int which, CORE_ADDR reg_addr) +x86_64_linux_dr_set (int regnum, unsigned long value) { - elf_gregset_t gregset; - elf_fpregset_t fpregset; - switch (which) - { - case 0: - if (core_reg_size != sizeof (gregset)) - warning ("Wrong size gregset in core file."); - else - { - memcpy (&gregset, core_reg_sect, sizeof (gregset)); - supply_gregset (&gregset); - } - break; - - case 2: - if (core_reg_size != sizeof (fpregset)) - warning ("Wrong size fpregset in core file."); - else - { - memcpy (&fpregset, core_reg_sect, sizeof (fpregset)); - supply_fpregset (&fpregset); - } - break; - - default: - /* We've covered all the kinds of registers we know about here, - so this must be something we wouldn't know what to do with - anyway. Just ignore it. */ - break; - } -} + int tid; -/* Register that we are able to handle GNU/Linux ELF core file formats. */ + /* FIXME: kettenis/2001-01-29: It's not clear what we should do with + multi-threaded processes here. For now, pretend there is just + one thread. */ + tid = PIDGET (inferior_ptid); -static struct core_fns linux_elf_core_fns = { - bfd_target_elf_flavour, /* core_flavour */ - default_check_format, /* check_format */ - default_core_sniffer, /* core_sniffer */ - fetch_core_registers, /* core_read_registers */ - NULL /* next */ -}; - + errno = 0; + ptrace (PT_WRITE_U, tid, offsetof (struct user, u_debugreg[regnum]), value); + if (errno != 0) + perror_with_name ("Couldn't write debug register"); +} -#if !defined (offsetof) -#define offsetof(TYPE, MEMBER) ((unsigned long) &((TYPE *)0)->MEMBER) -#endif +void +x86_64_linux_dr_set_control (unsigned long control) +{ + x86_64_linux_dr_set (DR_CONTROL, control); +} -/* Return the address of register REGNUM. BLOCKEND is the value of - u.u_ar0, which should point to the registers. */ -CORE_ADDR -x86_64_register_u_addr (CORE_ADDR blockend, int regnum) +void +x86_64_linux_dr_set_addr (int regnum, CORE_ADDR addr) { - struct user u; - CORE_ADDR fpstate; - CORE_ADDR ubase; - ubase = blockend; - if (IS_FP_REGNUM (regnum)) - { - fpstate = ubase + ((char *) &u.i387.st_space - (char *) &u); - return (fpstate + 16 * (regnum - FP0_REGNUM)); - } - else if (IS_SSE_REGNUM (regnum)) - { - fpstate = ubase + ((char *) &u.i387.xmm_space - (char *) &u); - return (fpstate + 16 * (regnum - XMM0_REGNUM)); - } - else - return (ubase + 8 * x86_64_regmap[regnum]); + gdb_assert (regnum >= 0 && regnum <= DR_LASTADDR - DR_FIRSTADDR); + + x86_64_linux_dr_set (DR_FIRSTADDR + regnum, addr); } void -_initialize_x86_64_linux_nat (void) +x86_64_linux_dr_reset_addr (int regnum) { - add_core_fns (&linux_elf_core_fns); + gdb_assert (regnum >= 0 && regnum <= DR_LASTADDR - DR_FIRSTADDR); + + x86_64_linux_dr_set (DR_FIRSTADDR + regnum, 0L); } -int -kernel_u_size (void) +unsigned long +x86_64_linux_dr_get_status (void) { - return (sizeof (struct user)); + return x86_64_linux_dr_get (DR_STATUS); } |