linux_ptrace_dumper: Handle ARMEABI binaries on ARM64 kernels
For ARM32 binaries running on ARM64 Linux (kernel) reading of FP registers fails. It's guarded for Android as well as softap platforms, but other ARM platforms can suffer from this issue. The ARMEABI linux_ptrace_dumper_unittest fails on system that runs under ARM64 kernel. In order to mitigate the issue, we adding a VFP registers read. The Breakpad does not support include of VFP registers into a minidump file, so that read is noop for the backend, but just a fix for broken systems. Bug: internal 322205293 Test: Run linux_ptrace_dumper_unittest on following [userland:kernel] combinations: armeabi-hardfp:armeabi armeabi-softfp:armeabi armeabi-hardfp:aarch64 aarch64:aarch64 Signed-off-by: Volodymyr Riazantsev <riazantsevv@google.com> Change-Id: I0709ae9a7ff913340ebc89de703ab2cb9c823b14 Reviewed-on: https://chromium-review.googlesource.com/c/breakpad/breakpad/+/5247149 Reviewed-by: Joshua Peraza <jperaza@chromium.org>
This commit is contained in:
parent
6551ac3632
commit
5a0e1e34b0
1 changed files with 68 additions and 2 deletions
|
@ -62,6 +62,20 @@
|
|||
#include "common/linux/linux_libc_support.h"
|
||||
#include "third_party/lss/linux_syscall_support.h"
|
||||
|
||||
#if defined(__arm__)
|
||||
/*
|
||||
* https://elixir.bootlin.com/linux/v6.8-rc2/source/arch/arm/include/asm/user.h#L81
|
||||
* User specific VFP registers. If only VFPv2 is present, registers 16 to 31
|
||||
* are ignored by the ptrace system call and the signal handler.
|
||||
*/
|
||||
typedef struct user_vfp {
|
||||
unsigned long long fpregs[32];
|
||||
unsigned long fpscr;
|
||||
// Kernel just appends fpscr to the copy of fpregs, so we need to force
|
||||
// compiler to build the same layout.
|
||||
} __attribute__((packed, aligned(4))) user_vfp_t;
|
||||
#endif // defined(__arm__)
|
||||
|
||||
// Suspends a thread by attaching to it.
|
||||
static bool SuspendThread(pid_t pid) {
|
||||
// This may fail if the thread has just died or debugged.
|
||||
|
@ -152,6 +166,24 @@ bool LinuxPtraceDumper::CopyFromProcess(void* dest, pid_t child,
|
|||
return true;
|
||||
}
|
||||
|
||||
// This read VFP registers via either PTRACE_GETREGSET or PTRACE_GETREGS
|
||||
#if defined(__arm__)
|
||||
static bool ReadVFPRegistersArm32(pid_t tid, struct iovec* io) {
|
||||
#ifdef PTRACE_GETREGSET
|
||||
if (sys_ptrace(PTRACE_GETREGSET, tid, reinterpret_cast<void*>(NT_ARM_VFP),
|
||||
io) == 0 && io->iov_len == sizeof(user_vfp_t)) {
|
||||
return true;
|
||||
}
|
||||
#endif // PTRACE_GETREGSET
|
||||
#ifdef PTRACE_GETVFPREGS
|
||||
if (sys_ptrace(PTRACE_GETVFPREGS, tid, nullptr, io->iov_base) == 0) {
|
||||
return true;
|
||||
}
|
||||
#endif // PTRACE_GETVFPREGS
|
||||
return false;
|
||||
}
|
||||
#endif // defined(__arm__)
|
||||
|
||||
bool LinuxPtraceDumper::ReadRegisterSet(ThreadInfo* info, pid_t tid)
|
||||
{
|
||||
#ifdef PTRACE_GETREGSET
|
||||
|
@ -163,8 +195,25 @@ bool LinuxPtraceDumper::ReadRegisterSet(ThreadInfo* info, pid_t tid)
|
|||
|
||||
info->GetFloatingPointRegisters(&io.iov_base, &io.iov_len);
|
||||
if (sys_ptrace(PTRACE_GETREGSET, tid, (void*)NT_FPREGSET, (void*)&io) == -1) {
|
||||
// We are going to check if we can read VFP registers on ARM32.
|
||||
// Currently breakpad does not support VFP registers to be a part of minidump,
|
||||
// so this is only to confirm that we can actually read FP registers.
|
||||
// That is needed to prevent a false-positive minidumps failures with ARM32
|
||||
// binaries running on top of ARM64 Linux kernels.
|
||||
#if defined(__arm__)
|
||||
switch (errno) {
|
||||
case EIO:
|
||||
case EINVAL:
|
||||
user_vfp vfp;
|
||||
struct iovec io;
|
||||
io.iov_base = &vfp;
|
||||
io.iov_len = sizeof(vfp);
|
||||
return ReadVFPRegistersArm32(tid, &io);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
#endif // defined(__arm__)
|
||||
}
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
|
@ -194,8 +243,25 @@ bool LinuxPtraceDumper::ReadRegisters(ThreadInfo* info, pid_t tid) {
|
|||
void* fp_addr;
|
||||
info->GetFloatingPointRegisters(&fp_addr, NULL);
|
||||
if (sys_ptrace(PTRACE_GETFPREGS, tid, NULL, fp_addr) == -1) {
|
||||
// We are going to check if we can read VFP registers on ARM32.
|
||||
// Currently breakpad does not support VFP registers to be a part of minidump,
|
||||
// so this is only to confirm that we can actually read FP registers.
|
||||
// That is needed to prevent a false-positive minidumps failures with ARM32
|
||||
// binaries running on top of ARM64 Linux kernels.
|
||||
#if defined(__arm__)
|
||||
switch (errno) {
|
||||
case EIO:
|
||||
case EINVAL:
|
||||
user_vfp vfp;
|
||||
struct iovec io;
|
||||
io.iov_base = &vfp;
|
||||
io.iov_len = sizeof(vfp);
|
||||
return ReadVFPRegistersArm32(tid, &io);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
#endif // defined(__arm__)
|
||||
}
|
||||
#endif // !(defined(__ANDROID__) && defined(__ARM_EABI__))
|
||||
#endif // !defined(__SOFTFP__)
|
||||
return true;
|
||||
|
|
Loading…
Reference in a new issue