diff options
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); } |