diff --git a/gdbserver/linux-low.cc b/gdbserver/linux-low.cc index 39642705b0d..e8c4eb8a78d 100644 --- a/gdbserver/linux-low.cc +++ b/gdbserver/linux-low.cc @@ -5006,23 +5006,31 @@ regsets_fetch_inferior_registers (struct regsets_info *regsets_info, if (res < 0) { if (errno == EIO - || (errno == EINVAL && regset->type == OPTIONAL_REGS)) + || (errno == EINVAL + && (regset->type == OPTIONAL_REGS + || regset->type == OPTIONAL_RUNTIME_REGS))) { /* If we get EIO on a regset, or an EINVAL and the regset is - optional, do not try it again for this process mode. */ + optional, do not try it again for this process mode. + Even if the regset can be enabled at runtime it is safe + to deactivate the regset in case of EINVAL, as we know + the regset itself was the invalid argument of the ptrace + call which means that it's unsupported by the kernel. */ disable_regset (regsets_info, regset); } - else if (errno == ENODATA) + else if (errno == ENODATA + || (errno == ENODEV + && regset->type == OPTIONAL_RUNTIME_REGS) + || errno == ESRCH) { - /* ENODATA may be returned if the regset is currently - not "active". This can happen in normal operation, - so suppress the warning in this case. */ - } - else if (errno == ESRCH) - { - /* At this point, ESRCH should mean the process is - already gone, in which case we simply ignore attempts - to read its registers. */ + /* ENODATA or ENODEV may be returned if the regset is + currently not "active". For ENODEV we additionally check + if the register set is of type OPTIONAL_RUNTIME_REGS. + This can happen in normal operation, so suppress the + warning in this case. + ESRCH should mean the process is already gone at this + point, in which case we simply ignore attempts to read + its registers. */ } else { @@ -5104,12 +5112,26 @@ regsets_store_inferior_registers (struct regsets_info *regsets_info, if (res < 0) { if (errno == EIO - || (errno == EINVAL && regset->type == OPTIONAL_REGS)) + || (errno == EINVAL + && (regset->type == OPTIONAL_REGS + || regset->type == OPTIONAL_RUNTIME_REGS))) { /* If we get EIO on a regset, or an EINVAL and the regset is - optional, do not try it again for this process mode. */ + optional, do not try it again for this process mode. + Even if the regset can be enabled at runtime it is safe + to deactivate the regset in case of EINVAL, as we know + the regset itself was the invalid argument of the ptrace + call which means that it's unsupported by the kernel. */ disable_regset (regsets_info, regset); } + else if (errno == ENODEV + && regset->type == OPTIONAL_RUNTIME_REGS) + { + /* If we get ENODEV on a regset and the regset can be + enabled at runtime try it again for this process mode. + This can happen in normal operation, so suppress the + warning in this case. */ + } else if (errno == ESRCH) { /* At this point, ESRCH should mean the process is diff --git a/gdbserver/linux-low.h b/gdbserver/linux-low.h index e1c88ee0bb2..5710e49d950 100644 --- a/gdbserver/linux-low.h +++ b/gdbserver/linux-low.h @@ -42,7 +42,12 @@ enum regset_type { GENERAL_REGS, FP_REGS, EXTENDED_REGS, - OPTIONAL_REGS, /* Do not error if the regset cannot be accessed. */ + OPTIONAL_REGS, /* Do not error if the regset cannot be accessed. + Disable the regset instead. */ + OPTIONAL_RUNTIME_REGS, /* Some optional regsets can only be accessed + dependent on the execution flow. For such + access errors don't show a warning and don't + disable the regset. */ }; /* The arch's regsets array initializer must be terminated with a NULL