123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242 |
- // Copyright 2014 The Crashpad Authors. All rights reserved.
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
- #include "snapshot/cpu_context.h"
- #include <stddef.h>
- #include <string.h>
- #include <iterator>
- #include "base/notreached.h"
- #include "util/misc/arraysize.h"
- #include "util/misc/implicit_cast.h"
- namespace crashpad {
- namespace {
- // Sanity-check complex structures to ensure interoperability.
- static_assert(sizeof(CPUContextX86::Fsave) == 108, "CPUContextX86::Fsave size");
- static_assert(sizeof(CPUContextX86::Fxsave) == 512,
- "CPUContextX86::Fxsave size");
- static_assert(sizeof(CPUContextX86_64::Fxsave) == 512,
- "CPUContextX86_64::Fxsave size");
- enum {
- kX87TagValid = 0,
- kX87TagZero,
- kX87TagSpecial,
- kX87TagEmpty,
- };
- } // namespace
- // static
- void CPUContextX86::FxsaveToFsave(const Fxsave& fxsave, Fsave* fsave) {
- fsave->fcw = fxsave.fcw;
- fsave->reserved_1 = 0;
- fsave->fsw = fxsave.fsw;
- fsave->reserved_2 = 0;
- fsave->ftw = FxsaveToFsaveTagWord(fxsave.fsw, fxsave.ftw, fxsave.st_mm);
- fsave->reserved_3 = 0;
- fsave->fpu_ip = fxsave.fpu_ip;
- fsave->fpu_cs = fxsave.fpu_cs;
- fsave->fop = fxsave.fop;
- fsave->fpu_dp = fxsave.fpu_dp;
- fsave->fpu_ds = fxsave.fpu_ds;
- fsave->reserved_4 = 0;
- static_assert(ArraySize(fsave->st) == ArraySize(fxsave.st_mm),
- "FPU stack registers must be equivalent");
- for (size_t index = 0; index < std::size(fsave->st); ++index) {
- memcpy(fsave->st[index], fxsave.st_mm[index].st, sizeof(fsave->st[index]));
- }
- }
- // static
- void CPUContextX86::FsaveToFxsave(const Fsave& fsave, Fxsave* fxsave) {
- fxsave->fcw = fsave.fcw;
- fxsave->fsw = fsave.fsw;
- fxsave->ftw = FsaveToFxsaveTagWord(fsave.ftw);
- fxsave->reserved_1 = 0;
- fxsave->fop = fsave.fop;
- fxsave->fpu_ip = fsave.fpu_ip;
- fxsave->fpu_cs = fsave.fpu_cs;
- fxsave->reserved_2 = 0;
- fxsave->fpu_dp = fsave.fpu_dp;
- fxsave->fpu_ds = fsave.fpu_ds;
- fxsave->reserved_3 = 0;
- fxsave->mxcsr = 0;
- fxsave->mxcsr_mask = 0;
- static_assert(ArraySize(fxsave->st_mm) == ArraySize(fsave.st),
- "FPU stack registers must be equivalent");
- for (size_t index = 0; index < std::size(fsave.st); ++index) {
- memcpy(fxsave->st_mm[index].st, fsave.st[index], sizeof(fsave.st[index]));
- memset(fxsave->st_mm[index].st_reserved,
- 0,
- sizeof(fxsave->st_mm[index].st_reserved));
- }
- memset(fxsave->xmm, 0, sizeof(*fxsave) - offsetof(Fxsave, xmm));
- }
- // static
- uint16_t CPUContextX86::FxsaveToFsaveTagWord(
- uint16_t fsw,
- uint8_t fxsave_tag,
- const CPUContextX86::X87OrMMXRegister st_mm[8]) {
- // The x87 tag word (in both abridged and full form) identifies physical
- // registers, but |st_mm| is arranged in logical stack order. In order to map
- // physical tag word bits to the logical stack registers they correspond to,
- // the “stack top” value from the x87 status word is necessary.
- int stack_top = (fsw >> 11) & 0x7;
- uint16_t fsave_tag = 0;
- for (int physical_index = 0; physical_index < 8; ++physical_index) {
- bool fxsave_bit = (fxsave_tag & (1 << physical_index)) != 0;
- uint8_t fsave_bits;
- if (fxsave_bit) {
- int st_index = (physical_index + 8 - stack_top) % 8;
- const CPUContextX86::X87Register& st = st_mm[st_index].st;
- uint32_t exponent = ((st[9] & 0x7f) << 8) | st[8];
- if (exponent == 0x7fff) {
- // Infinity, NaN, pseudo-infinity, or pseudo-NaN. If it was important to
- // distinguish between these, the J bit and the M bit (the most
- // significant bit of |fraction|) could be consulted.
- fsave_bits = kX87TagSpecial;
- } else {
- // The integer bit the “J bit”.
- bool integer_bit = (st[7] & 0x80) != 0;
- if (exponent == 0) {
- uint64_t fraction = ((implicit_cast<uint64_t>(st[7]) & 0x7f) << 56) |
- (implicit_cast<uint64_t>(st[6]) << 48) |
- (implicit_cast<uint64_t>(st[5]) << 40) |
- (implicit_cast<uint64_t>(st[4]) << 32) |
- (implicit_cast<uint32_t>(st[3]) << 24) |
- (st[2] << 16) | (st[1] << 8) | st[0];
- if (!integer_bit && fraction == 0) {
- fsave_bits = kX87TagZero;
- } else {
- // Denormal (if the J bit is clear) or pseudo-denormal.
- fsave_bits = kX87TagSpecial;
- }
- } else if (integer_bit) {
- fsave_bits = kX87TagValid;
- } else {
- // Unnormal.
- fsave_bits = kX87TagSpecial;
- }
- }
- } else {
- fsave_bits = kX87TagEmpty;
- }
- fsave_tag |= (fsave_bits << (physical_index * 2));
- }
- return fsave_tag;
- }
- // static
- uint8_t CPUContextX86::FsaveToFxsaveTagWord(uint16_t fsave_tag) {
- uint8_t fxsave_tag = 0;
- for (int physical_index = 0; physical_index < 8; ++physical_index) {
- const uint8_t fsave_bits = (fsave_tag >> (physical_index * 2)) & 0x3;
- const bool fxsave_bit = fsave_bits != kX87TagEmpty;
- fxsave_tag |= fxsave_bit << physical_index;
- }
- return fxsave_tag;
- }
- uint64_t CPUContext::InstructionPointer() const {
- switch (architecture) {
- case kCPUArchitectureX86:
- return x86->eip;
- case kCPUArchitectureX86_64:
- return x86_64->rip;
- case kCPUArchitectureARM:
- return arm->pc;
- case kCPUArchitectureARM64:
- return arm64->pc;
- default:
- NOTREACHED();
- return ~0ull;
- }
- }
- uint64_t CPUContext::StackPointer() const {
- switch (architecture) {
- case kCPUArchitectureX86:
- return x86->esp;
- case kCPUArchitectureX86_64:
- return x86_64->rsp;
- case kCPUArchitectureARM:
- return arm->sp;
- case kCPUArchitectureARM64:
- return arm64->sp;
- default:
- NOTREACHED();
- return ~0ull;
- }
- }
- uint64_t CPUContext::ShadowStackPointer() const {
- switch (architecture) {
- case kCPUArchitectureX86:
- case kCPUArchitectureARM:
- case kCPUArchitectureARM64:
- NOTREACHED();
- return 0;
- case kCPUArchitectureX86_64:
- return x86_64->xstate.cet_u.ssp;
- default:
- NOTREACHED();
- return ~0ull;
- }
- }
- bool CPUContext::HasShadowStack() const {
- switch (architecture) {
- case kCPUArchitectureX86:
- case kCPUArchitectureARM:
- case kCPUArchitectureARM64:
- return false;
- case kCPUArchitectureX86_64:
- return x86_64->xstate.cet_u.cetmsr != 0;
- default:
- NOTREACHED();
- return false;
- }
- }
- bool CPUContext::Is64Bit() const {
- switch (architecture) {
- case kCPUArchitectureX86_64:
- case kCPUArchitectureARM64:
- case kCPUArchitectureMIPS64EL:
- case kCPUArchitectureRISCV64:
- return true;
- case kCPUArchitectureX86:
- case kCPUArchitectureARM:
- case kCPUArchitectureMIPSEL:
- case kCPUArchitectureRISCV:
- return false;
- default:
- NOTREACHED();
- return false;
- }
- }
- } // namespace crashpad
|