lldb had three preprocessor defines for logging, LLDB_LOG - formatv style argument LLDB_LOGF - printf style argument LLDB_LOGV - formatv style argument, only when verbose enabled If you weren't looking at Log.h and the definition of these three, and wanted to log something with formatv, it was easy to use LLDB_LOGV by accident. We just had a situation where an important log statement wasn't logging and it turned out to be this. This is fragile if you aren't looking at the header directly, so I'd like to make this more explicit. My proposal: LLDB_LOG - formatv style argument LLDB_LOG_VERBOSE - formatv style argument, only when verbose enabled LLDB_LOGF - printf style argument LLDB_LOGF_VERBOSE - printf style argument, only when verbose enabled The new fouth one is to remove several places where we do `if (log && log->GetVerbose()) LLDB_LOGF (...)` in the sources today, and make both styles consistent. This PR implements that change, mechanically changing all LLDB_LOGV's to LLDB_LOG_VERBOSE. It also updates many of the `if (log && log->GetVerbose()) LLDB_LOGF`'s. Some uses of this conditional expression do extra calculations in addition to logging, and so those were left as-is so we're not doing throwaway work when running without verbose logging. There were many instances throughout lldb where callers are still doing `if (log) LLDB_LOG*(...)`, a remnant of when all calls were to the `Log` object's `Printf()` method, and you had to check if your local Log* pointer was non-nullptr before calling the method. I removed those, again keeping ones where work for logging is done in the block of code. The code changes are all mechanical and uninteresting, but the question of whether this naming change is widely agreed on is maybe worth discussing.
151 lines
5.9 KiB
C++
151 lines
5.9 KiB
C++
//===-- WatchpointAlgorithms.cpp ------------------------------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "lldb/Breakpoint/WatchpointAlgorithms.h"
|
|
#include "lldb/Breakpoint/WatchpointResource.h"
|
|
#include "lldb/Target/Process.h"
|
|
#include "lldb/Utility/ArchSpec.h"
|
|
#include "lldb/Utility/LLDBLog.h"
|
|
#include "lldb/Utility/Log.h"
|
|
|
|
#include <algorithm>
|
|
#include <utility>
|
|
#include <vector>
|
|
|
|
using namespace lldb;
|
|
using namespace lldb_private;
|
|
|
|
std::vector<WatchpointResourceSP>
|
|
WatchpointAlgorithms::AtomizeWatchpointRequest(
|
|
addr_t addr, size_t size, bool read, bool write,
|
|
WatchpointHardwareFeature supported_features, ArchSpec &arch) {
|
|
|
|
std::vector<Region> entries;
|
|
|
|
if (supported_features & eWatchpointHardwareArmMASK) {
|
|
entries =
|
|
PowerOf2Watchpoints(addr, size,
|
|
/*min_byte_size*/ 1,
|
|
/*max_byte_size*/ INT32_MAX,
|
|
/*address_byte_size*/ arch.GetAddressByteSize());
|
|
} else {
|
|
// As a fallback, assume we can watch any power-of-2
|
|
// number of bytes up through the size of an address in the target.
|
|
entries =
|
|
PowerOf2Watchpoints(addr, size,
|
|
/*min_byte_size*/ 1,
|
|
/*max_byte_size*/ arch.GetAddressByteSize(),
|
|
/*address_byte_size*/ arch.GetAddressByteSize());
|
|
}
|
|
|
|
Log *log = GetLog(LLDBLog::Watchpoints);
|
|
LLDB_LOG_VERBOSE(log,
|
|
"AtomizeWatchpointRequest user request addr {0:x} size {1}",
|
|
addr, size);
|
|
std::vector<WatchpointResourceSP> resources;
|
|
for (Region &ent : entries) {
|
|
LLDB_LOG_VERBOSE(
|
|
log, "AtomizeWatchpointRequest creating resource {0:x} size {1}",
|
|
ent.addr, ent.size);
|
|
WatchpointResourceSP wp_res_sp =
|
|
std::make_shared<WatchpointResource>(ent.addr, ent.size, read, write);
|
|
resources.push_back(wp_res_sp);
|
|
}
|
|
|
|
return resources;
|
|
}
|
|
|
|
/// Convert a user's watchpoint request (\a user_addr and \a user_size)
|
|
/// into hardware watchpoints, for a target that can watch a power-of-2
|
|
/// region of memory (1, 2, 4, 8, etc), aligned to that same power-of-2
|
|
/// memory address.
|
|
///
|
|
/// If a user asks to watch 4 bytes at address 0x1002 (0x1002-0x1005
|
|
/// inclusive) we can implement this with two 2-byte watchpoints
|
|
/// (0x1002 and 0x1004) or with an 8-byte watchpoint at 0x1000.
|
|
/// A 4-byte watchpoint at 0x1002 would not be properly 4 byte aligned.
|
|
///
|
|
/// If a user asks to watch 16 bytes at 0x1000, and this target supports
|
|
/// 8-byte watchpoints, we can implement this with two 8-byte watchpoints
|
|
/// at 0x1000 and 0x1008.
|
|
std::vector<WatchpointAlgorithms::Region>
|
|
WatchpointAlgorithms::PowerOf2Watchpoints(addr_t user_addr, size_t user_size,
|
|
size_t min_byte_size,
|
|
size_t max_byte_size,
|
|
uint32_t address_byte_size) {
|
|
|
|
Log *log = GetLog(LLDBLog::Watchpoints);
|
|
LLDB_LOG_VERBOSE(
|
|
log,
|
|
"AtomizeWatchpointRequest user request addr {0:x} size {1} "
|
|
"min_byte_size {2}, max_byte_size {3}, address_byte_size {4}",
|
|
user_addr, user_size, min_byte_size, max_byte_size, address_byte_size);
|
|
|
|
// Can't watch zero bytes.
|
|
if (user_size == 0)
|
|
return {};
|
|
|
|
size_t aligned_size = std::max(user_size, min_byte_size);
|
|
/// Round up \a user_size to the next power-of-2 size
|
|
/// user_size == 8 -> aligned_size == 8
|
|
/// user_size == 9 -> aligned_size == 16
|
|
aligned_size = llvm::bit_ceil(aligned_size);
|
|
|
|
addr_t aligned_start = user_addr & ~(aligned_size - 1);
|
|
|
|
// Does this power-of-2 memory range, aligned to power-of-2 that the
|
|
// hardware can watch, completely cover the requested region.
|
|
if (aligned_size <= max_byte_size &&
|
|
aligned_start + aligned_size >= user_addr + user_size)
|
|
return {{aligned_start, aligned_size}};
|
|
|
|
// If the maximum region we can watch is larger than the aligned
|
|
// size, try increasing the region size by one power of 2 and see
|
|
// if aligning to that amount can cover the requested region.
|
|
//
|
|
// Increasing the aligned_size repeatedly instead of splitting the
|
|
// watchpoint can result in us watching large regions of memory
|
|
// unintentionally when we could use small two watchpoints. e.g.
|
|
// user_addr 0x3ff8 user_size 32
|
|
// can be watched with four 8-byte watchpoints or if it's done with one
|
|
// MASK watchpoint, it would need to be a 32KB watchpoint (a 16KB
|
|
// watchpoint at 0x0 only covers 0x0000-0x4000). A user request
|
|
// at the end of a power-of-2 region can lead to these undesirably
|
|
// large watchpoints and many false positive hits to ignore.
|
|
if (max_byte_size >= (aligned_size << 1)) {
|
|
aligned_size <<= 1;
|
|
aligned_start = user_addr & ~(aligned_size - 1);
|
|
if (aligned_size <= max_byte_size &&
|
|
aligned_start + aligned_size >= user_addr + user_size)
|
|
return {{aligned_start, aligned_size}};
|
|
|
|
// Go back to our original aligned size, to try the multiple
|
|
// watchpoint approach.
|
|
aligned_size >>= 1;
|
|
}
|
|
|
|
// We need to split the user's watchpoint into two or more watchpoints
|
|
// that can be monitored by hardware, because of alignment and/or size
|
|
// reasons.
|
|
aligned_size = std::min(aligned_size, max_byte_size);
|
|
aligned_start = user_addr & ~(aligned_size - 1);
|
|
|
|
std::vector<Region> result;
|
|
addr_t current_address = aligned_start;
|
|
const addr_t user_end_address = user_addr + user_size;
|
|
while (current_address + aligned_size < user_end_address) {
|
|
result.push_back({current_address, aligned_size});
|
|
current_address += aligned_size;
|
|
}
|
|
|
|
if (current_address < user_end_address)
|
|
result.push_back({current_address, aligned_size});
|
|
|
|
return result;
|
|
}
|