Path: blob/main/contrib/llvm-project/lldb/source/Breakpoint/WatchpointAlgorithms.cpp
39587 views
//===-- WatchpointAlgorithms.cpp ------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "lldb/Breakpoint/WatchpointAlgorithms.h"9#include "lldb/Breakpoint/WatchpointResource.h"10#include "lldb/Target/Process.h"11#include "lldb/Utility/ArchSpec.h"12#include "lldb/Utility/LLDBLog.h"13#include "lldb/Utility/Log.h"1415#include <algorithm>16#include <utility>17#include <vector>1819using namespace lldb;20using namespace lldb_private;2122std::vector<WatchpointResourceSP>23WatchpointAlgorithms::AtomizeWatchpointRequest(24addr_t addr, size_t size, bool read, bool write,25WatchpointHardwareFeature supported_features, ArchSpec &arch) {2627std::vector<Region> entries;2829if (supported_features & eWatchpointHardwareArmMASK) {30entries =31PowerOf2Watchpoints(addr, size,32/*min_byte_size*/ 1,33/*max_byte_size*/ INT32_MAX,34/*address_byte_size*/ arch.GetAddressByteSize());35} else {36// As a fallback, assume we can watch any power-of-237// number of bytes up through the size of an address in the target.38entries =39PowerOf2Watchpoints(addr, size,40/*min_byte_size*/ 1,41/*max_byte_size*/ arch.GetAddressByteSize(),42/*address_byte_size*/ arch.GetAddressByteSize());43}4445Log *log = GetLog(LLDBLog::Watchpoints);46LLDB_LOGV(log, "AtomizeWatchpointRequest user request addr {0:x} size {1}",47addr, size);48std::vector<WatchpointResourceSP> resources;49for (Region &ent : entries) {50LLDB_LOGV(log, "AtomizeWatchpointRequest creating resource {0:x} size {1}",51ent.addr, ent.size);52WatchpointResourceSP wp_res_sp =53std::make_shared<WatchpointResource>(ent.addr, ent.size, read, write);54resources.push_back(wp_res_sp);55}5657return resources;58}5960// This should be `std::bit_ceil(aligned_size)` but61// that requires C++20.62// Calculates the smallest integral power of two that is not smaller than x.63static uint64_t bit_ceil(uint64_t input) {64if (input <= 1 || llvm::popcount(input) == 1)65return input;6667return 1ULL << (64 - llvm::countl_zero(input));68}6970/// Convert a user's watchpoint request (\a user_addr and \a user_size)71/// into hardware watchpoints, for a target that can watch a power-of-272/// region of memory (1, 2, 4, 8, etc), aligned to that same power-of-273/// memory address.74///75/// If a user asks to watch 4 bytes at address 0x1002 (0x1002-0x100576/// inclusive) we can implement this with two 2-byte watchpoints77/// (0x1002 and 0x1004) or with an 8-byte watchpoint at 0x1000.78/// A 4-byte watchpoint at 0x1002 would not be properly 4 byte aligned.79///80/// If a user asks to watch 16 bytes at 0x1000, and this target supports81/// 8-byte watchpoints, we can implement this with two 8-byte watchpoints82/// at 0x1000 and 0x1008.83std::vector<WatchpointAlgorithms::Region>84WatchpointAlgorithms::PowerOf2Watchpoints(addr_t user_addr, size_t user_size,85size_t min_byte_size,86size_t max_byte_size,87uint32_t address_byte_size) {8889Log *log = GetLog(LLDBLog::Watchpoints);90LLDB_LOGV(log,91"AtomizeWatchpointRequest user request addr {0:x} size {1} "92"min_byte_size {2}, max_byte_size {3}, address_byte_size {4}",93user_addr, user_size, min_byte_size, max_byte_size,94address_byte_size);9596// Can't watch zero bytes.97if (user_size == 0)98return {};99100size_t aligned_size = std::max(user_size, min_byte_size);101/// Round up \a user_size to the next power-of-2 size102/// user_size == 8 -> aligned_size == 8103/// user_size == 9 -> aligned_size == 16104aligned_size = bit_ceil(aligned_size);105106addr_t aligned_start = user_addr & ~(aligned_size - 1);107108// Does this power-of-2 memory range, aligned to power-of-2 that the109// hardware can watch, completely cover the requested region.110if (aligned_size <= max_byte_size &&111aligned_start + aligned_size >= user_addr + user_size)112return {{aligned_start, aligned_size}};113114// If the maximum region we can watch is larger than the aligned115// size, try increasing the region size by one power of 2 and see116// if aligning to that amount can cover the requested region.117//118// Increasing the aligned_size repeatedly instead of splitting the119// watchpoint can result in us watching large regions of memory120// unintentionally when we could use small two watchpoints. e.g.121// user_addr 0x3ff8 user_size 32122// can be watched with four 8-byte watchpoints or if it's done with one123// MASK watchpoint, it would need to be a 32KB watchpoint (a 16KB124// watchpoint at 0x0 only covers 0x0000-0x4000). A user request125// at the end of a power-of-2 region can lead to these undesirably126// large watchpoints and many false positive hits to ignore.127if (max_byte_size >= (aligned_size << 1)) {128aligned_size <<= 1;129aligned_start = user_addr & ~(aligned_size - 1);130if (aligned_size <= max_byte_size &&131aligned_start + aligned_size >= user_addr + user_size)132return {{aligned_start, aligned_size}};133134// Go back to our original aligned size, to try the multiple135// watchpoint approach.136aligned_size >>= 1;137}138139// We need to split the user's watchpoint into two or more watchpoints140// that can be monitored by hardware, because of alignment and/or size141// reasons.142aligned_size = std::min(aligned_size, max_byte_size);143aligned_start = user_addr & ~(aligned_size - 1);144145std::vector<Region> result;146addr_t current_address = aligned_start;147const addr_t user_end_address = user_addr + user_size;148while (current_address + aligned_size < user_end_address) {149result.push_back({current_address, aligned_size});150current_address += aligned_size;151}152153if (current_address < user_end_address)154result.push_back({current_address, aligned_size});155156return result;157}158159160