* Makefile.in (HFILES_NO_SRCDIR): Add
	common/mips-linux-watch.h.
	(mips-linux-watch.o): New rule.
	* common/mips-linux-watch.c: New.
	* common/mips-linux-watch.h: New.
	* config/mips/linux.mh (NATDEPFILES): Add mips-linux-watch.o
	* mips-linux-nat.c: Include mips-linux-watch.h.
	(W_BIT, R_BIT, I_BIT, W_MASK, R_MASK, I_MASK, IRW_MASK): Move
	to common/mips-linux-watch.h.
	(MAX_DEBUG_REGISTER): Likewise.
	(enum pt_watch_style): Likewise.
	(struct mips32_watch_regs): Likewise.
	(struct mips64_watch_regs): Likewise.
	(struct pt_watch_regs): Likewise.
	(struct mips_watchpoint): Likewise.
	(mips_linux_watch_get_irw_mask): Move to
	common/mips-linux-watch.c.
	(get_reg_mask, mips_linux_watch_get_num_valid): Likewise.
	(mips_linux_watch_get_watchlo): Likewise.
	(mips_linux_watch_set_watchlo): Likewise.
	(mips_linux_watch_get_watchhi): Likewise.
	(mips_linux_watch_set_watchhi): Likewise.
	(mips_linux_read_watch_registers): Likewise.
	(mips_linux_watch_type_to_irw): Likewise.
	(mips_linux_stopped_data_address, fill_mask): Likewise.
	(mips_linux_watch_try_one_watch): Likewise.
	(mips_linux_watch_populate_regs): Likewise.
This commit is contained in:
Yao Qi 2013-07-27 07:49:05 +00:00
parent b343645045
commit aaee205620
6 changed files with 513 additions and 408 deletions

View file

@ -1,3 +1,33 @@
2013-07-27 Yao Qi <yao@codesourcery.com>
* Makefile.in (HFILES_NO_SRCDIR): Add
common/mips-linux-watch.h.
(mips-linux-watch.o): New rule.
* common/mips-linux-watch.c: New.
* common/mips-linux-watch.h: New.
* config/mips/linux.mh (NATDEPFILES): Add mips-linux-watch.o
* mips-linux-nat.c: Include mips-linux-watch.h.
(W_BIT, R_BIT, I_BIT, W_MASK, R_MASK, I_MASK, IRW_MASK): Move
to common/mips-linux-watch.h.
(MAX_DEBUG_REGISTER): Likewise.
(enum pt_watch_style): Likewise.
(struct mips32_watch_regs): Likewise.
(struct mips64_watch_regs): Likewise.
(struct pt_watch_regs): Likewise.
(struct mips_watchpoint): Likewise.
(mips_linux_watch_get_irw_mask): Move to
common/mips-linux-watch.c.
(get_reg_mask, mips_linux_watch_get_num_valid): Likewise.
(mips_linux_watch_get_watchlo): Likewise.
(mips_linux_watch_set_watchlo): Likewise.
(mips_linux_watch_get_watchhi): Likewise.
(mips_linux_watch_set_watchhi): Likewise.
(mips_linux_read_watch_registers): Likewise.
(mips_linux_watch_type_to_irw): Likewise.
(mips_linux_stopped_data_address, fill_mask): Likewise.
(mips_linux_watch_try_one_watch): Likewise.
(mips_linux_watch_populate_regs): Likewise.
2013-07-27 Yao Qi <yao@codesourcery.com>
* mips-linux-nat.c (get_irw_mask): Rename to ...

View file

@ -787,7 +787,7 @@ LINTFILES = $(SFILES) $(YYFILES) $(CONFIG_SRCS) init.c
HFILES_NO_SRCDIR = \
common/gdb_signals.h common/gdb_thread_db.h common/gdb_vecs.h \
common/i386-xstate.h common/linux-ptrace.h \
common/i386-xstate.h common/linux-ptrace.h common/mips-linux-watch.h \
proc-utils.h aarch64-tdep.h arm-tdep.h ax-gdb.h ppcfbsd-tdep.h \
ppcnbsd-tdep.h cli-out.h gdb_expat.h breakpoint.h infcall.h obsd-tdep.h \
exec.h m32r-tdep.h osabi.h gdbcore.h solib-som.h amd64bsd-nat.h \
@ -2026,6 +2026,10 @@ target-common.o: ${srcdir}/common/target-common.c
$(COMPILE) $(srcdir)/common/target-common.c
$(POSTCOMPILE)
mips-linux-watch.o: ${srcdir}/common/mips-linux-watch.c
$(COMPILE) $(srcdir)/common/mips-linux-watch.c
$(POSTCOMPILE)
#
# gdb/tui/ dependencies
#

View file

@ -0,0 +1,349 @@
/* Copyright (C) 2009-2013 Free Software Foundation, Inc.
This file is part of GDB.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include <sys/ptrace.h>
#include "mips-linux-watch.h"
#include "gdb_assert.h"
/* Assuming usable watch registers REGS, return the irw_mask of
register N. */
uint32_t
mips_linux_watch_get_irw_mask (struct pt_watch_regs *regs, int n)
{
switch (regs->style)
{
case pt_watch_style_mips32:
return regs->mips32.watch_masks[n] & IRW_MASK;
case pt_watch_style_mips64:
return regs->mips64.watch_masks[n] & IRW_MASK;
default:
internal_error (__FILE__, __LINE__,
_("Unrecognized watch register style"));
}
}
/* Assuming usable watch registers REGS, return the reg_mask of
register N. */
static uint32_t
get_reg_mask (struct pt_watch_regs *regs, int n)
{
switch (regs->style)
{
case pt_watch_style_mips32:
return regs->mips32.watch_masks[n] & ~IRW_MASK;
case pt_watch_style_mips64:
return regs->mips64.watch_masks[n] & ~IRW_MASK;
default:
internal_error (__FILE__, __LINE__,
_("Unrecognized watch register style"));
}
}
/* Assuming usable watch registers REGS, return the num_valid. */
uint32_t
mips_linux_watch_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 REGS, return the watchlo of
register N. */
CORE_ADDR
mips_linux_watch_get_watchlo (struct pt_watch_regs *regs, int n)
{
switch (regs->style)
{
case pt_watch_style_mips32:
return regs->mips32.watchlo[n];
case pt_watch_style_mips64:
return regs->mips64.watchlo[n];
default:
internal_error (__FILE__, __LINE__,
_("Unrecognized watch register style"));
}
}
/* Assuming usable watch registers REGS, set watchlo of register N to
VALUE. */
void
mips_linux_watch_set_watchlo (struct pt_watch_regs *regs, int n,
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[n] = (uint32_t) value;
break;
case pt_watch_style_mips64:
regs->mips64.watchlo[n] = value;
break;
default:
internal_error (__FILE__, __LINE__,
_("Unrecognized watch register style"));
}
}
/* Assuming usable watch registers REGS, return the watchhi of
register N. */
uint32_t
mips_linux_watch_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 REGS, set watchhi of register N to
VALUE. */
void
mips_linux_watch_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"));
}
}
/* Read the watch registers of process LWPID and store it in
WATCH_READBACK. Save true to *WATCH_READBACK_VALID if watch
registers are valid. Return 1 if watch registers are usable.
Cached information is used unless FORCE is true. */
int
mips_linux_read_watch_registers (long lwpid,
struct pt_watch_regs *watch_readback,
int *watch_readback_valid, int force)
{
if (force || *watch_readback_valid == 0)
{
if (ptrace (PTRACE_GET_WATCH_REGS, lwpid, 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. */
uint32_t
mips_linux_watch_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;
}
}
/* 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 REGS. The
address of added watch is ADDR, the length is LEN, and the mask
is IRW. Return 1 on success, 0 on failure. */
int
mips_linux_watch_try_one_watch (struct pt_watch_regs *regs,
CORE_ADDR addr, int len, uint32_t irw)
{
CORE_ADDR base_addr, last_byte, break_addr, segment_len;
CORE_ADDR mask_bits, t_low;
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 < mips_linux_watch_get_num_valid (regs); i++)
{
t_low = mips_linux_watch_get_watchlo (regs, i);
if (t_low != 0 && irw == ((uint32_t) t_low & irw))
{
t_hi = mips_linux_watch_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 < mips_linux_watch_get_num_valid (regs); i++)
{
t_low = mips_linux_watch_get_watchlo (regs, i);
if (t_low == 0
&& irw == (mips_linux_watch_get_irw_mask (regs, i) & irw))
{
if (mask_bits <= (get_reg_mask (regs, i) | IRW_MASK))
{
/* It fits, we'll take it. */
mips_linux_watch_set_watchlo (regs, i, base_addr | irw);
mips_linux_watch_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 < mips_linux_watch_get_num_valid (&regs_copy); i++)
{
t_low = mips_linux_watch_get_watchlo (&regs_copy, i);
t_hi = get_reg_mask (&regs_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));
mips_linux_watch_set_watchlo (&regs_copy, i,
(addr & ~mask_bits) | irw);
mips_linux_watch_set_watchhi (&regs_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;
}
/* Fill in the watch registers REGS with the currently cached
watches CURRENT_WATCHES. */
void
mips_linux_watch_populate_regs (struct mips_watchpoint *current_watches,
struct pt_watch_regs *regs)
{
struct mips_watchpoint *w;
int i;
/* Clear them out. */
for (i = 0; i < mips_linux_watch_get_num_valid (regs); i++)
{
mips_linux_watch_set_watchlo (regs, i, 0);
mips_linux_watch_set_watchhi (regs, i, 0);
}
w = current_watches;
while (w)
{
uint32_t irw = mips_linux_watch_type_to_irw (w->type);
i = mips_linux_watch_try_one_watch (regs, w->addr, w->len, irw);
/* They must all fit, because we previously calculated that they
would. */
gdb_assert (i);
w = w->next;
}
}

View file

@ -0,0 +1,126 @@
/* Copyright (C) 2009-2013 Free Software Foundation, Inc.
This file is part of GDB.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#ifndef MIPS_LINUX_WATCH_H
#define MIPS_LINUX_WATCH_H 1
#ifdef GDBSERVER
#include "server.h"
#else
#include "defs.h"
#endif
#include <asm/ptrace.h>
#include <stdint.h>
#include "break-common.h"
#define MAX_DEBUG_REGISTER 8
/* If macro PTRACE_GET_WATCH_REGS is not defined, kernel header doesn't
have hardware watchpoint-related structures. Define them below. */
#ifndef PTRACE_GET_WATCH_REGS
# define PTRACE_GET_WATCH_REGS 0xd0
# define PTRACE_SET_WATCH_REGS 0xd1
enum pt_watch_style {
pt_watch_style_mips32,
pt_watch_style_mips64
};
/* 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;
};
};
#endif /* !PTRACE_GET_WATCH_REGS */
#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)
/* 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;
};
uint32_t mips_linux_watch_get_num_valid (struct pt_watch_regs *regs);
uint32_t mips_linux_watch_get_irw_mask (struct pt_watch_regs *regs, int n);
CORE_ADDR mips_linux_watch_get_watchlo (struct pt_watch_regs *regs, int n);
void mips_linux_watch_set_watchlo (struct pt_watch_regs *regs, int n,
CORE_ADDR value);
uint32_t mips_linux_watch_get_watchhi (struct pt_watch_regs *regs, int n);
void mips_linux_watch_set_watchhi (struct pt_watch_regs *regs, int n,
uint16_t value);
int mips_linux_watch_try_one_watch (struct pt_watch_regs *regs,
CORE_ADDR addr, int len, uint32_t irw);
void mips_linux_watch_populate_regs (struct mips_watchpoint *current_watches,
struct pt_watch_regs *regs);
uint32_t mips_linux_watch_type_to_irw (int type);
int mips_linux_read_watch_registers (long lwpid,
struct pt_watch_regs *watch_readback,
int *watch_readback_valid, int force);
#endif

View file

@ -3,7 +3,7 @@ NAT_FILE= config/nm-linux.h
NATDEPFILES= inf-ptrace.o fork-child.o mips-linux-nat.o \
linux-thread-db.o proc-service.o \
linux-nat.o linux-osdata.o linux-fork.o \
linux-procfs.o linux-ptrace.o
linux-procfs.o linux-ptrace.o mips-linux-watch.o
NAT_CDEPS = $(srcdir)/proc-service.list
LOADLIBES = -ldl $(RDYNAMIC)

View file

@ -36,6 +36,8 @@
#include <sys/ptrace.h>
#include <asm/ptrace.h>
#include "mips-linux-watch.h"
#include "features/mips-linux.c"
#include "features/mips-dsp-linux.c"
#include "features/mips64-linux.c"
@ -461,71 +463,6 @@ mips_linux_read_description (struct target_ops *ops)
return have_dsp ? tdesc_mips64_dsp_linux : tdesc_mips64_linux;
}
#define MAX_DEBUG_REGISTER 8
/* If macro PTRACE_GET_WATCH_REGS is not defined, kernel header doesn't
have hardware watchpoint-related structures. Define them below. */
#ifndef PTRACE_GET_WATCH_REGS
# define PTRACE_GET_WATCH_REGS 0xd0
# define PTRACE_SET_WATCH_REGS 0xd1
enum pt_watch_style {
pt_watch_style_mips32,
pt_watch_style_mips64
};
/* 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;
};
};
#endif /* !PTRACE_GET_WATCH_REGS */
#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)
/* -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.
@ -537,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
@ -556,139 +481,6 @@ static struct mips_watchpoint *current_watches;
static struct pt_watch_regs watch_mirror;
/* Assuming usable watch registers REGS, return the irw_mask of
register N. */
static uint32_t
mips_linux_watch_get_irw_mask (struct pt_watch_regs *regs, int n)
{
switch (regs->style)
{
case pt_watch_style_mips32:
return regs->mips32.watch_masks[n] & IRW_MASK;
case pt_watch_style_mips64:
return regs->mips64.watch_masks[n] & IRW_MASK;
default:
internal_error (__FILE__, __LINE__,
_("Unrecognized watch register style"));
}
}
/* Assuming usable watch registers REGS, return the reg_mask of
register N. */
static uint32_t
get_reg_mask (struct pt_watch_regs *regs, int n)
{
switch (regs->style)
{
case pt_watch_style_mips32:
return regs->mips32.watch_masks[n] & ~IRW_MASK;
case pt_watch_style_mips64:
return regs->mips64.watch_masks[n] & ~IRW_MASK;
default:
internal_error (__FILE__, __LINE__,
_("Unrecognized watch register style"));
}
}
/* Assuming usable watch registers REGS, return the num_valid. */
static uint32_t
mips_linux_watch_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 REGS, return the watchlo of
register N. */
static CORE_ADDR
mips_linux_watch_get_watchlo (struct pt_watch_regs *regs, int n)
{
switch (regs->style)
{
case pt_watch_style_mips32:
return regs->mips32.watchlo[n];
case pt_watch_style_mips64:
return regs->mips64.watchlo[n];
default:
internal_error (__FILE__, __LINE__,
_("Unrecognized watch register style"));
}
}
/* Assuming usable watch registers REGS, set watchlo of register N to
VALUE. */
static void
mips_linux_watch_set_watchlo (struct pt_watch_regs *regs, int n,
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[n] = (uint32_t) value;
break;
case pt_watch_style_mips64:
regs->mips64.watchlo[n] = value;
break;
default:
internal_error (__FILE__, __LINE__,
_("Unrecognized watch register style"));
}
}
/* Assuming usable watch registers REGS, return the watchhi of
register N. */
static uint32_t
mips_linux_watch_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 REGS, set watchhi of register N to
VALUE. */
static void
mips_linux_watch_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)
@ -716,67 +508,6 @@ mips_show_dr (const char *func, CORE_ADDR addr,
i)));
}
/* Read the watch registers of process LWPID and store it in
WATCH_READBACK. Save true to *WATCH_READBACK_VALID if watch
registers are valid. Return 1 if watch registers are usable.
Cached information is used unless FORCE is true. */
static int
mips_linux_read_watch_registers (long lwpid,
struct pt_watch_regs *watch_readback,
int *watch_readback_valid, int force)
{
if (force || *watch_readback_valid == 0)
{
if (ptrace (PTRACE_GET_WATCH_REGS, lwpid, 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 uint32_t
mips_linux_watch_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;
}
}
/* Target to_can_use_hw_breakpoint implementation. Return 1 if we can
handle the specified watch type. */
@ -853,111 +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 REGS. The
address of added watch is ADDR, the length is LEN, and the mask
is IRW. Return 1 on success, 0 on failure. */
static int
mips_linux_watch_try_one_watch (struct pt_watch_regs *regs,
CORE_ADDR addr, int len, uint32_t irw)
{
CORE_ADDR base_addr, last_byte, break_addr, segment_len;
CORE_ADDR mask_bits, t_low;
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 < mips_linux_watch_get_num_valid (regs); i++)
{
t_low = mips_linux_watch_get_watchlo (regs, i);
if (t_low != 0 && irw == ((uint32_t) t_low & irw))
{
t_hi = mips_linux_watch_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 < mips_linux_watch_get_num_valid (regs); i++)
{
t_low = mips_linux_watch_get_watchlo (regs, i);
if (t_low == 0
&& irw == (mips_linux_watch_get_irw_mask (regs, i) & irw))
{
if (mask_bits <= (get_reg_mask (regs, i) | IRW_MASK))
{
/* It fits, we'll take it. */
mips_linux_watch_set_watchlo (regs, i, base_addr | irw);
mips_linux_watch_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 < mips_linux_watch_get_num_valid (&regs_copy); i++)
{
t_low = mips_linux_watch_get_watchlo (&regs_copy, i);
t_hi = get_reg_mask (&regs_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));
mips_linux_watch_set_watchlo (&regs_copy, i,
(addr & ~mask_bits) | irw);
mips_linux_watch_set_watchhi (&regs_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. */
@ -1014,36 +640,6 @@ mips_linux_new_thread (struct lwp_info *lp)
perror_with_name (_("Couldn't write debug register"));
}
/* Fill in the watch registers REGS with the currently cached
watches CURRENT_WATCHES. */
static void
mips_linux_watch_populate_regs (struct mips_watchpoint *current_watches,
struct pt_watch_regs *regs)
{
struct mips_watchpoint *w;
int i;
/* Clear them out. */
for (i = 0; i < mips_linux_watch_get_num_valid (regs); i++)
{
mips_linux_watch_set_watchlo (regs, i, 0);
mips_linux_watch_set_watchhi (regs, i, 0);
}
w = current_watches;
while (w)
{
uint32_t irw = mips_linux_watch_type_to_irw (w->type);
i = mips_linux_watch_try_one_watch (regs, w->addr, w->len, irw);
/* 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. */