This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
Re: [PATCH v2] gdb: ADI support
- From: Yao Qi <qiyaoltc at gmail dot com>
- To: Weimin Pan <weimin dot pan at oracle dot com>
- Cc: gdb-patches at sourceware dot org
- Date: Tue, 20 Jun 2017 14:35:18 +0100
- Subject: Re: [PATCH v2] gdb: ADI support
- Authentication-results: sourceware.org; auth=none
- References: <1497655802-111684-1-git-send-email-weimin.pan@oracle.com>
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 (¤t_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 (¤t_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?
--
Yao (齐尧)