--- gdb-7.8.2.orig/gdb/microblaze-linux-nat.c 1970-01-01 00:00:00.000000000 +0100
+++ gdb-7.8.2/gdb/microblaze-linux-nat.c 2016-09-21 10:34:30.029222319 +0200
@@ -0,0 +1,430 @@
+/* Microblaze GNU/Linux native support.
+
+ Copyright (C) 1988-1989, 1991-1992, 1994, 1996, 2000-2012 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 . */
+
+#include "defs.h"
+#include "arch-utils.h"
+#include "dis-asm.h"
+#include "frame.h"
+#include "trad-frame.h"
+#include "symtab.h"
+#include "value.h"
+#include "gdbcmd.h"
+#include "breakpoint.h"
+#include "inferior.h"
+#include "regcache.h"
+#include "target.h"
+#include "frame.h"
+#include "frame-base.h"
+#include "frame-unwind.h"
+#include "dwarf2-frame.h"
+#include "osabi.h"
+
+#include "gdb_assert.h"
+#include "target-descriptions.h"
+#include "opcodes/microblaze-opcm.h"
+#include "opcodes/microblaze-dis.h"
+
+#include "linux-nat.h"
+#include "target-descriptions.h"
+
+#include
+#include
+#include
+#include
+
+/* Prototypes for supply_gregset etc. */
+#include "gregset.h"
+
+#include "microblaze-tdep.h"
+
+#include
+#include "auxv.h"
+
+/* Defines ps_err_e, struct ps_prochandle. */
+#include "gdb_proc_service.h"
+
+/* On GNU/Linux, threads are implemented as pseudo-processes, in which
+ case we may be tracing more than one process at a time. In that
+ case, inferior_ptid will contain the main process ID and the
+ individual thread (process) ID. get_thread_id () is used to get
+ the thread id if it's available, and the process id otherwise. */
+
+int
+get_thread_id (ptid_t ptid)
+{
+ int tid = ptid_get_lwp (ptid);
+ if (0 == tid)
+ tid = ptid_get_pid (ptid);
+ return tid;
+}
+
+#define GET_THREAD_ID(PTID) get_thread_id (PTID)
+
+/* Non-zero if our kernel may support the PTRACE_GETREGS and
+ PTRACE_SETREGS requests, for reading and writing the
+ general-purpose registers. Zero if we've tried one of
+ them and gotten an error. */
+int have_ptrace_getsetregs = 1;
+
+static int
+microblaze_register_u_addr (struct gdbarch *gdbarch, int regno)
+{
+ int u_addr = -1;
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+ /* NOTE: cagney/2003-11-25: This is the word size used by the ptrace
+ interface, and not the wordsize of the program's ABI. */
+ int wordsize = sizeof (long);
+
+ /* General purpose registers occupy 1 slot each in the buffer. */
+ if (regno >= MICROBLAZE_R0_REGNUM
+ && regno <= MICROBLAZE_FSR_REGNUM)
+ u_addr = (regno * wordsize);
+
+ return u_addr;
+}
+
+
+static void
+fetch_register (struct regcache *regcache, int tid, int regno)
+{
+ struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+ /* This isn't really an address. But ptrace thinks of it as one. */
+ CORE_ADDR regaddr = microblaze_register_u_addr (gdbarch, regno);
+ int bytes_transferred;
+ unsigned int offset; /* Offset of registers within the u area. */
+ char buf[MAX_REGISTER_SIZE];
+
+ if (regaddr == -1)
+ {
+ memset (buf, '\0', register_size (gdbarch, regno)); /* Supply zeroes */
+ regcache_raw_supply (regcache, regno, buf);
+ return;
+ }
+
+ /* Read the raw register using sizeof(long) sized chunks. On a
+ 32-bit platform, 64-bit floating-point registers will require two
+ transfers. */
+ for (bytes_transferred = 0;
+ bytes_transferred < register_size (gdbarch, regno);
+ bytes_transferred += sizeof (long))
+ {
+ long l;
+
+ errno = 0;
+ l = ptrace (PTRACE_PEEKUSER, tid, (PTRACE_TYPE_ARG3) regaddr, 0);
+ regaddr += sizeof (long);
+ if (errno != 0)
+ {
+ char message[128];
+ sprintf (message, "reading register %s (#%d)",
+ gdbarch_register_name (gdbarch, regno), regno);
+ perror_with_name (message);
+ }
+ memcpy (&buf[bytes_transferred], &l, sizeof (l));
+ }
+
+ /* Now supply the register. Keep in mind that the regcache's idea
+ of the register's size may not be a multiple of sizeof
+ (long). */
+ if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_LITTLE)
+ {
+ /* Little-endian values are always found at the left end of the
+ bytes transferred. */
+ regcache_raw_supply (regcache, regno, buf);
+ }
+ else if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
+ {
+ /* Big-endian values are found at the right end of the bytes
+ transferred. */
+ size_t padding = (bytes_transferred - register_size (gdbarch, regno));
+ regcache_raw_supply (regcache, regno, buf + padding);
+ }
+ else
+ internal_error (__FILE__, __LINE__,
+ _("fetch_register: unexpected byte order: %d"),
+ gdbarch_byte_order (gdbarch));
+}
+
+/* This function actually issues the request to ptrace, telling
+ it to get all general-purpose registers and put them into the
+ specified regset.
+
+ If the ptrace request does not exist, this function returns 0
+ and properly sets the have_ptrace_* flag. If the request fails,
+ this function calls perror_with_name. Otherwise, if the request
+ succeeds, then the regcache gets filled and 1 is returned. */
+static int
+fetch_all_gp_regs (struct regcache *regcache, int tid)
+{
+ struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+ gdb_gregset_t gregset;
+
+ if (ptrace (PTRACE_GETREGS, tid, 0, (void *) &gregset) < 0)
+ {
+ if (errno == EIO)
+ {
+ have_ptrace_getsetregs = 0;
+ return 0;
+ }
+ perror_with_name (_("Couldn't get general-purpose registers."));
+ }
+
+ supply_gregset (regcache, (const gdb_gregset_t *) &gregset);
+
+ return 1;
+}
+
+
+/* This is a wrapper for the fetch_all_gp_regs function. It is
+ responsible for verifying if this target has the ptrace request
+ that can be used to fetch all general-purpose registers at one
+ shot. If it doesn't, then we should fetch them using the
+ old-fashioned way, which is to iterate over the registers and
+ request them one by one. */
+static void
+fetch_gp_regs (struct regcache *regcache, int tid)
+{
+ struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+ int i;
+
+ if (have_ptrace_getsetregs)
+ if (fetch_all_gp_regs (regcache, tid))
+ return;
+
+ /* If we've hit this point, it doesn't really matter which
+ architecture we are using. We just need to read the
+ registers in the "old-fashioned way". */
+ for (i = MICROBLAZE_R0_REGNUM; i <= MICROBLAZE_FSR_REGNUM; i++)
+ fetch_register (regcache, tid, i);
+}
+
+
+static void
+store_register (const struct regcache *regcache, int tid, int regno)
+{
+ struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+ /* This isn't really an address. But ptrace thinks of it as one. */
+ CORE_ADDR regaddr = microblaze_register_u_addr (gdbarch, regno);
+ int i;
+ size_t bytes_to_transfer;
+ char buf[MAX_REGISTER_SIZE];
+
+ if (regaddr == -1)
+ return;
+
+ /* First collect the register. Keep in mind that the regcache's
+ idea of the register's size may not be a multiple of sizeof
+ (long). */
+ memset (buf, 0, sizeof buf);
+ bytes_to_transfer = align_up (register_size (gdbarch, regno), sizeof (long));
+ if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_LITTLE)
+ {
+ /* Little-endian values always sit at the left end of the buffer. */
+ regcache_raw_collect (regcache, regno, buf);
+ }
+ else if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
+ {
+ /* Big-endian values sit at the right end of the buffer. */
+ size_t padding = (bytes_to_transfer - register_size (gdbarch, regno));
+ regcache_raw_collect (regcache, regno, buf + padding);
+ }
+
+ for (i = 0; i < bytes_to_transfer; i += sizeof (long))
+ {
+ long l;
+
+ memcpy (&l, &buf[i], sizeof (l));
+ errno = 0;
+ ptrace (PTRACE_POKEUSER, tid, (PTRACE_TYPE_ARG3) regaddr, l);
+ regaddr += sizeof (long);
+
+ if (errno != 0)
+ {
+ char message[128];
+ sprintf (message, "writing register %s (#%d)",
+ gdbarch_register_name (gdbarch, regno), regno);
+ perror_with_name (message);
+ }
+ }
+}
+
+/* This function actually issues the request to ptrace, telling
+ it to store all general-purpose registers present in the specified
+ regset.
+
+ If the ptrace request does not exist, this function returns 0
+ and properly sets the have_ptrace_* flag. If the request fails,
+ this function calls perror_with_name. Otherwise, if the request
+ succeeds, then the regcache is stored and 1 is returned. */
+static int
+store_all_gp_regs (const struct regcache *regcache, int tid, int regno)
+{
+ struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+ gdb_gregset_t gregset;
+
+ if (ptrace (PTRACE_GETREGS, tid, 0, (void *) &gregset) < 0)
+ {
+ if (errno == EIO)
+ {
+ have_ptrace_getsetregs = 0;
+ return 0;
+ }
+ perror_with_name (_("Couldn't get general-purpose registers."));
+ }
+
+ fill_gregset (regcache, &gregset, regno);
+
+ if (ptrace (PTRACE_SETREGS, tid, 0, (void *) &gregset) < 0)
+ {
+ if (errno == EIO)
+ {
+ have_ptrace_getsetregs = 0;
+ return 0;
+ }
+ perror_with_name (_("Couldn't set general-purpose registers."));
+ }
+
+ return 1;
+}
+
+/* This is a wrapper for the store_all_gp_regs function. It is
+ responsible for verifying if this target has the ptrace request
+ that can be used to store all general-purpose registers at one
+ shot. If it doesn't, then we should store them using the
+ old-fashioned way, which is to iterate over the registers and
+ store them one by one. */
+static void
+store_gp_regs (const struct regcache *regcache, int tid, int regno)
+{
+ struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+ int i;
+
+ if (have_ptrace_getsetregs)
+ if (store_all_gp_regs (regcache, tid, regno))
+ return;
+
+ /* If we hit this point, it doesn't really matter which
+ architecture we are using. We just need to store the
+ registers in the "old-fashioned way". */
+ for (i = MICROBLAZE_R0_REGNUM; i <= MICROBLAZE_FSR_REGNUM; i++)
+ store_register (regcache, tid, i);
+}
+
+
+/* Fetch registers from the child process. Fetch all registers if
+ regno == -1, otherwise fetch all general registers or all floating
+ point registers depending upon the value of regno. */
+
+static void
+microblaze_linux_fetch_inferior_registers (struct target_ops *ops,
+ struct regcache *regcache, int regno)
+{
+ /* Get the thread id for the ptrace call. */
+ int tid = GET_THREAD_ID (inferior_ptid);
+
+ if (regno == -1)
+ fetch_gp_regs (regcache, tid);
+ else
+ fetch_register (regcache, tid, regno);
+}
+
+/* Store registers back into the inferior. Store all registers if
+ regno == -1, otherwise store all general registers or all floating
+ point registers depending upon the value of regno. */
+
+static void
+microblaze_linux_store_inferior_registers (struct target_ops *ops,
+ struct regcache *regcache, int regno)
+{
+ /* Get the thread id for the ptrace call. */
+ int tid = GET_THREAD_ID (inferior_ptid);
+
+ if (regno >= 0)
+ store_register (regcache, tid, regno);
+ else
+ store_gp_regs (regcache, tid, -1);
+}
+
+/* Wrapper functions for the standard regset handling, used by
+ thread debugging. */
+
+void
+fill_gregset (const struct regcache *regcache,
+ gdb_gregset_t *gregsetp, int regno)
+{
+ microblaze_collect_gregset (NULL, regcache, regno, gregsetp);
+}
+
+void
+supply_gregset (struct regcache *regcache, const gdb_gregset_t *gregsetp)
+{
+ microblaze_supply_gregset (NULL, regcache, -1, gregsetp);
+}
+
+void
+fill_fpregset (const struct regcache *regcache,
+ gdb_fpregset_t *fpregsetp, int regno)
+{
+ /* FIXME. */
+}
+
+void
+supply_fpregset (struct regcache *regcache, const gdb_fpregset_t *fpregsetp)
+{
+ /* FIXME. */
+}
+
+static const struct target_desc *
+microblaze_linux_read_description (struct target_ops *ops)
+{
+ CORE_ADDR microblaze_hwcap = 0;
+
+ if (target_auxv_search (ops, AT_HWCAP, µblaze_hwcap) != 1)
+ return NULL;
+
+ return NULL;
+}
+
+
+void _initialize_microblaze_linux_nat (void);
+
+void
+_initialize_microblaze_linux_nat (void)
+{
+ struct target_ops *t;
+
+ /* Fill in the generic GNU/Linux methods. */
+ t = linux_target ();
+
+ /* Add our register access methods. */
+ t->to_fetch_registers = microblaze_linux_fetch_inferior_registers;
+ t->to_store_registers = microblaze_linux_store_inferior_registers;
+
+ t->to_read_description = microblaze_linux_read_description;
+
+ /* Register the target. */
+ linux_nat_add_target (t);
+}