range_map.cc
Go to the documentation of this file.
1 // Copyright 2016 Google Inc. All Rights Reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "range_map.h"
16 
17 #include "bloaty.h"
18 
19 namespace bloaty {
20 
22 
23 template <class T>
25  assert(EntryContains(iter, addr));
26  assert(iter->second.HasTranslation());
27  return addr - iter->first + iter->second.other_start;
28 }
29 
30 template <class T>
32  uint64_t size, uint64_t* trimmed_addr,
33  uint64_t* translated_addr,
34  uint64_t* trimmed_size) const {
35  addr = std::max(addr, iter->first);
36  *trimmed_addr = addr;
37 
38  if (size == kUnknownSize) {
39  *trimmed_size = kUnknownSize;
40  } else {
41  uint64_t end = std::min(addr + size, iter->first + iter->second.size);
42  if (addr >= end) {
43  *trimmed_size = 0;
44  return false;
45  }
46  *trimmed_size = end - addr;
47  }
48 
49  if (!iter->second.HasTranslation()) {
50  return false;
51  }
52 
53  *translated_addr = TranslateWithEntry(iter, addr);
54  return true;
55 }
56 
57 RangeMap::Map::const_iterator RangeMap::FindContaining(uint64_t addr) const {
58  auto it = mappings_.upper_bound(addr); // Entry directly after.
59  if (it == mappings_.begin() || (--it, !EntryContains(it, addr))) {
60  return mappings_.end();
61  } else {
62  return it;
63  }
64 }
65 
67  auto after = mappings_.upper_bound(addr);
68  auto it = after;
69  if (it != mappings_.begin() && (--it, EntryContains(it, addr))) {
70  return it; // Containing
71  } else {
72  return after; // May be end().
73  }
74 }
75 
76 RangeMap::Map::const_iterator RangeMap::FindContainingOrAfter(
77  uint64_t addr) const {
78  auto after = mappings_.upper_bound(addr);
79  auto it = after;
80  if (it != mappings_.begin() && (--it, EntryContains(it, addr))) {
81  return it; // Containing
82  } else {
83  return after; // May be end().
84  }
85 }
86 
87 bool RangeMap::Translate(uint64_t addr, uint64_t* translated) const {
88  auto iter = FindContaining(addr);
89  if (iter == mappings_.end() || !iter->second.HasTranslation()) {
90  return false;
91  } else {
92  *translated = TranslateWithEntry(iter, addr);
93  return true;
94  }
95 }
96 
98  auto iter = FindContaining(addr);
99  if (iter == mappings_.end()) {
100  return false;
101  } else {
102  *label = iter->second.label;
103  return true;
104  }
105 }
106 
108  std::string* label) const {
109  uint64_t end = addr + size;
110  if (end < addr) {
111  return false;
112  }
113  auto iter = FindContaining(addr);
114  if (iter == mappings_.end()) {
115  return false;
116  } else {
117  *label = iter->second.label;
118  while (iter != mappings_.end() && iter->first + iter->second.size < end) {
119  if (iter->second.label != *label) {
120  return false;
121  }
122  ++iter;
123  }
124  return iter != mappings_.end();
125  }
126 }
127 
129  auto iter = mappings_.find(addr);
130  if (iter == mappings_.end()) {
131  return false;
132  } else {
133  *size = iter->second.size;
134  return true;
135  }
136 }
137 
140  for (auto it = mappings_.begin(); it != mappings_.end(); ++it) {
142  }
143  return ret;
144 }
145 
148 }
149 
150 template <class T>
152  uint64_t size) {
153  assert(EntryContains(iter, addr));
154  if (iter->second.size == kUnknownSize && size != kUnknownSize) {
155  assert(addr + size >= addr);
156  assert(addr + size >= iter->first);
157  assert(addr >= iter->first);
158  if (addr == iter->first) {
159  T next = std::next(iter);
160  uint64_t end = addr + size;
161  if (!IterIsEnd(next)) {
162  end = std::min(end, next->first);
163  }
164  uint64_t new_size = end - iter->first;
165  if (verbose_level > 2) {
166  printf(" updating mapping (%s) with new size %" PRIx64 "\n",
168  new_size);
169  }
170  // This new defined range encompassess all of the unknown-length range, so
171  // just define the range to have our end.
172  iter->second.size = new_size;
174  }
175  } else if (verbose_level > 2) {
176  printf(" skipping existing mapping (%s)\n",
178  }
179 }
180 
182  const std::string& label) {
183  if (verbose_level > 2) {
184  printf("%p AddDualRange([%" PRIx64 ", %" PRIx64 "], %" PRIx64 ", %s)\n",
185  this, addr, size, otheraddr, label.c_str());
186  }
187 
188  if (size == 0) return;
189 
190  auto it = FindContainingOrAfter(addr);
191 
192  if (size == kUnknownSize) {
193  assert(otheraddr == kNoTranslation);
194  if (it != mappings_.end() && EntryContainsStrict(it, addr)) {
196  } else {
197  auto iter = mappings_.emplace_hint(
198  it, std::make_pair(addr, Entry(label, kUnknownSize, kNoTranslation)));
199  if (verbose_level > 2) {
200  printf(" added entry: %s\n", EntryDebugString(iter).c_str());
201  }
202  }
203  return;
204  }
205 
206  const uint64_t base = addr;
207  uint64_t end = addr + size;
208  assert(end >= addr);
209 
210  while (1) {
211  // Advance past existing entries that intersect this range until we find a
212  // gap.
213  while (addr < end && !IterIsEnd(it) && EntryContains(it, addr)) {
214  assert(end >= addr);
217  ++it;
218  }
219 
220  if (addr >= end) {
221  return;
222  }
223 
224  // We found a gap and need to create an entry. Need to make sure the new
225  // entry doesn't extend into a range that was previously defined.
226  uint64_t this_end = end;
227  if (it != mappings_.end() && end > it->first) {
228  assert(it->first >= addr);
229  this_end = std::min(end, it->first);
230  }
231 
232  uint64_t other = (otheraddr == kNoTranslation) ? kNoTranslation
233  : addr - base + otheraddr;
234  assert(this_end >= addr);
235  auto iter = mappings_.emplace_hint(
236  it, std::make_pair(addr, Entry(label, this_end - addr, other)));
237  if (verbose_level > 2) {
238  printf(" added entry: %s\n", EntryDebugString(iter).c_str());
239  }
241  addr = this_end;
242  }
243 }
244 
245 // In most cases we don't expect the range we're translating to span mappings
246 // in the translator. For example, we would never expect a symbol to span
247 // sections.
248 //
249 // However there are some examples. An archive member (in the file domain) can
250 // span several section mappings. If we really wanted to get particular here,
251 // we could pass a parameter indicating whether such spanning is expected, and
252 // warn if not.
254  const std::string& val,
255  const RangeMap& translator,
256  bool verbose,
257  RangeMap* other) {
258  auto it = translator.FindContaining(addr);
259  uint64_t end;
260  if (size == kUnknownSize) {
261  end = addr + 1;
262  } else {
263  end = addr + size;
264  assert(end >= addr);
265  }
266  uint64_t total_size = 0;
267 
268  // TODO: optionally warn about when we span ranges of the translator. In some
269  // cases this would be a bug (ie. symbols VM->file). In other cases it's
270  // totally normal (ie. archive members file->VM).
271  while (!translator.IterIsEnd(it) && it->first < end) {
272  uint64_t translated_addr;
273  uint64_t trimmed_addr;
274  uint64_t trimmed_size;
275  if (translator.TranslateAndTrimRangeWithEntry(
276  it, addr, size, &trimmed_addr, &translated_addr, &trimmed_size)) {
277  if (verbose_level > 2 || verbose) {
278  printf(" -> translates to: [%" PRIx64 " %" PRIx64 "]\n", translated_addr,
279  trimmed_size);
280  }
281  other->AddRange(translated_addr, trimmed_size, val);
282  }
283  AddRange(trimmed_addr, trimmed_size, val);
284  total_size += trimmed_size;
285  ++it;
286  }
287 
288  return total_size == size;
289 }
290 
292  auto prev = mappings_.begin();
293  auto it = prev;
294  while (it != mappings_.end()) {
295  if (prev->first + prev->second.size == it->first &&
296  (prev->second.label == it->second.label ||
297  (!prev->second.HasFallbackLabel() && it->second.IsShortFallback()))) {
298  prev->second.size += it->second.size;
299  mappings_.erase(it++);
300  } else {
301  prev = it;
302  ++it;
303  }
304  }
305 }
306 
308  auto it = FindContaining(addr);
309  uint64_t end = addr + size;
310  assert(end >= addr);
311 
312  while (true) {
313  if (addr >= end) {
314  return true;
315  } else if (it == mappings_.end() || !EntryContains(it, addr)) {
316  return false;
317  }
318  addr = RangeEnd(it);
319  it++;
320  }
321 }
322 
324  if (mappings_.empty()) {
325  return 0;
326  } else {
327  auto& entry = *mappings_.rbegin();
328  return entry.first + entry.second.size;
329  }
330 }
331 
332 } // namespace bloaty
bloaty::RangeMap::EntryDebugString
static std::string EntryDebugString(uint64_t addr, uint64_t size, uint64_t other_start, const std::string &label)
Definition: range_map.h:110
bloaty::RangeMap::RangeEndUnknownLimit
uint64_t RangeEndUnknownLimit(Map::const_iterator iter, uint64_t unknown) const
Definition: range_map.h:207
bloaty
Definition: bloaty.cc:69
bloaty::RangeMap::TranslateAndTrimRangeWithEntry
bool TranslateAndTrimRangeWithEntry(T iter, uint64_t addr, uint64_t size, uint64_t *trimmed_addr, uint64_t *translated_addr, uint64_t *trimmed_size) const
Definition: range_map.cc:31
bloaty::RangeMap::IterIsEnd
bool IterIsEnd(Map::const_iterator iter) const
Definition: range_map.h:227
regen-readme.it
it
Definition: regen-readme.py:15
bloaty::RangeMap::GetMaxAddress
uint64_t GetMaxAddress() const
Definition: range_map.cc:323
absl::StrAppend
void StrAppend(std::string *dest, const AlphaNum &a)
Definition: abseil-cpp/absl/strings/str_cat.cc:193
bloaty::RangeMap::kNoTranslation
static const uint64_t kNoTranslation
Definition: range_map.h:158
bloaty::RangeMap::EntryContainsStrict
bool EntryContainsStrict(T iter, uint64_t addr) const
Definition: range_map.h:194
bloaty::RangeMap::FindContaining
Map::const_iterator FindContaining(uint64_t addr) const
Definition: range_map.cc:57
bloaty::verbose_level
int verbose_level
Definition: bloaty.cc:74
bloaty::RangeMap::MaybeSetLabel
void MaybeSetLabel(T iter, const std::string &label, uint64_t addr, uint64_t end)
Definition: range_map.cc:151
bloaty::RangeMap::kUnknownSize
static constexpr uint64_t kUnknownSize
Definition: range_map.h:154
bloaty::RangeMap::TryGetLabelForRange
bool TryGetLabelForRange(uint64_t addr, uint64_t size, std::string *label) const
Definition: range_map.cc:107
printf
_Use_decl_annotations_ int __cdecl printf(const char *_Format,...)
Definition: cs_driver.c:91
bloaty.h
testing::internal::string
::std::string string
Definition: bloaty/third_party/protobuf/third_party/googletest/googletest/include/gtest/internal/gtest-port.h:881
binary_size.new_size
def new_size
Definition: binary_size.py:124
UINT64_MAX
#define UINT64_MAX
Definition: stdint-msvc2008.h:143
bloaty::RangeMap::CoversRange
bool CoversRange(uint64_t addr, uint64_t size) const
Definition: range_map.cc:307
bloaty::RangeMap::AddRangeWithTranslation
bool AddRangeWithTranslation(uint64_t addr, uint64_t size, const std::string &val, const RangeMap &translator, bool verbose, RangeMap *other)
Definition: range_map.cc:253
iterator
const typedef MCPhysReg * iterator
Definition: MCRegisterInfo.h:27
bloaty::RangeMap::RangeEnd
uint64_t RangeEnd(Map::const_iterator iter) const
Definition: range_map.h:223
T
#define T(upbtypeconst, upbtype, ctype, default_value)
bloaty::RangeMap
Definition: range_map.h:46
bloaty::RangeMap::DebugString
std::string DebugString() const
Definition: range_map.cc:138
bloaty::RangeMap::AddDualRange
void AddDualRange(uint64_t addr, uint64_t size, uint64_t otheraddr, const std::string &val)
Definition: range_map.cc:181
bloaty::RangeMap::TranslateWithEntry
uint64_t TranslateWithEntry(T iter, uint64_t addr) const
Definition: range_map.cc:24
end
char * end
Definition: abseil-cpp/absl/strings/internal/str_format/float_conversion.cc:1008
gen_synthetic_protos.label
label
Definition: gen_synthetic_protos.py:102
gen_stats_data.c_str
def c_str(s, encoding='ascii')
Definition: gen_stats_data.py:38
max
int max
Definition: bloaty/third_party/zlib/examples/enough.c:170
bloaty::RangeMap::TryGetSize
bool TryGetSize(uint64_t addr, uint64_t *size) const
Definition: range_map.cc:128
bloaty::RangeMap::AddRange
void AddRange(uint64_t addr, uint64_t size, const std::string &val)
Definition: range_map.cc:146
bloaty::RangeMap::Compress
void Compress()
Definition: range_map.cc:291
bloaty::RangeMap::EntryContains
bool EntryContains(T iter, uint64_t addr) const
Definition: range_map.h:189
uint64_t
unsigned __int64 uint64_t
Definition: stdint-msvc2008.h:90
gen_synthetic_protos.base
base
Definition: gen_synthetic_protos.py:31
min
#define min(a, b)
Definition: qsort.h:83
bloaty::RangeMap::CheckConsistency
void CheckConsistency(T iter) const
Definition: range_map.h:180
bloaty::RangeMap::FindContainingOrAfter
Map::iterator FindContainingOrAfter(uint64_t addr)
Definition: range_map.cc:66
bloaty::RangeMap::Translate
bool Translate(uint64_t addr, uint64_t *translated) const
Definition: range_map.cc:87
after
IntAfterTypedTestSuiteP after
Definition: googletest/googletest/test/gtest-typed-test_test.cc:375
verbose
bool verbose
Definition: bloaty/third_party/protobuf/conformance/conformance_cpp.cc:70
bloaty::RangeMap::mappings_
Map mappings_
Definition: range_map.h:177
ret
UniquePtr< SSL_SESSION > ret
Definition: ssl_x509.cc:1029
next
AllocList * next[kMaxLevel]
Definition: abseil-cpp/absl/base/internal/low_level_alloc.cc:100
bloaty::RangeMap::Entry
Definition: range_map.h:160
range_map.h
iter
Definition: test_winkernel.cpp:47
bloaty::RangeMap::TryGetLabel
bool TryGetLabel(uint64_t addr, std::string *label) const
Definition: range_map.cc:97
size
voidpf void uLong size
Definition: bloaty/third_party/zlib/contrib/minizip/ioapi.h:136
addr
struct sockaddr_in addr
Definition: libuv/docs/code/tcp-echo-server/main.c:10


grpc
Author(s):
autogenerated on Thu Mar 13 2025 03:00:59