diff options
author | Chaoren Lin <chaorenl@google.com> | 2015-02-03 01:51:47 +0000 |
---|---|---|
committer | Chaoren Lin <chaorenl@google.com> | 2015-02-03 01:51:47 +0000 |
commit | 18fe6404f9bc379045f4bce801f1c7113cddc6a0 (patch) | |
tree | efb591cfed07504ecae67514806e536c98cc8153 /lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.cpp | |
parent | 2fe1d0abc2434c359c3761910cebceb00a5743bf (diff) | |
download | bcm5719-llvm-18fe6404f9bc379045f4bce801f1c7113cddc6a0.tar.gz bcm5719-llvm-18fe6404f9bc379045f4bce801f1c7113cddc6a0.zip |
Implement setting and clearing watchpoints.
llvm-svn: 227930
Diffstat (limited to 'lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.cpp')
-rw-r--r-- | lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.cpp | 167 |
1 files changed, 167 insertions, 0 deletions
diff --git a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.cpp b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.cpp index 649dfb238be..80df3265099 100644 --- a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.cpp +++ b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_x86_64.cpp @@ -1032,3 +1032,170 @@ NativeRegisterContextLinux_x86_64::WriteGPR() return process_p->WriteGPR (m_thread.GetID (), &m_gpr_x86_64, GetRegisterInfoInterface ().GetGPRSize ()).Success(); } +Error +NativeRegisterContextLinux_x86_64::IsWatchpointHit(uint8_t wp_index) +{ + if (wp_index >= NumSupportedHardwareWatchpoints()) + return Error ("Watchpoint index out of range"); + + RegisterValue reg_value; + Error error = ReadRegisterRaw(lldb_dr6_x86_64, reg_value); + if (error.Fail()) return error; + + uint64_t status_bits = reg_value.GetAsUInt64(); + + bool is_hit = status_bits & (1 << wp_index); + + error.SetError (!is_hit, lldb::eErrorTypeInvalid); + + return error; +} + +Error +NativeRegisterContextLinux_x86_64::IsWatchpointVacant(uint32_t wp_index) +{ + if (wp_index >= NumSupportedHardwareWatchpoints()) + return Error ("Watchpoint index out of range"); + + RegisterValue reg_value; + Error error = ReadRegisterRaw(lldb_dr7_x86_64, reg_value); + if (error.Fail()) return error; + + uint64_t control_bits = reg_value.GetAsUInt64(); + + bool is_vacant = !(control_bits & (1 << (2 * wp_index))); + + error.SetError (!is_vacant, lldb::eErrorTypeInvalid); + + return error; +} + +Error +NativeRegisterContextLinux_x86_64::SetHardwareWatchpointWithIndex( + lldb::addr_t addr, size_t size, uint32_t watch_flags, uint32_t wp_index) { + + if (wp_index >= NumSupportedHardwareWatchpoints()) + return Error ("Watchpoint index out of range"); + + if (watch_flags != 0x1 && watch_flags != 0x3) + return Error ("Invalid read/write bits for watchpoint"); + + if (size != 1 && size != 2 && size != 4 && size != 8) + return Error ("Invalid size for watchpoint"); + + Error error = IsWatchpointVacant (wp_index); + if (error.Fail()) return error; + + RegisterValue reg_value; + error = ReadRegisterRaw(lldb_dr7_x86_64, reg_value); + if (error.Fail()) return error; + + // for watchpoints 0, 1, 2, or 3, respectively, + // set bits 1, 3, 5, or 7 + uint64_t enable_bit = 1 << (2 * wp_index); + + // set bits 16-17, 20-21, 24-25, or 28-29 + // with 0b01 for write, and 0b11 for read/write + uint64_t rw_bits = watch_flags << (16 + 4 * wp_index); + + // set bits 18-19, 22-23, 26-27, or 30-31 + // with 0b00, 0b01, 0b10, or 0b11 + // for 1, 2, 8 (if supported), or 4 bytes, respectively + uint64_t size_bits = (size == 8 ? 0x2 : size - 1) << (18 + 4 * wp_index); + + uint64_t bit_mask = (0x3 << (2 * wp_index)) | (0xF << (16 + 4 * wp_index)); + + uint64_t control_bits = reg_value.GetAsUInt64() & ~bit_mask; + + control_bits |= enable_bit | rw_bits | size_bits; + + error = WriteRegister(m_reg_info.first_dr + wp_index, RegisterValue(addr)); + if (error.Fail()) return error; + + error = WriteRegister(lldb_dr7_x86_64, RegisterValue(control_bits)); + if (error.Fail()) return error; + + error.Clear(); + return error; +} + +bool +NativeRegisterContextLinux_x86_64::ClearHardwareWatchpoint(uint32_t wp_index) +{ + if (wp_index >= NumSupportedHardwareWatchpoints()) + return false; + + RegisterValue reg_value; + + // for watchpoints 0, 1, 2, or 3, respectively, + // clear bits 0, 1, 2, or 3 of the debug status register (DR6) + Error error = ReadRegisterRaw(lldb_dr6_x86_64, reg_value); + if (error.Fail()) return false; + uint64_t bit_mask = 1 << wp_index; + uint64_t status_bits = reg_value.GetAsUInt64() & ~bit_mask; + error = WriteRegister(lldb_dr6_x86_64, RegisterValue(status_bits)); + if (error.Fail()) return false; + + // for watchpoints 0, 1, 2, or 3, respectively, + // clear bits {0-1,16-19}, {2-3,20-23}, {4-5,24-27}, or {6-7,28-31} + // of the debug control register (DR7) + error = ReadRegisterRaw(lldb_dr7_x86_64, reg_value); + if (error.Fail()) return false; + bit_mask = (0x3 << (2 * wp_index)) | (0xF << (16 + 4 * wp_index)); + uint64_t control_bits = reg_value.GetAsUInt64() & ~bit_mask; + return WriteRegister(lldb_dr7_x86_64, RegisterValue(control_bits)).Success(); +} + +Error +NativeRegisterContextLinux_x86_64::ClearAllHardwareWatchpoints() +{ + RegisterValue reg_value; + + // clear bits {0-4} of the debug status register (DR6) + Error error = ReadRegisterRaw(lldb_dr6_x86_64, reg_value); + if (error.Fail()) return error; + uint64_t bit_mask = 0xF; + uint64_t status_bits = reg_value.GetAsUInt64() & ~bit_mask; + error = WriteRegister(lldb_dr6_x86_64, RegisterValue(status_bits)); + if (error.Fail()) return error; + + // clear bits {0-7,16-31} of the debug control register (DR7) + error = ReadRegisterRaw(lldb_dr7_x86_64, reg_value); + if (error.Fail()) return error; + bit_mask = 0xFF | (0xFFFF << 16); + uint64_t control_bits = reg_value.GetAsUInt64() & ~bit_mask; + return WriteRegister(lldb_dr7_x86_64, RegisterValue(control_bits)); +} + +uint32_t +NativeRegisterContextLinux_x86_64::SetHardwareWatchpoint( + lldb::addr_t addr, size_t size, uint32_t watch_flags) +{ + const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints(); + for (uint32_t wp_index = 0; wp_index < num_hw_watchpoints; ++wp_index) + if (IsWatchpointVacant(wp_index).Success()) + { + if (SetHardwareWatchpointWithIndex(addr, size, watch_flags, wp_index).Fail()) + continue; + return wp_index; + } + return LLDB_INVALID_INDEX32; +} + +lldb::addr_t +NativeRegisterContextLinux_x86_64::GetWatchpointAddress(uint32_t wp_index) +{ + if (wp_index >= NumSupportedHardwareWatchpoints()) + return LLDB_INVALID_ADDRESS; + RegisterValue reg_value; + if (ReadRegisterRaw(m_reg_info.first_dr + wp_index, reg_value).Fail()) + return LLDB_INVALID_ADDRESS; + return reg_value.GetAsUInt64(); +} + +uint32_t +NativeRegisterContextLinux_x86_64::NumSupportedHardwareWatchpoints () +{ + // Available debug address registers: dr0, dr1, dr2, dr3 + return 4; +} |