/* GNU/Linux/MIPS specific low level interface, for the remote server for GDB.
- Copyright (C) 1995-2015 Free Software Foundation, Inc.
+ Copyright (C) 1995-2018 Free Software Foundation, Inc.
This file is part of GDB.
#include "server.h"
#include "linux-low.h"
-#include <sys/ptrace.h>
+#include "nat/gdb_ptrace.h"
#include <endian.h>
#include "nat/mips-linux-watch.h"
/* Pseudo registers can not be read. ptrace does not provide a way to
read (or set) PS_REGNUM, and there's no point in reading or setting
- ZERO_REGNUM. We also can not set BADVADDR, CAUSE, or FCRIR via
- ptrace(). */
+ ZERO_REGNUM, it's always 0. We also can not set BADVADDR, CAUSE,
+ or FCRIR via ptrace(). */
static int
mips_cannot_fetch_register (int regno)
tdesc = current_process ()->tdesc;
+ /* On n32 we can't access 64-bit registers via PTRACE_PEEKUSR. */
+ if (register_size (tdesc, regno) > sizeof (PTRACE_XFER_TYPE))
+ return 1;
+
if (find_regno (tdesc, "r0") == regno)
return 1;
tdesc = current_process ()->tdesc;
+ /* On n32 we can't access 64-bit registers via PTRACE_POKEUSR. */
+ if (register_size (tdesc, regno) > sizeof (PTRACE_XFER_TYPE))
+ return 1;
+
if (find_regno (tdesc, "r0") == regno)
return 1;
return 0;
}
+static int
+mips_fetch_register (struct regcache *regcache, int regno)
+{
+ const struct target_desc *tdesc = current_process ()->tdesc;
+
+ if (find_regno (tdesc, "r0") == regno)
+ {
+ supply_register_zeroed (regcache, regno);
+ return 1;
+ }
+
+ return 0;
+}
+
static CORE_ADDR
mips_get_pc (struct regcache *regcache)
{
static const unsigned int mips_breakpoint = 0x0005000d;
#define mips_breakpoint_len 4
-/* We only place breakpoints in empty marker functions, and thread locking
- is outside of the function. So rather than importing software single-step,
- we can just run until exit. */
-static CORE_ADDR
-mips_reinsert_addr (void)
+/* Implementation of linux_target_ops method "sw_breakpoint_from_kind". */
+
+static const gdb_byte *
+mips_sw_breakpoint_from_kind (int kind, int *size)
{
- struct regcache *regcache = get_thread_regcache (current_thread, 1);
- union mips_register ra;
- collect_register_by_name (regcache, "r31", ra.buf);
- return register_size (regcache->tdesc, 0) == 4 ? ra.reg32 : ra.reg64;
+ *size = mips_breakpoint_len;
+ return (const gdb_byte *) &mips_breakpoint;
}
static int
return 0;
}
-/* Mark the watch registers of lwp, represented by ENTRY, as changed,
- if the lwp's process id is *PID_P. */
+/* Mark the watch registers of lwp, represented by ENTRY, as changed. */
-static int
-update_watch_registers_callback (struct inferior_list_entry *entry,
- void *pid_p)
+static void
+update_watch_registers_callback (thread_info *thread)
{
- struct thread_info *thread = (struct thread_info *) entry;
struct lwp_info *lwp = get_thread_lwp (thread);
- int pid = *(int *) pid_p;
- /* Only update the threads of this process. */
- if (pid_of (thread) == pid)
- {
- /* The actual update is done later just before resuming the lwp,
- we just mark that the registers need updating. */
- lwp->arch_private->watch_registers_changed = 1;
-
- /* If the lwp isn't stopped, force it to momentarily pause, so
- we can update its watch registers. */
- if (!lwp->stopped)
- linux_stop_lwp (lwp);
- }
+ /* The actual update is done later just before resuming the lwp,
+ we just mark that the registers need updating. */
+ lwp->arch_private->watch_registers_changed = 1;
- return 0;
+ /* If the lwp isn't stopped, force it to momentarily pause, so
+ we can update its watch registers. */
+ if (!lwp->stopped)
+ linux_stop_lwp (lwp);
}
/* This is the implementation of linux_target_ops method
static struct arch_process_info *
mips_linux_new_process (void)
{
- struct arch_process_info *info = xcalloc (1, sizeof (*info));
+ struct arch_process_info *info = XCNEW (struct arch_process_info);
return info;
}
+/* This is the implementation of linux_target_ops method
+ delete_process. */
+
+static void
+mips_linux_delete_process (struct arch_process_info *info)
+{
+ xfree (info);
+}
+
/* This is the implementation of linux_target_ops method new_thread.
Mark the watch registers as changed, so the threads' copies will
be updated. */
static void
mips_linux_new_thread (struct lwp_info *lwp)
{
- struct arch_lwp_info *info = xcalloc (1, sizeof (*info));
+ struct arch_lwp_info *info = XCNEW (struct arch_lwp_info);
info->watch_registers_changed = 1;
lwp->arch_private = info;
}
+/* Function to call when a thread is being deleted. */
+
+static void
+mips_linux_delete_thread (struct arch_lwp_info *arch_lwp)
+{
+ xfree (arch_lwp);
+}
+
/* Create a new mips_watchpoint and add it to the list. */
static void
-mips_add_watchpoint (struct arch_process_info *private, CORE_ADDR addr,
- int len, int watch_type)
+mips_add_watchpoint (struct arch_process_info *priv, CORE_ADDR addr, int len,
+ enum target_hw_bp_type watch_type)
{
struct mips_watchpoint *new_watch;
struct mips_watchpoint **pw;
- new_watch = xmalloc (sizeof (struct mips_watchpoint));
+ new_watch = XNEW (struct mips_watchpoint);
new_watch->addr = addr;
new_watch->len = len;
new_watch->type = watch_type;
new_watch->next = NULL;
- pw = &private->current_watches;
+ pw = &priv->current_watches;
while (*pw != NULL)
pw = &(*pw)->next;
*pw = new_watch;
struct mips_watchpoint *wp;
/* These are allocated by linux_add_process. */
- gdb_assert (parent->private != NULL
- && parent->private->arch_private != NULL);
- gdb_assert (child->private != NULL
- && child->private->arch_private != NULL);
+ gdb_assert (parent->priv != NULL
+ && parent->priv->arch_private != NULL);
+ gdb_assert (child->priv != NULL
+ && child->priv->arch_private != NULL);
/* Linux kernel before 2.6.33 commit
72f674d203cd230426437cdcf7dd6f681dad8b0d
in the end before detaching the forked off process, thus making
this compatible with older Linux kernels too. */
- parent_private = parent->private->arch_private;
- child_private = child->private->arch_private;
+ parent_private = parent->priv->arch_private;
+ child_private = child->priv->arch_private;
child_private->watch_readback_valid = parent_private->watch_readback_valid;
child_private->watch_readback = parent_private->watch_readback;
int tid = ptid_get_lwp (ptid);
if (-1 == ptrace (PTRACE_SET_WATCH_REGS, tid,
- &priv->watch_mirror))
+ &priv->watch_mirror, NULL))
perror_with_name ("Couldn't write watch register");
}
struct process_info *proc = current_process ();
struct arch_process_info *priv = proc->priv->arch_private;
struct pt_watch_regs regs;
- int pid;
long lwpid;
enum target_hw_bp_type watch_type;
uint32_t irw;
priv->watch_mirror = regs;
/* Only update the threads of this process. */
- pid = pid_of (proc);
- find_inferior (&all_threads, update_watch_registers_callback, &pid);
+ for_each_thread (proc->pid, update_watch_registers_callback);
return 0;
}
struct arch_process_info *priv = proc->priv->arch_private;
int deleted_one;
- int pid;
enum target_hw_bp_type watch_type;
struct mips_watchpoint **pw;
&priv->watch_mirror);
/* Only update the threads of this process. */
- pid = pid_of (proc);
- find_inferior (&all_threads, update_watch_registers_callback, &pid);
+ for_each_thread (proc->pid, update_watch_registers_callback);
+
return 0;
}
/* Fetch the thread-local storage pointer for libthread_db. */
ps_err_e
-ps_get_thread_area (const struct ps_prochandle *ph,
+ps_get_thread_area (struct ps_prochandle *ph,
lwpid_t lwpid, int idx, void **base)
{
if (ptrace (PTRACE_GET_THREAD_AREA, lwpid, NULL, base) != 0)
static void
mips_fill_gregset (struct regcache *regcache, void *buf)
{
- union mips_register *regset = buf;
+ union mips_register *regset = (union mips_register *) buf;
int i, use_64bit;
const struct target_desc *tdesc = regcache->tdesc;
static void
mips_store_gregset (struct regcache *regcache, const void *buf)
{
- const union mips_register *regset = buf;
+ const union mips_register *regset = (const union mips_register *) buf;
int i, use_64bit;
use_64bit = (register_size (regcache->tdesc, 0) == 8);
- for (i = 0; i < 32; i++)
+ supply_register_by_name_zeroed (regcache, "r0");
+
+ for (i = 1; i < 32; i++)
mips_supply_register (regcache, use_64bit, i, regset + i);
mips_supply_register (regcache, use_64bit,
static void
mips_fill_fpregset (struct regcache *regcache, void *buf)
{
- union mips_register *regset = buf;
+ union mips_register *regset = (union mips_register *) buf;
int i, use_64bit, first_fp, big_endian;
use_64bit = (register_size (regcache->tdesc, 0) == 8);
static void
mips_store_fpregset (struct regcache *regcache, const void *buf)
{
- const union mips_register *regset = buf;
+ const union mips_register *regset = (const union mips_register *) buf;
int i, use_64bit, first_fp, big_endian;
use_64bit = (register_size (regcache->tdesc, 0) == 8);
{ PTRACE_GETFPREGS, PTRACE_SETFPREGS, 0, 33 * 8, FP_REGS,
mips_fill_fpregset, mips_store_fpregset },
#endif /* HAVE_PTRACE_GETREGS */
- { 0, 0, 0, -1, -1, NULL, NULL }
+ NULL_REGSET
};
static struct regsets_info mips_regsets_info =
mips_regs_info,
mips_cannot_fetch_register,
mips_cannot_store_register,
- NULL, /* fetch_register */
+ mips_fetch_register,
mips_get_pc,
mips_set_pc,
- (const unsigned char *) &mips_breakpoint,
- mips_breakpoint_len,
- mips_reinsert_addr,
+ NULL, /* breakpoint_kind_from_pc */
+ mips_sw_breakpoint_from_kind,
+ NULL, /* get_next_pcs */
0,
mips_breakpoint_at,
mips_supports_z_point_type,
NULL,
NULL, /* siginfo_fixup */
mips_linux_new_process,
+ mips_linux_delete_process,
mips_linux_new_thread,
+ mips_linux_delete_thread,
mips_linux_new_fork,
mips_linux_prepare_to_resume
};