Patchwork [v2] gdb: ADI support

login
register
mail settings
Submitter Weimin Pan
Date June 16, 2017, 11:30 p.m.
Message ID <1497655802-111684-1-git-send-email-weimin.pan@oracle.com>
Download mbox | patch
Permalink /patch/21060/
State New
Headers show

Comments

Weimin Pan - June 16, 2017, 11:30 p.m.
The M7 processor supports an Application Data Integrity (ADI) feature
   that detects invalid data accesses.  When software allocates data, 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.

   This patch adds ADI support in gdb which allows the user to examine
   current version tags and assign new version tags in the program.
   It also catches and reports precise or disrupting memory corruption
   traps.

Tested in sparc64-linux-gnu. No regressions.

gdb/ChangeLog:
2017-06-16  Weimin Pan  <weimin.pan@oracle.com>

	* sparc64-tdep.h: (adi_normalize_address): New export.
	* sparc64-adi-tdep.c: New file.
	* Makefile.in (ALLDEPFILES): Add sparc64-adi-tdep.c.
	* configure.tgt: Add sparc64-adi-tdep.o.
	* sparc64-linux-nat.c:
	(sparc64_linux_watchpoint_addr_within_range): New function.
	(_initialize_sparc64_linux_nat): Register sparc64_linux_watchpoint_addr_within_range.
	* sparc64-linux-tdep.c: Include <adi.h>.
	(sparc64_linux_handle_segmentation_fault): New function.
	(sparc64_linux_init_abi): Register sparc64_linux_handle_segmentation_fault
	* sparc64-tdep.c: (sparc64_pstate_type): Replace PID1 with MCDE.
gdb/doc/ChangeLog:
2017-06-16  Weimin Pan  <weimin.pan@oracle.com>
	* gdb.texinfo (Architectures): Add new Sparc64 section to document ADI support.
---
 gdb/ChangeLog            |   14 ++
 gdb/Makefile.in          |    2 +
 gdb/configure.tgt        |    1 +
 gdb/doc/ChangeLog        |    4 +
 gdb/doc/gdb.texinfo      |   85 +++++++++
 gdb/sparc64-adi-tdep.c   |  460 ++++++++++++++++++++++++++++++++++++++++++++++
 gdb/sparc64-linux-nat.c  |   15 ++
 gdb/sparc64-linux-tdep.c |   49 +++++
 gdb/sparc64-tdep.c       |    2 +-
 gdb/sparc64-tdep.h       |    2 +
 10 files changed, 633 insertions(+), 1 deletions(-)
 create mode 100644 gdb/sparc64-adi-tdep.c
Yao Qi - June 20, 2017, 1:35 p.m.
Weimin Pan <weimin.pan@oracle.com> writes:

>
> Tested in sparc64-linux-gnu. No regressions.
>

Could you build a cross gdb with your patch applied?  That is, host and
build is x86_64-linux and target is sparc64-linux, for example.

> gdb/ChangeLog:
> 2017-06-16  Weimin Pan  <weimin.pan@oracle.com>
>
> 	* sparc64-tdep.h: (adi_normalize_address): New export.
> 	* sparc64-adi-tdep.c: New file.
> 	* Makefile.in (ALLDEPFILES): Add sparc64-adi-tdep.c.
> 	* configure.tgt: Add sparc64-adi-tdep.o.
> 	* sparc64-linux-nat.c:
> 	(sparc64_linux_watchpoint_addr_within_range): New function.
> 	(_initialize_sparc64_linux_nat): Register sparc64_linux_watchpoint_addr_within_range.

This line is too long.
See https://sourceware.org/gdb/wiki/ContributionChecklist#Properly_Formatted_GNU_ChangeLog
> 	* sparc64-linux-tdep.c: Include <adi.h>.
> 	(sparc64_linux_handle_segmentation_fault): New function.
> 	(sparc64_linux_init_abi): Register sparc64_linux_handle_segmentation_fault

Likewise.

> 	* sparc64-tdep.c: (sparc64_pstate_type): Replace PID1 with MCDE.
> gdb/doc/ChangeLog:
> 2017-06-16  Weimin Pan  <weimin.pan@oracle.com>
> 	* gdb.texinfo (Architectures): Add new Sparc64 section to document ADI support.
> ---
>  gdb/ChangeLog            |   14 ++
>  gdb/Makefile.in          |    2 +
>  gdb/configure.tgt        |    1 +
>  gdb/doc/ChangeLog        |    4 +
>  gdb/doc/gdb.texinfo      |   85 +++++++++
>  gdb/sparc64-adi-tdep.c   |  460 ++++++++++++++++++++++++++++++++++++++++++++++
>  gdb/sparc64-linux-nat.c  |   15 ++
>  gdb/sparc64-linux-tdep.c |   49 +++++
>  gdb/sparc64-tdep.c       |    2 +-
>  gdb/sparc64-tdep.h       |    2 +
>  10 files changed, 633 insertions(+), 1 deletions(-)
>  create mode 100644 gdb/sparc64-adi-tdep.c
>
> diff --git a/gdb/ChangeLog b/gdb/ChangeLog
> index 5ebc7f8..8126a47 100644
> --- a/gdb/ChangeLog
> +++ b/gdb/ChangeLog
> @@ -1,3 +1,17 @@
> +2017-06-16  Weimin Pan  <weimin.pan@oracle.com>
> +
> +	* sparc64-tdep.h: (adi_normalize_address): New export.
> +	* sparc64-adi-tdep.c: New file.
> +	* Makefile.in (ALLDEPFILES): Add sparc64-adi-tdep.c.
> +	* configure.tgt: Add sparc64-adi-tdep.o.
> +	* sparc64-linux-nat.c: 
> +	(sparc64_linux_watchpoint_addr_within_range): New function.
> +	(_initialize_sparc64_linux_nat): Register sparc64_linux_watchpoint_addr_within_range.
> +	* sparc64-linux-tdep.c: Include <adi.h>. 
> +	(sparc64_linux_handle_segmentation_fault): New function.
> +	(sparc64_linux_init_abi): Register sparc64_linux_handle_segmentation_fault
> +	* sparc64-tdep.c: (sparc64_pstate_type): Replace PID1 with MCDE.
> +
>  2017-06-08  Sergio Durigan Junior  <sergiodj@redhat.com>
>  
>  	* common/common-utils.c (stringify_argv): Check for "arg[0] !=
> diff --git a/gdb/Makefile.in b/gdb/Makefile.in
> index 5e5fcaa..a6b0d99 100644
> --- a/gdb/Makefile.in
> +++ b/gdb/Makefile.in
> @@ -772,6 +772,7 @@ ALL_64_TARGET_OBS = \
>  	ia64-tdep.o \
>  	ia64-vms-tdep.o \
>  	mips64-obsd-tdep.o \
> +	sparc64-adi-tdep.o \
>  	sparc64-fbsd-tdep.o \
>  	sparc64-linux-tdep.o \
>  	sparc64-nbsd-tdep.o \
> @@ -2660,6 +2661,7 @@ ALLDEPFILES = \
>  	sparc-sol2-nat.c \
>  	sparc-sol2-tdep.c \
>  	sparc-tdep.c \
> +	sparc64-adi-tdep.c \
>  	sparc64-fbsd-nat.c \
>  	sparc64-fbsd-tdep.c \
>  	sparc64-linux-nat.c \
> diff --git a/gdb/configure.tgt b/gdb/configure.tgt
> index fdcb7b1..0519c62 100644
> --- a/gdb/configure.tgt
> +++ b/gdb/configure.tgt
> @@ -548,6 +548,7 @@ sparc64-*-linux*)
>  	gdb_target_obs="sparc64-tdep.o sparc64-sol2-tdep.o sol2-tdep.o \
>  			sparc64-linux-tdep.o sparc-tdep.o sparc-sol2-tdep.o \
>  			sparc-linux-tdep.o solib-svr4.o linux-tdep.o \
> +			sparc64-adi-tdep.o \
>  			ravenscar-thread.o sparc-ravenscar-thread.o"
>  	build_gdbserver=yes
>  	;;
> diff --git a/gdb/doc/ChangeLog b/gdb/doc/ChangeLog
> index 868cde9..a411d64 100644
> --- a/gdb/doc/ChangeLog
> +++ b/gdb/doc/ChangeLog
> @@ -1,3 +1,7 @@
> +2017-06-16  Weimin Pan  <weimin.pan@oracle.com>
> +	* gdb.texinfo (Architectures): Add new Sparc64 section to document ADI support.
> +	* NEWS: Add "adi examine" and "adi assign" commands.
> +
>  2017-06-07  Sergio Durigan Junior  <sergiodj@redhat.com>
>  
>  	* gdb.texinfo (Starting) <startup-with-shell>: Add @anchor.
> diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
> index 8d7a1c9..843c1bf 100644
> --- a/gdb/doc/gdb.texinfo
> +++ b/gdb/doc/gdb.texinfo
> @@ -22465,6 +22465,7 @@ all uses of @value{GDBN} with the architecture, both native and cross.
>  * SPU::                Cell Broadband Engine SPU architecture
>  * PowerPC::
>  * Nios II::
> +* Sparc64::
>  @end menu
>  
>  @node AArch64
> @@ -22849,6 +22850,90 @@ target code in @value{GDBN}.
>  Show the current setting of Nios II debugging messages.
>  @end table
>  
> +@node Sparc64
> +@subsection Sparc64
> +@cindex Sparc64 support
> +@cindex Application Data Integrity
> +@subsubsection ADI Support
> +
> +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 that data.  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.
> +
> +Note that only 64-bit applications can use ADI and need to be built with
> +ADI-enabled.
> +
> +Values of the ADI version tags, which are in granularity of a 
> +cacheline (64 bytes), can be viewed or modified. 
> +
> +
> +@table @code
> +@kindex adi examine
> +@item adi examine
> +
> +The @code{adi examine} command displays the value of one ADI version tag per 
> +cacheline.  It has the following command syntax: 
> +
> +@table @code
> +@itemx adi (examine | x) [ / @var{n} ] @var{addr}
> +@end table
> +
> +@var{n}, the byte count
> +The count is a decimal integer specifying the number in bytes; the default 
> +is 1.  It specifies how much ADI version information, at the ratio of 1:ADI 
> +block size, to display. 
> +
> +@var{addr}, starting display address
> +@var{addr} is the address in user address space where you want @value{GDBN} 
> +to begin displaying the ADI version tags. 
> +
> +Below is an example of displaying ADI versions of variable "shmaddr".
> +
> +@smallexample
> +(@value{GDBP}) adi x/100 shmaddr
> +   0xfff800010002c000:     0 0
> +@end smallexample
> +
> +@kindex adi assign
> +@item adi assign
> +
> +The @code{adi assign} command is used to assign new ADI version tag 
> +to an address.  It has the following command syntax:
> +
> +@table @code
> +@itemx adi (assign | a) [ / @var{n} ] @var{addr} = @var{tag}
> +@end table
> +
> +@var{n}, the byte count
> +The count is a decimal integer specifying the number in bytes; the default 
> +is 1.  It specifies how much ADI version information, at the ratio of 1:ADI 
> +block size, to modify. 
> +
> +@var{addr}, starting display address
> +@var{addr} is the address in user address space where you want @value{GDBN} 
> +to begin modifying the ADI version tags. 
> +
> +@var{tag}, the new ADI version tag
> +
> +For example, do the following to modify then verify ADI versions of 
> +variable "shmaddr":
> +
> +@smallexample
> +(@value{GDBP}) adi a/100 shmaddr = 7
> +(@value{GDBP}) adi x/100 shmaddr
> +   0xfff800010002c000:     7 7
> +@end smallexample
> +
> +@end table
> +
>  @node Controlling GDB
>  @chapter Controlling @value{GDBN}
>  
> diff --git a/gdb/sparc64-adi-tdep.c b/gdb/sparc64-adi-tdep.c
> new file mode 100644
> index 0000000..9c9d0ae
> --- /dev/null
> +++ b/gdb/sparc64-adi-tdep.c
> @@ -0,0 +1,460 @@
> +/* Target-dependent code for Sparc64.

The new file sparc64-adi-tdep.c should be merged into the existing
sparc64-tdep.c.  The file name schema in GDB is ARCH-OSABI-tdep.c.
Since adi is a new hardware feature rather than an OSABI, it should be
put in sparc64-tdep.c

> +
> +   Copyright (C) 2017 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 <http://www.gnu.org/licenses/>.  */
> +
> +#include <adi.h>

I am afraid this will break the gdb cross build.

> +#include "defs.h"
> +#include "inferior.h"
> +#include "gdbcmd.h"
> +#include "auxv.h"
> +
> +/* 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. */

due to lack of hardware support or kernel support?  I ask this because
it is related to my comment to the following function arch_is_64bit.

> +
> +
> +#define MAX_PROC_NAME_SIZE sizeof("/proc/99999/lwp/9999/adi/lstatus")
> +
> +/* ADI command list.  */
> +static struct cmd_list_element *sparc64adilist = NULL;
> +
> +/* Current ADI stat settings.  */
> +static 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;
> +
> +  /* Last ADI address examined.  */
> +  CORE_ADDR last_vaddr;
> +
> +  /* Last specified examination count.  */
> +  int last_cnt;
> +
> +  /* ADI availability check has been done.  */
> +  bool checked_avail;
> +
> +  /* ADI is available.  */
> +  bool is_avail;
> +
> +} adi_stat;

It is a global data, but as I read the rest of the patch, looks like adi
data should be per-process.

> +
> +
> +static void
> +info_adi_command (char *args, int from_tty)
> +{
> +  printf_unfiltered ("\"adi\" must be followed by \"examine\" "
> +                     "or \"assign\".\n");
> +  help_list (sparc64adilist, "adi ", all_commands, gdb_stdout);
> +}
> +
> +static bool
> +arch_is_64bit (void)
> +{
> +  struct gdbarch *gdbarch = get_frame_arch (get_current_frame ());
> +  return gdbarch_bfd_arch_info (gdbarch)->bits_per_word == 64;
> +
> +}
> +
> +static int
> +parse_byte_count (const char **sptr)
> +{
> +  const char *p = *sptr;
> +  int cnt = 1;
> +  if (*p == '-')
> +    {
> +      cnt = -1;
> +      p++;
> +    }
> +  if (*p >= '0' && *p <= '9')
> +    cnt *= atoi (p);
> +  while (*p >= '0' && *p <= '9')
> +    p++;
> +  while (*p == ' ' || *p == '\t')
> +    p++;
> +  *sptr = p;
> +
> +  if (cnt <= 0)
> +    error (_("Byte count should have a positive value."));
> +
> +  return cnt;
> +}

You can use get_number or other apis declared in in gdb/cli-utils.h.

> +
> +/* 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)
> +{
> +  if (adi_stat.checked_avail)
> +    return adi_stat.is_avail;
> +
> +  adi_stat.checked_avail = true;
> +  if (!arch_is_64bit ())
> +    return false;
> +  if (target_auxv_search (&current_target, AT_ADI_BLKSZ, &adi_stat.blksize) <= 0)

If kernel doesn't support ADI for 32-bit application, why don't we fetch
AT_ADI_BLKSZ unconditionally?

> +    return false;
> +  target_auxv_search (&current_target, AT_ADI_NBITS, &adi_stat.nbits);
> +  adi_stat.max_version = (1 << adi_stat.nbits) - 2;
> +  adi_stat.is_avail = true;
> +
> +  return adi_stat.is_avail;
> +}
> +
> +#if 0
> +/* Extract version tag from a versioned address.  */
> +
> +int adi_extract_version (CORE_ADDR versioned_addr)
> +{
> +  return ((unsigned long)versioned_addr) >> (64 - adi_stat.nbits);
> +}
> +#endif
> +
> +/* Normalize a versioned address - a VA with ADI bits (63-60) set.  */
> +
> +CORE_ADDR
> +adi_normalize_address (CORE_ADDR addr)
> +{
> +  if (adi_stat.nbits)
> +    return ((CORE_ADDR)(((long)addr << adi_stat.nbits) >> adi_stat.nbits));
> +  return addr;
> +}

I think the right approach is to implement gdbarch_addr_bits_remove for
sparc64-linux, which remove these unused bits.

> +
> +/* Align a normalized address - a VA with bit 59 sign extended into ADI bits.  */
> +
> +static CORE_ADDR
> +adi_align_address (CORE_ADDR naddr)
> +{
> +    return (naddr - (naddr % adi_stat.blksize)) / adi_stat.blksize;

Indentation is wrong.  

> +}
> +
> +/* 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)
> +{
> +    return ((naddr + nbytes + adi_stat.blksize - 1) / adi_stat.blksize) - locl;

This line is too long.

> +}
> +
> +/* The /proc/[pid]/adi/tag 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)
> +{
> +  if (adi_stat.tag_fd != 0)
> +    return adi_stat.tag_fd;
> +
> +  char cl_name[MAX_PROC_NAME_SIZE];
> +  pid_t pid = ptid_get_pid (inferior_ptid);
> +  snprintf (cl_name, sizeof(cl_name), "/proc/%d/adi/tag", pid);
> +  adi_stat.tag_fd = open (cl_name, O_RDWR|O_EXCL|O_CLOEXEC);

You can't access /proc in *-tdep.c file, because it is also compiled for
cross-debugger.  The rule in general is to move it to sparc64-linux-nat.c.

> +
> +  return adi_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 = ptid_get_pid (inferior_ptid);
> +  snprintf (filename, sizeof filename, "/proc/%d/adi/maps", pid);
> +  char *data = target_fileio_read_stralloc (NULL, filename);

It is better to define adi as a qXfer object, which can be read and
written through target layer.

> +  if (data)
> +    {
> +      struct cleanup *cleanup = make_cleanup (xfree, data);
> +      char *line;
> +      for (line = strtok (data, "\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)
> +                {
> +                  do_cleanups (cleanup);
> +                  return true;
> +                }
> +            }
> +        }
> +        do_cleanups (cleanup);
> +      }
> +    else
> +      warning (_("unable to open /proc file '%s'"), filename);
> +
> +  return false;
> +}
> +

> +
> +/* 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, unsigned char *tags)
> +{
> +  int v_idx = 0;
> +  const int maxelts = 8;  /* # of elements per line */
> +
> +  while (cnt > 0)
> +    {
> +      QUIT;
> +      printf_filtered ("0x%016lx:\t", 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]);
> +          ++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);
> +  struct cleanup *cleanup;
> +
> +  CORE_ADDR vstart = adi_align_address (vaddr);
> +  int cnt = adi_convert_byte_count (vaddr, bcnt, vstart);
> +  unsigned char *buf = (unsigned char *) xmalloc (cnt);
> +  cleanup = make_cleanup (xfree, buf);
> +  int read_cnt = adi_read_versions (vstart, cnt, buf);
> +  if (read_cnt == -1)
> +    error (_("No ADI information"));
> +  else if (read_cnt < cnt)
> +    error(_("No ADI information at 0x%lx"), vaddr);
> +
> +  adi_print_versions(vstart, cnt, buf);
> +
> +  do_cleanups (cleanup);
> +}
> +
> +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);
> +  unsigned char *buf = (unsigned char *) xmalloc (cnt);
> +  memset(buf, version, cnt);
> +
> +  int set_cnt = adi_write_versions (vstart, cnt, buf);
> +  xfree (buf);
> +
> +  if (set_cnt == -1)
> +    error (_("No ADI information"));
> +  else if (set_cnt < cnt)
> +    error(_("No ADI information at 0x%lx"), vaddr);
> +
> +}
> +
> +/* ADI examine version tag command.
> +
> +   Command syntax:
> +
> +     adi (examine|x)/count <addr> */
> +
> +static void
> +adi_examine_command (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 = adi_stat.last_cnt? adi_stat.last_cnt : 1;
> +  const char *p = args;
> +  if (p && *p == '/')
> +    {
> +      p++;
> +      cnt = parse_byte_count (&p);
> +    }
> +
> +  CORE_ADDR next_address = adi_stat.last_vaddr ? adi_stat.last_vaddr : 0;
> +  if (p != 0 && *p != 0)
> +    next_address = parse_and_eval_address (p);
> +  else if (!adi_stat.last_cnt)
> +    error (_("Usage: adi examine|x[/count] <addr>"));
> +
> +  if (next_address)
> +    do_examine(next_address, cnt);
> +
> +  adi_stat.last_cnt = cnt;
> +  adi_stat.last_vaddr = next_address + adi_stat.blksize * cnt;
> +}
> +
> +/* ADI assign version tag command.
> +
> +   Command syntax:
> +
> +     adi (assign|a)/count <addr> = <version>  */
> +
> +static void
> +adi_assign_command (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"));
> +
> +  const char *exp = args;
> +  if (exp == 0)
> +    error_no_arg (_("Usage: adi assign|a[/count] <addr> = <version>"));
> +
> +  char *q = (char *) strchr (exp, '=');
> +  if (q)
> +    *q++ = 0;
> +  else
> +    error (_("Usage: adi assign|a[/count] <addr> = <version>"));
> +
> +  size_t cnt = 1;
> +  const char *p = exp;
> +  if (exp && *exp == '/')
> +    {
> +      p = exp + 1;
> +      cnt = parse_byte_count (&p);
> +    }
> +
> +  CORE_ADDR next_address = 0;
> +  if (p != 0 && *p != 0)
> +    next_address = parse_and_eval_address (p);
> +  else
> +    error (_("Usage: adi assign|a[/count] <addr> = <version>"));
> +
> +  int version = 0;
> +  if (q)           /* parse version tag */
> +    {
> +      version = parse_and_eval_long (q);
> +      if (version < 0 || version > adi_stat.max_version)
> +        error (_("Invalid ADI version tag %d"), version);
> +    }
> +
> +  do_assign(next_address, cnt, version);
> +}
> +
> +extern initialize_file_ftype _initialize_sparc64_adi_tdep; /* -Wmissing-prototypes */
> +

This line is not needed.

> +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);
> +
> +}
> +
> diff --git a/gdb/sparc64-linux-nat.c b/gdb/sparc64-linux-nat.c
> index 638aa29..01adcd6 100644
> --- a/gdb/sparc64-linux-nat.c
> +++ b/gdb/sparc64-linux-nat.c
> @@ -69,6 +69,18 @@ fill_fpregset (const struct regcache *regcache,
>    sparc64_collect_fpregset (&sparc64_bsd_fpregmap, regcache, regnum, fpregs);
>  }
>  
> +/* Implement the "to_watchpoint_addr_within_range" target_ops method.  */
> +
> +static int
> +sparc64_linux_watchpoint_addr_within_range (struct target_ops *target,
> +					    CORE_ADDR addr,
> +					    CORE_ADDR start, int length)
> +{
> +  start = adi_normalize_address (start);
> +  addr = adi_normalize_address (addr);
> +  return (start <= addr) && (start + length - 1 >= addr);

I suppose once you implement gdbarch_addr_bits_remove, you don't need
this change.

> +}
> +
>  /* Provide a prototype to silence -Wmissing-prototypes.  */
>  void _initialize_sparc64_linux_nat (void);
>  
> @@ -86,6 +98,9 @@ _initialize_sparc64_linux_nat (void)
>    t->to_fetch_registers = sparc_fetch_inferior_registers;
>    t->to_store_registers = sparc_store_inferior_registers;
>  
> +  t->to_watchpoint_addr_within_range =
> +    sparc64_linux_watchpoint_addr_within_range;
> +
>    /* Register the target.  */
>    linux_nat_add_target (t);
>  
> diff --git a/gdb/sparc64-linux-tdep.c b/gdb/sparc64-linux-tdep.c
> index 814bc29..17eb8c5 100644
> --- a/gdb/sparc64-linux-tdep.c
> +++ b/gdb/sparc64-linux-tdep.c
> @@ -32,6 +32,7 @@
>  #include "tramp-frame.h"
>  #include "xml-syscall.h"
>  #include "linux-tdep.h"
> +#include <adi.h>
>  
>  /* The syscall's XML filename for sparc 64-bit.  */
>  #define XML_SYSCALL_FILENAME_SPARC64 "syscalls/sparc64-linux.xml"
> @@ -104,6 +105,52 @@ sparc64_linux_sigframe_init (const struct tramp_frame *self,
>      }
>    trad_frame_set_id (this_cache, frame_id_build (base, func));
>  }
> +
> +/* sparc64 GNU/Linux implementation of the handle_segmentation_fault
> +   gdbarch hook.
> +   Displays information related to ADI memory corruptions.  */
> +
> +void
> +sparc64_linux_handle_segmentation_fault (struct gdbarch *gdbarch,
> +				      struct ui_out *uiout)
> +{
> +  if (gdbarch_bfd_arch_info (gdbarch)->bits_per_word != 64)
> +    return;
> +

Do you need to return if some sparc64 processor doesn't have adi?

> +  CORE_ADDR addr = 0;
> +  long si_code = 0;
> +
> +  TRY
> +    {
> +      /* Evaluate si_code to see if the segfault is ADI related.  */
> +      si_code = parse_and_eval_long ("$_siginfo.si_code\n");
> +
> +      if (si_code >= SEGV_ACCADI && si_code <= SEGV_ADIPERR)
> +        addr = parse_and_eval_long ("$_siginfo._sifields._sigfault.si_addr");
> +    }
> +  CATCH (exception, RETURN_MASK_ALL)
> +    {
> +      return;
> +    }
> +  END_CATCH
> +
> +  /* Print out ADI event based on sig_code value */
> +  switch (si_code)
> +    {
> +    case SEGV_ACCADI:	/* adi not enabled */
> +      printf_unfiltered (" (ADI disabled at address 0x%lx)\n", addr);
> +      break;
> +    case SEGV_ADIDERR:	/* disrupting mismatch */
> +      printf_unfiltered (" (ADI deferred mismatch at address 0x%lx)\n", addr);
> +      break;
> +    case SEGV_ADIPERR:	/* precise mismatch */
> +      printf_unfiltered (" (ADI precise mismatch at address
> 0x%lx)\n", addr);

Use uiout instead print_unfiltered.  See i386_linux_handle_segmentation_fault.


> +      break;
> +    default:
> +      break;
> +    }
> +}
> +
>  
>  /* Return the address of a system call's alternative return
>     address.  */
> @@ -338,6 +385,8 @@ sparc64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
>    set_xml_syscall_file_name (gdbarch, XML_SYSCALL_FILENAME_SPARC64);
>    set_gdbarch_get_syscall_number (gdbarch,
>                                    sparc64_linux_get_syscall_number);
> +  set_gdbarch_handle_segmentation_fault (gdbarch,
> +					 sparc64_linux_handle_segmentation_fault);
>  }
>  
>  
> diff --git a/gdb/sparc64-tdep.c b/gdb/sparc64-tdep.c
> index 9e0e6b5..e8c5a63 100644
> --- a/gdb/sparc64-tdep.c
> +++ b/gdb/sparc64-tdep.c
> @@ -165,7 +165,7 @@ sparc64_pstate_type (struct gdbarch *gdbarch)
>        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");
> +      append_flags_type_flag (type, 11, "MCDE");
>  

Why do you do this change?
Weimin Pan - June 20, 2017, 5:50 p.m.
Yao Qi wrote:
> Weimin Pan <weimin.pan@oracle.com> writes:
>
>   
>> Tested in sparc64-linux-gnu. No regressions.
>>
>>     
>
> Could you build a cross gdb with your patch applied?  That is, host and
> build is x86_64-linux and target is sparc64-linux, for example.
>   
OK, will do the cross build and address your concern of  <adi.h> likely 
breaking it as you commented below.
>> gdb/ChangeLog:
>> 2017-06-16  Weimin Pan  <weimin.pan@oracle.com>
>>
>> 	* sparc64-tdep.h: (adi_normalize_address): New export.
>> 	* sparc64-adi-tdep.c: New file.
>> 	* Makefile.in (ALLDEPFILES): Add sparc64-adi-tdep.c.
>> 	* configure.tgt: Add sparc64-adi-tdep.o.
>> 	* sparc64-linux-nat.c:
>> 	(sparc64_linux_watchpoint_addr_within_range): New function.
>> 	(_initialize_sparc64_linux_nat): Register sparc64_linux_watchpoint_addr_within_range.
>>     
>
> This line is too long.
> See https://sourceware.org/gdb/wiki/ContributionChecklist#Properly_Formatted_GNU_ChangeLog
>   

Will split it.

>> 	* sparc64-linux-tdep.c: Include <adi.h>.
>> 	(sparc64_linux_handle_segmentation_fault): New function.
>> 	(sparc64_linux_init_abi): Register sparc64_linux_handle_segmentation_fault
>>     
>
> Likewise.
>   

OK.
>   
>> 	* sparc64-tdep.c: (sparc64_pstate_type): Replace PID1 with MCDE.
>> gdb/doc/ChangeLog:
>> 2017-06-16  Weimin Pan  <weimin.pan@oracle.com>
>> 	* gdb.texinfo (Architectures): Add new Sparc64 section to document ADI support.
>> ---
>>  gdb/ChangeLog            |   14 ++
>>  gdb/Makefile.in          |    2 +
>>  gdb/configure.tgt        |    1 +
>>  gdb/doc/ChangeLog        |    4 +
>>  gdb/doc/gdb.texinfo      |   85 +++++++++
>>  gdb/sparc64-adi-tdep.c   |  460 ++++++++++++++++++++++++++++++++++++++++++++++
>>  gdb/sparc64-linux-nat.c  |   15 ++
>>  gdb/sparc64-linux-tdep.c |   49 +++++
>>  gdb/sparc64-tdep.c       |    2 +-
>>  gdb/sparc64-tdep.h       |    2 +
>>  10 files changed, 633 insertions(+), 1 deletions(-)
>>  create mode 100644 gdb/sparc64-adi-tdep.c
>>
>> diff --git a/gdb/ChangeLog b/gdb/ChangeLog
>> index 5ebc7f8..8126a47 100644
>> --- a/gdb/ChangeLog
>> +++ b/gdb/ChangeLog
>> @@ -1,3 +1,17 @@
>> +2017-06-16  Weimin Pan  <weimin.pan@oracle.com>
>> +
>> +	* sparc64-tdep.h: (adi_normalize_address): New export.
>> +	* sparc64-adi-tdep.c: New file.
>> +	* Makefile.in (ALLDEPFILES): Add sparc64-adi-tdep.c.
>> +	* configure.tgt: Add sparc64-adi-tdep.o.
>> +	* sparc64-linux-nat.c: 
>> +	(sparc64_linux_watchpoint_addr_within_range): New function.
>> +	(_initialize_sparc64_linux_nat): Register sparc64_linux_watchpoint_addr_within_range.
>> +	* sparc64-linux-tdep.c: Include <adi.h>. 
>> +	(sparc64_linux_handle_segmentation_fault): New function.
>> +	(sparc64_linux_init_abi): Register sparc64_linux_handle_segmentation_fault
>> +	* sparc64-tdep.c: (sparc64_pstate_type): Replace PID1 with MCDE.
>> +
>>  2017-06-08  Sergio Durigan Junior  <sergiodj@redhat.com>
>>  
>>  	* common/common-utils.c (stringify_argv): Check for "arg[0] !=
>> diff --git a/gdb/Makefile.in b/gdb/Makefile.in
>> index 5e5fcaa..a6b0d99 100644
>> --- a/gdb/Makefile.in
>> +++ b/gdb/Makefile.in
>> @@ -772,6 +772,7 @@ ALL_64_TARGET_OBS = \
>>  	ia64-tdep.o \
>>  	ia64-vms-tdep.o \
>>  	mips64-obsd-tdep.o \
>> +	sparc64-adi-tdep.o \
>>  	sparc64-fbsd-tdep.o \
>>  	sparc64-linux-tdep.o \
>>  	sparc64-nbsd-tdep.o \
>> @@ -2660,6 +2661,7 @@ ALLDEPFILES = \
>>  	sparc-sol2-nat.c \
>>  	sparc-sol2-tdep.c \
>>  	sparc-tdep.c \
>> +	sparc64-adi-tdep.c \
>>  	sparc64-fbsd-nat.c \
>>  	sparc64-fbsd-tdep.c \
>>  	sparc64-linux-nat.c \
>> diff --git a/gdb/configure.tgt b/gdb/configure.tgt
>> index fdcb7b1..0519c62 100644
>> --- a/gdb/configure.tgt
>> +++ b/gdb/configure.tgt
>> @@ -548,6 +548,7 @@ sparc64-*-linux*)
>>  	gdb_target_obs="sparc64-tdep.o sparc64-sol2-tdep.o sol2-tdep.o \
>>  			sparc64-linux-tdep.o sparc-tdep.o sparc-sol2-tdep.o \
>>  			sparc-linux-tdep.o solib-svr4.o linux-tdep.o \
>> +			sparc64-adi-tdep.o \
>>  			ravenscar-thread.o sparc-ravenscar-thread.o"
>>  	build_gdbserver=yes
>>  	;;
>> diff --git a/gdb/doc/ChangeLog b/gdb/doc/ChangeLog
>> index 868cde9..a411d64 100644
>> --- a/gdb/doc/ChangeLog
>> +++ b/gdb/doc/ChangeLog
>> @@ -1,3 +1,7 @@
>> +2017-06-16  Weimin Pan  <weimin.pan@oracle.com>
>> +	* gdb.texinfo (Architectures): Add new Sparc64 section to document ADI support.
>> +	* NEWS: Add "adi examine" and "adi assign" commands.
>> +
>>  2017-06-07  Sergio Durigan Junior  <sergiodj@redhat.com>
>>  
>>  	* gdb.texinfo (Starting) <startup-with-shell>: Add @anchor.
>> diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
>> index 8d7a1c9..843c1bf 100644
>> --- a/gdb/doc/gdb.texinfo
>> +++ b/gdb/doc/gdb.texinfo
>> @@ -22465,6 +22465,7 @@ all uses of @value{GDBN} with the architecture, both native and cross.
>>  * SPU::                Cell Broadband Engine SPU architecture
>>  * PowerPC::
>>  * Nios II::
>> +* Sparc64::
>>  @end menu
>>  
>>  @node AArch64
>> @@ -22849,6 +22850,90 @@ target code in @value{GDBN}.
>>  Show the current setting of Nios II debugging messages.
>>  @end table
>>  
>> +@node Sparc64
>> +@subsection Sparc64
>> +@cindex Sparc64 support
>> +@cindex Application Data Integrity
>> +@subsubsection ADI Support
>> +
>> +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 that data.  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.
>> +
>> +Note that only 64-bit applications can use ADI and need to be built with
>> +ADI-enabled.
>> +
>> +Values of the ADI version tags, which are in granularity of a 
>> +cacheline (64 bytes), can be viewed or modified. 
>> +
>> +
>> +@table @code
>> +@kindex adi examine
>> +@item adi examine
>> +
>> +The @code{adi examine} command displays the value of one ADI version tag per 
>> +cacheline.  It has the following command syntax: 
>> +
>> +@table @code
>> +@itemx adi (examine | x) [ / @var{n} ] @var{addr}
>> +@end table
>> +
>> +@var{n}, the byte count
>> +The count is a decimal integer specifying the number in bytes; the default 
>> +is 1.  It specifies how much ADI version information, at the ratio of 1:ADI 
>> +block size, to display. 
>> +
>> +@var{addr}, starting display address
>> +@var{addr} is the address in user address space where you want @value{GDBN} 
>> +to begin displaying the ADI version tags. 
>> +
>> +Below is an example of displaying ADI versions of variable "shmaddr".
>> +
>> +@smallexample
>> +(@value{GDBP}) adi x/100 shmaddr
>> +   0xfff800010002c000:     0 0
>> +@end smallexample
>> +
>> +@kindex adi assign
>> +@item adi assign
>> +
>> +The @code{adi assign} command is used to assign new ADI version tag 
>> +to an address.  It has the following command syntax:
>> +
>> +@table @code
>> +@itemx adi (assign | a) [ / @var{n} ] @var{addr} = @var{tag}
>> +@end table
>> +
>> +@var{n}, the byte count
>> +The count is a decimal integer specifying the number in bytes; the default 
>> +is 1.  It specifies how much ADI version information, at the ratio of 1:ADI 
>> +block size, to modify. 
>> +
>> +@var{addr}, starting display address
>> +@var{addr} is the address in user address space where you want @value{GDBN} 
>> +to begin modifying the ADI version tags. 
>> +
>> +@var{tag}, the new ADI version tag
>> +
>> +For example, do the following to modify then verify ADI versions of 
>> +variable "shmaddr":
>> +
>> +@smallexample
>> +(@value{GDBP}) adi a/100 shmaddr = 7
>> +(@value{GDBP}) adi x/100 shmaddr
>> +   0xfff800010002c000:     7 7
>> +@end smallexample
>> +
>> +@end table
>> +
>>  @node Controlling GDB
>>  @chapter Controlling @value{GDBN}
>>  
>> diff --git a/gdb/sparc64-adi-tdep.c b/gdb/sparc64-adi-tdep.c
>> new file mode 100644
>> index 0000000..9c9d0ae
>> --- /dev/null
>> +++ b/gdb/sparc64-adi-tdep.c
>> @@ -0,0 +1,460 @@
>> +/* Target-dependent code for Sparc64.
>>     
>
> The new file sparc64-adi-tdep.c should be merged into the existing
> sparc64-tdep.c.  The file name schema in GDB is ARCH-OSABI-tdep.c.
> Since adi is a new hardware feature rather than an OSABI, it should be
> put in sparc64-tdep.c
>   

Originally it was part of sparc64-tdep.c. But our engineer thought it's 
cleaner to make it a
separate source file. Being new to the gnu world, I believe following 
the file name schema
is the way to go. Thanks.

>> +
>> +   Copyright (C) 2017 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 <http://www.gnu.org/licenses/>.  */
>> +
>> +#include <adi.h>
>>     
>
> I am afraid this will break the gdb cross build.
>
>   
>> +#include "defs.h"
>> +#include "inferior.h"
>> +#include "gdbcmd.h"
>> +#include "auxv.h"
>> +
>> +/* 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. */
>>     
>
> due to lack of hardware support or kernel support?  I ask this because
> it is related to my comment to the following function arch_is_64bit.
>   
Yes.
>> +
>> +
>> +#define MAX_PROC_NAME_SIZE sizeof("/proc/99999/lwp/9999/adi/lstatus")
>> +
>> +/* ADI command list.  */
>> +static struct cmd_list_element *sparc64adilist = NULL;
>> +
>> +/* Current ADI stat settings.  */
>> +static 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;
>> +
>> +  /* Last ADI address examined.  */
>> +  CORE_ADDR last_vaddr;
>> +
>> +  /* Last specified examination count.  */
>> +  int last_cnt;
>> +
>> +  /* ADI availability check has been done.  */
>> +  bool checked_avail;
>> +
>> +  /* ADI is available.  */
>> +  bool is_avail;
>> +
>> +} adi_stat;
>>     
>
> It is a global data, but as I read the rest of the patch, looks like adi
> data should be per-process.
>   

You're right. Will investigate.

>> +
>> +
>> +static void
>> +info_adi_command (char *args, int from_tty)
>> +{
>> +  printf_unfiltered ("\"adi\" must be followed by \"examine\" "
>> +                     "or \"assign\".\n");
>> +  help_list (sparc64adilist, "adi ", all_commands, gdb_stdout);
>> +}
>> +
>> +static bool
>> +arch_is_64bit (void)
>> +{
>> +  struct gdbarch *gdbarch = get_frame_arch (get_current_frame ());
>> +  return gdbarch_bfd_arch_info (gdbarch)->bits_per_word == 64;
>> +
>> +}
>> +
>> +static int
>> +parse_byte_count (const char **sptr)
>> +{
>> +  const char *p = *sptr;
>> +  int cnt = 1;
>> +  if (*p == '-')
>> +    {
>> +      cnt = -1;
>> +      p++;
>> +    }
>> +  if (*p >= '0' && *p <= '9')
>> +    cnt *= atoi (p);
>> +  while (*p >= '0' && *p <= '9')
>> +    p++;
>> +  while (*p == ' ' || *p == '\t')
>> +    p++;
>> +  *sptr = p;
>> +
>> +  if (cnt <= 0)
>> +    error (_("Byte count should have a positive value."));
>> +
>> +  return cnt;
>> +}
>>     
>
> You can use get_number or other apis declared in in gdb/cli-utils.h.
>   

It's nice to know. Will do.

>> +
>> +/* 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)
>> +{
>> +  if (adi_stat.checked_avail)
>> +    return adi_stat.is_avail;
>> +
>> +  adi_stat.checked_avail = true;
>> +  if (!arch_is_64bit ())
>> +    return false;
>> +  if (target_auxv_search (&current_target, AT_ADI_BLKSZ, &adi_stat.blksize) <= 0)
>>     
>
> If kernel doesn't support ADI for 32-bit application, why don't we fetch
> AT_ADI_BLKSZ unconditionally?
>   
Yes, we could do that. Will get rid of the arch_is_64bit() call.

>> +    return false;
>> +  target_auxv_search (&current_target, AT_ADI_NBITS, &adi_stat.nbits);
>> +  adi_stat.max_version = (1 << adi_stat.nbits) - 2;
>> +  adi_stat.is_avail = true;
>> +
>> +  return adi_stat.is_avail;
>> +}
>> +
>> +#if 0
>> +/* Extract version tag from a versioned address.  */
>> +
>> +int adi_extract_version (CORE_ADDR versioned_addr)
>> +{
>> +  return ((unsigned long)versioned_addr) >> (64 - adi_stat.nbits);
>> +}
>> +#endif
>> +
>> +/* Normalize a versioned address - a VA with ADI bits (63-60) set.  */
>> +
>> +CORE_ADDR
>> +adi_normalize_address (CORE_ADDR addr)
>> +{
>> +  if (adi_stat.nbits)
>> +    return ((CORE_ADDR)(((long)addr << adi_stat.nbits) >> adi_stat.nbits));
>> +  return addr;
>> +}
>>     
>
> I think the right approach is to implement gdbarch_addr_bits_remove for
> sparc64-linux, which remove these unused bits.
>   

I suspect keeping this little function whose name implies clearly to 
normalize a VA might be OK. Will look into it.

>> +
>> +/* Align a normalized address - a VA with bit 59 sign extended into ADI bits.  */
>> +
>> +static CORE_ADDR
>> +adi_align_address (CORE_ADDR naddr)
>> +{
>> +    return (naddr - (naddr % adi_stat.blksize)) / adi_stat.blksize;
>>     
>
> Indentation is wrong.  
>   
Will check/correct.
>> +}
>> +
>> +/* 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)
>> +{
>> +    return ((naddr + nbytes + adi_stat.blksize - 1) / adi_stat.blksize) - locl;
>>     
>
> This line is too long.
>
>   
Will correct.
>> +}
>> +
>> +/* The /proc/[pid]/adi/tag 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)
>> +{
>> +  if (adi_stat.tag_fd != 0)
>> +    return adi_stat.tag_fd;
>> +
>> +  char cl_name[MAX_PROC_NAME_SIZE];
>> +  pid_t pid = ptid_get_pid (inferior_ptid);
>> +  snprintf (cl_name, sizeof(cl_name), "/proc/%d/adi/tag", pid);
>> +  adi_stat.tag_fd = open (cl_name, O_RDWR|O_EXCL|O_CLOEXEC);
>>     
>
> You can't access /proc in *-tdep.c file, because it is also compiled for
> cross-debugger.  The rule in general is to move it to sparc64-linux-nat.c.
>   
It's nice to know. Will look into it. BTW is there any document that 
specifies/defines these rules for
*-tdep.c and *-nat.c files?

>> +
>> +  return adi_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 = ptid_get_pid (inferior_ptid);
>> +  snprintf (filename, sizeof filename, "/proc/%d/adi/maps", pid);
>> +  char *data = target_fileio_read_stralloc (NULL, filename);
>>     
>
> It is better to define adi as a qXfer object, which can be read and
> written through target layer.
>   

OK, will take a look.

>> +  if (data)
>> +    {
>> +      struct cleanup *cleanup = make_cleanup (xfree, data);
>> +      char *line;
>> +      for (line = strtok (data, "\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)
>> +                {
>> +                  do_cleanups (cleanup);
>> +                  return true;
>> +                }
>> +            }
>> +        }
>> +        do_cleanups (cleanup);
>> +      }
>> +    else
>> +      warning (_("unable to open /proc file '%s'"), filename);
>> +
>> +  return false;
>> +}
>> +
>>     
>
>   
>> +
>> +/* 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, unsigned char *tags)
>> +{
>> +  int v_idx = 0;
>> +  const int maxelts = 8;  /* # of elements per line */
>> +
>> +  while (cnt > 0)
>> +    {
>> +      QUIT;
>> +      printf_filtered ("0x%016lx:\t", 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]);
>> +          ++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);
>> +  struct cleanup *cleanup;
>> +
>> +  CORE_ADDR vstart = adi_align_address (vaddr);
>> +  int cnt = adi_convert_byte_count (vaddr, bcnt, vstart);
>> +  unsigned char *buf = (unsigned char *) xmalloc (cnt);
>> +  cleanup = make_cleanup (xfree, buf);
>> +  int read_cnt = adi_read_versions (vstart, cnt, buf);
>> +  if (read_cnt == -1)
>> +    error (_("No ADI information"));
>> +  else if (read_cnt < cnt)
>> +    error(_("No ADI information at 0x%lx"), vaddr);
>> +
>> +  adi_print_versions(vstart, cnt, buf);
>> +
>> +  do_cleanups (cleanup);
>> +}
>> +
>> +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);
>> +  unsigned char *buf = (unsigned char *) xmalloc (cnt);
>> +  memset(buf, version, cnt);
>> +
>> +  int set_cnt = adi_write_versions (vstart, cnt, buf);
>> +  xfree (buf);
>> +
>> +  if (set_cnt == -1)
>> +    error (_("No ADI information"));
>> +  else if (set_cnt < cnt)
>> +    error(_("No ADI information at 0x%lx"), vaddr);
>> +
>> +}
>> +
>> +/* ADI examine version tag command.
>> +
>> +   Command syntax:
>> +
>> +     adi (examine|x)/count <addr> */
>> +
>> +static void
>> +adi_examine_command (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 = adi_stat.last_cnt? adi_stat.last_cnt : 1;
>> +  const char *p = args;
>> +  if (p && *p == '/')
>> +    {
>> +      p++;
>> +      cnt = parse_byte_count (&p);
>> +    }
>> +
>> +  CORE_ADDR next_address = adi_stat.last_vaddr ? adi_stat.last_vaddr : 0;
>> +  if (p != 0 && *p != 0)
>> +    next_address = parse_and_eval_address (p);
>> +  else if (!adi_stat.last_cnt)
>> +    error (_("Usage: adi examine|x[/count] <addr>"));
>> +
>> +  if (next_address)
>> +    do_examine(next_address, cnt);
>> +
>> +  adi_stat.last_cnt = cnt;
>> +  adi_stat.last_vaddr = next_address + adi_stat.blksize * cnt;
>> +}
>> +
>> +/* ADI assign version tag command.
>> +
>> +   Command syntax:
>> +
>> +     adi (assign|a)/count <addr> = <version>  */
>> +
>> +static void
>> +adi_assign_command (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"));
>> +
>> +  const char *exp = args;
>> +  if (exp == 0)
>> +    error_no_arg (_("Usage: adi assign|a[/count] <addr> = <version>"));
>> +
>> +  char *q = (char *) strchr (exp, '=');
>> +  if (q)
>> +    *q++ = 0;
>> +  else
>> +    error (_("Usage: adi assign|a[/count] <addr> = <version>"));
>> +
>> +  size_t cnt = 1;
>> +  const char *p = exp;
>> +  if (exp && *exp == '/')
>> +    {
>> +      p = exp + 1;
>> +      cnt = parse_byte_count (&p);
>> +    }
>> +
>> +  CORE_ADDR next_address = 0;
>> +  if (p != 0 && *p != 0)
>> +    next_address = parse_and_eval_address (p);
>> +  else
>> +    error (_("Usage: adi assign|a[/count] <addr> = <version>"));
>> +
>> +  int version = 0;
>> +  if (q)           /* parse version tag */
>> +    {
>> +      version = parse_and_eval_long (q);
>> +      if (version < 0 || version > adi_stat.max_version)
>> +        error (_("Invalid ADI version tag %d"), version);
>> +    }
>> +
>> +  do_assign(next_address, cnt, version);
>> +}
>> +
>> +extern initialize_file_ftype _initialize_sparc64_adi_tdep; /* -Wmissing-prototypes */
>> +
>>     
>
> This line is not needed.
>   

I thought "lint" would need this line so it can be added to init.c?

>> +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);
>> +
>> +}
>> +
>> diff --git a/gdb/sparc64-linux-nat.c b/gdb/sparc64-linux-nat.c
>> index 638aa29..01adcd6 100644
>> --- a/gdb/sparc64-linux-nat.c
>> +++ b/gdb/sparc64-linux-nat.c
>> @@ -69,6 +69,18 @@ fill_fpregset (const struct regcache *regcache,
>>    sparc64_collect_fpregset (&sparc64_bsd_fpregmap, regcache, regnum, fpregs);
>>  }
>>  
>> +/* Implement the "to_watchpoint_addr_within_range" target_ops method.  */
>> +
>> +static int
>> +sparc64_linux_watchpoint_addr_within_range (struct target_ops *target,
>> +					    CORE_ADDR addr,
>> +					    CORE_ADDR start, int length)
>> +{
>> +  start = adi_normalize_address (start);
>> +  addr = adi_normalize_address (addr);
>> +  return (start <= addr) && (start + length - 1 >= addr);
>>     
>
> I suppose once you implement gdbarch_addr_bits_remove, you don't need
> this change.
>   

OK. Will check that.

>> +}
>> +
>>  /* Provide a prototype to silence -Wmissing-prototypes.  */
>>  void _initialize_sparc64_linux_nat (void);
>>  
>> @@ -86,6 +98,9 @@ _initialize_sparc64_linux_nat (void)
>>    t->to_fetch_registers = sparc_fetch_inferior_registers;
>>    t->to_store_registers = sparc_store_inferior_registers;
>>  
>> +  t->to_watchpoint_addr_within_range =
>> +    sparc64_linux_watchpoint_addr_within_range;
>> +
>>    /* Register the target.  */
>>    linux_nat_add_target (t);
>>  
>> diff --git a/gdb/sparc64-linux-tdep.c b/gdb/sparc64-linux-tdep.c
>> index 814bc29..17eb8c5 100644
>> --- a/gdb/sparc64-linux-tdep.c
>> +++ b/gdb/sparc64-linux-tdep.c
>> @@ -32,6 +32,7 @@
>>  #include "tramp-frame.h"
>>  #include "xml-syscall.h"
>>  #include "linux-tdep.h"
>> +#include <adi.h>
>>  
>>  /* The syscall's XML filename for sparc 64-bit.  */
>>  #define XML_SYSCALL_FILENAME_SPARC64 "syscalls/sparc64-linux.xml"
>> @@ -104,6 +105,52 @@ sparc64_linux_sigframe_init (const struct tramp_frame *self,
>>      }
>>    trad_frame_set_id (this_cache, frame_id_build (base, func));
>>  }
>> +
>> +/* sparc64 GNU/Linux implementation of the handle_segmentation_fault
>> +   gdbarch hook.
>> +   Displays information related to ADI memory corruptions.  */
>> +
>> +void
>> +sparc64_linux_handle_segmentation_fault (struct gdbarch *gdbarch,
>> +				      struct ui_out *uiout)
>> +{
>> +  if (gdbarch_bfd_arch_info (gdbarch)->bits_per_word != 64)
>> +    return;
>> +
>>     
>
> Do you need to return if some sparc64 processor doesn't have adi?
>   

No. The code that followed will check for the si_code bit which would 
signal if the segfault is caused by adi.

>> +  CORE_ADDR addr = 0;
>> +  long si_code = 0;
>> +
>> +  TRY
>> +    {
>> +      /* Evaluate si_code to see if the segfault is ADI related.  */
>> +      si_code = parse_and_eval_long ("$_siginfo.si_code\n");
>> +
>> +      if (si_code >= SEGV_ACCADI && si_code <= SEGV_ADIPERR)
>> +        addr = parse_and_eval_long ("$_siginfo._sifields._sigfault.si_addr");
>> +    }
>> +  CATCH (exception, RETURN_MASK_ALL)
>> +    {
>> +      return;
>> +    }
>> +  END_CATCH
>> +
>> +  /* Print out ADI event based on sig_code value */
>> +  switch (si_code)
>> +    {
>> +    case SEGV_ACCADI:	/* adi not enabled */
>> +      printf_unfiltered (" (ADI disabled at address 0x%lx)\n", addr);
>> +      break;
>> +    case SEGV_ADIDERR:	/* disrupting mismatch */
>> +      printf_unfiltered (" (ADI deferred mismatch at address 0x%lx)\n", addr);
>> +      break;
>> +    case SEGV_ADIPERR:	/* precise mismatch */
>> +      printf_unfiltered (" (ADI precise mismatch at address
>> 0x%lx)\n", addr);
>>     
>
> Use uiout instead print_unfiltered.  See i386_linux_handle_segmentation_fault.
>   

OK.
>   
>> +      break;
>> +    default:
>> +      break;
>> +    }
>> +}
>> +
>>  
>>  /* Return the address of a system call's alternative return
>>     address.  */
>> @@ -338,6 +385,8 @@ sparc64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
>>    set_xml_syscall_file_name (gdbarch, XML_SYSCALL_FILENAME_SPARC64);
>>    set_gdbarch_get_syscall_number (gdbarch,
>>                                    sparc64_linux_get_syscall_number);
>> +  set_gdbarch_handle_segmentation_fault (gdbarch,
>> +					 sparc64_linux_handle_segmentation_fault);
>>  }
>>  
>>  
>> diff --git a/gdb/sparc64-tdep.c b/gdb/sparc64-tdep.c
>> index 9e0e6b5..e8c5a63 100644
>> --- a/gdb/sparc64-tdep.c
>> +++ b/gdb/sparc64-tdep.c
>> @@ -165,7 +165,7 @@ sparc64_pstate_type (struct gdbarch *gdbarch)
>>        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");
>> +      append_flags_type_flag (type, 11, "MCDE");
>>  
>>     
>
> Why do you do this change?
>   
This change, which indicated that the TSTATE reigster contained the 
"mcde" value, was requested by our kernel engineers.

Thanks very much  for your comments.
Yao Qi - June 21, 2017, 9:46 a.m.
Wei-min Pan <weimin.pan@oracle.com> writes:

>> The new file sparc64-adi-tdep.c should be merged into the existing
>> sparc64-tdep.c.  The file name schema in GDB is ARCH-OSABI-tdep.c.
>> Since adi is a new hardware feature rather than an OSABI, it should be
>> put in sparc64-tdep.c
>>   
>
> Originally it was part of sparc64-tdep.c. But our engineer thought
> it's cleaner to make it a
> separate source file. Being new to the gnu world, I believe following
> the file name schema
> is the way to go. Thanks.
>

That is the current file name convention we have to follow, however, I
personally prefer putting them into separated files.  Let me post a mail
to ask this.

>>
>> You can't access /proc in *-tdep.c file, because it is also compiled for
>> cross-debugger.  The rule in general is to move it to sparc64-linux-nat.c.
>>   
> It's nice to know. Will look into it. BTW is there any document that
> specifies/defines these rules for
> *-tdep.c and *-nat.c files?

I was puzzled by this for several years when I started on GDB :)  The
most relevant one is
https://sourceware.org/gdb/wiki/Internals%20Native-Debugging  In short,
anything required in native debugging (gdb and program are running on
the same machine) should be put in *-nat.c.  The rest of things related
to this arch should be put into *-tdep.c.  Note some ports have
*-linux-nat.c and *-linux-tdep.c, the former is about anything required
in Linux native debugging (gdb and the program is running on the same Linux
machine), while the latter is about debugging a program running on Linux
of that arch.
Pedro Alves - June 21, 2017, 10:10 a.m.
On 06/21/2017 10:46 AM, Yao Qi wrote:
> Wei-min Pan <weimin.pan@oracle.com> writes:
> 

> 
>>>
>>> You can't access /proc in *-tdep.c file, because it is also compiled for
>>> cross-debugger.  The rule in general is to move it to sparc64-linux-nat.c.
>>>   
>> It's nice to know. Will look into it. BTW is there any document that
>> specifies/defines these rules for
>> *-tdep.c and *-nat.c files?
> 
> I was puzzled by this for several years when I started on GDB :)  The
> most relevant one is
> https://sourceware.org/gdb/wiki/Internals%20Native-Debugging  In short,
> anything required in native debugging (gdb and program are running on
> the same machine) should be put in *-nat.c.  The rest of things related
> to this arch should be put into *-tdep.c.  Note some ports have
> *-linux-nat.c and *-linux-tdep.c, the former is about anything required
> in Linux native debugging (gdb and the program is running on the same Linux
> machine), while the latter is about debugging a program running on Linux
> of that arch.
> 

There's also:
 https://sourceware.org/gdb/wiki/Internals/Source%20Tree%20Structure

I've extended the tdep section a bit now, and added something about
unit tests too, while at it:
 https://sourceware.org/gdb/wiki/Internals/Source%20Tree%20Structure?action=diff&rev1=7&rev2=8

Thanks,
Pedro Alves
Weimin Pan - June 21, 2017, 4:22 p.m.
Yao Qi wrote:
> Wei-min Pan <weimin.pan@oracle.com> writes:
>
>   
>>> The new file sparc64-adi-tdep.c should be merged into the existing
>>> sparc64-tdep.c.  The file name schema in GDB is ARCH-OSABI-tdep.c.
>>> Since adi is a new hardware feature rather than an OSABI, it should be
>>> put in sparc64-tdep.c
>>>   
>>>       
>> Originally it was part of sparc64-tdep.c. But our engineer thought
>> it's cleaner to make it a
>> separate source file. Being new to the gnu world, I believe following
>> the file name schema
>> is the way to go. Thanks.
>>
>>     
>
> That is the current file name convention we have to follow, however, I
> personally prefer putting them into separated files.  Let me post a mail
> to ask this.
>   

Thanks for bringing up and taking care of  this matter. I will create 
sparc64-tdep-adi.c for SPARC
ADI support.

>>> You can't access /proc in *-tdep.c file, because it is also compiled for
>>> cross-debugger.  The rule in general is to move it to sparc64-linux-nat.c.
>>>   
>>>       
>> It's nice to know. Will look into it. BTW is there any document that
>> specifies/defines these rules for
>> *-tdep.c and *-nat.c files?
>>     
>
> I was puzzled by this for several years when I started on GDB :)  The
> most relevant one is
> https://sourceware.org/gdb/wiki/Internals%20Native-Debugging  In short,
> anything required in native debugging (gdb and program are running on
> the same machine) should be put in *-nat.c.  The rest of things related
> to this arch should be put into *-tdep.c.  Note some ports have
> *-linux-nat.c and *-linux-tdep.c, the former is about anything required
> in Linux native debugging (gdb and the program is running on the same Linux
> machine), while the latter is about debugging a program running on Linux
> of that arch.
>   
I'm glad that I wasn't the only one who struggled to grasp the concept :) 
Thanks for the clarification (also Pedro's).
Yao Qi - June 21, 2017, 4:42 p.m.
On Wed, Jun 21, 2017 at 5:22 PM, Wei-min Pan <weimin.pan@oracle.com> wrote:
>
> Thanks for bringing up and taking care of  this matter. I will create
> sparc64-tdep-adi.c for SPARC
> ADI support.
>

Hold on :), I don't think people agreed on the new
convention yet.  Before the agreement is made,
sparc64-tdep.c is still the right place to add adi stuff.

Patch

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 5ebc7f8..8126a47 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,17 @@ 
+2017-06-16  Weimin Pan  <weimin.pan@oracle.com>
+
+	* sparc64-tdep.h: (adi_normalize_address): New export.
+	* sparc64-adi-tdep.c: New file.
+	* Makefile.in (ALLDEPFILES): Add sparc64-adi-tdep.c.
+	* configure.tgt: Add sparc64-adi-tdep.o.
+	* sparc64-linux-nat.c: 
+	(sparc64_linux_watchpoint_addr_within_range): New function.
+	(_initialize_sparc64_linux_nat): Register sparc64_linux_watchpoint_addr_within_range.
+	* sparc64-linux-tdep.c: Include <adi.h>. 
+	(sparc64_linux_handle_segmentation_fault): New function.
+	(sparc64_linux_init_abi): Register sparc64_linux_handle_segmentation_fault
+	* sparc64-tdep.c: (sparc64_pstate_type): Replace PID1 with MCDE.
+
 2017-06-08  Sergio Durigan Junior  <sergiodj@redhat.com>
 
 	* common/common-utils.c (stringify_argv): Check for "arg[0] !=
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 5e5fcaa..a6b0d99 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -772,6 +772,7 @@  ALL_64_TARGET_OBS = \
 	ia64-tdep.o \
 	ia64-vms-tdep.o \
 	mips64-obsd-tdep.o \
+	sparc64-adi-tdep.o \
 	sparc64-fbsd-tdep.o \
 	sparc64-linux-tdep.o \
 	sparc64-nbsd-tdep.o \
@@ -2660,6 +2661,7 @@  ALLDEPFILES = \
 	sparc-sol2-nat.c \
 	sparc-sol2-tdep.c \
 	sparc-tdep.c \
+	sparc64-adi-tdep.c \
 	sparc64-fbsd-nat.c \
 	sparc64-fbsd-tdep.c \
 	sparc64-linux-nat.c \
diff --git a/gdb/configure.tgt b/gdb/configure.tgt
index fdcb7b1..0519c62 100644
--- a/gdb/configure.tgt
+++ b/gdb/configure.tgt
@@ -548,6 +548,7 @@  sparc64-*-linux*)
 	gdb_target_obs="sparc64-tdep.o sparc64-sol2-tdep.o sol2-tdep.o \
 			sparc64-linux-tdep.o sparc-tdep.o sparc-sol2-tdep.o \
 			sparc-linux-tdep.o solib-svr4.o linux-tdep.o \
+			sparc64-adi-tdep.o \
 			ravenscar-thread.o sparc-ravenscar-thread.o"
 	build_gdbserver=yes
 	;;
diff --git a/gdb/doc/ChangeLog b/gdb/doc/ChangeLog
index 868cde9..a411d64 100644
--- a/gdb/doc/ChangeLog
+++ b/gdb/doc/ChangeLog
@@ -1,3 +1,7 @@ 
+2017-06-16  Weimin Pan  <weimin.pan@oracle.com>
+	* gdb.texinfo (Architectures): Add new Sparc64 section to document ADI support.
+	* NEWS: Add "adi examine" and "adi assign" commands.
+
 2017-06-07  Sergio Durigan Junior  <sergiodj@redhat.com>
 
 	* gdb.texinfo (Starting) <startup-with-shell>: Add @anchor.
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 8d7a1c9..843c1bf 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -22465,6 +22465,7 @@  all uses of @value{GDBN} with the architecture, both native and cross.
 * SPU::                Cell Broadband Engine SPU architecture
 * PowerPC::
 * Nios II::
+* Sparc64::
 @end menu
 
 @node AArch64
@@ -22849,6 +22850,90 @@  target code in @value{GDBN}.
 Show the current setting of Nios II debugging messages.
 @end table
 
+@node Sparc64
+@subsection Sparc64
+@cindex Sparc64 support
+@cindex Application Data Integrity
+@subsubsection ADI Support
+
+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 that data.  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.
+
+Note that only 64-bit applications can use ADI and need to be built with
+ADI-enabled.
+
+Values of the ADI version tags, which are in granularity of a 
+cacheline (64 bytes), can be viewed or modified. 
+
+
+@table @code
+@kindex adi examine
+@item adi examine
+
+The @code{adi examine} command displays the value of one ADI version tag per 
+cacheline.  It has the following command syntax: 
+
+@table @code
+@itemx adi (examine | x) [ / @var{n} ] @var{addr}
+@end table
+
+@var{n}, the byte count
+The count is a decimal integer specifying the number in bytes; the default 
+is 1.  It specifies how much ADI version information, at the ratio of 1:ADI 
+block size, to display. 
+
+@var{addr}, starting display address
+@var{addr} is the address in user address space where you want @value{GDBN} 
+to begin displaying the ADI version tags. 
+
+Below is an example of displaying ADI versions of variable "shmaddr".
+
+@smallexample
+(@value{GDBP}) adi x/100 shmaddr
+   0xfff800010002c000:     0 0
+@end smallexample
+
+@kindex adi assign
+@item adi assign
+
+The @code{adi assign} command is used to assign new ADI version tag 
+to an address.  It has the following command syntax:
+
+@table @code
+@itemx adi (assign | a) [ / @var{n} ] @var{addr} = @var{tag}
+@end table
+
+@var{n}, the byte count
+The count is a decimal integer specifying the number in bytes; the default 
+is 1.  It specifies how much ADI version information, at the ratio of 1:ADI 
+block size, to modify. 
+
+@var{addr}, starting display address
+@var{addr} is the address in user address space where you want @value{GDBN} 
+to begin modifying the ADI version tags. 
+
+@var{tag}, the new ADI version tag
+
+For example, do the following to modify then verify ADI versions of 
+variable "shmaddr":
+
+@smallexample
+(@value{GDBP}) adi a/100 shmaddr = 7
+(@value{GDBP}) adi x/100 shmaddr
+   0xfff800010002c000:     7 7
+@end smallexample
+
+@end table
+
 @node Controlling GDB
 @chapter Controlling @value{GDBN}
 
diff --git a/gdb/sparc64-adi-tdep.c b/gdb/sparc64-adi-tdep.c
new file mode 100644
index 0000000..9c9d0ae
--- /dev/null
+++ b/gdb/sparc64-adi-tdep.c
@@ -0,0 +1,460 @@ 
+/* Target-dependent code for Sparc64.
+
+   Copyright (C) 2017 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 <http://www.gnu.org/licenses/>.  */
+
+#include <adi.h>
+#include "defs.h"
+#include "inferior.h"
+#include "gdbcmd.h"
+#include "auxv.h"
+
+/* 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. */
+
+
+#define MAX_PROC_NAME_SIZE sizeof("/proc/99999/lwp/9999/adi/lstatus")
+
+/* ADI command list.  */
+static struct cmd_list_element *sparc64adilist = NULL;
+
+/* Current ADI stat settings.  */
+static 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;
+
+  /* Last ADI address examined.  */
+  CORE_ADDR last_vaddr;
+
+  /* Last specified examination count.  */
+  int last_cnt;
+
+  /* ADI availability check has been done.  */
+  bool checked_avail;
+
+  /* ADI is available.  */
+  bool is_avail;
+
+} adi_stat;
+
+
+static void
+info_adi_command (char *args, int from_tty)
+{
+  printf_unfiltered ("\"adi\" must be followed by \"examine\" "
+                     "or \"assign\".\n");
+  help_list (sparc64adilist, "adi ", all_commands, gdb_stdout);
+}
+
+static bool
+arch_is_64bit (void)
+{
+  struct gdbarch *gdbarch = get_frame_arch (get_current_frame ());
+  return gdbarch_bfd_arch_info (gdbarch)->bits_per_word == 64;
+
+}
+
+static int
+parse_byte_count (const char **sptr)
+{
+  const char *p = *sptr;
+  int cnt = 1;
+  if (*p == '-')
+    {
+      cnt = -1;
+      p++;
+    }
+  if (*p >= '0' && *p <= '9')
+    cnt *= atoi (p);
+  while (*p >= '0' && *p <= '9')
+    p++;
+  while (*p == ' ' || *p == '\t')
+    p++;
+  *sptr = p;
+
+  if (cnt <= 0)
+    error (_("Byte count should have a positive value."));
+
+  return cnt;
+}
+
+/* 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)
+{
+  if (adi_stat.checked_avail)
+    return adi_stat.is_avail;
+
+  adi_stat.checked_avail = true;
+  if (!arch_is_64bit ())
+    return false;
+  if (target_auxv_search (&current_target, AT_ADI_BLKSZ, &adi_stat.blksize) <= 0)
+    return false;
+  target_auxv_search (&current_target, AT_ADI_NBITS, &adi_stat.nbits);
+  adi_stat.max_version = (1 << adi_stat.nbits) - 2;
+  adi_stat.is_avail = true;
+
+  return adi_stat.is_avail;
+}
+
+#if 0
+/* Extract version tag from a versioned address.  */
+
+int adi_extract_version (CORE_ADDR versioned_addr)
+{
+  return ((unsigned long)versioned_addr) >> (64 - adi_stat.nbits);
+}
+#endif
+
+/* Normalize a versioned address - a VA with ADI bits (63-60) set.  */
+
+CORE_ADDR
+adi_normalize_address (CORE_ADDR addr)
+{
+  if (adi_stat.nbits)
+    return ((CORE_ADDR)(((long)addr << adi_stat.nbits) >> adi_stat.nbits));
+  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)
+{
+    return (naddr - (naddr % adi_stat.blksize)) / adi_stat.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)
+{
+    return ((naddr + nbytes + adi_stat.blksize - 1) / adi_stat.blksize) - locl;
+}
+
+/* The /proc/[pid]/adi/tag 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)
+{
+  if (adi_stat.tag_fd != 0)
+    return adi_stat.tag_fd;
+
+  char cl_name[MAX_PROC_NAME_SIZE];
+  pid_t pid = ptid_get_pid (inferior_ptid);
+  snprintf (cl_name, sizeof(cl_name), "/proc/%d/adi/tag", pid);
+  adi_stat.tag_fd = open (cl_name, O_RDWR|O_EXCL|O_CLOEXEC);
+
+  return adi_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 = ptid_get_pid (inferior_ptid);
+  snprintf (filename, sizeof filename, "/proc/%d/adi/maps", pid);
+  char *data = target_fileio_read_stralloc (NULL, filename);
+  if (data)
+    {
+      struct cleanup *cleanup = make_cleanup (xfree, data);
+      char *line;
+      for (line = strtok (data, "\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)
+                {
+                  do_cleanups (cleanup);
+                  return true;
+                }
+            }
+        }
+        do_cleanups (cleanup);
+      }
+    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, unsigned char *tags)
+{
+  int fd = adi_tag_fd ();
+  if (fd == -1)
+    return -1;
+
+  if (!adi_is_addr_mapped (vaddr, size))
+    error(_("Address at 0x%lx is not in ADI maps"), vaddr*adi_stat.blksize);
+
+  return pread64 (fd, tags, size, vaddr);
+}
+
+/* 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))
+    error(_("Address at 0x%lx is not in ADI maps"), vaddr*adi_stat.blksize);
+
+  return pwrite64 (fd, tags, size, vaddr);
+}
+
+/* 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, unsigned char *tags)
+{
+  int v_idx = 0;
+  const int maxelts = 8;  /* # of elements per line */
+
+  while (cnt > 0)
+    {
+      QUIT;
+      printf_filtered ("0x%016lx:\t", 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]);
+          ++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);
+  struct cleanup *cleanup;
+
+  CORE_ADDR vstart = adi_align_address (vaddr);
+  int cnt = adi_convert_byte_count (vaddr, bcnt, vstart);
+  unsigned char *buf = (unsigned char *) xmalloc (cnt);
+  cleanup = make_cleanup (xfree, buf);
+  int read_cnt = adi_read_versions (vstart, cnt, buf);
+  if (read_cnt == -1)
+    error (_("No ADI information"));
+  else if (read_cnt < cnt)
+    error(_("No ADI information at 0x%lx"), vaddr);
+
+  adi_print_versions(vstart, cnt, buf);
+
+  do_cleanups (cleanup);
+}
+
+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);
+  unsigned char *buf = (unsigned char *) xmalloc (cnt);
+  memset(buf, version, cnt);
+
+  int set_cnt = adi_write_versions (vstart, cnt, buf);
+  xfree (buf);
+
+  if (set_cnt == -1)
+    error (_("No ADI information"));
+  else if (set_cnt < cnt)
+    error(_("No ADI information at 0x%lx"), vaddr);
+
+}
+
+/* ADI examine version tag command.
+
+   Command syntax:
+
+     adi (examine|x)/count <addr> */
+
+static void
+adi_examine_command (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 = adi_stat.last_cnt? adi_stat.last_cnt : 1;
+  const char *p = args;
+  if (p && *p == '/')
+    {
+      p++;
+      cnt = parse_byte_count (&p);
+    }
+
+  CORE_ADDR next_address = adi_stat.last_vaddr ? adi_stat.last_vaddr : 0;
+  if (p != 0 && *p != 0)
+    next_address = parse_and_eval_address (p);
+  else if (!adi_stat.last_cnt)
+    error (_("Usage: adi examine|x[/count] <addr>"));
+
+  if (next_address)
+    do_examine(next_address, cnt);
+
+  adi_stat.last_cnt = cnt;
+  adi_stat.last_vaddr = next_address + adi_stat.blksize * cnt;
+}
+
+/* ADI assign version tag command.
+
+   Command syntax:
+
+     adi (assign|a)/count <addr> = <version>  */
+
+static void
+adi_assign_command (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"));
+
+  const char *exp = args;
+  if (exp == 0)
+    error_no_arg (_("Usage: adi assign|a[/count] <addr> = <version>"));
+
+  char *q = (char *) strchr (exp, '=');
+  if (q)
+    *q++ = 0;
+  else
+    error (_("Usage: adi assign|a[/count] <addr> = <version>"));
+
+  size_t cnt = 1;
+  const char *p = exp;
+  if (exp && *exp == '/')
+    {
+      p = exp + 1;
+      cnt = parse_byte_count (&p);
+    }
+
+  CORE_ADDR next_address = 0;
+  if (p != 0 && *p != 0)
+    next_address = parse_and_eval_address (p);
+  else
+    error (_("Usage: adi assign|a[/count] <addr> = <version>"));
+
+  int version = 0;
+  if (q)           /* parse version tag */
+    {
+      version = parse_and_eval_long (q);
+      if (version < 0 || version > adi_stat.max_version)
+        error (_("Invalid ADI version tag %d"), version);
+    }
+
+  do_assign(next_address, cnt, version);
+}
+
+extern initialize_file_ftype _initialize_sparc64_adi_tdep; /* -Wmissing-prototypes */
+
+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);
+
+}
+
diff --git a/gdb/sparc64-linux-nat.c b/gdb/sparc64-linux-nat.c
index 638aa29..01adcd6 100644
--- a/gdb/sparc64-linux-nat.c
+++ b/gdb/sparc64-linux-nat.c
@@ -69,6 +69,18 @@  fill_fpregset (const struct regcache *regcache,
   sparc64_collect_fpregset (&sparc64_bsd_fpregmap, regcache, regnum, fpregs);
 }
 
+/* Implement the "to_watchpoint_addr_within_range" target_ops method.  */
+
+static int
+sparc64_linux_watchpoint_addr_within_range (struct target_ops *target,
+					    CORE_ADDR addr,
+					    CORE_ADDR start, int length)
+{
+  start = adi_normalize_address (start);
+  addr = adi_normalize_address (addr);
+  return (start <= addr) && (start + length - 1 >= addr);
+}
+
 /* Provide a prototype to silence -Wmissing-prototypes.  */
 void _initialize_sparc64_linux_nat (void);
 
@@ -86,6 +98,9 @@  _initialize_sparc64_linux_nat (void)
   t->to_fetch_registers = sparc_fetch_inferior_registers;
   t->to_store_registers = sparc_store_inferior_registers;
 
+  t->to_watchpoint_addr_within_range =
+    sparc64_linux_watchpoint_addr_within_range;
+
   /* Register the target.  */
   linux_nat_add_target (t);
 
diff --git a/gdb/sparc64-linux-tdep.c b/gdb/sparc64-linux-tdep.c
index 814bc29..17eb8c5 100644
--- a/gdb/sparc64-linux-tdep.c
+++ b/gdb/sparc64-linux-tdep.c
@@ -32,6 +32,7 @@ 
 #include "tramp-frame.h"
 #include "xml-syscall.h"
 #include "linux-tdep.h"
+#include <adi.h>
 
 /* The syscall's XML filename for sparc 64-bit.  */
 #define XML_SYSCALL_FILENAME_SPARC64 "syscalls/sparc64-linux.xml"
@@ -104,6 +105,52 @@  sparc64_linux_sigframe_init (const struct tramp_frame *self,
     }
   trad_frame_set_id (this_cache, frame_id_build (base, func));
 }
+
+/* sparc64 GNU/Linux implementation of the handle_segmentation_fault
+   gdbarch hook.
+   Displays information related to ADI memory corruptions.  */
+
+void
+sparc64_linux_handle_segmentation_fault (struct gdbarch *gdbarch,
+				      struct ui_out *uiout)
+{
+  if (gdbarch_bfd_arch_info (gdbarch)->bits_per_word != 64)
+    return;
+
+  CORE_ADDR addr = 0;
+  long si_code = 0;
+
+  TRY
+    {
+      /* Evaluate si_code to see if the segfault is ADI related.  */
+      si_code = parse_and_eval_long ("$_siginfo.si_code\n");
+
+      if (si_code >= SEGV_ACCADI && si_code <= SEGV_ADIPERR)
+        addr = parse_and_eval_long ("$_siginfo._sifields._sigfault.si_addr");
+    }
+  CATCH (exception, RETURN_MASK_ALL)
+    {
+      return;
+    }
+  END_CATCH
+
+  /* Print out ADI event based on sig_code value */
+  switch (si_code)
+    {
+    case SEGV_ACCADI:	/* adi not enabled */
+      printf_unfiltered (" (ADI disabled at address 0x%lx)\n", addr);
+      break;
+    case SEGV_ADIDERR:	/* disrupting mismatch */
+      printf_unfiltered (" (ADI deferred mismatch at address 0x%lx)\n", addr);
+      break;
+    case SEGV_ADIPERR:	/* precise mismatch */
+      printf_unfiltered (" (ADI precise mismatch at address 0x%lx)\n", addr);
+      break;
+    default:
+      break;
+    }
+}
+
 
 /* Return the address of a system call's alternative return
    address.  */
@@ -338,6 +385,8 @@  sparc64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
   set_xml_syscall_file_name (gdbarch, XML_SYSCALL_FILENAME_SPARC64);
   set_gdbarch_get_syscall_number (gdbarch,
                                   sparc64_linux_get_syscall_number);
+  set_gdbarch_handle_segmentation_fault (gdbarch,
+					 sparc64_linux_handle_segmentation_fault);
 }
 
 
diff --git a/gdb/sparc64-tdep.c b/gdb/sparc64-tdep.c
index 9e0e6b5..e8c5a63 100644
--- a/gdb/sparc64-tdep.c
+++ b/gdb/sparc64-tdep.c
@@ -165,7 +165,7 @@  sparc64_pstate_type (struct gdbarch *gdbarch)
       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");
+      append_flags_type_flag (type, 11, "MCDE");
 
       tdep->sparc64_pstate_type = type;
     }
diff --git a/gdb/sparc64-tdep.h b/gdb/sparc64-tdep.h
index 324778e..d229c76 100644
--- a/gdb/sparc64-tdep.h
+++ b/gdb/sparc64-tdep.h
@@ -113,6 +113,8 @@  extern void sparc64_collect_fpregset (const struct sparc_fpregmap *fpregmap,
 				      const struct regcache *regcache,
 				      int regnum, void *fpregs);
 
+extern CORE_ADDR adi_normalize_address (CORE_ADDR addr);
+
 /* Functions and variables exported from sparc64-sol2-tdep.c.  */
 
 /* Register offsets for Solaris 2.  */