[PATCH v2 16/24] AArch64: Report tag violation error information

Luis Machado via Gdb-patches
2020-10-22T20:01:52Z

Whenever a memory tag violation occurs, we get a SIGSEGV. Additional
information can be obtained through the siginfo data structure.

For AArch64 the Linux kernel may expose the fault address and tag
information, if we have a synchronous event. Otherwise there is
no fault address available.

gdb/ChangeLog:

YYYY-MM-DD Luis Machado <luis.machado@linaro.org>

* aarch64-linux-tdep.c
(aarch64_linux_report_signal_info): New function.
(aarch64_linux_init_abi): Register
aarch64_linux_report_signal_info as the report_signal_info hook.
* arch/aarch64-linux.h (SEGV_MTEAERR): Define.
(SEGV_MTESERR): Define.
---
gdb/aarch64-linux-tdep.c | 64 ++++++++++++++++++++++++++++++++++++
gdb/arch/aarch64-mte-linux.h | 6 ++++
2 files changed, 70 insertions(+)

diff --git a/gdb/aarch64-linux-tdep.c b/gdb/aarch64-linux-tdep.c
index 7ae41fc098..0084717c0e 100644
--- a/gdb/aarch64-linux-tdep.c
+++ b/gdb/aarch64-linux-tdep.c
@@ -1626,6 +1626,67 @@ aarch64_linux_memtag_to_string (struct gdbarch *gdbarch,
return string_printf ("0x%s", phex_nz (tag, sizeof (tag)));
}

+/* AArch64 Linux implementation of the report_signal_info gdbarch
+ hook. Displays information about possible memory tag violations. */
+
+static void
+aarch64_linux_report_signal_info (struct gdbarch *gdbarch,
+ struct ui_out *uiout,
+ enum gdb_signal siggnal)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ if (!tdep->has_mte () || siggnal != GDB_SIGNAL_SEGV)
+ return;
+
+ CORE_ADDR fault_addr = 0;
+ long si_code = 0;
+
+ try
+ {
+ /* Sigcode tells us if the segfault is actually a memory tag
+ violation. */
+ si_code = parse_and_eval_long ("$_siginfo.si_code\n");
+
+ fault_addr
+ = parse_and_eval_long ("$_siginfo._sifields._sigfault.si_addr");
+ }
+ catch (const gdb_exception &exception)
+ {
+ return;
+ }
+
+ /* If this is not a memory tag violation, just return. */
+ if (si_code != SEGV_MTEAERR && si_code != SEGV_MTESERR)
+ return;
+
+ uiout->text ("\n");
+
+ uiout->field_string ("sigcode-meaning", _("Memory tag violation"));
+
+ /* For synchronous faults, show additional information. */
+ if (si_code == SEGV_MTESERR)
+ {
+ uiout->text (_(" while accessing address "));
+ uiout->field_core_addr ("fault-addr", gdbarch, fault_addr);
+ uiout->text ("\n");
+
+ CORE_ADDR atag;
+ if (aarch64_linux_get_atag (fault_addr, &atag) != 0)
+ uiout->text (_("Allocation tag unavailable"));
+ else
+ {
+ uiout->text (_("Allocation tag "));
+ uiout->field_core_addr ("allocation-tag", gdbarch, atag);
+ }
+ }
+ else
+ {
+ uiout->text ("\n");
+ uiout->text (_("Fault address unavailable"));
+ }
+}
+
static void
aarch64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
{
@@ -1706,6 +1767,9 @@ aarch64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)

/* Register a hook for converting a memory tag to a string. */
set_gdbarch_memtag_to_string (gdbarch, aarch64_linux_memtag_to_string);
+
+ set_gdbarch_report_signal_info (gdbarch,
+ aarch64_linux_report_signal_info);
}

/* Initialize the aarch64_linux_record_tdep. */
diff --git a/gdb/arch/aarch64-mte-linux.h b/gdb/arch/aarch64-mte-linux.h
index 5c5783f28b..a5a980ed49 100644
--- a/gdb/arch/aarch64-mte-linux.h
+++ b/gdb/arch/aarch64-mte-linux.h
@@ -35,6 +35,12 @@
#define MTE_LOGICAL_TAG_START_BIT 56
#define MTE_LOGICAL_MAX_VALUE 0xf

+/* Memory tagging definitions. */
+#ifndef SEGV_MTEAERR
+# define SEGV_MTEAERR 8
+# define SEGV_MTESERR 9
+#endif
+
/* Return the number of tag granules in the memory range
[ADDR, ADDR + LEN) given GRANULE_SIZE. */
extern size_t get_tag_granules (CORE_ADDR addr, size_t len,
--
2.17.1