X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gdb%2Fia64-linux-nat.c;h=361fc6ae375f44dd7b8c85b06b39ee95d83c6fef;hb=f1f28025c3ea75d5368ddd3046461648145b89b3;hp=00f66fb2e83693883d58b72d7dbbc12a9c7a08e2;hpb=287a334e725d8a095303b6017b725e511319ff8a;p=deliverable%2Fbinutils-gdb.git
diff --git a/gdb/ia64-linux-nat.c b/gdb/ia64-linux-nat.c
index 00f66fb2e8..361fc6ae37 100644
--- a/gdb/ia64-linux-nat.c
+++ b/gdb/ia64-linux-nat.c
@@ -1,14 +1,13 @@
/* Functions specific to running gdb native on IA-64 running
GNU/Linux.
- Copyright 1999, 2000, 2001, 2002, 2003 Free Software Foundation,
- Inc.
+ Copyright (C) 1999-2020 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 2 of the License, or
+ 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,
@@ -17,20 +16,19 @@
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
- Foundation, Inc., 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA. */
+ along with this program. If not, see . */
#include "defs.h"
-#include "gdb_string.h"
#include "inferior.h"
#include "target.h"
#include "gdbcore.h"
#include "regcache.h"
+#include "ia64-tdep.h"
+#include "linux-nat.h"
#include
-#include
-#include "gdb_wait.h"
+#include "nat/gdb_ptrace.h"
+#include "gdbsupport/gdb_wait.h"
#ifdef HAVE_SYS_REG_H
#include
#endif
@@ -40,9 +38,52 @@
#include
#include
-/* Prototypes for supply_gregset etc. */
+/* Prototypes for supply_gregset etc. */
#include "gregset.h"
+#include "inf-ptrace.h"
+
+class ia64_linux_nat_target final : public linux_nat_target
+{
+public:
+ /* Add our register access methods. */
+ void fetch_registers (struct regcache *, int) override;
+ void store_registers (struct regcache *, int) override;
+
+ enum target_xfer_status xfer_partial (enum target_object object,
+ const char *annex,
+ gdb_byte *readbuf,
+ const gdb_byte *writebuf,
+ ULONGEST offset, ULONGEST len,
+ ULONGEST *xfered_len) override;
+
+ /* Override watchpoint routines. */
+
+ /* The IA-64 architecture can step over a watch point (without
+ triggering it again) if the "dd" (data debug fault disable) bit
+ in the processor status word is set.
+
+ This PSR bit is set in
+ ia64_linux_nat_target::stopped_by_watchpoint when the code there
+ has determined that a hardware watchpoint has indeed been hit.
+ The CPU will then be able to execute one instruction without
+ triggering a watchpoint. */
+ bool have_steppable_watchpoint () override { return true; }
+
+ int can_use_hw_breakpoint (enum bptype, int, int) override;
+ bool stopped_by_watchpoint () override;
+ bool stopped_data_address (CORE_ADDR *) override;
+ int insert_watchpoint (CORE_ADDR, int, enum target_hw_bp_type,
+ struct expression *) override;
+ int remove_watchpoint (CORE_ADDR, int, enum target_hw_bp_type,
+ struct expression *) override;
+ /* Override linux_nat_target low methods. */
+ void low_new_thread (struct lwp_info *lp) override;
+ bool low_status_is_event (int status) override;
+};
+
+static ia64_linux_nat_target the_ia64_linux_nat_target;
+
/* These must match the order of the register names.
Some sort of lookup table is needed because the offsets associated
@@ -51,7 +92,7 @@
static int u_offsets[] =
{
/* general registers */
- -1, /* gr0 not available; i.e, it's always zero */
+ -1, /* gr0 not available; i.e, it's always zero. */
PT_R1,
PT_R2,
PT_R3,
@@ -83,7 +124,7 @@ static int u_offsets[] =
PT_R29,
PT_R30,
PT_R31,
- /* gr32 through gr127 not directly available via the ptrace interface */
+ /* gr32 through gr127 not directly available via the ptrace interface. */
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
@@ -91,7 +132,7 @@ static int u_offsets[] =
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
/* Floating point registers */
- -1, -1, /* f0 and f1 not available (f0 is +0.0 and f1 is +1.0) */
+ -1, -1, /* f0 and f1 not available (f0 is +0.0 and f1 is +1.0). */
PT_F2,
PT_F3,
PT_F4,
@@ -218,7 +259,7 @@ static int u_offsets[] =
PT_F125,
PT_F126,
PT_F127,
- /* predicate registers - we don't fetch these individually */
+ /* Predicate registers - we don't fetch these individually. */
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
@@ -236,14 +277,14 @@ static int u_offsets[] =
PT_B5,
PT_B6,
PT_B7,
- /* virtual frame pointer and virtual return address pointer */
+ /* Virtual frame pointer and virtual return address pointer. */
-1, -1,
/* other registers */
PT_PR,
PT_CR_IIP, /* ip */
PT_CR_IPSR, /* psr */
PT_CFM, /* cfm */
- /* kernel registers not visible via ptrace interface (?) */
+ /* kernel registers not visible via ptrace interface (?) */
-1, -1, -1, -1, -1, -1, -1, -1,
/* hole */
-1, -1, -1, -1, -1, -1, -1, -1,
@@ -252,7 +293,7 @@ static int u_offsets[] =
PT_AR_BSPSTORE,
PT_AR_RNAT,
-1,
- -1, /* Not available: FCR, IA32 floating control register */
+ -1, /* Not available: FCR, IA32 floating control register. */
-1, -1,
-1, /* Not available: EFLAG */
-1, /* Not available: CSD */
@@ -273,7 +314,7 @@ static int u_offsets[] =
-1, -1, -1, -1, -1, -1, -1, -1, -1,
PT_AR_PFS,
PT_AR_LC,
- -1, /* Not available: EC, the Epilog Count register */
+ PT_AR_EC,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
@@ -282,7 +323,7 @@ static int u_offsets[] =
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1,
/* nat bits - not fetched directly; instead we obtain these bits from
- either rnat or unat or from memory. */
+ either rnat or unat or from memory. */
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
@@ -301,13 +342,13 @@ static int u_offsets[] =
-1, -1, -1, -1, -1, -1, -1, -1,
};
-CORE_ADDR
-register_addr (int regno, CORE_ADDR blockend)
+static CORE_ADDR
+ia64_register_addr (struct gdbarch *gdbarch, int regno)
{
CORE_ADDR addr;
- if (regno < 0 || regno >= NUM_REGS)
- error ("Invalid register number %d.", regno);
+ if (regno < 0 || regno >= gdbarch_num_regs (gdbarch))
+ error (_("Invalid register number %d."), regno);
if (u_offsets[regno] == -1)
addr = 0;
@@ -317,14 +358,16 @@ register_addr (int regno, CORE_ADDR blockend)
return addr;
}
-int ia64_cannot_fetch_register (regno)
- int regno;
+static int
+ia64_cannot_fetch_register (struct gdbarch *gdbarch, int regno)
{
- return regno < 0 || regno >= NUM_REGS || u_offsets[regno] == -1;
+ return regno < 0
+ || regno >= gdbarch_num_regs (gdbarch)
+ || u_offsets[regno] == -1;
}
-int ia64_cannot_store_register (regno)
- int regno;
+static int
+ia64_cannot_store_register (struct gdbarch *gdbarch, int regno)
{
/* Rationale behind not permitting stores to bspstore...
@@ -355,63 +398,64 @@ int ia64_cannot_store_register (regno)
were previously read from the inferior process to be written
back.) */
- return regno < 0 || regno >= NUM_REGS || u_offsets[regno] == -1
+ return regno < 0
+ || regno >= gdbarch_num_regs (gdbarch)
+ || u_offsets[regno] == -1
|| regno == IA64_BSPSTORE_REGNUM;
}
void
-supply_gregset (gregset_t *gregsetp)
+supply_gregset (struct regcache *regcache, const gregset_t *gregsetp)
{
int regi;
- greg_t *regp = (greg_t *) gregsetp;
+ const greg_t *regp = (const greg_t *) gregsetp;
for (regi = IA64_GR0_REGNUM; regi <= IA64_GR31_REGNUM; regi++)
{
- supply_register (regi, (char *) (regp + (regi - IA64_GR0_REGNUM)));
+ regcache->raw_supply (regi, regp + (regi - IA64_GR0_REGNUM));
}
/* FIXME: NAT collection bits are at index 32; gotta deal with these
- somehow... */
+ somehow... */
- supply_register (IA64_PR_REGNUM, (char *) (regp + 33));
+ regcache->raw_supply (IA64_PR_REGNUM, regp + 33);
for (regi = IA64_BR0_REGNUM; regi <= IA64_BR7_REGNUM; regi++)
{
- supply_register (regi, (char *) (regp + 34 + (regi - IA64_BR0_REGNUM)));
+ regcache->raw_supply (regi, regp + 34 + (regi - IA64_BR0_REGNUM));
}
- supply_register (IA64_IP_REGNUM, (char *) (regp + 42));
- supply_register (IA64_CFM_REGNUM, (char *) (regp + 43));
- supply_register (IA64_PSR_REGNUM, (char *) (regp + 44));
- supply_register (IA64_RSC_REGNUM, (char *) (regp + 45));
- supply_register (IA64_BSP_REGNUM, (char *) (regp + 46));
- supply_register (IA64_BSPSTORE_REGNUM, (char *) (regp + 47));
- supply_register (IA64_RNAT_REGNUM, (char *) (regp + 48));
- supply_register (IA64_CCV_REGNUM, (char *) (regp + 49));
- supply_register (IA64_UNAT_REGNUM, (char *) (regp + 50));
- supply_register (IA64_FPSR_REGNUM, (char *) (regp + 51));
- supply_register (IA64_PFS_REGNUM, (char *) (regp + 52));
- supply_register (IA64_LC_REGNUM, (char *) (regp + 53));
- supply_register (IA64_EC_REGNUM, (char *) (regp + 54));
+ regcache->raw_supply (IA64_IP_REGNUM, regp + 42);
+ regcache->raw_supply (IA64_CFM_REGNUM, regp + 43);
+ regcache->raw_supply (IA64_PSR_REGNUM, regp + 44);
+ regcache->raw_supply (IA64_RSC_REGNUM, regp + 45);
+ regcache->raw_supply (IA64_BSP_REGNUM, regp + 46);
+ regcache->raw_supply (IA64_BSPSTORE_REGNUM, regp + 47);
+ regcache->raw_supply (IA64_RNAT_REGNUM, regp + 48);
+ regcache->raw_supply (IA64_CCV_REGNUM, regp + 49);
+ regcache->raw_supply (IA64_UNAT_REGNUM, regp + 50);
+ regcache->raw_supply (IA64_FPSR_REGNUM, regp + 51);
+ regcache->raw_supply (IA64_PFS_REGNUM, regp + 52);
+ regcache->raw_supply (IA64_LC_REGNUM, regp + 53);
+ regcache->raw_supply (IA64_EC_REGNUM, regp + 54);
}
void
-fill_gregset (gregset_t *gregsetp, int regno)
+fill_gregset (const struct regcache *regcache, gregset_t *gregsetp, int regno)
{
int regi;
greg_t *regp = (greg_t *) gregsetp;
#define COPY_REG(_idx_,_regi_) \
if ((regno == -1) || regno == _regi_) \
- memcpy (regp + _idx_, &deprecated_registers[DEPRECATED_REGISTER_BYTE (_regi_)], \
- DEPRECATED_REGISTER_RAW_SIZE (_regi_))
+ regcache->raw_collect (_regi_, regp + _idx_)
for (regi = IA64_GR0_REGNUM; regi <= IA64_GR31_REGNUM; regi++)
{
COPY_REG (regi - IA64_GR0_REGNUM, regi);
}
- /* FIXME: NAT collection bits at index 32? */
+ /* FIXME: NAT collection bits at index 32? */
COPY_REG (33, IA64_PR_REGNUM);
@@ -437,41 +481,48 @@ fill_gregset (gregset_t *gregsetp, int regno)
/* Given a pointer to a floating point register set in /proc format
(fpregset_t *), unpack the register contents and supply them as gdb's
- idea of the current floating point register values. */
+ idea of the current floating point register values. */
void
-supply_fpregset (fpregset_t *fpregsetp)
+supply_fpregset (struct regcache *regcache, const fpregset_t *fpregsetp)
{
int regi;
- char *from;
+ const char *from;
+ const gdb_byte f_zero[16] = { 0 };
+ const gdb_byte f_one[16] =
+ { 0, 0, 0, 0, 0, 0, 0, 0x80, 0xff, 0xff, 0, 0, 0, 0, 0, 0 };
- for (regi = IA64_FR0_REGNUM; regi <= IA64_FR127_REGNUM; regi++)
+ /* Kernel generated cores have fr1==0 instead of 1.0. Older GDBs
+ did the same. So ignore whatever might be recorded in fpregset_t
+ for fr0/fr1 and always supply their expected values. */
+
+ /* fr0 is always read as zero. */
+ regcache->raw_supply (IA64_FR0_REGNUM, f_zero);
+ /* fr1 is always read as one (1.0). */
+ regcache->raw_supply (IA64_FR1_REGNUM, f_one);
+
+ for (regi = IA64_FR2_REGNUM; regi <= IA64_FR127_REGNUM; regi++)
{
- from = (char *) &((*fpregsetp)[regi - IA64_FR0_REGNUM]);
- supply_register (regi, from);
+ from = (const char *) &((*fpregsetp)[regi - IA64_FR0_REGNUM]);
+ regcache->raw_supply (regi, from);
}
}
/* Given a pointer to a floating point register set in /proc format
(fpregset_t *), update the register specified by REGNO from gdb's idea
of the current floating point register set. If REGNO is -1, update
- them all. */
+ them all. */
void
-fill_fpregset (fpregset_t *fpregsetp, int regno)
+fill_fpregset (const struct regcache *regcache,
+ fpregset_t *fpregsetp, int regno)
{
int regi;
- char *to;
- char *from;
for (regi = IA64_FR0_REGNUM; regi <= IA64_FR127_REGNUM; regi++)
{
if ((regno == -1) || (regno == regi))
- {
- from = (char *) &deprecated_registers[DEPRECATED_REGISTER_BYTE (regi)];
- to = (char *) &((*fpregsetp)[regi - IA64_FR0_REGNUM]);
- memcpy (to, from, DEPRECATED_REGISTER_RAW_SIZE (regi));
- }
+ regcache->raw_collect (regi, &((*fpregsetp)[regi - IA64_FR0_REGNUM]));
}
}
@@ -481,55 +532,35 @@ fill_fpregset (fpregset_t *fpregsetp, int regno)
static void
enable_watchpoints_in_psr (ptid_t ptid)
{
- CORE_ADDR psr;
+ struct regcache *regcache = get_thread_regcache (ptid);
+ ULONGEST psr;
- psr = read_register_pid (IA64_PSR_REGNUM, ptid);
+ regcache_cooked_read_unsigned (regcache, IA64_PSR_REGNUM, &psr);
if (!(psr & IA64_PSR_DB))
{
psr |= IA64_PSR_DB; /* Set the db bit - this enables hardware
- watchpoints and breakpoints. */
- write_register_pid (IA64_PSR_REGNUM, psr, ptid);
+ watchpoints and breakpoints. */
+ regcache_cooked_write_unsigned (regcache, IA64_PSR_REGNUM, psr);
}
}
-static long
-fetch_debug_register (ptid_t ptid, int idx)
-{
- long val;
- int tid;
-
- tid = TIDGET (ptid);
- if (tid == 0)
- tid = PIDGET (ptid);
-
- val = ptrace (PT_READ_U, tid, (PTRACE_ARG3_TYPE) (PT_DBR + 8 * idx), 0);
-
- return val;
-}
+static long debug_registers[8];
static void
store_debug_register (ptid_t ptid, int idx, long val)
{
int tid;
- tid = TIDGET (ptid);
+ tid = ptid.lwp ();
if (tid == 0)
- tid = PIDGET (ptid);
+ tid = ptid.pid ();
- (void) ptrace (PT_WRITE_U, tid, (PTRACE_ARG3_TYPE) (PT_DBR + 8 * idx), val);
-}
-
-static void
-fetch_debug_register_pair (ptid_t ptid, int idx, long *dbr_addr, long *dbr_mask)
-{
- if (dbr_addr)
- *dbr_addr = fetch_debug_register (ptid, 2 * idx);
- if (dbr_mask)
- *dbr_mask = fetch_debug_register (ptid, 2 * idx + 1);
+ (void) ptrace (PT_WRITE_U, tid, (PTRACE_TYPE_ARG3) (PT_DBR + 8 * idx), val);
}
static void
-store_debug_register_pair (ptid_t ptid, int idx, long *dbr_addr, long *dbr_mask)
+store_debug_register_pair (ptid_t ptid, int idx, long *dbr_addr,
+ long *dbr_mask)
{
if (dbr_addr)
store_debug_register (ptid, 2 * idx, *dbr_addr);
@@ -551,8 +582,11 @@ is_power_of_2 (int val)
}
int
-ia64_linux_insert_watchpoint (ptid_t ptid, CORE_ADDR addr, int len, int rw)
+ia64_linux_nat_target::insert_watchpoint (CORE_ADDR addr, int len,
+ enum target_hw_bp_type type,
+ struct expression *cond)
{
+ struct lwp_info *lp;
int idx;
long dbr_addr, dbr_mask;
int max_watchpoints = 4;
@@ -562,10 +596,10 @@ ia64_linux_insert_watchpoint (ptid_t ptid, CORE_ADDR addr, int len, int rw)
for (idx = 0; idx < max_watchpoints; idx++)
{
- fetch_debug_register_pair (ptid, idx, NULL, &dbr_mask);
+ dbr_mask = debug_registers[idx * 2 + 1];
if ((dbr_mask & (0x3UL << 62)) == 0)
{
- /* Exit loop if both r and w bits clear */
+ /* Exit loop if both r and w bits clear. */
break;
}
}
@@ -576,7 +610,7 @@ ia64_linux_insert_watchpoint (ptid_t ptid, CORE_ADDR addr, int len, int rw)
dbr_addr = (long) addr;
dbr_mask = (~(len - 1) & 0x00ffffffffffffffL); /* construct mask to match */
dbr_mask |= 0x0800000000000000L; /* Only match privilege level 3 */
- switch (rw)
+ switch (type)
{
case hw_write:
dbr_mask |= (1L << 62); /* Set w bit */
@@ -591,14 +625,21 @@ ia64_linux_insert_watchpoint (ptid_t ptid, CORE_ADDR addr, int len, int rw)
return -1;
}
- store_debug_register_pair (ptid, idx, &dbr_addr, &dbr_mask);
- enable_watchpoints_in_psr (ptid);
+ debug_registers[2 * idx] = dbr_addr;
+ debug_registers[2 * idx + 1] = dbr_mask;
+ ALL_LWPS (lp)
+ {
+ store_debug_register_pair (lp->ptid, idx, &dbr_addr, &dbr_mask);
+ enable_watchpoints_in_psr (lp->ptid);
+ }
return 0;
}
int
-ia64_linux_remove_watchpoint (ptid_t ptid, CORE_ADDR addr, int len)
+ia64_linux_nat_target::remove_watchpoint (CORE_ADDR addr, int len,
+ enum target_hw_bp_type type,
+ struct expression *cond)
{
int idx;
long dbr_addr, dbr_mask;
@@ -609,50 +650,281 @@ ia64_linux_remove_watchpoint (ptid_t ptid, CORE_ADDR addr, int len)
for (idx = 0; idx < max_watchpoints; idx++)
{
- fetch_debug_register_pair (ptid, idx, &dbr_addr, &dbr_mask);
+ dbr_addr = debug_registers[2 * idx];
+ dbr_mask = debug_registers[2 * idx + 1];
if ((dbr_mask & (0x3UL << 62)) && addr == (CORE_ADDR) dbr_addr)
{
+ struct lwp_info *lp;
+
+ debug_registers[2 * idx] = 0;
+ debug_registers[2 * idx + 1] = 0;
dbr_addr = 0;
dbr_mask = 0;
- store_debug_register_pair (ptid, idx, &dbr_addr, &dbr_mask);
+
+ ALL_LWPS (lp)
+ store_debug_register_pair (lp->ptid, idx, &dbr_addr, &dbr_mask);
+
return 0;
}
}
return -1;
}
-CORE_ADDR
-ia64_linux_stopped_by_watchpoint (ptid_t ptid)
+void
+ia64_linux_nat_target::low_new_thread (struct lwp_info *lp)
+{
+ int i, any;
+
+ any = 0;
+ for (i = 0; i < 8; i++)
+ {
+ if (debug_registers[i] != 0)
+ any = 1;
+ store_debug_register (lp->ptid, i, debug_registers[i]);
+ }
+
+ if (any)
+ enable_watchpoints_in_psr (lp->ptid);
+}
+
+bool
+ia64_linux_nat_target::stopped_data_address (CORE_ADDR *addr_p)
{
CORE_ADDR psr;
- int tid;
- struct siginfo siginfo;
+ siginfo_t siginfo;
+ struct regcache *regcache = get_current_regcache ();
- tid = TIDGET(ptid);
- if (tid == 0)
- tid = PIDGET (ptid);
-
- errno = 0;
- ptrace (PTRACE_GETSIGINFO, tid, (PTRACE_ARG3_TYPE) 0, &siginfo);
+ if (!linux_nat_get_siginfo (inferior_ptid, &siginfo))
+ return false;
- if (errno != 0 || siginfo.si_signo != SIGTRAP ||
- (siginfo.si_code & 0xffff) != 0x0004 /* TRAP_HWBKPT */)
- return 0;
+ if (siginfo.si_signo != SIGTRAP
+ || (siginfo.si_code & 0xffff) != 0x0004 /* TRAP_HWBKPT */)
+ return false;
- psr = read_register_pid (IA64_PSR_REGNUM, ptid);
+ regcache_cooked_read_unsigned (regcache, IA64_PSR_REGNUM, &psr);
psr |= IA64_PSR_DD; /* Set the dd bit - this will disable the watchpoint
- for the next instruction */
- write_register_pid (IA64_PSR_REGNUM, psr, ptid);
+ for the next instruction. */
+ regcache_cooked_write_unsigned (regcache, IA64_PSR_REGNUM, psr);
+
+ *addr_p = (CORE_ADDR) siginfo.si_addr;
+ return true;
+}
+
+bool
+ia64_linux_nat_target::stopped_by_watchpoint ()
+{
+ CORE_ADDR addr;
+ return stopped_data_address (&addr);
+}
+
+int
+ia64_linux_nat_target::can_use_hw_breakpoint (enum bptype type,
+ int cnt, int othertype)
+{
+ return 1;
+}
+
+
+/* Fetch register REGNUM from the inferior. */
+
+static void
+ia64_linux_fetch_register (struct regcache *regcache, int regnum)
+{
+ struct gdbarch *gdbarch = regcache->arch ();
+ CORE_ADDR addr;
+ size_t size;
+ PTRACE_TYPE_RET *buf;
+ pid_t pid;
+ int i;
- return (CORE_ADDR) siginfo.si_addr;
+ /* r0 cannot be fetched but is always zero. */
+ if (regnum == IA64_GR0_REGNUM)
+ {
+ const gdb_byte zero[8] = { 0 };
+
+ gdb_assert (sizeof (zero) == register_size (gdbarch, regnum));
+ regcache->raw_supply (regnum, zero);
+ return;
+ }
+
+ /* fr0 cannot be fetched but is always zero. */
+ if (regnum == IA64_FR0_REGNUM)
+ {
+ const gdb_byte f_zero[16] = { 0 };
+
+ gdb_assert (sizeof (f_zero) == register_size (gdbarch, regnum));
+ regcache->raw_supply (regnum, f_zero);
+ return;
+ }
+
+ /* fr1 cannot be fetched but is always one (1.0). */
+ if (regnum == IA64_FR1_REGNUM)
+ {
+ const gdb_byte f_one[16] =
+ { 0, 0, 0, 0, 0, 0, 0, 0x80, 0xff, 0xff, 0, 0, 0, 0, 0, 0 };
+
+ gdb_assert (sizeof (f_one) == register_size (gdbarch, regnum));
+ regcache->raw_supply (regnum, f_one);
+ return;
+ }
+
+ if (ia64_cannot_fetch_register (gdbarch, regnum))
+ {
+ regcache->raw_supply (regnum, NULL);
+ return;
+ }
+
+ pid = get_ptrace_pid (regcache->ptid ());
+
+ /* This isn't really an address, but ptrace thinks of it as one. */
+ addr = ia64_register_addr (gdbarch, regnum);
+ size = register_size (gdbarch, regnum);
+
+ gdb_assert ((size % sizeof (PTRACE_TYPE_RET)) == 0);
+ buf = (PTRACE_TYPE_RET *) alloca (size);
+
+ /* Read the register contents from the inferior a chunk at a time. */
+ for (i = 0; i < size / sizeof (PTRACE_TYPE_RET); i++)
+ {
+ errno = 0;
+ buf[i] = ptrace (PT_READ_U, pid, (PTRACE_TYPE_ARG3)addr, 0);
+ if (errno != 0)
+ error (_("Couldn't read register %s (#%d): %s."),
+ gdbarch_register_name (gdbarch, regnum),
+ regnum, safe_strerror (errno));
+
+ addr += sizeof (PTRACE_TYPE_RET);
+ }
+ regcache->raw_supply (regnum, buf);
+}
+
+/* Fetch register REGNUM from the inferior. If REGNUM is -1, do this
+ for all registers. */
+
+void
+ia64_linux_nat_target::fetch_registers (struct regcache *regcache, int regnum)
+{
+ if (regnum == -1)
+ for (regnum = 0;
+ regnum < gdbarch_num_regs (regcache->arch ());
+ regnum++)
+ ia64_linux_fetch_register (regcache, regnum);
+ else
+ ia64_linux_fetch_register (regcache, regnum);
}
-LONGEST
-ia64_linux_xfer_unwind_table (struct target_ops *ops,
- enum target_object object,
- const char *annex,
- void *readbuf, const void *writebuf,
- ULONGEST offset, LONGEST len)
+/* Store register REGNUM into the inferior. */
+
+static void
+ia64_linux_store_register (const struct regcache *regcache, int regnum)
+{
+ struct gdbarch *gdbarch = regcache->arch ();
+ CORE_ADDR addr;
+ size_t size;
+ PTRACE_TYPE_RET *buf;
+ pid_t pid;
+ int i;
+
+ if (ia64_cannot_store_register (gdbarch, regnum))
+ return;
+
+ pid = get_ptrace_pid (regcache->ptid ());
+
+ /* This isn't really an address, but ptrace thinks of it as one. */
+ addr = ia64_register_addr (gdbarch, regnum);
+ size = register_size (gdbarch, regnum);
+
+ gdb_assert ((size % sizeof (PTRACE_TYPE_RET)) == 0);
+ buf = (PTRACE_TYPE_RET *) alloca (size);
+
+ /* Write the register contents into the inferior a chunk at a time. */
+ regcache->raw_collect (regnum, buf);
+ for (i = 0; i < size / sizeof (PTRACE_TYPE_RET); i++)
+ {
+ errno = 0;
+ ptrace (PT_WRITE_U, pid, (PTRACE_TYPE_ARG3)addr, buf[i]);
+ if (errno != 0)
+ error (_("Couldn't write register %s (#%d): %s."),
+ gdbarch_register_name (gdbarch, regnum),
+ regnum, safe_strerror (errno));
+
+ addr += sizeof (PTRACE_TYPE_RET);
+ }
+}
+
+/* Store register REGNUM back into the inferior. If REGNUM is -1, do
+ this for all registers. */
+
+void
+ia64_linux_nat_target::store_registers (struct regcache *regcache, int regnum)
+{
+ if (regnum == -1)
+ for (regnum = 0;
+ regnum < gdbarch_num_regs (regcache->arch ());
+ regnum++)
+ ia64_linux_store_register (regcache, regnum);
+ else
+ ia64_linux_store_register (regcache, regnum);
+}
+
+/* Implement the xfer_partial target_ops method. */
+
+enum target_xfer_status
+ia64_linux_nat_target::xfer_partial (enum target_object object,
+ const char *annex,
+ gdb_byte *readbuf, const gdb_byte *writebuf,
+ ULONGEST offset, ULONGEST len,
+ ULONGEST *xfered_len)
+{
+ if (object == TARGET_OBJECT_UNWIND_TABLE && readbuf != NULL)
+ {
+ static long gate_table_size;
+ gdb_byte *tmp_buf;
+ long res;
+
+ /* Probe for the table size once. */
+ if (gate_table_size == 0)
+ gate_table_size = syscall (__NR_getunwind, NULL, 0);
+ if (gate_table_size < 0)
+ return TARGET_XFER_E_IO;
+
+ if (offset >= gate_table_size)
+ return TARGET_XFER_EOF;
+
+ tmp_buf = (gdb_byte *) alloca (gate_table_size);
+ res = syscall (__NR_getunwind, tmp_buf, gate_table_size);
+ if (res < 0)
+ return TARGET_XFER_E_IO;
+ gdb_assert (res == gate_table_size);
+
+ if (offset + len > gate_table_size)
+ len = gate_table_size - offset;
+
+ memcpy (readbuf, tmp_buf + offset, len);
+ *xfered_len = len;
+ return TARGET_XFER_OK;
+ }
+
+ return linux_nat_target::xfer_partial (object, annex, readbuf, writebuf,
+ offset, len, xfered_len);
+}
+
+/* For break.b instruction ia64 CPU forgets the immediate value and generates
+ SIGILL with ILL_ILLOPC instead of more common SIGTRAP with TRAP_BRKPT.
+ ia64 does not use gdbarch_decr_pc_after_break so we do not have to make any
+ difference for the signals here. */
+
+bool
+ia64_linux_nat_target::low_status_is_event (int status)
+{
+ return WIFSTOPPED (status) && (WSTOPSIG (status) == SIGTRAP
+ || WSTOPSIG (status) == SIGILL);
+}
+
+void
+_initialize_ia64_linux_nat (void)
{
- return syscall (__NR_getunwind, readbuf, len);
+ /* Register the target. */
+ linux_target = &the_ia64_linux_nat_target;
+ add_inf_child_target (&the_ia64_linux_nat_target);
}