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 <vapier@chromium.org>
This commit is contained in:
Andrew Ermakovich 2017-04-21 18:41:24 +03:00 committed by Mike Frysinger
parent a9fca58305
commit 67649c6185
2 changed files with 53 additions and 29 deletions

View file

@ -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

View file

@ -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