| Index: third_party/crashpad/crashpad/snapshot/cpu_context_test.cc
|
| diff --git a/third_party/crashpad/crashpad/snapshot/cpu_context_test.cc b/third_party/crashpad/crashpad/snapshot/cpu_context_test.cc
|
| index 808ba615fa02af6629cfed7f9e622a5820527774..ffc18cfeadc3b3522974b9f1e480caae5e2ff5ed 100644
|
| --- a/third_party/crashpad/crashpad/snapshot/cpu_context_test.cc
|
| +++ b/third_party/crashpad/crashpad/snapshot/cpu_context_test.cc
|
| @@ -19,6 +19,7 @@
|
|
|
| #include "base/macros.h"
|
| #include "gtest/gtest.h"
|
| +#include "test/hex_string.h"
|
|
|
| namespace crashpad {
|
| namespace test {
|
| @@ -48,37 +49,188 @@ enum FractionValue {
|
| //! \param[in] j_bit The value to use for the “J bit” (“integer bit”).
|
| //! \param[in] fraction_value If kFractionAllZero, the fraction will be zeroed
|
| //! out. If kFractionNormal, the fraction will not be all zeroes.
|
| -void SetX87Register(CPUContextX86::X87OrMMXRegister* st_mm,
|
| +void SetX87Register(CPUContextX86::X87Register* st,
|
| ExponentValue exponent_value,
|
| bool j_bit,
|
| FractionValue fraction_value) {
|
| switch (exponent_value) {
|
| case kExponentAllZero:
|
| - st_mm->st[9] = 0x80;
|
| - st_mm->st[8] = 0;
|
| + (*st)[9] = 0x80;
|
| + (*st)[8] = 0;
|
| break;
|
| case kExponentAllOne:
|
| - st_mm->st[9] = 0x7f;
|
| - st_mm->st[8] = 0xff;
|
| + (*st)[9] = 0x7f;
|
| + (*st)[8] = 0xff;
|
| break;
|
| case kExponentNormal:
|
| - st_mm->st[9] = 0x55;
|
| - st_mm->st[8] = 0x55;
|
| + (*st)[9] = 0x55;
|
| + (*st)[8] = 0x55;
|
| break;
|
| }
|
|
|
| uint8_t fraction_pattern = fraction_value == kFractionAllZero ? 0 : 0x55;
|
| - memset(&st_mm->st[0], fraction_pattern, 8);
|
| + memset(st, fraction_pattern, 8);
|
|
|
| if (j_bit) {
|
| - st_mm->st[7] |= 0x80;
|
| + (*st)[7] |= 0x80;
|
| } else {
|
| - st_mm->st[7] &= ~0x80;
|
| + (*st)[7] &= ~0x80;
|
| }
|
| +}
|
|
|
| +//! \brief Initializes an x87 register to a known bit pattern.
|
| +//!
|
| +//! This behaves as SetX87Register() but also clears the reserved portion of the
|
| +//! field as used in the `fxsave` format.
|
| +void SetX87OrMMXRegister(CPUContextX86::X87OrMMXRegister* st_mm,
|
| + ExponentValue exponent_value,
|
| + bool j_bit,
|
| + FractionValue fraction_value) {
|
| + SetX87Register(&st_mm->st, exponent_value, j_bit, fraction_value);
|
| memset(st_mm->st_reserved, 0, sizeof(st_mm->st_reserved));
|
| }
|
|
|
| +TEST(CPUContextX86, FxsaveToFsave) {
|
| + // Establish a somewhat plausible fxsave state. Use nonzero values for
|
| + // reserved fields and things that aren’t present in fsave.
|
| + CPUContextX86::Fxsave fxsave;
|
| + fxsave.fcw = 0x027f; // mask exceptions, 53-bit precision, round to nearest
|
| + fxsave.fsw = 1 << 11; // top = 1: logical 0-7 maps to physical 1-7, 0
|
| + fxsave.ftw = 0x1f; // physical 5-7 (logical 4-6) empty
|
| + fxsave.reserved_1 = 0x5a;
|
| + fxsave.fop = 0x1fe; // fsin
|
| + fxsave.fpu_ip = 0x76543210;
|
| + fxsave.fpu_cs = 0x0007;
|
| + fxsave.reserved_2 = 0x5a5a;
|
| + fxsave.fpu_dp = 0xfedcba98;
|
| + fxsave.fpu_ds = 0x000f;
|
| + fxsave.reserved_3 = 0x5a5a;
|
| + fxsave.mxcsr = 0x1f80;
|
| + fxsave.mxcsr_mask = 0xffff;
|
| + SetX87Register(
|
| + &fxsave.st_mm[0].st, kExponentNormal, true, kFractionAllZero); // valid
|
| + SetX87Register(
|
| + &fxsave.st_mm[1].st, kExponentAllZero, false, kFractionAllZero); // zero
|
| + SetX87Register(
|
| + &fxsave.st_mm[2].st, kExponentAllOne, true, kFractionAllZero); // spec.
|
| + SetX87Register(
|
| + &fxsave.st_mm[3].st, kExponentAllOne, true, kFractionNormal); // spec.
|
| + SetX87Register(
|
| + &fxsave.st_mm[4].st, kExponentAllZero, false, kFractionAllZero);
|
| + SetX87Register(
|
| + &fxsave.st_mm[5].st, kExponentAllZero, false, kFractionAllZero);
|
| + SetX87Register(
|
| + &fxsave.st_mm[6].st, kExponentAllZero, false, kFractionAllZero);
|
| + SetX87Register(
|
| + &fxsave.st_mm[7].st, kExponentNormal, true, kFractionNormal); // valid
|
| + for (size_t index = 0; index < arraysize(fxsave.st_mm); ++index) {
|
| + memset(&fxsave.st_mm[index].st_reserved,
|
| + 0x5a,
|
| + sizeof(fxsave.st_mm[index].st_reserved));
|
| + }
|
| + memset(&fxsave.xmm, 0x5a, sizeof(fxsave) - offsetof(decltype(fxsave), xmm));
|
| +
|
| + CPUContextX86::Fsave fsave;
|
| + CPUContextX86::FxsaveToFsave(fxsave, &fsave);
|
| +
|
| + // Everything should have come over from fxsave. Reserved fields should be
|
| + // zero.
|
| + EXPECT_EQ(fxsave.fcw, fsave.fcw);
|
| + EXPECT_EQ(0, fsave.reserved_1);
|
| + EXPECT_EQ(fxsave.fsw, fsave.fsw);
|
| + EXPECT_EQ(0, fsave.reserved_2);
|
| + EXPECT_EQ(0xfe90, fsave.ftw); // FxsaveToFsaveTagWord
|
| + EXPECT_EQ(0, fsave.reserved_3);
|
| + EXPECT_EQ(fxsave.fpu_ip, fsave.fpu_ip);
|
| + EXPECT_EQ(fxsave.fpu_cs, fsave.fpu_cs);
|
| + EXPECT_EQ(fxsave.fop, fsave.fop);
|
| + EXPECT_EQ(fxsave.fpu_dp, fsave.fpu_dp);
|
| + EXPECT_EQ(fxsave.fpu_ds, fsave.fpu_ds);
|
| + EXPECT_EQ(0, fsave.reserved_4);
|
| + for (size_t index = 0; index < arraysize(fsave.st); ++index) {
|
| + EXPECT_EQ(BytesToHexString(fxsave.st_mm[index].st,
|
| + arraysize(fxsave.st_mm[index].st)),
|
| + BytesToHexString(fsave.st[index], arraysize(fsave.st[index])))
|
| + << "index " << index;
|
| + }
|
| +}
|
| +
|
| +TEST(CPUContextX86, FsaveToFxsave) {
|
| + // Establish a somewhat plausible fsave state. Use nonzero values for
|
| + // reserved fields.
|
| + CPUContextX86::Fsave fsave;
|
| + fsave.fcw = 0x0300; // unmask exceptions, 64-bit precision, round to nearest
|
| + fsave.reserved_1 = 0xa5a5;
|
| + fsave.fsw = 2 << 11; // top = 2: logical 0-7 maps to physical 2-7, 0-1
|
| + fsave.reserved_2 = 0xa5a5;
|
| + fsave.ftw = 0xa9ff; // physical 0-3 (logical 6-7, 0-1) empty; physical 4
|
| + // (logical 2) zero; physical 5-7 (logical 3-5) special
|
| + fsave.reserved_3 = 0xa5a5;
|
| + fsave.fpu_ip = 0x456789ab;
|
| + fsave.fpu_cs = 0x1013;
|
| + fsave.fop = 0x01ee; // fldz
|
| + fsave.fpu_dp = 0x0123cdef;
|
| + fsave.fpu_ds = 0x2017;
|
| + fsave.reserved_4 = 0xa5a5;
|
| + SetX87Register(&fsave.st[0], kExponentAllZero, false, kFractionNormal);
|
| + SetX87Register(&fsave.st[1], kExponentAllZero, true, kFractionNormal);
|
| + SetX87Register(
|
| + &fsave.st[2], kExponentAllZero, false, kFractionAllZero); // zero
|
| + SetX87Register(
|
| + &fsave.st[3], kExponentAllZero, true, kFractionAllZero); // spec.
|
| + SetX87Register(
|
| + &fsave.st[4], kExponentAllZero, false, kFractionNormal); // spec.
|
| + SetX87Register(
|
| + &fsave.st[5], kExponentAllZero, true, kFractionNormal); // spec.
|
| + SetX87Register(&fsave.st[6], kExponentAllZero, false, kFractionAllZero);
|
| + SetX87Register(&fsave.st[7], kExponentAllZero, true, kFractionAllZero);
|
| +
|
| + CPUContextX86::Fxsave fxsave;
|
| + CPUContextX86::FsaveToFxsave(fsave, &fxsave);
|
| +
|
| + // Everything in fsave should have come over from there. Fields not present in
|
| + // fsave and reserved fields should be zero.
|
| + EXPECT_EQ(fsave.fcw, fxsave.fcw);
|
| + EXPECT_EQ(fsave.fsw, fxsave.fsw);
|
| + EXPECT_EQ(0xf0, fxsave.ftw); // FsaveToFxsaveTagWord
|
| + EXPECT_EQ(0, fxsave.reserved_1);
|
| + EXPECT_EQ(fsave.fop, fxsave.fop);
|
| + EXPECT_EQ(fsave.fpu_ip, fxsave.fpu_ip);
|
| + EXPECT_EQ(fsave.fpu_cs, fxsave.fpu_cs);
|
| + EXPECT_EQ(0, fxsave.reserved_2);
|
| + EXPECT_EQ(fsave.fpu_dp, fxsave.fpu_dp);
|
| + EXPECT_EQ(fsave.fpu_ds, fxsave.fpu_ds);
|
| + EXPECT_EQ(0, fxsave.reserved_3);
|
| + EXPECT_EQ(0u, fxsave.mxcsr);
|
| + EXPECT_EQ(0u, fxsave.mxcsr_mask);
|
| + for (size_t index = 0; index < arraysize(fxsave.st_mm); ++index) {
|
| + EXPECT_EQ(BytesToHexString(fsave.st[index], arraysize(fsave.st[index])),
|
| + BytesToHexString(fxsave.st_mm[index].st,
|
| + arraysize(fxsave.st_mm[index].st)))
|
| + << "index " << index;
|
| + EXPECT_EQ(std::string(arraysize(fxsave.st_mm[index].st_reserved) * 2, '0'),
|
| + BytesToHexString(fxsave.st_mm[index].st_reserved,
|
| + arraysize(fxsave.st_mm[index].st_reserved)))
|
| + << "index " << index;
|
| + }
|
| + size_t unused_len = sizeof(fxsave) - offsetof(decltype(fxsave), xmm);
|
| + EXPECT_EQ(std::string(unused_len * 2, '0'),
|
| + BytesToHexString(fxsave.xmm, unused_len));
|
| +
|
| + // Since the fsave format is a subset of the fxsave format, fsave-fxsave-fsave
|
| + // should round-trip cleanly.
|
| + CPUContextX86::Fsave fsave_2;
|
| + CPUContextX86::FxsaveToFsave(fxsave, &fsave_2);
|
| +
|
| + // Clear the reserved fields in the original fsave structure, since they’re
|
| + // expected to be clear in the copy.
|
| + fsave.reserved_1 = 0;
|
| + fsave.reserved_2 = 0;
|
| + fsave.reserved_3 = 0;
|
| + fsave.reserved_4 = 0;
|
| + EXPECT_EQ(0, memcmp(&fsave, &fsave_2, sizeof(fsave)));
|
| +}
|
| +
|
| TEST(CPUContextX86, FxsaveToFsaveTagWord) {
|
| // The fsave tag word uses bit pattern 00 for valid, 01 for zero, 10 for
|
| // “special”, and 11 for empty. Like the fxsave tag word, it is arranged by
|
| @@ -93,40 +245,52 @@ TEST(CPUContextX86, FxsaveToFsaveTagWord) {
|
| uint16_t fsw = 0 << 11; // top = 0: logical 0-7 maps to physical 0-7
|
| uint8_t fxsave_tag = 0x0f; // physical 4-7 (logical 4-7) empty
|
| CPUContextX86::X87OrMMXRegister st_mm[8];
|
| - SetX87Register(&st_mm[0], kExponentNormal, false, kFractionNormal); // spec.
|
| - SetX87Register(&st_mm[1], kExponentNormal, true, kFractionNormal); // valid
|
| - SetX87Register(&st_mm[2], kExponentNormal, false, kFractionAllZero); // spec.
|
| - SetX87Register(&st_mm[3], kExponentNormal, true, kFractionAllZero); // valid
|
| - SetX87Register(&st_mm[4], kExponentNormal, false, kFractionNormal);
|
| - SetX87Register(&st_mm[5], kExponentNormal, true, kFractionNormal);
|
| - SetX87Register(&st_mm[6], kExponentNormal, false, kFractionAllZero);
|
| - SetX87Register(&st_mm[7], kExponentNormal, true, kFractionAllZero);
|
| + SetX87OrMMXRegister(
|
| + &st_mm[0], kExponentNormal, false, kFractionNormal); // spec.
|
| + SetX87OrMMXRegister(
|
| + &st_mm[1], kExponentNormal, true, kFractionNormal); // valid
|
| + SetX87OrMMXRegister(
|
| + &st_mm[2], kExponentNormal, false, kFractionAllZero); // spec.
|
| + SetX87OrMMXRegister(
|
| + &st_mm[3], kExponentNormal, true, kFractionAllZero); // valid
|
| + SetX87OrMMXRegister(&st_mm[4], kExponentNormal, false, kFractionNormal);
|
| + SetX87OrMMXRegister(&st_mm[5], kExponentNormal, true, kFractionNormal);
|
| + SetX87OrMMXRegister(&st_mm[6], kExponentNormal, false, kFractionAllZero);
|
| + SetX87OrMMXRegister(&st_mm[7], kExponentNormal, true, kFractionAllZero);
|
| EXPECT_EQ(0xff22,
|
| CPUContextX86::FxsaveToFsaveTagWord(fsw, fxsave_tag, st_mm));
|
|
|
| fsw = 2 << 11; // top = 2: logical 0-7 maps to physical 2-7, 0-1
|
| fxsave_tag = 0xf0; // physical 0-3 (logical 6-7, 0-1) empty
|
| - SetX87Register(&st_mm[0], kExponentAllZero, false, kFractionNormal);
|
| - SetX87Register(&st_mm[1], kExponentAllZero, true, kFractionNormal);
|
| - SetX87Register(&st_mm[2], kExponentAllZero, false, kFractionAllZero); // zero
|
| - SetX87Register(&st_mm[3], kExponentAllZero, true, kFractionAllZero); // spec.
|
| - SetX87Register(&st_mm[4], kExponentAllZero, false, kFractionNormal); // spec.
|
| - SetX87Register(&st_mm[5], kExponentAllZero, true, kFractionNormal); // spec.
|
| - SetX87Register(&st_mm[6], kExponentAllZero, false, kFractionAllZero);
|
| - SetX87Register(&st_mm[7], kExponentAllZero, true, kFractionAllZero);
|
| + SetX87OrMMXRegister(&st_mm[0], kExponentAllZero, false, kFractionNormal);
|
| + SetX87OrMMXRegister(&st_mm[1], kExponentAllZero, true, kFractionNormal);
|
| + SetX87OrMMXRegister(
|
| + &st_mm[2], kExponentAllZero, false, kFractionAllZero); // zero
|
| + SetX87OrMMXRegister(
|
| + &st_mm[3], kExponentAllZero, true, kFractionAllZero); // spec.
|
| + SetX87OrMMXRegister(
|
| + &st_mm[4], kExponentAllZero, false, kFractionNormal); // spec.
|
| + SetX87OrMMXRegister(
|
| + &st_mm[5], kExponentAllZero, true, kFractionNormal); // spec.
|
| + SetX87OrMMXRegister(&st_mm[6], kExponentAllZero, false, kFractionAllZero);
|
| + SetX87OrMMXRegister(&st_mm[7], kExponentAllZero, true, kFractionAllZero);
|
| EXPECT_EQ(0xa9ff,
|
| CPUContextX86::FxsaveToFsaveTagWord(fsw, fxsave_tag, st_mm));
|
|
|
| fsw = 5 << 11; // top = 5: logical 0-7 maps to physical 5-7, 0-4
|
| fxsave_tag = 0x5a; // physical 0, 2, 5, and 7 (logical 5, 0, 2, and 3) empty
|
| - SetX87Register(&st_mm[0], kExponentAllOne, false, kFractionNormal);
|
| - SetX87Register(&st_mm[1], kExponentAllOne, true, kFractionNormal); // spec.
|
| - SetX87Register(&st_mm[2], kExponentAllOne, false, kFractionAllZero);
|
| - SetX87Register(&st_mm[3], kExponentAllOne, true, kFractionAllZero);
|
| - SetX87Register(&st_mm[4], kExponentAllOne, false, kFractionNormal); // spec.
|
| - SetX87Register(&st_mm[5], kExponentAllOne, true, kFractionNormal);
|
| - SetX87Register(&st_mm[6], kExponentAllOne, false, kFractionAllZero); // spec.
|
| - SetX87Register(&st_mm[7], kExponentAllOne, true, kFractionAllZero); // spec.
|
| + SetX87OrMMXRegister(&st_mm[0], kExponentAllOne, false, kFractionNormal);
|
| + SetX87OrMMXRegister(
|
| + &st_mm[1], kExponentAllOne, true, kFractionNormal); // spec.
|
| + SetX87OrMMXRegister(&st_mm[2], kExponentAllOne, false, kFractionAllZero);
|
| + SetX87OrMMXRegister(&st_mm[3], kExponentAllOne, true, kFractionAllZero);
|
| + SetX87OrMMXRegister(
|
| + &st_mm[4], kExponentAllOne, false, kFractionNormal); // spec.
|
| + SetX87OrMMXRegister(&st_mm[5], kExponentAllOne, true, kFractionNormal);
|
| + SetX87OrMMXRegister(
|
| + &st_mm[6], kExponentAllOne, false, kFractionAllZero); // spec.
|
| + SetX87OrMMXRegister(
|
| + &st_mm[7], kExponentAllOne, true, kFractionAllZero); // spec.
|
| EXPECT_EQ(0xeebb,
|
| CPUContextX86::FxsaveToFsaveTagWord(fsw, fxsave_tag, st_mm));
|
|
|
| @@ -134,14 +298,19 @@ TEST(CPUContextX86, FxsaveToFsaveTagWord) {
|
| // register file.
|
| fsw = 1 << 11; // top = 1: logical 0-7 maps to physical 1-7, 0
|
| fxsave_tag = 0x1f; // physical 5-7 (logical 4-6) empty
|
| - SetX87Register(&st_mm[0], kExponentNormal, true, kFractionAllZero); // valid
|
| - SetX87Register(&st_mm[1], kExponentAllZero, false, kFractionAllZero); // zero
|
| - SetX87Register(&st_mm[2], kExponentAllOne, true, kFractionAllZero); // spec.
|
| - SetX87Register(&st_mm[3], kExponentAllOne, true, kFractionNormal); // spec.
|
| - SetX87Register(&st_mm[4], kExponentAllZero, false, kFractionAllZero);
|
| - SetX87Register(&st_mm[5], kExponentAllZero, false, kFractionAllZero);
|
| - SetX87Register(&st_mm[6], kExponentAllZero, false, kFractionAllZero);
|
| - SetX87Register(&st_mm[7], kExponentNormal, true, kFractionNormal); // valid
|
| + SetX87OrMMXRegister(
|
| + &st_mm[0], kExponentNormal, true, kFractionAllZero); // valid
|
| + SetX87OrMMXRegister(
|
| + &st_mm[1], kExponentAllZero, false, kFractionAllZero); // zero
|
| + SetX87OrMMXRegister(
|
| + &st_mm[2], kExponentAllOne, true, kFractionAllZero); // spec.
|
| + SetX87OrMMXRegister(
|
| + &st_mm[3], kExponentAllOne, true, kFractionNormal); // spec.
|
| + SetX87OrMMXRegister(&st_mm[4], kExponentAllZero, false, kFractionAllZero);
|
| + SetX87OrMMXRegister(&st_mm[5], kExponentAllZero, false, kFractionAllZero);
|
| + SetX87OrMMXRegister(&st_mm[6], kExponentAllZero, false, kFractionAllZero);
|
| + SetX87OrMMXRegister(
|
| + &st_mm[7], kExponentNormal, true, kFractionNormal); // valid
|
| EXPECT_EQ(0xfe90,
|
| CPUContextX86::FxsaveToFsaveTagWord(fsw, fxsave_tag, st_mm));
|
|
|
| @@ -149,7 +318,7 @@ TEST(CPUContextX86, FxsaveToFsaveTagWord) {
|
| fsw = 0 << 11; // top = 0: logical 0-7 maps to physical 0-7
|
| fxsave_tag = 0xff; // nothing empty
|
| for (size_t index = 0; index < arraysize(st_mm); ++index) {
|
| - SetX87Register(&st_mm[index], kExponentNormal, true, kFractionAllZero);
|
| + SetX87OrMMXRegister(&st_mm[index], kExponentNormal, true, kFractionAllZero);
|
| }
|
| EXPECT_EQ(0, CPUContextX86::FxsaveToFsaveTagWord(fsw, fxsave_tag, st_mm));
|
|
|
| @@ -161,6 +330,17 @@ TEST(CPUContextX86, FxsaveToFsaveTagWord) {
|
| CPUContextX86::FxsaveToFsaveTagWord(fsw, fxsave_tag, st_mm));
|
| }
|
|
|
| +TEST(CPUContextX86, FsaveToFxsaveTagWord) {
|
| + // The register sets that these x87 tag words might apply to are given in the
|
| + // FxsaveToFsaveTagWord test above.
|
| + EXPECT_EQ(0x0f, CPUContextX86::FsaveToFxsaveTagWord(0xff22));
|
| + EXPECT_EQ(0xf0, CPUContextX86::FsaveToFxsaveTagWord(0xa9ff));
|
| + EXPECT_EQ(0x5a, CPUContextX86::FsaveToFxsaveTagWord(0xeebb));
|
| + EXPECT_EQ(0x1f, CPUContextX86::FsaveToFxsaveTagWord(0xfe90));
|
| + EXPECT_EQ(0xff, CPUContextX86::FsaveToFxsaveTagWord(0x0000));
|
| + EXPECT_EQ(0x00, CPUContextX86::FsaveToFxsaveTagWord(0xffff));
|
| +}
|
| +
|
| } // namespace
|
| } // namespace test
|
| } // namespace crashpad
|
|
|