lin
2025-08-01 633231e833e21d5b8b1c00cb15aedb62b3b78e8f
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
// Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
 
#ifndef CHROMIUMOS_WIDE_PROFILING_ADDRESS_MAPPER_H_
#define CHROMIUMOS_WIDE_PROFILING_ADDRESS_MAPPER_H_
 
#include <stddef.h>
#include <stdint.h>
 
#include <list>
#include <map>
 
namespace quipper {
 
class AddressMapper {
 private:
  struct MappedRange;
 
 public:
  AddressMapper() : page_alignment_(0) {}
 
  // Copy constructor: copies mappings from |source| to this AddressMapper. This
  // is useful for copying mappings from parent to child process upon fork(). It
  // is also useful to copy kernel mappings to any process that is created.
  AddressMapper(const AddressMapper& other);
 
  typedef std::list<MappedRange> MappingList;
 
  // Maps a new address range [real_addr, real_addr + length) to quipper space.
  // |id| is an identifier value to be stored along with the mapping.
  // AddressMapper does not care whether it is unique compared to all other IDs
  // passed in. That is up to the caller to keep track of.
  // |offset_base| represents the offset within the original region at which the
  // mapping begins. The original region can be much larger than the mapped
  // region.
  // e.g. Given a mapped region with base=0x4000 and size=0x2000 mapped with
  // offset_base=0x10000, then the address 0x5000 maps to an offset of 0x11000
  // (0x5000 - 0x4000 + 0x10000).
  // |remove_existing_mappings| indicates whether to remove old mappings that
  // collide with the new range in real address space, indicating it has been
  // unmapped.
  // Returns true if mapping was successful.
  bool MapWithID(const uint64_t real_addr, const uint64_t size,
                 const uint64_t id, const uint64_t offset_base,
                 bool remove_existing_mappings);
 
  // Looks up |real_addr| and returns the mapped address and MappingList
  // iterator.
  bool GetMappedAddressAndListIterator(const uint64_t real_addr,
                                       uint64_t* mapped_addr,
                                       MappingList::const_iterator* iter) const;
 
  // Uses MappingList iterator to fetch and return the mapping's ID and offset
  // from the start of the mapped space.
  // |real_addr_iter| must be valid and not at the end of the list.
  void GetMappedIDAndOffset(const uint64_t real_addr,
                            MappingList::const_iterator real_addr_iter,
                            uint64_t* id, uint64_t* offset) const;
 
  // Returns true if there are no mappings.
  bool IsEmpty() const { return mappings_.empty(); }
 
  // Returns the number of address ranges that are currently mapped.
  size_t GetNumMappedRanges() const { return mappings_.size(); }
 
  // Returns the maximum length of quipper space containing mapped areas.
  // There may be gaps in between blocks.
  // If the result is 2^64 (all of quipper space), this returns 0.  Call
  // IsEmpty() to distinguish this from actual emptiness.
  uint64_t GetMaxMappedLength() const;
 
  // Sets the page alignment size. Set to 0 to disable page alignment.
  // The alignment value must be a power of two. Any other value passed in will
  // have no effect. Changing this value in between mappings results in
  // undefined behavior.
  void set_page_alignment(uint64_t alignment) {
    // This also includes the case of 0.
    if ((alignment & (alignment - 1)) == 0) page_alignment_ = alignment;
  }
 
  // Dumps the state of the address mapper to logs. Useful for debugging.
  void DumpToLog() const;
 
 private:
  typedef std::map<uint64_t, MappingList::iterator> MappingMap;
 
  struct MappedRange {
    uint64_t real_addr;
    uint64_t mapped_addr;
    uint64_t size;
 
    uint64_t id;
    uint64_t offset_base;
 
    // Length of unmapped space after this range.
    uint64_t unmapped_space_after;
 
    // Determines if this range intersects another range in real space.
    inline bool Intersects(const MappedRange& range) const {
      return (real_addr <= range.real_addr + range.size - 1) &&
             (real_addr + size - 1 >= range.real_addr);
    }
 
    // Determines if this range fully covers another range in real space.
    inline bool Covers(const MappedRange& range) const {
      return (real_addr <= range.real_addr) &&
             (real_addr + size - 1 >= range.real_addr + range.size - 1);
    }
 
    // Determines if this range fully contains another range in real space.
    // This is different from Covers() in that the boundaries cannot overlap.
    inline bool Contains(const MappedRange& range) const {
      return (real_addr < range.real_addr) &&
             (real_addr + size - 1 > range.real_addr + range.size - 1);
    }
 
    // Determines if this range contains the given address |addr|.
    inline bool ContainsAddress(uint64_t addr) const {
      return (addr >= real_addr && addr <= real_addr + size - 1);
    }
  };
 
  // Returns an iterator to a MappedRange in |mappings_| that contains
  // |real_addr|. Returns |mappings_.end()| if no range contains |real_addr|.
  MappingList::const_iterator GetRangeContainingAddress(
      uint64_t real_addr) const;
 
  // Removes an existing address mapping, given by an iterator pointing to an
  // element of |mappings_|.
  void Unmap(MappingList::iterator mapping_iter);
 
  // Given an address, and a nonzero, power-of-two |page_alignment_| value,
  // returns the offset of the address from the start of the page it is on.
  // Equivalent to |addr % page_alignment_|. Should not be called if
  // |page_alignment_| is zero.
  uint64_t GetAlignedOffset(uint64_t addr) const {
    return addr & (page_alignment_ - 1);
  }
 
  // Container for all the existing mappings.
  MappingList mappings_;
 
  // Maps real addresses to iterators pointing to entries within |mappings_|.
  // Must maintain a 1:1 entry correspondence with |mappings_|.
  MappingMap real_addr_to_mapped_range_;
 
  // If set to nonzero, use this as a mapping page boundary. If a mapping does
  // not begin at a multiple of this value, the remapped address should be given
  // an offset that is the remainder.
  //
  // e.g. if alignment=0x1000 and a mapping starts at 0x520100, then the
  // remapping should treat the mapping as starting at 0x520000, but addresses
  // are only valid starting at 0x520100.
  uint64_t page_alignment_;
};
 
}  // namespace quipper
 
#endif  // CHROMIUMOS_WIDE_PROFILING_ADDRESS_MAPPER_H_