linux, x86: Read floating point state via mcontext.fpptr

Floating-point content may not begin at the start of __fpregs_mem and
should be located via mcontext.fpptr, which may be `nullptr`.

Bug: crashpad:30
Change-Id: Ie3116339d79f6669d757618e9e592f8480dcdcba
Reviewed-on: https://chromium-review.googlesource.com/1001332
Reviewed-by: Scott Graham <scottmg@chromium.org>
Commit-Queue: Joshua Peraza <jperaza@chromium.org>
This commit is contained in:
Joshua Peraza 2018-04-09 11:50:13 -07:00 committed by Commit Bot
parent a3ba96c0d4
commit 914e7f76dd
5 changed files with 83 additions and 39 deletions

View File

@ -77,6 +77,8 @@ void InitializeCPUContextX86_NoFloatingPoint(
CPUContextX86* context) {
SET_GPRS32();
memset(&context->fxsave, 0, sizeof(context->fxsave));
context->dr0 = 0;
context->dr1 = 0;
context->dr2 = 0;
@ -152,6 +154,23 @@ void InitializeCPUContextX86_64(const SignalThreadContext64& thread_context,
context->dr7 = 0;
}
void InitializeCPUContextX86_64_NoFloatingPoint(
const SignalThreadContext64& thread_context,
CPUContextX86_64* context) {
SET_GPRS64();
memset(&context->fxsave, 0, sizeof(context->fxsave));
context->dr0 = 0;
context->dr1 = 0;
context->dr2 = 0;
context->dr3 = 0;
context->dr4 = 0;
context->dr5 = 0;
context->dr6 = 0;
context->dr7 = 0;
}
#elif defined(ARCH_CPU_ARM_FAMILY)
void InitializeCPUContextARM(const ThreadContext::t32_t& thread_context,
@ -195,6 +214,11 @@ void InitializeCPUContextARM_NoFloatingPoint(
context->lr = thread_context.lr;
context->pc = thread_context.pc;
context->cpsr = thread_context.cpsr;
memset(&context->fpa_regs, 0, sizeof(context->fpa_regs));
memset(&context->vfp_regs, 0, sizeof(context->vfp_regs));
context->have_fpa_regs = false;
context->have_vfp_regs = false;
}
void InitializeCPUContextARM64(const ThreadContext::t64_t& thread_context,
@ -218,6 +242,10 @@ void InitializeCPUContextARM64_NoFloatingPoint(
context->sp = thread_context.sp;
context->pc = thread_context.pc;
context->pstate = thread_context.pstate;
memset(&context->fpsimd, 0, sizeof(context->fpsimd));
context->fpsr = 0;
context->fpcr = 0;
}
void InitializeCPUContextARM64_OnlyFPSIMD(
@ -230,12 +258,6 @@ void InitializeCPUContextARM64_OnlyFPSIMD(
context->fpcr = float_context.fpcr;
}
void InitializeCPUContextARM64_ClearFPSIMD(CPUContextARM64* context) {
memset(context->fpsimd, 0, sizeof(context->fpsimd));
context->fpsr = 0;
context->fpcr = 0;
}
#endif // ARCH_CPU_X86_FAMILY
} // namespace internal

View File

@ -44,8 +44,7 @@ void InitializeCPUContextX86(const SignalThreadContext32& thread_context,
//! \brief Initializes GPR and debug state in a CPUContextX86 from a native
//! signal context structure on Linux.
//!
//! Floating point state is not initialized. Debug registers are initialized to
//! zero.
//! Floating point state and debug registers are initialized to zero.
//!
//! \param[in] thread_context The native thread context.
//! \param[out] context The CPUContextX86 structure to initialize.
@ -69,6 +68,17 @@ void InitializeCPUContextX86_64(const SignalThreadContext64& thread_context,
CPUContextX86_64* context);
//! \}
//! \brief Initializes GPR and debug state in a CPUContextX86_64 from a native
//! signal context structure on Linux.
//!
//! Floating point state and debug registers are initialized to zero.
//!
//! \param[in] thread_context The native thread context.
//! \param[out] context The CPUContextX86_64 structure to initialize.
void InitializeCPUContextX86_64_NoFloatingPoint(
const SignalThreadContext64& thread_context,
CPUContextX86_64* context);
#endif // ARCH_CPU_X86_FAMILY || DOXYGEN
#if defined(ARCH_CPU_ARM_FAMILY) || DOXYGEN
@ -86,7 +96,7 @@ void InitializeCPUContextARM(const ThreadContext::t32_t& thread_context,
//! \brief Initializes GPR state in a CPUContextARM from a native signal context
//! structure on Linux.
//!
//! Floating point state is not initialized.
//! Floating point state is initialized to zero.
//!
//! \param[in] thread_context The native thread context.
//! \param[out] context The CPUContextARM structure to initialize.
@ -107,7 +117,7 @@ void InitializeCPUContextARM64(const ThreadContext::t64_t& thread_context,
//! \brief Initializes GPR state in a CPUContextARM64 from a native context
//! structure on Linux.
//!
//! Floating point state is not initialized.
//! Floating point state is initialized to zero.
//!
//! \param[in] thread_context The native thread context.
//! \param[out] context The CPUContextARM64 structure to initialize.
@ -126,13 +136,6 @@ void InitializeCPUContextARM64_OnlyFPSIMD(
const SignalFPSIMDContext& float_context,
CPUContextARM64* context);
//! \brief Initializes FPSIMD state in a CPUContextARM64 to zero.
//!
//! General purpose registers are not initialized.
//!
//! \param[out] context The CPUContextARM64 structure to initialize.
void InitializeCPUContextARM64_ClearFPSIMD(CPUContextARM64* context);
#endif // ARCH_CPU_ARM_FAMILY || DOXYGEN
} // namespace internal

View File

@ -41,6 +41,7 @@ ExceptionSnapshotLinux::ExceptionSnapshotLinux()
ExceptionSnapshotLinux::~ExceptionSnapshotLinux() {}
#if defined(ARCH_CPU_X86_FAMILY)
template <>
bool ExceptionSnapshotLinux::ReadContext<ContextTraits32>(
ProcessReaderLinux* reader,
@ -54,26 +55,35 @@ bool ExceptionSnapshotLinux::ReadContext<ContextTraits32>(
context_.architecture = kCPUArchitectureX86;
context_.x86 = &context_union_.x86;
if (ucontext.fprs.magic == X86_FXSR_MAGIC) {
if (!reader->Memory()->Read(context_address +
offsetof(UContext<ContextTraits32>, fprs) +
offsetof(SignalFloatContext32, fxsave),
sizeof(CPUContextX86::Fxsave),
&context_.x86->fxsave)) {
if (!ucontext.mcontext.fpptr) {
InitializeCPUContextX86_NoFloatingPoint(ucontext.mcontext.gprs,
context_.x86);
return true;
}
SignalFloatContext32 fprs;
if (!reader->Memory()->Read(ucontext.mcontext.fpptr, sizeof(fprs), &fprs)) {
LOG(ERROR) << "Couldn't read float context";
return false;
}
if (fprs.magic == X86_FXSR_MAGIC) {
InitializeCPUContextX86_NoFloatingPoint(ucontext.mcontext.gprs,
context_.x86);
if (!reader->Memory()->Read(
ucontext.mcontext.fpptr + offsetof(SignalFloatContext32, fxsave),
sizeof(CPUContextX86::Fxsave),
&context_.x86->fxsave)) {
LOG(ERROR) << "Couldn't read fxsave";
return false;
}
InitializeCPUContextX86_NoFloatingPoint(ucontext.mcontext.gprs,
context_.x86);
} else if (fprs.magic == 0xffff) {
InitializeCPUContextX86(ucontext.mcontext.gprs, fprs, context_.x86);
} else {
if (ucontext.fprs.magic != 0xffff) {
LOG(ERROR) << "unexpected magic 0x" << std::hex << ucontext.fprs.magic;
return false;
}
InitializeCPUContextX86(
ucontext.mcontext.gprs, ucontext.fprs, context_.x86);
LOG(ERROR) << "unexpected magic 0x" << std::hex << fprs.magic;
return false;
}
return true;
}
@ -90,8 +100,19 @@ bool ExceptionSnapshotLinux::ReadContext<ContextTraits64>(
context_.architecture = kCPUArchitectureX86_64;
context_.x86_64 = &context_union_.x86_64;
InitializeCPUContextX86_64(
ucontext.mcontext.gprs, ucontext.fprs, context_.x86_64);
if (!ucontext.mcontext.fpptr) {
InitializeCPUContextX86_64_NoFloatingPoint(ucontext.mcontext.gprs,
context_.x86_64);
return true;
}
SignalFloatContext64 fprs;
if (!reader->Memory()->Read(ucontext.mcontext.fpptr, sizeof(fprs), &fprs)) {
LOG(ERROR) << "Couldn't read float context";
return false;
}
InitializeCPUContextX86_64(ucontext.mcontext.gprs, fprs, context_.x86_64);
return true;
}
@ -118,8 +139,6 @@ bool ExceptionSnapshotLinux::ReadContext<ContextTraits32>(
}
InitializeCPUContextARM_NoFloatingPoint(thread_context, dest_context);
dest_context->have_fpa_regs = false;
LinuxVMAddress reserved_address =
context_address + offsetof(UContext<ContextTraits32>, reserved);
if ((reserved_address & 7) != 0) {
@ -134,7 +153,6 @@ bool ExceptionSnapshotLinux::ReadContext<ContextTraits32>(
return false;
}
dest_context->have_vfp_regs = false;
do {
CoprocessorContextHead head;
if (!range.Read(reserved_address, sizeof(head), &head)) {
@ -241,7 +259,6 @@ bool ExceptionSnapshotLinux::ReadContext<ContextTraits64>(
case 0:
LOG(WARNING) << "fpsimd not found";
InitializeCPUContextARM64_ClearFPSIMD(dest_context);
return true;
default:

View File

@ -54,6 +54,7 @@ using NativeCPUContext = FxsaveUContext;
void InitializeContext(NativeCPUContext* context) {
context->ucontext.uc_mcontext.gregs[REG_EAX] = 0xabcd1234;
context->ucontext.uc_mcontext.fpregs = &context->ucontext.__fpregs_mem;
// glibc and bionic use an unsigned long for status, but the kernel treats
// status as two uint16_t, with the upper 16 bits called "magic" which, if set
// to X86_FXSR_MAGIC, indicate that an fxsave follows.
@ -78,6 +79,7 @@ using NativeCPUContext = ucontext_t;
void InitializeContext(NativeCPUContext* context) {
context->uc_mcontext.gregs[REG_RAX] = 0xabcd1234abcd1234;
context->uc_mcontext.fpregs = &context->__fpregs_mem;
memset(&context->__fpregs_mem, 44, sizeof(context->__fpregs_mem));
}

View File

@ -206,7 +206,7 @@ struct UContext {
SignalStack<Traits> stack;
MContext<Traits> mcontext;
Sigset<Traits> sigmask;
typename Traits::FloatContext fprs;
char fpregs_mem[0];
};
#elif defined(ARCH_CPU_ARM_FAMILY)