diff --git a/src/developer/debug/debug_agent/arch_x64.cc b/src/developer/debug/debug_agent/arch_x64.cc index 5054e66c6851e5384a274a420aef86029af1178e..5084e6c0a7cfa7489d8512f1b78f1b3e45c22899 100644 --- a/src/developer/debug/debug_agent/arch_x64.cc +++ b/src/developer/debug/debug_agent/arch_x64.cc @@ -10,6 +10,7 @@ #include "src/developer/debug/debug_agent/arch_x64_helpers.h" #include "src/developer/debug/debug_agent/debugged_thread.h" #include "src/developer/debug/ipc/register_desc.h" +#include "src/developer/debug/shared/arch_x86.h" #include "src/developer/debug/shared/logging/logging.h" namespace debug_agent { @@ -252,12 +253,12 @@ debug_ipc::NotifyException::Type ArchProvider::DecodeExceptionType( << DR6ToString(debug_regs.dr6); // HW breakpoints have priority over single-step. - if (FLAG_VALUE(debug_regs.dr6, kDR6B0) || - FLAG_VALUE(debug_regs.dr6, kDR6B1) || - FLAG_VALUE(debug_regs.dr6, kDR6B2) || - FLAG_VALUE(debug_regs.dr6, kDR6B3)) { + if (X86_FLAG_VALUE(debug_regs.dr6, DR6B0) || + X86_FLAG_VALUE(debug_regs.dr6, DR6B1) || + X86_FLAG_VALUE(debug_regs.dr6, DR6B2) || + X86_FLAG_VALUE(debug_regs.dr6, DR6B3)) { return debug_ipc::NotifyException::Type::kHardware; - } else if (FLAG_VALUE(debug_regs.dr6, kDR6BS)) { + } else if (X86_FLAG_VALUE(debug_regs.dr6, DR6BS)) { return debug_ipc::NotifyException::Type::kSingleStep; } else { FXL_NOTREACHED() << "x86: No known hw exception set in DR6"; diff --git a/src/developer/debug/debug_agent/arch_x64.h b/src/developer/debug/debug_agent/arch_x64.h index a5cb05cb194bcbe5e50560725b103cba25744bc7..b6008b2603e78d09ef6f89297dd1e01a9979c1a6 100644 --- a/src/developer/debug/debug_agent/arch_x64.h +++ b/src/developer/debug/debug_agent/arch_x64.h @@ -15,44 +15,5 @@ namespace arch { // The type that is large enough to hold the debug breakpoint CPU instruction. using BreakInstructionType = uint8_t; -#define FLAG_VALUE(val, shift) ((val) & (shift)) - -// DR6 ------------------------------------------------------------------------- - -constexpr uint64_t kDR6B0 = (1 << 0); -constexpr uint64_t kDR6B1 = (1 << 1); -constexpr uint64_t kDR6B2 = (1 << 2); -constexpr uint64_t kDR6B3 = (1 << 3); -constexpr uint64_t kDR6BD = (1 << 13); -constexpr uint64_t kDR6BS = (1 << 14); -constexpr uint64_t kDR6BT = (1 << 15); - -constexpr uint64_t kDR6Mask(0xffff0ff0ul); - -// DR7 ------------------------------------------------------------------------- - -constexpr uint64_t kDR7L0 = (1 << 0); -constexpr uint64_t kDR7G0 = (1 << 1); -constexpr uint64_t kDR7L1 = (1 << 2); -constexpr uint64_t kDR7G1 = (1 << 3); -constexpr uint64_t kDR7L2 = (1 << 4); -constexpr uint64_t kDR7G2 = (1 << 5); -constexpr uint64_t kDR7L3 = (1 << 6); -constexpr uint64_t kDR7G3 = (1 << 7); -// Not used for now. -constexpr uint64_t kDR7LE = (1 << 8); -constexpr uint64_t kDR7GE = (1 << 9); -constexpr uint64_t kDR7GD = (1 << 13); -constexpr uint64_t kDR7RW0 = (1 << 16); -constexpr uint64_t kDR7LEN0 = (1 << 18); -constexpr uint64_t kDR7RW1 = (1 << 20); -constexpr uint64_t kDR7LEN1 = (1 << 22); -constexpr uint64_t kDR7RW2 = (1 << 24); -constexpr uint64_t kDR7LEN2 = (1 << 26); -constexpr uint64_t kDR7RW3 = (1 << 28); -constexpr uint64_t kDR7LEN3 = (1 << 30); - -constexpr uint64_t kDR7Mask((1ul << 10) | kDR7LE | kDR7GE); - } // namespace arch } // namespace debug_agent diff --git a/src/developer/debug/debug_agent/arch_x64_helpers.cc b/src/developer/debug/debug_agent/arch_x64_helpers.cc index 032f5dfed4d800c553d6966f3a47011e82392943..2424ff1f9a5de9103c8eb63749ea98f60382e2cd 100644 --- a/src/developer/debug/debug_agent/arch_x64_helpers.cc +++ b/src/developer/debug/debug_agent/arch_x64_helpers.cc @@ -16,81 +16,85 @@ namespace arch { namespace { -struct DebugRegMask { - int index = -1; - uint64_t bp_mask = 0; // Enable mask within DR7 - uint64_t rw_mask = 0; // RW mask within DR7 - uint64_t len_mask = 0; // LEN mask within DR7 -}; - -const DebugRegMask* GetDebugRegisterMasks(size_t index) { - static std::vector<DebugRegMask> masks = { - {0, kDR7L0, kDR7RW0 | (kDR7RW0 << 1), kDR7LEN0 | (kDR7LEN0 << 1)}, - {1, kDR7L1, kDR7RW1 | (kDR7RW1 << 1), kDR7LEN1 | (kDR7LEN1 << 1)}, - {2, kDR7L2, kDR7RW2 | (kDR7RW2 << 1), kDR7LEN2 | (kDR7LEN2 << 1)}, - {3, kDR7L3, kDR7RW3 | (kDR7RW3 << 1), kDR7LEN3 | (kDR7LEN3 << 1)}, +uint64_t HWBreakpointEnabled(uint64_t dr7, size_t index) { + FXL_DCHECK(index < 4); + static uint64_t masks[4] = { + X86_FLAG_MASK(DR7L0), + X86_FLAG_MASK(DR7L1), + X86_FLAG_MASK(DR7L2), + X86_FLAG_MASK(DR7L3) }; - FXL_DCHECK(index < masks.size()); - return &masks[index]; + + return (dr7 & masks[index]) != 0; +} + +// Mask needed to clear a particular HW breakpoint. +uint64_t HWBreakpointD7ClearMask(size_t index) { + FXL_DCHECK(index < 4); + static uint64_t masks[4] = { + ~(X86_FLAG_MASK(DR7L0) | X86_FLAG_MASK(DR7RW0) | X86_FLAG_MASK(DR7LEN0)), + ~(X86_FLAG_MASK(DR7L1) | X86_FLAG_MASK(DR7RW1) | X86_FLAG_MASK(DR7LEN1)), + ~(X86_FLAG_MASK(DR7L2) | X86_FLAG_MASK(DR7RW2) | X86_FLAG_MASK(DR7LEN2)), + ~(X86_FLAG_MASK(DR7L3) | X86_FLAG_MASK(DR7RW3) | X86_FLAG_MASK(DR7LEN3)), + }; + return masks[index]; +} + +// Mask needed to set a particular HW breakpoint. +uint64_t HWBreakpointDR7SetMask(size_t index) { + FXL_DCHECK(index < 4); + // Mask is: L = 1, RW = 00, LEN = 10 + static uint64_t dr_masks[4] = { + X86_FLAG_MASK(DR7L0), + X86_FLAG_MASK(DR7L1), + X86_FLAG_MASK(DR7L2), + X86_FLAG_MASK(DR7L3), + }; + return dr_masks[index]; } } // namespace zx_status_t SetupHWBreakpoint(uint64_t address, zx_thread_state_debug_regs_t* debug_regs) { - // Search for an unset register. - // TODO(donosoc): This doesn't check that the address is already set. - const DebugRegMask* slot = nullptr; + // Search for a free slot. + int slot = -1; for (size_t i = 0; i < 4; i++) { - const DebugRegMask* mask = GetDebugRegisterMasks(i); - // If it's the same address or it's free, we found our slot. - bool active = FLAG_VALUE(debug_regs->dr7, mask->bp_mask); - if (debug_regs->dr[i] == address || !active) { - slot = mask; + if (HWBreakpointEnabled(debug_regs->dr7, i)) { + // If it's already bound there, we don't need to do anything. + if (debug_regs->dr[i] == address) + return ZX_ERR_ALREADY_BOUND; + } else { + slot = i; break; } } - if (!slot) + if (slot == -1) return ZX_ERR_NO_RESOURCES; - debug_regs->dr[slot->index] = address; - // Modify the DR7 register. - // TODO(donosoc): For now only add execution breakpoints. - uint64_t dr7 = debug_regs->dr7; - dr7 |= slot->bp_mask; // Activate the breakpoint. - uint64_t mask = ~(slot->rw_mask); - // TODO(donosoc): Handle LEN properties of the breakpoint. - dr7 &= mask; - debug_regs->dr7 = dr7; - + // We found a slot, we bind the address. + debug_regs->dr[slot] = address; + debug_regs->dr7 &= HWBreakpointD7ClearMask(slot); + debug_regs->dr7 |= HWBreakpointDR7SetMask(slot); return ZX_OK; } zx_status_t RemoveHWBreakpoint(uint64_t address, zx_thread_state_debug_regs_t* debug_regs) { - // Search for the address. - bool found = false; - for (size_t i = 0; i < 4; i++) { + // Search for the slot. + for (int i = 0; i < 4; i++) { if (address != debug_regs->dr[i]) continue; - const DebugRegMask* mask = GetDebugRegisterMasks(i); - // Only unset the - uint64_t dr7 = debug_regs->dr7; - dr7 &= ~(mask->bp_mask); // Disable the breakpoint. - + // Clear this breakpoint. debug_regs->dr[i] = 0; - debug_regs->dr7 = dr7; - - found = true; + debug_regs->dr7 &= HWBreakpointD7ClearMask(i); + return ZX_OK; } - // No register found, we warn the caller. No change was issued. - if (!found) - return ZX_ERR_OUT_OF_RANGE; - - return ZX_OK; + // We didn't find the address. + return ZX_ERR_OUT_OF_RANGE; } zx_status_t WriteGeneralRegisters(const std::vector<debug_ipc::Register>& regs, @@ -152,7 +156,7 @@ std::string DebugRegistersToString(const zx_thread_state_debug_regs_t& regs) { << "DR2: 0x" << std::hex << regs.dr[2] << std::endl << "DR3: 0x" << std::hex << regs.dr[3] << std::endl << "DR6: " << DR6ToString(regs.dr6) << std::endl - << "DR7: 0x" << std::hex << regs.dr7 << std::endl; + << "DR7: " << DR7ToString(regs.dr7) << std::endl; return ss.str(); } @@ -160,10 +164,27 @@ std::string DebugRegistersToString(const zx_thread_state_debug_regs_t& regs) { std::string DR6ToString(uint64_t dr6) { return fxl::StringPrintf( "0x%lx: B0=%d, B1=%d, B2=%d, B3=%d, BD=%d, BS=%d, BT=%d", dr6, - X86_FLAG_VALUE(dr6, Dr6B0), X86_FLAG_VALUE(dr6, Dr6B1), - X86_FLAG_VALUE(dr6, Dr6B2), X86_FLAG_VALUE(dr6, Dr6B3), - X86_FLAG_VALUE(dr6, Dr6BD), X86_FLAG_VALUE(dr6, Dr6BS), - X86_FLAG_VALUE(dr6, Dr6BT)); + X86_FLAG_VALUE(dr6, DR6B0), X86_FLAG_VALUE(dr6, DR6B1), + X86_FLAG_VALUE(dr6, DR6B2), X86_FLAG_VALUE(dr6, DR6B3), + X86_FLAG_VALUE(dr6, DR6BD), X86_FLAG_VALUE(dr6, DR6BS), + X86_FLAG_VALUE(dr6, DR6BT)); +} + +std::string DR7ToString(uint64_t dr7) { + return fxl::StringPrintf( + "0x%lx: L0=%d, G0=%d, L1=%d, G1=%d, L2=%d, G2=%d, L3=%d, G4=%d, LE=%d, " + "GE=%d, GD=%d, R/W0=%d, LEN0=%d, R/W1=%d, LEN1=%d, R/W2=%d, LEN2=%d, " + "R/W3=%d, LEN3=%d", + dr7, X86_FLAG_VALUE(dr7, DR7L0), X86_FLAG_VALUE(dr7, DR7G0), + X86_FLAG_VALUE(dr7, DR7L1), X86_FLAG_VALUE(dr7, DR7G1), + X86_FLAG_VALUE(dr7, DR7L2), X86_FLAG_VALUE(dr7, DR7G2), + X86_FLAG_VALUE(dr7, DR7L3), X86_FLAG_VALUE(dr7, DR7G3), + X86_FLAG_VALUE(dr7, DR7LE), X86_FLAG_VALUE(dr7, DR7GE), + X86_FLAG_VALUE(dr7, DR7GD), X86_FLAG_VALUE(dr7, DR7RW0), + X86_FLAG_VALUE(dr7, DR7LEN0), X86_FLAG_VALUE(dr7, DR7RW1), + X86_FLAG_VALUE(dr7, DR7LEN1), X86_FLAG_VALUE(dr7, DR7RW2), + X86_FLAG_VALUE(dr7, DR7LEN2), X86_FLAG_VALUE(dr7, DR7RW3), + X86_FLAG_VALUE(dr7, DR7LEN3)); } } // namespace arch diff --git a/src/developer/debug/debug_agent/arch_x64_helpers.h b/src/developer/debug/debug_agent/arch_x64_helpers.h index 9d1730d046ad3abd145fcd9e977c81462a15f7d8..0c1b0577e4e96afafa43a9312c7142c9a8d90f64 100644 --- a/src/developer/debug/debug_agent/arch_x64_helpers.h +++ b/src/developer/debug/debug_agent/arch_x64_helpers.h @@ -43,5 +43,7 @@ std::string DebugRegistersToString(const zx_thread_state_debug_regs_t&); std::string DR6ToString(uint64_t dr6); +std::string DR7ToString(uint64_t dr7); + } // namespace arch } // namespace debug_agent diff --git a/src/developer/debug/debug_agent/arch_x64_helpers_unittest.cc b/src/developer/debug/debug_agent/arch_x64_helpers_unittest.cc index 9bca06515523b7a38448a0d659df29a252acfbcb..6ef6f758cf31571f461d55a48458cf3f5c5930a6 100644 --- a/src/developer/debug/debug_agent/arch_x64_helpers_unittest.cc +++ b/src/developer/debug/debug_agent/arch_x64_helpers_unittest.cc @@ -7,24 +7,18 @@ #include <gtest/gtest.h> #include "src/developer/debug/ipc/register_test_support.h" +#include "src/developer/debug/shared/arch_x86.h" #include "src/developer/debug/shared/logging/file_line_function.h" #include "src/developer/debug/shared/zx_status.h" - #include "src/lib/fxl/logging.h" +using namespace debug_ipc; + namespace debug_agent { namespace arch { namespace { -zx_thread_state_debug_regs_t GetDefaultRegs() { - zx_thread_state_debug_regs_t debug_regs = {}; - debug_regs.dr6 = kDR6Mask; - debug_regs.dr7 = kDR7Mask; - - return debug_regs; -} - void SetupHWBreakpointTest(debug_ipc::FileLineFunction file_line, zx_thread_state_debug_regs_t* debug_regs, uint64_t address, zx_status_t expected_result) { @@ -45,6 +39,28 @@ void RemoveHWBreakpointTest(debug_ipc::FileLineFunction file_line, << ", expected: " << debug_ipc::ZxStatusToString(expected_result); } +uint64_t GetHWBreakpointDR7Mask(size_t index) { + FXL_DCHECK(index < 4); + // Mask is: L = 1, RW = 00, LEN = 10 + static uint64_t dr_masks[4] = { + X86_FLAG_MASK(DR7L0), + X86_FLAG_MASK(DR7L1), + X86_FLAG_MASK(DR7L2), + X86_FLAG_MASK(DR7L3), + }; + return dr_masks[index]; +} + +uint64_t JoinDR7Masks(std::initializer_list<size_t> indices = {}) { + uint64_t result = 0; + for (size_t index : indices) { + FXL_DCHECK(index < 4); + result |= GetHWBreakpointDR7Mask(index); + } + + return result; +} + constexpr uint64_t kAddress1 = 0x0123; constexpr uint64_t kAddress2 = 0x4567; constexpr uint64_t kAddress3 = 0x89ab; @@ -54,24 +70,25 @@ constexpr uint64_t kAddress5 = 0xdeadbeef; } // namespace TEST(x64Helpers, SettingHWBreakpoints) { - auto debug_regs = GetDefaultRegs(); + zx_thread_state_debug_regs_t debug_regs = {}; SetupHWBreakpointTest(FROM_HERE_NO_FUNC, &debug_regs, kAddress1, ZX_OK); EXPECT_EQ(debug_regs.dr[0], kAddress1); EXPECT_EQ(debug_regs.dr[1], 0u); EXPECT_EQ(debug_regs.dr[2], 0u); EXPECT_EQ(debug_regs.dr[3], 0u); - EXPECT_EQ(debug_regs.dr6, kDR6Mask); - EXPECT_EQ(debug_regs.dr7, kDR7Mask | kDR7L0 | 0 | 0 | 0); + EXPECT_EQ(debug_regs.dr6, 0u); + EXPECT_EQ(debug_regs.dr7, JoinDR7Masks({0})); // Adding the same breakpoint should detect that the same already exists. - SetupHWBreakpointTest(FROM_HERE_NO_FUNC, &debug_regs, kAddress1, ZX_OK); + SetupHWBreakpointTest(FROM_HERE_NO_FUNC, &debug_regs, kAddress1, + ZX_ERR_ALREADY_BOUND); EXPECT_EQ(debug_regs.dr[0], kAddress1); EXPECT_EQ(debug_regs.dr[1], 0u); EXPECT_EQ(debug_regs.dr[2], 0u); EXPECT_EQ(debug_regs.dr[3], 0u); - EXPECT_EQ(debug_regs.dr6, kDR6Mask); - EXPECT_EQ(debug_regs.dr7, kDR7Mask | kDR7L0 | 0 | 0 | 0); + EXPECT_EQ(debug_regs.dr6, 0u); + EXPECT_EQ(debug_regs.dr7, JoinDR7Masks({0})); // Continuing adding should append. SetupHWBreakpointTest(FROM_HERE_NO_FUNC, &debug_regs, kAddress2, ZX_OK); @@ -79,24 +96,24 @@ TEST(x64Helpers, SettingHWBreakpoints) { EXPECT_EQ(debug_regs.dr[1], kAddress2); EXPECT_EQ(debug_regs.dr[2], 0u); EXPECT_EQ(debug_regs.dr[3], 0u); - EXPECT_EQ(debug_regs.dr6, kDR6Mask); - EXPECT_EQ(debug_regs.dr7, kDR7Mask | kDR7L0 | kDR7L1 | 0 | 0); + EXPECT_EQ(debug_regs.dr6, 0u); + EXPECT_EQ(debug_regs.dr7, JoinDR7Masks({0, 1})); SetupHWBreakpointTest(FROM_HERE_NO_FUNC, &debug_regs, kAddress3, ZX_OK); EXPECT_EQ(debug_regs.dr[0], kAddress1); EXPECT_EQ(debug_regs.dr[1], kAddress2); EXPECT_EQ(debug_regs.dr[2], kAddress3); EXPECT_EQ(debug_regs.dr[3], 0u); - EXPECT_EQ(debug_regs.dr6, kDR6Mask); - EXPECT_EQ(debug_regs.dr7, kDR7Mask | kDR7L0 | kDR7L1 | kDR7L2 | 0); + EXPECT_EQ(debug_regs.dr6, 0u); + EXPECT_EQ(debug_regs.dr7, JoinDR7Masks({0, 1, 2})); SetupHWBreakpointTest(FROM_HERE_NO_FUNC, &debug_regs, kAddress4, ZX_OK); EXPECT_EQ(debug_regs.dr[0], kAddress1); EXPECT_EQ(debug_regs.dr[1], kAddress2); EXPECT_EQ(debug_regs.dr[2], kAddress3); EXPECT_EQ(debug_regs.dr[3], kAddress4); - EXPECT_EQ(debug_regs.dr6, kDR6Mask); - EXPECT_EQ(debug_regs.dr7, kDR7Mask | kDR7L0 | kDR7L1 | kDR7L2 | kDR7L3); + EXPECT_EQ(debug_regs.dr6, 0u); + EXPECT_EQ(debug_regs.dr7, JoinDR7Masks({0, 1, 2, 3})); // No more registers left should not change anything. SetupHWBreakpointTest(FROM_HERE_NO_FUNC, &debug_regs, kAddress5, @@ -105,12 +122,12 @@ TEST(x64Helpers, SettingHWBreakpoints) { EXPECT_EQ(debug_regs.dr[1], kAddress2); EXPECT_EQ(debug_regs.dr[2], kAddress3); EXPECT_EQ(debug_regs.dr[3], kAddress4); - EXPECT_EQ(debug_regs.dr6, kDR6Mask); - EXPECT_EQ(debug_regs.dr7, kDR7Mask | kDR7L0 | kDR7L1 | kDR7L2 | kDR7L3); + EXPECT_EQ(debug_regs.dr6, 0u); + EXPECT_EQ(debug_regs.dr7, JoinDR7Masks({0, 1, 2, 3})); } TEST(x64Helpers, RemovingHWBreakpoint) { - auto debug_regs = GetDefaultRegs(); + zx_thread_state_debug_regs_t debug_regs = {}; // Previous state verifies the state of this calls. SetupHWBreakpointTest(FROM_HERE_NO_FUNC, &debug_regs, kAddress1, ZX_OK); @@ -125,8 +142,8 @@ TEST(x64Helpers, RemovingHWBreakpoint) { EXPECT_EQ(debug_regs.dr[1], kAddress2); EXPECT_EQ(debug_regs.dr[2], 0u); EXPECT_EQ(debug_regs.dr[3], kAddress4); - EXPECT_EQ(debug_regs.dr6, kDR6Mask); - EXPECT_EQ(debug_regs.dr7, kDR7Mask | kDR7L0 | kDR7L1 | 0 | kDR7L3); + EXPECT_EQ(debug_regs.dr6, 0u); + EXPECT_EQ(debug_regs.dr7, JoinDR7Masks({0, 1, 3})); // Removing same breakpoint should not work. RemoveHWBreakpointTest(FROM_HERE_NO_FUNC, &debug_regs, kAddress3, @@ -135,8 +152,8 @@ TEST(x64Helpers, RemovingHWBreakpoint) { EXPECT_EQ(debug_regs.dr[1], kAddress2); EXPECT_EQ(debug_regs.dr[2], 0u); EXPECT_EQ(debug_regs.dr[3], kAddress4); - EXPECT_EQ(debug_regs.dr6, kDR6Mask); - EXPECT_EQ(debug_regs.dr7, kDR7Mask | kDR7L0 | kDR7L1 | 0 | kDR7L3); + EXPECT_EQ(debug_regs.dr6, 0u); + EXPECT_EQ(debug_regs.dr7, JoinDR7Masks({0, 1, 3})); // Removing an unknown address should warn and change nothing. RemoveHWBreakpointTest(FROM_HERE_NO_FUNC, &debug_regs, 0xaaaaaaa, @@ -145,16 +162,16 @@ TEST(x64Helpers, RemovingHWBreakpoint) { EXPECT_EQ(debug_regs.dr[1], kAddress2); EXPECT_EQ(debug_regs.dr[2], 0u); EXPECT_EQ(debug_regs.dr[3], kAddress4); - EXPECT_EQ(debug_regs.dr6, kDR6Mask); - EXPECT_EQ(debug_regs.dr7, kDR7Mask | kDR7L0 | kDR7L1 | 0 | kDR7L3); + EXPECT_EQ(debug_regs.dr6, 0u); + EXPECT_EQ(debug_regs.dr7, JoinDR7Masks({0, 1, 3})); RemoveHWBreakpointTest(FROM_HERE_NO_FUNC, &debug_regs, kAddress1, ZX_OK); EXPECT_EQ(debug_regs.dr[0], 0u); EXPECT_EQ(debug_regs.dr[1], kAddress2); EXPECT_EQ(debug_regs.dr[2], 0u); EXPECT_EQ(debug_regs.dr[3], kAddress4); - EXPECT_EQ(debug_regs.dr6, kDR6Mask); - EXPECT_EQ(debug_regs.dr7, kDR7Mask | 0 | kDR7L1 | 0 | kDR7L3); + EXPECT_EQ(debug_regs.dr6, 0u); + EXPECT_EQ(debug_regs.dr7, JoinDR7Masks({1, 3})); // Adding again should work. SetupHWBreakpointTest(FROM_HERE_NO_FUNC, &debug_regs, kAddress5, ZX_OK); @@ -162,25 +179,26 @@ TEST(x64Helpers, RemovingHWBreakpoint) { EXPECT_EQ(debug_regs.dr[1], kAddress2); EXPECT_EQ(debug_regs.dr[2], 0u); EXPECT_EQ(debug_regs.dr[3], kAddress4); - EXPECT_EQ(debug_regs.dr6, kDR6Mask); - EXPECT_EQ(debug_regs.dr7, kDR7Mask | kDR7L0 | kDR7L1 | 0 | kDR7L3); + EXPECT_EQ(debug_regs.dr6, 0u); + EXPECT_EQ(debug_regs.dr7, JoinDR7Masks({0, 1, 3})); SetupHWBreakpointTest(FROM_HERE_NO_FUNC, &debug_regs, kAddress1, ZX_OK); EXPECT_EQ(debug_regs.dr[0], kAddress5); EXPECT_EQ(debug_regs.dr[1], kAddress2); EXPECT_EQ(debug_regs.dr[2], kAddress1); EXPECT_EQ(debug_regs.dr[3], kAddress4); - EXPECT_EQ(debug_regs.dr6, kDR6Mask); - EXPECT_EQ(debug_regs.dr7, kDR7Mask | kDR7L0 | kDR7L1 | kDR7L2 | kDR7L3); + EXPECT_EQ(debug_regs.dr6, 0u); + EXPECT_EQ(debug_regs.dr7, JoinDR7Masks({0, 1, 2, 3})); // Already exists should not change. - SetupHWBreakpointTest(FROM_HERE_NO_FUNC, &debug_regs, kAddress5, ZX_OK); + SetupHWBreakpointTest(FROM_HERE_NO_FUNC, &debug_regs, kAddress5, + ZX_ERR_ALREADY_BOUND); EXPECT_EQ(debug_regs.dr[0], kAddress5); EXPECT_EQ(debug_regs.dr[1], kAddress2); EXPECT_EQ(debug_regs.dr[2], kAddress1); EXPECT_EQ(debug_regs.dr[3], kAddress4); - EXPECT_EQ(debug_regs.dr6, kDR6Mask); - EXPECT_EQ(debug_regs.dr7, kDR7Mask | kDR7L0 | kDR7L1 | kDR7L2 | kDR7L3); + EXPECT_EQ(debug_regs.dr6, 0u); + EXPECT_EQ(debug_regs.dr7, JoinDR7Masks({0, 1, 2, 3})); // No more resources. SetupHWBreakpointTest(FROM_HERE_NO_FUNC, &debug_regs, kAddress3, @@ -189,8 +207,8 @@ TEST(x64Helpers, RemovingHWBreakpoint) { EXPECT_EQ(debug_regs.dr[1], kAddress2); EXPECT_EQ(debug_regs.dr[2], kAddress1); EXPECT_EQ(debug_regs.dr[3], kAddress4); - EXPECT_EQ(debug_regs.dr6, kDR6Mask); - EXPECT_EQ(debug_regs.dr7, kDR7Mask | kDR7L0 | kDR7L1 | kDR7L2 | kDR7L3); + EXPECT_EQ(debug_regs.dr6, 0u); + EXPECT_EQ(debug_regs.dr7, JoinDR7Masks({0, 1, 2, 3})); } TEST(x64Helpers, WritingGeneralRegs) { diff --git a/src/developer/debug/debug_agent/integration_tests/breakpoint_test.cc b/src/developer/debug/debug_agent/integration_tests/breakpoint_test.cc index 9533bf50901c8ec7f744bc3c4e833d2bcd61735e..1a70af13c6e5c88808a2209961975210360c85b8 100644 --- a/src/developer/debug/debug_agent/integration_tests/breakpoint_test.cc +++ b/src/developer/debug/debug_agent/integration_tests/breakpoint_test.cc @@ -190,10 +190,6 @@ TEST(BreakpointIntegration, SWBreakpoint) { } } -// TODO(DX-909): Some HW capabilities (like HW breakpoints) are not well -// emulated by QEMU without KVM. This will sometimes make tests -// fail or even crash QEMU. The bot configuration should avoid -// running this test on QEMU. TEST(BreakpointIntegration, HWBreakpoint) { // We attempt to load the pre-made .so. SoWrapper so_wrapper; @@ -279,7 +275,8 @@ TEST(BreakpointIntegration, HWBreakpoint) { // We should have received an exception now. debug_ipc::NotifyException exception = mock_stream_backend.exception(); EXPECT_EQ(exception.thread.process_koid, launch_reply.process_id); - EXPECT_EQ(exception.type, debug_ipc::NotifyException::Type::kHardware); + EXPECT_EQ(exception.type, debug_ipc::NotifyException::Type::kHardware) + << "Got: " << debug_ipc::NotifyException::TypeToString(exception.type); ASSERT_EQ(exception.hit_breakpoints.size(), 1u); // Verify that the correct breakpoint was hit. diff --git a/src/developer/debug/shared/arch_x86.h b/src/developer/debug/shared/arch_x86.h index df76a919b3af2aaeed32d23514dcda993bdacf5f..4137df52a030021a0384b51e17b7e847c446c3cd 100644 --- a/src/developer/debug/shared/arch_x86.h +++ b/src/developer/debug/shared/arch_x86.h @@ -27,96 +27,96 @@ namespace debug_ipc { _X86_FLAG_VALUE(value, ::debug_ipc::k##flag##Shift, \ ::debug_ipc::k##flag##Mask) -constexpr uint64_t kRflagsCFShift = 0; // Carry Flag. +constexpr uint64_t kRflagsCFShift = 0; // Carry Flag. constexpr uint64_t kRflagsCFMask = 0x1; -constexpr uint64_t kRflagsPFShift = 2; // Parity Flag. +constexpr uint64_t kRflagsPFShift = 2; // Parity Flag. constexpr uint64_t kRflagsPFMask = 0x1; -constexpr uint64_t kRflagsAFShift = 4; // Aux Carry Flag. +constexpr uint64_t kRflagsAFShift = 4; // Aux Carry Flag. constexpr uint64_t kRflagsAFMask = 0x1; -constexpr uint64_t kRflagsZFShift = 6; // Zero Flag. +constexpr uint64_t kRflagsZFShift = 6; // Zero Flag. constexpr uint64_t kRflagsZFMask = 0x1; -constexpr uint64_t kRflagsSFShift = 7; // Sign Flag. +constexpr uint64_t kRflagsSFShift = 7; // Sign Flag. constexpr uint64_t kRflagsSFMask = 0x1; -constexpr uint64_t kRflagsTFShift = 8; // Trap Flag. +constexpr uint64_t kRflagsTFShift = 8; // Trap Flag. constexpr uint64_t kRflagsTFMask = 0x1; -constexpr uint64_t kRflagsIFShift = 9; // Interrupt Enable Flag. +constexpr uint64_t kRflagsIFShift = 9; // Interrupt Enable Flag. constexpr uint64_t kRflagsIFMask = 0x1; -constexpr uint64_t kRflagsDFShift = 10; // Direction Flag. +constexpr uint64_t kRflagsDFShift = 10; // Direction Flag. constexpr uint64_t kRflagsDFMask = 0x1; -constexpr uint64_t kRflagsOFShift = 11; // Overflow Flag. +constexpr uint64_t kRflagsOFShift = 11; // Overflow Flag. constexpr uint64_t kRflagsOFMask = 0x1; -constexpr uint64_t kRflagsIOPLShift = 12; // IO Priviledge Level. +constexpr uint64_t kRflagsIOPLShift = 12; // IO Priviledge Level. constexpr uint64_t kRflagsIOPLMask = 0x3; -constexpr uint64_t kRflagsNTShift = 14; // Nested Task. +constexpr uint64_t kRflagsNTShift = 14; // Nested Task. constexpr uint64_t kRflagsNTMask = 0x1; -constexpr uint64_t kRflagsRFShift = 16; // Resume Flag. +constexpr uint64_t kRflagsRFShift = 16; // Resume Flag. constexpr uint64_t kRflagsRFMask = 0x1; -constexpr uint64_t kRflagsVMShift = 17; // Virtual-8086 Mode. +constexpr uint64_t kRflagsVMShift = 17; // Virtual-8086 Mode. constexpr uint64_t kRflagsVMMask = 0x1; -constexpr uint64_t kRflagsACShift = 18; // Alignment Check/ Access Control. +constexpr uint64_t kRflagsACShift = 18; // Alignment Check/ Access Control. constexpr uint64_t kRflagsACMask = 0x1; constexpr uint64_t kRflagsVIFShift = 19; // Virtual Interrupt Flag. constexpr uint64_t kRflagsVIFMask = 0x1; constexpr uint64_t kRflagsVIPShift = 20; // Virtual Interrupt Pending. constexpr uint64_t kRflagsVIPMask = 0x1; -constexpr uint64_t kRflagsIDShift = 21; // ID Flag. +constexpr uint64_t kRflagsIDShift = 21; // ID Flag. constexpr uint64_t kRflagsIDMask = 0x1; -constexpr uint64_t kDr6B0Shift = 0; // HW Breakpoint 0. -constexpr uint64_t kDr6B0Mask = 0x1; -constexpr uint64_t kDr6B1Shift = 1; // HW Breakpoint 1. -constexpr uint64_t kDr6B1Mask = 0x1; -constexpr uint64_t kDr6B2Shift = 2; // HW Breakpoint 2. -constexpr uint64_t kDr6B2Mask = 0x1; -constexpr uint64_t kDr6B3Shift = 3; // HW Breakpoint 3. -constexpr uint64_t kDr6B3Mask = 0x1; -constexpr uint64_t kDr6BDShift = 13; // Breakpoint Debug Access Detected. -constexpr uint64_t kDr6BDMask = 0x1; -constexpr uint64_t kDr6BSShift = 14; // Single Step. -constexpr uint64_t kDr6BSMask = 0x1; -constexpr uint64_t kDr6BTShift = 15; // Breakpoint Task. -constexpr uint64_t kDr6BTMask = 0x1; +constexpr uint64_t kDR6B0Shift = 0; // HW Breakpoint 0. +constexpr uint64_t kDR6B0Mask = 0x1; +constexpr uint64_t kDR6B1Shift = 1; // HW Breakpoint 1. +constexpr uint64_t kDR6B1Mask = 0x1; +constexpr uint64_t kDR6B2Shift = 2; // HW Breakpoint 2. +constexpr uint64_t kDR6B2Mask = 0x1; +constexpr uint64_t kDR6B3Shift = 3; // HW Breakpoint 3. +constexpr uint64_t kDR6B3Mask = 0x1; +constexpr uint64_t kDR6BDShift = 13; // Breakpoint Debug Access Detected. +constexpr uint64_t kDR6BDMask = 0x1; +constexpr uint64_t kDR6BSShift = 14; // Single Step. +constexpr uint64_t kDR6BSMask = 0x1; +constexpr uint64_t kDR6BTShift = 15; // Breakpoint Task. +constexpr uint64_t kDR6BTMask = 0x1; -constexpr uint64_t kDr7L0Shift = 0; // HW Breakpoint 0 enabled. -constexpr uint64_t kDr7L0Mask = 0x1; -constexpr uint64_t kDr7G0Shift = 1; // Global Breakpoint 0 enabled (not used). -constexpr uint64_t kDr7G0Mask = 0x1; -constexpr uint64_t kDr7L1Shift = 2; // HW Breakpoint 1 enabled. -constexpr uint64_t kDr7L1Mask = 0x1; -constexpr uint64_t kDr7G1Shift = 3; // Global Breakpoint 1 enabled (not used). -constexpr uint64_t kDr7G1Mask = 0x1; -constexpr uint64_t kDr7L2Shift = 4; // HW Breakpoint 2 enabled. -constexpr uint64_t kDr7L2Mask = 0x1; -constexpr uint64_t kDr7G2Shift = 5; // Global Breakpoint 2 enabled (not used). -constexpr uint64_t kDr7G2Mask = 0x1; -constexpr uint64_t kDr7L3Shift = 6; // HW Breakpoint 3 enabled. -constexpr uint64_t kDr7L3Mask = 0x1; -constexpr uint64_t kDr7G3Shift = 7; // Global Breakpoint 3 enabled (not used). -constexpr uint64_t kDr7G3Mask = 0x1; -constexpr uint64_t kDr7LEShift = 8; // Local Exact enabled (not used). -constexpr uint64_t kDr7LEMask = 0x1; -constexpr uint64_t kDr7GEShift = 9; // Global Exact enabled (not used). -constexpr uint64_t kDr7GEMask = 0x1; -constexpr uint64_t kDr7GDShift = 13; // General Detect Enabled. -constexpr uint64_t kDr7GDMask = 0x1; +constexpr uint64_t kDR7L0Shift = 0; // HW Breakpoint 0 enabled. +constexpr uint64_t kDR7L0Mask = 0x1; +constexpr uint64_t kDR7G0Shift = 1; // Global Breakpoint 0 enabled (not used). +constexpr uint64_t kDR7G0Mask = 0x1; +constexpr uint64_t kDR7L1Shift = 2; // HW Breakpoint 1 enabled. +constexpr uint64_t kDR7L1Mask = 0x1; +constexpr uint64_t kDR7G1Shift = 3; // Global Breakpoint 1 enabled (not used). +constexpr uint64_t kDR7G1Mask = 0x1; +constexpr uint64_t kDR7L2Shift = 4; // HW Breakpoint 2 enabled. +constexpr uint64_t kDR7L2Mask = 0x1; +constexpr uint64_t kDR7G2Shift = 5; // Global Breakpoint 2 enabled (not used). +constexpr uint64_t kDR7G2Mask = 0x1; +constexpr uint64_t kDR7L3Shift = 6; // HW Breakpoint 3 enabled. +constexpr uint64_t kDR7L3Mask = 0x1; +constexpr uint64_t kDR7G3Shift = 7; // Global Breakpoint 3 enabled (not used). +constexpr uint64_t kDR7G3Mask = 0x1; +constexpr uint64_t kDR7LEShift = 8; // Local Exact enabled (not used). +constexpr uint64_t kDR7LEMask = 0x1; +constexpr uint64_t kDR7GEShift = 9; // Global Exact enabled (not used). +constexpr uint64_t kDR7GEMask = 0x1; +constexpr uint64_t kDR7GDShift = 13; // General Detect Enabled. +constexpr uint64_t kDR7GDMask = 0x1; -constexpr uint64_t kDr7RW0Shift = 16; // Bkpt 0 R/W (which exception to trap). -constexpr uint64_t kDr7RW0Mask = 0x3; -constexpr uint64_t kDr7LEN0Shift = 18; // Bkpt 0 LEN (len of address to match). -constexpr uint64_t kDr7LEN0Mask = 0x3; -constexpr uint64_t kDr7RW1Shift = 20; // Bkpt 1 R/W (exception type). -constexpr uint64_t kDr7RW1Mask = 0x3; -constexpr uint64_t kDr7LEN1Shift = 22; // Bkpt 1 LEN (len of address to match). -constexpr uint64_t kDr7LEN1Mask = 0x3; -constexpr uint64_t kDr7RW2Shift = 24; // Bkpt 2 R/W (exception type). -constexpr uint64_t kDr7RW2Mask = 0x3; -constexpr uint64_t kDr7LEN2Shift = 26; // Bkpt 2 LEN (len of address to match). -constexpr uint64_t kDr7LEN2Mask = 0x3; -constexpr uint64_t kDr7RW3Shift = 28; // Bkpt 3 R/W (exception type). -constexpr uint64_t kDr7RW3Mask = 0x3; -constexpr uint64_t kDr7LEN3Shift = 30; // Bkpt 3 LEN (len of address to match). -constexpr uint64_t kDr7LEN3Mask = 0x3; +constexpr uint64_t kDR7RW0Shift = 16; // Bkpt 0 R/W (which exception to trap). +constexpr uint64_t kDR7RW0Mask = 0x3; +constexpr uint64_t kDR7LEN0Shift = 18; // Bkpt 0 LEN (len of address to match). +constexpr uint64_t kDR7LEN0Mask = 0x3; +constexpr uint64_t kDR7RW1Shift = 20; // Bkpt 1 R/W (exception type). +constexpr uint64_t kDR7RW1Mask = 0x3; +constexpr uint64_t kDR7LEN1Shift = 22; // Bkpt 1 LEN (len of address to match). +constexpr uint64_t kDR7LEN1Mask = 0x3; +constexpr uint64_t kDR7RW2Shift = 24; // Bkpt 2 R/W (exception type). +constexpr uint64_t kDR7RW2Mask = 0x3; +constexpr uint64_t kDR7LEN2Shift = 26; // Bkpt 2 LEN (len of address to match). +constexpr uint64_t kDR7LEN2Mask = 0x3; +constexpr uint64_t kDR7RW3Shift = 28; // Bkpt 3 R/W (exception type). +constexpr uint64_t kDR7RW3Mask = 0x3; +constexpr uint64_t kDR7LEN3Shift = 30; // Bkpt 3 LEN (len of address to match). +constexpr uint64_t kDR7LEN3Mask = 0x3; } // namespace debug_ipc diff --git a/src/developer/debug/zxdb/console/format_register_x64.cc b/src/developer/debug/zxdb/console/format_register_x64.cc index 4583ffb89b3910f76b7befb671adc526948da2c4..fbf16fb0b6bb9dbf93dfa376b252f448077e50d8 100644 --- a/src/developer/debug/zxdb/console/format_register_x64.cc +++ b/src/developer/debug/zxdb/console/format_register_x64.cc @@ -247,10 +247,10 @@ std::vector<OutputBuffer> FormatDr6(const Register& dr6, result.emplace_back( fxl::StringPrintf( "B0=%d, B1=%d, B2=%d, B3=%d, BD=%d, BS=%d, BT=%d", - X86_FLAG_VALUE(value, Dr6B0), X86_FLAG_VALUE(value, Dr6B1), - X86_FLAG_VALUE(value, Dr6B2), X86_FLAG_VALUE(value, Dr6B3), - X86_FLAG_VALUE(value, Dr6BD), X86_FLAG_VALUE(value, Dr6BS), - X86_FLAG_VALUE(value, Dr6BT)), + X86_FLAG_VALUE(value, DR6B0), X86_FLAG_VALUE(value, DR6B1), + X86_FLAG_VALUE(value, DR6B2), X86_FLAG_VALUE(value, DR6B3), + X86_FLAG_VALUE(value, DR6BD), X86_FLAG_VALUE(value, DR6BS), + X86_FLAG_VALUE(value, DR6BT)), color); return result; @@ -273,12 +273,12 @@ void FormatDr7(const Register& dr7, TextForegroundColor color, "L0=%d, G0=%d, L1=%d, G1=%d, L2=%d, G2=%d, L3=%d, G4=%d, LE=%d, " "GE=%d, " "GD=%d", - X86_FLAG_VALUE(value, Dr7L0), X86_FLAG_VALUE(value, Dr7G0), - X86_FLAG_VALUE(value, Dr7L1), X86_FLAG_VALUE(value, Dr7G1), - X86_FLAG_VALUE(value, Dr7L2), X86_FLAG_VALUE(value, Dr7G2), - X86_FLAG_VALUE(value, Dr7L3), X86_FLAG_VALUE(value, Dr7G3), - X86_FLAG_VALUE(value, Dr7LE), X86_FLAG_VALUE(value, Dr7GE), - X86_FLAG_VALUE(value, Dr7GD)), + X86_FLAG_VALUE(value, DR7L0), X86_FLAG_VALUE(value, DR7G0), + X86_FLAG_VALUE(value, DR7L1), X86_FLAG_VALUE(value, DR7G1), + X86_FLAG_VALUE(value, DR7L2), X86_FLAG_VALUE(value, DR7G2), + X86_FLAG_VALUE(value, DR7L3), X86_FLAG_VALUE(value, DR7G3), + X86_FLAG_VALUE(value, DR7LE), X86_FLAG_VALUE(value, DR7GE), + X86_FLAG_VALUE(value, DR7GD)), color); // Second row only gets decoded values in the 3rd column. @@ -290,10 +290,10 @@ void FormatDr7(const Register& dr7, TextForegroundColor color, fxl::StringPrintf( "R/W0=%d, LEN0=%d, R/W1=%d, LEN1=%d, R/W2=%d, " "LEN2=%d, R/W3=%d, LEN3=%d", - X86_FLAG_VALUE(value, Dr7RW0), X86_FLAG_VALUE(value, Dr7LEN0), - X86_FLAG_VALUE(value, Dr7RW1), X86_FLAG_VALUE(value, Dr7LEN1), - X86_FLAG_VALUE(value, Dr7RW2), X86_FLAG_VALUE(value, Dr7LEN2), - X86_FLAG_VALUE(value, Dr7RW3), X86_FLAG_VALUE(value, Dr7LEN3)), + X86_FLAG_VALUE(value, DR7RW0), X86_FLAG_VALUE(value, DR7LEN0), + X86_FLAG_VALUE(value, DR7RW1), X86_FLAG_VALUE(value, DR7LEN1), + X86_FLAG_VALUE(value, DR7RW2), X86_FLAG_VALUE(value, DR7LEN2), + X86_FLAG_VALUE(value, DR7RW3), X86_FLAG_VALUE(value, DR7LEN3)), color); }