linux: Collect fxsave instead of fsave in ThreadInfo

Bug: crashpad:30
Change-Id: Ib4abf0ad60b792c8241b28e6b5e47970fdfcf451
Reviewed-on: https://chromium-review.googlesource.com/537532
Reviewed-by: Mark Mentovai <mark@chromium.org>
Commit-Queue: Joshua Peraza <jperaza@chromium.org>
This commit is contained in:
Joshua Peraza 2017-06-15 15:51:41 -07:00 committed by Commit Bot
parent 63ccbd0e4c
commit d3e4f09742
2 changed files with 73 additions and 47 deletions

View File

@ -30,6 +30,34 @@ namespace crashpad {
namespace {
#if defined(ARCH_CPU_X86_FAMILY)
template <typename Destination>
bool GetRegisterSet(pid_t tid, int set, Destination* dest) {
iovec iov;
iov.iov_base = dest;
iov.iov_len = sizeof(*dest);
if (ptrace(PTRACE_GETREGSET, tid, reinterpret_cast<void*>(set), &iov) != 0) {
PLOG(ERROR) << "ptrace";
return false;
}
if (iov.iov_len != sizeof(*dest)) {
LOG(ERROR) << "Unexpected registers size";
return false;
}
return true;
}
bool GetFloatingPointRegisters32(pid_t tid, FloatContext* context) {
return GetRegisterSet(tid, NT_PRXFPREG, &context->f32.fxsave);
}
bool GetFloatingPointRegisters64(pid_t tid, FloatContext* context) {
return GetRegisterSet(tid, NT_PRFPREG, &context->f64.fxsave);
}
#elif defined(ARCH_CPU_ARM_FAMILY)
#if defined(ARCH_CPU_ARMEL)
// PTRACE_GETREGSET, introduced in Linux 2.6.34 (2225a122ae26), requires kernel
// support enabled by HAVE_ARCH_TRACEHOOK. This has been set for x86 (including
@ -77,7 +105,6 @@ bool GetFloatingPointRegistersLegacy(pid_t tid, FloatContext* context) {
}
#endif // ARCH_CPU_ARMEL
#if defined(ARCH_CPU_ARM_FAMILY)
// Normally, the Linux kernel will copy out register sets according to the size
// of the struct that contains them. Tracing a 32-bit ARM process running in
// compatibility mode on a 64-bit ARM cpu will only copy data for the number of
@ -163,7 +190,9 @@ bool GetFloatingPointRegisters64(pid_t tid, FloatContext* context) {
}
return true;
}
#endif // ARCH_CPU_ARM_FAMILY
#else
#error Port.
#endif // ARCH_CPU_X86_FAMILY
} // namespace
@ -241,31 +270,8 @@ size_t ThreadInfo::GetGeneralPurposeRegistersAndLength(ThreadContext* context) {
bool ThreadInfo::GetFloatingPointRegisters(FloatContext* context) {
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
#if defined(ARCH_CPU_X86_FAMILY)
iovec iov;
iov.iov_base = context;
iov.iov_len = sizeof(*context);
if (ptrace(
PTRACE_GETREGSET, tid_, reinterpret_cast<void*>(NT_PRFPREG), &iov) !=
0) {
PLOG(ERROR) << "ptrace";
return false;
}
if (is_64_bit_ && iov.iov_len == sizeof(context->f64)) {
return true;
}
if (!is_64_bit_ && iov.iov_len == sizeof(context->f32)) {
return true;
}
LOG(ERROR) << "Unexpected registers size";
return false;
#elif defined(ARCH_CPU_ARM_FAMILY)
return is_64_bit_ ? GetFloatingPointRegisters64(tid_, context)
: GetFloatingPointRegisters32(tid_, context);
#else
#error Port.
#endif // ARCH_CPU_X86_FAMILY
}
bool ThreadInfo::GetThreadArea(LinuxVMAddress* address) {

View File

@ -27,6 +27,10 @@
#include "util/misc/initialization_state_dcheck.h"
#include "util/numeric/int128.h"
#if defined(OS_ANDROID)
#include <android/api-level.h>
#endif
namespace crashpad {
//! \brief The set of general purpose registers for an architecture family.
@ -140,15 +144,22 @@ union FloatContext {
//! architecture.
struct f32 {
#if defined(ARCH_CPU_X86_FAMILY)
// Reflects user_fpregs_struct in sys/user.h.
uint32_t cwd;
uint32_t swd;
uint32_t twd;
uint32_t fip;
uint32_t fcs;
uint32_t foo;
uint32_t fos;
uint32_t st_space[20];
// Reflects user_fpxregs_struct in sys/user.h
struct fxsave {
uint16_t cwd;
uint16_t swd;
uint16_t twd;
uint16_t fop;
uint32_t fip;
uint32_t fcs;
uint32_t foo;
uint32_t fos;
uint32_t mxcsr;
uint32_t reserved;
uint32_t st_space[32];
uint32_t xmm_space[32];
uint32_t padding[56];
} fxsave;
#elif defined(ARCH_CPU_ARM_FAMILY)
// Reflects user_fpregs in sys/user.h.
struct fpregs {
@ -184,17 +195,20 @@ union FloatContext {
//! architecture.
struct f64 {
#if defined(ARCH_CPU_X86_FAMILY)
uint16_t cwd;
uint16_t swd;
uint16_t ftw;
uint16_t fop;
uint64_t rip;
uint64_t rdp;
uint32_t mxcsr;
uint32_t mxcr_mask;
uint32_t st_space[32];
uint32_t xmm_space[64];
uint32_t padding[24];
// Refelects user_fpregs_struct in sys/user.h
struct fxsave {
uint16_t cwd;
uint16_t swd;
uint16_t ftw;
uint16_t fop;
uint64_t rip;
uint64_t rdp;
uint32_t mxcsr;
uint32_t mxcr_mask;
uint32_t st_space[32];
uint32_t xmm_space[64];
uint32_t padding[24];
} fxsave;
#elif defined(ARCH_CPU_ARM_FAMILY)
uint128_struct vregs[32];
uint32_t fpsr;
@ -206,9 +220,15 @@ union FloatContext {
} f64;
#if defined(ARCH_CPU_X86)
static_assert(sizeof(f32) == sizeof(user_fpregs_struct), "Size mismatch");
#if defined(OS_ANDROID) && __ANDROID_API__ <= 19
using NativeFpxregs = user_fxsr_struct;
#else
using NativeFpxregs = user_fpxregs_struct;
#endif // OS_ANDROID
static_assert(sizeof(f32::fxsave) == sizeof(NativeFpxregs), "Size mismatch");
#elif defined(ARCH_CPU_X86_64)
static_assert(sizeof(f64) == sizeof(user_fpregs_struct), "Size mismatch");
static_assert(sizeof(f64::fxsave) == sizeof(user_fpregs_struct),
"Size mismatch");
#elif defined(ARCH_CPU_ARMEL)
static_assert(sizeof(f32::fpregs) == sizeof(user_fpregs), "Size mismatch");
static_assert(sizeof(f32::vfp) == sizeof(user_vfp), "Size mismatch");