#include "target.h"
#include <sys/ptrace.h>
-#ifdef FIVE_ARG_PTRACE
+/* 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. */
-/* Deal with HPUX 8.0 braindamage. */
-#define ptrace(a,b,c,d) ptrace(a,b,c,d,0)
-
-#endif
-
-#ifndef PT_ATTACH
-#define PT_ATTACH PTRACE_ATTACH
-#endif
-
-#ifndef PT_DETACH
-#define PT_DETACH PTRACE_DETACH
-#endif
-
-/* This function simply calls ptrace with the given arguments.
- It exists so that all calls to ptrace are isolated in this
- machine-dependent file. */
-
-int
-call_ptrace (request, pid, addr, data)
- int request, pid;
- PTRACE_ARG3_TYPE addr;
- int data;
-{
- return ptrace (request, pid, addr, data);
-}
-
-#ifdef DEBUG_PTRACE
-/* For the rest of the file, use an extra level of indirection */
-/* This lets us breakpoint usefully on call_ptrace. */
#define ptrace call_ptrace
-#endif
-
-void
-kill_inferior ()
-{
- if (inferior_pid == 0)
- return;
- ptrace (PT_KILL, inferior_pid, (PTRACE_ARG3_TYPE) 0, 0);
- wait ((int *)0);
- target_mourn_inferior ();
-}
-
-#ifdef ATTACH_DETACH
-
-/* Start debugging the process whose number is PID. */
-int
-attach (pid)
- int pid;
-{
- errno = 0;
- ptrace (PT_ATTACH, pid, (PTRACE_ARG3_TYPE) 0, 0);
- if (errno)
- perror_with_name ("ptrace");
- attach_flag = 1;
- return pid;
-}
-
-/* Stop debugging the process whose number is PID
- and continue it with signal number SIGNAL.
- SIGNAL = 0 means just continue it. */
-
-void
-detach (signal)
- int signal;
-{
- errno = 0;
- ptrace (PT_DETACH, inferior_pid, (PTRACE_ARG3_TYPE) 1, signal);
- if (errno)
- perror_with_name ("ptrace");
- attach_flag = 0;
-}
-#endif /* ATTACH_DETACH */
-\f
-
-
-/* KERNEL_U_ADDR is the amount to subtract from u.u_ar0
- to get the offset in the core file of the register values. */
-#if defined (KERNEL_U_ADDR_BSD)
-/* Get kernel_u_addr using BSD-style nlist(). */
-CORE_ADDR kernel_u_addr;
-
-#include <a.out.gnu.h> /* For struct nlist */
-
-void
-_initialize_kernel_u_addr ()
-{
- struct nlist names[2];
-
- names[0].n_un.n_name = "_u";
- names[1].n_un.n_name = NULL;
- if (nlist ("/vmunix", names) == 0)
- kernel_u_addr = names[0].n_value;
- else
- fatal ("Unable to get kernel u area address.");
-}
-#endif /* KERNEL_U_ADDR_BSD. */
-
-#if defined (KERNEL_U_ADDR_HPUX)
-/* Get kernel_u_addr using HPUX-style nlist(). */
-CORE_ADDR kernel_u_addr;
-
-struct hpnlist {
- char * n_name;
- long n_value;
- unsigned char n_type;
- unsigned char n_length;
- short n_almod;
- short n_unused;
-};
-static struct hpnlist nl[] = {{ "_u", -1, }, { (char *) 0, }};
-
-/* read the value of the u area from the hp-ux kernel */
-void _initialize_kernel_u_addr ()
-{
- struct user u;
- nlist ("/hp-ux", &nl);
- kernel_u_addr = nl[0].n_value;
-}
-#endif /* KERNEL_U_ADDR_HPUX. */
#if !defined (offsetof)
#define offsetof(TYPE, MEMBER) ((unsigned long) &((TYPE *)0)->MEMBER)
int regno;
{
register unsigned int regaddr;
+ char buf[80];
extern char registers[];
register int i;
-
unsigned int offset = U_REGS_OFFSET;
+ int scratch;
if (regno >= 0)
{
+ if (CANNOT_STORE_REGISTER (regno))
+ return;
regaddr = register_addr (regno, offset);
- for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof(int))
- {
- errno = 0;
- ptrace (PT_WUREGS, inferior_pid, (PTRACE_ARG3_TYPE) regaddr,
- *(int *) ®isters[REGISTER_BYTE (regno) + i]);
- if (errno != 0)
- {
- char *err = safe_strerror (errno);
- char *msg = alloca (strlen (err) + 128);
- sprintf (msg, "writing register %s: %s", reg_names[regno], err);
- warning (msg);
- }
- regaddr += sizeof(int);
- }
+ errno = 0;
+ if (regno == PCOQ_HEAD_REGNUM || regno == PCOQ_TAIL_REGNUM)
+ {
+ scratch = *(int *) ®isters[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 *) ®isters[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);
+ }
}
else
- {
- for (regno = 0; regno < NUM_REGS; regno++)
- {
- if (CANNOT_STORE_REGISTER (regno))
- continue;
- store_inferior_registers (regno);
- }
- }
- return;
+ for (regno = 0; regno < NUM_REGS; regno++)
+ store_inferior_registers (regno);
}
-/* Resume execution of the inferior process.
- If STEP is nonzero, single-step it.
- If SIGNAL is nonzero, give it that signal. */
+/* PT_PROT is specific to the PA BSD kernel and isn't documented
+ anywhere (except here).
-void
-child_resume (step, signal)
- int step;
- int signal;
-{
- errno = 0;
+ 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.
- /* An address of (PTRACE_ARG3_TYPE) 1 tells ptrace to continue from where
- it was. (If GDB wanted it to start some other way, we have already
- written a new PC value to the child.) */
+ The arguments are as follows:
- if (step)
- ptrace (PT_STEP, inferior_pid, (PTRACE_ARG3_TYPE) 1, signal);
- else
- ptrace (PT_CONTINUE, inferior_pid, (PTRACE_ARG3_TYPE) 1, signal);
+ PT_PROT -- The ptrace action to perform.
- if (errno)
- perror_with_name ("ptrace");
-}
+ INFERIOR_PID -- The pid of the process who's page table entries
+ will be modified.
-/* NOTE! I tried using PTRACE_READDATA, etc., to read and write memory
- in the NEW_SUN_PTRACE case.
- It ought to be straightforward. But it appears that writing did
- not write the data that I specified. I cannot understand where
- it got the data that it actually did write. */
-
-/* Copy LEN bytes to or from inferior's memory starting at MEMADDR
- to debugger memory starting at MYADDR. Copy to inferior if
- WRITE is nonzero.
-
- Returns the length copied, which is either the LEN argument or zero.
- This xfer function does not do partial moves, since child_ops
- doesn't allow memory operations to cross below us in the target stack
- anyway. */
+ PT_ARGS -- The *address* of a 3 word block of memory which has
+ additional information:
-int
-child_xfer_memory (memaddr, myaddr, len, write, target)
- CORE_ADDR memaddr;
- char *myaddr;
- int len;
- int write;
- struct target_ops *target; /* ignored */
-{
- register int i;
- /* Round starting address down to longword boundary. */
- register CORE_ADDR addr = memaddr & - sizeof (int);
- /* Round ending address up; get number of longwords that makes. */
- register int count
- = (((memaddr + len) - addr) + sizeof (int) - 1) / sizeof (int);
- /* Allocate buffer of that many longwords. */
- register int *buffer = (int *) alloca (count * sizeof (int));
-
- if (write)
- {
- /* Fill start and end extra bytes of buffer with existing memory data. */
+ word 0 -- The start address to watch. This should be a page-aligned
+ address.
- if (addr != memaddr || len < (int)sizeof (int)) {
- /* Need part of initial word -- fetch it. */
- buffer[0] = ptrace (PT_READ_I, inferior_pid, (PTRACE_ARG3_TYPE) addr,
- 0);
- }
+ word 1 -- The ending address to watch. Again, this should be a
+ page aligned address.
- if (count > 1) /* FIXME, avoid if even boundary */
- {
- buffer[count - 1]
- = ptrace (PT_READ_I, inferior_pid,
- (PTRACE_ARG3_TYPE) (addr + (count - 1) * sizeof (int)),
- 0);
- }
+ 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.
- /* Copy data to be written over corresponding part of buffer */
+ 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
- bcopy (myaddr, (char *) buffer + (memaddr & (sizeof (int) - 1)), len);
+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;
- /* Write the entire buffer. */
+ /* Mask off the lower 12 bits since we want to work on a page basis. */
+ pt_args[0] >>= 12;
+ pt_args[1] >>= 12;
- for (i = 0; i < count; i++, addr += sizeof (int))
- {
- errno = 0;
- ptrace (PT_WRITE_D, inferior_pid, (PTRACE_ARG3_TYPE) addr,
- buffer[i]);
- if (errno)
- {
- /* Using the appropriate one (I or D) is necessary for
- Gould NP1, at least. */
- errno = 0;
- ptrace (PT_WRITE_I, inferior_pid, (PTRACE_ARG3_TYPE) addr,
- buffer[i]);
- }
- if (errno)
- return 0;
- }
- }
- else
- {
- /* Read all the longwords */
- for (i = 0; i < count; i++, addr += sizeof (int))
- {
- errno = 0;
- buffer[i] = ptrace (PT_READ_I, inferior_pid,
- (PTRACE_ARG3_TYPE) addr, 0);
- if (errno)
- return 0;
- QUIT;
- }
+ /* Rounding adjustments. */
+ pt_args[1] -= pt_args[0];
+ pt_args[1]++;
- /* Copy appropriate bytes out of the buffer. */
- bcopy ((char *) buffer + (memaddr & (sizeof (int) - 1)), myaddr, len);
- }
- return len;
-}
+ /* 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);
+}