aboutsummaryrefslogtreecommitdiff
path: root/gdbserver
diff options
context:
space:
mode:
authorLuis Machado <luis.machado@linaro.org>2021-11-29 09:19:39 -0300
committerLuis Machado <luis.machado@linaro.org>2021-12-20 10:54:49 -0300
commit3f6d78d98442668ff8685864a7599d905412203f (patch)
treeffb9b3750fd95242d3a02573b0ddcda00d11908f /gdbserver
parent01ae9258509e29d4f79511aba5ffe3d4e9a6af57 (diff)
downloadgdb-3f6d78d98442668ff8685864a7599d905412203f.zip
gdb-3f6d78d98442668ff8685864a7599d905412203f.tar.gz
gdb-3f6d78d98442668ff8685864a7599d905412203f.tar.bz2
Handle C regset write warnings better in GDBServer
GDBServer handles register reads/writes a bit differently compared to GDB. Since C register writes are only allowed with cheri.ptrace_forge_cap=1, GDBServer will keep issuing warnings if such setting is 0. This patch improves it by issuing a single more helpful warning to the user. If cheri.ptrace_forge_cap is flipped, the warning will be issued again appropriately to remind the user about it. Bug-ID: https://git.morello-project.org/morello/binutils-gdb/-/issues/5
Diffstat (limited to 'gdbserver')
-rw-r--r--gdbserver/linux-aarch64-low.cc80
-rw-r--r--gdbserver/linux-low.cc21
-rw-r--r--gdbserver/linux-low.h9
3 files changed, 74 insertions, 36 deletions
diff --git a/gdbserver/linux-aarch64-low.cc b/gdbserver/linux-aarch64-low.cc
index 94f2fda..8531378 100644
--- a/gdbserver/linux-aarch64-low.cc
+++ b/gdbserver/linux-aarch64-low.cc
@@ -691,39 +691,6 @@ aarch64_target::low_new_fork (process_info *parent,
*child->priv->arch_private = *parent->priv->arch_private;
}
-/* Matches HWCAP_PACA in kernel header arch/arm64/include/uapi/asm/hwcap.h. */
-#define AARCH64_HWCAP_PACA (1 << 30)
-
-/* Implementation of linux target ops method "low_arch_setup". */
-
-void
-aarch64_target::low_arch_setup ()
-{
- unsigned int machine;
- int is_elf64;
- int tid;
-
- tid = lwpid_of (current_thread);
-
- is_elf64 = linux_pid_exe_is_elf_64_file (tid, &machine);
-
- if (is_elf64)
- {
- uint64_t vq = aarch64_sve_get_vq (tid);
- unsigned long hwcap = linux_get_hwcap (8);
- unsigned long hwcap2 = linux_get_hwcap2 (8);
- bool pauth_p = hwcap & AARCH64_HWCAP_PACA;
- bool capability_p = hwcap2 & HWCAP2_MORELLO;
-
- current_process ()->tdesc = aarch64_linux_read_description (vq, pauth_p,
- capability_p);
- }
- else
- current_process ()->tdesc = aarch32_linux_read_description ();
-
- aarch64_linux_get_debug_reg_capacity (lwpid_of (current_thread));
-}
-
/* Wrapper for aarch64_sve_regs_copy_to_reg_buf. */
static void
@@ -755,7 +722,9 @@ static struct regset_info aarch64_regsets[] =
/* FIXME-Morello: Fixup the register set size. */
{ PTRACE_GETREGSET, PTRACE_SETREGSET, NT_ARM_MORELLO,
AARCH64_LINUX_CREGS_SIZE, OPTIONAL_REGS,
- aarch64_fill_cregset, aarch64_store_cregset },
+ aarch64_fill_cregset, aarch64_store_cregset, nullptr,
+ "cheri.ptrace_forge_cap"
+ },
NULL_REGSET
};
@@ -788,7 +757,9 @@ static struct regset_info aarch64_sve_regsets[] =
/* FIXME-Morello: Fixup the register set size. */
{ PTRACE_GETREGSET, PTRACE_SETREGSET, NT_ARM_MORELLO,
AARCH64_LINUX_CREGS_SIZE, OPTIONAL_REGS,
- aarch64_fill_cregset, aarch64_store_cregset },
+ aarch64_fill_cregset, aarch64_store_cregset, nullptr,
+ "cheri.ptrace_forge_cap"
+ },
NULL_REGSET
};
@@ -806,6 +777,45 @@ static struct regs_info regs_info_aarch64_sve =
&aarch64_sve_regsets_info,
};
+/* Matches HWCAP_PACA in kernel header arch/arm64/include/uapi/asm/hwcap.h. */
+#define AARCH64_HWCAP_PACA (1 << 30)
+
+/* Implementation of linux target ops method "low_arch_setup". */
+
+void
+aarch64_target::low_arch_setup ()
+{
+ unsigned int machine;
+ int is_elf64;
+ int tid;
+
+ tid = lwpid_of (current_thread);
+
+ is_elf64 = linux_pid_exe_is_elf_64_file (tid, &machine);
+
+ if (is_elf64)
+ {
+ uint64_t vq = aarch64_sve_get_vq (tid);
+ unsigned long hwcap = linux_get_hwcap (8);
+ unsigned long hwcap2 = linux_get_hwcap2 (8);
+ bool pauth_p = hwcap & AARCH64_HWCAP_PACA;
+ bool capability_p = hwcap2 & HWCAP2_MORELLO;
+
+ current_process ()->tdesc = aarch64_linux_read_description (vq, pauth_p,
+ capability_p);
+
+ /* Re-enable warnings for register sets with sysctl settings. */
+ aarch64_regsets[4].sysctl_write_should_warn = true;
+ aarch64_sve_regsets[4].sysctl_write_should_warn = true;
+ }
+ else
+ current_process ()->tdesc = aarch32_linux_read_description ();
+
+ aarch64_linux_get_debug_reg_capacity (lwpid_of (current_thread));
+}
+
+
+
/* Implementation of linux target ops method "get_regs_info". */
const regs_info *
diff --git a/gdbserver/linux-low.cc b/gdbserver/linux-low.cc
index 24509f1..7fe0be3 100644
--- a/gdbserver/linux-low.cc
+++ b/gdbserver/linux-low.cc
@@ -5242,6 +5242,16 @@ regsets_store_inferior_registers (struct regsets_info *regsets_info,
free (buf);
return 0;
}
+ else if (errno == EPERM && regset->sysctl_write_permission != nullptr)
+ {
+ if (regset->sysctl_write_should_warn)
+ {
+ warning ("Unable to store registers.\n"
+ "Please run \"sysctl %s=1\".",
+ regset->sysctl_write_permission);
+ regset->sysctl_write_should_warn = false;
+ }
+ }
else
{
perror ("Warning: ptrace(regsets_store_inferior_registers)");
@@ -5249,6 +5259,17 @@ regsets_store_inferior_registers (struct regsets_info *regsets_info,
}
else if (regset->type == GENERAL_REGS)
saw_general_regs = 1;
+ else
+ {
+ /* We've succeeded in writing the registers. If this register set
+ has a sysctl permission flag and the warnings are disabled,
+ re-enable it so we can issue a warning next time the write
+ attempt fails. */
+ if (regset->sysctl_write_permission != nullptr
+ && !regset->sysctl_write_should_warn)
+ regset->sysctl_write_should_warn = true;
+ }
+
free (buf);
}
if (saw_general_regs)
diff --git a/gdbserver/linux-low.h b/gdbserver/linux-low.h
index bd6f402..503f23d 100644
--- a/gdbserver/linux-low.h
+++ b/gdbserver/linux-low.h
@@ -48,7 +48,7 @@ enum regset_type {
/* The arch's regsets array initializer must be terminated with a NULL
regset. */
#define NULL_REGSET \
- { 0, 0, 0, -1, (enum regset_type) -1, NULL, NULL }
+ { 0, 0, 0, -1, (enum regset_type) -1, nullptr, nullptr, nullptr, nullptr }
struct regset_info
{
@@ -60,6 +60,13 @@ struct regset_info
enum regset_type type;
regset_fill_func fill_function;
regset_store_func store_function;
+ /* The name of the sysctl flag that controls read/write permission for this
+ particular register set. If it is nullptr, it means there is no such
+ switch. */
+ const char *sysctl_read_permission = nullptr;
+ const char *sysctl_write_permission = nullptr;
+ bool sysctl_read_should_warn = true;
+ bool sysctl_write_should_warn = true;
};
/* Aggregation of all the supported regsets of a given