diff options
author | Luis Machado <luis.machado@linaro.org> | 2021-11-29 09:19:39 -0300 |
---|---|---|
committer | Luis Machado <luis.machado@linaro.org> | 2021-12-20 10:54:49 -0300 |
commit | 3f6d78d98442668ff8685864a7599d905412203f (patch) | |
tree | ffb9b3750fd95242d3a02573b0ddcda00d11908f /gdbserver | |
parent | 01ae9258509e29d4f79511aba5ffe3d4e9a6af57 (diff) | |
download | gdb-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.cc | 80 | ||||
-rw-r--r-- | gdbserver/linux-low.cc | 21 | ||||
-rw-r--r-- | gdbserver/linux-low.h | 9 |
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 |