[PATCH v2] gdb: ADI support

Wei-min Pan weimin.pan@oracle.com
Tue Jun 20 17:50:00 GMT 2017


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.




More information about the Gdb-patches mailing list