From 49295e420a37c05e62acbc4b1b272820d6ff0247 Mon Sep 17 00:00:00 2001 From: Luis Machado Date: Mon, 29 Nov 2021 09:19:39 -0300 Subject: [PATCH] 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 --- gdbserver/linux-aarch64-low.cc | 9 +++++++-- gdbserver/linux-low.cc | 21 +++++++++++++++++++++ gdbserver/linux-low.h | 9 ++++++++- 3 files changed, 36 insertions(+), 3 deletions(-) diff --git a/gdbserver/linux-aarch64-low.cc b/gdbserver/linux-aarch64-low.cc index b8929ef4bab..131c48ecdd3 100644 --- a/gdbserver/linux-aarch64-low.cc +++ b/gdbserver/linux-aarch64-low.cc @@ -816,7 +816,9 @@ static struct regset_info aarch64_regsets[] = /* FIXME-Morello: Fixup the register set size. */ { PTRACE_GETREGSET, PTRACE_SETREGSET, NT_ARM_MORELLO, 0, OPTIONAL_REGS, - aarch64_fill_cregset, aarch64_store_cregset }, + aarch64_fill_cregset, aarch64_store_cregset, nullptr, + "cheri.ptrace_forge_cap" + }, NULL_REGSET }; @@ -874,7 +876,10 @@ aarch64_adjust_register_sets (const struct aarch64_features &features) break; case NT_ARM_MORELLO: if (features.capability) - regset->size = AARCH64_LINUX_CREGS_SIZE; + { + regset->size = AARCH64_LINUX_CREGS_SIZE; + regset->sysctl_write_should_warn = true; + } break; default: gdb_assert_not_reached ("Unknown register set found."); diff --git a/gdbserver/linux-low.cc b/gdbserver/linux-low.cc index 2ab3a8794c1..56be6e8edc6 100644 --- a/gdbserver/linux-low.cc +++ b/gdbserver/linux-low.cc @@ -5025,6 +5025,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)"); @@ -5032,6 +5042,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 9edf4468650..1f98039e485 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 -- 2.47.2