+ debug_registers[2 * idx] = 0;
+ debug_registers[2 * idx + 1] = 0;
+ dbr_addr = 0;
+ dbr_mask = 0;
+
+ ALL_LWPS (lp)
+ store_debug_register_pair (lp->ptid, idx, &dbr_addr, &dbr_mask);
+
+ return 0;
+ }
+ }
+ return -1;
+}
+
+static void
+ia64_linux_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;
+ siginfo_t siginfo;
+ struct regcache *regcache = get_current_regcache ();
+
+ if (!linux_nat_get_siginfo (inferior_ptid, &siginfo))
+ return false;
+
+ if (siginfo.si_signo != SIGTRAP
+ || (siginfo.si_code & 0xffff) != 0x0004 /* TRAP_HWBKPT */)
+ return false;
+
+ 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. */
+ 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);
+}
+
+static int
+ia64_linux_can_use_hw_breakpoint (struct target_ops *self,
+ 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;
+
+ /* 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);
+}
+
+/* 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);