binutils-gdb/gdb/hppab-nat.c

216 lines
6.1 KiB
C
Raw Normal View History

1992-10-21 05:57:35 +01:00
/* Machine-dependent hooks for the unix child process stratum. This
code is for the HP PA-RISC cpu.
Copyright 1986, 1987, 1989, 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
1992-10-21 05:57:35 +01:00
Contributed by the Center for Software Science at the
University of Utah (pa-gdb-bugs@cs.utah.edu).
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 2 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, write to the Free Software
1995-08-02 05:41:12 +02:00
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
1992-10-21 05:57:35 +01:00
#include "defs.h"
#include "inferior.h"
#include "target.h"
#include <sys/ptrace.h>
1992-10-21 05:57:35 +01:00
/* Use an extra level of indirection for ptrace calls.
This lets us breakpoint usefully on call_ptrace. It also
allows us to pass an extra argument to ptrace without
using an ANSI-C specific macro. */
1992-10-21 05:57:35 +01:00
#define ptrace call_ptrace
#if !defined (offsetof)
#define offsetof(TYPE, MEMBER) ((unsigned long) &((TYPE *)0)->MEMBER)
#endif
/* U_REGS_OFFSET is the offset of the registers within the u area. */
#if !defined (U_REGS_OFFSET)
#define U_REGS_OFFSET \
ptrace (PT_READ_U, inferior_pid, \
(PTRACE_ARG3_TYPE) (offsetof (struct user, u_ar0)), 0) \
- KERNEL_U_ADDR
#endif
/* Fetch one register. */
static void
fetch_register (regno)
int regno;
{
register unsigned int regaddr;
char buf[MAX_REGISTER_RAW_SIZE];
register int i;
/* Offset of registers within the u area. */
unsigned int offset;
offset = U_REGS_OFFSET;
regaddr = register_addr (regno, offset);
for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof (int))
{
errno = 0;
*(int *) &buf[i] = ptrace (PT_RUREGS, inferior_pid,
(PTRACE_ARG3_TYPE) regaddr, 0);
regaddr += sizeof (int);
if (errno != 0)
{
/* Warning, not error, in case we are attached; sometimes the
kernel doesn't let us at the registers. */
char *err = safe_strerror (errno);
char *msg = alloca (strlen (err) + 128);
sprintf (msg, "reading register %s: %s", reg_names[regno], err);
warning (msg);
goto error_exit;
1992-10-21 05:57:35 +01:00
}
}
supply_register (regno, buf);
error_exit:;
1992-10-21 05:57:35 +01:00
}
/* Fetch all registers, or just one, from the child process. */
void
fetch_inferior_registers (regno)
int regno;
{
if (regno == -1)
for (regno = 0; regno < NUM_REGS; regno++)
fetch_register (regno);
else
fetch_register (regno);
}
/* Store our register values back into the inferior.
If REGNO is -1, do this for all registers.
Otherwise, REGNO specifies which register (so we can save time). */
void
store_inferior_registers (regno)
int regno;
{
register unsigned int regaddr;
char buf[80];
1992-10-21 05:57:35 +01:00
extern char registers[];
register int i;
unsigned int offset = U_REGS_OFFSET;
int scratch;
1992-10-21 05:57:35 +01:00
if (regno >= 0)
{
if (CANNOT_STORE_REGISTER (regno))
return;
1992-10-21 05:57:35 +01:00
regaddr = register_addr (regno, offset);
errno = 0;
if (regno == PCOQ_HEAD_REGNUM || regno == PCOQ_TAIL_REGNUM)
{
scratch = *(int *) &registers[REGISTER_BYTE (regno)] | 0x3;
ptrace (PT_WUREGS, inferior_pid, (PTRACE_ARG3_TYPE) regaddr,
scratch);
if (errno != 0)
{
/* Error, even if attached. Failing to write these two
registers is pretty serious. */
sprintf (buf, "writing register number %d", regno);
perror_with_name (buf);
}
}
else
for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof(int))
{
errno = 0;
ptrace (PT_WUREGS, inferior_pid, (PTRACE_ARG3_TYPE) regaddr,
*(int *) &registers[REGISTER_BYTE (regno) + i]);
if (errno != 0)
{
/* Warning, not error, in case we are attached; sometimes the
kernel doesn't let us at the registers. */
char *err = safe_strerror (errno);
char *msg = alloca (strlen (err) + 128);
sprintf (msg, "writing register %s: %s",
reg_names[regno], err);
warning (msg);
return;
}
regaddr += sizeof(int);
}
1992-10-21 05:57:35 +01:00
}
else
for (regno = 0; regno < NUM_REGS; regno++)
store_inferior_registers (regno);
1992-10-21 05:57:35 +01:00
}
* breakpoint.h (enum bptype): Add bp_hardware_watchpoint and bp_watchpoint_scope breakpoints. (struct breakpoint): Add val_chain and related_breakpoint fields for use by watchpoints. * breakpoint.c (within_scope): Delete. No longer used. (TARGET_CAN_USE_HARDWARE_WATCHPOINT): Provide default definition. (target_{remove,insert}_watchpoint): Likewise. (can_use_hardware_watchpoint): New function. (remove_breakpoint): New function to remove a single breakpoint or hardware watchpoint. (insert_breakpoints): Handle insertion of hardware watchpoints. Store a copy of the value chain derived from the watchpoint expression. (remove_breakpoints): Simplify by using remove_breakpoint. (delete_breakpoint): Likewise. (watchpoint_check): Delete the watchpoint and watchpoint scope breakpoints when the watchpoint goes out of scope. Save & restore the current frame after checking watchpoints. (breakpoint_init_inferior): Likewise (restarting the program makes all local watchpoints go out of scope). (bpstat_stop_status): Handle hardware watchpoints much like normal watchpoints. Delete the watchpoint and watchpoint scope breakpoint when the watchpoint goes out of scope. Remove and reinsert all breakpoints before returning if we stopped when a hardware watchpoint fired. (watch_command): Use a hardware watchpoint when possible. If watching a local expression, build a scope breakpoint too. (map_breakpoint_numbers): Also call given function for any related breakpoints. (disable_breakpoint): Never disable a scope breakpoint. (enable_breakpoint): Handle hardware breakpoints much like normal breakpoints, but recompute the watchpoint_scope breakpoint's frame and address (if we have an associated scope breakpoint). (read_memory_nobpt): Handle hardware watchpoints like normal watchpoints. When necessary handle watchpoint_scope breakpoints. (print_it_normal, bpstat_what, breakpoint_1, mention): Likewise. (clear_command, breakpoint_re_set_one, enable_command): Likewise. (disable_command): Likewise. * blockframe.c (find_frame_addr_in_frame_chain): New function. Extern prototype added to frame.h * infrun.c (wait_for_inferior): Set current_frame and select a frame before checking if we stopped due to a hardare watchpoint firing. Handle stepping over hardware watchpoints. (normal_stop): Remove unnecessary call to select_frame. * value.h (value_release_to_mark): Declare. * values.c (value_release_to_mark): New function. * procfs.c (procfs_wait): Add cases for hardware watchpoints. (procfs_set_watchpoint, procfs_stopped_by_watchpoint): New functions. * hppab-nat.c (hppa_set_watchpoint): New function. * config/pa/nm-hppab.h (STOPPED_BY_WATCHPOINT): Define. (HAVE_STEPPABLE_WATCHPOINT): Define. (TARGET_CAN_USE_HARDWARE_WATCHPOINT): Define. (target_{insert,delete}_watchpoint): Define.
1994-04-13 23:57:00 +02:00
/* PT_PROT is specific to the PA BSD kernel and isn't documented
anywhere (except here).
PT_PROT allows one to enable/disable the data memory break bit
for pages of memory in an inferior process. This bit is used
to cause "Data memory break traps" to occur when the appropriate
page is written to.
The arguments are as follows:
PT_PROT -- The ptrace action to perform.
INFERIOR_PID -- The pid of the process who's page table entries
will be modified.
PT_ARGS -- The *address* of a 3 word block of memory which has
additional information:
word 0 -- The start address to watch. This should be a page-aligned
address.
word 1 -- The ending address to watch. Again, this should be a
page aligned address.
word 2 -- Nonzero to enable the data memory break bit on the
given address range or zero to disable the data memory break
bit on the given address range.
This call may fail if the given addresses are not valid in the inferior
process. This most often happens when restarting a program which
as watchpoints inserted on heap or stack memory. */
#define PT_PROT 21
int
hppa_set_watchpoint (addr, len, flag)
int addr, len, flag;
{
int pt_args[3];
pt_args[0] = addr;
pt_args[1] = addr + len;
pt_args[2] = flag;
/* Mask off the lower 12 bits since we want to work on a page basis. */
pt_args[0] >>= 12;
pt_args[1] >>= 12;
/* Rounding adjustments. */
pt_args[1] -= pt_args[0];
pt_args[1]++;
/* Put the lower 12 bits back as zero. */
pt_args[0] <<= 12;
pt_args[1] <<= 12;
/* Do it. */
return ptrace (PT_PROT, inferior_pid, (PTRACE_ARG3_TYPE) pt_args, 0);
}