diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 23f2d1b..95902a7 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,42 @@
+2017-08-07  Weimin Pan  <weimin.pan@oracle.com>
+
+	* sparc64-tdep.h: (sparc64_forget_process): New export.
+	* sparc64-linux-tdep.c:
+	(SEGV_ACCADI, SEGV_ADIDERR, SEGV_ADIPERR) New defines.
+	(sparc64_linux_handle_segmentation_fault): New function.
+	(sparc64_linux_init_abi): Register
+	sparc64_linux_handle_segmentation_fault
+	* sparc64-linux-nat.c:
+	(_initialize_sparc64_linux_nat): Register sparc64_forget_process
+	* sparc64-tdep.c: Include cli-utils.h,gdbcmd.h,auxv.h.
+	(sparc64_addr_bits_remove): New function.
+	(sparc64_init_abi): Register sparc64_addr_bits_remove.
+	(MAX_PROC_NAME_SIZE): New macro.
+	(AT_ADI_BLKSZ, AT_ADI_NBITS, AT_ADI_UEONADI) New defines.
+	(sparc64adilist): New variable.
+	(adi_proc_list): New variable.
+	(find_adi_info): New function.
+	(add_adi_info): New function.
+	(get_adi_info_proc): New function.
+	(get_adi_info): New function.
+	(info_adi_command): New function.
+	(read_maps_entry): New function.
+	(adi_available): New function.
+	(adi_normalize_address): New function.
+	(adi_align_address): New function.
+	(adi_convert_byte_count): New function.
+	(adi_tag_fd): New function.
+	(adi_is_addr_mapped): New function.
+	(adi_read_versions): New function.
+	(adi_write_versions): New function.
+	(adi_print_versions): New function.
+	(do_examine): New function.
+	(do_assign): New function.
+	(adi_examine_command): New function.
+	(adi_assign_command): New function.
+	(_initialize_sparc64_tdep): New function.
+	* NEWS: Add "adi examine" and "adi assign" commands.
+
 2017-07-10  Yao Qi  <yao.qi@linaro.org>
 
 	* features/i386/amd64-avx-avx512-linux.c: Re-generated.
diff --git a/gdb/doc/ChangeLog b/gdb/doc/ChangeLog
index 8c7c3da..61b0b8e 100644
--- a/gdb/doc/ChangeLog
+++ b/gdb/doc/ChangeLog
@@ -1,3 +1,8 @@
+2017-08-07  Weimin Pan  <weimin.pan@oracle.com>
+
+	* gdb.texinfo (Architectures): Add new Sparc64 section to document 
+	ADI support.
+
 2017-06-20  Sergio Durigan Junior  <sergiodj@redhat.com>
 
 	PR gdb/21606
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index c167a86..1485da9 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,78 @@ 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 | x) [ / @var{n} ] @var{addr}
+
+The @code{adi examine} command displays the value of one ADI version tag per 
+cacheline. 
+
+@var{n} 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} 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 | a) [ / @var{n} ] @var{addr} = @var{tag}
+
+The @code{adi assign} command is used to assign new ADI version tag 
+to an address. 
+
+@var{n} 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} is the address in user address space where you want @value{GDBN} 
+to begin modifying the ADI version tags. 
+
+@var{tag} is 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-linux-nat.c b/gdb/sparc64-linux-nat.c
index 638aa29..282980a 100644
--- a/gdb/sparc64-linux-nat.c
+++ b/gdb/sparc64-linux-nat.c
@@ -89,5 +89,8 @@ _initialize_sparc64_linux_nat (void)
   /* Register the target.  */
   linux_nat_add_target (t);
 
+  /* ADI support */
+  linux_nat_set_forget_process (t, sparc64_forget_process);
+
   sparc_gregmap = &sparc64_linux_ptrace_gregmap;
 }
diff --git a/gdb/sparc64-linux-tdep.c b/gdb/sparc64-linux-tdep.c
index 814bc29..2da978f 100644
--- a/gdb/sparc64-linux-tdep.c
+++ b/gdb/sparc64-linux-tdep.c
@@ -33,6 +33,17 @@
 #include "xml-syscall.h"
 #include "linux-tdep.h"
 
+/* ADI specific si_code */
+#ifndef SEGV_ACCADI
+#define SEGV_ACCADI	3
+#endif
+#ifndef SEGV_ADIDERR
+#define SEGV_ADIDERR	4
+#endif
+#ifndef SEGV_ADIPERR
+#define SEGV_ADIPERR	5
+#endif
+
 /* The syscall's XML filename for sparc 64-bit.  */
 #define XML_SYSCALL_FILENAME_SPARC64 "syscalls/sparc64-linux.xml"
 
@@ -104,6 +115,62 @@ 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 */
+      uiout->text ("\n");
+      uiout->field_string ("sigcode-meaning", _("ADI disabled"));
+      uiout->text (_(" while accessing address "));
+      uiout->field_fmt ("bound-access", "%s", paddress (gdbarch, addr));
+      break;
+    case SEGV_ADIDERR:	/* disrupting mismatch */
+      uiout->text ("\n");
+      uiout->field_string ("sigcode-meaning", _("ADI deferred mismatch"));
+      uiout->text (_(" while accessing address "));
+      uiout->field_fmt ("bound-access", "%s", paddress (gdbarch, addr));
+      break;
+    case SEGV_ADIPERR:	/* precise mismatch */
+      uiout->text ("\n");
+      uiout->field_string ("sigcode-meaning", _("ADI precise mismatch"));
+      uiout->text (_(" while accessing address "));
+      uiout->field_fmt ("bound-access", "%s", paddress (gdbarch, addr));
+      break;
+    default:
+      break;
+    }
+
+}
+
 
 /* Return the address of a system call's alternative return
    address.  */
@@ -338,6 +405,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..8d3917e 100644
--- a/gdb/sparc64-tdep.c
+++ b/gdb/sparc64-tdep.c
@@ -46,6 +46,505 @@
    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 <algorithm>
+#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<sparc64_adi_info> 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 (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 = ptid_get_pid (inferior_ptid);
+  sparc64_adi_info *proc = get_adi_info_proc (pid);
+
+  if (proc->stat.checked_avail)
+    return proc->stat.is_avail;
+
+  proc->stat.checked_avail = true;
+  if (target_auxv_search (&current_target, AT_ADI_BLKSZ, 
+                          &proc->stat.blksize) <= 0)
+    return false;
+  target_auxv_search (&current_target, AT_ADI_NBITS, &proc->stat.nbits);
+  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 (ptid_get_pid (inferior_ptid));
+
+  if (ast.nbits)
+    return ((CORE_ADDR)(((long)addr << ast.nbits) >> ast.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)
+{
+  adi_stat_t ast = get_adi_info (ptid_get_pid (inferior_ptid));
+
+  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 (ptid_get_pid (inferior_ptid));
+
+  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 = ptid_get_pid (inferior_ptid);
+  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/%d/adi/tags", 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 = 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);
+      adi_stat_t adi_stat = get_adi_info (pid);
+      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))
+    {
+      adi_stat_t ast = get_adi_info (ptid_get_pid (inferior_ptid));
+      error(_("Address at 0x%lx is not in ADI maps"), 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 (ptid_get_pid (inferior_ptid));
+      error(_("Address at 0x%lx is not in ADI maps"), 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, unsigned char *tags)
+{
+  int v_idx = 0;
+  const int maxelts = 8;  /* # of elements per line */
+
+  adi_stat_t adi_stat = get_adi_info (ptid_get_pid (inferior_ptid));
+
+  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]);
+	  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);
+  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);
+  std::vector<unsigned char> 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 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"));
+
+  pid_t pid = ptid_get_pid (inferior_ptid);
+  sparc64_adi_info *proc = get_adi_info_proc (pid);
+  int cnt = 1;
+  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 (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"));
+
+  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;
+  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 (_("Usage: adi assign|a[/count] <addr> = <version>"));
+
+  int version = 0;
+  if (q != NULL)           /* parse version tag */
+    {
+      adi_stat_t ast = get_adi_info (ptid_get_pid (inferior_ptid));
+      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.  */
 
@@ -1290,6 +1789,14 @@ sparc64_dwarf2_frame_init_reg (struct gdbarch *gdbarch, int regnum,
     }
 }
 
+/* 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)
 {
@@ -1342,6 +1849,8 @@ sparc64_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
 
   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);
 }
 
 
diff --git a/gdb/sparc64-tdep.h b/gdb/sparc64-tdep.h
index 324778e..da61a82 100644
--- a/gdb/sparc64-tdep.h
+++ b/gdb/sparc64-tdep.h
@@ -138,4 +138,6 @@ extern struct trad_frame_saved_reg *
 
 extern const struct sparc_fpregmap sparc64_bsd_fpregmap;
 
+extern void sparc64_forget_process (pid_t pid);
+
 #endif /* sparc64-tdep.h */
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index 6b22498..77f2727 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2017-08-07  Weimin Pan  <weimin.pan@oracle.com>
+
+	* gdb.arch/sparc64-adi.exp: New file.
+	* gdb.arch/sparc64-adi.c: New file.
+
 2017-07-09  Tom Tromey  <tom@tromey.com>
 
 	* gdb.dwarf2/shortpiece.exp: New file.
diff --git a/gdb/testsuite/gdb.arch/sparc64-adi.c b/gdb/testsuite/gdb.arch/sparc64-adi.c
new file mode 100755
index 0000000..704fe26
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/sparc64-adi.c
@@ -0,0 +1,145 @@
+/* Application Data Integrity (ADI) test in sparc64.
+
+   Copyright 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 <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <pthread.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <sys/errno.h>
+#include <sys/utsname.h>
+#include <sys/param.h>
+#include <malloc.h>
+#include <string.h>
+#include <signal.h>
+#include <sys/shm.h>
+#include <errno.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <poll.h>
+#include <setjmp.h>
+#include "adi.h"
+
+#define	ONEKB		1024
+#define PAT 		0xdeadbeaf
+
+#define MAPSIZE 8192
+#define SHMSIZE 102400
+#ifndef PROT_ADI
+#define PROT_ADI 0x10
+#endif
+
+static int
+memory_fill (char *addr, size_t size, int pattern)
+{
+  long *aligned_addr = (long *) addr;
+  long i;
+  for (i = 0; i < size / sizeof (long); i += ONEKB) 
+    { 
+      *aligned_addr = pattern; 
+      aligned_addr = aligned_addr + ONEKB;
+    }
+  return (0);
+}
+
+int main ()
+{
+  char *haddr;
+  caddr_t vaddr;
+  int	version;
+
+  /* Test ISM. */
+  int shmid = shmget (IPC_PRIVATE, SHMSIZE, IPC_CREAT | 0666);
+  if (shmid == -1) 
+    exit(1);
+  char *shmaddr = (char *)shmat (shmid, NULL, 0x666 | SHM_RND);
+  if (shmaddr == (char *)-1) 
+    { 
+      shmctl (shmid, IPC_RMID, NULL); 
+      exit(1);
+    }
+  /* Enable ADI on ISM segment. */
+  if (mprotect (shmaddr, SHMSIZE, PROT_READ|PROT_WRITE|PROT_ADI)) 
+    { 
+      perror ("mprotect failed"); 
+      goto err_out; 
+    }
+  if (memory_fill (shmaddr, SHMSIZE, PAT) != 0) /* line breakpoint here */
+    {
+      exit(1); 
+    }
+  adi_clr_version (shmaddr, SHMSIZE);
+  caddr_t vshmaddr = adi_set_version (shmaddr, SHMSIZE, 0x8);
+  if (vshmaddr == 0) 
+    exit(1);
+  /* Test mmap. */ 
+  int fd = open ("/dev/zero", O_RDWR);
+  if (fd < 0)
+    exit(1);
+  char *maddr = (char *)mmap (NULL, MAPSIZE, PROT_READ|PROT_WRITE, 
+                              MAP_PRIVATE, fd, 0);
+  if (maddr == (char *)-1) 
+    exit(1); 
+  /* Enable ADI. */
+  if (mprotect (shmaddr, MAPSIZE, PROT_READ|PROT_WRITE|PROT_ADI)) 
+    { 
+      perror ("mprotect failed"); 
+      goto err_out;
+   
+    }
+  if (memory_fill (maddr, MAPSIZE, PAT) != 0) 
+    exit(1); 
+  caddr_t vmaddr = adi_set_version (maddr, MAPSIZE, 0x8);
+
+  /* Test heap. */
+  haddr = (char*) memalign (MAPSIZE, MAPSIZE);
+  /* Enable ADI. */
+  if (mprotect (shmaddr, MAPSIZE, PROT_READ|PROT_WRITE|PROT_ADI)) 
+    { 
+      perror ("mprotect failed"); 
+      goto err_out;
+    }
+
+  if (memory_fill (haddr, MAPSIZE, PAT) != 0) 
+    exit(1);
+  adi_clr_version (haddr, MAPSIZE);
+  /* Set some ADP version number. */
+  caddr_t vaddr1, vaddr2, vaddr3, vaddr4;
+  vaddr = adi_set_version (haddr, 64*2, 0x8);
+  vaddr1 = adi_set_version (haddr+64*2, 64*2, 0x9);
+  vaddr2 = adi_clr_version (haddr+64*4, 64*2);
+  vaddr3 = adi_set_version (haddr+64*6, 64*2, 0xa);
+  vaddr4 = adi_set_version (haddr+64*8, 64*10, 0x3);
+  if (vaddr == 0) 
+    exit(1);
+  char *versioned_p = vaddr;
+  *versioned_p = 'a';
+  char *uvp = haddr;	// unversioned pointer
+  *uvp = 'b';		// version mismatch trap
+
+  return (0);
+err_out: 
+  if (shmdt ((const void *)shmaddr) != 0) 
+    perror ("Detach failure");
+  shmctl (shmid, IPC_RMID, NULL);
+  exit (1);
+}
diff --git a/gdb/testsuite/gdb.arch/sparc64-adi.exp b/gdb/testsuite/gdb.arch/sparc64-adi.exp
new file mode 100644
index 0000000..410bcf9
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/sparc64-adi.exp
@@ -0,0 +1,53 @@
+# Copyright 2017 Free Software Foundation, Inc.
+
+# 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/>.
+
+# This file is part of the gdb testsuite.
+
+# Basic tests of examining/assigning ADI version tags, and reporting 
+# precise mismatch.
+
+if ![istarget "sparc64*-*-linux*"] then {
+    verbose "Skipping sparc64 ADI test."
+    return 0
+}
+
+standard_testfile
+
+if { [prepare_for_testing "failed to prepare" $testfile $srcfile \
+          [list debug libs=-ladi]] } {
+    return -1
+}
+
+if ![runto_main] then {
+    untested "could not run to main"
+    return -1
+}
+
+gdb_test "break [gdb_get_line_number "line breakpoint here"]" \
+         "Breakpoint .* at .*${srcfile}.*" \
+         "set line breakpoint in main"
+gdb_continue_to_breakpoint "continue to line breakpoint in main"
+
+##########################################
+set newadi "7"
+gdb_test "adi x shmaddr" "${hex}00:\t0" "examine ADI"
+gdb_test_no_output "adi a/100 shmaddr=${newadi}" "assign ADI"
+gdb_test "adi x/100 shmaddr" "${hex}00:\t${newadi} ${newadi}" \
+         "examine new ADI"
+gdb_test_no_output "adi a/100 shmaddr=0x0" "reset ADI"
+gdb_test "continue" \
+         [multi_line "Program received signal SIGSEGV, Segmentation fault.*" \
+                     "ADI precise mismatch while accessing address $hex.*" ] \
+	"continue to sigsegv"
