brintos

brintos / llvm-project-archived public Read only

0
0
Text · 9.1 KiB · 3038cbc Raw
277 lines · cpp
1//===-- NativeRegisterContextDBReg_x86.cpp --------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "NativeRegisterContextDBReg_x86.h"10#include "lldb/Utility/LLDBLog.h"11#include "lldb/Utility/RegisterValue.h"12 13#include "Plugins/Process/Utility/lldb-x86-register-enums.h"14 15using namespace lldb_private;16 17// Returns mask/value for status bit of wp_index in DR618static inline uint64_t GetStatusBit(uint32_t wp_index) {19  // DR6: ...BBBB20  //         3210 <- status bits for bp./wp. i; 1 if hit21  return 1ULL << wp_index;22}23 24// Returns mask/value for global enable bit of wp_index in DR725static inline uint64_t GetEnableBit(uint32_t wp_index) {26  // DR7: ...GLGLGLGL27  //         33221100 <- global/local enable for bp./wp.; 1 if enabled28  // we use global bits because NetBSD kernel does not preserve local29  // bits reliably; Linux seems fine with either30  return 1ULL << (2 * wp_index + 1);31}32 33// Returns mask for both enable bits of wp_index in DR734static inline uint64_t GetBothEnableBitMask(uint32_t wp_index) {35  // DR7: ...GLGLGLGL36  //         33221100 <- global/local enable for bp./wp.; 1 if enabled37  return 3ULL << (2 * wp_index + 1);38}39 40// Returns value for type bits of wp_index in DR741static inline uint64_t GetWatchTypeBits(uint32_t watch_flags,42                                        uint32_t wp_index) {43  // DR7:44  // bit: 3322222222221111...45  //      1098765432109876...46  // val: SSTTSSTTSSTTSSTT...47  // wp.: 3333222211110000...48  //49  // where T - type is 01 for write, 11 for r/w50  return static_cast<uint64_t>(watch_flags) << (16 + 4 * wp_index);51}52 53// Returns value for size bits of wp_index in DR754static inline uint64_t GetWatchSizeBits(uint32_t size, uint32_t wp_index) {55  // DR7:56  // bit: 3322222222221111...57  //      1098765432109876...58  // val: SSTTSSTTSSTTSSTT...59  // wp.: 3333222211110000...60  //61  // where S - size is:62  // 00 for 1 byte63  // 01 for 2 bytes64  // 10 for 8 bytes65  // 11 for 4 bytes66  return static_cast<uint64_t>(size == 8 ? 0x2 : size - 1)67         << (18 + 4 * wp_index);68}69 70// Returns bitmask for all bits controlling wp_index in DR771static inline uint64_t GetWatchControlBitmask(uint32_t wp_index) {72  // DR7:73  // bit: 3322222222221111111111000000000074  //      1098765432109876543210987654321075  // val: SSTTSSTTSSTTSSTTxxxxxxGLGLGLGLGL76  // wp.: 3333222211110000xxxxxxEE3322110077  return GetBothEnableBitMask(wp_index) | (0xF << (16 + 4 * wp_index));78}79 80// Bit mask for control bits regarding all watchpoints.81static constexpr uint64_t watchpoint_all_control_bit_mask = 0xFFFF00FF;82 83const RegisterInfo *NativeRegisterContextDBReg_x86::GetDR(int num) const {84  assert(num >= 0 && num <= 7);85  switch (GetRegisterInfoInterface().GetTargetArchitecture().GetMachine()) {86  case llvm::Triple::x86:87    return GetRegisterInfoAtIndex(lldb_dr0_i386 + num);88  case llvm::Triple::x86_64:89    return GetRegisterInfoAtIndex(lldb_dr0_x86_64 + num);90  default:91    llvm_unreachable("Unhandled target architecture.");92  }93}94 95Status NativeRegisterContextDBReg_x86::IsWatchpointHit(uint32_t wp_index,96                                                       bool &is_hit) {97  if (wp_index >= NumSupportedHardwareWatchpoints())98    return Status::FromErrorString("Watchpoint index out of range");99 100  RegisterValue dr6;101  Status error = ReadRegister(GetDR(6), dr6);102  if (error.Fail())103    is_hit = false;104  else105    is_hit = dr6.GetAsUInt64() & GetStatusBit(wp_index);106 107  return error;108}109 110Status111NativeRegisterContextDBReg_x86::GetWatchpointHitIndex(uint32_t &wp_index,112                                                      lldb::addr_t trap_addr) {113  uint32_t num_hw_wps = NumSupportedHardwareWatchpoints();114  for (wp_index = 0; wp_index < num_hw_wps; ++wp_index) {115    bool is_hit;116    Status error = IsWatchpointHit(wp_index, is_hit);117    if (error.Fail()) {118      wp_index = LLDB_INVALID_INDEX32;119      return error;120    } else if (is_hit) {121      return error;122    }123  }124  wp_index = LLDB_INVALID_INDEX32;125  return Status();126}127 128Status NativeRegisterContextDBReg_x86::IsWatchpointVacant(uint32_t wp_index,129                                                          bool &is_vacant) {130  if (wp_index >= NumSupportedHardwareWatchpoints())131    return Status::FromErrorString("Watchpoint index out of range");132 133  RegisterValue dr7;134  Status error = ReadRegister(GetDR(7), dr7);135  if (error.Fail())136    is_vacant = false;137  else138    is_vacant = !(dr7.GetAsUInt64() & GetEnableBit(wp_index));139 140  return error;141}142 143Status NativeRegisterContextDBReg_x86::SetHardwareWatchpointWithIndex(144    lldb::addr_t addr, size_t size, uint32_t watch_flags, uint32_t wp_index) {145 146  if (wp_index >= NumSupportedHardwareWatchpoints())147    return Status::FromErrorString("Watchpoint index out of range");148 149  // Read only watchpoints aren't supported on x86_64. Fall back to read/write150  // waitchpoints instead.151  // TODO: Add logic to detect when a write happens and ignore that watchpoint152  // hit.153  if (watch_flags == 2)154    watch_flags = 3;155 156  if (watch_flags != 1 && watch_flags != 3)157    return Status::FromErrorString("Invalid read/write bits for watchpoint");158  if (size != 1 && size != 2 && size != 4 && size != 8)159    return Status::FromErrorString("Invalid size for watchpoint");160 161  bool is_vacant;162  Status error = IsWatchpointVacant(wp_index, is_vacant);163  if (error.Fail())164    return error;165  if (!is_vacant)166    return Status::FromErrorString("Watchpoint index not vacant");167 168  RegisterValue dr7, drN;169  error = ReadRegister(GetDR(7), dr7);170  if (error.Fail())171    return error;172  error = ReadRegister(GetDR(wp_index), drN);173  if (error.Fail())174    return error;175 176  uint64_t control_bits = dr7.GetAsUInt64() & ~GetWatchControlBitmask(wp_index);177  control_bits |= GetEnableBit(wp_index) |178                  GetWatchTypeBits(watch_flags, wp_index) |179                  GetWatchSizeBits(size, wp_index);180 181  // Clear dr6 if address or bits changed (i.e. we're not reenabling the same182  // watchpoint).  This can not be done when clearing watchpoints since183  // the gdb-remote protocol repeatedly clears and readds watchpoints on all184  // program threads, effectively clearing pending events on NetBSD.185  // NB: enable bits in dr7 are always 0 here since we're (re)adding it186  if (drN.GetAsUInt64() != addr ||187      (dr7.GetAsUInt64() & GetWatchControlBitmask(wp_index)) !=188          (GetWatchTypeBits(watch_flags, wp_index) |189           GetWatchSizeBits(size, wp_index))) {190    ClearWatchpointHit(wp_index);191 192    // We skip update to drN if neither address nor mode changed.193    error = WriteRegister(GetDR(wp_index), RegisterValue(addr));194    if (error.Fail())195      return error;196  }197 198  error = WriteRegister(GetDR(7), RegisterValue(control_bits));199  if (error.Fail())200    return error;201 202  return error;203}204 205bool NativeRegisterContextDBReg_x86::ClearHardwareWatchpoint(206    uint32_t wp_index) {207  if (wp_index >= NumSupportedHardwareWatchpoints())208    return false;209 210  RegisterValue dr7;211  Status error = ReadRegister(GetDR(7), dr7);212  if (error.Fail())213    return false;214 215  return WriteRegister(GetDR(7), RegisterValue(dr7.GetAsUInt64() &216                                               ~GetBothEnableBitMask(wp_index)))217      .Success();218}219 220Status NativeRegisterContextDBReg_x86::ClearWatchpointHit(uint32_t wp_index) {221  if (wp_index >= NumSupportedHardwareWatchpoints())222    return Status::FromErrorString("Watchpoint index out of range");223 224  RegisterValue dr6;225  Status error = ReadRegister(GetDR(6), dr6);226  if (error.Fail())227    return error;228 229  return WriteRegister(230      GetDR(6), RegisterValue(dr6.GetAsUInt64() & ~GetStatusBit(wp_index)));231}232 233Status NativeRegisterContextDBReg_x86::ClearAllHardwareWatchpoints() {234  RegisterValue dr7;235  Status error = ReadRegister(GetDR(7), dr7);236  if (error.Fail())237    return error;238  return WriteRegister(239      GetDR(7),240      RegisterValue(dr7.GetAsUInt64() & ~watchpoint_all_control_bit_mask));241}242 243uint32_t NativeRegisterContextDBReg_x86::SetHardwareWatchpoint(244    lldb::addr_t addr, size_t size, uint32_t watch_flags) {245  Log *log = GetLog(LLDBLog::Watchpoints);246  const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints();247  for (uint32_t wp_index = 0; wp_index < num_hw_watchpoints; ++wp_index) {248    bool is_vacant;249    Status error = IsWatchpointVacant(wp_index, is_vacant);250    if (is_vacant) {251      error = SetHardwareWatchpointWithIndex(addr, size, watch_flags, wp_index);252      if (error.Success())253        return wp_index;254    }255    if (error.Fail() && log) {256      LLDB_LOGF(log, "NativeRegisterContextDBReg_x86::%s Error: %s",257                __FUNCTION__, error.AsCString());258    }259  }260  return LLDB_INVALID_INDEX32;261}262 263lldb::addr_t264NativeRegisterContextDBReg_x86::GetWatchpointAddress(uint32_t wp_index) {265  if (wp_index >= NumSupportedHardwareWatchpoints())266    return LLDB_INVALID_ADDRESS;267  RegisterValue drN;268  if (ReadRegister(GetDR(wp_index), drN).Fail())269    return LLDB_INVALID_ADDRESS;270  return drN.GetAsUInt64();271}272 273uint32_t NativeRegisterContextDBReg_x86::NumSupportedHardwareWatchpoints() {274  // Available debug address registers: dr0, dr1, dr2, dr3275  return 4;276}277