1//===-- MemoryTagMap.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-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "lldb/Target/MemoryTagMap.h"
10#include <optional>
11
12using namespace lldb_private;
13
14MemoryTagMap::MemoryTagMap(const MemoryTagManager *manager)
15    : m_manager(manager) {
16  assert(m_manager && "valid tag manager required to construct a MemoryTagMap");
17}
18
19void MemoryTagMap::InsertTags(lldb::addr_t addr,
20                              const std::vector<lldb::addr_t> tags) {
21  // We're assuming that addr has no non address bits and is granule aligned.
22  size_t granule_size = m_manager->GetGranuleSize();
23  for (auto tag : tags) {
24    m_addr_to_tag[addr] = tag;
25    addr += granule_size;
26  }
27}
28
29bool MemoryTagMap::Empty() const { return m_addr_to_tag.empty(); }
30
31std::vector<std::optional<lldb::addr_t>>
32MemoryTagMap::GetTags(lldb::addr_t addr, size_t len) const {
33  // Addr and len might be unaligned
34  addr = m_manager->RemoveTagBits(addr);
35  MemoryTagManager::TagRange range(addr, len);
36  range = m_manager->ExpandToGranule(range);
37
38  std::vector<std::optional<lldb::addr_t>> tags;
39  lldb::addr_t end_addr = range.GetRangeEnd();
40  addr = range.GetRangeBase();
41  bool got_valid_tags = false;
42  size_t granule_size = m_manager->GetGranuleSize();
43
44  for (; addr < end_addr; addr += granule_size) {
45    std::optional<lldb::addr_t> tag = GetTag(addr);
46    tags.push_back(tag);
47    if (tag)
48      got_valid_tags = true;
49  }
50
51  // To save the caller checking if every item is std::nullopt,
52  // we return an empty vector if we got no tags at all.
53  if (got_valid_tags)
54    return tags;
55  return {};
56}
57
58std::optional<lldb::addr_t> MemoryTagMap::GetTag(lldb::addr_t addr) const {
59  // Here we assume that addr is granule aligned, just like when the tags
60  // were inserted.
61  auto found = m_addr_to_tag.find(addr);
62  if (found == m_addr_to_tag.end())
63    return std::nullopt;
64  return found->second;
65}
66