From e74a272ab50f7af0fa58e9a3d4657cd9bd3ef799 Mon Sep 17 00:00:00 2001 From: Mark Mentovai Date: Tue, 7 Oct 2014 17:27:11 -0400 Subject: [PATCH] Add MinidumpContextWriter test. TEST=minidump_test MinidumpContextWriter.* R=rsesek@chromium.org Review URL: https://codereview.chromium.org/628153004 --- minidump/minidump.gyp | 3 + minidump/minidump_context_test_util.cc | 319 +++++++++++++++++++++++ minidump/minidump_context_test_util.h | 61 +++++ minidump/minidump_context_writer_test.cc | 102 ++++++++ 4 files changed, 485 insertions(+) create mode 100644 minidump/minidump_context_test_util.cc create mode 100644 minidump/minidump_context_test_util.h create mode 100644 minidump/minidump_context_writer_test.cc diff --git a/minidump/minidump.gyp b/minidump/minidump.gyp index 63db0325..3f2c7cd4 100644 --- a/minidump/minidump.gyp +++ b/minidump/minidump.gyp @@ -67,6 +67,9 @@ '..', ], 'sources': [ + 'minidump_context_test_util.cc', + 'minidump_context_test_util.h', + 'minidump_context_writer_test.cc', 'minidump_file_writer_test.cc', 'minidump_memory_writer_test.cc', 'minidump_misc_info_writer_test.cc', diff --git a/minidump/minidump_context_test_util.cc b/minidump/minidump_context_test_util.cc new file mode 100644 index 00000000..18c2b142 --- /dev/null +++ b/minidump/minidump_context_test_util.cc @@ -0,0 +1,319 @@ +// 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 "minidump/minidump_context_test_util.h" + +#include "base/basictypes.h" +#include "gtest/gtest.h" + +namespace crashpad { +namespace test { + +void InitializeMinidumpContextX86(MinidumpContextX86* context, uint32_t seed) { + if (seed == 0) { + memset(context, 0, sizeof(*context)); + context->context_flags = kMinidumpContextX86; + return; + } + + context->context_flags = kMinidumpContextX86All; + + uint32_t value = seed; + + context->dr0 = value++; + context->dr1 = value++; + context->dr2 = value++; + context->dr3 = value++; + context->dr6 = value++; + context->dr7 = value++; + context->float_save.control_word = value++; + context->float_save.status_word = value++; + context->float_save.tag_word = value++; + context->float_save.error_offset = value++; + context->float_save.error_selector = value++; + context->float_save.data_offset = value++; + context->float_save.data_selector = value++; + for (size_t index = 0; + index < arraysize(context->float_save.register_area); + ++index) { + context->float_save.register_area[index] = value++; + } + context->float_save.spare_0 = value++; + context->gs = value++; + context->fs = value++; + context->es = value++; + context->ds = value++; + context->edi = value++; + context->esi = value++; + context->ebx = value++; + context->edx = value++; + context->ecx = value++; + context->eax = value++; + context->ebp = value++; + context->eip = value++; + context->cs = value++; + context->eflags = value++; + context->esp = value++; + context->ss = value++; + for (size_t index = 0; index < arraysize(context->extended_registers); + ++index) { + context->extended_registers[index] = value++; + } +} + +void InitializeMinidumpContextAMD64(MinidumpContextAMD64* context, + uint32_t seed) { + if (seed == 0) { + memset(context, 0, sizeof(*context)); + context->context_flags = kMinidumpContextAMD64; + return; + } + + context->context_flags = kMinidumpContextAMD64All; + + uint32_t value = seed; + + context->p1_home = value++; + context->p2_home = value++; + context->p3_home = value++; + context->p4_home = value++; + context->p5_home = value++; + context->p6_home = value++; + context->mx_csr = value++; + context->cs = value++; + context->ds = value++; + context->es = value++; + context->fs = value++; + context->gs = value++; + context->ss = value++; + context->eflags = value++; + context->dr0 = value++; + context->dr1 = value++; + context->dr2 = value++; + context->dr3 = value++; + context->dr6 = value++; + context->dr7 = value++; + context->rax = value++; + context->rcx = value++; + context->rdx = value++; + context->rbx = value++; + context->rsp = value++; + context->rbp = value++; + context->rsi = value++; + context->rdi = value++; + context->r8 = value++; + context->r9 = value++; + context->r10 = value++; + context->r11 = value++; + context->r12 = value++; + context->r13 = value++; + context->r14 = value++; + context->r15 = value++; + context->rip = value++; + context->float_save.control_word = value++; + context->float_save.status_word = value++; + context->float_save.tag_word = value++; + context->float_save.reserved_1 = value++; + context->float_save.error_opcode = value++; + context->float_save.error_offset = value++; + context->float_save.error_selector = value++; + context->float_save.reserved_2 = value++; + context->float_save.data_offset = value++; + context->float_save.data_selector = value++; + context->float_save.reserved_3 = value++; + context->float_save.mx_csr = value++; + context->float_save.mx_csr_mask = value++; + for (size_t index = 0; + index < arraysize(context->float_save.float_registers); + ++index) { + context->float_save.float_registers[index].lo = value++; + context->float_save.float_registers[index].hi = value++; + } + for (size_t index = 0; + index < arraysize(context->float_save.xmm_registers); + ++index) { + context->float_save.xmm_registers[index].lo = value++; + context->float_save.xmm_registers[index].hi = value++; + } + for (size_t index = 0; + index < arraysize(context->float_save.reserved_4); + ++index) { + context->float_save.reserved_4[index] = value++; + } + for (size_t index = 0; index < arraysize(context->vector_register); ++index) { + context->vector_register[index].lo = value++; + context->vector_register[index].hi = value++; + } + context->vector_control = value++; + context->debug_control = value++; + context->last_branch_to_rip = value++; + context->last_branch_from_rip = value++; + context->last_exception_to_rip = value++; + context->last_exception_from_rip = value++; +} + +void ExpectMinidumpContextX86(uint32_t expect_seed, + const MinidumpContextX86* observed) { + MinidumpContextX86 expected; + InitializeMinidumpContextX86(&expected, expect_seed); + + EXPECT_EQ(expected.context_flags, observed->context_flags); + EXPECT_EQ(expected.dr0, observed->dr0); + EXPECT_EQ(expected.dr1, observed->dr1); + EXPECT_EQ(expected.dr2, observed->dr2); + EXPECT_EQ(expected.dr3, observed->dr3); + EXPECT_EQ(expected.dr6, observed->dr6); + EXPECT_EQ(expected.dr7, observed->dr7); + EXPECT_EQ(expected.float_save.control_word, + observed->float_save.control_word); + EXPECT_EQ(expected.float_save.status_word, observed->float_save.status_word); + EXPECT_EQ(expected.float_save.tag_word, observed->float_save.tag_word); + EXPECT_EQ(expected.float_save.error_offset, + observed->float_save.error_offset); + EXPECT_EQ(expected.float_save.error_selector, + observed->float_save.error_selector); + EXPECT_EQ(expected.float_save.data_offset, observed->float_save.data_offset); + EXPECT_EQ(expected.float_save.data_selector, + observed->float_save.data_selector); + for (size_t index = 0; + index < arraysize(expected.float_save.register_area); + ++index) { + EXPECT_EQ(expected.float_save.register_area[index], + observed->float_save.register_area[index]); + } + EXPECT_EQ(expected.float_save.spare_0, observed->float_save.spare_0); + EXPECT_EQ(expected.gs, observed->gs); + EXPECT_EQ(expected.fs, observed->fs); + EXPECT_EQ(expected.es, observed->es); + EXPECT_EQ(expected.ds, observed->ds); + EXPECT_EQ(expected.edi, observed->edi); + EXPECT_EQ(expected.esi, observed->esi); + EXPECT_EQ(expected.ebx, observed->ebx); + EXPECT_EQ(expected.edx, observed->edx); + EXPECT_EQ(expected.ecx, observed->ecx); + EXPECT_EQ(expected.eax, observed->eax); + EXPECT_EQ(expected.ebp, observed->ebp); + EXPECT_EQ(expected.eip, observed->eip); + EXPECT_EQ(expected.cs, observed->cs); + EXPECT_EQ(expected.eflags, observed->eflags); + EXPECT_EQ(expected.esp, observed->esp); + EXPECT_EQ(expected.ss, observed->ss); + for (size_t index = 0; + index < arraysize(expected.extended_registers); + ++index) { + EXPECT_EQ(expected.extended_registers[index], + observed->extended_registers[index]); + } +} + +void ExpectMinidumpContextAMD64(uint32_t expect_seed, + const MinidumpContextAMD64* observed) { + MinidumpContextAMD64 expected; + InitializeMinidumpContextAMD64(&expected, expect_seed); + + EXPECT_EQ(expected.context_flags, observed->context_flags); + EXPECT_EQ(expected.p1_home, observed->p1_home); + EXPECT_EQ(expected.p2_home, observed->p2_home); + EXPECT_EQ(expected.p3_home, observed->p3_home); + EXPECT_EQ(expected.p4_home, observed->p4_home); + EXPECT_EQ(expected.p5_home, observed->p5_home); + EXPECT_EQ(expected.p6_home, observed->p6_home); + EXPECT_EQ(expected.mx_csr, observed->mx_csr); + EXPECT_EQ(expected.cs, observed->cs); + EXPECT_EQ(expected.ds, observed->ds); + EXPECT_EQ(expected.es, observed->es); + EXPECT_EQ(expected.fs, observed->fs); + EXPECT_EQ(expected.gs, observed->gs); + EXPECT_EQ(expected.ss, observed->ss); + EXPECT_EQ(expected.eflags, observed->eflags); + EXPECT_EQ(expected.dr0, observed->dr0); + EXPECT_EQ(expected.dr1, observed->dr1); + EXPECT_EQ(expected.dr2, observed->dr2); + EXPECT_EQ(expected.dr3, observed->dr3); + EXPECT_EQ(expected.dr6, observed->dr6); + EXPECT_EQ(expected.dr7, observed->dr7); + EXPECT_EQ(expected.rax, observed->rax); + EXPECT_EQ(expected.rcx, observed->rcx); + EXPECT_EQ(expected.rdx, observed->rdx); + EXPECT_EQ(expected.rbx, observed->rbx); + EXPECT_EQ(expected.rsp, observed->rsp); + EXPECT_EQ(expected.rbp, observed->rbp); + EXPECT_EQ(expected.rsi, observed->rsi); + EXPECT_EQ(expected.rdi, observed->rdi); + EXPECT_EQ(expected.r8, observed->r8); + EXPECT_EQ(expected.r9, observed->r9); + EXPECT_EQ(expected.r10, observed->r10); + EXPECT_EQ(expected.r11, observed->r11); + EXPECT_EQ(expected.r12, observed->r12); + EXPECT_EQ(expected.r13, observed->r13); + EXPECT_EQ(expected.r14, observed->r14); + EXPECT_EQ(expected.r15, observed->r15); + EXPECT_EQ(expected.rip, observed->rip); + EXPECT_EQ(expected.float_save.control_word, + observed->float_save.control_word); + EXPECT_EQ(expected.float_save.status_word, observed->float_save.status_word); + EXPECT_EQ(expected.float_save.tag_word, observed->float_save.tag_word); + EXPECT_EQ(expected.float_save.reserved_1, observed->float_save.reserved_1); + EXPECT_EQ(expected.float_save.error_opcode, + observed->float_save.error_opcode); + EXPECT_EQ(expected.float_save.error_offset, + observed->float_save.error_offset); + EXPECT_EQ(expected.float_save.error_selector, + observed->float_save.error_selector); + EXPECT_EQ(expected.float_save.reserved_2, observed->float_save.reserved_2); + EXPECT_EQ(expected.float_save.data_offset, observed->float_save.data_offset); + EXPECT_EQ(expected.float_save.data_selector, + observed->float_save.data_selector); + EXPECT_EQ(expected.float_save.reserved_3, observed->float_save.reserved_3); + EXPECT_EQ(expected.float_save.mx_csr, observed->float_save.mx_csr); + EXPECT_EQ(expected.float_save.mx_csr_mask, observed->float_save.mx_csr_mask); + for (size_t index = 0; + index < arraysize(expected.float_save.float_registers); + ++index) { + EXPECT_EQ(expected.float_save.float_registers[index].lo, + observed->float_save.float_registers[index].lo); + EXPECT_EQ(expected.float_save.float_registers[index].hi, + observed->float_save.float_registers[index].hi); + } + for (size_t index = 0; + index < arraysize(expected.float_save.xmm_registers); + ++index) { + EXPECT_EQ(expected.float_save.xmm_registers[index].lo, + observed->float_save.xmm_registers[index].lo); + EXPECT_EQ(expected.float_save.xmm_registers[index].hi, + observed->float_save.xmm_registers[index].hi); + } + for (size_t index = 0; + index < arraysize(expected.float_save.reserved_4); + ++index) { + EXPECT_EQ(expected.float_save.reserved_4[index], + observed->float_save.reserved_4[index]); + } + for (size_t index = 0; index < arraysize(expected.vector_register); ++index) { + EXPECT_EQ(expected.vector_register[index].lo, + observed->vector_register[index].lo); + EXPECT_EQ(expected.vector_register[index].hi, + observed->vector_register[index].hi); + } + EXPECT_EQ(expected.vector_control, observed->vector_control); + EXPECT_EQ(expected.debug_control, observed->debug_control); + EXPECT_EQ(expected.last_branch_to_rip, observed->last_branch_to_rip); + EXPECT_EQ(expected.last_branch_from_rip, observed->last_branch_from_rip); + EXPECT_EQ(expected.last_exception_to_rip, observed->last_exception_to_rip); + EXPECT_EQ(expected.last_exception_from_rip, + observed->last_exception_from_rip); +} + +} // namespace test +} // namespace crashpad diff --git a/minidump/minidump_context_test_util.h b/minidump/minidump_context_test_util.h new file mode 100644 index 00000000..1db974db --- /dev/null +++ b/minidump/minidump_context_test_util.h @@ -0,0 +1,61 @@ +// 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. + +#ifndef CRASHPAD_MINIDUMP_MINIDUMP_CONTEXT_TEST_UTIL_H_ +#define CRASHPAD_MINIDUMP_MINIDUMP_CONTEXT_TEST_UTIL_H_ + +#include + +#include "minidump/minidump_context.h" + +namespace crashpad { +namespace test { + +//! \brief Initializes a context structure for testing. +//! +//! \param[out] context The structure to initialize. +//! \param[in] seed The seed value. Initializing two context structures of the +//! same type with identical seed values should produce identical context +//! structures. Initialization with a different seed value should produce +//! a different context structure. If \a seed is `0`, \a context is zeroed +//! out entirely except for the flags field, which will identify the context +//! type. If \a seed is nonzero \a context will be populated entirely with +//! nonzero values. +//! +//! \{ +void InitializeMinidumpContextX86(MinidumpContextX86* context, uint32_t seed); +void InitializeMinidumpContextAMD64(MinidumpContextAMD64* context, + uint32_t seed); +//! \} + +//! \brief Verifies, via gtest assertions, that a context structure contains +//! expected values. +//! +//! \param[in] expect_seed The seed value used to initialize a context +//! structure. This is the seed value used with +//! InitializeMinidumpContext*(). +//! \param[in] observed The context structure to check. All fields of this +//! structure will be compared against the expected context structure, one +//! initialized with \a expect_seed. +//! \{ +void ExpectMinidumpContextX86(uint32_t expect_seed, + const MinidumpContextX86* observed); +void ExpectMinidumpContextAMD64(uint32_t expect_seed, + const MinidumpContextAMD64* observed); +//! \} + +} // namespace test +} // namespace crashpad + +#endif // CRASHPAD_MINIDUMP_MINIDUMP_CONTEXT_TEST_UTIL_H_ diff --git a/minidump/minidump_context_writer_test.cc b/minidump/minidump_context_writer_test.cc new file mode 100644 index 00000000..559b2e3f --- /dev/null +++ b/minidump/minidump_context_writer_test.cc @@ -0,0 +1,102 @@ +// 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 "minidump/minidump_context_writer.h" + +#include + +#include "gtest/gtest.h" +#include "minidump/minidump_context.h" +#include "minidump/minidump_context_test_util.h" +#include "util/file/string_file_writer.h" + +namespace crashpad { +namespace test { +namespace { + +TEST(MinidumpContextWriter, MinidumpContextX86Writer) { + StringFileWriter file_writer; + + { + // Make sure that a context writer that’s untouched writes a zeroed-out + // context. + SCOPED_TRACE("zero"); + + MinidumpContextX86Writer context_writer; + + EXPECT_TRUE(context_writer.WriteEverything(&file_writer)); + ASSERT_EQ(sizeof(MinidumpContextX86), file_writer.string().size()); + + const MinidumpContextX86* observed = + reinterpret_cast(&file_writer.string()[0]); + ExpectMinidumpContextX86(0, observed); + } + + { + SCOPED_TRACE("nonzero"); + + file_writer.Reset(); + const uint32_t kSeed = 0x8086; + + MinidumpContextX86Writer context_writer; + InitializeMinidumpContextX86(context_writer.context(), kSeed); + + EXPECT_TRUE(context_writer.WriteEverything(&file_writer)); + ASSERT_EQ(sizeof(MinidumpContextX86), file_writer.string().size()); + + const MinidumpContextX86* observed = + reinterpret_cast(&file_writer.string()[0]); + ExpectMinidumpContextX86(kSeed, observed); + } +} + +TEST(MinidumpContextWriter, MinidumpContextAMD64Writer) { + StringFileWriter file_writer; + + { + // Make sure that a context writer that’s untouched writes a zeroed-out + // context. + SCOPED_TRACE("zero"); + + MinidumpContextAMD64Writer context_writer; + + EXPECT_TRUE(context_writer.WriteEverything(&file_writer)); + ASSERT_EQ(sizeof(MinidumpContextAMD64), file_writer.string().size()); + + const MinidumpContextAMD64* observed = + reinterpret_cast(&file_writer.string()[0]); + ExpectMinidumpContextAMD64(0, observed); + } + + { + SCOPED_TRACE("nonzero"); + + file_writer.Reset(); + const uint32_t kSeed = 0x808664; + + MinidumpContextAMD64Writer context_writer; + InitializeMinidumpContextAMD64(context_writer.context(), kSeed); + + EXPECT_TRUE(context_writer.WriteEverything(&file_writer)); + ASSERT_EQ(sizeof(MinidumpContextAMD64), file_writer.string().size()); + + const MinidumpContextAMD64* observed = + reinterpret_cast(&file_writer.string()[0]); + ExpectMinidumpContextAMD64(kSeed, observed); + } +} + +} // namespace +} // namespace test +} // namespace crashpad