| Index: gdb/mips-linux-nat.c
|
| diff --git a/gdb/mips-linux-nat.c b/gdb/mips-linux-nat.c
|
| index b9f7f1dc638fb8c57329d21e7927053312cf660c..9246741c7107ac49a64131d1df47ab3b56af05cb 100644
|
| --- a/gdb/mips-linux-nat.c
|
| +++ b/gdb/mips-linux-nat.c
|
| @@ -1,6 +1,6 @@
|
| /* Native-dependent code for GNU/Linux on MIPS processors.
|
|
|
| - Copyright (C) 2001-2012 Free Software Foundation, Inc.
|
| + Copyright (C) 2001-2013 Free Software Foundation, Inc.
|
|
|
| This file is part of GDB.
|
|
|
| @@ -34,6 +34,9 @@
|
|
|
| #include <sgidefs.h>
|
| #include <sys/ptrace.h>
|
| +#include <asm/ptrace.h>
|
| +
|
| +#include "mips-linux-watch.h"
|
|
|
| #include "features/mips-linux.c"
|
| #include "features/mips-dsp-linux.c"
|
| @@ -60,7 +63,7 @@ static void (*super_fetch_registers) (struct target_ops *,
|
| static void (*super_store_registers) (struct target_ops *,
|
| struct regcache *, int);
|
|
|
| -static void (*super_close) (int);
|
| +static void (*super_close) (void);
|
|
|
| /* Map gdb internal register number to ptrace ``address''.
|
| These ``addresses'' are normally defined in <asm/ptrace.h>.
|
| @@ -326,7 +329,7 @@ mips64_linux_regsets_store_registers (struct target_ops *ops,
|
| have_dsp = mips_regnum (gdbarch)->dspctl != -1;
|
| if (!have_dsp)
|
| is_dsp = 0;
|
| - if (regno >= mips_regnum (gdbarch)->dspacc
|
| + else if (regno >= mips_regnum (gdbarch)->dspacc
|
| && regno < mips_regnum (gdbarch)->dspacc + 6)
|
| is_dsp = 1;
|
| else if (regno == mips_regnum (gdbarch)->dspctl)
|
| @@ -460,70 +463,6 @@ mips_linux_read_description (struct target_ops *ops)
|
| return have_dsp ? tdesc_mips64_dsp_linux : tdesc_mips64_linux;
|
| }
|
|
|
| -#ifndef PTRACE_GET_WATCH_REGS
|
| -# define PTRACE_GET_WATCH_REGS 0xd0
|
| -#endif
|
| -
|
| -#ifndef PTRACE_SET_WATCH_REGS
|
| -# define PTRACE_SET_WATCH_REGS 0xd1
|
| -#endif
|
| -
|
| -#define W_BIT 0
|
| -#define R_BIT 1
|
| -#define I_BIT 2
|
| -
|
| -#define W_MASK (1 << W_BIT)
|
| -#define R_MASK (1 << R_BIT)
|
| -#define I_MASK (1 << I_BIT)
|
| -
|
| -#define IRW_MASK (I_MASK | R_MASK | W_MASK)
|
| -
|
| -enum pt_watch_style {
|
| - pt_watch_style_mips32,
|
| - pt_watch_style_mips64
|
| -};
|
| -
|
| -#define MAX_DEBUG_REGISTER 8
|
| -
|
| -/* A value of zero in a watchlo indicates that it is available. */
|
| -
|
| -struct mips32_watch_regs
|
| -{
|
| - uint32_t watchlo[MAX_DEBUG_REGISTER];
|
| - /* Lower 16 bits of watchhi. */
|
| - uint16_t watchhi[MAX_DEBUG_REGISTER];
|
| - /* Valid mask and I R W bits.
|
| - * bit 0 -- 1 if W bit is usable.
|
| - * bit 1 -- 1 if R bit is usable.
|
| - * bit 2 -- 1 if I bit is usable.
|
| - * bits 3 - 11 -- Valid watchhi mask bits.
|
| - */
|
| - uint16_t watch_masks[MAX_DEBUG_REGISTER];
|
| - /* The number of valid watch register pairs. */
|
| - uint32_t num_valid;
|
| - /* There is confusion across gcc versions about structure alignment,
|
| - so we force 8 byte alignment for these structures so they match
|
| - the kernel even if it was build with a different gcc version. */
|
| -} __attribute__ ((aligned (8)));
|
| -
|
| -struct mips64_watch_regs
|
| -{
|
| - uint64_t watchlo[MAX_DEBUG_REGISTER];
|
| - uint16_t watchhi[MAX_DEBUG_REGISTER];
|
| - uint16_t watch_masks[MAX_DEBUG_REGISTER];
|
| - uint32_t num_valid;
|
| -} __attribute__ ((aligned (8)));
|
| -
|
| -struct pt_watch_regs
|
| -{
|
| - enum pt_watch_style style;
|
| - union
|
| - {
|
| - struct mips32_watch_regs mips32;
|
| - struct mips64_watch_regs mips64;
|
| - };
|
| -};
|
| -
|
| /* -1 if the kernel and/or CPU do not support watch registers.
|
| 1 if watch_readback is valid and we can read style, num_valid
|
| and the masks.
|
| @@ -535,18 +474,6 @@ static int watch_readback_valid;
|
|
|
| static struct pt_watch_regs watch_readback;
|
|
|
| -/* We keep list of all watchpoints we should install and calculate the
|
| - watch register values each time the list changes. This allows for
|
| - easy sharing of watch registers for more than one watchpoint. */
|
| -
|
| -struct mips_watchpoint
|
| -{
|
| - CORE_ADDR addr;
|
| - int len;
|
| - int type;
|
| - struct mips_watchpoint *next;
|
| -};
|
| -
|
| static struct mips_watchpoint *current_watches;
|
|
|
| /* The current set of watch register values for writing the
|
| @@ -554,131 +481,6 @@ static struct mips_watchpoint *current_watches;
|
|
|
| static struct pt_watch_regs watch_mirror;
|
|
|
| -/* Assuming usable watch registers, return the irw_mask. */
|
| -
|
| -static uint32_t
|
| -get_irw_mask (struct pt_watch_regs *regs, int set)
|
| -{
|
| - switch (regs->style)
|
| - {
|
| - case pt_watch_style_mips32:
|
| - return regs->mips32.watch_masks[set] & IRW_MASK;
|
| - case pt_watch_style_mips64:
|
| - return regs->mips64.watch_masks[set] & IRW_MASK;
|
| - default:
|
| - internal_error (__FILE__, __LINE__,
|
| - _("Unrecognized watch register style"));
|
| - }
|
| -}
|
| -
|
| -/* Assuming usable watch registers, return the reg_mask. */
|
| -
|
| -static uint32_t
|
| -get_reg_mask (struct pt_watch_regs *regs, int set)
|
| -{
|
| - switch (regs->style)
|
| - {
|
| - case pt_watch_style_mips32:
|
| - return regs->mips32.watch_masks[set] & ~IRW_MASK;
|
| - case pt_watch_style_mips64:
|
| - return regs->mips64.watch_masks[set] & ~IRW_MASK;
|
| - default:
|
| - internal_error (__FILE__, __LINE__,
|
| - _("Unrecognized watch register style"));
|
| - }
|
| -}
|
| -
|
| -/* Assuming usable watch registers, return the num_valid. */
|
| -
|
| -static uint32_t
|
| -get_num_valid (struct pt_watch_regs *regs)
|
| -{
|
| - switch (regs->style)
|
| - {
|
| - case pt_watch_style_mips32:
|
| - return regs->mips32.num_valid;
|
| - case pt_watch_style_mips64:
|
| - return regs->mips64.num_valid;
|
| - default:
|
| - internal_error (__FILE__, __LINE__,
|
| - _("Unrecognized watch register style"));
|
| - }
|
| -}
|
| -
|
| -/* Assuming usable watch registers, return the watchlo. */
|
| -
|
| -static CORE_ADDR
|
| -get_watchlo (struct pt_watch_regs *regs, int set)
|
| -{
|
| - switch (regs->style)
|
| - {
|
| - case pt_watch_style_mips32:
|
| - return regs->mips32.watchlo[set];
|
| - case pt_watch_style_mips64:
|
| - return regs->mips64.watchlo[set];
|
| - default:
|
| - internal_error (__FILE__, __LINE__,
|
| - _("Unrecognized watch register style"));
|
| - }
|
| -}
|
| -
|
| -/* Assuming usable watch registers, set a watchlo value. */
|
| -
|
| -static void
|
| -set_watchlo (struct pt_watch_regs *regs, int set, CORE_ADDR value)
|
| -{
|
| - switch (regs->style)
|
| - {
|
| - case pt_watch_style_mips32:
|
| - /* The cast will never throw away bits as 64 bit addresses can
|
| - never be used on a 32 bit kernel. */
|
| - regs->mips32.watchlo[set] = (uint32_t)value;
|
| - break;
|
| - case pt_watch_style_mips64:
|
| - regs->mips64.watchlo[set] = value;
|
| - break;
|
| - default:
|
| - internal_error (__FILE__, __LINE__,
|
| - _("Unrecognized watch register style"));
|
| - }
|
| -}
|
| -
|
| -/* Assuming usable watch registers, return the watchhi. */
|
| -
|
| -static uint32_t
|
| -get_watchhi (struct pt_watch_regs *regs, int n)
|
| -{
|
| - switch (regs->style)
|
| - {
|
| - case pt_watch_style_mips32:
|
| - return regs->mips32.watchhi[n];
|
| - case pt_watch_style_mips64:
|
| - return regs->mips64.watchhi[n];
|
| - default:
|
| - internal_error (__FILE__, __LINE__,
|
| - _("Unrecognized watch register style"));
|
| - }
|
| -}
|
| -
|
| -/* Assuming usable watch registers, set a watchhi value. */
|
| -
|
| -static void
|
| -set_watchhi (struct pt_watch_regs *regs, int n, uint16_t value)
|
| -{
|
| - switch (regs->style)
|
| - {
|
| - case pt_watch_style_mips32:
|
| - regs->mips32.watchhi[n] = value;
|
| - break;
|
| - case pt_watch_style_mips64:
|
| - regs->mips64.watchhi[n] = value;
|
| - break;
|
| - default:
|
| - internal_error (__FILE__, __LINE__,
|
| - _("Unrecognized watch register style"));
|
| - }
|
| -}
|
| -
|
| static void
|
| mips_show_dr (const char *func, CORE_ADDR addr,
|
| int len, enum target_hw_bp_type type)
|
| @@ -688,7 +490,7 @@ mips_show_dr (const char *func, CORE_ADDR addr,
|
| puts_unfiltered (func);
|
| if (addr || len)
|
| printf_unfiltered (" (addr=%s, len=%d, type=%s)",
|
| - paddress (target_gdbarch, addr), len,
|
| + paddress (target_gdbarch (), addr), len,
|
| type == hw_write ? "data-write"
|
| : (type == hw_read ? "data-read"
|
| : (type == hw_access ? "data-read/write"
|
| @@ -698,70 +500,12 @@ mips_show_dr (const char *func, CORE_ADDR addr,
|
|
|
| for (i = 0; i < MAX_DEBUG_REGISTER; i++)
|
| printf_unfiltered ("\tDR%d: lo=%s, hi=%s\n", i,
|
| - paddress (target_gdbarch,
|
| - get_watchlo (&watch_mirror, i)),
|
| - paddress (target_gdbarch,
|
| - get_watchhi (&watch_mirror, i)));
|
| -}
|
| -
|
| -/* Return 1 if watch registers are usable. Cached information is used
|
| - unless force is true. */
|
| -
|
| -static int
|
| -mips_linux_read_watch_registers (int force)
|
| -{
|
| - int tid;
|
| -
|
| - if (force || watch_readback_valid == 0)
|
| - {
|
| - tid = ptid_get_lwp (inferior_ptid);
|
| - if (ptrace (PTRACE_GET_WATCH_REGS, tid, &watch_readback) == -1)
|
| - {
|
| - watch_readback_valid = -1;
|
| - return 0;
|
| - }
|
| - switch (watch_readback.style)
|
| - {
|
| - case pt_watch_style_mips32:
|
| - if (watch_readback.mips32.num_valid == 0)
|
| - {
|
| - watch_readback_valid = -1;
|
| - return 0;
|
| - }
|
| - break;
|
| - case pt_watch_style_mips64:
|
| - if (watch_readback.mips64.num_valid == 0)
|
| - {
|
| - watch_readback_valid = -1;
|
| - return 0;
|
| - }
|
| - break;
|
| - default:
|
| - watch_readback_valid = -1;
|
| - return 0;
|
| - }
|
| - /* Watch registers appear to be usable. */
|
| - watch_readback_valid = 1;
|
| - }
|
| - return (watch_readback_valid == 1) ? 1 : 0;
|
| -}
|
| -
|
| -/* Convert GDB's type to an IRW mask. */
|
| -
|
| -static unsigned
|
| -type_to_irw (int type)
|
| -{
|
| - switch (type)
|
| - {
|
| - case hw_write:
|
| - return W_MASK;
|
| - case hw_read:
|
| - return R_MASK;
|
| - case hw_access:
|
| - return (W_MASK | R_MASK);
|
| - default:
|
| - return 0;
|
| - }
|
| + paddress (target_gdbarch (),
|
| + mips_linux_watch_get_watchlo (&watch_mirror,
|
| + i)),
|
| + paddress (target_gdbarch (),
|
| + mips_linux_watch_get_watchhi (&watch_mirror,
|
| + i)));
|
| }
|
|
|
| /* Target to_can_use_hw_breakpoint implementation. Return 1 if we can
|
| @@ -773,7 +517,9 @@ mips_linux_can_use_hw_breakpoint (int type, int cnt, int ot)
|
| int i;
|
| uint32_t wanted_mask, irw_mask;
|
|
|
| - if (!mips_linux_read_watch_registers (0))
|
| + if (!mips_linux_read_watch_registers (ptid_get_lwp (inferior_ptid),
|
| + &watch_readback,
|
| + &watch_readback_valid, 0))
|
| return 0;
|
|
|
| switch (type)
|
| @@ -791,9 +537,11 @@ mips_linux_can_use_hw_breakpoint (int type, int cnt, int ot)
|
| return 0;
|
| }
|
|
|
| - for (i = 0; i < get_num_valid (&watch_readback) && cnt; i++)
|
| + for (i = 0;
|
| + i < mips_linux_watch_get_num_valid (&watch_readback) && cnt;
|
| + i++)
|
| {
|
| - irw_mask = get_irw_mask (&watch_readback, i);
|
| + irw_mask = mips_linux_watch_get_irw_mask (&watch_readback, i);
|
| if ((irw_mask & wanted_mask) == wanted_mask)
|
| cnt--;
|
| }
|
| @@ -810,13 +558,15 @@ mips_linux_stopped_by_watchpoint (void)
|
| int n;
|
| int num_valid;
|
|
|
| - if (!mips_linux_read_watch_registers (1))
|
| + if (!mips_linux_read_watch_registers (ptid_get_lwp (inferior_ptid),
|
| + &watch_readback,
|
| + &watch_readback_valid, 1))
|
| return 0;
|
|
|
| - num_valid = get_num_valid (&watch_readback);
|
| + num_valid = mips_linux_watch_get_num_valid (&watch_readback);
|
|
|
| for (n = 0; n < MAX_DEBUG_REGISTER && n < num_valid; n++)
|
| - if (get_watchhi (&watch_readback, n) & (R_MASK | W_MASK))
|
| + if (mips_linux_watch_get_watchhi (&watch_readback, n) & (R_MASK | W_MASK))
|
| return 1;
|
|
|
| return 0;
|
| @@ -834,106 +584,6 @@ mips_linux_stopped_data_address (struct target_ops *t, CORE_ADDR *paddr)
|
| return 0;
|
| }
|
|
|
| -/* Set any low order bits in mask that are not set. */
|
| -
|
| -static CORE_ADDR
|
| -fill_mask (CORE_ADDR mask)
|
| -{
|
| - CORE_ADDR f = 1;
|
| - while (f && f < mask)
|
| - {
|
| - mask |= f;
|
| - f <<= 1;
|
| - }
|
| - return mask;
|
| -}
|
| -
|
| -/* Try to add a single watch to the specified registers. Return 1 on
|
| - success, 0 on failure. */
|
| -
|
| -static int
|
| -try_one_watch (struct pt_watch_regs *regs, CORE_ADDR addr,
|
| - int len, unsigned irw)
|
| -{
|
| - CORE_ADDR base_addr, last_byte, break_addr, segment_len;
|
| - CORE_ADDR mask_bits, t_low, t_low_end;
|
| - uint16_t t_hi;
|
| - int i, free_watches;
|
| - struct pt_watch_regs regs_copy;
|
| -
|
| - if (len <= 0)
|
| - return 0;
|
| -
|
| - last_byte = addr + len - 1;
|
| - mask_bits = fill_mask (addr ^ last_byte) | IRW_MASK;
|
| - base_addr = addr & ~mask_bits;
|
| -
|
| - /* Check to see if it is covered by current registers. */
|
| - for (i = 0; i < get_num_valid (regs); i++)
|
| - {
|
| - t_low = get_watchlo (regs, i);
|
| - if (t_low != 0 && irw == ((unsigned)t_low & irw))
|
| - {
|
| - t_hi = get_watchhi (regs, i) | IRW_MASK;
|
| - t_low &= ~(CORE_ADDR)t_hi;
|
| - if (addr >= t_low && last_byte <= (t_low + t_hi))
|
| - return 1;
|
| - }
|
| - }
|
| - /* Try to find an empty register. */
|
| - free_watches = 0;
|
| - for (i = 0; i < get_num_valid (regs); i++)
|
| - {
|
| - t_low = get_watchlo (regs, i);
|
| - if (t_low == 0 && irw == (get_irw_mask (regs, i) & irw))
|
| - {
|
| - if (mask_bits <= (get_reg_mask (regs, i) | IRW_MASK))
|
| - {
|
| - /* It fits, we'll take it. */
|
| - set_watchlo (regs, i, base_addr | irw);
|
| - set_watchhi (regs, i, mask_bits & ~IRW_MASK);
|
| - return 1;
|
| - }
|
| - else
|
| - {
|
| - /* It doesn't fit, but has the proper IRW capabilities. */
|
| - free_watches++;
|
| - }
|
| - }
|
| - }
|
| - if (free_watches > 1)
|
| - {
|
| - /* Try to split it across several registers. */
|
| - regs_copy = *regs;
|
| - for (i = 0; i < get_num_valid (®s_copy); i++)
|
| - {
|
| - t_low = get_watchlo (®s_copy, i);
|
| - t_hi = get_reg_mask (®s_copy, i) | IRW_MASK;
|
| - if (t_low == 0 && irw == (t_hi & irw))
|
| - {
|
| - t_low = addr & ~(CORE_ADDR)t_hi;
|
| - break_addr = t_low + t_hi + 1;
|
| - if (break_addr >= addr + len)
|
| - segment_len = len;
|
| - else
|
| - segment_len = break_addr - addr;
|
| - mask_bits = fill_mask (addr ^ (addr + segment_len - 1));
|
| - set_watchlo (®s_copy, i, (addr & ~mask_bits) | irw);
|
| - set_watchhi (®s_copy, i, mask_bits & ~IRW_MASK);
|
| - if (break_addr >= addr + len)
|
| - {
|
| - *regs = regs_copy;
|
| - return 1;
|
| - }
|
| - len = addr + len - break_addr;
|
| - addr = break_addr;
|
| - }
|
| - }
|
| - }
|
| - /* It didn't fit anywhere, we failed. */
|
| - return 0;
|
| -}
|
| -
|
| /* Target to_region_ok_for_hw_watchpoint implementation. Return 1 if
|
| the specified region can be covered by the watch registers. */
|
|
|
| @@ -943,17 +593,18 @@ mips_linux_region_ok_for_hw_watchpoint (CORE_ADDR addr, int len)
|
| struct pt_watch_regs dummy_regs;
|
| int i;
|
|
|
| - if (!mips_linux_read_watch_registers (0))
|
| + if (!mips_linux_read_watch_registers (ptid_get_lwp (inferior_ptid),
|
| + &watch_readback,
|
| + &watch_readback_valid, 0))
|
| return 0;
|
|
|
| dummy_regs = watch_readback;
|
| /* Clear them out. */
|
| - for (i = 0; i < get_num_valid (&dummy_regs); i++)
|
| - set_watchlo (&dummy_regs, i, 0);
|
| - return try_one_watch (&dummy_regs, addr, len, 0);
|
| + for (i = 0; i < mips_linux_watch_get_num_valid (&dummy_regs); i++)
|
| + mips_linux_watch_set_watchlo (&dummy_regs, i, 0);
|
| + return mips_linux_watch_try_one_watch (&dummy_regs, addr, len, 0);
|
| }
|
|
|
| -
|
| /* Write the mirrored watch register values for each thread. */
|
|
|
| static int
|
| @@ -979,7 +630,9 @@ mips_linux_new_thread (struct lwp_info *lp)
|
| {
|
| int tid;
|
|
|
| - if (!mips_linux_read_watch_registers (0))
|
| + if (!mips_linux_read_watch_registers (ptid_get_lwp (inferior_ptid),
|
| + &watch_readback,
|
| + &watch_readback_valid, 0))
|
| return;
|
|
|
| tid = ptid_get_lwp (lp->ptid);
|
| @@ -987,32 +640,6 @@ mips_linux_new_thread (struct lwp_info *lp)
|
| perror_with_name (_("Couldn't write debug register"));
|
| }
|
|
|
| -/* Fill in the watch registers with the currently cached watches. */
|
| -
|
| -static void
|
| -populate_regs_from_watches (struct pt_watch_regs *regs)
|
| -{
|
| - struct mips_watchpoint *w;
|
| - int i;
|
| -
|
| - /* Clear them out. */
|
| - for (i = 0; i < get_num_valid (regs); i++)
|
| - {
|
| - set_watchlo (regs, i, 0);
|
| - set_watchhi (regs, i, 0);
|
| - }
|
| -
|
| - w = current_watches;
|
| - while (w)
|
| - {
|
| - i = try_one_watch (regs, w->addr, w->len, type_to_irw (w->type));
|
| - /* They must all fit, because we previously calculated that they
|
| - would. */
|
| - gdb_assert (i);
|
| - w = w->next;
|
| - }
|
| -}
|
| -
|
| /* Target to_insert_watchpoint implementation. Try to insert a new
|
| watch. Return zero on success. */
|
|
|
| @@ -1027,7 +654,9 @@ mips_linux_insert_watchpoint (CORE_ADDR addr, int len, int type,
|
| int i;
|
| int retval;
|
|
|
| - if (!mips_linux_read_watch_registers (0))
|
| + if (!mips_linux_read_watch_registers (ptid_get_lwp (inferior_ptid),
|
| + &watch_readback,
|
| + &watch_readback_valid, 0))
|
| return -1;
|
|
|
| if (len <= 0)
|
| @@ -1035,10 +664,11 @@ mips_linux_insert_watchpoint (CORE_ADDR addr, int len, int type,
|
|
|
| regs = watch_readback;
|
| /* Add the current watches. */
|
| - populate_regs_from_watches (®s);
|
| + mips_linux_watch_populate_regs (current_watches, ®s);
|
|
|
| /* Now try to add the new watch. */
|
| - if (!try_one_watch (®s, addr, len, type_to_irw (type)))
|
| + if (!mips_linux_watch_try_one_watch (®s, addr, len,
|
| + mips_linux_watch_type_to_irw (type)))
|
| return -1;
|
|
|
| /* It fit. Stick it on the end of the list. */
|
| @@ -1100,7 +730,7 @@ mips_linux_remove_watchpoint (CORE_ADDR addr, int len, int type,
|
| gdb_assert (watch_readback_valid == 1);
|
|
|
| watch_mirror = watch_readback;
|
| - populate_regs_from_watches (&watch_mirror);
|
| + mips_linux_watch_populate_regs (current_watches, &watch_mirror);
|
|
|
| retval = write_watchpoint_regs ();
|
|
|
| @@ -1114,7 +744,7 @@ mips_linux_remove_watchpoint (CORE_ADDR addr, int len, int type,
|
| super implementation. */
|
|
|
| static void
|
| -mips_linux_close (int quitting)
|
| +mips_linux_close (void)
|
| {
|
| struct mips_watchpoint *w;
|
| struct mips_watchpoint *nw;
|
| @@ -1130,7 +760,7 @@ mips_linux_close (int quitting)
|
| current_watches = NULL;
|
|
|
| if (super_close)
|
| - super_close (quitting);
|
| + super_close ();
|
| }
|
|
|
| void _initialize_mips_linux_nat (void);
|
|
|