|  | // Copyright 2018 The Fuchsia Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #include <zircon/hw/debug/x86.h> | 
|  | #include <zircon/syscalls/exception.h> | 
|  |  | 
|  | #include <gtest/gtest.h> | 
|  |  | 
|  | #include "src/developer/debug/ipc/decode_exception.h" | 
|  | #include "src/developer/debug/shared/arch_x86.h" | 
|  |  | 
|  | namespace debug_ipc { | 
|  | namespace { | 
|  |  | 
|  | class ArmTestInfo : public Arm64ExceptionInfo { | 
|  | public: | 
|  | uint32_t esr = 0; | 
|  |  | 
|  | std::optional<uint32_t> FetchESR() const override { return esr; } | 
|  | }; | 
|  |  | 
|  | class X64TestInfo : public X64ExceptionInfo { | 
|  | public: | 
|  | X64ExceptionInfo::DebugRegs regs; | 
|  |  | 
|  | std::optional<X64ExceptionInfo::DebugRegs> FetchDebugRegs() const override { return regs; } | 
|  | }; | 
|  |  | 
|  | }  // namespace | 
|  |  | 
|  | TEST(DecodeException, Arm64) { | 
|  | ArmTestInfo info; | 
|  |  | 
|  | // Exceptions that require no decoding. | 
|  | EXPECT_EQ(ExceptionType::kSoftwareBreakpoint, DecodeException(ZX_EXCP_SW_BREAKPOINT, info)); | 
|  | EXPECT_EQ(ExceptionType::kGeneral, DecodeException(ZX_EXCP_GENERAL, info)); | 
|  | EXPECT_EQ(ExceptionType::kPageFault, DecodeException(ZX_EXCP_FATAL_PAGE_FAULT, info)); | 
|  | EXPECT_EQ(ExceptionType::kUndefinedInstruction, | 
|  | DecodeException(ZX_EXCP_UNDEFINED_INSTRUCTION, info)); | 
|  | EXPECT_EQ(ExceptionType::kUnalignedAccess, DecodeException(ZX_EXCP_UNALIGNED_ACCESS, info)); | 
|  | EXPECT_EQ(ExceptionType::kThreadStarting, DecodeException(ZX_EXCP_THREAD_STARTING, info)); | 
|  | EXPECT_EQ(ExceptionType::kThreadExiting, DecodeException(ZX_EXCP_THREAD_EXITING, info)); | 
|  | EXPECT_EQ(ExceptionType::kPolicyError, DecodeException(ZX_EXCP_POLICY_ERROR, info)); | 
|  | EXPECT_EQ(ExceptionType::kProcessStarting, DecodeException(ZX_EXCP_PROCESS_STARTING, info)); | 
|  |  | 
|  | // Hardware breakpoints. The meaty stuff. | 
|  | info.esr = 0b110000 << 26; | 
|  | EXPECT_EQ(ExceptionType::kHardwareBreakpoint, DecodeException(ZX_EXCP_HW_BREAKPOINT, info)); | 
|  | info.esr = 0b110001 << 26; | 
|  | EXPECT_EQ(ExceptionType::kHardwareBreakpoint, DecodeException(ZX_EXCP_HW_BREAKPOINT, info)); | 
|  |  | 
|  | info.esr = 0b110010 << 26; | 
|  | EXPECT_EQ(ExceptionType::kSingleStep, DecodeException(ZX_EXCP_HW_BREAKPOINT, info)); | 
|  | info.esr = 0b110011 << 26; | 
|  | EXPECT_EQ(ExceptionType::kSingleStep, DecodeException(ZX_EXCP_HW_BREAKPOINT, info)); | 
|  | } | 
|  |  | 
|  | TEST(DecodeException, X64) { | 
|  | X64TestInfo info; | 
|  |  | 
|  | // Exceptions that require no decoding. | 
|  | EXPECT_EQ(ExceptionType::kSoftwareBreakpoint, DecodeException(ZX_EXCP_SW_BREAKPOINT, info)); | 
|  | EXPECT_EQ(ExceptionType::kGeneral, DecodeException(ZX_EXCP_GENERAL, info)); | 
|  | EXPECT_EQ(ExceptionType::kPageFault, DecodeException(ZX_EXCP_FATAL_PAGE_FAULT, info)); | 
|  | EXPECT_EQ(ExceptionType::kUndefinedInstruction, | 
|  | DecodeException(ZX_EXCP_UNDEFINED_INSTRUCTION, info)); | 
|  | EXPECT_EQ(ExceptionType::kUnalignedAccess, DecodeException(ZX_EXCP_UNALIGNED_ACCESS, info)); | 
|  | EXPECT_EQ(ExceptionType::kThreadStarting, DecodeException(ZX_EXCP_THREAD_STARTING, info)); | 
|  | EXPECT_EQ(ExceptionType::kThreadExiting, DecodeException(ZX_EXCP_THREAD_EXITING, info)); | 
|  | EXPECT_EQ(ExceptionType::kPolicyError, DecodeException(ZX_EXCP_POLICY_ERROR, info)); | 
|  | EXPECT_EQ(ExceptionType::kProcessStarting, DecodeException(ZX_EXCP_PROCESS_STARTING, info)); | 
|  |  | 
|  | // Hardware breakpoints. The meaty stuff. | 
|  | info.regs.dr0 = 0x1111111111111111; | 
|  | info.regs.dr1 = 0x2222222222222222; | 
|  | info.regs.dr2 = 0x3333333333333333; | 
|  | info.regs.dr3 = 0x4444444444444444; | 
|  |  | 
|  | info.regs.dr6 = 0; | 
|  | X86_DBG_STATUS_BS_SET(&info.regs.dr6, 1); | 
|  | ASSERT_EQ(ExceptionType::kSingleStep, DecodeException(ZX_EXCP_HW_BREAKPOINT, info)); | 
|  |  | 
|  | info.regs.dr6 = 0; | 
|  | X86_DBG_STATUS_B0_SET(&info.regs.dr6, 1); | 
|  | EXPECT_EQ(ExceptionType::kHardwareBreakpoint, DecodeException(ZX_EXCP_HW_BREAKPOINT, info)); | 
|  | X86_DBG_CONTROL_RW0_SET(&info.regs.dr7, 1); | 
|  | EXPECT_EQ(ExceptionType::kWatchpoint, DecodeException(ZX_EXCP_HW_BREAKPOINT, info)); | 
|  |  | 
|  | info.regs.dr6 = 0; | 
|  | X86_DBG_STATUS_B1_SET(&info.regs.dr6, 1); | 
|  | EXPECT_EQ(ExceptionType::kHardwareBreakpoint, DecodeException(ZX_EXCP_HW_BREAKPOINT, info)); | 
|  | X86_DBG_CONTROL_RW1_SET(&info.regs.dr7, 1); | 
|  | EXPECT_EQ(ExceptionType::kWatchpoint, DecodeException(ZX_EXCP_HW_BREAKPOINT, info)); | 
|  |  | 
|  | info.regs.dr6 = 0; | 
|  | X86_DBG_STATUS_B2_SET(&info.regs.dr6, 1); | 
|  | EXPECT_EQ(ExceptionType::kHardwareBreakpoint, DecodeException(ZX_EXCP_HW_BREAKPOINT, info)); | 
|  | X86_DBG_CONTROL_RW2_SET(&info.regs.dr7, 1); | 
|  | EXPECT_EQ(ExceptionType::kWatchpoint, DecodeException(ZX_EXCP_HW_BREAKPOINT, info)); | 
|  |  | 
|  | info.regs.dr6 = 0; | 
|  | X86_DBG_STATUS_B3_SET(&info.regs.dr6, 1); | 
|  | EXPECT_EQ(ExceptionType::kHardwareBreakpoint, DecodeException(ZX_EXCP_HW_BREAKPOINT, info)); | 
|  | X86_DBG_CONTROL_RW3_SET(&info.regs.dr7, 1); | 
|  | EXPECT_EQ(ExceptionType::kWatchpoint, DecodeException(ZX_EXCP_HW_BREAKPOINT, info)); | 
|  | } | 
|  |  | 
|  | }  // namespace debug_ipc |