| // Copyright 2019 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "src/developer/debug/debug_agent/align.h" |
| |
| #include <lib/syslog/cpp/macros.h> |
| |
| namespace debug_agent { |
| |
| namespace { |
| |
| // Returns 0 on an invalid alignment. |
| size_t GetAlignment(size_t size) { |
| if (size < 1) |
| return 0; |
| |
| if (size == 1) { |
| return 1; |
| } else if (size == 2) { |
| return 2; |
| } else if (size <= 4) { |
| return 4; |
| } else if (size <= 8) { |
| return 8; |
| } else { |
| return 0; |
| } |
| } |
| |
| // clang-format off |
| // Gets the next alignment a watchpoint might use |
| size_t GetNextSize(uint64_t size) { |
| switch (size) { |
| case 1: return 2; |
| case 2: return 4; |
| case 4: return 8; |
| case 8: return 0; |
| } |
| |
| FX_NOTREACHED(); |
| return 0; |
| } |
| |
| uint64_t GetMask(uint64_t size) { |
| switch (size) { |
| case 1: return 0; |
| case 2: return 0b1; |
| case 4: return 0b11; |
| case 8: return 0b111; |
| } |
| |
| FX_NOTREACHED(); |
| return 0; |
| } |
| // clang-format on |
| |
| } // namespace |
| |
| std::optional<debug::AddressRange> AlignRange(const debug::AddressRange& range) { |
| uint64_t size = range.end() - range.begin(); |
| uint64_t alignment = GetAlignment(size); |
| if (alignment == 0) |
| return std::nullopt; |
| |
| // Check if the range is already aligned. |
| uint64_t mask = GetMask(alignment); |
| uint64_t aligned_address = range.begin() & ~mask; |
| if (aligned_address == range.begin()) |
| return debug::AddressRange{range.begin(), range.begin() + alignment}; |
| |
| // Check if the aligned address + the current size gets the job done. |
| if (aligned_address <= range.begin() && (aligned_address + alignment) >= range.end()) |
| return debug::AddressRange{aligned_address, aligned_address + alignment}; |
| |
| // See if we can over align this with a range. |
| |
| uint64_t next_size = GetNextSize(alignment); |
| while (next_size != 0) { |
| // Align the address to the new size. |
| aligned_address = aligned_address & ~GetMask(next_size); |
| |
| // We see if we can cover the range with this size. |
| if (aligned_address > range.begin() || (aligned_address + next_size) < range.end()) { |
| next_size = GetNextSize(next_size); |
| continue; |
| } |
| |
| // The range fits. |
| break; |
| } |
| |
| // |next_size| == 0 means that there is no range the extends this range. |
| if (next_size == 0) |
| return std::nullopt; |
| return debug::AddressRange(aligned_address, aligned_address + next_size); |
| } |
| |
| } // namespace debug_agent |