gdb/i386-linux-nat.c - gdb
Global variables defined
Functions defined
Macros defined
Source code
- #include "defs.h"
- #include "inferior.h"
- #include "gdbcore.h"
- #include "regcache.h"
- #include "elf/common.h"
- #include <sys/ptrace.h>
- #include <sys/uio.h>
- #include "gregset.h"
- #include "gdb_proc_service.h"
- #include "i386-linux-nat.h"
- #include "i387-tdep.h"
- #include "i386-tdep.h"
- #include "i386-linux-tdep.h"
- #include "x86-xstate.h"
- #include "x86-linux-nat.h"
- #define GETREGS_SUPPLIES(regno) \
- ((0 <= (regno) && (regno) <= 15) || (regno) == I386_LINUX_ORIG_EAX_REGNUM)
- #define GETFPXREGS_SUPPLIES(regno) \
- (I386_ST0_REGNUM <= (regno) && (regno) < I386_SSE_NUM_REGS)
- #define GETXSTATEREGS_SUPPLIES(regno) \
- (I386_ST0_REGNUM <= (regno) && (regno) < I386_AVX512_NUM_REGS)
- int have_ptrace_getregs =
- #ifdef HAVE_PTRACE_GETREGS
- 1
- #else
- 0
- #endif
- ;
- int have_ptrace_getfpxregs =
- #ifdef HAVE_PTRACE_GETFPXREGS
- -1
- #else
- 0
- #endif
- ;
- static void
- fetch_register (struct regcache *regcache, int regno)
- {
- int tid;
- int val;
- gdb_assert (!have_ptrace_getregs);
- if (i386_linux_gregset_reg_offset[regno] == -1)
- {
- regcache_raw_supply (regcache, regno, NULL);
- return;
- }
-
- tid = ptid_get_lwp (inferior_ptid);
- if (tid == 0)
- tid = ptid_get_pid (inferior_ptid);
- errno = 0;
- val = ptrace (PTRACE_PEEKUSER, tid,
- i386_linux_gregset_reg_offset[regno], 0);
- if (errno != 0)
- error (_("Couldn't read register %s (#%d): %s."),
- gdbarch_register_name (get_regcache_arch (regcache), regno),
- regno, safe_strerror (errno));
- regcache_raw_supply (regcache, regno, &val);
- }
- static void
- store_register (const struct regcache *regcache, int regno)
- {
- int tid;
- int val;
- gdb_assert (!have_ptrace_getregs);
- if (i386_linux_gregset_reg_offset[regno] == -1)
- return;
-
- tid = ptid_get_lwp (inferior_ptid);
- if (tid == 0)
- tid = ptid_get_pid (inferior_ptid);
- errno = 0;
- regcache_raw_collect (regcache, regno, &val);
- ptrace (PTRACE_POKEUSER, tid,
- i386_linux_gregset_reg_offset[regno], val);
- if (errno != 0)
- error (_("Couldn't write register %s (#%d): %s."),
- gdbarch_register_name (get_regcache_arch (regcache), regno),
- regno, safe_strerror (errno));
- }
- void
- supply_gregset (struct regcache *regcache, const elf_gregset_t *gregsetp)
- {
- const gdb_byte *regp = (const gdb_byte *) gregsetp;
- int i;
- for (i = 0; i < I386_NUM_GREGS; i++)
- regcache_raw_supply (regcache, i,
- regp + i386_linux_gregset_reg_offset[i]);
- if (I386_LINUX_ORIG_EAX_REGNUM
- < gdbarch_num_regs (get_regcache_arch (regcache)))
- regcache_raw_supply (regcache, I386_LINUX_ORIG_EAX_REGNUM, regp
- + i386_linux_gregset_reg_offset[I386_LINUX_ORIG_EAX_REGNUM]);
- }
- void
- fill_gregset (const struct regcache *regcache,
- elf_gregset_t *gregsetp, int regno)
- {
- gdb_byte *regp = (gdb_byte *) gregsetp;
- int i;
- for (i = 0; i < I386_NUM_GREGS; i++)
- if (regno == -1 || regno == i)
- regcache_raw_collect (regcache, i,
- regp + i386_linux_gregset_reg_offset[i]);
- if ((regno == -1 || regno == I386_LINUX_ORIG_EAX_REGNUM)
- && I386_LINUX_ORIG_EAX_REGNUM
- < gdbarch_num_regs (get_regcache_arch (regcache)))
- regcache_raw_collect (regcache, I386_LINUX_ORIG_EAX_REGNUM, regp
- + i386_linux_gregset_reg_offset[I386_LINUX_ORIG_EAX_REGNUM]);
- }
- #ifdef HAVE_PTRACE_GETREGS
- static void
- fetch_regs (struct regcache *regcache, int tid)
- {
- elf_gregset_t regs;
- elf_gregset_t *regs_p = ®s;
- if (ptrace (PTRACE_GETREGS, tid, 0, (int) ®s) < 0)
- {
- if (errno == EIO)
- {
-
- have_ptrace_getregs = 0;
- return;
- }
- perror_with_name (_("Couldn't get registers"));
- }
- supply_gregset (regcache, (const elf_gregset_t *) regs_p);
- }
- static void
- store_regs (const struct regcache *regcache, int tid, int regno)
- {
- elf_gregset_t regs;
- if (ptrace (PTRACE_GETREGS, tid, 0, (int) ®s) < 0)
- perror_with_name (_("Couldn't get registers"));
- fill_gregset (regcache, ®s, regno);
- if (ptrace (PTRACE_SETREGS, tid, 0, (int) ®s) < 0)
- perror_with_name (_("Couldn't write registers"));
- }
- #else
- static void fetch_regs (struct regcache *regcache, int tid) {}
- static void store_regs (const struct regcache *regcache, int tid, int regno) {}
- #endif
- void
- supply_fpregset (struct regcache *regcache, const elf_fpregset_t *fpregsetp)
- {
- i387_supply_fsave (regcache, -1, fpregsetp);
- }
- void
- fill_fpregset (const struct regcache *regcache,
- elf_fpregset_t *fpregsetp, int regno)
- {
- i387_collect_fsave (regcache, regno, fpregsetp);
- }
- #ifdef HAVE_PTRACE_GETREGS
- static void
- fetch_fpregs (struct regcache *regcache, int tid)
- {
- elf_fpregset_t fpregs;
- if (ptrace (PTRACE_GETFPREGS, tid, 0, (int) &fpregs) < 0)
- perror_with_name (_("Couldn't get floating point status"));
- supply_fpregset (regcache, (const elf_fpregset_t *) &fpregs);
- }
- static void
- store_fpregs (const struct regcache *regcache, int tid, int regno)
- {
- elf_fpregset_t fpregs;
- if (ptrace (PTRACE_GETFPREGS, tid, 0, (int) &fpregs) < 0)
- perror_with_name (_("Couldn't get floating point status"));
- fill_fpregset (regcache, &fpregs, regno);
- if (ptrace (PTRACE_SETFPREGS, tid, 0, (int) &fpregs) < 0)
- perror_with_name (_("Couldn't write floating point status"));
- }
- #else
- static void
- fetch_fpregs (struct regcache *regcache, int tid)
- {
- }
- static void
- store_fpregs (const struct regcache *regcache, int tid, int regno)
- {
- }
- #endif
- static int
- fetch_xstateregs (struct regcache *regcache, int tid)
- {
- char xstateregs[X86_XSTATE_MAX_SIZE];
- struct iovec iov;
- if (!have_ptrace_getregset)
- return 0;
- iov.iov_base = xstateregs;
- iov.iov_len = sizeof(xstateregs);
- if (ptrace (PTRACE_GETREGSET, tid, (unsigned int) NT_X86_XSTATE,
- &iov) < 0)
- perror_with_name (_("Couldn't read extended state status"));
- i387_supply_xsave (regcache, -1, xstateregs);
- return 1;
- }
- static int
- store_xstateregs (const struct regcache *regcache, int tid, int regno)
- {
- char xstateregs[X86_XSTATE_MAX_SIZE];
- struct iovec iov;
- if (!have_ptrace_getregset)
- return 0;
- iov.iov_base = xstateregs;
- iov.iov_len = sizeof(xstateregs);
- if (ptrace (PTRACE_GETREGSET, tid, (unsigned int) NT_X86_XSTATE,
- &iov) < 0)
- perror_with_name (_("Couldn't read extended state status"));
- i387_collect_xsave (regcache, regno, xstateregs, 0);
- if (ptrace (PTRACE_SETREGSET, tid, (unsigned int) NT_X86_XSTATE,
- (int) &iov) < 0)
- perror_with_name (_("Couldn't write extended state status"));
- return 1;
- }
- #ifdef HAVE_PTRACE_GETFPXREGS
- static int
- fetch_fpxregs (struct regcache *regcache, int tid)
- {
- elf_fpxregset_t fpxregs;
- if (! have_ptrace_getfpxregs)
- return 0;
- if (ptrace (PTRACE_GETFPXREGS, tid, 0, (int) &fpxregs) < 0)
- {
- if (errno == EIO)
- {
- have_ptrace_getfpxregs = 0;
- return 0;
- }
- perror_with_name (_("Couldn't read floating-point and SSE registers"));
- }
- i387_supply_fxsave (regcache, -1, (const elf_fpxregset_t *) &fpxregs);
- return 1;
- }
- static int
- store_fpxregs (const struct regcache *regcache, int tid, int regno)
- {
- elf_fpxregset_t fpxregs;
- if (! have_ptrace_getfpxregs)
- return 0;
- if (ptrace (PTRACE_GETFPXREGS, tid, 0, &fpxregs) == -1)
- {
- if (errno == EIO)
- {
- have_ptrace_getfpxregs = 0;
- return 0;
- }
- perror_with_name (_("Couldn't read floating-point and SSE registers"));
- }
- i387_collect_fxsave (regcache, regno, &fpxregs);
- if (ptrace (PTRACE_SETFPXREGS, tid, 0, &fpxregs) == -1)
- perror_with_name (_("Couldn't write floating-point and SSE registers"));
- return 1;
- }
- #else
- static int
- fetch_fpxregs (struct regcache *regcache, int tid)
- {
- return 0;
- }
- static int
- store_fpxregs (const struct regcache *regcache, int tid, int regno)
- {
- return 0;
- }
- #endif
- static void
- i386_linux_fetch_inferior_registers (struct target_ops *ops,
- struct regcache *regcache, int regno)
- {
- int tid;
-
- if (!have_ptrace_getregs)
- {
- int i;
- for (i = 0; i < gdbarch_num_regs (get_regcache_arch (regcache)); i++)
- if (regno == -1 || regno == i)
- fetch_register (regcache, i);
- return;
- }
-
- tid = ptid_get_lwp (inferior_ptid);
- if (tid == 0)
- tid = ptid_get_pid (inferior_ptid);
-
- if (regno == -1)
- {
- fetch_regs (regcache, tid);
-
- if (!have_ptrace_getregs)
- {
- i386_linux_fetch_inferior_registers (ops, regcache, regno);
- return;
- }
- if (fetch_xstateregs (regcache, tid))
- return;
- if (fetch_fpxregs (regcache, tid))
- return;
- fetch_fpregs (regcache, tid);
- return;
- }
- if (GETREGS_SUPPLIES (regno))
- {
- fetch_regs (regcache, tid);
- return;
- }
- if (GETXSTATEREGS_SUPPLIES (regno))
- {
- if (fetch_xstateregs (regcache, tid))
- return;
- }
- if (GETFPXREGS_SUPPLIES (regno))
- {
- if (fetch_fpxregs (regcache, tid))
- return;
-
- fetch_fpregs (regcache, tid);
- return;
- }
- internal_error (__FILE__, __LINE__,
- _("Got request for bad register number %d."), regno);
- }
- static void
- i386_linux_store_inferior_registers (struct target_ops *ops,
- struct regcache *regcache, int regno)
- {
- int tid;
-
- if (!have_ptrace_getregs)
- {
- int i;
- for (i = 0; i < gdbarch_num_regs (get_regcache_arch (regcache)); i++)
- if (regno == -1 || regno == i)
- store_register (regcache, i);
- return;
- }
-
- tid = ptid_get_lwp (inferior_ptid);
- if (tid == 0)
- tid = ptid_get_pid (inferior_ptid);
-
- if (regno == -1)
- {
- store_regs (regcache, tid, regno);
- if (store_xstateregs (regcache, tid, regno))
- return;
- if (store_fpxregs (regcache, tid, regno))
- return;
- store_fpregs (regcache, tid, regno);
- return;
- }
- if (GETREGS_SUPPLIES (regno))
- {
- store_regs (regcache, tid, regno);
- return;
- }
- if (GETXSTATEREGS_SUPPLIES (regno))
- {
- if (store_xstateregs (regcache, tid, regno))
- return;
- }
- if (GETFPXREGS_SUPPLIES (regno))
- {
- if (store_fpxregs (regcache, tid, regno))
- return;
-
- store_fpregs (regcache, tid, regno);
- return;
- }
- internal_error (__FILE__, __LINE__,
- _("Got request to store bad register number %d."), regno);
- }
- ps_err_e
- ps_get_thread_area (const struct ps_prochandle *ph,
- lwpid_t lwpid, int idx, void **base)
- {
- unsigned int base_addr;
- ps_err_e result;
- result = x86_linux_get_thread_area (lwpid, (void *) idx, &base_addr);
- if (result == PS_OK)
- *(int *) base = base_addr;
- return result;
- }
- static const unsigned char linux_syscall[] = { 0xcd, 0x80 };
- #define LINUX_SYSCALL_LEN (sizeof linux_syscall)
- #define LINUX_SYSCALL_REGNUM I386_EAX_REGNUM
- #ifndef SYS_sigreturn
- #define SYS_sigreturn 0x77
- #endif
- #ifndef SYS_rt_sigreturn
- #define SYS_rt_sigreturn 0xad
- #endif
- #define LINUX_SIGCONTEXT_EFLAGS_OFFSET (64)
- static void
- i386_linux_resume (struct target_ops *ops,
- ptid_t ptid, int step, enum gdb_signal signal)
- {
- int pid = ptid_get_pid (ptid);
- int request;
- if (catch_syscall_enabled () > 0)
- request = PTRACE_SYSCALL;
- else
- request = PTRACE_CONT;
- if (step)
- {
- struct regcache *regcache = get_thread_regcache (pid_to_ptid (pid));
- struct gdbarch *gdbarch = get_regcache_arch (regcache);
- enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
- ULONGEST pc;
- gdb_byte buf[LINUX_SYSCALL_LEN];
- request = PTRACE_SINGLESTEP;
- regcache_cooked_read_unsigned (regcache,
- gdbarch_pc_regnum (gdbarch), &pc);
-
-
- if (target_read_memory (pc, buf, LINUX_SYSCALL_LEN) == 0
- && memcmp (buf, linux_syscall, LINUX_SYSCALL_LEN) == 0)
- {
- ULONGEST syscall;
- regcache_cooked_read_unsigned (regcache,
- LINUX_SYSCALL_REGNUM, &syscall);
-
- if (syscall == SYS_sigreturn || syscall == SYS_rt_sigreturn)
- {
- ULONGEST sp, addr;
- unsigned long int eflags;
- regcache_cooked_read_unsigned (regcache, I386_ESP_REGNUM, &sp);
- if (syscall == SYS_rt_sigreturn)
- addr = read_memory_unsigned_integer (sp + 8, 4, byte_order)
- + 20;
- else
- addr = sp;
-
- addr += LINUX_SIGCONTEXT_EFLAGS_OFFSET;
- read_memory (addr, (gdb_byte *) &eflags, 4);
- eflags |= 0x0100;
- write_memory (addr, (gdb_byte *) &eflags, 4);
- }
- }
- }
- if (ptrace (request, pid, 0, gdb_signal_to_host (signal)) == -1)
- perror_with_name (("ptrace"));
- }
- extern initialize_file_ftype _initialize_i386_linux_nat;
- void
- _initialize_i386_linux_nat (void)
- {
-
- struct target_ops *t = x86_linux_create_target ();
-
- t->to_resume = i386_linux_resume;
-
- t->to_fetch_registers = i386_linux_fetch_inferior_registers;
- t->to_store_registers = i386_linux_store_inferior_registers;
-
- x86_linux_add_target (t);
- }