X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gdb%2Fsparc64-tdep.c;h=030850955ace9fff37a5a26ef673249cc5f85e81;hb=be6d4f74c77c6f521afc873d226480e001cb99c2;hp=437650876b8430d7b543575ec64d0412baab8399;hpb=b31bc72481caa94afd56f9fbbf7cdb064842b479;p=deliverable%2Fbinutils-gdb.git
diff --git a/gdb/sparc64-tdep.c b/gdb/sparc64-tdep.c
index 437650876b..030850955a 100644
--- a/gdb/sparc64-tdep.c
+++ b/gdb/sparc64-tdep.c
@@ -1,12 +1,12 @@
/* Target-dependent code for UltraSPARC.
- Copyright 2003, 2004 Free Software Foundation, Inc.
+ Copyright (C) 2003-2019 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,
@@ -15,13 +15,11 @@
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 "arch-utils.h"
-#include "floatformat.h"
+#include "dwarf2-frame.h"
#include "frame.h"
#include "frame-base.h"
#include "frame-unwind.h"
@@ -32,15 +30,13 @@
#include "objfiles.h"
#include "osabi.h"
#include "regcache.h"
+#include "target-descriptions.h"
#include "target.h"
#include "value.h"
-#include "gdb_assert.h"
-#include "gdb_string.h"
-
#include "sparc64-tdep.h"
-/* This file implements the The SPARC 64-bit ABI as defined by the
+/* This file implements the SPARC 64-bit ABI as defined by the
section "Low-Level System Information" of the SPARC Compliance
Definition (SCD) 2.4.1, which is the 64-bit System V psABI for
SPARC. */
@@ -49,6 +45,510 @@
sparc64_-prefix for 64-bit specific code and the sparc_-prefix for
code can handle both. */
+/* The M7 processor supports an Application Data Integrity (ADI) feature
+ that detects invalid data accesses. When software allocates memory and
+ enables ADI on the allocated memory, it chooses a 4-bit version number,
+ sets the version in the upper 4 bits of the 64-bit pointer to that data,
+ and stores the 4-bit version in every cacheline of the object. Hardware
+ saves the latter in spare bits in the cache and memory hierarchy. On each
+ load and store, the processor compares the upper 4 VA (virtual address) bits
+ to the cacheline's version. If there is a mismatch, the processor generates
+ a version mismatch trap which can be either precise or disrupting.
+ The trap is an error condition which the kernel delivers to the process
+ as a SIGSEGV signal.
+
+ The upper 4 bits of the VA represent a version and are not part of the
+ true address. The processor clears these bits and sign extends bit 59
+ to generate the true address.
+
+ Note that 32-bit applications cannot use ADI. */
+
+
+#include
+#include "cli/cli-utils.h"
+#include "gdbcmd.h"
+#include "auxv.h"
+
+#define MAX_PROC_NAME_SIZE sizeof("/proc/99999/lwp/9999/adi/lstatus")
+
+/* ELF Auxiliary vectors */
+#ifndef AT_ADI_BLKSZ
+#define AT_ADI_BLKSZ 34
+#endif
+#ifndef AT_ADI_NBITS
+#define AT_ADI_NBITS 35
+#endif
+#ifndef AT_ADI_UEONADI
+#define AT_ADI_UEONADI 36
+#endif
+
+/* ADI command list. */
+static struct cmd_list_element *sparc64adilist = NULL;
+
+/* ADI stat settings. */
+typedef struct
+{
+ /* The ADI block size. */
+ unsigned long blksize;
+
+ /* Number of bits used for an ADI version tag which can be
+ used together with the shift value for an ADI version tag
+ to encode or extract the ADI version value in a pointer. */
+ unsigned long nbits;
+
+ /* The maximum ADI version tag value supported. */
+ int max_version;
+
+ /* ADI version tag file. */
+ int tag_fd = 0;
+
+ /* ADI availability check has been done. */
+ bool checked_avail = false;
+
+ /* ADI is available. */
+ bool is_avail = false;
+
+} adi_stat_t;
+
+/* Per-process ADI stat info. */
+
+typedef struct sparc64_adi_info
+{
+ sparc64_adi_info (pid_t pid_)
+ : pid (pid_)
+ {}
+
+ /* The process identifier. */
+ pid_t pid;
+
+ /* The ADI stat. */
+ adi_stat_t stat = {};
+
+} sparc64_adi_info;
+
+static std::forward_list adi_proc_list;
+
+
+/* Get ADI info for process PID, creating one if it doesn't exist. */
+
+static sparc64_adi_info *
+get_adi_info_proc (pid_t pid)
+{
+ auto found = std::find_if (adi_proc_list.begin (), adi_proc_list.end (),
+ [&pid] (const sparc64_adi_info &info)
+ {
+ return info.pid == pid;
+ });
+
+ if (found == adi_proc_list.end ())
+ {
+ adi_proc_list.emplace_front (pid);
+ return &adi_proc_list.front ();
+ }
+ else
+ {
+ return &(*found);
+ }
+}
+
+static adi_stat_t
+get_adi_info (pid_t pid)
+{
+ sparc64_adi_info *proc;
+
+ proc = get_adi_info_proc (pid);
+ return proc->stat;
+}
+
+/* Is called when GDB is no longer debugging process PID. It
+ deletes data structure that keeps track of the ADI stat. */
+
+void
+sparc64_forget_process (pid_t pid)
+{
+ int target_errno;
+
+ for (auto pit = adi_proc_list.before_begin (),
+ it = std::next (pit);
+ it != adi_proc_list.end ();
+ )
+ {
+ if ((*it).pid == pid)
+ {
+ if ((*it).stat.tag_fd > 0)
+ target_fileio_close ((*it).stat.tag_fd, &target_errno);
+ adi_proc_list.erase_after (pit);
+ break;
+ }
+ else
+ pit = it++;
+ }
+
+}
+
+static void
+info_adi_command (const char *args, int from_tty)
+{
+ printf_unfiltered ("\"adi\" must be followed by \"examine\" "
+ "or \"assign\".\n");
+ help_list (sparc64adilist, "adi ", all_commands, gdb_stdout);
+}
+
+/* Read attributes of a maps entry in /proc/[pid]/adi/maps. */
+
+static void
+read_maps_entry (const char *line,
+ ULONGEST *addr, ULONGEST *endaddr)
+{
+ const char *p = line;
+
+ *addr = strtoulst (p, &p, 16);
+ if (*p == '-')
+ p++;
+
+ *endaddr = strtoulst (p, &p, 16);
+}
+
+/* Check if ADI is available. */
+
+static bool
+adi_available (void)
+{
+ pid_t pid = inferior_ptid.pid ();
+ sparc64_adi_info *proc = get_adi_info_proc (pid);
+ CORE_ADDR value;
+
+ if (proc->stat.checked_avail)
+ return proc->stat.is_avail;
+
+ proc->stat.checked_avail = true;
+ if (target_auxv_search (current_top_target (), AT_ADI_BLKSZ, &value) <= 0)
+ return false;
+ proc->stat.blksize = value;
+ target_auxv_search (current_top_target (), AT_ADI_NBITS, &value);
+ proc->stat.nbits = value;
+ proc->stat.max_version = (1 << proc->stat.nbits) - 2;
+ proc->stat.is_avail = true;
+
+ return proc->stat.is_avail;
+}
+
+/* Normalize a versioned address - a VA with ADI bits (63-60) set. */
+
+static CORE_ADDR
+adi_normalize_address (CORE_ADDR addr)
+{
+ adi_stat_t ast = get_adi_info (inferior_ptid.pid ());
+
+ if (ast.nbits)
+ {
+ /* Clear upper bits. */
+ addr &= ((uint64_t) -1) >> ast.nbits;
+
+ /* Sign extend. */
+ CORE_ADDR signbit = (uint64_t) 1 << (64 - ast.nbits - 1);
+ return (addr ^ signbit) - signbit;
+ }
+ return addr;
+}
+
+/* Align a normalized address - a VA with bit 59 sign extended into
+ ADI bits. */
+
+static CORE_ADDR
+adi_align_address (CORE_ADDR naddr)
+{
+ adi_stat_t ast = get_adi_info (inferior_ptid.pid ());
+
+ return (naddr - (naddr % ast.blksize)) / ast.blksize;
+}
+
+/* Convert a byte count to count at a ratio of 1:adi_blksz. */
+
+static int
+adi_convert_byte_count (CORE_ADDR naddr, int nbytes, CORE_ADDR locl)
+{
+ adi_stat_t ast = get_adi_info (inferior_ptid.pid ());
+
+ return ((naddr + nbytes + ast.blksize - 1) / ast.blksize) - locl;
+}
+
+/* The /proc/[pid]/adi/tags file, which allows gdb to get/set ADI
+ version in a target process, maps linearly to the address space
+ of the target process at a ratio of 1:adi_blksz.
+
+ A read (or write) at offset K in the file returns (or modifies)
+ the ADI version tag stored in the cacheline containing address
+ K * adi_blksz, encoded as 1 version tag per byte. The allowed
+ version tag values are between 0 and adi_stat.max_version. */
+
+static int
+adi_tag_fd (void)
+{
+ pid_t pid = inferior_ptid.pid ();
+ sparc64_adi_info *proc = get_adi_info_proc (pid);
+
+ if (proc->stat.tag_fd != 0)
+ return proc->stat.tag_fd;
+
+ char cl_name[MAX_PROC_NAME_SIZE];
+ snprintf (cl_name, sizeof(cl_name), "/proc/%ld/adi/tags", (long) pid);
+ int target_errno;
+ proc->stat.tag_fd = target_fileio_open (NULL, cl_name, O_RDWR|O_EXCL,
+ 0, &target_errno);
+ return proc->stat.tag_fd;
+}
+
+/* Check if an address set is ADI enabled, using /proc/[pid]/adi/maps
+ which was exported by the kernel and contains the currently ADI
+ mapped memory regions and their access permissions. */
+
+static bool
+adi_is_addr_mapped (CORE_ADDR vaddr, size_t cnt)
+{
+ char filename[MAX_PROC_NAME_SIZE];
+ size_t i = 0;
+
+ pid_t pid = inferior_ptid.pid ();
+ snprintf (filename, sizeof filename, "/proc/%ld/adi/maps", (long) pid);
+ gdb::unique_xmalloc_ptr data
+ = target_fileio_read_stralloc (NULL, filename);
+ if (data)
+ {
+ adi_stat_t adi_stat = get_adi_info (pid);
+ char *line;
+ for (line = strtok (data.get (), "\n"); line; line = strtok (NULL, "\n"))
+ {
+ ULONGEST addr, endaddr;
+
+ read_maps_entry (line, &addr, &endaddr);
+
+ while (((vaddr + i) * adi_stat.blksize) >= addr
+ && ((vaddr + i) * adi_stat.blksize) < endaddr)
+ {
+ if (++i == cnt)
+ return true;
+ }
+ }
+ }
+ else
+ warning (_("unable to open /proc file '%s'"), filename);
+
+ return false;
+}
+
+/* Read ADI version tag value for memory locations starting at "VADDR"
+ for "SIZE" number of bytes. */
+
+static int
+adi_read_versions (CORE_ADDR vaddr, size_t size, gdb_byte *tags)
+{
+ int fd = adi_tag_fd ();
+ if (fd == -1)
+ return -1;
+
+ if (!adi_is_addr_mapped (vaddr, size))
+ {
+ adi_stat_t ast = get_adi_info (inferior_ptid.pid ());
+ error(_("Address at %s is not in ADI maps"),
+ paddress (target_gdbarch (), vaddr * ast.blksize));
+ }
+
+ int target_errno;
+ return target_fileio_pread (fd, tags, size, vaddr, &target_errno);
+}
+
+/* Write ADI version tag for memory locations starting at "VADDR" for
+ "SIZE" number of bytes to "TAGS". */
+
+static int
+adi_write_versions (CORE_ADDR vaddr, size_t size, unsigned char *tags)
+{
+ int fd = adi_tag_fd ();
+ if (fd == -1)
+ return -1;
+
+ if (!adi_is_addr_mapped (vaddr, size))
+ {
+ adi_stat_t ast = get_adi_info (inferior_ptid.pid ());
+ error(_("Address at %s is not in ADI maps"),
+ paddress (target_gdbarch (), vaddr * ast.blksize));
+ }
+
+ int target_errno;
+ return target_fileio_pwrite (fd, tags, size, vaddr, &target_errno);
+}
+
+/* Print ADI version tag value in "TAGS" for memory locations starting
+ at "VADDR" with number of "CNT". */
+
+static void
+adi_print_versions (CORE_ADDR vaddr, size_t cnt, gdb_byte *tags)
+{
+ int v_idx = 0;
+ const int maxelts = 8; /* # of elements per line */
+
+ adi_stat_t adi_stat = get_adi_info (inferior_ptid.pid ());
+
+ while (cnt > 0)
+ {
+ QUIT;
+ printf_filtered ("%s:\t",
+ paddress (target_gdbarch (), vaddr * adi_stat.blksize));
+ for (int i = maxelts; i > 0 && cnt > 0; i--, cnt--)
+ {
+ if (tags[v_idx] == 0xff) /* no version tag */
+ printf_filtered ("-");
+ else
+ printf_filtered ("%1X", tags[v_idx]);
+ if (cnt > 1)
+ printf_filtered (" ");
+ ++v_idx;
+ }
+ printf_filtered ("\n");
+ gdb_flush (gdb_stdout);
+ vaddr += maxelts;
+ }
+}
+
+static void
+do_examine (CORE_ADDR start, int bcnt)
+{
+ CORE_ADDR vaddr = adi_normalize_address (start);
+
+ CORE_ADDR vstart = adi_align_address (vaddr);
+ int cnt = adi_convert_byte_count (vaddr, bcnt, vstart);
+ gdb::def_vector buf (cnt);
+ int read_cnt = adi_read_versions (vstart, cnt, buf.data ());
+ if (read_cnt == -1)
+ error (_("No ADI information"));
+ else if (read_cnt < cnt)
+ error(_("No ADI information at %s"), paddress (target_gdbarch (), vaddr));
+
+ adi_print_versions (vstart, cnt, buf.data ());
+}
+
+static void
+do_assign (CORE_ADDR start, size_t bcnt, int version)
+{
+ CORE_ADDR vaddr = adi_normalize_address (start);
+
+ CORE_ADDR vstart = adi_align_address (vaddr);
+ int cnt = adi_convert_byte_count (vaddr, bcnt, vstart);
+ std::vector buf (cnt, version);
+ int set_cnt = adi_write_versions (vstart, cnt, buf.data ());
+
+ if (set_cnt == -1)
+ error (_("No ADI information"));
+ else if (set_cnt < cnt)
+ error(_("No ADI information at %s"), paddress (target_gdbarch (), vaddr));
+
+}
+
+/* ADI examine version tag command.
+
+ Command syntax:
+
+ adi (examine|x)[/COUNT] [ADDR] */
+
+static void
+adi_examine_command (const char *args, int from_tty)
+{
+ /* make sure program is active and adi is available */
+ if (!target_has_execution)
+ error (_("ADI command requires a live process/thread"));
+
+ if (!adi_available ())
+ error (_("No ADI information"));
+
+ int cnt = 1;
+ const char *p = args;
+ if (p && *p == '/')
+ {
+ p++;
+ cnt = get_number (&p);
+ }
+
+ CORE_ADDR next_address = 0;
+ if (p != 0 && *p != 0)
+ next_address = parse_and_eval_address (p);
+ if (!cnt || !next_address)
+ error (_("Usage: adi examine|x[/COUNT] [ADDR]"));
+
+ do_examine (next_address, cnt);
+}
+
+/* ADI assign version tag command.
+
+ Command syntax:
+
+ adi (assign|a)[/COUNT] ADDR = VERSION */
+
+static void
+adi_assign_command (const char *args, int from_tty)
+{
+ static const char *adi_usage
+ = N_("Usage: adi assign|a[/COUNT] ADDR = VERSION");
+
+ /* make sure program is active and adi is available */
+ if (!target_has_execution)
+ error (_("ADI command requires a live process/thread"));
+
+ if (!adi_available ())
+ error (_("No ADI information"));
+
+ const char *exp = args;
+ if (exp == 0)
+ error_no_arg (_(adi_usage));
+
+ char *q = (char *) strchr (exp, '=');
+ if (q)
+ *q++ = 0;
+ else
+ error ("%s", _(adi_usage));
+
+ size_t cnt = 1;
+ const char *p = args;
+ if (exp && *exp == '/')
+ {
+ p = exp + 1;
+ cnt = get_number (&p);
+ }
+
+ CORE_ADDR next_address = 0;
+ if (p != 0 && *p != 0)
+ next_address = parse_and_eval_address (p);
+ else
+ error ("%s", _(adi_usage));
+
+ int version = 0;
+ if (q != NULL) /* parse version tag */
+ {
+ adi_stat_t ast = get_adi_info (inferior_ptid.pid ());
+ version = parse_and_eval_long (q);
+ if (version < 0 || version > ast.max_version)
+ error (_("Invalid ADI version tag %d"), version);
+ }
+
+ do_assign (next_address, cnt, version);
+}
+
+void
+_initialize_sparc64_adi_tdep (void)
+{
+
+ add_prefix_cmd ("adi", class_support, info_adi_command,
+ _("ADI version related commands."),
+ &sparc64adilist, "adi ", 0, &cmdlist);
+ add_cmd ("examine", class_support, adi_examine_command,
+ _("Examine ADI versions."), &sparc64adilist);
+ add_alias_cmd ("x", "examine", no_class, 1, &sparc64adilist);
+ add_cmd ("assign", class_support, adi_assign_command,
+ _("Assign ADI versions."), &sparc64adilist);
+
+}
+
+
/* The functions on this page are intended to be used to classify
function arguments. */
@@ -71,6 +571,7 @@ sparc64_integral_or_pointer_p (const struct type *type)
return 1;
case TYPE_CODE_PTR:
case TYPE_CODE_REF:
+ case TYPE_CODE_RVALUE_REF:
{
int len = TYPE_LENGTH (type);
gdb_assert (len == 8);
@@ -103,7 +604,31 @@ sparc64_floating_p (const struct type *type)
return 0;
}
-/* Check whether TYPE is "Structure or Union". */
+/* Check whether TYPE is "Complex Floating". */
+
+static int
+sparc64_complex_floating_p (const struct type *type)
+{
+ switch (TYPE_CODE (type))
+ {
+ case TYPE_CODE_COMPLEX:
+ {
+ int len = TYPE_LENGTH (type);
+ gdb_assert (len == 8 || len == 16 || len == 32);
+ }
+ return 1;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+/* Check whether TYPE is "Structure or Union".
+
+ In terms of Ada subprogram calls, arrays are treated the same as
+ struct and union types. So this function also returns non-zero
+ for array types. */
static int
sparc64_structure_or_union_p (const struct type *type)
@@ -112,6 +637,7 @@ sparc64_structure_or_union_p (const struct type *type)
{
case TYPE_CODE_STRUCT:
case TYPE_CODE_UNION:
+ case TYPE_CODE_ARRAY:
return 1;
default:
break;
@@ -119,245 +645,305 @@ sparc64_structure_or_union_p (const struct type *type)
return 0;
}
+
-/* Register information. */
+/* Construct types for ISA-specific registers. */
-struct sparc64_register_info
+static struct type *
+sparc64_pstate_type (struct gdbarch *gdbarch)
{
- char *name;
- struct type **type;
-};
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ if (!tdep->sparc64_pstate_type)
+ {
+ struct type *type;
+
+ type = arch_flags_type (gdbarch, "builtin_type_sparc64_pstate", 64);
+ append_flags_type_flag (type, 0, "AG");
+ append_flags_type_flag (type, 1, "IE");
+ append_flags_type_flag (type, 2, "PRIV");
+ append_flags_type_flag (type, 3, "AM");
+ append_flags_type_flag (type, 4, "PEF");
+ append_flags_type_flag (type, 5, "RED");
+ append_flags_type_flag (type, 8, "TLE");
+ append_flags_type_flag (type, 9, "CLE");
+ append_flags_type_flag (type, 10, "PID0");
+ append_flags_type_flag (type, 11, "PID1");
+
+ tdep->sparc64_pstate_type = type;
+ }
+
+ return tdep->sparc64_pstate_type;
+}
-static struct sparc64_register_info sparc64_register_info[] =
+static struct type *
+sparc64_ccr_type (struct gdbarch *gdbarch)
{
- { "g0", &builtin_type_int64 },
- { "g1", &builtin_type_int64 },
- { "g2", &builtin_type_int64 },
- { "g3", &builtin_type_int64 },
- { "g4", &builtin_type_int64 },
- { "g5", &builtin_type_int64 },
- { "g6", &builtin_type_int64 },
- { "g7", &builtin_type_int64 },
-
- { "o0", &builtin_type_int64 },
- { "o1", &builtin_type_int64 },
- { "o2", &builtin_type_int64 },
- { "o3", &builtin_type_int64 },
- { "o4", &builtin_type_int64 },
- { "o5", &builtin_type_int64 },
- { "sp", &builtin_type_void_data_ptr },
- { "o7", &builtin_type_int64 },
-
- { "l0", &builtin_type_int64 },
- { "l1", &builtin_type_int64 },
- { "l2", &builtin_type_int64 },
- { "l3", &builtin_type_int64 },
- { "l4", &builtin_type_int64 },
- { "l5", &builtin_type_int64 },
- { "l6", &builtin_type_int64 },
- { "l7", &builtin_type_int64 },
-
- { "i0", &builtin_type_int64 },
- { "i1", &builtin_type_int64 },
- { "i2", &builtin_type_int64 },
- { "i3", &builtin_type_int64 },
- { "i4", &builtin_type_int64 },
- { "i5", &builtin_type_int64 },
- { "fp", &builtin_type_void_data_ptr },
- { "i7", &builtin_type_int64 },
-
- { "f0", &builtin_type_float },
- { "f1", &builtin_type_float },
- { "f2", &builtin_type_float },
- { "f3", &builtin_type_float },
- { "f4", &builtin_type_float },
- { "f5", &builtin_type_float },
- { "f6", &builtin_type_float },
- { "f7", &builtin_type_float },
- { "f8", &builtin_type_float },
- { "f9", &builtin_type_float },
- { "f10", &builtin_type_float },
- { "f11", &builtin_type_float },
- { "f12", &builtin_type_float },
- { "f13", &builtin_type_float },
- { "f14", &builtin_type_float },
- { "f15", &builtin_type_float },
- { "f16", &builtin_type_float },
- { "f17", &builtin_type_float },
- { "f18", &builtin_type_float },
- { "f19", &builtin_type_float },
- { "f20", &builtin_type_float },
- { "f21", &builtin_type_float },
- { "f22", &builtin_type_float },
- { "f23", &builtin_type_float },
- { "f24", &builtin_type_float },
- { "f25", &builtin_type_float },
- { "f26", &builtin_type_float },
- { "f27", &builtin_type_float },
- { "f28", &builtin_type_float },
- { "f29", &builtin_type_float },
- { "f30", &builtin_type_float },
- { "f31", &builtin_type_float },
- { "f32", &builtin_type_double },
- { "f34", &builtin_type_double },
- { "f36", &builtin_type_double },
- { "f38", &builtin_type_double },
- { "f40", &builtin_type_double },
- { "f42", &builtin_type_double },
- { "f44", &builtin_type_double },
- { "f46", &builtin_type_double },
- { "f48", &builtin_type_double },
- { "f50", &builtin_type_double },
- { "f52", &builtin_type_double },
- { "f54", &builtin_type_double },
- { "f56", &builtin_type_double },
- { "f58", &builtin_type_double },
- { "f60", &builtin_type_double },
- { "f62", &builtin_type_double },
-
- { "pc", &builtin_type_void_func_ptr },
- { "npc", &builtin_type_void_func_ptr },
-
- /* This raw register contains the contents of %cwp, %pstate, %asi
- and %ccr as laid out in a %tstate register. */
- /* FIXME: Give it a name until we start using register groups. */
- { "state", &builtin_type_int64 },
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
- { "fsr", &builtin_type_int64 },
- { "fprs", &builtin_type_int64 },
+ if (tdep->sparc64_ccr_type == NULL)
+ {
+ struct type *type;
+
+ type = arch_flags_type (gdbarch, "builtin_type_sparc64_ccr", 64);
+ append_flags_type_flag (type, 0, "icc.c");
+ append_flags_type_flag (type, 1, "icc.v");
+ append_flags_type_flag (type, 2, "icc.z");
+ append_flags_type_flag (type, 3, "icc.n");
+ append_flags_type_flag (type, 4, "xcc.c");
+ append_flags_type_flag (type, 5, "xcc.v");
+ append_flags_type_flag (type, 6, "xcc.z");
+ append_flags_type_flag (type, 7, "xcc.n");
+
+ tdep->sparc64_ccr_type = type;
+ }
- /* "Although Y is a 64-bit register, its high-order 32 bits are
- reserved and always read as 0." */
- { "y", &builtin_type_int64 }
+ return tdep->sparc64_ccr_type;
+}
+
+static struct type *
+sparc64_fsr_type (struct gdbarch *gdbarch)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ if (!tdep->sparc64_fsr_type)
+ {
+ struct type *type;
+
+ type = arch_flags_type (gdbarch, "builtin_type_sparc64_fsr", 64);
+ append_flags_type_flag (type, 0, "NXC");
+ append_flags_type_flag (type, 1, "DZC");
+ append_flags_type_flag (type, 2, "UFC");
+ append_flags_type_flag (type, 3, "OFC");
+ append_flags_type_flag (type, 4, "NVC");
+ append_flags_type_flag (type, 5, "NXA");
+ append_flags_type_flag (type, 6, "DZA");
+ append_flags_type_flag (type, 7, "UFA");
+ append_flags_type_flag (type, 8, "OFA");
+ append_flags_type_flag (type, 9, "NVA");
+ append_flags_type_flag (type, 22, "NS");
+ append_flags_type_flag (type, 23, "NXM");
+ append_flags_type_flag (type, 24, "DZM");
+ append_flags_type_flag (type, 25, "UFM");
+ append_flags_type_flag (type, 26, "OFM");
+ append_flags_type_flag (type, 27, "NVM");
+
+ tdep->sparc64_fsr_type = type;
+ }
+
+ return tdep->sparc64_fsr_type;
+}
+
+static struct type *
+sparc64_fprs_type (struct gdbarch *gdbarch)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ if (!tdep->sparc64_fprs_type)
+ {
+ struct type *type;
+
+ type = arch_flags_type (gdbarch, "builtin_type_sparc64_fprs", 64);
+ append_flags_type_flag (type, 0, "DL");
+ append_flags_type_flag (type, 1, "DU");
+ append_flags_type_flag (type, 2, "FEF");
+
+ tdep->sparc64_fprs_type = type;
+ }
+
+ return tdep->sparc64_fprs_type;
+}
+
+
+/* Register information. */
+#define SPARC64_FPU_REGISTERS \
+ "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", \
+ "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", \
+ "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", \
+ "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31", \
+ "f32", "f34", "f36", "f38", "f40", "f42", "f44", "f46", \
+ "f48", "f50", "f52", "f54", "f56", "f58", "f60", "f62"
+#define SPARC64_CP0_REGISTERS \
+ "pc", "npc", \
+ /* FIXME: Give "state" a name until we start using register groups. */ \
+ "state", \
+ "fsr", \
+ "fprs", \
+ "y"
+
+static const char *sparc64_fpu_register_names[] = { SPARC64_FPU_REGISTERS };
+static const char *sparc64_cp0_register_names[] = { SPARC64_CP0_REGISTERS };
+
+static const char *sparc64_register_names[] =
+{
+ SPARC_CORE_REGISTERS,
+ SPARC64_FPU_REGISTERS,
+ SPARC64_CP0_REGISTERS
};
/* Total number of registers. */
-#define SPARC64_NUM_REGS ARRAY_SIZE (sparc64_register_info)
+#define SPARC64_NUM_REGS ARRAY_SIZE (sparc64_register_names)
/* We provide the aliases %d0..%d62 and %q0..%q60 for the floating
registers as "psuedo" registers. */
-static struct sparc64_register_info sparc64_pseudo_register_info[] =
+static const char *sparc64_pseudo_register_names[] =
{
- { "cwp", &builtin_type_int64 },
- { "pstate", &builtin_type_int64 },
- { "asi", &builtin_type_int64 },
- { "ccr", &builtin_type_int64 },
-
- { "d0", &builtin_type_double },
- { "d2", &builtin_type_double },
- { "d4", &builtin_type_double },
- { "d6", &builtin_type_double },
- { "d8", &builtin_type_double },
- { "d10", &builtin_type_double },
- { "d12", &builtin_type_double },
- { "d14", &builtin_type_double },
- { "d16", &builtin_type_double },
- { "d18", &builtin_type_double },
- { "d20", &builtin_type_double },
- { "d22", &builtin_type_double },
- { "d24", &builtin_type_double },
- { "d26", &builtin_type_double },
- { "d28", &builtin_type_double },
- { "d30", &builtin_type_double },
- { "d32", &builtin_type_double },
- { "d34", &builtin_type_double },
- { "d36", &builtin_type_double },
- { "d38", &builtin_type_double },
- { "d40", &builtin_type_double },
- { "d42", &builtin_type_double },
- { "d44", &builtin_type_double },
- { "d46", &builtin_type_double },
- { "d48", &builtin_type_double },
- { "d50", &builtin_type_double },
- { "d52", &builtin_type_double },
- { "d54", &builtin_type_double },
- { "d56", &builtin_type_double },
- { "d58", &builtin_type_double },
- { "d60", &builtin_type_double },
- { "d62", &builtin_type_double },
-
- { "q0", &builtin_type_long_double },
- { "q4", &builtin_type_long_double },
- { "q8", &builtin_type_long_double },
- { "q12", &builtin_type_long_double },
- { "q16", &builtin_type_long_double },
- { "q20", &builtin_type_long_double },
- { "q24", &builtin_type_long_double },
- { "q28", &builtin_type_long_double },
- { "q32", &builtin_type_long_double },
- { "q36", &builtin_type_long_double },
- { "q40", &builtin_type_long_double },
- { "q44", &builtin_type_long_double },
- { "q48", &builtin_type_long_double },
- { "q52", &builtin_type_long_double },
- { "q56", &builtin_type_long_double },
- { "q60", &builtin_type_long_double }
+ "cwp", "pstate", "asi", "ccr",
+
+ "d0", "d2", "d4", "d6", "d8", "d10", "d12", "d14",
+ "d16", "d18", "d20", "d22", "d24", "d26", "d28", "d30",
+ "d32", "d34", "d36", "d38", "d40", "d42", "d44", "d46",
+ "d48", "d50", "d52", "d54", "d56", "d58", "d60", "d62",
+
+ "q0", "q4", "q8", "q12", "q16", "q20", "q24", "q28",
+ "q32", "q36", "q40", "q44", "q48", "q52", "q56", "q60",
};
/* Total number of pseudo registers. */
-#define SPARC64_NUM_PSEUDO_REGS ARRAY_SIZE (sparc64_pseudo_register_info)
+#define SPARC64_NUM_PSEUDO_REGS ARRAY_SIZE (sparc64_pseudo_register_names)
+
+/* Return the name of pseudo register REGNUM. */
+
+static const char *
+sparc64_pseudo_register_name (struct gdbarch *gdbarch, int regnum)
+{
+ regnum -= gdbarch_num_regs (gdbarch);
+
+ if (regnum < SPARC64_NUM_PSEUDO_REGS)
+ return sparc64_pseudo_register_names[regnum];
+
+ internal_error (__FILE__, __LINE__,
+ _("sparc64_pseudo_register_name: bad register number %d"),
+ regnum);
+}
/* Return the name of register REGNUM. */
static const char *
-sparc64_register_name (int regnum)
+sparc64_register_name (struct gdbarch *gdbarch, int regnum)
{
- if (regnum >= 0 && regnum < SPARC64_NUM_REGS)
- return sparc64_register_info[regnum].name;
+ if (tdesc_has_registers (gdbarch_target_desc (gdbarch)))
+ return tdesc_register_name (gdbarch, regnum);
- if (regnum >= SPARC64_NUM_REGS
- && regnum < SPARC64_NUM_REGS + SPARC64_NUM_PSEUDO_REGS)
- return sparc64_pseudo_register_info[regnum - SPARC64_NUM_REGS].name;
+ if (regnum >= 0 && regnum < gdbarch_num_regs (gdbarch))
+ return sparc64_register_names[regnum];
- return NULL;
+ return sparc64_pseudo_register_name (gdbarch, regnum);
}
/* Return the GDB type object for the "standard" data type of data in
- register REGNUM. */
+ pseudo register REGNUM. */
+
+static struct type *
+sparc64_pseudo_register_type (struct gdbarch *gdbarch, int regnum)
+{
+ regnum -= gdbarch_num_regs (gdbarch);
+
+ if (regnum == SPARC64_CWP_REGNUM)
+ return builtin_type (gdbarch)->builtin_int64;
+ if (regnum == SPARC64_PSTATE_REGNUM)
+ return sparc64_pstate_type (gdbarch);
+ if (regnum == SPARC64_ASI_REGNUM)
+ return builtin_type (gdbarch)->builtin_int64;
+ if (regnum == SPARC64_CCR_REGNUM)
+ return sparc64_ccr_type (gdbarch);
+ if (regnum >= SPARC64_D0_REGNUM && regnum <= SPARC64_D62_REGNUM)
+ return builtin_type (gdbarch)->builtin_double;
+ if (regnum >= SPARC64_Q0_REGNUM && regnum <= SPARC64_Q60_REGNUM)
+ return builtin_type (gdbarch)->builtin_long_double;
+
+ internal_error (__FILE__, __LINE__,
+ _("sparc64_pseudo_register_type: bad register number %d"),
+ regnum);
+}
+
+/* Return the GDB type object for the "standard" data type of data in
+ register REGNUM. */
static struct type *
sparc64_register_type (struct gdbarch *gdbarch, int regnum)
{
- if (regnum >= SPARC64_NUM_REGS
- && regnum < SPARC64_NUM_REGS + SPARC64_NUM_PSEUDO_REGS)
- return *sparc64_pseudo_register_info[regnum - SPARC64_NUM_REGS].type;
+ if (tdesc_has_registers (gdbarch_target_desc (gdbarch)))
+ return tdesc_register_type (gdbarch, regnum);
+
+ /* Raw registers. */
+ if (regnum == SPARC_SP_REGNUM || regnum == SPARC_FP_REGNUM)
+ return builtin_type (gdbarch)->builtin_data_ptr;
+ if (regnum >= SPARC_G0_REGNUM && regnum <= SPARC_I7_REGNUM)
+ return builtin_type (gdbarch)->builtin_int64;
+ if (regnum >= SPARC_F0_REGNUM && regnum <= SPARC_F31_REGNUM)
+ return builtin_type (gdbarch)->builtin_float;
+ if (regnum >= SPARC64_F32_REGNUM && regnum <= SPARC64_F62_REGNUM)
+ return builtin_type (gdbarch)->builtin_double;
+ if (regnum == SPARC64_PC_REGNUM || regnum == SPARC64_NPC_REGNUM)
+ return builtin_type (gdbarch)->builtin_func_ptr;
+ /* This raw register contains the contents of %cwp, %pstate, %asi
+ and %ccr as laid out in a %tstate register. */
+ if (regnum == SPARC64_STATE_REGNUM)
+ return builtin_type (gdbarch)->builtin_int64;
+ if (regnum == SPARC64_FSR_REGNUM)
+ return sparc64_fsr_type (gdbarch);
+ if (regnum == SPARC64_FPRS_REGNUM)
+ return sparc64_fprs_type (gdbarch);
+ /* "Although Y is a 64-bit register, its high-order 32 bits are
+ reserved and always read as 0." */
+ if (regnum == SPARC64_Y_REGNUM)
+ return builtin_type (gdbarch)->builtin_int64;
+
+ /* Pseudo registers. */
+ if (regnum >= gdbarch_num_regs (gdbarch))
+ return sparc64_pseudo_register_type (gdbarch, regnum);
- gdb_assert (regnum >= 0 && regnum < SPARC64_NUM_REGS);
- return *sparc64_register_info[regnum].type;
+ internal_error (__FILE__, __LINE__, _("invalid regnum"));
}
-static void
+static enum register_status
sparc64_pseudo_register_read (struct gdbarch *gdbarch,
- struct regcache *regcache,
- int regnum, void *buf)
+ readable_regcache *regcache,
+ int regnum, gdb_byte *buf)
{
- gdb_assert (regnum >= SPARC64_NUM_REGS);
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+ enum register_status status;
+
+ regnum -= gdbarch_num_regs (gdbarch);
if (regnum >= SPARC64_D0_REGNUM && regnum <= SPARC64_D30_REGNUM)
{
regnum = SPARC_F0_REGNUM + 2 * (regnum - SPARC64_D0_REGNUM);
- regcache_raw_read (regcache, regnum, buf);
- regcache_raw_read (regcache, regnum + 1, ((char *)buf) + 4);
+ status = regcache->raw_read (regnum, buf);
+ if (status == REG_VALID)
+ status = regcache->raw_read (regnum + 1, buf + 4);
+ return status;
}
else if (regnum >= SPARC64_D32_REGNUM && regnum <= SPARC64_D62_REGNUM)
{
regnum = SPARC64_F32_REGNUM + (regnum - SPARC64_D32_REGNUM);
- regcache_raw_read (regcache, regnum, buf);
+ return regcache->raw_read (regnum, buf);
}
else if (regnum >= SPARC64_Q0_REGNUM && regnum <= SPARC64_Q28_REGNUM)
{
regnum = SPARC_F0_REGNUM + 4 * (regnum - SPARC64_Q0_REGNUM);
- regcache_raw_read (regcache, regnum, buf);
- regcache_raw_read (regcache, regnum + 1, ((char *)buf) + 4);
- regcache_raw_read (regcache, regnum + 2, ((char *)buf) + 8);
- regcache_raw_read (regcache, regnum + 3, ((char *)buf) + 12);
+
+ status = regcache->raw_read (regnum, buf);
+ if (status == REG_VALID)
+ status = regcache->raw_read (regnum + 1, buf + 4);
+ if (status == REG_VALID)
+ status = regcache->raw_read (regnum + 2, buf + 8);
+ if (status == REG_VALID)
+ status = regcache->raw_read (regnum + 3, buf + 12);
+
+ return status;
}
else if (regnum >= SPARC64_Q32_REGNUM && regnum <= SPARC64_Q60_REGNUM)
{
regnum = SPARC64_F32_REGNUM + 2 * (regnum - SPARC64_Q32_REGNUM);
- regcache_raw_read (regcache, regnum, buf);
- regcache_raw_read (regcache, regnum + 1, ((char *)buf) + 8);
+
+ status = regcache->raw_read (regnum, buf);
+ if (status == REG_VALID)
+ status = regcache->raw_read (regnum + 1, buf + 8);
+
+ return status;
}
else if (regnum == SPARC64_CWP_REGNUM
|| regnum == SPARC64_PSTATE_REGNUM
@@ -366,7 +952,10 @@ sparc64_pseudo_register_read (struct gdbarch *gdbarch,
{
ULONGEST state;
- regcache_raw_read_unsigned (regcache, SPARC64_STATE_REGNUM, &state);
+ status = regcache->raw_read (SPARC64_STATE_REGNUM, &state);
+ if (status != REG_VALID)
+ return status;
+
switch (regnum)
{
case SPARC64_CWP_REGNUM:
@@ -382,41 +971,45 @@ sparc64_pseudo_register_read (struct gdbarch *gdbarch,
state = (state >> 32) & ((1 << 8) - 1);
break;
}
- store_unsigned_integer (buf, 8, state);
+ store_unsigned_integer (buf, 8, byte_order, state);
}
+
+ return REG_VALID;
}
static void
sparc64_pseudo_register_write (struct gdbarch *gdbarch,
struct regcache *regcache,
- int regnum, const void *buf)
+ int regnum, const gdb_byte *buf)
{
- gdb_assert (regnum >= SPARC64_NUM_REGS);
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+
+ regnum -= gdbarch_num_regs (gdbarch);
if (regnum >= SPARC64_D0_REGNUM && regnum <= SPARC64_D30_REGNUM)
{
regnum = SPARC_F0_REGNUM + 2 * (regnum - SPARC64_D0_REGNUM);
- regcache_raw_write (regcache, regnum, buf);
- regcache_raw_write (regcache, regnum + 1, ((const char *)buf) + 4);
+ regcache->raw_write (regnum, buf);
+ regcache->raw_write (regnum + 1, buf + 4);
}
else if (regnum >= SPARC64_D32_REGNUM && regnum <= SPARC64_D62_REGNUM)
{
regnum = SPARC64_F32_REGNUM + (regnum - SPARC64_D32_REGNUM);
- regcache_raw_write (regcache, regnum, buf);
+ regcache->raw_write (regnum, buf);
}
else if (regnum >= SPARC64_Q0_REGNUM && regnum <= SPARC64_Q28_REGNUM)
{
regnum = SPARC_F0_REGNUM + 4 * (regnum - SPARC64_Q0_REGNUM);
- regcache_raw_write (regcache, regnum, buf);
- regcache_raw_write (regcache, regnum + 1, ((const char *)buf) + 4);
- regcache_raw_write (regcache, regnum + 2, ((const char *)buf) + 8);
- regcache_raw_write (regcache, regnum + 3, ((const char *)buf) + 12);
+ regcache->raw_write (regnum, buf);
+ regcache->raw_write (regnum + 1, buf + 4);
+ regcache->raw_write (regnum + 2, buf + 8);
+ regcache->raw_write (regnum + 3, buf + 12);
}
else if (regnum >= SPARC64_Q32_REGNUM && regnum <= SPARC64_Q60_REGNUM)
{
regnum = SPARC64_F32_REGNUM + 2 * (regnum - SPARC64_Q32_REGNUM);
- regcache_raw_write (regcache, regnum, buf);
- regcache_raw_write (regcache, regnum + 1, ((const char *)buf) + 8);
+ regcache->raw_write (regnum, buf);
+ regcache->raw_write (regnum + 1, buf + 8);
}
else if (regnum == SPARC64_CWP_REGNUM
|| regnum == SPARC64_PSTATE_REGNUM
@@ -426,7 +1019,7 @@ sparc64_pseudo_register_write (struct gdbarch *gdbarch,
ULONGEST state, bits;
regcache_raw_read_unsigned (regcache, SPARC64_STATE_REGNUM, &state);
- bits = extract_unsigned_integer (buf, 8);
+ bits = extract_unsigned_integer (buf, 8, byte_order);
switch (regnum)
{
case SPARC64_CWP_REGNUM:
@@ -451,7 +1044,7 @@ sparc64_pseudo_register_write (struct gdbarch *gdbarch,
START_PC. */
static CORE_ADDR
-sparc64_skip_prologue (CORE_ADDR start_pc)
+sparc64_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR start_pc)
{
struct symtab_and_line sal;
CORE_ADDR func_start, func_end;
@@ -468,23 +1061,24 @@ sparc64_skip_prologue (CORE_ADDR start_pc)
return sal.end;
}
- return sparc_analyze_prologue (start_pc, 0xffffffffffffffffULL, &cache);
+ return sparc_analyze_prologue (gdbarch, start_pc, 0xffffffffffffffffULL,
+ &cache);
}
/* Normal frames. */
static struct sparc_frame_cache *
-sparc64_frame_cache (struct frame_info *next_frame, void **this_cache)
+sparc64_frame_cache (struct frame_info *this_frame, void **this_cache)
{
- return sparc_frame_cache (next_frame, this_cache);
+ return sparc_frame_cache (this_frame, this_cache);
}
static void
-sparc64_frame_this_id (struct frame_info *next_frame, void **this_cache,
+sparc64_frame_this_id (struct frame_info *this_frame, void **this_cache,
struct frame_id *this_id)
{
struct sparc_frame_cache *cache =
- sparc64_frame_cache (next_frame, this_cache);
+ sparc64_frame_cache (this_frame, this_cache);
/* This marks the outermost frame. */
if (cache->base == 0)
@@ -493,82 +1087,75 @@ sparc64_frame_this_id (struct frame_info *next_frame, void **this_cache,
(*this_id) = frame_id_build (cache->base, cache->pc);
}
-static void
-sparc64_frame_prev_register (struct frame_info *next_frame, void **this_cache,
- int regnum, int *optimizedp,
- enum lval_type *lvalp, CORE_ADDR *addrp,
- int *realnump, void *valuep)
+static struct value *
+sparc64_frame_prev_register (struct frame_info *this_frame, void **this_cache,
+ int regnum)
{
+ struct gdbarch *gdbarch = get_frame_arch (this_frame);
struct sparc_frame_cache *cache =
- sparc64_frame_cache (next_frame, this_cache);
+ sparc64_frame_cache (this_frame, this_cache);
if (regnum == SPARC64_PC_REGNUM || regnum == SPARC64_NPC_REGNUM)
{
- *optimizedp = 0;
- *lvalp = not_lval;
- *addrp = 0;
- *realnump = -1;
- if (valuep)
- {
- CORE_ADDR pc = (regnum == SPARC64_NPC_REGNUM) ? 4 : 0;
+ CORE_ADDR pc = (regnum == SPARC64_NPC_REGNUM) ? 4 : 0;
- regnum = cache->frameless_p ? SPARC_O7_REGNUM : SPARC_I7_REGNUM;
- pc += frame_unwind_register_unsigned (next_frame, regnum) + 8;
- store_unsigned_integer (valuep, 8, pc);
- }
- return;
+ regnum =
+ (cache->copied_regs_mask & 0x80) ? SPARC_I7_REGNUM : SPARC_O7_REGNUM;
+ pc += get_frame_register_unsigned (this_frame, regnum) + 8;
+ return frame_unwind_got_constant (this_frame, regnum, pc);
}
- /* The previous frame's `local' and `in' registers have been saved
+ /* Handle StackGhost. */
+ {
+ ULONGEST wcookie = sparc_fetch_wcookie (gdbarch);
+
+ if (wcookie != 0 && !cache->frameless_p && regnum == SPARC_I7_REGNUM)
+ {
+ CORE_ADDR addr = cache->base + (regnum - SPARC_L0_REGNUM) * 8;
+ ULONGEST i7;
+
+ /* Read the value in from memory. */
+ i7 = get_frame_memory_unsigned (this_frame, addr, 8);
+ return frame_unwind_got_constant (this_frame, regnum, i7 ^ wcookie);
+ }
+ }
+
+ /* The previous frame's `local' and `in' registers may have been saved
in the register save area. */
- if (!cache->frameless_p
- && regnum >= SPARC_L0_REGNUM && regnum <= SPARC_I7_REGNUM)
- {
- *optimizedp = 0;
- *lvalp = lval_memory;
- *addrp = cache->base + BIAS + (regnum - SPARC_L0_REGNUM) * 8;
- *realnump = -1;
- if (valuep)
- {
- struct gdbarch *gdbarch = get_frame_arch (next_frame);
+ if (regnum >= SPARC_L0_REGNUM && regnum <= SPARC_I7_REGNUM
+ && (cache->saved_regs_mask & (1 << (regnum - SPARC_L0_REGNUM))))
+ {
+ CORE_ADDR addr = cache->base + (regnum - SPARC_L0_REGNUM) * 8;
- /* Read the value in from memory. */
- read_memory (*addrp, valuep, register_size (gdbarch, regnum));
- }
- return;
+ return frame_unwind_got_memory (this_frame, regnum, addr);
}
- /* The previous frame's `out' registers are accessable as the
- current frame's `in' registers. */
- if (!cache->frameless_p
- && regnum >= SPARC_O0_REGNUM && regnum <= SPARC_O7_REGNUM)
+ /* The previous frame's `out' registers may be accessible as the current
+ frame's `in' registers. */
+ if (regnum >= SPARC_O0_REGNUM && regnum <= SPARC_O7_REGNUM
+ && (cache->copied_regs_mask & (1 << (regnum - SPARC_O0_REGNUM))))
regnum += (SPARC_I0_REGNUM - SPARC_O0_REGNUM);
- frame_register_unwind (next_frame, regnum,
- optimizedp, lvalp, addrp, realnump, valuep);
+ return frame_unwind_got_register (this_frame, regnum, regnum);
}
static const struct frame_unwind sparc64_frame_unwind =
{
NORMAL_FRAME,
+ default_frame_unwind_stop_reason,
sparc64_frame_this_id,
- sparc64_frame_prev_register
+ sparc64_frame_prev_register,
+ NULL,
+ default_frame_sniffer
};
-
-static const struct frame_unwind *
-sparc64_frame_sniffer (struct frame_info *next_frame)
-{
- return &sparc64_frame_unwind;
-}
static CORE_ADDR
-sparc64_frame_base_address (struct frame_info *next_frame, void **this_cache)
+sparc64_frame_base_address (struct frame_info *this_frame, void **this_cache)
{
struct sparc_frame_cache *cache =
- sparc64_frame_cache (next_frame, this_cache);
+ sparc64_frame_cache (this_frame, this_cache);
- /* ??? Should we take BIAS into account here? */
return cache->base;
}
@@ -585,6 +1172,13 @@ static const struct frame_base sparc64_frame_base =
static int
sparc64_16_byte_align_p (struct type *type)
{
+ if (TYPE_CODE (type) == TYPE_CODE_ARRAY)
+ {
+ struct type *t = check_typedef (TYPE_TARGET_TYPE (type));
+
+ if (sparc64_floating_p (t))
+ return 1;
+ }
if (sparc64_floating_p (type) && TYPE_LENGTH (type) == 16)
return 1;
@@ -612,13 +1206,32 @@ sparc64_16_byte_align_p (struct type *type)
static void
sparc64_store_floating_fields (struct regcache *regcache, struct type *type,
- char *valbuf, int element, int bitpos)
+ const gdb_byte *valbuf, int element, int bitpos)
{
+ struct gdbarch *gdbarch = regcache->arch ();
+ int len = TYPE_LENGTH (type);
+
gdb_assert (element < 16);
- if (sparc64_floating_p (type))
+ if (TYPE_CODE (type) == TYPE_CODE_ARRAY)
+ {
+ gdb_byte buf[8];
+ int regnum = SPARC_F0_REGNUM + element * 2 + bitpos / 32;
+
+ valbuf += bitpos / 8;
+ if (len < 8)
+ {
+ memset (buf, 0, 8 - len);
+ memcpy (buf + 8 - len, valbuf, len);
+ valbuf = buf;
+ len = 8;
+ }
+ for (int n = 0; n < (len + 3) / 4; n++)
+ regcache->cooked_write (regnum + n, valbuf + n * 4);
+ }
+ else if (sparc64_floating_p (type)
+ || (sparc64_complex_floating_p (type) && len <= 16))
{
- int len = TYPE_LENGTH (type);
int regnum;
if (len == 16)
@@ -626,15 +1239,16 @@ sparc64_store_floating_fields (struct regcache *regcache, struct type *type,
gdb_assert (bitpos == 0);
gdb_assert ((element % 2) == 0);
- regnum = SPARC64_Q0_REGNUM + element / 2;
- regcache_cooked_write (regcache, regnum, valbuf);
+ regnum = gdbarch_num_regs (gdbarch) + SPARC64_Q0_REGNUM + element / 2;
+ regcache->cooked_write (regnum, valbuf);
}
else if (len == 8)
{
gdb_assert (bitpos == 0 || bitpos == 64);
- regnum = SPARC64_D0_REGNUM + element + bitpos / 64;
- regcache_cooked_write (regcache, regnum, valbuf + (bitpos / 8));
+ regnum = gdbarch_num_regs (gdbarch) + SPARC64_D0_REGNUM
+ + element + bitpos / 64;
+ regcache->cooked_write (regnum, valbuf + (bitpos / 8));
}
else
{
@@ -642,7 +1256,7 @@ sparc64_store_floating_fields (struct regcache *regcache, struct type *type,
gdb_assert (bitpos % 32 == 0 && bitpos >= 0 && bitpos < 128);
regnum = SPARC_F0_REGNUM + element * 2 + bitpos / 32;
- regcache_cooked_write (regcache, regnum, valbuf + (bitpos / 8));
+ regcache->cooked_write (regnum, valbuf + (bitpos / 8));
}
}
else if (sparc64_structure_or_union_p (type))
@@ -672,7 +1286,7 @@ sparc64_store_floating_fields (struct regcache *regcache, struct type *type,
struct type *subtype = check_typedef (TYPE_FIELD_TYPE (type, 0));
if (sparc64_floating_p (subtype) && TYPE_LENGTH (subtype) == 4)
- regcache_cooked_write (regcache, SPARC_F1_REGNUM, valbuf);
+ regcache->cooked_write (SPARC_F1_REGNUM, valbuf);
}
}
}
@@ -684,9 +1298,27 @@ sparc64_store_floating_fields (struct regcache *regcache, struct type *type,
static void
sparc64_extract_floating_fields (struct regcache *regcache, struct type *type,
- char *valbuf, int bitpos)
+ gdb_byte *valbuf, int bitpos)
{
- if (sparc64_floating_p (type))
+ struct gdbarch *gdbarch = regcache->arch ();
+
+ if (TYPE_CODE (type) == TYPE_CODE_ARRAY)
+ {
+ int len = TYPE_LENGTH (type);
+ int regnum = SPARC_F0_REGNUM + bitpos / 32;
+
+ valbuf += bitpos / 8;
+ if (len < 4)
+ {
+ gdb_byte buf[4];
+ regcache->cooked_read (regnum, buf);
+ memcpy (valbuf, buf + 4 - len, len);
+ }
+ else
+ for (int i = 0; i < (len + 3) / 4; i++)
+ regcache->cooked_read (regnum + i, valbuf + i * 4);
+ }
+ else if (sparc64_floating_p (type))
{
int len = TYPE_LENGTH (type);
int regnum;
@@ -695,15 +1327,16 @@ sparc64_extract_floating_fields (struct regcache *regcache, struct type *type,
{
gdb_assert (bitpos == 0 || bitpos == 128);
- regnum = SPARC64_Q0_REGNUM + bitpos / 128;
- regcache_cooked_read (regcache, regnum, valbuf + (bitpos / 8));
+ regnum = gdbarch_num_regs (gdbarch) + SPARC64_Q0_REGNUM
+ + bitpos / 128;
+ regcache->cooked_read (regnum, valbuf + (bitpos / 8));
}
else if (len == 8)
{
gdb_assert (bitpos % 64 == 0 && bitpos >= 0 && bitpos < 256);
- regnum = SPARC64_D0_REGNUM + bitpos / 64;
- regcache_cooked_read (regcache, regnum, valbuf + (bitpos / 8));
+ regnum = gdbarch_num_regs (gdbarch) + SPARC64_D0_REGNUM + bitpos / 64;
+ regcache->cooked_read (regnum, valbuf + (bitpos / 8));
}
else
{
@@ -711,7 +1344,7 @@ sparc64_extract_floating_fields (struct regcache *regcache, struct type *type,
gdb_assert (bitpos % 32 == 0 && bitpos >= 0 && bitpos < 256);
regnum = SPARC_F0_REGNUM + bitpos / 32;
- regcache_cooked_read (regcache, regnum, valbuf + (bitpos / 8));
+ regcache->cooked_read (regnum, valbuf + (bitpos / 8));
}
}
else if (sparc64_structure_or_union_p (type))
@@ -734,8 +1367,10 @@ sparc64_extract_floating_fields (struct regcache *regcache, struct type *type,
static CORE_ADDR
sparc64_store_arguments (struct regcache *regcache, int nargs,
struct value **args, CORE_ADDR sp,
- int struct_return, CORE_ADDR struct_addr)
+ function_call_return_method return_method,
+ CORE_ADDR struct_addr)
{
+ struct gdbarch *gdbarch = regcache->arch ();
/* Number of extended words in the "parameter array". */
int num_elements = 0;
int element = 0;
@@ -747,15 +1382,16 @@ sparc64_store_arguments (struct regcache *regcache, int nargs,
/* First we calculate the number of extended words in the "parameter
array". While doing so we also convert some of the arguments. */
- if (struct_return)
+ if (return_method == return_method_struct)
num_elements++;
for (i = 0; i < nargs; i++)
{
- struct type *type = VALUE_TYPE (args[i]);
+ struct type *type = value_type (args[i]);
int len = TYPE_LENGTH (type);
- if (sparc64_structure_or_union_p (type))
+ if (sparc64_structure_or_union_p (type)
+ || (sparc64_complex_floating_p (type) && len == 32))
{
/* Structure or Union arguments. */
if (len <= 16)
@@ -781,15 +1417,14 @@ sparc64_store_arguments (struct regcache *regcache, int nargs,
a problem. */
sp &= ~0xf;
- write_memory (sp, VALUE_CONTENTS (args[i]), len);
+ write_memory (sp, value_contents (args[i]), len);
args[i] = value_from_pointer (lookup_pointer_type (type), sp);
num_elements++;
}
}
- else if (sparc64_floating_p (type))
+ else if (sparc64_floating_p (type) || sparc64_complex_floating_p (type))
{
/* Floating arguments. */
-
if (len == 16)
{
/* The psABI says that "Each quad-precision parameter
@@ -801,7 +1436,7 @@ sparc64_store_arguments (struct regcache *regcache, int nargs,
quad-aligned, and thus a hole might be introduced
into the parameter array to force alignment." Skip
an element if necessary. */
- if (num_elements % 2)
+ if ((num_elements % 2) && sparc64_16_byte_align_p (type))
num_elements++;
}
else
@@ -817,7 +1452,8 @@ sparc64_store_arguments (struct regcache *regcache, int nargs,
caller to an extended word according to the signed-ness
of the argument type." */
if (len < 8)
- args[i] = value_cast (builtin_type_int64, args[i]);
+ args[i] = value_cast (builtin_type (gdbarch)->builtin_int64,
+ args[i]);
num_elements++;
}
}
@@ -842,7 +1478,7 @@ sparc64_store_arguments (struct regcache *regcache, int nargs,
contents of any unused memory or registers in the "parameter
array" are undefined. */
- if (struct_return)
+ if (return_method == return_method_struct)
{
regcache_cooked_write_unsigned (regcache, SPARC_O0_REGNUM, struct_addr);
element++;
@@ -850,18 +1486,20 @@ sparc64_store_arguments (struct regcache *regcache, int nargs,
for (i = 0; i < nargs; i++)
{
- char *valbuf = VALUE_CONTENTS (args[i]);
- struct type *type = VALUE_TYPE (args[i]);
+ const gdb_byte *valbuf = value_contents (args[i]);
+ struct type *type = value_type (args[i]);
int len = TYPE_LENGTH (type);
int regnum = -1;
- char buf[16];
+ gdb_byte buf[16];
- if (sparc64_structure_or_union_p (type))
+ if (sparc64_structure_or_union_p (type)
+ || (sparc64_complex_floating_p (type) && len == 32))
{
- /* Structure or Union arguments. */
+ /* Structure, Union or long double Complex arguments. */
gdb_assert (len <= 16);
memset (buf, 0, sizeof (buf));
- valbuf = memcpy (buf, valbuf, len);
+ memcpy (buf, valbuf, len);
+ valbuf = buf;
if (element % 2 && sparc64_16_byte_align_p (type))
element++;
@@ -870,12 +1508,29 @@ sparc64_store_arguments (struct regcache *regcache, int nargs,
{
regnum = SPARC_O0_REGNUM + element;
if (len > 8 && element < 5)
- regcache_cooked_write (regcache, regnum + 1, valbuf + 8);
+ regcache->cooked_write (regnum + 1, valbuf + 8);
}
if (element < 16)
sparc64_store_floating_fields (regcache, type, valbuf, element, 0);
}
+ else if (sparc64_complex_floating_p (type))
+ {
+ /* Float Complex or double Complex arguments. */
+ if (element < 16)
+ {
+ regnum = gdbarch_num_regs (gdbarch) + SPARC64_D0_REGNUM + element;
+
+ if (len == 16)
+ {
+ if (regnum < gdbarch_num_regs (gdbarch) + SPARC64_D30_REGNUM)
+ regcache->cooked_write (regnum + 1, valbuf + 8);
+ if (regnum < gdbarch_num_regs (gdbarch) + SPARC64_D10_REGNUM)
+ regcache->cooked_write (SPARC_O0_REGNUM + element + 1,
+ valbuf + 8);
+ }
+ }
+ }
else if (sparc64_floating_p (type))
{
/* Floating arguments. */
@@ -884,19 +1539,21 @@ sparc64_store_arguments (struct regcache *regcache, int nargs,
if (element % 2)
element++;
if (element < 16)
- regnum = SPARC64_Q0_REGNUM + element / 2;
+ regnum = gdbarch_num_regs (gdbarch) + SPARC64_Q0_REGNUM
+ + element / 2;
}
else if (len == 8)
{
if (element < 16)
- regnum = SPARC64_D0_REGNUM + element;
+ regnum = gdbarch_num_regs (gdbarch) + SPARC64_D0_REGNUM
+ + element;
}
- else
+ else if (len == 4)
{
/* The psABI says "Each single-precision parameter value
will be assigned to one extended word in the
parameter array, and right-justified within that
- word; the left half (even floatregister) is
+ word; the left half (even float register) is
undefined." Even though the psABI says that "the
left half is undefined", set it to zero here. */
memset (buf, 0, 4);
@@ -904,7 +1561,8 @@ sparc64_store_arguments (struct regcache *regcache, int nargs,
valbuf = buf;
len = 8;
if (element < 16)
- regnum = SPARC64_D0_REGNUM + element;
+ regnum = gdbarch_num_regs (gdbarch) + SPARC64_D0_REGNUM
+ + element;
}
}
else
@@ -917,26 +1575,31 @@ sparc64_store_arguments (struct regcache *regcache, int nargs,
if (regnum != -1)
{
- regcache_cooked_write (regcache, regnum, valbuf);
+ regcache->cooked_write (regnum, valbuf);
/* If we're storing the value in a floating-point register,
also store it in the corresponding %0 register(s). */
- if (regnum >= SPARC64_D0_REGNUM && regnum <= SPARC64_D10_REGNUM)
- {
- gdb_assert (element < 6);
- regnum = SPARC_O0_REGNUM + element;
- regcache_cooked_write (regcache, regnum, valbuf);
- }
- else if (regnum >= SPARC64_Q0_REGNUM && regnum <= SPARC64_Q8_REGNUM)
- {
- gdb_assert (element < 6);
- regnum = SPARC_O0_REGNUM + element;
- regcache_cooked_write (regcache, regnum, valbuf);
- regcache_cooked_write (regcache, regnum + 1, valbuf);
- }
+ if (regnum >= gdbarch_num_regs (gdbarch))
+ {
+ regnum -= gdbarch_num_regs (gdbarch);
+
+ if (regnum >= SPARC64_D0_REGNUM && regnum <= SPARC64_D10_REGNUM)
+ {
+ gdb_assert (element < 6);
+ regnum = SPARC_O0_REGNUM + element;
+ regcache->cooked_write (regnum, valbuf);
+ }
+ else if (regnum >= SPARC64_Q0_REGNUM && regnum <= SPARC64_Q8_REGNUM)
+ {
+ gdb_assert (element < 5);
+ regnum = SPARC_O0_REGNUM + element;
+ regcache->cooked_write (regnum, valbuf);
+ regcache->cooked_write (regnum + 1, valbuf + 8);
+ }
+ }
}
- /* Always store the argument in memeory. */
+ /* Always store the argument in memory. */
write_memory (sp + element * 8, valbuf, len);
element += ((len + 7) / 8);
}
@@ -949,17 +1612,25 @@ sparc64_store_arguments (struct regcache *regcache, int nargs,
}
static CORE_ADDR
-sparc64_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
+sparc64_frame_align (struct gdbarch *gdbarch, CORE_ADDR address)
+{
+ /* The ABI requires 16-byte alignment. */
+ return address & ~0xf;
+}
+
+static CORE_ADDR
+sparc64_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
struct regcache *regcache, CORE_ADDR bp_addr,
int nargs, struct value **args, CORE_ADDR sp,
- int struct_return, CORE_ADDR struct_addr)
+ function_call_return_method return_method,
+ CORE_ADDR struct_addr)
{
/* Set return address. */
regcache_cooked_write_unsigned (regcache, SPARC_O7_REGNUM, bp_addr - 8);
/* Set up function arguments. */
- sp = sparc64_store_arguments (regcache, nargs, args, sp,
- struct_return, struct_addr);
+ sp = sparc64_store_arguments (regcache, nargs, args, sp, return_method,
+ struct_addr);
/* Allocate the register save area. */
sp -= 16 * 8;
@@ -970,7 +1641,7 @@ sparc64_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
/* Finally, update the stack pointer. */
regcache_cooked_write_unsigned (regcache, SPARC_SP_REGNUM, sp);
- return sp;
+ return sp + BIAS;
}
@@ -979,10 +1650,10 @@ sparc64_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
static void
sparc64_extract_return_value (struct type *type, struct regcache *regcache,
- void *valbuf)
+ gdb_byte *valbuf)
{
int len = TYPE_LENGTH (type);
- char buf[32];
+ gdb_byte buf[32];
int i;
if (sparc64_structure_or_union_p (type))
@@ -991,16 +1662,25 @@ sparc64_extract_return_value (struct type *type, struct regcache *regcache,
gdb_assert (len <= 32);
for (i = 0; i < ((len + 7) / 8); i++)
- regcache_cooked_read (regcache, SPARC_O0_REGNUM + i, buf + i * 8);
+ regcache->cooked_read (SPARC_O0_REGNUM + i, buf + i * 8);
if (TYPE_CODE (type) != TYPE_CODE_UNION)
sparc64_extract_floating_fields (regcache, type, buf, 0);
memcpy (valbuf, buf, len);
}
- else if (sparc64_floating_p (type))
+ else if (sparc64_floating_p (type) || sparc64_complex_floating_p (type))
{
/* Floating return values. */
for (i = 0; i < len / 4; i++)
- regcache_cooked_read (regcache, SPARC_F0_REGNUM + i, buf + i * 4);
+ regcache->cooked_read (SPARC_F0_REGNUM + i, buf + i * 4);
+ memcpy (valbuf, buf, len);
+ }
+ else if (TYPE_CODE (type) == TYPE_CODE_ARRAY)
+ {
+ /* Small arrays are returned the same way as small structures. */
+ gdb_assert (len <= 32);
+
+ for (i = 0; i < ((len + 7) / 8); i++)
+ regcache->cooked_read (SPARC_O0_REGNUM + i, buf + i * 8);
memcpy (valbuf, buf, len);
}
else
@@ -1010,7 +1690,7 @@ sparc64_extract_return_value (struct type *type, struct regcache *regcache,
/* Just stripping off any unused bytes should preserve the
signed-ness just fine. */
- regcache_cooked_read (regcache, SPARC_O0_REGNUM, buf);
+ regcache->cooked_read (SPARC_O0_REGNUM, buf);
memcpy (valbuf, buf + 8 - len, len);
}
}
@@ -1020,10 +1700,10 @@ sparc64_extract_return_value (struct type *type, struct regcache *regcache,
static void
sparc64_store_return_value (struct type *type, struct regcache *regcache,
- const void *valbuf)
+ const gdb_byte *valbuf)
{
int len = TYPE_LENGTH (type);
- char buf[16];
+ gdb_byte buf[16];
int i;
if (sparc64_structure_or_union_p (type))
@@ -1037,16 +1717,26 @@ sparc64_store_return_value (struct type *type, struct regcache *regcache,
memset (buf, 0, sizeof (buf));
memcpy (buf, valbuf, len);
for (i = 0; i < ((len + 7) / 8); i++)
- regcache_cooked_write (regcache, SPARC_O0_REGNUM + i, buf + i * 8);
+ regcache->cooked_write (SPARC_O0_REGNUM + i, buf + i * 8);
if (TYPE_CODE (type) != TYPE_CODE_UNION)
sparc64_store_floating_fields (regcache, type, buf, 0, 0);
}
- else if (sparc64_floating_p (type))
+ else if (sparc64_floating_p (type) || sparc64_complex_floating_p (type))
{
/* Floating return values. */
memcpy (buf, valbuf, len);
for (i = 0; i < len / 4; i++)
- regcache_cooked_write (regcache, SPARC_F0_REGNUM + i, buf + i * 4);
+ regcache->cooked_write (SPARC_F0_REGNUM + i, buf + i * 4);
+ }
+ else if (TYPE_CODE (type) == TYPE_CODE_ARRAY)
+ {
+ /* Small arrays are returned the same way as small structures. */
+ gdb_assert (len <= 32);
+
+ memset (buf, 0, sizeof (buf));
+ memcpy (buf, valbuf, len);
+ for (i = 0; i < ((len + 7) / 8); i++)
+ regcache->cooked_write (SPARC_O0_REGNUM + i, buf + i * 8);
}
else
{
@@ -1056,14 +1746,14 @@ sparc64_store_return_value (struct type *type, struct regcache *regcache,
/* ??? Do we need to do any sign-extension here? */
memset (buf, 0, 8);
memcpy (buf + 8 - len, valbuf, len);
- regcache_cooked_write (regcache, SPARC_O0_REGNUM, buf);
+ regcache->cooked_write (SPARC_O0_REGNUM, buf);
}
}
static enum return_value_convention
-sparc64_return_value (struct gdbarch *gdbarch, struct type *type,
- struct regcache *regcache, void *readbuf,
- const void *writebuf)
+sparc64_return_value (struct gdbarch *gdbarch, struct value *function,
+ struct type *type, struct regcache *regcache,
+ gdb_byte *readbuf, const gdb_byte *writebuf)
{
if (TYPE_LENGTH (type) > 32)
return RETURN_VALUE_STRUCT_CONVENTION;
@@ -1077,6 +1767,41 @@ sparc64_return_value (struct gdbarch *gdbarch, struct type *type,
}
+static void
+sparc64_dwarf2_frame_init_reg (struct gdbarch *gdbarch, int regnum,
+ struct dwarf2_frame_state_reg *reg,
+ struct frame_info *this_frame)
+{
+ switch (regnum)
+ {
+ case SPARC_G0_REGNUM:
+ /* Since %g0 is always zero, there is no point in saving it, and
+ people will be inclined omit it from the CFI. Make sure we
+ don't warn about that. */
+ reg->how = DWARF2_FRAME_REG_SAME_VALUE;
+ break;
+ case SPARC_SP_REGNUM:
+ reg->how = DWARF2_FRAME_REG_CFA;
+ break;
+ case SPARC64_PC_REGNUM:
+ reg->how = DWARF2_FRAME_REG_RA_OFFSET;
+ reg->loc.offset = 8;
+ break;
+ case SPARC64_NPC_REGNUM:
+ reg->how = DWARF2_FRAME_REG_RA_OFFSET;
+ reg->loc.offset = 12;
+ break;
+ }
+}
+
+/* sparc64_addr_bits_remove - remove useless address bits */
+
+static CORE_ADDR
+sparc64_addr_bits_remove (struct gdbarch *gdbarch, CORE_ADDR addr)
+{
+ return adi_normalize_address (addr);
+}
+
void
sparc64_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
{
@@ -1084,16 +1809,25 @@ sparc64_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
tdep->pc_regnum = SPARC64_PC_REGNUM;
tdep->npc_regnum = SPARC64_NPC_REGNUM;
+ tdep->fpu_register_names = sparc64_fpu_register_names;
+ tdep->fpu_registers_num = ARRAY_SIZE (sparc64_fpu_register_names);
+ tdep->cp0_register_names = sparc64_cp0_register_names;
+ tdep->cp0_registers_num = ARRAY_SIZE (sparc64_cp0_register_names);
/* This is what all the fuss is about. */
set_gdbarch_long_bit (gdbarch, 64);
set_gdbarch_long_long_bit (gdbarch, 64);
set_gdbarch_ptr_bit (gdbarch, 64);
+ set_gdbarch_wchar_bit (gdbarch, 16);
+ set_gdbarch_wchar_signed (gdbarch, 0);
+
set_gdbarch_num_regs (gdbarch, SPARC64_NUM_REGS);
set_gdbarch_register_name (gdbarch, sparc64_register_name);
set_gdbarch_register_type (gdbarch, sparc64_register_type);
set_gdbarch_num_pseudo_regs (gdbarch, SPARC64_NUM_PSEUDO_REGS);
+ set_tdesc_pseudo_register_name (gdbarch, sparc64_pseudo_register_name);
+ set_tdesc_pseudo_register_type (gdbarch, sparc64_pseudo_register_type);
set_gdbarch_pseudo_register_read (gdbarch, sparc64_pseudo_register_read);
set_gdbarch_pseudo_register_write (gdbarch, sparc64_pseudo_register_write);
@@ -1101,6 +1835,7 @@ sparc64_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
set_gdbarch_pc_regnum (gdbarch, SPARC64_PC_REGNUM); /* %pc */
/* Call dummy code. */
+ set_gdbarch_frame_align (gdbarch, sparc64_frame_align);
set_gdbarch_call_dummy_location (gdbarch, AT_ENTRY_POINT);
set_gdbarch_push_dummy_code (gdbarch, NULL);
set_gdbarch_push_dummy_call (gdbarch, sparc64_push_dummy_call);
@@ -1110,9 +1845,17 @@ sparc64_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
(gdbarch, default_stabs_argument_has_addr);
set_gdbarch_skip_prologue (gdbarch, sparc64_skip_prologue);
+ set_gdbarch_stack_frame_destroyed_p (gdbarch, sparc_stack_frame_destroyed_p);
- frame_unwind_append_sniffer (gdbarch, sparc64_frame_sniffer);
+ /* Hook in the DWARF CFI frame unwinder. */
+ dwarf2_frame_set_init_reg (gdbarch, sparc64_dwarf2_frame_init_reg);
+ /* FIXME: kettenis/20050423: Don't enable the unwinder until the
+ StackGhost issues have been resolved. */
+
+ frame_unwind_append_unwinder (gdbarch, &sparc64_frame_unwind);
frame_base_set_default (gdbarch, &sparc64_frame_base);
+
+ set_gdbarch_addr_bits_remove (gdbarch, sparc64_addr_bits_remove);
}
@@ -1123,86 +1866,93 @@ sparc64_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
#define TSTATE_XCC 0x000000f000000000ULL
#define PSR_S 0x00000080
+#ifndef PSR_ICC
#define PSR_ICC 0x00f00000
+#endif
#define PSR_VERS 0x0f000000
+#ifndef PSR_IMPL
#define PSR_IMPL 0xf0000000
+#endif
#define PSR_V8PLUS 0xff000000
#define PSR_XCC 0x000f0000
void
-sparc64_supply_gregset (const struct sparc_gregset *gregset,
+sparc64_supply_gregset (const struct sparc_gregmap *gregmap,
struct regcache *regcache,
int regnum, const void *gregs)
{
- int sparc32 = (gdbarch_ptr_bit (current_gdbarch) == 32);
- const char *regs = gregs;
+ struct gdbarch *gdbarch = regcache->arch ();
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+ int sparc32 = (gdbarch_ptr_bit (gdbarch) == 32);
+ const gdb_byte *regs = (const gdb_byte *) gregs;
+ gdb_byte zero[8] = { 0 };
int i;
if (sparc32)
{
if (regnum == SPARC32_PSR_REGNUM || regnum == -1)
{
- int offset = gregset->r_tstate_offset;
+ int offset = gregmap->r_tstate_offset;
ULONGEST tstate, psr;
- char buf[4];
+ gdb_byte buf[4];
- tstate = extract_unsigned_integer (regs + offset, 8);
+ tstate = extract_unsigned_integer (regs + offset, 8, byte_order);
psr = ((tstate & TSTATE_CWP) | PSR_S | ((tstate & TSTATE_ICC) >> 12)
| ((tstate & TSTATE_XCC) >> 20) | PSR_V8PLUS);
- store_unsigned_integer (buf, 4, psr);
- regcache_raw_supply (regcache, SPARC32_PSR_REGNUM, buf);
+ store_unsigned_integer (buf, 4, byte_order, psr);
+ regcache->raw_supply (SPARC32_PSR_REGNUM, buf);
}
if (regnum == SPARC32_PC_REGNUM || regnum == -1)
- regcache_raw_supply (regcache, SPARC32_PC_REGNUM,
- regs + gregset->r_pc_offset + 4);
+ regcache->raw_supply (SPARC32_PC_REGNUM,
+ regs + gregmap->r_pc_offset + 4);
if (regnum == SPARC32_NPC_REGNUM || regnum == -1)
- regcache_raw_supply (regcache, SPARC32_NPC_REGNUM,
- regs + gregset->r_npc_offset + 4);
+ regcache->raw_supply (SPARC32_NPC_REGNUM,
+ regs + gregmap->r_npc_offset + 4);
if (regnum == SPARC32_Y_REGNUM || regnum == -1)
{
- int offset = gregset->r_y_offset + 8 - gregset->r_y_size;
- regcache_raw_supply (regcache, SPARC32_Y_REGNUM, regs + offset);
+ int offset = gregmap->r_y_offset + 8 - gregmap->r_y_size;
+ regcache->raw_supply (SPARC32_Y_REGNUM, regs + offset);
}
}
else
{
if (regnum == SPARC64_STATE_REGNUM || regnum == -1)
- regcache_raw_supply (regcache, SPARC64_STATE_REGNUM,
- regs + gregset->r_tstate_offset);
+ regcache->raw_supply (SPARC64_STATE_REGNUM,
+ regs + gregmap->r_tstate_offset);
if (regnum == SPARC64_PC_REGNUM || regnum == -1)
- regcache_raw_supply (regcache, SPARC64_PC_REGNUM,
- regs + gregset->r_pc_offset);
+ regcache->raw_supply (SPARC64_PC_REGNUM,
+ regs + gregmap->r_pc_offset);
if (regnum == SPARC64_NPC_REGNUM || regnum == -1)
- regcache_raw_supply (regcache, SPARC64_NPC_REGNUM,
- regs + gregset->r_npc_offset);
+ regcache->raw_supply (SPARC64_NPC_REGNUM,
+ regs + gregmap->r_npc_offset);
if (regnum == SPARC64_Y_REGNUM || regnum == -1)
{
- char buf[8];
+ gdb_byte buf[8];
memset (buf, 0, 8);
- memcpy (buf + 8 - gregset->r_y_size,
- regs + gregset->r_y_offset, gregset->r_y_size);
- regcache_raw_supply (regcache, SPARC64_Y_REGNUM, buf);
+ memcpy (buf + 8 - gregmap->r_y_size,
+ regs + gregmap->r_y_offset, gregmap->r_y_size);
+ regcache->raw_supply (SPARC64_Y_REGNUM, buf);
}
if ((regnum == SPARC64_FPRS_REGNUM || regnum == -1)
- && gregset->r_fprs_offset != -1)
- regcache_raw_supply (regcache, SPARC64_FPRS_REGNUM,
- regs + gregset->r_fprs_offset);
+ && gregmap->r_fprs_offset != -1)
+ regcache->raw_supply (SPARC64_FPRS_REGNUM,
+ regs + gregmap->r_fprs_offset);
}
if (regnum == SPARC_G0_REGNUM || regnum == -1)
- regcache_raw_supply (regcache, SPARC_G0_REGNUM, NULL);
+ regcache->raw_supply (SPARC_G0_REGNUM, &zero);
if ((regnum >= SPARC_G1_REGNUM && regnum <= SPARC_O7_REGNUM) || regnum == -1)
{
- int offset = gregset->r_g1_offset;
+ int offset = gregmap->r_g1_offset;
if (sparc32)
offset += 4;
@@ -1210,7 +1960,7 @@ sparc64_supply_gregset (const struct sparc_gregset *gregset,
for (i = SPARC_G1_REGNUM; i <= SPARC_O7_REGNUM; i++)
{
if (regnum == i || regnum == -1)
- regcache_raw_supply (regcache, i, regs + offset);
+ regcache->raw_supply (i, regs + offset);
offset += 8;
}
}
@@ -1219,7 +1969,7 @@ sparc64_supply_gregset (const struct sparc_gregset *gregset,
{
/* Not all of the register set variants include Locals and
Inputs. For those that don't, we read them off the stack. */
- if (gregset->r_l0_offset == -1)
+ if (gregmap->r_l0_offset == -1)
{
ULONGEST sp;
@@ -1228,7 +1978,7 @@ sparc64_supply_gregset (const struct sparc_gregset *gregset,
}
else
{
- int offset = gregset->r_l0_offset;
+ int offset = gregmap->r_l0_offset;
if (sparc32)
offset += 4;
@@ -1236,7 +1986,7 @@ sparc64_supply_gregset (const struct sparc_gregset *gregset,
for (i = SPARC_L0_REGNUM; i <= SPARC_I7_REGNUM; i++)
{
if (regnum == i || regnum == -1)
- regcache_raw_supply (regcache, i, regs + offset);
+ regcache->raw_supply (i, regs + offset);
offset += 8;
}
}
@@ -1244,79 +1994,81 @@ sparc64_supply_gregset (const struct sparc_gregset *gregset,
}
void
-sparc64_collect_gregset (const struct sparc_gregset *gregset,
+sparc64_collect_gregset (const struct sparc_gregmap *gregmap,
const struct regcache *regcache,
int regnum, void *gregs)
{
- int sparc32 = (gdbarch_ptr_bit (current_gdbarch) == 32);
- char *regs = gregs;
+ struct gdbarch *gdbarch = regcache->arch ();
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+ int sparc32 = (gdbarch_ptr_bit (gdbarch) == 32);
+ gdb_byte *regs = (gdb_byte *) gregs;
int i;
if (sparc32)
{
if (regnum == SPARC32_PSR_REGNUM || regnum == -1)
{
- int offset = gregset->r_tstate_offset;
+ int offset = gregmap->r_tstate_offset;
ULONGEST tstate, psr;
- char buf[8];
+ gdb_byte buf[8];
- tstate = extract_unsigned_integer (regs + offset, 8);
- regcache_raw_collect (regcache, SPARC32_PSR_REGNUM, buf);
- psr = extract_unsigned_integer (buf, 4);
+ tstate = extract_unsigned_integer (regs + offset, 8, byte_order);
+ regcache->raw_collect (SPARC32_PSR_REGNUM, buf);
+ psr = extract_unsigned_integer (buf, 4, byte_order);
tstate |= (psr & PSR_ICC) << 12;
if ((psr & (PSR_VERS | PSR_IMPL)) == PSR_V8PLUS)
tstate |= (psr & PSR_XCC) << 20;
- store_unsigned_integer (buf, 8, tstate);
+ store_unsigned_integer (buf, 8, byte_order, tstate);
memcpy (regs + offset, buf, 8);
}
if (regnum == SPARC32_PC_REGNUM || regnum == -1)
- regcache_raw_collect (regcache, SPARC32_PC_REGNUM,
- regs + gregset->r_pc_offset + 4);
+ regcache->raw_collect (SPARC32_PC_REGNUM,
+ regs + gregmap->r_pc_offset + 4);
if (regnum == SPARC32_NPC_REGNUM || regnum == -1)
- regcache_raw_collect (regcache, SPARC32_NPC_REGNUM,
- regs + gregset->r_npc_offset + 4);
+ regcache->raw_collect (SPARC32_NPC_REGNUM,
+ regs + gregmap->r_npc_offset + 4);
if (regnum == SPARC32_Y_REGNUM || regnum == -1)
{
- int offset = gregset->r_y_offset + 8 - gregset->r_y_size;
- regcache_raw_collect (regcache, SPARC32_Y_REGNUM, regs + offset);
+ int offset = gregmap->r_y_offset + 8 - gregmap->r_y_size;
+ regcache->raw_collect (SPARC32_Y_REGNUM, regs + offset);
}
}
else
{
if (regnum == SPARC64_STATE_REGNUM || regnum == -1)
- regcache_raw_collect (regcache, SPARC64_STATE_REGNUM,
- regs + gregset->r_tstate_offset);
+ regcache->raw_collect (SPARC64_STATE_REGNUM,
+ regs + gregmap->r_tstate_offset);
if (regnum == SPARC64_PC_REGNUM || regnum == -1)
- regcache_raw_collect (regcache, SPARC64_PC_REGNUM,
- regs + gregset->r_pc_offset);
+ regcache->raw_collect (SPARC64_PC_REGNUM,
+ regs + gregmap->r_pc_offset);
if (regnum == SPARC64_NPC_REGNUM || regnum == -1)
- regcache_raw_collect (regcache, SPARC64_NPC_REGNUM,
- regs + gregset->r_npc_offset);
+ regcache->raw_collect (SPARC64_NPC_REGNUM,
+ regs + gregmap->r_npc_offset);
if (regnum == SPARC64_Y_REGNUM || regnum == -1)
{
- char buf[8];
+ gdb_byte buf[8];
- regcache_raw_collect (regcache, SPARC64_Y_REGNUM, buf);
- memcpy (regs + gregset->r_y_offset,
- buf + 8 - gregset->r_y_size, gregset->r_y_size);
+ regcache->raw_collect (SPARC64_Y_REGNUM, buf);
+ memcpy (regs + gregmap->r_y_offset,
+ buf + 8 - gregmap->r_y_size, gregmap->r_y_size);
}
if ((regnum == SPARC64_FPRS_REGNUM || regnum == -1)
- && gregset->r_fprs_offset != -1)
- regcache_raw_collect (regcache, SPARC64_FPRS_REGNUM,
- regs + gregset->r_fprs_offset);
+ && gregmap->r_fprs_offset != -1)
+ regcache->raw_collect (SPARC64_FPRS_REGNUM,
+ regs + gregmap->r_fprs_offset);
}
if ((regnum >= SPARC_G1_REGNUM && regnum <= SPARC_O7_REGNUM) || regnum == -1)
{
- int offset = gregset->r_g1_offset;
+ int offset = gregmap->r_g1_offset;
if (sparc32)
offset += 4;
@@ -1325,7 +2077,7 @@ sparc64_collect_gregset (const struct sparc_gregset *gregset,
for (i = SPARC_G1_REGNUM; i <= SPARC_O7_REGNUM; i++)
{
if (regnum == i || regnum == -1)
- regcache_raw_collect (regcache, i, regs + offset);
+ regcache->raw_collect (i, regs + offset);
offset += 8;
}
}
@@ -1334,9 +2086,9 @@ sparc64_collect_gregset (const struct sparc_gregset *gregset,
{
/* Not all of the register set variants include Locals and
Inputs. For those that don't, we read them off the stack. */
- if (gregset->r_l0_offset != -1)
+ if (gregmap->r_l0_offset != -1)
{
- int offset = gregset->r_l0_offset;
+ int offset = gregmap->r_l0_offset;
if (sparc32)
offset += 4;
@@ -1344,7 +2096,7 @@ sparc64_collect_gregset (const struct sparc_gregset *gregset,
for (i = SPARC_L0_REGNUM; i <= SPARC_I7_REGNUM; i++)
{
if (regnum == i || regnum == -1)
- regcache_raw_collect (regcache, i, regs + offset);
+ regcache->raw_collect (i, regs + offset);
offset += 8;
}
}
@@ -1352,71 +2104,83 @@ sparc64_collect_gregset (const struct sparc_gregset *gregset,
}
void
-sparc64_supply_fpregset (struct regcache *regcache,
+sparc64_supply_fpregset (const struct sparc_fpregmap *fpregmap,
+ struct regcache *regcache,
int regnum, const void *fpregs)
{
- int sparc32 = (gdbarch_ptr_bit (current_gdbarch) == 32);
- const char *regs = fpregs;
+ int sparc32 = (gdbarch_ptr_bit (regcache->arch ()) == 32);
+ const gdb_byte *regs = (const gdb_byte *) fpregs;
int i;
for (i = 0; i < 32; i++)
{
if (regnum == (SPARC_F0_REGNUM + i) || regnum == -1)
- regcache_raw_supply (regcache, SPARC_F0_REGNUM + i, regs + (i * 4));
+ regcache->raw_supply (SPARC_F0_REGNUM + i,
+ regs + fpregmap->r_f0_offset + (i * 4));
}
if (sparc32)
{
if (regnum == SPARC32_FSR_REGNUM || regnum == -1)
- regcache_raw_supply (regcache, SPARC32_FSR_REGNUM,
- regs + (32 * 4) + (16 * 8) + 4);
+ regcache->raw_supply (SPARC32_FSR_REGNUM,
+ regs + fpregmap->r_fsr_offset);
}
else
{
for (i = 0; i < 16; i++)
{
if (regnum == (SPARC64_F32_REGNUM + i) || regnum == -1)
- regcache_raw_supply (regcache, SPARC64_F32_REGNUM + i,
- regs + (32 * 4) + (i * 8));
+ regcache->raw_supply
+ (SPARC64_F32_REGNUM + i,
+ regs + fpregmap->r_f0_offset + (32 * 4) + (i * 8));
}
if (regnum == SPARC64_FSR_REGNUM || regnum == -1)
- regcache_raw_supply (regcache, SPARC64_FSR_REGNUM,
- regs + (32 * 4) + (16 * 8));
+ regcache->raw_supply (SPARC64_FSR_REGNUM,
+ regs + fpregmap->r_fsr_offset);
}
}
void
-sparc64_collect_fpregset (const struct regcache *regcache,
+sparc64_collect_fpregset (const struct sparc_fpregmap *fpregmap,
+ const struct regcache *regcache,
int regnum, void *fpregs)
{
- int sparc32 = (gdbarch_ptr_bit (current_gdbarch) == 32);
- char *regs = fpregs;
+ int sparc32 = (gdbarch_ptr_bit (regcache->arch ()) == 32);
+ gdb_byte *regs = (gdb_byte *) fpregs;
int i;
for (i = 0; i < 32; i++)
{
if (regnum == (SPARC_F0_REGNUM + i) || regnum == -1)
- regcache_raw_collect (regcache, SPARC_F0_REGNUM + i, regs + (i * 4));
+ regcache->raw_collect (SPARC_F0_REGNUM + i,
+ regs + fpregmap->r_f0_offset + (i * 4));
}
if (sparc32)
{
if (regnum == SPARC32_FSR_REGNUM || regnum == -1)
- regcache_raw_collect (regcache, SPARC32_FSR_REGNUM,
- regs + (32 * 4) + (16 * 8) + 4);
+ regcache->raw_collect (SPARC32_FSR_REGNUM,
+ regs + fpregmap->r_fsr_offset);
}
else
{
for (i = 0; i < 16; i++)
{
if (regnum == (SPARC64_F32_REGNUM + i) || regnum == -1)
- regcache_raw_collect (regcache, SPARC64_F32_REGNUM + i,
- regs + (32 * 4) + (i * 8));
+ regcache->raw_collect (SPARC64_F32_REGNUM + i,
+ (regs + fpregmap->r_f0_offset
+ + (32 * 4) + (i * 8)));
}
if (regnum == SPARC64_FSR_REGNUM || regnum == -1)
- regcache_raw_collect (regcache, SPARC64_FSR_REGNUM,
- regs + (32 * 4) + (16 * 8));
+ regcache->raw_collect (SPARC64_FSR_REGNUM,
+ regs + fpregmap->r_fsr_offset);
}
}
+
+const struct sparc_fpregmap sparc64_bsd_fpregmap =
+{
+ 0 * 8, /* %f0 */
+ 32 * 8, /* %fsr */
+};