From 67649c61853108eb0c29703f6ff0db42e9d69f10 Mon Sep 17 00:00:00 2001 From: Andrew Ermakovich Date: Fri, 21 Apr 2017 18:41:24 +0300 Subject: [PATCH] Fixing breakpad on old linux kernel Try to read the trace's registers by PTRACE_GETREGS if kernel doesn't support PTRACE_GETREGSET. Bug: Change-Id: I881f3a868789747ca217f22a93370c6914881f9a Reviewed-on: https://chromium-review.googlesource.com/484479 Reviewed-by: Mike Frysinger --- .../minidump_writer/linux_ptrace_dumper.cc | 73 +++++++++++-------- .../minidump_writer/linux_ptrace_dumper.h | 9 +++ 2 files changed, 53 insertions(+), 29 deletions(-) diff --git a/src/client/linux/minidump_writer/linux_ptrace_dumper.cc b/src/client/linux/minidump_writer/linux_ptrace_dumper.cc index 30b8f3dd..f181bf92 100644 --- a/src/client/linux/minidump_writer/linux_ptrace_dumper.cc +++ b/src/client/linux/minidump_writer/linux_ptrace_dumper.cc @@ -149,6 +149,46 @@ bool LinuxPtraceDumper::CopyFromProcess(void* dest, pid_t child, return true; } +bool LinuxPtraceDumper::ReadRegisterSet(ThreadInfo* info, pid_t tid) +{ +#ifdef PTRACE_GETREGSET + struct iovec io; + info->GetGeneralPurposeRegisters(&io.iov_base, &io.iov_len); + if (sys_ptrace(PTRACE_GETREGSET, tid, (void*)NT_PRSTATUS, (void*)&io) == -1) { + return false; + } + + info->GetFloatingPointRegisters(&io.iov_base, &io.iov_len); + if (sys_ptrace(PTRACE_GETREGSET, tid, (void*)NT_FPREGSET, (void*)&io) == -1) { + return false; + } + return true; +#else + return false; +#endif +} + +bool LinuxPtraceDumper::ReadRegisters(ThreadInfo* info, pid_t tid) { + void* gp_addr; + info->GetGeneralPurposeRegisters(&gp_addr, NULL); + if (sys_ptrace(PTRACE_GETREGS, tid, NULL, gp_addr) == -1) { + return false; + } + +#if !(defined(__ANDROID__) && defined(__ARM_EABI__)) + // When running an arm build on an arm64 device, attempting to get the + // floating point registers fails. On Android, the floating point registers + // aren't written to the cpu context anyway, so just don't get them here. + // See http://crbug.com/508324 + void* fp_addr; + info->GetFloatingPointRegisters(&fp_addr, NULL); + if (sys_ptrace(PTRACE_GETFPREGS, tid, NULL, fp_addr) == -1) { + return false; + } +#endif + return true; +} + // Read thread info from /proc/$pid/status. // Fill out the |tgid|, |ppid| and |pid| members of |info|. If unavailable, // these members are set to -1. Returns true iff all three members are @@ -188,37 +228,12 @@ bool LinuxPtraceDumper::GetThreadInfoByIndex(size_t index, ThreadInfo* info) { if (info->ppid == -1 || info->tgid == -1) return false; -#ifdef PTRACE_GETREGSET - struct iovec io; - info->GetGeneralPurposeRegisters(&io.iov_base, &io.iov_len); - if (sys_ptrace(PTRACE_GETREGSET, tid, (void*)NT_PRSTATUS, (void*)&io) == -1) { - return false; + if (!ReadRegisterSet(info, tid)) { + if (!ReadRegisters(info, tid)) { + return false; + } } - info->GetFloatingPointRegisters(&io.iov_base, &io.iov_len); - if (sys_ptrace(PTRACE_GETREGSET, tid, (void*)NT_FPREGSET, (void*)&io) == -1) { - return false; - } -#else // PTRACE_GETREGSET - void* gp_addr; - info->GetGeneralPurposeRegisters(&gp_addr, NULL); - if (sys_ptrace(PTRACE_GETREGS, tid, NULL, gp_addr) == -1) { - return false; - } - -#if !(defined(__ANDROID__) && defined(__ARM_EABI__)) - // When running an arm build on an arm64 device, attempting to get the - // floating point registers fails. On Android, the floating point registers - // aren't written to the cpu context anyway, so just don't get them here. - // See http://crbug.com/508324 - void* fp_addr; - info->GetFloatingPointRegisters(&fp_addr, NULL); - if (sys_ptrace(PTRACE_GETFPREGS, tid, NULL, fp_addr) == -1) { - return false; - } -#endif -#endif // PTRACE_GETREGSET - #if defined(__i386) #if !defined(bit_FXSAVE) // e.g. Clang #define bit_FXSAVE bit_FXSR diff --git a/src/client/linux/minidump_writer/linux_ptrace_dumper.h b/src/client/linux/minidump_writer/linux_ptrace_dumper.h index 2ce834b0..cee58178 100644 --- a/src/client/linux/minidump_writer/linux_ptrace_dumper.h +++ b/src/client/linux/minidump_writer/linux_ptrace_dumper.h @@ -85,6 +85,15 @@ class LinuxPtraceDumper : public LinuxDumper { private: // Set to true if all threads of the crashed process are suspended. bool threads_suspended_; + + // Read the tracee's registers on kernel with PTRACE_GETREGSET support. + // Returns false if PTRACE_GETREGSET is not defined. + // Returns true on success. + bool ReadRegisterSet(ThreadInfo* info, pid_t tid); + + // Read the tracee's registers on kernel with PTRACE_GETREGS support. + // Returns true on success. + bool ReadRegisters(ThreadInfo* info, pid_t tid); }; } // namespace google_breakpad